SidebarSimple.qml 42 KB

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