Sidebar.qml 22 KB

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