SettingView.qml 25 KB

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