SettingView.qml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Uranium is released under the terms of the LGPLv3 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. 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: UM.Theme.getSize("sidebar_margin").width
  27. right: parent.right
  28. rightMargin: 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 = catalog.i18nc("@", "No Profile Available") // default text
  56. if (Cura.MachineManager.isActiveQualitySupported ) {
  57. result = Cura.MachineManager.activeQualityName
  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.floor(parent.height * 0.6)
  72. width: Math.floor(parent.height * 0.6)
  73. anchors.verticalCenter: parent.verticalCenter
  74. anchors.right: parent.right
  75. anchors.rightMargin: 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. Rectangle
  93. {
  94. id: filterContainer
  95. visible: true
  96. border.width: UM.Theme.getSize("default_lining").width
  97. border.color:
  98. {
  99. if(hoverMouseArea.containsMouse || clearFilterButton.containsMouse)
  100. {
  101. return UM.Theme.getColor("setting_control_border_highlight");
  102. }
  103. else
  104. {
  105. return UM.Theme.getColor("setting_control_border");
  106. }
  107. }
  108. color: UM.Theme.getColor("setting_control")
  109. anchors
  110. {
  111. top: globalProfileRow.bottom
  112. topMargin: UM.Theme.getSize("sidebar_margin").height
  113. left: parent.left
  114. leftMargin: UM.Theme.getSize("sidebar_margin").width
  115. right: parent.right
  116. rightMargin: UM.Theme.getSize("sidebar_margin").width
  117. }
  118. height: visible ? UM.Theme.getSize("setting_control").height : 0
  119. Behavior on height { NumberAnimation { duration: 100 } }
  120. TextField
  121. {
  122. id: filter;
  123. anchors.left: parent.left
  124. anchors.right: clearFilterButton.left
  125. anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
  126. placeholderText: catalog.i18nc("@label:textbox", "Search...")
  127. style: TextFieldStyle
  128. {
  129. textColor: UM.Theme.getColor("setting_control_text");
  130. placeholderTextColor: UM.Theme.getColor("setting_control_text")
  131. font: UM.Theme.getFont("default");
  132. background: Item {}
  133. }
  134. property var expandedCategories
  135. property bool lastFindingSettings: false
  136. onTextChanged:
  137. {
  138. definitionsModel.filter = {"i18n_label": "*" + text};
  139. findingSettings = (text.length > 0);
  140. if(findingSettings != lastFindingSettings)
  141. {
  142. if(findingSettings)
  143. {
  144. expandedCategories = definitionsModel.expanded.slice();
  145. definitionsModel.expanded = ["*"];
  146. definitionsModel.showAncestors = true;
  147. definitionsModel.showAll = true;
  148. }
  149. else
  150. {
  151. definitionsModel.expanded = expandedCategories;
  152. definitionsModel.showAncestors = false;
  153. definitionsModel.showAll = false;
  154. }
  155. lastFindingSettings = findingSettings;
  156. }
  157. }
  158. Keys.onEscapePressed:
  159. {
  160. filter.text = "";
  161. }
  162. }
  163. MouseArea
  164. {
  165. id: hoverMouseArea
  166. anchors.fill: parent
  167. hoverEnabled: true
  168. acceptedButtons: Qt.NoButton
  169. cursorShape: Qt.IBeamCursor
  170. }
  171. UM.SimpleButton
  172. {
  173. id: clearFilterButton
  174. iconSource: UM.Theme.getIcon("cross1")
  175. visible: findingSettings
  176. height: parent.height * 0.4
  177. width: visible ? height : 0
  178. anchors.verticalCenter: parent.verticalCenter
  179. anchors.right: parent.right
  180. anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
  181. color: UM.Theme.getColor("setting_control_button")
  182. hoverColor: UM.Theme.getColor("setting_control_button_hover")
  183. onClicked:
  184. {
  185. filter.text = "";
  186. filter.forceActiveFocus();
  187. }
  188. }
  189. }
  190. ScrollView
  191. {
  192. anchors.top: filterContainer.bottom;
  193. anchors.bottom: parent.bottom;
  194. anchors.right: parent.right;
  195. anchors.left: parent.left;
  196. anchors.topMargin: filterContainer.visible ? UM.Theme.getSize("sidebar_margin").height : 0
  197. Behavior on anchors.topMargin { NumberAnimation { duration: 100 } }
  198. style: UM.Theme.styles.scrollview;
  199. flickableItem.flickableDirection: Flickable.VerticalFlick;
  200. __wheelAreaScrollSpeed: 75; // Scroll three lines in one scroll event
  201. ListView
  202. {
  203. id: contents
  204. spacing: UM.Theme.getSize("default_lining").height;
  205. cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item.
  206. model: UM.SettingDefinitionsModel
  207. {
  208. id: definitionsModel;
  209. containerId: Cura.MachineManager.activeDefinitionId
  210. visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
  211. 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.
  212. expanded: CuraApplication.expandedCategories
  213. onExpandedChanged:
  214. {
  215. if(!findingSettings)
  216. {
  217. // Do not change expandedCategories preference while filtering settings
  218. // because all categories are expanded while filtering
  219. CuraApplication.setExpandedCategories(expanded)
  220. }
  221. }
  222. onVisibilityChanged: Cura.SettingInheritanceManager.forceUpdate()
  223. }
  224. property var indexWithFocus: -1
  225. delegate: Loader
  226. {
  227. id: delegate
  228. width: UM.Theme.getSize("sidebar").width;
  229. height: provider.properties.enabled == "True" ? UM.Theme.getSize("section").height : - contents.spacing
  230. Behavior on height { NumberAnimation { duration: 100 } }
  231. opacity: provider.properties.enabled == "True" ? 1 : 0
  232. Behavior on opacity { NumberAnimation { duration: 100 } }
  233. enabled:
  234. {
  235. if(!ExtruderManager.activeExtruderStackId && machineExtruderCount.properties.value > 1)
  236. {
  237. // disable all controls on the global tab, except categories
  238. return model.type == "category"
  239. }
  240. return provider.properties.enabled == "True"
  241. }
  242. property var definition: model
  243. property var settingDefinitionsModel: definitionsModel
  244. property var propertyProvider: provider
  245. property var globalPropertyProvider: inheritStackProvider
  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 || machineExtruderCount.properties.value == 1)
  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 ExtruderManager.extruderIds[String(inheritStackProvider.properties.limit_to_extruder)];
  301. }
  302. if(ExtruderManager.activeExtruderStackId)
  303. {
  304. //We're on an extruder tab. Pick the current extruder.
  305. return 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: 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. }