SettingView.qml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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. // associate this binding with Cura.MachineManager.activeMachineId in the beginning so this
  210. // binding will be triggered when activeMachineId is changed too.
  211. // Otherwise, if this value only depends on the extruderIds, it won't get updated when the
  212. // machine gets changed.
  213. var activeMachineId = Cura.MachineManager.activeMachineId;
  214. if(!model.settable_per_extruder || machineExtruderCount.properties.value == 1)
  215. {
  216. //Not settable per extruder or there only is global, so we must pick global.
  217. return activeMachineId;
  218. }
  219. if(inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0)
  220. {
  221. //We have limit_to_extruder, so pick that stack.
  222. return ExtruderManager.extruderIds[String(inheritStackProvider.properties.limit_to_extruder)];
  223. }
  224. if(ExtruderManager.activeExtruderStackId)
  225. {
  226. //We're on an extruder tab. Pick the current extruder.
  227. return ExtruderManager.activeExtruderStackId;
  228. }
  229. //No extruder tab is selected. Pick the global stack. Shouldn't happen any more since we removed the global tab.
  230. return activeMachineId;
  231. }
  232. }
  233. // Specialty provider that only watches global_inherits (we cant filter on what property changed we get events
  234. // so we bypass that to make a dedicated provider).
  235. UM.SettingPropertyProvider
  236. {
  237. id: inheritStackProvider
  238. containerStackId: Cura.MachineManager.activeMachineId
  239. key: model.key
  240. watchedProperties: [ "limit_to_extruder" ]
  241. }
  242. UM.SettingPropertyProvider
  243. {
  244. id: provider
  245. containerStackId: Cura.MachineManager.activeMachineId
  246. key: model.key ? model.key : ""
  247. watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
  248. storeIndex: 0
  249. // Due to the way setPropertyValue works, removeUnusedValue gives the correct output in case of resolve
  250. removeUnusedValue: model.resolve == undefined
  251. }
  252. Connections
  253. {
  254. target: item
  255. onContextMenuRequested:
  256. {
  257. contextMenu.key = model.key;
  258. contextMenu.settingVisible = model.visible;
  259. contextMenu.provider = provider
  260. contextMenu.popup();
  261. }
  262. onShowTooltip: base.showTooltip(delegate, { x: 0, y: delegate.height / 2 }, text)
  263. onHideTooltip: base.hideTooltip()
  264. onShowAllHiddenInheritedSettings:
  265. {
  266. var children_with_override = Cura.SettingInheritanceManager.getChildrenKeysWithOverride(category_id)
  267. for(var i = 0; i < children_with_override.length; i++)
  268. {
  269. definitionsModel.setVisible(children_with_override[i], true)
  270. }
  271. Cura.SettingInheritanceManager.manualRemoveOverride(category_id)
  272. }
  273. onFocusReceived:
  274. {
  275. contents.indexWithFocus = index;
  276. animateContentY.from = contents.contentY;
  277. contents.positionViewAtIndex(index, ListView.Contain);
  278. animateContentY.to = contents.contentY;
  279. animateContentY.running = true;
  280. }
  281. onSetActiveFocusToNextSetting:
  282. {
  283. if(forward == undefined || forward)
  284. {
  285. contents.currentIndex = contents.indexWithFocus + 1;
  286. while(contents.currentItem && contents.currentItem.height <= 0)
  287. {
  288. contents.currentIndex++;
  289. }
  290. if(contents.currentItem)
  291. {
  292. contents.currentItem.item.focusItem.forceActiveFocus();
  293. }
  294. }
  295. else
  296. {
  297. contents.currentIndex = contents.indexWithFocus - 1;
  298. while(contents.currentItem && contents.currentItem.height <= 0)
  299. {
  300. contents.currentIndex--;
  301. }
  302. if(contents.currentItem)
  303. {
  304. contents.currentItem.item.focusItem.forceActiveFocus();
  305. }
  306. }
  307. }
  308. }
  309. }
  310. UM.I18nCatalog { id: catalog; name: "cura"; }
  311. NumberAnimation {
  312. id: animateContentY
  313. target: contents
  314. property: "contentY"
  315. duration: 50
  316. }
  317. add: Transition {
  318. SequentialAnimation {
  319. NumberAnimation { properties: "height"; from: 0; duration: 100 }
  320. NumberAnimation { properties: "opacity"; from: 0; duration: 100 }
  321. }
  322. }
  323. remove: Transition {
  324. SequentialAnimation {
  325. NumberAnimation { properties: "opacity"; to: 0; duration: 100 }
  326. NumberAnimation { properties: "height"; to: 0; duration: 100 }
  327. }
  328. }
  329. addDisplaced: Transition {
  330. NumberAnimation { properties: "x,y"; duration: 100 }
  331. }
  332. removeDisplaced: Transition {
  333. SequentialAnimation {
  334. PauseAnimation { duration: 100; }
  335. NumberAnimation { properties: "x,y"; duration: 100 }
  336. }
  337. }
  338. Menu
  339. {
  340. id: contextMenu
  341. property string key
  342. property var provider
  343. property bool settingVisible
  344. MenuItem
  345. {
  346. //: Settings context menu action
  347. text: catalog.i18nc("@action:menu", "Copy value to all extruders")
  348. visible: machineExtruderCount.properties.value > 1
  349. enabled: contextMenu.provider != undefined && contextMenu.provider.properties.settable_per_extruder != "False"
  350. onTriggered: Cura.MachineManager.copyValueToExtruders(contextMenu.key)
  351. }
  352. MenuSeparator
  353. {
  354. visible: machineExtruderCount.properties.value > 1
  355. }
  356. MenuItem
  357. {
  358. //: Settings context menu action
  359. visible: !findingSettings;
  360. text: catalog.i18nc("@action:menu", "Hide this setting");
  361. onTriggered: definitionsModel.hide(contextMenu.key);
  362. }
  363. MenuItem
  364. {
  365. //: Settings context menu action
  366. text:
  367. {
  368. if (contextMenu.settingVisible)
  369. {
  370. return catalog.i18nc("@action:menu", "Don't show this setting");
  371. }
  372. else
  373. {
  374. return catalog.i18nc("@action:menu", "Keep this setting visible");
  375. }
  376. }
  377. visible: findingSettings;
  378. onTriggered:
  379. {
  380. if (contextMenu.settingVisible)
  381. {
  382. definitionsModel.hide(contextMenu.key);
  383. }
  384. else
  385. {
  386. definitionsModel.show(contextMenu.key);
  387. }
  388. }
  389. }
  390. MenuItem
  391. {
  392. //: Settings context menu action
  393. text: catalog.i18nc("@action:menu", "Configure setting visiblity...");
  394. onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
  395. }
  396. }
  397. UM.SettingPropertyProvider
  398. {
  399. id: machineExtruderCount
  400. containerStackId: Cura.MachineManager.activeMachineId
  401. key: "machine_extruder_count"
  402. watchedProperties: [ "value" ]
  403. storeIndex: 0
  404. }
  405. }
  406. }
  407. }