ExpandablePopup.qml 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright (c) 2018 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.7
  4. import QtQuick.Controls 2.3
  5. import UM 1.5 as UM
  6. import Cura 1.0 as Cura
  7. // The expandable component has 2 major sub components:
  8. // * The headerItem; Always visible and should hold some info about what happens if the component is expanded
  9. // * The contentItem; The content that needs to be shown if the component is expanded.
  10. Item
  11. {
  12. id: base
  13. // Enumeration with the different possible alignments of the content with respect of the headerItem
  14. enum ContentAlignment
  15. {
  16. AlignLeft,
  17. AlignRight
  18. }
  19. // The headerItem holds the QML item that is always displayed.
  20. property alias headerItem: headerItemLoader.sourceComponent
  21. // The contentItem holds the QML item that is shown when the "open" button is pressed
  22. property alias contentItem: content.contentItem
  23. // If the contentItem is a Layout (eg Column) you must use these to set the popup size otherwise you end up with a
  24. // binding loop between the popup and the contentItem
  25. // ImplicitWidth/ImplicitHeight can be used instead in the contentItem if it is not a Layout.
  26. property alias contentWidth: content.width
  27. property alias contentHeight: content.height
  28. property color contentBackgroundColor: UM.Theme.getColor("action_button")
  29. property color headerBackgroundColor: UM.Theme.getColor("action_button")
  30. property color headerActiveColor: UM.Theme.getColor("expandable_active")
  31. property color headerHoverColor: UM.Theme.getColor("expandable_hover")
  32. property alias mouseArea: headerMouseArea
  33. property alias enabled: headerMouseArea.enabled
  34. // Text to show when this component is disabled
  35. property alias disabledText: disabledLabel.text
  36. // Defines the alignment of the content with respect of the headerItem, by default to the right
  37. property int contentAlignment: ExpandablePopup.ContentAlignment.AlignRight
  38. // How much spacing is needed around the contentItem
  39. property alias contentPadding: content.padding
  40. // How much padding is needed around the header & button
  41. property alias headerPadding: background.padding
  42. property alias headerBackgroundBorder: background.border
  43. // Whether or not to show the background border
  44. property bool enableHeaderBackgroundBorder: true
  45. // What icon should be displayed on the right.
  46. property alias iconSource: collapseButton.source
  47. property alias iconColor: collapseButton.color
  48. // The icon size (it's always drawn as a square)
  49. property alias iconSize: collapseButton.height
  50. // Is the "drawer" open?
  51. readonly property alias expanded: content.visible
  52. property alias expandedHighlightColor: expandedHighlight.color
  53. // What should the radius of the header be. This is also influenced by the headerCornerSide
  54. property alias headerRadius: background.radius
  55. // On what side should the header corners be shown? 1 is down, 2 is left, 3 is up and 4 is right.
  56. property alias headerCornerSide: background.cornerSide
  57. // Change the contentItem close behaviour
  58. property alias contentClosePolicy : content.closePolicy
  59. // Distance between the header and the content.
  60. property int popupOffset: 2 * UM.Theme.getSize("default_lining").height
  61. onEnabledChanged:
  62. {
  63. if (!base.enabled && expanded)
  64. {
  65. toggleContent()
  66. }
  67. }
  68. function toggleContent()
  69. {
  70. if (content.visible)
  71. {
  72. content.close()
  73. }
  74. else
  75. {
  76. content.open()
  77. }
  78. }
  79. // Add this binding since the background color is not updated otherwise
  80. Binding
  81. {
  82. target: background
  83. property: "color"
  84. value: base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled")
  85. }
  86. implicitHeight: 100 * screenScaleFactor
  87. implicitWidth: 400 * screenScaleFactor
  88. RoundedRectangle
  89. {
  90. id: background
  91. property real padding: UM.Theme.getSize("default_margin").width
  92. border.width: base.enableHeaderBackgroundBorder ? UM.Theme.getSize("default_lining").width : 0
  93. border.color: UM.Theme.getColor("lining")
  94. color: base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled")
  95. anchors.fill: parent
  96. UM.Label
  97. {
  98. id: disabledLabel
  99. visible: !base.enabled
  100. leftPadding: background.padding
  101. text: ""
  102. height: parent.height
  103. }
  104. Item
  105. {
  106. anchors.fill: parent
  107. visible: base.enabled
  108. MouseArea
  109. {
  110. id: headerMouseArea
  111. anchors.fill: parent
  112. onClicked: toggleContent()
  113. hoverEnabled: true
  114. onEntered: background.color = headerHoverColor
  115. onExited: background.color = base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled")
  116. }
  117. Loader
  118. {
  119. id: headerItemLoader
  120. anchors
  121. {
  122. left: parent.left
  123. right: collapseButton.visible ? collapseButton.left : parent.right
  124. top: parent.top
  125. bottom: parent.bottom
  126. margins: background.padding
  127. }
  128. }
  129. // A highlight that is shown when the content is expanded
  130. Rectangle
  131. {
  132. id: expandedHighlight
  133. width: parent.width
  134. height: UM.Theme.getSize("thick_lining").height
  135. color: UM.Theme.getColor("primary")
  136. visible: expanded
  137. anchors.bottom: parent.bottom
  138. }
  139. UM.ColorImage
  140. {
  141. id: collapseButton
  142. anchors
  143. {
  144. right: parent.right
  145. verticalCenter: parent.verticalCenter
  146. margins: background.padding
  147. }
  148. source: UM.Theme.getIcon("ChevronSingleDown")
  149. visible: source != ""
  150. width: UM.Theme.getSize("standard_arrow").width
  151. height: UM.Theme.getSize("standard_arrow").height
  152. color: UM.Theme.getColor("small_button_text")
  153. }
  154. }
  155. }
  156. Popup
  157. {
  158. id: content
  159. // Ensure that the content is located directly below the headerItem
  160. y: background.height + base.popupOffset
  161. // Make the content aligned with the rest, using the property contentAlignment to decide whether is right or left.
  162. // In case of right alignment, the 3x padding is due to left, right and padding between the button & text.
  163. x: contentAlignment == ExpandablePopup.ContentAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0
  164. padding: UM.Theme.getSize("default_margin").width
  165. closePolicy: Popup.CloseOnPressOutsideParent
  166. background: Cura.RoundedRectangle
  167. {
  168. cornerSide: Cura.RoundedRectangle.Direction.Down
  169. color: contentBackgroundColor
  170. border.width: UM.Theme.getSize("default_lining").width
  171. border.color: UM.Theme.getColor("lining")
  172. radius: UM.Theme.getSize("default_radius").width
  173. height: contentItem.implicitHeight || content.height
  174. }
  175. contentItem: Item {}
  176. }
  177. }