SidebarSimple.qml 44 KB

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