Sidebar.qml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.7
  4. import QtQuick.Controls 2.0
  5. import QtQuick.Layouts 1.3
  6. import UM 1.2 as UM
  7. import Cura 1.0 as Cura
  8. import "Menus"
  9. import "Menus/ConfigurationMenu"
  10. Rectangle
  11. {
  12. id: base
  13. property int currentModeIndex
  14. property bool hideSettings: PrintInformation.preSliced
  15. property bool hideView: Cura.MachineManager.activeMachineName == ""
  16. // Is there an output device for this printer?
  17. property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
  18. property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
  19. property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
  20. property bool monitoringPrint: UM.Controller.activeStage.stageId == "MonitorStage"
  21. property variant printDuration: PrintInformation.currentPrintTime
  22. property variant printMaterialLengths: PrintInformation.materialLengths
  23. property variant printMaterialWeights: PrintInformation.materialWeights
  24. property variant printMaterialCosts: PrintInformation.materialCosts
  25. property variant printMaterialNames: PrintInformation.materialNames
  26. color: UM.Theme.getColor("sidebar")
  27. UM.I18nCatalog { id: catalog; name:"cura"}
  28. Timer {
  29. id: tooltipDelayTimer
  30. interval: 500
  31. repeat: false
  32. property var item
  33. property string text
  34. onTriggered:
  35. {
  36. base.showTooltip(base, {x: 0, y: item.y}, text);
  37. }
  38. }
  39. function showTooltip(item, position, text)
  40. {
  41. tooltip.text = text;
  42. position = item.mapToItem(base, position.x - UM.Theme.getSize("default_arrow").width, position.y);
  43. tooltip.show(position);
  44. }
  45. function hideTooltip()
  46. {
  47. tooltip.hide();
  48. }
  49. function strPadLeft(string, pad, length) {
  50. return (new Array(length + 1).join(pad) + string).slice(-length);
  51. }
  52. function getPrettyTime(time)
  53. {
  54. var hours = Math.floor(time / 3600)
  55. time -= hours * 3600
  56. var minutes = Math.floor(time / 60);
  57. time -= minutes * 60
  58. var seconds = Math.floor(time);
  59. var finalTime = strPadLeft(hours, "0", 2) + ':' + strPadLeft(minutes,'0',2)+ ':' + strPadLeft(seconds,'0',2);
  60. return finalTime;
  61. }
  62. MouseArea
  63. {
  64. anchors.fill: parent
  65. acceptedButtons: Qt.AllButtons
  66. onWheel:
  67. {
  68. wheel.accepted = true;
  69. }
  70. }
  71. MachineSelection {
  72. id: machineSelection
  73. width: base.width - configSelection.width - separator.width
  74. height: UM.Theme.getSize("sidebar_header").height
  75. anchors.top: base.top
  76. anchors.left: parent.left
  77. }
  78. Rectangle
  79. {
  80. id: separator
  81. visible: configSelection.visible
  82. width: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0
  83. height: UM.Theme.getSize("sidebar_header").height
  84. color: UM.Theme.getColor("sidebar_lining_thin")
  85. anchors.left: machineSelection.right
  86. }
  87. ConfigurationSelection {
  88. id: configSelection
  89. visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings
  90. width: visible ? Math.round(base.width * 0.15) : 0
  91. height: UM.Theme.getSize("sidebar_header").height
  92. anchors.top: base.top
  93. anchors.right: parent.right
  94. panelWidth: base.width
  95. }
  96. SidebarHeader {
  97. id: header
  98. width: parent.width
  99. visible: !hideSettings && (machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants) && !monitoringPrint
  100. anchors.top: machineSelection.bottom
  101. onShowTooltip: base.showTooltip(item, location, text)
  102. onHideTooltip: base.hideTooltip()
  103. }
  104. Rectangle {
  105. id: headerSeparator
  106. width: parent.width
  107. visible: settingsModeSelection.visible && header.visible
  108. height: visible ? UM.Theme.getSize("sidebar_lining").height : 0
  109. color: UM.Theme.getColor("sidebar_lining")
  110. anchors.top: header.bottom
  111. anchors.topMargin: visible ? UM.Theme.getSize("sidebar_margin").height : 0
  112. }
  113. onCurrentModeIndexChanged:
  114. {
  115. UM.Preferences.setValue("cura/active_mode", currentModeIndex);
  116. if(modesListModel.count > base.currentModeIndex)
  117. {
  118. sidebarContents.replace(modesListModel.get(base.currentModeIndex).item, { "replace": true })
  119. }
  120. }
  121. Label
  122. {
  123. id: settingsModeLabel
  124. text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox", "Print Setup disabled\nG-code files cannot be modified")
  125. renderType: Text.NativeRendering
  126. anchors.left: parent.left
  127. anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
  128. anchors.top: hideSettings ? machineSelection.bottom : headerSeparator.bottom
  129. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  130. width: Math.round(parent.width * 0.45)
  131. font: UM.Theme.getFont("large")
  132. color: UM.Theme.getColor("text")
  133. visible: !monitoringPrint && !hideView
  134. }
  135. // Settings mode selection toggle
  136. Rectangle
  137. {
  138. id: settingsModeSelection
  139. color: "transparent"
  140. width: Math.round(parent.width * 0.55)
  141. height: UM.Theme.getSize("sidebar_header_mode_toggle").height
  142. anchors.right: parent.right
  143. anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
  144. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  145. anchors.top:
  146. {
  147. if (settingsModeLabel.contentWidth >= parent.width - width - UM.Theme.getSize("sidebar_margin").width * 2)
  148. {
  149. return settingsModeLabel.bottom;
  150. }
  151. else
  152. {
  153. return headerSeparator.bottom;
  154. }
  155. }
  156. visible: !monitoringPrint && !hideSettings && !hideView
  157. Component
  158. {
  159. id: wizardDelegate
  160. Button
  161. {
  162. id: control
  163. height: settingsModeSelection.height
  164. width: Math.round(parent.width / 2)
  165. anchors.left: parent.left
  166. anchors.leftMargin: model.index * Math.round(settingsModeSelection.width / 2)
  167. anchors.verticalCenter: parent.verticalCenter
  168. ButtonGroup.group: modeMenuGroup
  169. checkable: true
  170. checked: base.currentModeIndex == index
  171. onClicked: base.currentModeIndex = index
  172. onHoveredChanged:
  173. {
  174. if (hovered)
  175. {
  176. tooltipDelayTimer.item = settingsModeSelection
  177. tooltipDelayTimer.text = model.tooltipText
  178. tooltipDelayTimer.start()
  179. }
  180. else
  181. {
  182. tooltipDelayTimer.stop()
  183. base.hideTooltip()
  184. }
  185. }
  186. background: Rectangle
  187. {
  188. border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width
  189. border.color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") : control.hovered ? UM.Theme.getColor("action_button_hovered_border"): UM.Theme.getColor("action_button_border")
  190. // for some reason, QtQuick decided to use the color of the background property as text color for the contentItem, so here it is
  191. color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
  192. }
  193. contentItem: Label
  194. {
  195. text: model.text
  196. font: UM.Theme.getFont("default")
  197. horizontalAlignment: Text.AlignHCenter
  198. verticalAlignment: Text.AlignVCenter
  199. renderType: Text.NativeRendering
  200. elide: Text.ElideRight
  201. color:
  202. {
  203. if(control.pressed)
  204. {
  205. return UM.Theme.getColor("action_button_active_text");
  206. }
  207. else if(control.hovered)
  208. {
  209. return UM.Theme.getColor("action_button_hovered_text");
  210. }
  211. return UM.Theme.getColor("action_button_text");
  212. }
  213. }
  214. }
  215. }
  216. ButtonGroup
  217. {
  218. id: modeMenuGroup
  219. }
  220. ListView
  221. {
  222. id: modesList
  223. property var index: 0
  224. model: modesListModel
  225. delegate: wizardDelegate
  226. anchors.top: parent.top
  227. anchors.left: parent.left
  228. width: parent.width
  229. }
  230. }
  231. StackView
  232. {
  233. id: sidebarContents
  234. anchors.bottom: footerSeparator.top
  235. anchors.top: settingsModeSelection.bottom
  236. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  237. anchors.left: base.left
  238. anchors.right: base.right
  239. visible: !monitoringPrint && !hideSettings
  240. replaceEnter: Transition {
  241. PropertyAnimation {
  242. property: "opacity"
  243. from: 0
  244. to:1
  245. duration: 100
  246. }
  247. }
  248. replaceExit: Transition {
  249. PropertyAnimation {
  250. property: "opacity"
  251. from: 1
  252. to:0
  253. duration: 100
  254. }
  255. }
  256. }
  257. Loader
  258. {
  259. id: controlItem
  260. anchors.bottom: footerSeparator.top
  261. anchors.top: monitoringPrint ? machineSelection.bottom : headerSeparator.bottom
  262. anchors.left: base.left
  263. anchors.right: base.right
  264. sourceComponent:
  265. {
  266. if(monitoringPrint && connectedPrinter != null)
  267. {
  268. if(connectedPrinter.controlItem != null)
  269. {
  270. return connectedPrinter.controlItem
  271. }
  272. }
  273. return null
  274. }
  275. }
  276. Loader
  277. {
  278. anchors.bottom: footerSeparator.top
  279. anchors.top: monitoringPrint ? machineSelection.bottom : headerSeparator.bottom
  280. anchors.left: base.left
  281. anchors.right: base.right
  282. source:
  283. {
  284. if(controlItem.sourceComponent == null)
  285. {
  286. if(monitoringPrint)
  287. {
  288. return "PrintMonitor.qml"
  289. } else
  290. {
  291. return "SidebarContents.qml"
  292. }
  293. }
  294. else
  295. {
  296. return ""
  297. }
  298. }
  299. }
  300. Rectangle
  301. {
  302. id: footerSeparator
  303. width: parent.width
  304. height: UM.Theme.getSize("sidebar_lining").height
  305. color: UM.Theme.getColor("sidebar_lining")
  306. anchors.bottom: printSpecs.top
  307. anchors.bottomMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize)
  308. }
  309. Item
  310. {
  311. id: printSpecs
  312. anchors.left: parent.left
  313. anchors.bottom: parent.bottom
  314. anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
  315. anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height
  316. height: timeDetails.height + costSpec.height
  317. width: base.width - (saveButton.buttonRowWidth + UM.Theme.getSize("sidebar_margin").width)
  318. visible: !monitoringPrint
  319. clip: true
  320. Label
  321. {
  322. id: timeDetails
  323. anchors.left: parent.left
  324. anchors.bottom: costSpec.top
  325. font: UM.Theme.getFont("large")
  326. color: UM.Theme.getColor("text_subtext")
  327. text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
  328. renderType: Text.NativeRendering
  329. MouseArea
  330. {
  331. id: timeDetailsMouseArea
  332. anchors.fill: parent
  333. hoverEnabled: true
  334. onEntered:
  335. {
  336. if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
  337. {
  338. // All the time information for the different features is achieved
  339. var print_time = PrintInformation.getFeaturePrintTimes();
  340. var total_seconds = parseInt(base.printDuration.getDisplayString(UM.DurationFormat.Seconds))
  341. // A message is created and displayed when the user hover the time label
  342. var tooltip_html = "<b>%1</b><br/><table width=\"100%\">".arg(catalog.i18nc("@tooltip", "Time specification"));
  343. for(var feature in print_time)
  344. {
  345. if(!print_time[feature].isTotalDurationZero)
  346. {
  347. tooltip_html += "<tr><td>" + feature + ":</td>" +
  348. "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(print_time[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) +
  349. "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1%</td>".arg(Math.round(100 * parseInt(print_time[feature].getDisplayString(UM.DurationFormat.Seconds)) / total_seconds)) +
  350. "</td></tr>";
  351. }
  352. }
  353. tooltip_html += "</table>";
  354. base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), tooltip_html);
  355. }
  356. }
  357. onExited:
  358. {
  359. base.hideTooltip();
  360. }
  361. }
  362. }
  363. Label
  364. {
  365. function formatRow(items)
  366. {
  367. var row_html = "<tr>";
  368. for(var item = 0; item < items.length; item++)
  369. {
  370. if (item == 0)
  371. {
  372. row_html += "<td valign=\"bottom\">%1</td>".arg(items[item]);
  373. }
  374. else
  375. {
  376. row_html += "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(items[item]);
  377. }
  378. }
  379. row_html += "</tr>";
  380. return row_html;
  381. }
  382. function getSpecsData()
  383. {
  384. var lengths = [];
  385. var total_length = 0;
  386. var weights = [];
  387. var total_weight = 0;
  388. var costs = [];
  389. var total_cost = 0;
  390. var some_costs_known = false;
  391. var names = [];
  392. if(base.printMaterialLengths)
  393. {
  394. for(var index = 0; index < base.printMaterialLengths.length; index++)
  395. {
  396. if(base.printMaterialLengths[index] > 0)
  397. {
  398. names.push(base.printMaterialNames[index]);
  399. lengths.push(base.printMaterialLengths[index].toFixed(2));
  400. weights.push(String(Math.round(base.printMaterialWeights[index])));
  401. var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
  402. costs.push(cost);
  403. if(cost > 0)
  404. {
  405. some_costs_known = true;
  406. }
  407. total_length += base.printMaterialLengths[index];
  408. total_weight += base.printMaterialWeights[index];
  409. total_cost += base.printMaterialCosts[index];
  410. }
  411. }
  412. }
  413. if(lengths.length == 0)
  414. {
  415. lengths = ["0.00"];
  416. weights = ["0"];
  417. costs = ["0.00"];
  418. }
  419. var tooltip_html = "<b>%1</b><br/><table width=\"100%\">".arg(catalog.i18nc("@label", "Cost specification"));
  420. for(var index = 0; index < lengths.length; index++)
  421. {
  422. tooltip_html += formatRow([
  423. "%1:".arg(names[index]),
  424. catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]),
  425. catalog.i18nc("@label g for grams", "%1g").arg(weights[index]),
  426. "%1&nbsp;%2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]),
  427. ]);
  428. }
  429. if(lengths.length > 1)
  430. {
  431. tooltip_html += formatRow([
  432. catalog.i18nc("@label", "Total:"),
  433. catalog.i18nc("@label m for meter", "%1m").arg(total_length.toFixed(2)),
  434. catalog.i18nc("@label g for grams", "%1g").arg(Math.round(total_weight)),
  435. "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(total_cost.toFixed(2)),
  436. ]);
  437. }
  438. tooltip_html += "</table>";
  439. tooltipText = tooltip_html;
  440. return tooltipText
  441. }
  442. id: costSpec
  443. anchors.left: parent.left
  444. anchors.bottom: parent.bottom
  445. font: UM.Theme.getFont("very_small")
  446. renderType: Text.NativeRendering
  447. color: UM.Theme.getColor("text_subtext")
  448. elide: Text.ElideMiddle
  449. width: parent.width
  450. property string tooltipText
  451. text:
  452. {
  453. var lengths = [];
  454. var weights = [];
  455. var costs = [];
  456. var someCostsKnown = false;
  457. if(base.printMaterialLengths) {
  458. for(var index = 0; index < base.printMaterialLengths.length; index++)
  459. {
  460. if(base.printMaterialLengths[index] > 0)
  461. {
  462. lengths.push(base.printMaterialLengths[index].toFixed(2));
  463. weights.push(String(Math.round(base.printMaterialWeights[index])));
  464. var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
  465. costs.push(cost);
  466. if(cost > 0)
  467. {
  468. someCostsKnown = true;
  469. }
  470. }
  471. }
  472. }
  473. if(lengths.length == 0)
  474. {
  475. lengths = ["0.00"];
  476. weights = ["0"];
  477. costs = ["0.00"];
  478. }
  479. var result = lengths.join(" + ") + "m / ~ " + weights.join(" + ") + "g";
  480. if(someCostsKnown)
  481. {
  482. result += " / ~ " + costs.join(" + ") + " " + UM.Preferences.getValue("cura/currency");
  483. }
  484. return result;
  485. }
  486. MouseArea
  487. {
  488. id: costSpecMouseArea
  489. anchors.fill: parent
  490. hoverEnabled: true
  491. onEntered:
  492. {
  493. if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
  494. {
  495. var show_data = costSpec.getSpecsData()
  496. base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), show_data);
  497. }
  498. }
  499. onExited:
  500. {
  501. base.hideTooltip();
  502. }
  503. }
  504. }
  505. }
  506. // SaveButton and MonitorButton are actually the bottom footer panels.
  507. // "!monitoringPrint" currently means "show-settings-mode"
  508. SaveButton
  509. {
  510. id: saveButton
  511. implicitWidth: base.width
  512. anchors.top: footerSeparator.bottom
  513. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  514. anchors.bottom: parent.bottom
  515. visible: !monitoringPrint
  516. }
  517. MonitorButton
  518. {
  519. id: monitorButton
  520. implicitWidth: base.width
  521. anchors.top: footerSeparator.bottom
  522. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  523. anchors.bottom: parent.bottom
  524. visible: monitoringPrint
  525. }
  526. SidebarTooltip
  527. {
  528. id: tooltip
  529. }
  530. // Setting mode: Recommended or Custom
  531. ListModel
  532. {
  533. id: modesListModel
  534. }
  535. SidebarSimple
  536. {
  537. id: sidebarSimple
  538. visible: false
  539. onShowTooltip: base.showTooltip(item, location, text)
  540. onHideTooltip: base.hideTooltip()
  541. }
  542. SidebarAdvanced
  543. {
  544. id: sidebarAdvanced
  545. visible: false
  546. onShowTooltip: base.showTooltip(item, location, text)
  547. onHideTooltip: base.hideTooltip()
  548. }
  549. Component.onCompleted:
  550. {
  551. modesListModel.append({
  552. text: catalog.i18nc("@title:tab", "Recommended"),
  553. tooltipText: catalog.i18nc("@tooltip", "<b>Recommended Print Setup</b><br/><br/>Print with the recommended settings for the selected printer, material and quality."),
  554. item: sidebarSimple
  555. })
  556. modesListModel.append({
  557. text: catalog.i18nc("@title:tab", "Custom"),
  558. tooltipText: catalog.i18nc("@tooltip", "<b>Custom Print Setup</b><br/><br/>Print with finegrained control over every last bit of the slicing process."),
  559. item: sidebarAdvanced
  560. })
  561. sidebarContents.replace(modesListModel.get(base.currentModeIndex).item, { "immediate": true })
  562. var index = Math.round(UM.Preferences.getValue("cura/active_mode"))
  563. if(index)
  564. {
  565. currentModeIndex = index;
  566. }
  567. }
  568. UM.SettingPropertyProvider
  569. {
  570. id: machineExtruderCount
  571. containerStackId: Cura.MachineManager.activeMachineId
  572. key: "machine_extruder_count"
  573. watchedProperties: [ "value" ]
  574. storeIndex: 0
  575. }
  576. UM.SettingPropertyProvider
  577. {
  578. id: machineHeatedBed
  579. containerStackId: Cura.MachineManager.activeMachineId
  580. key: "machine_heated_bed"
  581. watchedProperties: [ "value" ]
  582. storeIndex: 0
  583. }
  584. }