SidebarSimple.qml 46 KB

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