SettingView.qml 18 KB

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