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