RecommendedQualityProfileSelector.qml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // Copyright (c) 2018 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.7
  4. import QtQuick.Controls 1.4
  5. import QtQuick.Controls.Styles 1.4
  6. import UM 1.2 as UM
  7. import Cura 1.0 as Cura
  8. //
  9. // Quality profile
  10. //
  11. Item
  12. {
  13. id: qualityRow
  14. height: childrenRect.height
  15. property real labelColumnWidth: Math.round(width / 3)
  16. property real settingsColumnWidth: width - labelColumnWidth
  17. Timer
  18. {
  19. id: qualitySliderChangeTimer
  20. interval: 50
  21. running: false
  22. repeat: false
  23. onTriggered:
  24. {
  25. var item = Cura.QualityProfilesDropDownMenuModel.getItem(qualitySlider.value);
  26. Cura.MachineManager.activeQualityGroup = item.quality_group;
  27. }
  28. }
  29. Component.onCompleted: qualityModel.update()
  30. Connections
  31. {
  32. target: Cura.QualityProfilesDropDownMenuModel
  33. onItemsChanged: qualityModel.update()
  34. }
  35. Connections {
  36. target: base
  37. onVisibleChanged:
  38. {
  39. // update needs to be called when the widgets are visible, otherwise the step width calculation
  40. // will fail because the width of an invisible item is 0.
  41. if (visible)
  42. {
  43. qualityModel.update();
  44. }
  45. }
  46. }
  47. ListModel
  48. {
  49. id: qualityModel
  50. property var totalTicks: 0
  51. property var availableTotalTicks: 0
  52. property var existingQualityProfile: 0
  53. property var qualitySliderActiveIndex: 0
  54. property var qualitySliderStepWidth: 0
  55. property var qualitySliderAvailableMin: 0
  56. property var qualitySliderAvailableMax: 0
  57. property var qualitySliderMarginRight: 0
  58. function update ()
  59. {
  60. reset()
  61. var availableMin = -1
  62. var availableMax = -1
  63. for (var i = 0; i < Cura.QualityProfilesDropDownMenuModel.rowCount(); i++)
  64. {
  65. var qualityItem = Cura.QualityProfilesDropDownMenuModel.getItem(i)
  66. // Add each quality item to the UI quality model
  67. qualityModel.append(qualityItem)
  68. // Set selected value
  69. if (Cura.MachineManager.activeQualityType == qualityItem.quality_type)
  70. {
  71. // set to -1 when switching to user created profile so all ticks are clickable
  72. if (Cura.MachineManager.hasCustomQuality)
  73. {
  74. qualityModel.qualitySliderActiveIndex = -1
  75. }
  76. else
  77. {
  78. qualityModel.qualitySliderActiveIndex = i
  79. }
  80. qualityModel.existingQualityProfile = 1
  81. }
  82. // Set min available
  83. if (qualityItem.available && availableMin == -1)
  84. {
  85. availableMin = i
  86. }
  87. // Set max available
  88. if (qualityItem.available)
  89. {
  90. availableMax = i
  91. }
  92. }
  93. // Set total available ticks for active slider part
  94. if (availableMin != -1)
  95. {
  96. qualityModel.availableTotalTicks = availableMax - availableMin + 1
  97. }
  98. // Calculate slider values
  99. calculateSliderStepWidth(qualityModel.totalTicks)
  100. calculateSliderMargins(availableMin, availableMax, qualityModel.totalTicks)
  101. qualityModel.qualitySliderAvailableMin = availableMin
  102. qualityModel.qualitySliderAvailableMax = availableMax
  103. }
  104. function calculateSliderStepWidth (totalTicks)
  105. {
  106. // Do not use Math.round otherwise the tickmarks won't be aligned
  107. qualityModel.qualitySliderStepWidth = totalTicks != 0 ?
  108. ((settingsColumnWidth - UM.Theme.getSize("print_setup_slider_handle").width) / (totalTicks)) : 0
  109. }
  110. function calculateSliderMargins (availableMin, availableMax, totalTicks)
  111. {
  112. if (availableMin == -1 || (availableMin == 0 && availableMax == 0))
  113. {
  114. // Do not use Math.round otherwise the tickmarks won't be aligned
  115. qualityModel.qualitySliderMarginRight = settingsColumnWidth
  116. }
  117. else if (availableMin == availableMax)
  118. {
  119. // Do not use Math.round otherwise the tickmarks won't be aligned
  120. qualityModel.qualitySliderMarginRight = (totalTicks - availableMin) * qualitySliderStepWidth
  121. }
  122. else
  123. {
  124. // Do not use Math.round otherwise the tickmarks won't be aligned
  125. qualityModel.qualitySliderMarginRight = (totalTicks - availableMax) * qualitySliderStepWidth
  126. }
  127. }
  128. function reset () {
  129. qualityModel.clear()
  130. qualityModel.availableTotalTicks = 0
  131. qualityModel.existingQualityProfile = 0
  132. // check, the ticks count cannot be less than zero
  133. qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesDropDownMenuModel.rowCount() - 1)
  134. }
  135. }
  136. // Here are the elements that are shown in the left column
  137. Item
  138. {
  139. id: titleRow
  140. width: labelColumnWidth
  141. height: childrenRect.height
  142. Cura.IconWithText
  143. {
  144. id: qualityRowTitle
  145. source: UM.Theme.getIcon("category_layer_height")
  146. text: catalog.i18nc("@label", "Layer Height")
  147. font: UM.Theme.getFont("medium")
  148. anchors.left: parent.left
  149. anchors.right: customisedSettings.left
  150. }
  151. UM.SimpleButton
  152. {
  153. id: customisedSettings
  154. visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.MachineManager.hasCustomQuality
  155. height: visible ? UM.Theme.getSize("print_setup_icon").height : 0
  156. width: height
  157. anchors
  158. {
  159. right: parent.right
  160. rightMargin: UM.Theme.getSize("default_margin").width
  161. leftMargin: UM.Theme.getSize("default_margin").width
  162. verticalCenter: parent.verticalCenter
  163. }
  164. color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button")
  165. iconSource: UM.Theme.getIcon("reset")
  166. onClicked:
  167. {
  168. // if the current profile is user-created, switch to a built-in quality
  169. Cura.MachineManager.resetToUseDefaultQuality()
  170. }
  171. onEntered:
  172. {
  173. var tooltipContent = catalog.i18nc("@tooltip","You have modified some profile settings. If you want to change these go to custom mode.")
  174. base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, 0), tooltipContent)
  175. }
  176. onExited: base.hideTooltip()
  177. }
  178. }
  179. // Show titles for the each quality slider ticks
  180. Item
  181. {
  182. anchors.left: speedSlider.left
  183. anchors.top: speedSlider.bottom
  184. height: childrenRect.height
  185. Repeater
  186. {
  187. model: qualityModel
  188. Label
  189. {
  190. anchors.verticalCenter: parent.verticalCenter
  191. anchors.top: parent.top
  192. // The height has to be set manually, otherwise it's not automatically calculated in the repeater
  193. height: UM.Theme.getSize("default_margin").height
  194. color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesDropDownMenuModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  195. text:
  196. {
  197. var result = ""
  198. if(Cura.MachineManager.activeMachine != null)
  199. {
  200. result = Cura.QualityProfilesDropDownMenuModel.getItem(index).layer_height
  201. if(result == undefined)
  202. {
  203. result = "";
  204. }
  205. else
  206. {
  207. result = Number(Math.round(result + "e+2") + "e-2"); //Round to 2 decimals. Javascript makes this difficult...
  208. if (result == undefined || result != result) //Parse failure.
  209. {
  210. result = "";
  211. }
  212. }
  213. }
  214. return result
  215. }
  216. x:
  217. {
  218. // Make sure the text aligns correctly with each tick
  219. if (qualityModel.totalTicks == 0)
  220. {
  221. // If there is only one tick, align it centrally
  222. return Math.round(((settingsColumnWidth) - width) / 2)
  223. }
  224. else if (index == 0)
  225. {
  226. return Math.round(settingsColumnWidth / qualityModel.totalTicks) * index
  227. }
  228. else if (index == qualityModel.totalTicks)
  229. {
  230. return Math.round(settingsColumnWidth / qualityModel.totalTicks) * index - width
  231. }
  232. else
  233. {
  234. return Math.round((settingsColumnWidth / qualityModel.totalTicks) * index - (width / 2))
  235. }
  236. }
  237. font: UM.Theme.getFont("default")
  238. }
  239. }
  240. }
  241. // Print speed slider
  242. // Two sliders are created, one at the bottom with the unavailable qualities
  243. // and the other at the top with the available quality profiles and so the handle to select them.
  244. Item
  245. {
  246. id: speedSlider
  247. height: childrenRect.height
  248. anchors
  249. {
  250. left: titleRow.right
  251. right: parent.right
  252. verticalCenter: titleRow.verticalCenter
  253. }
  254. // Draw unavailable slider
  255. Slider
  256. {
  257. id: unavailableSlider
  258. width: parent.width
  259. height: qualitySlider.height // Same height as the slider that is on top
  260. updateValueWhileDragging : false
  261. tickmarksEnabled: true
  262. minimumValue: 0
  263. // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly
  264. // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available)
  265. maximumValue: qualityModel.totalTicks
  266. stepSize: 1
  267. style: SliderStyle
  268. {
  269. //Draw Unvailable line
  270. groove: Item
  271. {
  272. Rectangle
  273. {
  274. height: UM.Theme.getSize("print_setup_slider_groove").height
  275. width: control.width - UM.Theme.getSize("print_setup_slider_handle").width
  276. anchors.horizontalCenter: parent.horizontalCenter
  277. anchors.verticalCenter: parent.verticalCenter
  278. color: UM.Theme.getColor("quality_slider_unavailable")
  279. }
  280. }
  281. handle: Item {}
  282. tickmarks: Repeater
  283. {
  284. id: qualityRepeater
  285. model: qualityModel.totalTicks > 0 ? qualityModel : 0
  286. Rectangle
  287. {
  288. color: Cura.QualityProfilesDropDownMenuModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  289. implicitWidth: UM.Theme.getSize("print_setup_slider_tickmarks").width
  290. implicitHeight: UM.Theme.getSize("print_setup_slider_tickmarks").height
  291. anchors.verticalCenter: parent.verticalCenter
  292. // Do not use Math.round otherwise the tickmarks won't be aligned
  293. x: ((UM.Theme.getSize("print_setup_slider_handle").width / 2) - (implicitWidth / 2) + (qualityModel.qualitySliderStepWidth * index))
  294. radius: Math.round(implicitWidth / 2)
  295. }
  296. }
  297. }
  298. // Create a mouse area on top of the unavailable profiles to show a specific tooltip
  299. MouseArea
  300. {
  301. anchors.fill: parent
  302. hoverEnabled: true
  303. enabled: !Cura.MachineManager.hasCustomQuality
  304. onEntered:
  305. {
  306. var tooltipContent = catalog.i18nc("@tooltip", "This quality profile is not available for your current material and nozzle configuration. Please change these to enable this quality profile")
  307. base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), tooltipContent)
  308. }
  309. onExited: base.hideTooltip()
  310. }
  311. }
  312. // Draw available slider
  313. Slider
  314. {
  315. id: qualitySlider
  316. width: qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks - 1) + UM.Theme.getSize("print_setup_slider_handle").width
  317. height: UM.Theme.getSize("print_setup_slider_handle").height // The handle is the widest element of the slider
  318. enabled: qualityModel.totalTicks > 0 && !Cura.SimpleModeSettingsManager.isProfileCustomized
  319. visible: qualityModel.availableTotalTicks > 0
  320. updateValueWhileDragging : false
  321. anchors
  322. {
  323. right: parent.right
  324. rightMargin: qualityModel.qualitySliderMarginRight
  325. }
  326. minimumValue: qualityModel.qualitySliderAvailableMin >= 0 ? qualityModel.qualitySliderAvailableMin : 0
  327. // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly
  328. // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available)
  329. maximumValue: qualityModel.qualitySliderAvailableMax >= 1 ? qualityModel.qualitySliderAvailableMax : 1
  330. stepSize: 1
  331. value: qualityModel.qualitySliderActiveIndex
  332. style: SliderStyle
  333. {
  334. // Draw Available line
  335. groove: Item
  336. {
  337. Rectangle
  338. {
  339. height: UM.Theme.getSize("print_setup_slider_groove").height
  340. width: control.width - UM.Theme.getSize("print_setup_slider_handle").width
  341. anchors.verticalCenter: parent.verticalCenter
  342. // Do not use Math.round otherwise the tickmarks won't be aligned
  343. x: UM.Theme.getSize("print_setup_slider_handle").width / 2
  344. color: UM.Theme.getColor("quality_slider_available")
  345. }
  346. }
  347. handle: Rectangle
  348. {
  349. id: qualityhandleButton
  350. color: UM.Theme.getColor("primary")
  351. implicitWidth: UM.Theme.getSize("print_setup_slider_handle").width
  352. implicitHeight: implicitWidth
  353. radius: Math.round(implicitWidth / 2)
  354. visible: !Cura.SimpleModeSettingsManager.isProfileCustomized && !Cura.MachineManager.hasCustomQuality && qualityModel.existingQualityProfile
  355. }
  356. }
  357. onValueChanged:
  358. {
  359. // only change if an active machine is set and the slider is visible at all.
  360. if (Cura.MachineManager.activeMachine != null && visible)
  361. {
  362. // prevent updating during view initializing. Trigger only if the value changed by user
  363. if (qualitySlider.value != qualityModel.qualitySliderActiveIndex && qualityModel.qualitySliderActiveIndex != -1)
  364. {
  365. // start updating with short delay
  366. qualitySliderChangeTimer.start()
  367. }
  368. }
  369. }
  370. // This mouse area is only used to capture the onHover state and don't propagate it to the unavailable mouse area
  371. MouseArea
  372. {
  373. anchors.fill: parent
  374. hoverEnabled: true
  375. acceptedButtons: Qt.NoButton
  376. enabled: !Cura.MachineManager.hasCustomQuality
  377. }
  378. }
  379. // This mouse area will only take the mouse events and show a tooltip when the profile in use is
  380. // a user created profile
  381. MouseArea
  382. {
  383. anchors.fill: parent
  384. hoverEnabled: true
  385. visible: Cura.MachineManager.hasCustomQuality
  386. onEntered:
  387. {
  388. var tooltipContent = catalog.i18nc("@tooltip", "A custom profile is currently active. To enable the quality slider, choose a default quality profile in Custom tab")
  389. base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), tooltipContent)
  390. }
  391. onExited: base.hideTooltip()
  392. }
  393. }
  394. }