SidebarSimple.qml 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  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 QtQuick.Layouts 1.3
  7. import UM 1.2 as UM
  8. import Cura 1.0 as Cura
  9. Item
  10. {
  11. id: base
  12. signal showTooltip(Item item, point location, string text);
  13. signal hideTooltip();
  14. property Action configureSettings;
  15. property variant minimumPrintTime: PrintInformation.minimumPrintTime;
  16. property variant maximumPrintTime: PrintInformation.maximumPrintTime;
  17. property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1
  18. Component.onCompleted: PrintInformation.enabled = true
  19. Component.onDestruction: PrintInformation.enabled = false
  20. UM.I18nCatalog { id: catalog; name: "cura" }
  21. ScrollView
  22. {
  23. visible: Cura.MachineManager.activeMachineName != "" // If no printers added then the view is invisible
  24. anchors.fill: parent
  25. style: UM.Theme.styles.scrollview
  26. flickableItem.flickableDirection: Flickable.VerticalFlick
  27. Rectangle
  28. {
  29. width: childrenRect.width
  30. height: childrenRect.height
  31. color: UM.Theme.getColor("main_background")
  32. //
  33. // Quality profile
  34. //
  35. Item
  36. {
  37. id: qualityRow
  38. height: UM.Theme.getSize("thick_margin").height
  39. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  40. anchors.left: parent.left
  41. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  42. anchors.right: parent.right
  43. Timer
  44. {
  45. id: qualitySliderChangeTimer
  46. interval: 50
  47. running: false
  48. repeat: false
  49. onTriggered:
  50. {
  51. var item = Cura.QualityProfilesDropDownMenuModel.getItem(qualitySlider.value);
  52. Cura.MachineManager.activeQualityGroup = item.quality_group;
  53. }
  54. }
  55. Component.onCompleted: qualityModel.update()
  56. Connections
  57. {
  58. target: Cura.QualityProfilesDropDownMenuModel
  59. onItemsChanged: qualityModel.update()
  60. }
  61. Connections {
  62. target: base
  63. onVisibleChanged:
  64. {
  65. // update needs to be called when the widgets are visible, otherwise the step width calculation
  66. // will fail because the width of an invisible item is 0.
  67. if (visible)
  68. {
  69. qualityModel.update();
  70. }
  71. }
  72. }
  73. ListModel
  74. {
  75. id: qualityModel
  76. property var totalTicks: 0
  77. property var availableTotalTicks: 0
  78. property var existingQualityProfile: 0
  79. property var qualitySliderActiveIndex: 0
  80. property var qualitySliderStepWidth: 0
  81. property var qualitySliderAvailableMin: 0
  82. property var qualitySliderAvailableMax: 0
  83. property var qualitySliderMarginRight: 0
  84. function update ()
  85. {
  86. reset()
  87. var availableMin = -1
  88. var availableMax = -1
  89. for (var i = 0; i < Cura.QualityProfilesDropDownMenuModel.rowCount(); i++)
  90. {
  91. var qualityItem = Cura.QualityProfilesDropDownMenuModel.getItem(i)
  92. // Add each quality item to the UI quality model
  93. qualityModel.append(qualityItem)
  94. // Set selected value
  95. if (Cura.MachineManager.activeQualityType == qualityItem.quality_type)
  96. {
  97. // set to -1 when switching to user created profile so all ticks are clickable
  98. if (Cura.SimpleModeSettingsManager.isProfileUserCreated)
  99. {
  100. qualityModel.qualitySliderActiveIndex = -1
  101. }
  102. else
  103. {
  104. qualityModel.qualitySliderActiveIndex = i
  105. }
  106. qualityModel.existingQualityProfile = 1
  107. }
  108. // Set min available
  109. if (qualityItem.available && availableMin == -1)
  110. {
  111. availableMin = i
  112. }
  113. // Set max available
  114. if (qualityItem.available)
  115. {
  116. availableMax = i
  117. }
  118. }
  119. // Set total available ticks for active slider part
  120. if (availableMin != -1)
  121. {
  122. qualityModel.availableTotalTicks = availableMax - availableMin + 1
  123. }
  124. // Calculate slider values
  125. calculateSliderStepWidth(qualityModel.totalTicks)
  126. calculateSliderMargins(availableMin, availableMax, qualityModel.totalTicks)
  127. qualityModel.qualitySliderAvailableMin = availableMin
  128. qualityModel.qualitySliderAvailableMax = availableMax
  129. }
  130. function calculateSliderStepWidth (totalTicks)
  131. {
  132. qualityModel.qualitySliderStepWidth = totalTicks != 0 ? Math.round((base.width * 0.55) / (totalTicks)) : 0
  133. }
  134. function calculateSliderMargins (availableMin, availableMax, totalTicks)
  135. {
  136. if (availableMin == -1 || (availableMin == 0 && availableMax == 0))
  137. {
  138. qualityModel.qualitySliderMarginRight = Math.round(base.width * 0.55)
  139. }
  140. else if (availableMin == availableMax)
  141. {
  142. qualityModel.qualitySliderMarginRight = Math.round((totalTicks - availableMin) * qualitySliderStepWidth)
  143. }
  144. else
  145. {
  146. qualityModel.qualitySliderMarginRight = Math.round((totalTicks - availableMax) * qualitySliderStepWidth)
  147. }
  148. }
  149. function reset () {
  150. qualityModel.clear()
  151. qualityModel.availableTotalTicks = 0
  152. qualityModel.existingQualityProfile = 0
  153. // check, the ticks count cannot be less than zero
  154. qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesDropDownMenuModel.rowCount() - 1)
  155. }
  156. }
  157. Label
  158. {
  159. id: qualityRowTitle
  160. text: catalog.i18nc("@label", "Layer Height")
  161. font: UM.Theme.getFont("default")
  162. color: UM.Theme.getColor("text")
  163. }
  164. // Show titles for the each quality slider ticks
  165. Item
  166. {
  167. y: -5;
  168. anchors.left: speedSlider.left
  169. Repeater
  170. {
  171. model: qualityModel
  172. Label
  173. {
  174. anchors.verticalCenter: parent.verticalCenter
  175. anchors.top: parent.top
  176. anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height / 2)
  177. color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesDropDownMenuModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  178. text:
  179. {
  180. var result = ""
  181. if(Cura.MachineManager.activeMachine != null)
  182. {
  183. result = Cura.QualityProfilesDropDownMenuModel.getItem(index).layer_height
  184. if(result == undefined)
  185. {
  186. result = "";
  187. }
  188. else
  189. {
  190. result = Number(Math.round(result + "e+2") + "e-2"); //Round to 2 decimals. Javascript makes this difficult...
  191. if (result == undefined || result != result) //Parse failure.
  192. {
  193. result = "";
  194. }
  195. }
  196. }
  197. return result
  198. }
  199. x:
  200. {
  201. // Make sure the text aligns correctly with each tick
  202. if (qualityModel.totalTicks == 0)
  203. {
  204. // If there is only one tick, align it centrally
  205. return Math.round(((base.width * 0.55) - width) / 2)
  206. }
  207. else if (index == 0)
  208. {
  209. return Math.round(base.width * 0.55 / qualityModel.totalTicks) * index
  210. }
  211. else if (index == qualityModel.totalTicks)
  212. {
  213. return Math.round(base.width * 0.55 / qualityModel.totalTicks) * index - width
  214. }
  215. else
  216. {
  217. return Math.round((base.width * 0.55 / qualityModel.totalTicks) * index - (width / 2))
  218. }
  219. }
  220. }
  221. }
  222. }
  223. //Print speed slider
  224. Item
  225. {
  226. id: speedSlider
  227. width: Math.round(base.width * 0.55)
  228. height: UM.Theme.getSize("thick_margin").height
  229. anchors.right: parent.right
  230. anchors.top: parent.top
  231. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  232. // This Item is used only for tooltip, for slider area which is unavailable
  233. Item
  234. {
  235. function showTooltip (showTooltip)
  236. {
  237. if (showTooltip)
  238. {
  239. var content = catalog.i18nc("@tooltip", "This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile")
  240. base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), content)
  241. }
  242. else
  243. {
  244. base.hideTooltip()
  245. }
  246. }
  247. id: unavailableLineToolTip
  248. height: 20 * screenScaleFactor // hovered area height
  249. z: parent.z + 1 // should be higher, otherwise the area can be hovered
  250. x: 0
  251. anchors.verticalCenter: qualitySlider.verticalCenter
  252. Rectangle
  253. {
  254. id: leftArea
  255. width:
  256. {
  257. if (qualityModel.availableTotalTicks == 0)
  258. {
  259. return qualityModel.qualitySliderStepWidth * qualityModel.totalTicks
  260. }
  261. return qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin - 10
  262. }
  263. height: parent.height
  264. color: "transparent"
  265. MouseArea
  266. {
  267. anchors.fill: parent
  268. hoverEnabled: true
  269. enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false
  270. onEntered: unavailableLineToolTip.showTooltip(true)
  271. onExited: unavailableLineToolTip.showTooltip(false)
  272. }
  273. }
  274. Rectangle
  275. {
  276. id: rightArea
  277. width:
  278. {
  279. if(qualityModel.availableTotalTicks == 0)
  280. return 0
  281. return qualityModel.qualitySliderMarginRight - 10
  282. }
  283. height: parent.height
  284. color: "transparent"
  285. x:
  286. {
  287. if (qualityModel.availableTotalTicks == 0)
  288. {
  289. return 0
  290. }
  291. var leftUnavailableArea = qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin
  292. var totalGap = qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks -1) + leftUnavailableArea + 10
  293. return totalGap
  294. }
  295. MouseArea
  296. {
  297. anchors.fill: parent
  298. hoverEnabled: true
  299. enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false
  300. onEntered: unavailableLineToolTip.showTooltip(true)
  301. onExited: unavailableLineToolTip.showTooltip(false)
  302. }
  303. }
  304. }
  305. // Draw Unavailable line
  306. Rectangle
  307. {
  308. id: groovechildrect
  309. width: Math.round(base.width * 0.55)
  310. height: 2 * screenScaleFactor
  311. color: UM.Theme.getColor("quality_slider_unavailable")
  312. anchors.verticalCenter: qualitySlider.verticalCenter
  313. x: 0
  314. }
  315. // Draw ticks
  316. Repeater
  317. {
  318. id: qualityRepeater
  319. model: qualityModel.totalTicks > 0 ? qualityModel : 0
  320. Rectangle
  321. {
  322. anchors.verticalCenter: parent.verticalCenter
  323. color: Cura.QualityProfilesDropDownMenuModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  324. width: 1 * screenScaleFactor
  325. height: 6 * screenScaleFactor
  326. y: 0
  327. x: Math.round(qualityModel.qualitySliderStepWidth * index)
  328. }
  329. }
  330. Slider
  331. {
  332. id: qualitySlider
  333. height: UM.Theme.getSize("thick_margin").height
  334. anchors.bottom: speedSlider.bottom
  335. enabled: qualityModel.totalTicks > 0 && !Cura.SimpleModeSettingsManager.isProfileCustomized
  336. visible: qualityModel.availableTotalTicks > 0
  337. updateValueWhileDragging : false
  338. minimumValue: qualityModel.qualitySliderAvailableMin >= 0 ? qualityModel.qualitySliderAvailableMin : 0
  339. // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly
  340. // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available)
  341. maximumValue: qualityModel.qualitySliderAvailableMax >= 1 ? qualityModel.qualitySliderAvailableMax : 1
  342. stepSize: 1
  343. value: qualityModel.qualitySliderActiveIndex
  344. width: qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks - 1)
  345. anchors.right: parent.right
  346. anchors.rightMargin: qualityModel.qualitySliderMarginRight
  347. style: SliderStyle
  348. {
  349. //Draw Available line
  350. groove: Rectangle
  351. {
  352. implicitHeight: 2 * screenScaleFactor
  353. color: UM.Theme.getColor("quality_slider_available")
  354. radius: Math.round(height / 2)
  355. }
  356. handle: Item
  357. {
  358. Rectangle
  359. {
  360. id: qualityhandleButton
  361. anchors.centerIn: parent
  362. color: UM.Theme.getColor("quality_slider_available")
  363. implicitWidth: 10 * screenScaleFactor
  364. implicitHeight: implicitWidth
  365. radius: Math.round(implicitWidth / 2)
  366. visible: !Cura.SimpleModeSettingsManager.isProfileCustomized && !Cura.SimpleModeSettingsManager.isProfileUserCreated && qualityModel.existingQualityProfile
  367. }
  368. }
  369. }
  370. onValueChanged:
  371. {
  372. // only change if an active machine is set and the slider is visible at all.
  373. if (Cura.MachineManager.activeMachine != null && visible)
  374. {
  375. // prevent updating during view initializing. Trigger only if the value changed by user
  376. if (qualitySlider.value != qualityModel.qualitySliderActiveIndex && qualityModel.qualitySliderActiveIndex != -1)
  377. {
  378. // start updating with short delay
  379. qualitySliderChangeTimer.start()
  380. }
  381. }
  382. }
  383. }
  384. MouseArea
  385. {
  386. id: speedSliderMouseArea
  387. anchors.fill: parent
  388. hoverEnabled: true
  389. enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated
  390. onEntered:
  391. {
  392. var content = catalog.i18nc("@tooltip","A custom profile is currently active. To enable the quality slider, choose a default quality profile in Custom tab")
  393. base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), content)
  394. }
  395. onExited:
  396. {
  397. base.hideTooltip();
  398. }
  399. }
  400. }
  401. Label
  402. {
  403. id: speedLabel
  404. anchors.top: speedSlider.bottom
  405. anchors.left: parent.left
  406. text: catalog.i18nc("@label", "Print Speed")
  407. font: UM.Theme.getFont("default")
  408. color: UM.Theme.getColor("text")
  409. width: Math.round(UM.Theme.getSize("print_setup_widget").width * 0.35)
  410. elide: Text.ElideRight
  411. }
  412. Label
  413. {
  414. anchors.bottom: speedLabel.bottom
  415. anchors.left: speedSlider.left
  416. text: catalog.i18nc("@label", "Slower")
  417. font: UM.Theme.getFont("default")
  418. color: (qualityModel.availableTotalTicks > 1) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  419. horizontalAlignment: Text.AlignLeft
  420. }
  421. Label
  422. {
  423. anchors.bottom: speedLabel.bottom
  424. anchors.right: speedSlider.right
  425. text: catalog.i18nc("@label", "Faster")
  426. font: UM.Theme.getFont("default")
  427. color: (qualityModel.availableTotalTicks > 1) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  428. horizontalAlignment: Text.AlignRight
  429. }
  430. UM.SimpleButton
  431. {
  432. id: customisedSettings
  433. visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.SimpleModeSettingsManager.isProfileUserCreated
  434. height: Math.round(speedSlider.height * 0.8)
  435. width: Math.round(speedSlider.height * 0.8)
  436. anchors.verticalCenter: speedSlider.verticalCenter
  437. anchors.right: speedSlider.left
  438. anchors.rightMargin: Math.round(UM.Theme.getSize("thick_margin").width / 2)
  439. color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
  440. iconSource: UM.Theme.getIcon("reset");
  441. onClicked:
  442. {
  443. // if the current profile is user-created, switch to a built-in quality
  444. Cura.MachineManager.resetToUseDefaultQuality()
  445. }
  446. onEntered:
  447. {
  448. var content = catalog.i18nc("@tooltip","You have modified some profile settings. If you want to change these go to custom mode.")
  449. base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), content)
  450. }
  451. onExited: base.hideTooltip()
  452. }
  453. }
  454. //
  455. // Infill
  456. //
  457. Item
  458. {
  459. id: infillCellLeft
  460. anchors.top: qualityRow.bottom
  461. anchors.topMargin: UM.Theme.getSize("thick_margin").height * 2
  462. anchors.left: parent.left
  463. width: Math.round(UM.Theme.getSize("print_setup_widget").width * .45) - UM.Theme.getSize("thick_margin").width
  464. Label
  465. {
  466. id: infillLabel
  467. text: catalog.i18nc("@label", "Infill")
  468. font: UM.Theme.getFont("default")
  469. color: UM.Theme.getColor("text")
  470. anchors.top: parent.top
  471. anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height * 1.7)
  472. anchors.left: parent.left
  473. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  474. }
  475. }
  476. Item
  477. {
  478. id: infillCellRight
  479. height: infillSlider.height + UM.Theme.getSize("thick_margin").height + enableGradualInfillCheckBox.visible * (enableGradualInfillCheckBox.height + UM.Theme.getSize("thick_margin").height)
  480. width: Math.round(UM.Theme.getSize("print_setup_widget").width * .55)
  481. anchors.left: infillCellLeft.right
  482. anchors.top: infillCellLeft.top
  483. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  484. Label {
  485. id: selectedInfillRateText
  486. //anchors.top: parent.top
  487. anchors.left: infillSlider.left
  488. anchors.leftMargin: Math.round((infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 * screenScaleFactor)
  489. anchors.right: parent.right
  490. text: parseInt(infillDensity.properties.value) + "%"
  491. horizontalAlignment: Text.AlignLeft
  492. color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  493. }
  494. // We use a binding to make sure that after manually setting infillSlider.value it is still bound to the property provider
  495. Binding {
  496. target: infillSlider
  497. property: "value"
  498. value: parseInt(infillDensity.properties.value)
  499. }
  500. Slider
  501. {
  502. id: infillSlider
  503. anchors.top: selectedInfillRateText.bottom
  504. anchors.left: parent.left
  505. anchors.right: infillIcon.left
  506. anchors.rightMargin: UM.Theme.getSize("thick_margin").width
  507. height: UM.Theme.getSize("thick_margin").height
  508. width: parseInt(infillCellRight.width - UM.Theme.getSize("thick_margin").width - style.handleWidth)
  509. minimumValue: 0
  510. maximumValue: 100
  511. stepSize: 1
  512. tickmarksEnabled: true
  513. // disable slider when gradual support is enabled
  514. enabled: parseInt(infillSteps.properties.value) == 0
  515. // set initial value from stack
  516. value: parseInt(infillDensity.properties.value)
  517. onValueChanged: {
  518. // Don't round the value if it's already the same
  519. if (parseInt(infillDensity.properties.value) == infillSlider.value) {
  520. return
  521. }
  522. // Round the slider value to the nearest multiple of 10 (simulate step size of 10)
  523. var roundedSliderValue = Math.round(infillSlider.value / 10) * 10
  524. // Update the slider value to represent the rounded value
  525. infillSlider.value = roundedSliderValue
  526. // Update value only if the Recomended mode is Active,
  527. // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat
  528. // same operation
  529. var active_mode = UM.Preferences.getValue("cura/active_mode")
  530. if (active_mode == 0 || active_mode == "simple")
  531. {
  532. Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue)
  533. Cura.MachineManager.resetSettingForAllExtruders("infill_line_distance")
  534. }
  535. }
  536. style: SliderStyle
  537. {
  538. groove: Rectangle {
  539. id: groove
  540. implicitWidth: 200 * screenScaleFactor
  541. implicitHeight: 2 * screenScaleFactor
  542. color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  543. radius: 1
  544. }
  545. handle: Item {
  546. Rectangle {
  547. id: handleButton
  548. anchors.centerIn: parent
  549. color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  550. implicitWidth: 10 * screenScaleFactor
  551. implicitHeight: 10 * screenScaleFactor
  552. radius: 10 * screenScaleFactor
  553. }
  554. }
  555. tickmarks: Repeater {
  556. id: repeater
  557. model: control.maximumValue / control.stepSize + 1
  558. // check if a tick should be shown based on it's index and wether the infill density is a multiple of 10 (slider step size)
  559. function shouldShowTick (index) {
  560. if (index % 10 == 0) {
  561. return true
  562. }
  563. return false
  564. }
  565. Rectangle {
  566. anchors.verticalCenter: parent.verticalCenter
  567. color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
  568. width: 1 * screenScaleFactor
  569. height: 6 * screenScaleFactor
  570. y: 0
  571. x: Math.round(styleData.handleWidth / 2 + index * ((repeater.width - styleData.handleWidth) / (repeater.count-1)))
  572. visible: shouldShowTick(index)
  573. }
  574. }
  575. }
  576. }
  577. Rectangle
  578. {
  579. id: infillIcon
  580. width: Math.round((parent.width / 5) - (UM.Theme.getSize("thick_margin").width))
  581. height: width
  582. anchors.right: parent.right
  583. anchors.top: parent.top
  584. anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height / 2)
  585. // we loop over all density icons and only show the one that has the current density and steps
  586. Repeater
  587. {
  588. id: infillIconList
  589. model: infillModel
  590. anchors.fill: parent
  591. function activeIndex () {
  592. for (var i = 0; i < infillModel.count; i++) {
  593. var density = Math.round(infillDensity.properties.value)
  594. var steps = Math.round(infillSteps.properties.value)
  595. var infillModelItem = infillModel.get(i)
  596. if (infillModelItem != "undefined"
  597. && density >= infillModelItem.percentageMin
  598. && density <= infillModelItem.percentageMax
  599. && steps >= infillModelItem.stepsMin
  600. && steps <= infillModelItem.stepsMax
  601. ){
  602. return i
  603. }
  604. }
  605. return -1
  606. }
  607. Rectangle
  608. {
  609. anchors.fill: parent
  610. visible: infillIconList.activeIndex() == index
  611. border.width: UM.Theme.getSize("default_lining").width
  612. border.color: UM.Theme.getColor("quality_slider_unavailable")
  613. UM.RecolorImage {
  614. anchors.fill: parent
  615. anchors.margins: 2 * screenScaleFactor
  616. sourceSize.width: width
  617. sourceSize.height: width
  618. source: UM.Theme.getIcon(model.icon)
  619. color: UM.Theme.getColor("quality_slider_unavailable")
  620. }
  621. }
  622. }
  623. }
  624. // Gradual Support Infill Checkbox
  625. CheckBox {
  626. id: enableGradualInfillCheckBox
  627. property alias _hovered: enableGradualInfillMouseArea.containsMouse
  628. anchors.top: infillSlider.bottom
  629. anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height / 2) // closer to slider since it belongs to the same category
  630. anchors.left: infillCellRight.left
  631. style: UM.Theme.styles.checkbox
  632. enabled: base.settingsEnabled
  633. visible: infillSteps.properties.enabled == "True"
  634. checked: parseInt(infillSteps.properties.value) > 0
  635. MouseArea {
  636. id: enableGradualInfillMouseArea
  637. anchors.fill: parent
  638. hoverEnabled: true
  639. enabled: true
  640. property var previousInfillDensity: parseInt(infillDensity.properties.value)
  641. onClicked: {
  642. // Set to 90% only when enabling gradual infill
  643. var newInfillDensity;
  644. if (parseInt(infillSteps.properties.value) == 0) {
  645. previousInfillDensity = parseInt(infillDensity.properties.value)
  646. newInfillDensity = 90;
  647. } else {
  648. newInfillDensity = previousInfillDensity;
  649. }
  650. Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", String(newInfillDensity))
  651. var infill_steps_value = 0;
  652. if (parseInt(infillSteps.properties.value) == 0)
  653. infill_steps_value = 5;
  654. Cura.MachineManager.setSettingForAllExtruders("gradual_infill_steps", "value", infill_steps_value)
  655. }
  656. onEntered: {
  657. base.showTooltip(enableGradualInfillCheckBox, Qt.point(-infillCellRight.x, 0),
  658. catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top."))
  659. }
  660. onExited: {
  661. base.hideTooltip()
  662. }
  663. }
  664. Label {
  665. id: gradualInfillLabel
  666. height: parent.height
  667. anchors.left: enableGradualInfillCheckBox.right
  668. anchors.leftMargin: Math.round(UM.Theme.getSize("thick_margin").width / 2)
  669. verticalAlignment: Text.AlignVCenter;
  670. text: catalog.i18nc("@label", "Enable gradual")
  671. font: UM.Theme.getFont("default")
  672. color: UM.Theme.getColor("text")
  673. }
  674. }
  675. // Infill list model for mapping icon
  676. ListModel
  677. {
  678. id: infillModel
  679. Component.onCompleted:
  680. {
  681. infillModel.append({
  682. percentageMin: -1,
  683. percentageMax: 0,
  684. stepsMin: -1,
  685. stepsMax: 0,
  686. icon: "hollow"
  687. })
  688. infillModel.append({
  689. percentageMin: 0,
  690. percentageMax: 40,
  691. stepsMin: -1,
  692. stepsMax: 0,
  693. icon: "sparse"
  694. })
  695. infillModel.append({
  696. percentageMin: 40,
  697. percentageMax: 89,
  698. stepsMin: -1,
  699. stepsMax: 0,
  700. icon: "dense"
  701. })
  702. infillModel.append({
  703. percentageMin: 90,
  704. percentageMax: 9999999999,
  705. stepsMin: -1,
  706. stepsMax: 0,
  707. icon: "solid"
  708. })
  709. infillModel.append({
  710. percentageMin: 0,
  711. percentageMax: 9999999999,
  712. stepsMin: 1,
  713. stepsMax: 9999999999,
  714. icon: "gradual"
  715. })
  716. }
  717. }
  718. }
  719. //
  720. // Enable support
  721. //
  722. Label
  723. {
  724. id: enableSupportLabel
  725. visible: enableSupportCheckBox.visible
  726. anchors.top: infillCellRight.bottom
  727. anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height * 1.5)
  728. anchors.left: parent.left
  729. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  730. anchors.right: infillCellLeft.right
  731. anchors.rightMargin: UM.Theme.getSize("thick_margin").width
  732. anchors.verticalCenter: enableSupportCheckBox.verticalCenter
  733. text: catalog.i18nc("@label", "Generate Support");
  734. font: UM.Theme.getFont("default");
  735. color: UM.Theme.getColor("text");
  736. elide: Text.ElideRight
  737. }
  738. CheckBox
  739. {
  740. id: enableSupportCheckBox
  741. property alias _hovered: enableSupportMouseArea.containsMouse
  742. anchors.top: enableSupportLabel.top
  743. anchors.left: infillCellRight.left
  744. style: UM.Theme.styles.checkbox;
  745. enabled: base.settingsEnabled
  746. visible: supportEnabled.properties.enabled == "True"
  747. checked: supportEnabled.properties.value == "True";
  748. MouseArea
  749. {
  750. id: enableSupportMouseArea
  751. anchors.fill: parent
  752. hoverEnabled: true
  753. enabled: true
  754. onClicked:
  755. {
  756. // The value is a string "True" or "False"
  757. supportEnabled.setPropertyValue("value", supportEnabled.properties.value != "True");
  758. }
  759. onEntered:
  760. {
  761. base.showTooltip(enableSupportCheckBox, Qt.point(-enableSupportCheckBox.x, 0),
  762. catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing."));
  763. }
  764. onExited:
  765. {
  766. base.hideTooltip();
  767. }
  768. }
  769. }
  770. ComboBox
  771. {
  772. id: supportExtruderCombobox
  773. visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)
  774. model: extruderModel
  775. property string color_override: "" // for manually setting values
  776. property string color: // is evaluated automatically, but the first time is before extruderModel being filled
  777. {
  778. var current_extruder = extruderModel.get(currentIndex);
  779. color_override = "";
  780. if (current_extruder === undefined) return ""
  781. return (current_extruder.color) ? current_extruder.color : "";
  782. }
  783. textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started
  784. anchors.top: enableSupportCheckBox.top
  785. //anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("thick_margin").height : 0
  786. anchors.left: enableSupportCheckBox.right
  787. anchors.leftMargin: Math.round(UM.Theme.getSize("thick_margin").width / 2)
  788. width: Math.round(UM.Theme.getSize("print_setup_widget").width * .55) - Math.round(UM.Theme.getSize("thick_margin").width / 2) - enableSupportCheckBox.width
  789. height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0
  790. Behavior on height { NumberAnimation { duration: 100 } }
  791. style: UM.Theme.styles.combobox_color
  792. enabled: base.settingsEnabled
  793. property alias _hovered: supportExtruderMouseArea.containsMouse
  794. currentIndex:
  795. {
  796. if (supportExtruderNr.properties == null)
  797. {
  798. return Cura.MachineManager.defaultExtruderPosition;
  799. }
  800. else
  801. {
  802. var extruder = parseInt(supportExtruderNr.properties.value);
  803. if ( extruder === -1)
  804. {
  805. return Cura.MachineManager.defaultExtruderPosition;
  806. }
  807. return extruder;
  808. }
  809. }
  810. onActivated:
  811. {
  812. // Send the extruder nr as a string.
  813. supportExtruderNr.setPropertyValue("value", String(index));
  814. }
  815. MouseArea
  816. {
  817. id: supportExtruderMouseArea
  818. anchors.fill: parent
  819. hoverEnabled: true
  820. enabled: base.settingsEnabled
  821. acceptedButtons: Qt.NoButton
  822. onEntered:
  823. {
  824. base.showTooltip(supportExtruderCombobox, Qt.point(-supportExtruderCombobox.x, 0),
  825. catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air."));
  826. }
  827. onExited:
  828. {
  829. base.hideTooltip();
  830. }
  831. }
  832. function updateCurrentColor()
  833. {
  834. var current_extruder = extruderModel.get(currentIndex);
  835. if (current_extruder !== undefined) {
  836. supportExtruderCombobox.color_override = current_extruder.color;
  837. }
  838. }
  839. }
  840. Label
  841. {
  842. id: adhesionHelperLabel
  843. visible: adhesionCheckBox.visible
  844. text: catalog.i18nc("@label", "Build Plate Adhesion")
  845. font: UM.Theme.getFont("default")
  846. color: UM.Theme.getColor("text")
  847. elide: Text.ElideRight
  848. anchors {
  849. left: parent.left
  850. leftMargin: UM.Theme.getSize("thick_margin").width
  851. right: infillCellLeft.right
  852. rightMargin: UM.Theme.getSize("thick_margin").width
  853. verticalCenter: adhesionCheckBox.verticalCenter
  854. }
  855. }
  856. CheckBox
  857. {
  858. id: adhesionCheckBox
  859. property alias _hovered: adhesionMouseArea.containsMouse
  860. anchors.top: enableSupportCheckBox.bottom
  861. anchors.topMargin: UM.Theme.getSize("thick_margin").height
  862. anchors.left: infillCellRight.left
  863. //: Setting enable printing build-plate adhesion helper checkbox
  864. style: UM.Theme.styles.checkbox;
  865. enabled: base.settingsEnabled
  866. visible: platformAdhesionType.properties.enabled == "True"
  867. checked: platformAdhesionType.properties.value != "skirt" && platformAdhesionType.properties.value != "none"
  868. MouseArea
  869. {
  870. id: adhesionMouseArea
  871. anchors.fill: parent
  872. hoverEnabled: true
  873. enabled: base.settingsEnabled
  874. onClicked:
  875. {
  876. var adhesionType = "skirt";
  877. if(!parent.checked)
  878. {
  879. // Remove the "user" setting to see if the rest of the stack prescribes a brim or a raft
  880. platformAdhesionType.removeFromContainer(0);
  881. adhesionType = platformAdhesionType.properties.value;
  882. if(adhesionType == "skirt" || adhesionType == "none")
  883. {
  884. // If the rest of the stack doesn't prescribe an adhesion-type, default to a brim
  885. adhesionType = "brim";
  886. }
  887. }
  888. platformAdhesionType.setPropertyValue("value", adhesionType);
  889. }
  890. onEntered:
  891. {
  892. base.showTooltip(adhesionCheckBox, Qt.point(-adhesionCheckBox.x, 0),
  893. catalog.i18nc("@label", "Enable printing a brim or raft. This will add a flat area around or under your object which is easy to cut off afterwards."));
  894. }
  895. onExited:
  896. {
  897. base.hideTooltip();
  898. }
  899. }
  900. }
  901. ListModel
  902. {
  903. id: extruderModel
  904. Component.onCompleted: populateExtruderModel()
  905. }
  906. //: Model used to populate the extrudelModel
  907. Cura.ExtrudersModel
  908. {
  909. id: extruders
  910. onModelChanged: populateExtruderModel()
  911. }
  912. Item
  913. {
  914. id: tipsCell
  915. anchors.top: adhesionCheckBox.visible ? adhesionCheckBox.bottom : (enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom)
  916. anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height * 2)
  917. anchors.left: parent.left
  918. width: parent.width
  919. height: tipsText.contentHeight * tipsText.lineCount
  920. Label
  921. {
  922. id: tipsText
  923. anchors.left: parent.left
  924. anchors.leftMargin: UM.Theme.getSize("thick_margin").width
  925. anchors.right: parent.right
  926. anchors.rightMargin: UM.Theme.getSize("thick_margin").width
  927. anchors.top: parent.top
  928. wrapMode: Text.WordWrap
  929. text: catalog.i18nc("@label", "Need help improving your prints?<br>Read the <a href='%1'>Ultimaker Troubleshooting Guides</a>").arg("https://ultimaker.com/en/troubleshooting")
  930. font: UM.Theme.getFont("default");
  931. color: UM.Theme.getColor("text");
  932. linkColor: UM.Theme.getColor("text_link")
  933. onLinkActivated: Qt.openUrlExternally(link)
  934. }
  935. }
  936. UM.SettingPropertyProvider
  937. {
  938. id: infillExtruderNumber
  939. containerStackId: Cura.MachineManager.activeStackId
  940. key: "infill_extruder_nr"
  941. watchedProperties: [ "value" ]
  942. storeIndex: 0
  943. }
  944. UM.SettingPropertyProvider
  945. {
  946. id: infillDensity
  947. containerStackId: Cura.MachineManager.activeStackId
  948. key: "infill_sparse_density"
  949. watchedProperties: [ "value" ]
  950. storeIndex: 0
  951. }
  952. UM.SettingPropertyProvider
  953. {
  954. id: infillSteps
  955. containerStackId: Cura.MachineManager.activeStackId
  956. key: "gradual_infill_steps"
  957. watchedProperties: ["value", "enabled"]
  958. storeIndex: 0
  959. }
  960. UM.SettingPropertyProvider
  961. {
  962. id: platformAdhesionType
  963. containerStack: Cura.MachineManager.activeMachine
  964. removeUnusedValue: false //Doesn't work with settings that are resolved.
  965. key: "adhesion_type"
  966. watchedProperties: [ "value", "enabled" ]
  967. storeIndex: 0
  968. }
  969. UM.SettingPropertyProvider
  970. {
  971. id: supportEnabled
  972. containerStack: Cura.MachineManager.activeMachine
  973. key: "support_enable"
  974. watchedProperties: [ "value", "enabled", "description" ]
  975. storeIndex: 0
  976. }
  977. UM.SettingPropertyProvider
  978. {
  979. id: extrudersEnabledCount
  980. containerStack: Cura.MachineManager.activeMachine
  981. key: "extruders_enabled_count"
  982. watchedProperties: [ "value" ]
  983. storeIndex: 0
  984. }
  985. UM.SettingPropertyProvider
  986. {
  987. id: supportExtruderNr
  988. containerStack: Cura.MachineManager.activeMachine
  989. key: "support_extruder_nr"
  990. watchedProperties: [ "value" ]
  991. storeIndex: 0
  992. }
  993. }
  994. }
  995. function populateExtruderModel()
  996. {
  997. extruderModel.clear();
  998. for(var extruderNumber = 0; extruderNumber < extruders.rowCount() ; extruderNumber++)
  999. {
  1000. extruderModel.append({
  1001. text: extruders.getItem(extruderNumber).name,
  1002. color: extruders.getItem(extruderNumber).color
  1003. })
  1004. }
  1005. supportExtruderCombobox.updateCurrentColor();
  1006. }
  1007. }