SearchField.qml 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright (C) 2025 The Qt Company Ltd.
  2. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
  3. // Qt-Security score:significant reason:default
  4. pragma ComponentBehavior: Bound
  5. import QtQuick
  6. import QtQuick.Templates as T
  7. import QtQuick.Controls.impl
  8. import QtQuick.Controls.FluentWinUI3.impl as Impl
  9. T.SearchField {
  10. id: control
  11. implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
  12. implicitContentWidth + leftPadding + rightPadding)
  13. + searchIndicator.implicitIndicatorWidth + clearIndicator.implicitIndicatorWidth
  14. implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
  15. implicitContentHeight + topPadding + bottomPadding,
  16. searchIndicator.implicitIndicatorHeight + topPadding + bottomPadding)
  17. spacing: __config.contentItem.spacing / 2 || 0
  18. topPadding: __config.topPadding || 0
  19. bottomPadding: __config.bottomPadding || 0
  20. readonly property real __clearIndicator: (!clearIndicator.indicator || !clearIndicator.indicator.visible ? 0 : clearIndicator.indicator.width + control.spacing)
  21. readonly property real __searchIndicator: (!searchIndicator.indicator || !searchIndicator.indicator.visible ? 0 : searchIndicator.indicator.width + control.spacing)
  22. leftPadding: __config.leftPadding + (control.mirrored ? __clearIndicator + __searchIndicator : 0)
  23. rightPadding: __config.rightPadding + (control.mirrored ? 0 : __clearIndicator + __searchIndicator)
  24. topInset: -__config.topInset || 0
  25. bottomInset: -__config.bottomInset || 0
  26. leftInset: -__config.leftInset || 0
  27. rightInset: -__config.rightInset || 0
  28. readonly property string __currentState: [
  29. !control.enabled && "disabled",
  30. (control.searchIndicator.pressed && control.clearIndicator.pressed) && "hovered",
  31. control.popup.visible && "open",
  32. (control.searchIndicator.pressed && control.clearIndicator.pressed) && "pressed"
  33. ].filter(Boolean).join("_") || "normal"
  34. readonly property var __config: (control.popup.visible
  35. ? Config.controls.editablecombobox[__currentState]
  36. : Config.controls.combobox[__currentState]) || {}
  37. readonly property Item __focusFrameTarget: null
  38. readonly property bool __isHighContrast: Application.styleHints.accessibility.contrastPreference === Qt.HighContrast
  39. delegate: ItemDelegate {
  40. width: ListView.view.width
  41. text: model[control.textRole]
  42. palette.text: control.palette.text
  43. palette.highlightedText: control.palette.highlightedText
  44. font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
  45. highlighted: control.highlightedIndex === index
  46. hoverEnabled: control.hoverEnabled
  47. required property var model
  48. required property int index
  49. }
  50. searchIndicator.indicator: Impl.StyleImage {
  51. // use SpinBox indicator assets as they share the same style
  52. readonly property string __state: [
  53. (control.searchIndicator.hovered || control.searchIndicator.pressed) && "up",
  54. (control.searchIndicator.indicator.enabled && control.searchIndicator.hovered && !control.searchIndicator.pressed) && "hovered",
  55. (control.searchIndicator.indicator.enabled && control.searchIndicator.pressed) && "pressed",
  56. (!control.searchIndicator.indicator.enabled) && "disabled"
  57. ].filter(Boolean).join("_") || "normal"
  58. readonly property var indicatorConfig: Config.controls.spinbox[__state] || {}
  59. imageConfig: indicatorConfig.indicator_up_background
  60. x: !control.mirrored ? control.width - width - control.spacing : control.spacing
  61. y: control.topPadding
  62. implicitWidth: 32
  63. implicitHeight: 24
  64. height: control.availableHeight
  65. ColorImage {
  66. x: (parent.width - width) / 2
  67. y: (parent.height - height) / 2
  68. width: 13
  69. height: 13
  70. source: Qt.resolvedUrl("icons/search-magnifier")
  71. color: control.palette.placeholderText
  72. opacity: control.searchIndicator.pressed ? 0.7 : 1
  73. }
  74. }
  75. clearIndicator.indicator: Impl.StyleImage {
  76. // use SpinBox indicator assets as they share the same style
  77. readonly property string __state: [
  78. (control.clearIndicator.hovered || control.clearIndicator.pressed) && "down",
  79. (control.clearIndicator.indicator.enabled && control.clearIndicator.hovered && !control.clearIndicator.pressed) && "hovered",
  80. (control.clearIndicator.indicator.enabled && control.clearIndicator.pressed) && "pressed",
  81. (!control.clearIndicator.indicator.enabled) && "disabled"
  82. ].filter(Boolean).join("_") || "normal"
  83. readonly property var indicatorConfig: Config.controls.spinbox[__state] || {}
  84. imageConfig: indicatorConfig.indicator_down_background
  85. x: (!searchIndicator.indicator || !searchIndicator.indicator.visible)
  86. ? (!control.mirrored ? control.width - width - control.spacing : control.spacing)
  87. : (!control.mirrored ? control.width - width - (control.spacing * 2) - searchIndicator.indicator.width : searchIndicator.indicator.width + (control.spacing * 2))
  88. y: control.topPadding
  89. implicitWidth: 32
  90. implicitHeight: 24
  91. height: control.availableHeight
  92. visible: control.text.length > 0
  93. ColorImage {
  94. x: (parent.width - width) / 2
  95. y: (parent.height - height) / 2
  96. width: 13
  97. height: 13
  98. source: Qt.resolvedUrl("icons/close_big")
  99. color: control.palette.placeholderText
  100. opacity: control.clearIndicator.pressed ? 0.7 : 1
  101. }
  102. }
  103. contentItem: T.TextField {
  104. implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
  105. contentHeight + topPadding + bottomPadding)
  106. leftPadding: control.__config.label_contentItem.leftPadding
  107. rightPadding: control.__config.label_contentItem.rightPadding
  108. topPadding: control.__config.label_contentItem.topPadding
  109. bottomPadding: control.__config.label_contentItem.bottomPadding
  110. topInset: -control.__config.label_contentItem.topInset || 0
  111. bottomInset: -control.__config.label_contentItem.bottomInset || 0
  112. text: control.text
  113. color: control.palette.text
  114. selectionColor: control.palette.highlight
  115. selectedTextColor: control.palette.highlightedText
  116. horizontalAlignment: control.__config.label_text.textHAlignment
  117. verticalAlignment: control.__config.label_text.textVAlignment
  118. readonly property Item __focusFrameControl: control
  119. ContextMenu.menu: Impl.TextEditingContextMenu {
  120. editor: parent
  121. }
  122. }
  123. background: ItemGroup {
  124. Impl.StyleImage {
  125. visible: !control.__isHighContrast
  126. imageConfig: control.__config.background
  127. Item {
  128. visible: control.popup.visible || control.activeFocus
  129. width: parent.width
  130. height: 2
  131. y: parent.height - height
  132. Impl.FocusStroke {
  133. width: parent.width
  134. height: parent.height
  135. radius: control.popup.visible ? 0 : control.__config.background.bottomOffset
  136. color: control.palette.accent
  137. }
  138. }
  139. }
  140. Rectangle {
  141. visible: control.__isHighContrast
  142. implicitWidth: control.__config.background.width
  143. implicitHeight: control.__config.background.height
  144. color: control.palette.window
  145. border.color: control.hovered ? control.palette.accent : control.palette.text
  146. radius: 4
  147. }
  148. }
  149. popup: T.Popup {
  150. y: control.height
  151. width: control.width
  152. height: control.suggestionCount > 0 ? Math.min(contentItem.implicitHeight + topPadding + bottomPadding, control.Window.height - topMargin - bottomMargin) : 0
  153. topMargin: 8
  154. bottomMargin: 8
  155. palette: control.palette
  156. topPadding: control.__config.popup_contentItem.topPadding || 0
  157. leftPadding: control.__config.popup_contentItem.leftPadding || 0
  158. rightPadding: control.__config.popup_contentItem.rightPadding || 0
  159. bottomPadding: control.__config.popup_contentItem.bottomPadding || 0
  160. contentItem: ListView {
  161. clip: true
  162. implicitHeight: contentHeight
  163. model: control.delegateModel
  164. currentIndex: control.highlightedIndex
  165. highlightMoveDuration: 0
  166. }
  167. enter: Transition {
  168. NumberAnimation { property: "height"; from: control.popup.height / 3; to: control.popup.height; easing.type: Easing.OutCubic; duration: 250 }
  169. }
  170. background: ItemGroup {
  171. Impl.StyleImage {
  172. visible: !control.__isHighContrast
  173. imageConfig: control.__config.popup_background.filePath ? control.__config.popup_background : Config.controls.popup["normal"].background // fallback to regular popup
  174. }
  175. Rectangle {
  176. visible: control.__isHighContrast
  177. implicitWidth: Config.controls.popup["normal"].background.width
  178. implicitHeight: Config.controls.popup["normal"].background.height
  179. color: control.palette.window
  180. border.color: control.palette.text
  181. radius: 4
  182. }
  183. }
  184. }
  185. }