SidebarSimple.qml 42 KB

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