SettingView.qml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Uranium is released under the terms of the AGPLv3 or higher.
  3. import QtQuick 2.2
  4. import QtQuick.Controls 1.1
  5. import QtQuick.Controls.Styles 1.1
  6. import QtQuick.Layouts 1.1
  7. import UM 1.2 as UM
  8. import Cura 1.0 as Cura
  9. Item
  10. {
  11. id: base;
  12. property Action configureSettings;
  13. property bool findingSettings;
  14. signal showTooltip(Item item, point location, string text);
  15. signal hideTooltip();
  16. Rectangle
  17. {
  18. id: filterContainer
  19. visible: true
  20. border.width: UM.Theme.getSize("default_lining").width
  21. border.color:
  22. {
  23. if(hoverMouseArea.containsMouse || clearFilterButton.containsMouse)
  24. {
  25. return UM.Theme.getColor("setting_control_border_highlight");
  26. }
  27. else
  28. {
  29. return UM.Theme.getColor("setting_control_border");
  30. }
  31. }
  32. color: UM.Theme.getColor("setting_control")
  33. anchors
  34. {
  35. top: parent.top
  36. left: parent.left
  37. leftMargin: UM.Theme.getSize("sidebar_margin").width
  38. right: parent.right
  39. rightMargin: UM.Theme.getSize("sidebar_margin").width
  40. }
  41. height: visible ? UM.Theme.getSize("setting_control").height : 0
  42. Behavior on height { NumberAnimation { duration: 100 } }
  43. TextField
  44. {
  45. id: filter;
  46. anchors.left: parent.left
  47. anchors.right: clearFilterButton.left
  48. anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
  49. placeholderText: catalog.i18nc("@label:textbox", "Search...")
  50. style: TextFieldStyle
  51. {
  52. textColor: UM.Theme.getColor("setting_control_text");
  53. placeholderTextColor: UM.Theme.getColor("setting_control_text")
  54. font: UM.Theme.getFont("default");
  55. background: Item {}
  56. }
  57. property var expandedCategories
  58. property bool lastFindingSettings: false
  59. onTextChanged:
  60. {
  61. definitionsModel.filter = {"i18n_label": "*" + text};
  62. findingSettings = (text.length > 0);
  63. if(findingSettings != lastFindingSettings)
  64. {
  65. if(findingSettings)
  66. {
  67. expandedCategories = definitionsModel.expanded.slice();
  68. definitionsModel.expanded = ["*"];
  69. definitionsModel.showAncestors = true;
  70. definitionsModel.showAll = true;
  71. }
  72. else
  73. {
  74. definitionsModel.expanded = expandedCategories;
  75. definitionsModel.showAncestors = false;
  76. definitionsModel.showAll = false;
  77. }
  78. lastFindingSettings = findingSettings;
  79. }
  80. }
  81. Keys.onEscapePressed:
  82. {
  83. filter.text = "";
  84. }
  85. }
  86. MouseArea
  87. {
  88. id: hoverMouseArea
  89. anchors.fill: parent
  90. hoverEnabled: true
  91. acceptedButtons: Qt.NoButton
  92. cursorShape: Qt.IBeamCursor
  93. }
  94. UM.SimpleButton
  95. {
  96. id: clearFilterButton
  97. iconSource: UM.Theme.getIcon("cross1")
  98. visible: findingSettings
  99. height: parent.height * 0.4
  100. width: visible ? height : 0
  101. anchors.verticalCenter: parent.verticalCenter
  102. anchors.right: parent.right
  103. anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
  104. color: UM.Theme.getColor("setting_control_button")
  105. hoverColor: UM.Theme.getColor("setting_control_button_hover")
  106. onClicked:
  107. {
  108. filter.text = "";
  109. filter.forceActiveFocus();
  110. }
  111. }
  112. }
  113. ScrollView
  114. {
  115. anchors.top: filterContainer.bottom;
  116. anchors.bottom: parent.bottom;
  117. anchors.right: parent.right;
  118. anchors.left: parent.left;
  119. anchors.topMargin: filterContainer.visible ? UM.Theme.getSize("sidebar_margin").height : 0
  120. Behavior on anchors.topMargin { NumberAnimation { duration: 100 } }
  121. style: UM.Theme.styles.scrollview;
  122. flickableItem.flickableDirection: Flickable.VerticalFlick;
  123. __wheelAreaScrollSpeed: 75; // Scroll three lines in one scroll event
  124. ListView
  125. {
  126. id: contents
  127. spacing: UM.Theme.getSize("default_lining").height;
  128. cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item.
  129. model: UM.SettingDefinitionsModel
  130. {
  131. id: definitionsModel;
  132. containerId: Cura.MachineManager.activeDefinitionId
  133. visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
  134. 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.
  135. expanded: CuraApplication.expandedCategories
  136. onExpandedChanged:
  137. {
  138. if(!findingSettings)
  139. {
  140. // Do not change expandedCategories preference while filtering settings
  141. // because all categories are expanded while filtering
  142. CuraApplication.setExpandedCategories(expanded)
  143. }
  144. }
  145. onVisibilityChanged: Cura.SettingInheritanceManager.forceUpdate()
  146. }
  147. property var indexWithFocus: -1
  148. delegate: Loader
  149. {
  150. id: delegate
  151. width: UM.Theme.getSize("sidebar").width;
  152. height: provider.properties.enabled == "True" ? UM.Theme.getSize("section").height : - contents.spacing
  153. Behavior on height { NumberAnimation { duration: 100 } }
  154. opacity: provider.properties.enabled == "True" ? 1 : 0
  155. Behavior on opacity { NumberAnimation { duration: 100 } }
  156. enabled:
  157. {
  158. if(!ExtruderManager.activeExtruderStackId && machineExtruderCount.properties.value > 1)
  159. {
  160. // disable all controls on the global tab, except categories
  161. return model.type == "category"
  162. }
  163. return provider.properties.enabled == "True"
  164. }
  165. property var definition: model
  166. property var settingDefinitionsModel: definitionsModel
  167. property var propertyProvider: provider
  168. property var globalPropertyProvider: inheritStackProvider
  169. //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
  170. //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
  171. //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
  172. asynchronous: model.type != "enum" && model.type != "extruder" && model.type != "optional_extruder"
  173. active: model.type != undefined
  174. source:
  175. {
  176. switch(model.type)
  177. {
  178. case "int":
  179. return "SettingTextField.qml"
  180. case "[int]":
  181. return "SettingTextField.qml"
  182. case "float":
  183. return "SettingTextField.qml"
  184. case "enum":
  185. return "SettingComboBox.qml"
  186. case "extruder":
  187. return "SettingExtruder.qml"
  188. case "bool":
  189. return "SettingCheckBox.qml"
  190. case "str":
  191. return "SettingTextField.qml"
  192. case "category":
  193. return "SettingCategory.qml"
  194. case "optional_extruder":
  195. return "SettingOptionalExtruder.qml"
  196. default:
  197. return "SettingUnknown.qml"
  198. }
  199. }
  200. // Binding to ensure that the right containerstack ID is set for the provider.
  201. // This ensures that if a setting has a limit_to_extruder id (for instance; Support speed points to the
  202. // extruder that actually prints the support, as that is the setting we need to use to calculate the value)
  203. Binding
  204. {
  205. target: provider
  206. property: "containerStackId"
  207. when: model.settable_per_extruder || (inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0);
  208. value:
  209. {
  210. // associate this binding with Cura.MachineManager.activeMachineId in the beginning so this
  211. // binding will be triggered when activeMachineId is changed too.
  212. // Otherwise, if this value only depends on the extruderIds, it won't get updated when the
  213. // machine gets changed.
  214. var activeMachineId = Cura.MachineManager.activeMachineId;
  215. if(!model.settable_per_extruder || machineExtruderCount.properties.value == 1)
  216. {
  217. //Not settable per extruder or there only is global, so we must pick global.
  218. return activeMachineId;
  219. }
  220. if(inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0)
  221. {
  222. //We have limit_to_extruder, so pick that stack.
  223. return ExtruderManager.extruderIds[String(inheritStackProvider.properties.limit_to_extruder)];
  224. }
  225. if(ExtruderManager.activeExtruderStackId)
  226. {
  227. //We're on an extruder tab. Pick the current extruder.
  228. return ExtruderManager.activeExtruderStackId;
  229. }
  230. //No extruder tab is selected. Pick the global stack. Shouldn't happen any more since we removed the global tab.
  231. return activeMachineId;
  232. }
  233. }
  234. // Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
  235. // so we bypass that to make a dedicated provider).
  236. UM.SettingPropertyProvider
  237. {
  238. id: inheritStackProvider
  239. containerStackId: Cura.MachineManager.activeMachineId
  240. key: model.key
  241. watchedProperties: [ "limit_to_extruder" ]
  242. }
  243. UM.SettingPropertyProvider
  244. {
  245. id: provider
  246. containerStackId: Cura.MachineManager.activeMachineId
  247. key: model.key ? model.key : ""
  248. watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
  249. storeIndex: 0
  250. // Due to the way setPropertyValue works, removeUnusedValue gives the correct output in case of resolve
  251. removeUnusedValue: model.resolve == undefined
  252. }
  253. Connections
  254. {
  255. target: item
  256. onContextMenuRequested:
  257. {
  258. contextMenu.key = model.key;
  259. contextMenu.settingVisible = model.visible;
  260. contextMenu.provider = provider
  261. contextMenu.popup();
  262. }
  263. onShowTooltip: base.showTooltip(delegate, { x: -UM.Theme.getSize("default_arrow").width, y: delegate.height / 2 }, text)
  264. onHideTooltip: base.hideTooltip()
  265. onShowAllHiddenInheritedSettings:
  266. {
  267. var children_with_override = Cura.SettingInheritanceManager.getChildrenKeysWithOverride(category_id)
  268. for(var i = 0; i < children_with_override.length; i++)
  269. {
  270. definitionsModel.setVisible(children_with_override[i], true)
  271. }
  272. Cura.SettingInheritanceManager.manualRemoveOverride(category_id)
  273. }
  274. onFocusReceived:
  275. {
  276. contents.indexWithFocus = index;
  277. animateContentY.from = contents.contentY;
  278. contents.positionViewAtIndex(index, ListView.Contain);
  279. animateContentY.to = contents.contentY;
  280. animateContentY.running = true;
  281. }
  282. onSetActiveFocusToNextSetting:
  283. {
  284. if(forward == undefined || forward)
  285. {
  286. contents.currentIndex = contents.indexWithFocus + 1;
  287. while(contents.currentItem && contents.currentItem.height <= 0)
  288. {
  289. contents.currentIndex++;
  290. }
  291. if(contents.currentItem)
  292. {
  293. contents.currentItem.item.focusItem.forceActiveFocus();
  294. }
  295. }
  296. else
  297. {
  298. contents.currentIndex = contents.indexWithFocus - 1;
  299. while(contents.currentItem && contents.currentItem.height <= 0)
  300. {
  301. contents.currentIndex--;
  302. }
  303. if(contents.currentItem)
  304. {
  305. contents.currentItem.item.focusItem.forceActiveFocus();
  306. }
  307. }
  308. }
  309. }
  310. }
  311. UM.I18nCatalog { id: catalog; name: "cura"; }
  312. NumberAnimation {
  313. id: animateContentY
  314. target: contents
  315. property: "contentY"
  316. duration: 50
  317. }
  318. add: Transition {
  319. SequentialAnimation {
  320. NumberAnimation { properties: "height"; from: 0; duration: 100 }
  321. NumberAnimation { properties: "opacity"; from: 0; duration: 100 }
  322. }
  323. }
  324. remove: Transition {
  325. SequentialAnimation {
  326. NumberAnimation { properties: "opacity"; to: 0; duration: 100 }
  327. NumberAnimation { properties: "height"; to: 0; duration: 100 }
  328. }
  329. }
  330. addDisplaced: Transition {
  331. NumberAnimation { properties: "x,y"; duration: 100 }
  332. }
  333. removeDisplaced: Transition {
  334. SequentialAnimation {
  335. PauseAnimation { duration: 100; }
  336. NumberAnimation { properties: "x,y"; duration: 100 }
  337. }
  338. }
  339. Menu
  340. {
  341. id: contextMenu
  342. property string key
  343. property var provider
  344. property bool settingVisible
  345. MenuItem
  346. {
  347. //: Settings context menu action
  348. text: catalog.i18nc("@action:menu", "Copy value to all extruders")
  349. visible: machineExtruderCount.properties.value > 1
  350. enabled: contextMenu.provider != undefined && contextMenu.provider.properties.settable_per_extruder != "False"
  351. onTriggered: Cura.MachineManager.copyValueToExtruders(contextMenu.key)
  352. }
  353. MenuSeparator
  354. {
  355. visible: machineExtruderCount.properties.value > 1
  356. }
  357. MenuItem
  358. {
  359. //: Settings context menu action
  360. visible: !findingSettings;
  361. text: catalog.i18nc("@action:menu", "Hide this setting");
  362. onTriggered: definitionsModel.hide(contextMenu.key);
  363. }
  364. MenuItem
  365. {
  366. //: Settings context menu action
  367. text:
  368. {
  369. if (contextMenu.settingVisible)
  370. {
  371. return catalog.i18nc("@action:menu", "Don't show this setting");
  372. }
  373. else
  374. {
  375. return catalog.i18nc("@action:menu", "Keep this setting visible");
  376. }
  377. }
  378. visible: findingSettings;
  379. onTriggered:
  380. {
  381. if (contextMenu.settingVisible)
  382. {
  383. definitionsModel.hide(contextMenu.key);
  384. }
  385. else
  386. {
  387. definitionsModel.show(contextMenu.key);
  388. }
  389. }
  390. }
  391. MenuItem
  392. {
  393. //: Settings context menu action
  394. text: catalog.i18nc("@action:menu", "Configure setting visiblity...");
  395. onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
  396. }
  397. }
  398. UM.SettingPropertyProvider
  399. {
  400. id: machineExtruderCount
  401. containerStackId: Cura.MachineManager.activeMachineId
  402. key: "machine_extruder_count"
  403. watchedProperties: [ "value" ]
  404. storeIndex: 0
  405. }
  406. }
  407. }
  408. }