| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import QtQuick 2.15
- import QtQuick.Controls 2.15
- // import QtQuick.Effects // Disabled - MultiEffect causes issues on linuxfb
- import "." as Components
- Rectangle {
- property string name: ""
- property alias preview: previewImage.source
- // Clean up the pattern name for display
- property string cleanName: {
- var cleanedName = name
- // Remove path (get everything after the last slash)
- var parts = cleanedName.split('/')
- cleanedName = parts[parts.length - 1]
- // Remove .thr extension
- cleanedName = cleanedName.replace('.thr', '')
- return cleanedName
- }
- signal clicked()
- color: Components.ThemeManager.surfaceColor
- radius: 12
- border.width: 1
- border.color: Components.ThemeManager.borderColor
- // Drop shadow effect - disabled on linuxfb (causes rendering issues)
- // Using simple border instead for compatibility
- // layer.enabled: true
- // layer.effect: MultiEffect {
- // shadowEnabled: true
- // shadowColor: "#20000000"
- // shadowBlur: 0.8
- // shadowVerticalOffset: 2
- // shadowHorizontalOffset: 0
- // }
-
- // Hover/press animation
- scale: mouseArea.pressed ? 0.95 : (mouseArea.containsMouse ? 1.02 : 1.0)
-
- Behavior on scale {
- NumberAnimation { duration: 150; easing.type: Easing.OutQuad }
- }
-
- Column {
- anchors.fill: parent
- anchors.margins: 8
- spacing: 6
-
- // Preview image container
- Rectangle {
- width: parent.width
- height: parent.height - nameLabel.height - 12
- radius: 8
- color: Components.ThemeManager.previewBackground
- clip: true
-
- Image {
- id: previewImage
- anchors.fill: parent
- fillMode: Image.PreserveAspectFit
- source: preview ? "file:///" + preview : ""
- smooth: true
-
- // Loading animation
- opacity: status === Image.Ready ? 1 : 0
- Behavior on opacity {
- NumberAnimation { duration: 200 }
- }
- }
-
- // Placeholder when no preview
- Rectangle {
- anchors.fill: parent
- color: Components.ThemeManager.placeholderBackground
- visible: previewImage.status === Image.Error || previewImage.source == ""
- radius: 8
- Column {
- anchors.centerIn: parent
- spacing: 8
- Text {
- text: "◻"
- font.pixelSize: 32
- anchors.horizontalCenter: parent.horizontalCenter
- color: Components.ThemeManager.placeholderText
- }
- Text {
- text: "No Preview"
- anchors.horizontalCenter: parent.horizontalCenter
- color: Components.ThemeManager.textTertiary
- font.pixelSize: 12
- }
- }
- }
- }
- // Pattern name
- Label {
- id: nameLabel
- text: cleanName
- width: parent.width
- elide: Label.ElideRight
- horizontalAlignment: Label.AlignHCenter
- font.pixelSize: 13
- font.weight: Font.Medium
- color: Components.ThemeManager.textPrimary
- wrapMode: Text.Wrap
- maximumLineCount: 2
- }
- }
-
- // Click area
- MouseArea {
- id: mouseArea
- anchors.fill: parent
- hoverEnabled: true
- onClicked: parent.clicked()
-
- // Ripple effect on click
- Rectangle {
- id: ripple
- width: 0
- height: 0
- radius: width / 2
- color: "#20000000"
- anchors.centerIn: parent
-
- NumberAnimation {
- id: rippleAnimation
- target: ripple
- property: "width"
- from: 0
- to: mouseArea.width * 1.5
- duration: 300
- easing.type: Easing.OutQuad
-
- onFinished: {
- ripple.width = 0
- ripple.height = 0
- }
- }
-
- Connections {
- target: mouseArea
- function onPressed() {
- ripple.height = ripple.width
- rippleAnimation.start()
- }
- }
- }
- }
- }
|