SidebarSimple.qml 49 KB

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