SidebarSimple.qml 50 KB

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