SettingView.qml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. // Copyright (c) 2022 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.1
  5. import UM 1.5 as UM
  6. import Cura 1.0 as Cura
  7. import "../Menus"
  8. Item
  9. {
  10. id: settingsView
  11. property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel()
  12. property bool findingSettings
  13. Item
  14. {
  15. id: filterContainer
  16. anchors
  17. {
  18. top: parent.top
  19. left: parent.left
  20. right: settingVisibilityMenu.left
  21. }
  22. height: UM.Theme.getSize("print_setup_big_item").height
  23. Timer
  24. {
  25. id: settingsSearchTimer
  26. onTriggered: filter.editingFinished()
  27. interval: 500
  28. running: false
  29. repeat: false
  30. }
  31. Cura.TextField
  32. {
  33. id: filter
  34. implicitHeight: parent.height
  35. anchors.left: parent.left
  36. anchors.right: parent.right
  37. topPadding: height / 4
  38. leftPadding: searchIcon.width + UM.Theme.getSize("default_margin").width * 2
  39. placeholderText: catalog.i18nc("@label:textbox", "Search settings")
  40. font: UM.Theme.getFont("default_italic")
  41. property var expandedCategories
  42. property bool lastFindingSettings: false
  43. UM.ColorImage
  44. {
  45. id: searchIcon
  46. anchors
  47. {
  48. verticalCenter: parent.verticalCenter
  49. left: parent.left
  50. leftMargin: UM.Theme.getSize("default_margin").width
  51. }
  52. source: UM.Theme.getIcon("Magnifier")
  53. height: UM.Theme.getSize("small_button_icon").height
  54. width: height
  55. color: UM.Theme.getColor("text")
  56. }
  57. onTextChanged: settingsSearchTimer.restart()
  58. onEditingFinished:
  59. {
  60. definitionsModel.filter = {"i18n_label|i18n_description" : "*" + text}
  61. findingSettings = (text.length > 0)
  62. if (findingSettings != lastFindingSettings)
  63. {
  64. updateDefinitionModel()
  65. lastFindingSettings = findingSettings
  66. }
  67. }
  68. Keys.onEscapePressed: filter.text = ""
  69. function updateDefinitionModel()
  70. {
  71. if (findingSettings)
  72. {
  73. expandedCategories = definitionsModel.expanded.slice()
  74. definitionsModel.expanded = [""] // keep categories closed while to prevent render while making settings visible one by one
  75. definitionsModel.showAncestors = true
  76. definitionsModel.showAll = true
  77. definitionsModel.expanded = ["*"]
  78. }
  79. else
  80. {
  81. if (expandedCategories)
  82. {
  83. definitionsModel.expanded = expandedCategories
  84. }
  85. definitionsModel.showAncestors = false
  86. definitionsModel.showAll = false
  87. }
  88. }
  89. }
  90. UM.SimpleButton
  91. {
  92. id: clearFilterButton
  93. iconSource: UM.Theme.getIcon("Cancel")
  94. visible: findingSettings
  95. height: Math.round(parent.height * 0.4)
  96. width: visible ? height : 0
  97. anchors.verticalCenter: parent.verticalCenter
  98. anchors.right: parent.right
  99. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  100. color: UM.Theme.getColor("setting_control_button")
  101. hoverColor: UM.Theme.getColor("setting_control_button_hover")
  102. onClicked:
  103. {
  104. filter.text = ""
  105. filter.forceActiveFocus()
  106. }
  107. }
  108. }
  109. SettingVisibilityPresetsMenu
  110. {
  111. id: settingVisibilityPresetsMenu
  112. onCollapseAllCategories:
  113. {
  114. settingsSearchTimer.stop()
  115. filter.text = "" // clear search field
  116. filter.editingFinished()
  117. definitionsModel.collapseAllCategories()
  118. }
  119. }
  120. UM.BurgerButton
  121. {
  122. id: settingVisibilityMenu
  123. anchors
  124. {
  125. verticalCenter: filterContainer.verticalCenter
  126. right: parent.right
  127. }
  128. onClicked:
  129. {
  130. settingVisibilityPresetsMenu.popup(
  131. popupContainer,
  132. -settingVisibilityPresetsMenu.width + UM.Theme.getSize("default_margin").width,
  133. settingVisibilityMenu.height
  134. )
  135. }
  136. }
  137. Item
  138. {
  139. // Work around to prevent the buttom from being rescaled if a popup is attached
  140. id: popupContainer
  141. anchors.bottom: settingVisibilityMenu.bottom
  142. anchors.right: settingVisibilityMenu.right
  143. }
  144. // Mouse area that gathers the scroll events to not propagate it to the main view.
  145. MouseArea
  146. {
  147. anchors.fill: contents
  148. acceptedButtons: Qt.AllButtons
  149. onWheel: (wheel) => { wheel.accepted = true }
  150. }
  151. ListView
  152. {
  153. id: contents
  154. maximumFlickVelocity: 1000 * screenScaleFactor
  155. anchors
  156. {
  157. top: filterContainer.bottom
  158. topMargin: UM.Theme.getSize("default_margin").height
  159. bottom: parent.bottom
  160. right: parent.right
  161. left: parent.left
  162. }
  163. clip: true
  164. cacheBuffer: 1000000 // Set a large cache to effectively just cache every list item.
  165. ScrollBar.vertical: UM.ScrollBar
  166. {
  167. id: scrollBar
  168. onPositionChanged: {
  169. // This removes focus from items when scrolling.
  170. // This fixes comboboxes staying open and scrolling container
  171. if (!activeFocus && !filter.activeFocus) {
  172. forceActiveFocus();
  173. }
  174. }
  175. }
  176. model: UM.SettingDefinitionsModel
  177. {
  178. id: definitionsModel
  179. containerId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.definition.id: ""
  180. visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
  181. exclude: ["machine_settings", "command_line_settings", "infill_mesh", "infill_mesh_order", "cutting_mesh", "support_mesh", "anti_overhang_mesh"] // TODO: infill_mesh settings are excluded hardcoded, but should be based on the fact that settable_globally, settable_per_meshgroup and settable_per_extruder are false.
  182. expanded: CuraApplication.expandedCategories
  183. onExpandedChanged:
  184. {
  185. if (!findingSettings)
  186. {
  187. // Do not change expandedCategories preference while filtering settings
  188. // because all categories are expanded while filtering
  189. CuraApplication.setExpandedCategories(expanded)
  190. }
  191. }
  192. onVisibilityChanged: Cura.SettingInheritanceManager.scheduleUpdate()
  193. }
  194. property int indexWithFocus: -1
  195. property string activeMachineId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.id : ""
  196. delegate: Loader
  197. {
  198. id: delegate
  199. width: contents.width - (scrollBar.width + UM.Theme.getSize("narrow_margin").width)
  200. opacity: enabled ? 1 : 0
  201. enabled: provider.properties.enabled === "True"
  202. property var definition: model
  203. property var settingDefinitionsModel: definitionsModel
  204. property var propertyProvider: provider
  205. property var globalPropertyProvider: inheritStackProvider
  206. property bool externalResetHandler: false
  207. //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
  208. //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
  209. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
  210. asynchronous: model.type !== "enum" && model.type !== "extruder" && model.type !== "optional_extruder"
  211. active: model.type !== undefined
  212. source:
  213. {
  214. switch(model.type)
  215. {
  216. case "int":
  217. return "SettingTextField.qml"
  218. case "[int]":
  219. return "SettingTextField.qml"
  220. case "float":
  221. return "SettingTextField.qml"
  222. case "enum":
  223. return "SettingComboBox.qml"
  224. case "extruder":
  225. return "SettingExtruder.qml"
  226. case "bool":
  227. return "SettingCheckBox.qml"
  228. case "str":
  229. return "SettingTextField.qml"
  230. case "category":
  231. return "SettingCategory.qml"
  232. case "optional_extruder":
  233. return "SettingOptionalExtruder.qml"
  234. default:
  235. return "SettingUnknown.qml"
  236. }
  237. }
  238. // Binding to ensure that the right containerstack ID is set for the provider.
  239. // This ensures that if a setting has a limit_to_extruder id (for instance; Support speed points to the
  240. // extruder that actually prints the support, as that is the setting we need to use to calculate the value)
  241. Binding
  242. {
  243. target: provider
  244. property: "containerStackId"
  245. when: model.settable_per_extruder || (inheritStackProvider.properties.limit_to_extruder !== undefined && inheritStackProvider.properties.limit_to_extruder >= 0);
  246. value:
  247. {
  248. // Associate this binding with Cura.MachineManager.activeMachine.id in the beginning so this
  249. // binding will be triggered when activeMachineId is changed too.
  250. // Otherwise, if this value only depends on the extruderIds, it won't get updated when the
  251. // machine gets changed.
  252. if (!model.settable_per_extruder)
  253. {
  254. //Not settable per extruder or there only is global, so we must pick global.
  255. return contents.activeMachineId
  256. }
  257. if (inheritStackProvider.properties.limit_to_extruder !== undefined && inheritStackProvider.properties.limit_to_extruder >= 0)
  258. {
  259. //We have limit_to_extruder, so pick that stack.
  260. return Cura.ExtruderManager.extruderIds[inheritStackProvider.properties.limit_to_extruder]
  261. }
  262. if (Cura.ExtruderManager.activeExtruderStackId)
  263. {
  264. //We're on an extruder tab. Pick the current extruder.
  265. return Cura.ExtruderManager.activeExtruderStackId
  266. }
  267. //No extruder tab is selected. Pick the global stack. Shouldn't happen any more since we removed the global tab.
  268. return contents.activeMachineId
  269. }
  270. }
  271. // Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
  272. // so we bypass that to make a dedicated provider).
  273. UM.SettingPropertyProvider
  274. {
  275. id: inheritStackProvider
  276. containerStackId: contents.activeMachineId
  277. key: model.key
  278. watchedProperties: [ "limit_to_extruder" ]
  279. }
  280. UM.SettingPropertyProvider
  281. {
  282. id: provider
  283. containerStackId: contents.activeMachineId
  284. key: model.key
  285. watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
  286. storeIndex: 0
  287. removeUnusedValue: model.resolve === undefined
  288. }
  289. Connections
  290. {
  291. target: item
  292. function onContextMenuRequested()
  293. {
  294. contextMenu.key = model.key
  295. contextMenu.settingVisible = model.visible
  296. contextMenu.provider = provider
  297. contextMenu.popup() //iconName: model.icon_name
  298. }
  299. function onShowTooltip(text) { base.showTooltip(delegate, Qt.point(-settingsView.x - UM.Theme.getSize("default_margin").width, 0), text) }
  300. function onHideTooltip() { base.hideTooltip() }
  301. function onShowAllHiddenInheritedSettings(category_id)
  302. {
  303. var children_with_override = Cura.SettingInheritanceManager.getChildrenKeysWithOverride(category_id)
  304. for(var i = 0; i < children_with_override.length; i++)
  305. {
  306. definitionsModel.setVisible(children_with_override[i], true)
  307. }
  308. Cura.SettingInheritanceManager.manualRemoveOverride(category_id)
  309. }
  310. function onFocusReceived()
  311. {
  312. contents.indexWithFocus = index
  313. contents.positionViewAtIndex(index, ListView.Contain)
  314. }
  315. function onSetActiveFocusToNextSetting(forward)
  316. {
  317. if (forward == undefined || forward)
  318. {
  319. contents.currentIndex = contents.indexWithFocus + 1
  320. while(contents.currentItem && contents.currentItem.height <= 0)
  321. {
  322. contents.currentIndex++
  323. }
  324. if (contents.currentItem)
  325. {
  326. contents.currentItem.item.focusItem.forceActiveFocus()
  327. }
  328. }
  329. else
  330. {
  331. contents.currentIndex = contents.indexWithFocus - 1
  332. while(contents.currentItem && contents.currentItem.height <= 0)
  333. {
  334. contents.currentIndex--
  335. }
  336. if (contents.currentItem)
  337. {
  338. contents.currentItem.item.focusItem.forceActiveFocus()
  339. }
  340. }
  341. }
  342. }
  343. }
  344. Cura.Menu
  345. {
  346. id: contextMenu
  347. property string key
  348. property var provider
  349. property bool settingVisible
  350. Cura.MenuItem
  351. {
  352. //: Settings context menu action
  353. text: catalog.i18nc("@action:menu", "Copy value to all extruders")
  354. visible: machineExtruderCount.properties.value > 1
  355. enabled: contextMenu.provider !== undefined && contextMenu.provider.properties.settable_per_extruder !== "False"
  356. onTriggered: Cura.MachineManager.copyValueToExtruders(contextMenu.key)
  357. }
  358. Cura.MenuItem
  359. {
  360. //: Settings context menu action
  361. text: catalog.i18nc("@action:menu", "Copy all changed values to all extruders")
  362. visible: machineExtruderCount.properties.value > 1
  363. enabled: contextMenu.provider !== undefined
  364. onTriggered: Cura.MachineManager.copyAllValuesToExtruders()
  365. }
  366. Cura.MenuSeparator
  367. {
  368. visible: machineExtruderCount.properties.value > 1
  369. }
  370. Instantiator
  371. {
  372. id: customMenuItems
  373. model: Cura.SidebarCustomMenuItemsModel { }
  374. Cura.MenuItem
  375. {
  376. text: model.name
  377. onTriggered:
  378. {
  379. customMenuItems.model.callMenuItemMethod(name, model.actions, {"key": contextMenu.key})
  380. }
  381. }
  382. onObjectAdded: contextMenu.insertItem(index, object)
  383. onObjectRemoved: contextMenu.removeItem(object)
  384. }
  385. Cura.MenuSeparator
  386. {
  387. visible: customMenuItems.count > 0
  388. }
  389. Cura.MenuItem
  390. {
  391. //: Settings context menu action
  392. visible: !findingSettings
  393. text: catalog.i18nc("@action:menu", "Hide this setting")
  394. onTriggered:
  395. {
  396. definitionsModel.hide(contextMenu.key)
  397. }
  398. }
  399. Cura.MenuItem
  400. {
  401. //: Settings context menu action
  402. text:
  403. {
  404. if (contextMenu.settingVisible)
  405. {
  406. return catalog.i18nc("@action:menu", "Don't show this setting")
  407. }
  408. else
  409. {
  410. return catalog.i18nc("@action:menu", "Keep this setting visible")
  411. }
  412. }
  413. visible: findingSettings
  414. onTriggered:
  415. {
  416. if (contextMenu.settingVisible)
  417. {
  418. definitionsModel.hide(contextMenu.key)
  419. }
  420. else
  421. {
  422. definitionsModel.show(contextMenu.key)
  423. }
  424. }
  425. }
  426. Cura.MenuItem
  427. {
  428. //: Settings context menu action
  429. text: catalog.i18nc("@action:menu", "Configure setting visibility...")
  430. onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu)
  431. }
  432. }
  433. UM.SettingPropertyProvider
  434. {
  435. id: machineExtruderCount
  436. containerStackId: Cura.MachineManager.activeMachine !== null ? Cura.MachineManager.activeMachine.id : ""
  437. key: "machine_extruder_count"
  438. watchedProperties: [ "value" ]
  439. storeIndex: 0
  440. }
  441. }
  442. }