ModernPatternCard.qml 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.15
  3. // import QtQuick.Effects // Disabled - MultiEffect causes issues on linuxfb
  4. import "." as Components
  5. Rectangle {
  6. property string name: ""
  7. property alias preview: previewImage.source
  8. // Clean up the pattern name for display
  9. property string cleanName: {
  10. var cleanedName = name
  11. // Remove path (get everything after the last slash)
  12. var parts = cleanedName.split('/')
  13. cleanedName = parts[parts.length - 1]
  14. // Remove .thr extension
  15. cleanedName = cleanedName.replace('.thr', '')
  16. return cleanedName
  17. }
  18. signal clicked()
  19. color: Components.ThemeManager.surfaceColor
  20. radius: 12
  21. border.width: 1
  22. border.color: Components.ThemeManager.borderColor
  23. // Drop shadow effect - disabled on linuxfb (causes rendering issues)
  24. // Using simple border instead for compatibility
  25. // layer.enabled: true
  26. // layer.effect: MultiEffect {
  27. // shadowEnabled: true
  28. // shadowColor: "#20000000"
  29. // shadowBlur: 0.8
  30. // shadowVerticalOffset: 2
  31. // shadowHorizontalOffset: 0
  32. // }
  33. // Hover/press animation
  34. scale: mouseArea.pressed ? 0.95 : (mouseArea.containsMouse ? 1.02 : 1.0)
  35. Behavior on scale {
  36. NumberAnimation { duration: 150; easing.type: Easing.OutQuad }
  37. }
  38. Column {
  39. anchors.fill: parent
  40. anchors.margins: 8
  41. spacing: 6
  42. // Preview image container
  43. Rectangle {
  44. width: parent.width
  45. height: parent.height - nameLabel.height - 12
  46. radius: 8
  47. color: Components.ThemeManager.previewBackground
  48. clip: true
  49. Image {
  50. id: previewImage
  51. anchors.fill: parent
  52. fillMode: Image.PreserveAspectFit
  53. source: preview ? "file:///" + preview : ""
  54. smooth: true
  55. // Loading animation
  56. opacity: status === Image.Ready ? 1 : 0
  57. Behavior on opacity {
  58. NumberAnimation { duration: 200 }
  59. }
  60. }
  61. // Placeholder when no preview
  62. Rectangle {
  63. anchors.fill: parent
  64. color: Components.ThemeManager.placeholderBackground
  65. visible: previewImage.status === Image.Error || previewImage.source == ""
  66. radius: 8
  67. Column {
  68. anchors.centerIn: parent
  69. spacing: 8
  70. Text {
  71. text: "◻"
  72. font.pixelSize: 32
  73. anchors.horizontalCenter: parent.horizontalCenter
  74. color: Components.ThemeManager.placeholderText
  75. }
  76. Text {
  77. text: "No Preview"
  78. anchors.horizontalCenter: parent.horizontalCenter
  79. color: Components.ThemeManager.textTertiary
  80. font.pixelSize: 12
  81. }
  82. }
  83. }
  84. }
  85. // Pattern name
  86. Label {
  87. id: nameLabel
  88. text: cleanName
  89. width: parent.width
  90. elide: Label.ElideRight
  91. horizontalAlignment: Label.AlignHCenter
  92. font.pixelSize: 13
  93. font.weight: Font.Medium
  94. color: Components.ThemeManager.textPrimary
  95. wrapMode: Text.Wrap
  96. maximumLineCount: 2
  97. }
  98. }
  99. // Click area
  100. MouseArea {
  101. id: mouseArea
  102. anchors.fill: parent
  103. hoverEnabled: true
  104. onClicked: parent.clicked()
  105. // Ripple effect on click
  106. Rectangle {
  107. id: ripple
  108. width: 0
  109. height: 0
  110. radius: width / 2
  111. color: "#20000000"
  112. anchors.centerIn: parent
  113. NumberAnimation {
  114. id: rippleAnimation
  115. target: ripple
  116. property: "width"
  117. from: 0
  118. to: mouseArea.width * 1.5
  119. duration: 300
  120. easing.type: Easing.OutQuad
  121. onFinished: {
  122. ripple.width = 0
  123. ripple.height = 0
  124. }
  125. }
  126. Connections {
  127. target: mouseArea
  128. function onPressed() {
  129. ripple.height = ripple.width
  130. rippleAnimation.start()
  131. }
  132. }
  133. }
  134. }
  135. }