GenericPopUp.qml 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright (c) 2019 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.2
  4. import QtQuick.Controls 2.0
  5. import QtQuick.Controls.Styles 1.4
  6. import QtQuick.Dialogs 1.1
  7. import QtGraphicalEffects 1.0
  8. import UM 1.3 as UM
  9. /**
  10. * This is a generic pop-up element which can be supplied with a target and a content item. The
  11. * content item will appear to the left, right, above, or below the target depending on the value of
  12. * the direction property
  13. */
  14. Popup
  15. {
  16. id: base
  17. /**
  18. * The target item is what the pop-up is "tied" to, usually a button
  19. */
  20. property var target
  21. /**
  22. * Which direction should the pop-up "point"?
  23. * Possible values include:
  24. * - "up"
  25. * - "down"
  26. * - "left"
  27. * - "right"
  28. */
  29. property string direction: "down"
  30. /**
  31. * We save the default direction so that if a pop-up was flipped but later has space (i.e. it
  32. * moved), we can unflip it back to the default direction.
  33. */
  34. property string originalDirection: ""
  35. /**
  36. * Should the popup close when you click outside it? For example, this is
  37. * disabled by the InfoBlurb component since it's opened and closed using mouse
  38. * hovers, not clicks.
  39. */
  40. property bool closeOnClick: true
  41. /**
  42. * Use white for context menus, dark grey for info blurbs!
  43. */
  44. property var color: "#ffffff" // TODO: Theme!
  45. Component.onCompleted:
  46. {
  47. recalculatePosition()
  48. // Set the direction here so it's only set once and never mutated
  49. originalDirection = (' ' + direction).slice(1)
  50. }
  51. background: Item
  52. {
  53. anchors.fill: parent
  54. DropShadow
  55. {
  56. anchors.fill: pointedRectangle
  57. color: UM.Theme.getColor("monitor_shadow")
  58. radius: UM.Theme.getSize("monitor_shadow_radius").width
  59. source: pointedRectangle
  60. transparentBorder: true
  61. verticalOffset: 2 * screenScaleFactor
  62. }
  63. Item
  64. {
  65. id: pointedRectangle
  66. anchors
  67. {
  68. horizontalCenter: parent.horizontalCenter
  69. verticalCenter: parent.verticalCenter
  70. }
  71. height: parent.height - 10 * screenScaleFactor // Because of the shadow
  72. width: parent.width - 10 * screenScaleFactor // Because of the shadow
  73. Rectangle
  74. {
  75. id: point
  76. anchors
  77. {
  78. horizontalCenter:
  79. {
  80. switch(direction)
  81. {
  82. case "left":
  83. return bloop.left
  84. case "right":
  85. return bloop.right
  86. default:
  87. return bloop.horizontalCenter
  88. }
  89. }
  90. verticalCenter:
  91. {
  92. switch(direction)
  93. {
  94. case "up":
  95. return bloop.top
  96. case "down":
  97. return bloop.bottom
  98. default:
  99. return bloop.verticalCenter
  100. }
  101. }
  102. }
  103. color: base.color
  104. height: 12 * screenScaleFactor
  105. transform: Rotation
  106. {
  107. angle: 45
  108. origin.x: point.width / 2
  109. origin.y: point.height / 2
  110. }
  111. width: height
  112. }
  113. Rectangle
  114. {
  115. id: bloop
  116. anchors
  117. {
  118. fill: parent
  119. leftMargin: direction == "left" ? 8 * screenScaleFactor : 0
  120. rightMargin: direction == "right" ? 8 * screenScaleFactor : 0
  121. topMargin: direction == "up" ? 8 * screenScaleFactor : 0
  122. bottomMargin: direction == "down" ? 8 * screenScaleFactor : 0
  123. }
  124. color: base.color
  125. width: parent.width
  126. }
  127. }
  128. }
  129. visible: false
  130. onClosed: visible = false
  131. onOpened:
  132. {
  133. // Flip orientation if necessary
  134. recalculateOrientation()
  135. // Fix position if necessary
  136. recalculatePosition()
  137. // Show the pop up
  138. visible = true
  139. }
  140. closePolicy: closeOnClick ? Popup.CloseOnPressOutside : Popup.NoAutoClose
  141. clip: true
  142. padding: UM.Theme.getSize("monitor_shadow_radius").width
  143. topPadding: direction == "up" ? padding + 8 * screenScaleFactor : padding
  144. bottomPadding: direction == "down" ? padding + 8 * screenScaleFactor : padding
  145. leftPadding: direction == "left" ? padding + 8 * screenScaleFactor : padding
  146. rightPadding: direction == "right" ? padding + 8 * screenScaleFactor : padding
  147. function recalculatePosition() {
  148. // Stupid pop-up logic causes the pop-up to resize, so let's compute what it SHOULD be
  149. const realWidth = contentItem.implicitWidth + leftPadding + rightPadding
  150. const realHeight = contentItem.implicitHeight + topPadding + bottomPadding
  151. var centered = {
  152. x: target.x + target.width / 2 - realWidth / 2,
  153. y: target.y + target.height / 2 - realHeight / 2
  154. }
  155. switch(direction)
  156. {
  157. case "left":
  158. x = target.x + target.width
  159. y = centered.y
  160. break
  161. case "right":
  162. x = target.x - realWidth
  163. y = centered.y
  164. break
  165. case "up":
  166. x = centered.x
  167. y = target.y + target.height
  168. break
  169. case "down":
  170. x = centered.x
  171. y = target.y - realHeight
  172. break
  173. }
  174. }
  175. function recalculateOrientation() {
  176. var availableSpace
  177. var targetPosition = target.mapToItem(monitorFrame, 0, 0)
  178. // Stupid pop-up logic causes the pop-up to resize, so let's compute what it SHOULD be
  179. const realWidth = contentItem.implicitWidth + leftPadding + rightPadding
  180. const realHeight = contentItem.implicitHeight + topPadding + bottomPadding
  181. switch(originalDirection)
  182. {
  183. case "up":
  184. availableSpace = monitorFrame.height - (targetPosition.y + target.height)
  185. direction = availableSpace < realHeight ? "down" : originalDirection
  186. break
  187. case "down":
  188. availableSpace = targetPosition.y
  189. direction = availableSpace < realHeight ? "up" : originalDirection
  190. break
  191. case "right":
  192. availableSpace = targetPosition.x
  193. direction = availableSpace < realWidth ? "left" : originalDirection
  194. break
  195. case "left":
  196. availableSpace = monitorFrame.width - (targetPosition.x + target.width)
  197. direction = availableSpace < realWidth ? "right" : originalDirection
  198. break
  199. }
  200. }
  201. }