Sidebar.qml 22 KB

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