PerObjectSettingsPanel.qml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. //Copyright (c) 2022 Ultimaker B.V.
  2. //Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.15
  4. import QtQuick.Controls 2.15
  5. import UM 1.5 as UM
  6. import Cura 1.0 as Cura
  7. import ".."
  8. Item
  9. {
  10. id: base
  11. width: childrenRect.width
  12. height: childrenRect.height
  13. property var allCategoriesExceptSupport: [ "machine_settings", "resolution", "shell", "infill", "material", "speed",
  14. "travel", "cooling", "platform_adhesion", "dual", "meshfix", "blackmagic", "experimental"]
  15. readonly property string normalMeshType: ""
  16. readonly property string supportMeshType: "support_mesh"
  17. readonly property string cuttingMeshType: "cutting_mesh"
  18. readonly property string infillMeshType: "infill_mesh"
  19. readonly property string antiOverhangMeshType: "anti_overhang_mesh"
  20. property var currentMeshType: UM.Controller.properties.getValue("MeshType")
  21. // Update the view every time the currentMeshType changes
  22. onCurrentMeshTypeChanged:
  23. {
  24. var type = currentMeshType
  25. // set checked state of mesh type buttons
  26. updateMeshTypeCheckedState(type)
  27. // update active type label
  28. for (var button in meshTypeButtons.children)
  29. {
  30. if (meshTypeButtons.children[button].checked)
  31. {
  32. meshTypeLabel.text = catalog.i18nc("@label", "Mesh Type") + ": " + meshTypeButtons.children[button].text
  33. break
  34. }
  35. }
  36. visibility_handler.addSkipResetSetting(currentMeshType)
  37. }
  38. function updateMeshTypeCheckedState(type)
  39. {
  40. // set checked state of mesh type buttons
  41. normalButton.checked = type === normalMeshType
  42. supportMeshButton.checked = type === supportMeshType
  43. overlapMeshButton.checked = type === infillMeshType || type === cuttingMeshType
  44. antiOverhangMeshButton.checked = type === antiOverhangMeshType
  45. }
  46. function setMeshType(type)
  47. {
  48. UM.Controller.setProperty("MeshType", type)
  49. updateMeshTypeCheckedState(type)
  50. }
  51. UM.I18nCatalog { id: catalog; name: "cura"}
  52. Column
  53. {
  54. id: items
  55. anchors.top: parent.top;
  56. anchors.left: parent.left;
  57. spacing: UM.Theme.getSize("default_margin").height
  58. Row // Mesh type buttons
  59. {
  60. id: meshTypeButtons
  61. spacing: UM.Theme.getSize("default_margin").width
  62. UM.ToolbarButton
  63. {
  64. id: normalButton
  65. text: catalog.i18nc("@label", "Normal model")
  66. toolItem: UM.ColorImage
  67. {
  68. source: UM.Theme.getIcon("Infill0")
  69. color: UM.Theme.getColor("icon")
  70. }
  71. property bool needBorder: true
  72. checkable: true
  73. onClicked: setMeshType(normalMeshType);
  74. z: 4
  75. }
  76. UM.ToolbarButton
  77. {
  78. id: supportMeshButton
  79. text: catalog.i18nc("@label", "Print as support")
  80. toolItem: UM.ColorImage
  81. {
  82. source: UM.Theme.getIcon("MeshTypeSupport")
  83. color: UM.Theme.getColor("icon")
  84. }
  85. property bool needBorder: true
  86. checkable:true
  87. onClicked: setMeshType(supportMeshType)
  88. z: 3
  89. }
  90. UM.ToolbarButton
  91. {
  92. id: overlapMeshButton
  93. text: catalog.i18nc("@label", "Modify settings for overlaps")
  94. toolItem: UM.ColorImage
  95. {
  96. source: UM.Theme.getIcon("MeshTypeIntersect")
  97. color: UM.Theme.getColor("icon")
  98. }
  99. property bool needBorder: true
  100. checkable:true
  101. onClicked: setMeshType(infillMeshType)
  102. z: 2
  103. }
  104. UM.ToolbarButton
  105. {
  106. id: antiOverhangMeshButton
  107. text: catalog.i18nc("@label", "Don't support overlaps")
  108. toolItem: UM.ColorImage
  109. {
  110. source: UM.Theme.getIcon("BlockSupportOverlaps")
  111. color: UM.Theme.getColor("icon")
  112. }
  113. property bool needBorder: true
  114. checkable: true
  115. onClicked: setMeshType(antiOverhangMeshType)
  116. z: 1
  117. }
  118. }
  119. UM.Label
  120. {
  121. id: meshTypeLabel
  122. height: UM.Theme.getSize("setting").height
  123. }
  124. Cura.ComboBox
  125. {
  126. id: infillOnlyComboBox
  127. width: parent.width / 2 - UM.Theme.getSize("default_margin").width
  128. height: UM.Theme.getSize("setting_control").height
  129. textRole: "text"
  130. forceHighlight: base.hovered
  131. model: ListModel
  132. {
  133. id: infillOnlyComboBoxModel
  134. Component.onCompleted: {
  135. append({ text: catalog.i18nc("@item:inlistbox", "Infill mesh only") })
  136. append({ text: catalog.i18nc("@item:inlistbox", "Cutting mesh") })
  137. }
  138. }
  139. visible: currentMeshType === infillMeshType || currentMeshType === cuttingMeshType
  140. onActivated:
  141. {
  142. setMeshType(index === 0 ? infillMeshType : cuttingMeshType);
  143. }
  144. Binding
  145. {
  146. target: infillOnlyComboBox
  147. property: "currentIndex"
  148. value: currentMeshType === infillMeshType ? 0 : 1
  149. }
  150. }
  151. Column // List of selected Settings to override for the selected object
  152. {
  153. // This is to ensure that the panel is first increasing in size up to 200 and then shows a scrollbar.
  154. // It kinda looks ugly otherwise (big panel, no content on it)
  155. id: currentSettings
  156. property int maximumHeight: 200 * screenScaleFactor
  157. height: Math.min(contents.count * (UM.Theme.getSize("section").height + UM.Theme.getSize("narrow_margin").height + UM.Theme.getSize("default_lining").height), maximumHeight)
  158. visible: currentMeshType != "anti_overhang_mesh"
  159. ListView
  160. {
  161. id: contents
  162. height: parent.height
  163. width: UM.Theme.getSize("setting").width + UM.Theme.getSize("default_margin").width
  164. ScrollBar.vertical: UM.ScrollBar { id: scrollBar }
  165. clip: true
  166. spacing: UM.Theme.getSize("default_lining").height
  167. model: UM.SettingDefinitionsModel
  168. {
  169. id: addedSettingsModel
  170. containerId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.definition.id: ""
  171. expanded: ["*"]
  172. filter:
  173. {
  174. if (printSequencePropertyProvider.properties.value === "one_at_a_time")
  175. {
  176. return { settable_per_meshgroup: true }
  177. }
  178. return { settable_per_meshgroup: true }
  179. }
  180. exclude:
  181. {
  182. const excluded_settings = ["support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh"]
  183. if (currentMeshType === "support_mesh")
  184. {
  185. excluded_settings = excluded_settings.concat(base.allCategoriesExceptSupport)
  186. }
  187. return excluded_settings
  188. }
  189. visibilityHandler: Cura.PerObjectSettingVisibilityHandler
  190. {
  191. id: visibility_handler
  192. selectedObjectId: UM.Controller.properties.getValue("SelectedObjectId")
  193. }
  194. // For some reason the model object is updated after removing him from the memory and
  195. // it happens only on Windows. For this reason, set the destroyed value manually.
  196. Component.onDestruction:
  197. {
  198. setDestroyed(true)
  199. }
  200. }
  201. property int indexWithFocus: -1
  202. delegate: Row
  203. {
  204. spacing: UM.Theme.getSize("default_margin").width
  205. property var settingLoaderItem: settingLoader.item
  206. Loader
  207. {
  208. id: settingLoader
  209. width: UM.Theme.getSize("setting").width - removeButton.width - scrollBar.width
  210. enabled: provider.properties.enabled === "True"
  211. property var definition: model
  212. property var settingDefinitionsModel: addedSettingsModel
  213. property var propertyProvider: provider
  214. property var globalPropertyProvider: inheritStackProvider
  215. property var externalResetHandler: false
  216. //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
  217. //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
  218. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
  219. asynchronous: model.type !== "enum" && model.type !== "extruder"
  220. onLoaded:
  221. {
  222. settingLoader.item.showRevertButton = false
  223. settingLoader.item.showInheritButton = false
  224. settingLoader.item.showLinkedSettingIcon = false
  225. settingLoader.item.doDepthIndentation = false
  226. settingLoader.item.doQualityUserSettingEmphasis = false
  227. settingLoader.item.height = UM.Theme.getSize("setting").height + UM.Theme.getSize("narrow_margin").height
  228. }
  229. sourceComponent:
  230. {
  231. switch(model.type)
  232. {
  233. case "int":
  234. return settingTextField
  235. case "[int]":
  236. return settingTextField
  237. case "float":
  238. return settingTextField
  239. case "enum":
  240. return settingComboBox
  241. case "extruder":
  242. return settingExtruder
  243. case "optional_extruder":
  244. return settingOptionalExtruder
  245. case "bool":
  246. return settingCheckBox
  247. case "str":
  248. return settingTextField
  249. case "category":
  250. return settingCategory
  251. default:
  252. return settingUnknown
  253. }
  254. }
  255. }
  256. Button
  257. {
  258. id: removeButton
  259. width: UM.Theme.getSize("setting").height
  260. height: UM.Theme.getSize("setting").height + UM.Theme.getSize("narrow_margin").height
  261. onClicked: addedSettingsModel.setVisible(model.key, false)
  262. background: Item
  263. {
  264. UM.ColorImage
  265. {
  266. anchors.verticalCenter: parent.verticalCenter
  267. width: parent.width
  268. height: width
  269. color: parent.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button")
  270. source: UM.Theme.getIcon("Minus")
  271. }
  272. }
  273. }
  274. // Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
  275. // so we bypass that to make a dedicated provider).
  276. UM.SettingPropertyProvider
  277. {
  278. id: provider
  279. containerStackId: UM.Controller.properties.getValue("ContainerID")
  280. key: model.key
  281. watchedProperties: [ "value", "enabled", "validationState" ]
  282. storeIndex: 0
  283. removeUnusedValue: false
  284. }
  285. UM.SettingPropertyProvider
  286. {
  287. id: inheritStackProvider
  288. containerStackId: UM.Controller.properties.getValue("ContainerID")
  289. key: model.key
  290. watchedProperties: [ "limit_to_extruder" ]
  291. }
  292. Connections
  293. {
  294. target: inheritStackProvider
  295. function onPropertiesChanged() { provider.forcePropertiesChanged() }
  296. }
  297. Connections
  298. {
  299. target: settingLoader.item
  300. function onFocusReceived()
  301. {
  302. contents.indexWithFocus = index
  303. contents.positionViewAtIndex(index, ListView.Contain)
  304. }
  305. function onSetActiveFocusToNextSetting(forward)
  306. {
  307. if (forward == undefined || forward)
  308. {
  309. contents.currentIndex = contents.indexWithFocus + 1
  310. while(contents.currentItem && contents.currentItem.height <= 0)
  311. {
  312. contents.currentIndex++
  313. }
  314. if (contents.currentItem)
  315. {
  316. contents.currentItem.settingLoaderItem.focusItem.forceActiveFocus()
  317. }
  318. }
  319. else
  320. {
  321. contents.currentIndex = contents.indexWithFocus - 1
  322. while(contents.currentItem && contents.currentItem.height <= 0)
  323. {
  324. contents.currentIndex--
  325. }
  326. if (contents.currentItem)
  327. {
  328. contents.currentItem.settingLoaderItem.focusItem.forceActiveFocus()
  329. }
  330. }
  331. }
  332. }
  333. Connections
  334. {
  335. target: UM.Controller
  336. function onPropertiesChanged()
  337. {
  338. // the values cannot be bound with UM.Controller.properties.getValue() calls,
  339. // so here we connect to the signal and update the those values.
  340. if (typeof UM.Controller.properties.getValue("SelectedObjectId") !== "undefined")
  341. {
  342. const selectedObjectId = UM.Controller.properties.getValue("SelectedObjectId")
  343. if (addedSettingsModel.visibilityHandler.selectedObjectId != selectedObjectId)
  344. {
  345. addedSettingsModel.visibilityHandler.selectedObjectId = selectedObjectId
  346. }
  347. }
  348. if (typeof UM.Controller.properties.getValue("ContainerID") !== "undefined")
  349. {
  350. const containerId = UM.Controller.properties.getValue("ContainerID")
  351. if (provider.containerStackId !== containerId)
  352. {
  353. provider.containerStackId = containerId
  354. }
  355. if (inheritStackProvider.containerStackId !== containerId)
  356. {
  357. inheritStackProvider.containerStackId = containerId
  358. }
  359. }
  360. }
  361. }
  362. }
  363. }
  364. }
  365. Cura.SecondaryButton
  366. {
  367. id: customiseSettingsButton;
  368. height: UM.Theme.getSize("setting_control").height;
  369. visible: currentSettings.visible
  370. text: catalog.i18nc("@action:button", "Select settings");
  371. onClicked:
  372. {
  373. settingPickDialog.visible = true;
  374. if (currentMeshType === "support_mesh")
  375. {
  376. settingPickDialog.additional_excluded_settings = base.allCategoriesExceptSupport;
  377. }
  378. else
  379. {
  380. settingPickDialog.additional_excluded_settings = [];
  381. }
  382. }
  383. }
  384. }
  385. SettingPickDialog
  386. {
  387. id: settingPickDialog
  388. }
  389. UM.SettingPropertyProvider
  390. {
  391. id: machineExtruderCount
  392. containerStack: Cura.MachineManager.activeMachine
  393. key: "machine_extruder_count"
  394. watchedProperties: ["value"]
  395. storeIndex: 0
  396. }
  397. UM.SettingPropertyProvider
  398. {
  399. id: printSequencePropertyProvider
  400. containerStack: Cura.MachineManager.activeMachine
  401. key: "print_sequence"
  402. watchedProperties: ["value"]
  403. storeIndex: 0
  404. }
  405. Component { id: settingTextField; Cura.SettingTextField { } }
  406. Component { id: settingComboBox; Cura.SettingComboBox { } }
  407. Component { id: settingExtruder; Cura.SettingExtruder { } }
  408. Component { id: settingOptionalExtruder; Cura.SettingOptionalExtruder { } }
  409. Component { id: settingCheckBox; Cura.SettingCheckBox { } }
  410. Component { id: settingCategory; Cura.SettingCategory { } }
  411. Component { id: settingUnknown; Cura.SettingUnknown { } }
  412. }