MaterialBrandMenu.qml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright (c) 2022 UltiMaker
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.7
  4. import QtQuick.Controls 2.4
  5. import QtQuick.Layouts 2.7
  6. import UM 1.5 as UM
  7. import Cura 1.7 as Cura
  8. /* This element is a workaround for MacOS, where it can crash in Qt6 when nested menus are closed.
  9. Instead we'll use a pop-up which doesn't seem to have that problem. */
  10. Cura.MenuItem
  11. {
  12. id: materialBrandMenu
  13. overrideShowArrow: true
  14. property var materialTypesModel
  15. text: materialTypesModel.name
  16. contentItem: MouseArea
  17. {
  18. hoverEnabled: true
  19. RowLayout
  20. {
  21. spacing: 0
  22. opacity: materialBrandMenu.enabled ? 1 : 0.5
  23. Item
  24. {
  25. // Spacer
  26. width: UM.Theme.getSize("default_margin").width
  27. }
  28. UM.Label
  29. {
  30. id: brandLabelText
  31. text: replaceText(materialBrandMenu.text)
  32. Layout.fillWidth: true
  33. Layout.fillHeight:true
  34. elide: Label.ElideRight
  35. wrapMode: Text.NoWrap
  36. }
  37. Item
  38. {
  39. Layout.fillWidth: true
  40. }
  41. Item
  42. {
  43. // Right side margin
  44. width: UM.Theme.getSize("default_margin").width
  45. }
  46. }
  47. onEntered: showTimer.restartTimer()
  48. onExited: hideTimer.restartTimer()
  49. }
  50. Timer
  51. {
  52. id: showTimer
  53. interval: 250
  54. function restartTimer()
  55. {
  56. restart();
  57. running = Qt.binding(function() { return materialBrandMenu.enabled && materialBrandMenu.contentItem.containsMouse; });
  58. hideTimer.running = false;
  59. }
  60. onTriggered: menuPopup.open()
  61. }
  62. Timer
  63. {
  64. id: hideTimer
  65. interval: 250
  66. function restartTimer() //Restart but re-evaluate the running property then.
  67. {
  68. restart();
  69. running = Qt.binding(function() { return materialBrandMenu.enabled && !materialBrandMenu.contentItem.containsMouse && !menuPopup.itemHovered > 0; });
  70. showTimer.running = false;
  71. }
  72. onTriggered: menuPopup.close()
  73. }
  74. MaterialBrandSubMenu
  75. {
  76. id: menuPopup
  77. // Nasty hack to ensure that we can keep track if the popup contains the mouse.
  78. // Since we also want a hover for the sub items (and these events are sent async)
  79. // We have to keep a count of itemHovered (instead of just a bool)
  80. property int itemHovered: 0
  81. MouseArea
  82. {
  83. id: submenuArea
  84. anchors.fill: parent
  85. hoverEnabled: true
  86. onEntered: hideTimer.restartTimer()
  87. }
  88. Column
  89. {
  90. id: materialTypesList
  91. width: UM.Theme.getSize("menu").width
  92. height: childrenRect.height
  93. spacing: 0
  94. property var brandMaterials: materialTypesModel.material_types
  95. Repeater
  96. {
  97. model: parent.brandMaterials
  98. //Use a MouseArea and Rectangle, not a button, because the button grabs mouse events which makes the parent pop-up think it's no longer being hovered.
  99. //With a custom MouseArea, we can prevent the events from being accepted.
  100. delegate: Rectangle
  101. {
  102. id: brandMaterialBase
  103. height: UM.Theme.getSize("menu").height
  104. width: UM.Theme.getSize("menu").width
  105. color: materialTypeButton.containsMouse ? UM.Theme.getColor("background_2") : "transparent"
  106. RowLayout
  107. {
  108. spacing: 0
  109. opacity: materialBrandMenu.enabled ? 1 : 0.5
  110. height: parent.height
  111. width: parent.width
  112. Item
  113. {
  114. // Spacer
  115. width: UM.Theme.getSize("default_margin").width
  116. }
  117. UM.Label
  118. {
  119. text: model.name
  120. Layout.fillWidth: true
  121. Layout.fillHeight: true
  122. elide: Label.ElideRight
  123. wrapMode: Text.NoWrap
  124. }
  125. Item
  126. {
  127. Layout.fillWidth: true
  128. }
  129. UM.ColorImage
  130. {
  131. height: UM.Theme.getSize("default_arrow").height
  132. width: UM.Theme.getSize("default_arrow").width
  133. color: UM.Theme.getColor("setting_control_text")
  134. source: UM.Theme.getIcon("ChevronSingleRight")
  135. }
  136. Item
  137. {
  138. // Right side margin
  139. width: UM.Theme.getSize("default_margin").width
  140. }
  141. }
  142. MouseArea
  143. {
  144. id: materialTypeButton
  145. anchors.fill: parent
  146. hoverEnabled: true
  147. acceptedButtons: Qt.NoButton
  148. onEntered:
  149. {
  150. menuPopup.itemHovered += 1;
  151. showSubTimer.restartTimer();
  152. }
  153. onExited:
  154. {
  155. menuPopup.itemHovered -= 1;
  156. hideSubTimer.restartTimer();
  157. }
  158. }
  159. Timer
  160. {
  161. id: showSubTimer
  162. interval: 250
  163. function restartTimer()
  164. {
  165. restart();
  166. running = Qt.binding(function() { return materialTypeButton.containsMouse; });
  167. hideSubTimer.running = false;
  168. }
  169. onTriggered: colorPopup.open()
  170. }
  171. Timer
  172. {
  173. id: hideSubTimer
  174. interval: 250
  175. function restartTimer() //Restart but re-evaluate the running property then.
  176. {
  177. restart();
  178. running = Qt.binding(function() { return !materialTypeButton.containsMouse && !colorPopup.itemHovered > 0; });
  179. showSubTimer.running = false;
  180. }
  181. onTriggered: colorPopup.close()
  182. }
  183. MaterialBrandSubMenu
  184. {
  185. id: colorPopup
  186. property int itemHovered: 0
  187. Column
  188. {
  189. id: materialColorsList
  190. property var brandColors: model.colors
  191. width: UM.Theme.getSize("menu").width
  192. height: childrenRect.height
  193. spacing: 0
  194. Repeater
  195. {
  196. model: parent.brandColors
  197. delegate: Rectangle
  198. {
  199. height: UM.Theme.getSize("menu").height
  200. width: parent.width
  201. color: materialColorButton.containsMouse ? UM.Theme.getColor("background_2") : UM.Theme.getColor("main_background")
  202. MouseArea
  203. {
  204. id: materialColorButton
  205. anchors.fill: parent
  206. hoverEnabled: true
  207. onClicked:
  208. {
  209. Cura.MachineManager.setMaterial(extruderIndex, model.container_node);
  210. menuPopup.close();
  211. colorPopup.close();
  212. materialMenu.close();
  213. }
  214. onEntered:
  215. {
  216. menuPopup.itemHovered += 1;
  217. colorPopup.itemHovered += 1;
  218. }
  219. onExited:
  220. {
  221. menuPopup.itemHovered -= 1;
  222. colorPopup.itemHovered -= 1;
  223. }
  224. }
  225. Item
  226. {
  227. height: parent.height
  228. width: parent.width
  229. opacity: materialBrandMenu.enabled ? 1 : 0.5
  230. anchors.fill: parent
  231. //Checkmark, if the material is selected.
  232. UM.ColorImage
  233. {
  234. id: checkmark
  235. visible: model.id === materialMenu.activeMaterialId
  236. height: UM.Theme.getSize("default_arrow").height
  237. width: height
  238. anchors.left: parent.left
  239. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  240. anchors.verticalCenter: parent.verticalCenter
  241. source: UM.Theme.getIcon("Check", "low")
  242. color: UM.Theme.getColor("setting_control_text")
  243. }
  244. UM.Label
  245. {
  246. text: model.name
  247. anchors.left: parent.left
  248. anchors.leftMargin: UM.Theme.getSize("default_margin").width + UM.Theme.getSize("default_arrow").height
  249. anchors.verticalCenter: parent.verticalCenter
  250. anchors.right: parent.right
  251. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  252. elide: Label.ElideRight
  253. wrapMode: Text.NoWrap
  254. }
  255. }
  256. }
  257. }
  258. }
  259. }
  260. }
  261. }
  262. }
  263. }
  264. }