SettingView.qml 22 KB

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