SettingView.qml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. // Copyright (c) 2018 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. }
  169. }
  170. // Mouse area that gathers the scroll events to not propagate it to the main view.
  171. MouseArea
  172. {
  173. anchors.fill: scrollView
  174. acceptedButtons: Qt.AllButtons
  175. onWheel: wheel.accepted = true
  176. }
  177. ScrollView
  178. {
  179. id: scrollView
  180. anchors
  181. {
  182. top: filterContainer.bottom
  183. topMargin: UM.Theme.getSize("default_margin").height
  184. bottom: parent.bottom
  185. right: parent.right
  186. left: parent.left
  187. }
  188. style: UM.Theme.styles.scrollview
  189. flickableItem.flickableDirection: Flickable.VerticalFlick
  190. __wheelAreaScrollSpeed: 75 // Scroll three lines in one scroll event
  191. ListView
  192. {
  193. id: contents
  194. spacing: UM.Theme.getSize("default_lining").height
  195. cacheBuffer: 1000000 // Set a large cache to effectively just cache every list item.
  196. model: UM.SettingDefinitionsModel
  197. {
  198. id: definitionsModel
  199. containerId: Cura.MachineManager.activeDefinitionId
  200. visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
  201. 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.
  202. expanded: CuraApplication.expandedCategories
  203. onExpandedChanged:
  204. {
  205. if (!findingSettings)
  206. {
  207. // Do not change expandedCategories preference while filtering settings
  208. // because all categories are expanded while filtering
  209. CuraApplication.setExpandedCategories(expanded)
  210. }
  211. }
  212. onVisibilityChanged: Cura.SettingInheritanceManager.forceUpdate()
  213. }
  214. property var indexWithFocus: -1
  215. delegate: Loader
  216. {
  217. id: delegate
  218. width: scrollView.width
  219. height: provider.properties.enabled == "True" ? UM.Theme.getSize("section").height : - contents.spacing
  220. Behavior on height { NumberAnimation { duration: 100 } }
  221. opacity: provider.properties.enabled == "True" ? 1 : 0
  222. Behavior on opacity { NumberAnimation { duration: 100 } }
  223. enabled:
  224. {
  225. if (!Cura.ExtruderManager.activeExtruderStackId && machineExtruderCount.properties.value > 1)
  226. {
  227. // disable all controls on the global tab, except categories
  228. return model.type == "category"
  229. }
  230. return provider.properties.enabled == "True"
  231. }
  232. property var definition: model
  233. property var settingDefinitionsModel: definitionsModel
  234. property var propertyProvider: provider
  235. property var globalPropertyProvider: inheritStackProvider
  236. property var externalResetHandler: false
  237. //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
  238. //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
  239. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
  240. asynchronous: model.type != "enum" && model.type != "extruder" && model.type != "optional_extruder"
  241. active: model.type != undefined
  242. source:
  243. {
  244. switch(model.type)
  245. {
  246. case "int":
  247. return "SettingTextField.qml"
  248. case "[int]":
  249. return "SettingTextField.qml"
  250. case "float":
  251. return "SettingTextField.qml"
  252. case "enum":
  253. return "SettingComboBox.qml"
  254. case "extruder":
  255. return "SettingExtruder.qml"
  256. case "bool":
  257. return "SettingCheckBox.qml"
  258. case "str":
  259. return "SettingTextField.qml"
  260. case "category":
  261. return "SettingCategory.qml"
  262. case "optional_extruder":
  263. return "SettingOptionalExtruder.qml"
  264. default:
  265. return "SettingUnknown.qml"
  266. }
  267. }
  268. // Binding to ensure that the right containerstack ID is set for the provider.
  269. // This ensures that if a setting has a limit_to_extruder id (for instance; Support speed points to the
  270. // extruder that actually prints the support, as that is the setting we need to use to calculate the value)
  271. Binding
  272. {
  273. target: provider
  274. property: "containerStackId"
  275. when: model.settable_per_extruder || (inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0);
  276. value:
  277. {
  278. // associate this binding with Cura.MachineManager.activeMachineId in the beginning so this
  279. // binding will be triggered when activeMachineId is changed too.
  280. // Otherwise, if this value only depends on the extruderIds, it won't get updated when the
  281. // machine gets changed.
  282. var activeMachineId = Cura.MachineManager.activeMachineId;
  283. if (!model.settable_per_extruder)
  284. {
  285. //Not settable per extruder or there only is global, so we must pick global.
  286. return activeMachineId;
  287. }
  288. if (inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0)
  289. {
  290. //We have limit_to_extruder, so pick that stack.
  291. return Cura.ExtruderManager.extruderIds[String(inheritStackProvider.properties.limit_to_extruder)];
  292. }
  293. if (Cura.ExtruderManager.activeExtruderStackId)
  294. {
  295. //We're on an extruder tab. Pick the current extruder.
  296. return Cura.ExtruderManager.activeExtruderStackId;
  297. }
  298. //No extruder tab is selected. Pick the global stack. Shouldn't happen any more since we removed the global tab.
  299. return activeMachineId;
  300. }
  301. }
  302. // Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
  303. // so we bypass that to make a dedicated provider).
  304. UM.SettingPropertyProvider
  305. {
  306. id: inheritStackProvider
  307. containerStackId: Cura.MachineManager.activeMachineId
  308. key: model.key
  309. watchedProperties: [ "limit_to_extruder" ]
  310. }
  311. UM.SettingPropertyProvider
  312. {
  313. id: provider
  314. containerStackId: Cura.MachineManager.activeMachineId
  315. key: model.key ? model.key : ""
  316. watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
  317. storeIndex: 0
  318. removeUnusedValue: model.resolve == undefined
  319. }
  320. Connections
  321. {
  322. target: item
  323. onContextMenuRequested:
  324. {
  325. contextMenu.key = model.key;
  326. contextMenu.settingVisible = model.visible;
  327. contextMenu.provider = provider
  328. contextMenu.popup();
  329. }
  330. onShowTooltip: base.showTooltip(delegate, Qt.point(- settingsView.x - UM.Theme.getSize("default_margin").width, 0), text)
  331. onHideTooltip: base.hideTooltip()
  332. onShowAllHiddenInheritedSettings:
  333. {
  334. var children_with_override = Cura.SettingInheritanceManager.getChildrenKeysWithOverride(category_id)
  335. for(var i = 0; i < children_with_override.length; i++)
  336. {
  337. definitionsModel.setVisible(children_with_override[i], true)
  338. }
  339. Cura.SettingInheritanceManager.manualRemoveOverride(category_id)
  340. }
  341. onFocusReceived:
  342. {
  343. contents.indexWithFocus = index;
  344. animateContentY.from = contents.contentY;
  345. contents.positionViewAtIndex(index, ListView.Contain);
  346. animateContentY.to = contents.contentY;
  347. animateContentY.running = true;
  348. }
  349. onSetActiveFocusToNextSetting:
  350. {
  351. if (forward == undefined || forward)
  352. {
  353. contents.currentIndex = contents.indexWithFocus + 1;
  354. while(contents.currentItem && contents.currentItem.height <= 0)
  355. {
  356. contents.currentIndex++;
  357. }
  358. if (contents.currentItem)
  359. {
  360. contents.currentItem.item.focusItem.forceActiveFocus();
  361. }
  362. }
  363. else
  364. {
  365. contents.currentIndex = contents.indexWithFocus - 1;
  366. while(contents.currentItem && contents.currentItem.height <= 0)
  367. {
  368. contents.currentIndex--;
  369. }
  370. if (contents.currentItem)
  371. {
  372. contents.currentItem.item.focusItem.forceActiveFocus();
  373. }
  374. }
  375. }
  376. }
  377. }
  378. UM.I18nCatalog { id: catalog; name: "cura"; }
  379. NumberAnimation {
  380. id: animateContentY
  381. target: contents
  382. property: "contentY"
  383. duration: 50
  384. }
  385. add: Transition {
  386. SequentialAnimation {
  387. NumberAnimation { properties: "height"; from: 0; duration: 100 }
  388. NumberAnimation { properties: "opacity"; from: 0; duration: 100 }
  389. }
  390. }
  391. remove: Transition {
  392. SequentialAnimation {
  393. NumberAnimation { properties: "opacity"; to: 0; duration: 100 }
  394. NumberAnimation { properties: "height"; to: 0; duration: 100 }
  395. }
  396. }
  397. addDisplaced: Transition {
  398. NumberAnimation { properties: "x,y"; duration: 100 }
  399. }
  400. removeDisplaced: Transition {
  401. SequentialAnimation {
  402. PauseAnimation { duration: 100; }
  403. NumberAnimation { properties: "x,y"; duration: 100 }
  404. }
  405. }
  406. Menu
  407. {
  408. id: contextMenu
  409. property string key
  410. property var provider
  411. property bool settingVisible
  412. MenuItem
  413. {
  414. //: Settings context menu action
  415. text: catalog.i18nc("@action:menu", "Copy value to all extruders")
  416. visible: machineExtruderCount.properties.value > 1
  417. enabled: contextMenu.provider != undefined && contextMenu.provider.properties.settable_per_extruder != "False"
  418. onTriggered: Cura.MachineManager.copyValueToExtruders(contextMenu.key)
  419. }
  420. MenuItem
  421. {
  422. //: Settings context menu action
  423. text: catalog.i18nc("@action:menu", "Copy all changed values to all extruders")
  424. visible: machineExtruderCount.properties.value > 1
  425. enabled: contextMenu.provider != undefined
  426. onTriggered: Cura.MachineManager.copyAllValuesToExtruders()
  427. }
  428. MenuSeparator
  429. {
  430. visible: machineExtruderCount.properties.value > 1
  431. }
  432. Instantiator
  433. {
  434. id: customMenuItems
  435. model: Cura.SidebarCustomMenuItemsModel { }
  436. MenuItem
  437. {
  438. text: model.name
  439. iconName: model.icon_name
  440. onTriggered:
  441. {
  442. customMenuItems.model.callMenuItemMethod(name, model.actions, {"key": contextMenu.key})
  443. }
  444. }
  445. onObjectAdded: contextMenu.insertItem(index, object)
  446. onObjectRemoved: contextMenu.removeItem(object)
  447. }
  448. MenuSeparator
  449. {
  450. visible: customMenuItems.count > 0
  451. }
  452. MenuItem
  453. {
  454. //: Settings context menu action
  455. visible: !findingSettings
  456. text: catalog.i18nc("@action:menu", "Hide this setting");
  457. onTriggered:
  458. {
  459. definitionsModel.hide(contextMenu.key);
  460. // visible settings have changed, so we're no longer showing a preset
  461. if (settingVisibilityPresetsModel.activePreset != "")
  462. {
  463. settingVisibilityPresetsModel.setActivePreset("custom");
  464. }
  465. }
  466. }
  467. MenuItem
  468. {
  469. //: Settings context menu action
  470. text:
  471. {
  472. if (contextMenu.settingVisible)
  473. {
  474. return catalog.i18nc("@action:menu", "Don't show this setting");
  475. }
  476. else
  477. {
  478. return catalog.i18nc("@action:menu", "Keep this setting visible");
  479. }
  480. }
  481. visible: findingSettings
  482. onTriggered:
  483. {
  484. if (contextMenu.settingVisible)
  485. {
  486. definitionsModel.hide(contextMenu.key);
  487. }
  488. else
  489. {
  490. definitionsModel.show(contextMenu.key);
  491. }
  492. // visible settings have changed, so we're no longer showing a preset
  493. if (settingVisibilityPresetsModel.activePreset != "")
  494. {
  495. settingVisibilityPresetsModel.setActivePreset("custom");
  496. }
  497. }
  498. }
  499. MenuItem
  500. {
  501. //: Settings context menu action
  502. text: catalog.i18nc("@action:menu", "Configure setting visibility...");
  503. onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
  504. }
  505. }
  506. UM.SettingPropertyProvider
  507. {
  508. id: machineExtruderCount
  509. containerStackId: Cura.MachineManager.activeMachineId
  510. key: "machine_extruder_count"
  511. watchedProperties: [ "value" ]
  512. storeIndex: 0
  513. }
  514. }
  515. }
  516. }