SettingView.qml 22 KB

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