SidebarSimple.qml 45 KB

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