SidebarSimple.qml 46 KB

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