SidebarSimple.qml 51 KB

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