PrepareSidebar.qml 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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: -1
  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 isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
  18. property bool printerConnected: Cura.MachineManager.printerConnected
  19. property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
  20. property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
  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. {
  73. id: machineSelection
  74. width: base.width - configSelection.width - separator.width
  75. height: UM.Theme.getSize("sidebar_header").height
  76. anchors.top: base.top
  77. anchors.left: parent.left
  78. }
  79. Rectangle
  80. {
  81. id: separator
  82. visible: configSelection.visible
  83. width: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0
  84. height: UM.Theme.getSize("sidebar_header").height
  85. color: UM.Theme.getColor("sidebar_lining_thin")
  86. anchors.left: machineSelection.right
  87. }
  88. ConfigurationSelection
  89. {
  90. id: configSelection
  91. visible: isNetworkPrinter && printerConnected
  92. width: visible ? Math.round(base.width * 0.15) : 0
  93. height: UM.Theme.getSize("sidebar_header").height
  94. anchors.top: base.top
  95. anchors.right: parent.right
  96. panelWidth: base.width
  97. }
  98. SidebarHeader {
  99. id: header
  100. width: parent.width
  101. visible: !hideSettings && (machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants)
  102. anchors.top: machineSelection.bottom
  103. onShowTooltip: base.showTooltip(item, location, text)
  104. onHideTooltip: base.hideTooltip()
  105. }
  106. Rectangle {
  107. id: headerSeparator
  108. width: parent.width
  109. visible: settingsModeSelection.visible && header.visible
  110. height: visible ? UM.Theme.getSize("sidebar_lining").height : 0
  111. color: UM.Theme.getColor("sidebar_lining")
  112. anchors.top: header.bottom
  113. anchors.topMargin: visible ? UM.Theme.getSize("sidebar_margin").height : 0
  114. }
  115. onCurrentModeIndexChanged:
  116. {
  117. UM.Preferences.setValue("cura/active_mode", currentModeIndex);
  118. if(modesListModel.count > base.currentModeIndex)
  119. {
  120. sidebarContents.replace(modesListModel.get(base.currentModeIndex).item, { "replace": true })
  121. }
  122. }
  123. Label
  124. {
  125. id: settingsModeLabel
  126. text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox", "Print Setup disabled\nG-code files cannot be modified")
  127. renderType: Text.NativeRendering
  128. anchors.left: parent.left
  129. anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
  130. anchors.top: hideSettings ? machineSelection.bottom : headerSeparator.bottom
  131. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  132. width: Math.round(parent.width * 0.45)
  133. font: UM.Theme.getFont("large")
  134. color: UM.Theme.getColor("text")
  135. visible: !hideView
  136. }
  137. // Settings mode selection toggle
  138. Rectangle
  139. {
  140. id: settingsModeSelection
  141. color: "transparent"
  142. width: Math.round(parent.width * 0.55)
  143. height: UM.Theme.getSize("sidebar_header_mode_toggle").height
  144. anchors.right: parent.right
  145. anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
  146. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  147. anchors.top:
  148. {
  149. if (settingsModeLabel.contentWidth >= parent.width - width - UM.Theme.getSize("sidebar_margin").width * 2)
  150. {
  151. return settingsModeLabel.bottom;
  152. }
  153. else
  154. {
  155. return headerSeparator.bottom;
  156. }
  157. }
  158. visible: !hideSettings && !hideView
  159. Component
  160. {
  161. id: wizardDelegate
  162. Button
  163. {
  164. id: control
  165. height: settingsModeSelection.height
  166. width: Math.round(parent.width / 2)
  167. anchors.left: parent.left
  168. anchors.leftMargin: model.index * Math.round(settingsModeSelection.width / 2)
  169. anchors.verticalCenter: parent.verticalCenter
  170. ButtonGroup.group: modeMenuGroup
  171. checkable: true
  172. checked: base.currentModeIndex == index
  173. onClicked: base.currentModeIndex = index
  174. onHoveredChanged:
  175. {
  176. if (hovered)
  177. {
  178. tooltipDelayTimer.item = settingsModeSelection
  179. tooltipDelayTimer.text = model.tooltipText
  180. tooltipDelayTimer.start()
  181. }
  182. else
  183. {
  184. tooltipDelayTimer.stop()
  185. base.hideTooltip()
  186. }
  187. }
  188. background: Rectangle
  189. {
  190. border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width
  191. 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")
  192. // for some reason, QtQuick decided to use the color of the background property as text color for the contentItem, so here it is
  193. color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button")
  194. }
  195. contentItem: Label
  196. {
  197. text: model.text
  198. font: UM.Theme.getFont("default")
  199. horizontalAlignment: Text.AlignHCenter
  200. verticalAlignment: Text.AlignVCenter
  201. renderType: Text.NativeRendering
  202. elide: Text.ElideRight
  203. color:
  204. {
  205. if(control.pressed)
  206. {
  207. return UM.Theme.getColor("action_button_active_text");
  208. }
  209. else if(control.hovered)
  210. {
  211. return UM.Theme.getColor("action_button_hovered_text");
  212. }
  213. return UM.Theme.getColor("action_button_text");
  214. }
  215. }
  216. }
  217. }
  218. ButtonGroup
  219. {
  220. id: modeMenuGroup
  221. }
  222. ListView
  223. {
  224. id: modesList
  225. model: modesListModel
  226. delegate: wizardDelegate
  227. anchors.top: parent.top
  228. anchors.left: parent.left
  229. width: parent.width
  230. }
  231. }
  232. StackView
  233. {
  234. id: sidebarContents
  235. anchors.bottom: footerSeparator.top
  236. anchors.top: settingsModeSelection.bottom
  237. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  238. anchors.left: base.left
  239. anchors.right: base.right
  240. visible: !hideSettings
  241. replaceEnter: Transition {
  242. PropertyAnimation {
  243. property: "opacity"
  244. from: 0
  245. to:1
  246. duration: 100
  247. }
  248. }
  249. replaceExit: Transition {
  250. PropertyAnimation {
  251. property: "opacity"
  252. from: 1
  253. to:0
  254. duration: 100
  255. }
  256. }
  257. }
  258. Loader
  259. {
  260. anchors.bottom: footerSeparator.top
  261. anchors.top: headerSeparator.bottom
  262. anchors.left: base.left
  263. anchors.right: base.right
  264. source: "SidebarContents.qml"
  265. }
  266. Rectangle
  267. {
  268. id: footerSeparator
  269. width: parent.width
  270. height: UM.Theme.getSize("sidebar_lining").height
  271. color: UM.Theme.getColor("sidebar_lining")
  272. anchors.bottom: printSpecs.top
  273. anchors.bottomMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize)
  274. }
  275. Item
  276. {
  277. id: printSpecs
  278. anchors.left: parent.left
  279. anchors.bottom: parent.bottom
  280. anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width
  281. anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height
  282. height: timeDetails.height + costSpec.height
  283. width: base.width - (saveButton.buttonRowWidth + UM.Theme.getSize("sidebar_margin").width)
  284. clip: true
  285. Label
  286. {
  287. id: timeDetails
  288. anchors.left: parent.left
  289. anchors.bottom: costSpec.top
  290. font: UM.Theme.getFont("large")
  291. color: UM.Theme.getColor("text_subtext")
  292. text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
  293. renderType: Text.NativeRendering
  294. MouseArea
  295. {
  296. id: timeDetailsMouseArea
  297. anchors.fill: parent
  298. hoverEnabled: true
  299. onEntered:
  300. {
  301. if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
  302. {
  303. // All the time information for the different features is achieved
  304. var print_time = PrintInformation.getFeaturePrintTimes();
  305. var total_seconds = parseInt(base.printDuration.getDisplayString(UM.DurationFormat.Seconds))
  306. // A message is created and displayed when the user hover the time label
  307. var tooltip_html = "<b>%1</b><br/><table width=\"100%\">".arg(catalog.i18nc("@tooltip", "Time specification"));
  308. for(var feature in print_time)
  309. {
  310. if(!print_time[feature].isTotalDurationZero)
  311. {
  312. tooltip_html += "<tr><td>" + feature + ":</td>" +
  313. "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(print_time[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) +
  314. "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1%</td>".arg(Math.round(100 * parseInt(print_time[feature].getDisplayString(UM.DurationFormat.Seconds)) / total_seconds)) +
  315. "</td></tr>";
  316. }
  317. }
  318. tooltip_html += "</table>";
  319. base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), tooltip_html);
  320. }
  321. }
  322. onExited:
  323. {
  324. base.hideTooltip();
  325. }
  326. }
  327. }
  328. Label
  329. {
  330. function formatRow(items)
  331. {
  332. var row_html = "<tr>";
  333. for(var item = 0; item < items.length; item++)
  334. {
  335. if (item == 0)
  336. {
  337. row_html += "<td valign=\"bottom\">%1</td>".arg(items[item]);
  338. }
  339. else
  340. {
  341. row_html += "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(items[item]);
  342. }
  343. }
  344. row_html += "</tr>";
  345. return row_html;
  346. }
  347. function getSpecsData()
  348. {
  349. var lengths = [];
  350. var total_length = 0;
  351. var weights = [];
  352. var total_weight = 0;
  353. var costs = [];
  354. var total_cost = 0;
  355. var some_costs_known = false;
  356. var names = [];
  357. if(base.printMaterialLengths)
  358. {
  359. for(var index = 0; index < base.printMaterialLengths.length; index++)
  360. {
  361. if(base.printMaterialLengths[index] > 0)
  362. {
  363. names.push(base.printMaterialNames[index]);
  364. lengths.push(base.printMaterialLengths[index].toFixed(2));
  365. weights.push(String(Math.round(base.printMaterialWeights[index])));
  366. var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
  367. costs.push(cost);
  368. if(cost > 0)
  369. {
  370. some_costs_known = true;
  371. }
  372. total_length += base.printMaterialLengths[index];
  373. total_weight += base.printMaterialWeights[index];
  374. total_cost += base.printMaterialCosts[index];
  375. }
  376. }
  377. }
  378. if(lengths.length == 0)
  379. {
  380. lengths = ["0.00"];
  381. weights = ["0"];
  382. costs = ["0.00"];
  383. }
  384. var tooltip_html = "<b>%1</b><br/><table width=\"100%\">".arg(catalog.i18nc("@label", "Cost specification"));
  385. for(var index = 0; index < lengths.length; index++)
  386. {
  387. tooltip_html += formatRow([
  388. "%1:".arg(names[index]),
  389. catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]),
  390. catalog.i18nc("@label g for grams", "%1g").arg(weights[index]),
  391. "%1&nbsp;%2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]),
  392. ]);
  393. }
  394. if(lengths.length > 1)
  395. {
  396. tooltip_html += formatRow([
  397. catalog.i18nc("@label", "Total:"),
  398. catalog.i18nc("@label m for meter", "%1m").arg(total_length.toFixed(2)),
  399. catalog.i18nc("@label g for grams", "%1g").arg(Math.round(total_weight)),
  400. "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(total_cost.toFixed(2)),
  401. ]);
  402. }
  403. tooltip_html += "</table>";
  404. tooltipText = tooltip_html;
  405. return tooltipText
  406. }
  407. id: costSpec
  408. anchors.left: parent.left
  409. anchors.bottom: parent.bottom
  410. font: UM.Theme.getFont("very_small")
  411. renderType: Text.NativeRendering
  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.round(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. var result = lengths.join(" + ") + "m / ~ " + weights.join(" + ") + "g";
  445. if(someCostsKnown)
  446. {
  447. result += " / ~ " + costs.join(" + ") + " " + UM.Preferences.getValue("cura/currency");
  448. }
  449. return result;
  450. }
  451. MouseArea
  452. {
  453. id: costSpecMouseArea
  454. anchors.fill: parent
  455. hoverEnabled: true
  456. onEntered:
  457. {
  458. if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
  459. {
  460. var show_data = costSpec.getSpecsData()
  461. base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), show_data);
  462. }
  463. }
  464. onExited:
  465. {
  466. base.hideTooltip();
  467. }
  468. }
  469. }
  470. }
  471. // SaveButton is actually the bottom footer panel.
  472. SaveButton
  473. {
  474. id: saveButton
  475. implicitWidth: base.width
  476. anchors.top: footerSeparator.bottom
  477. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  478. anchors.bottom: parent.bottom
  479. }
  480. SidebarTooltip
  481. {
  482. id: tooltip
  483. }
  484. // Setting mode: Recommended or Custom
  485. ListModel
  486. {
  487. id: modesListModel
  488. }
  489. SidebarSimple
  490. {
  491. id: sidebarSimple
  492. visible: false
  493. onShowTooltip: base.showTooltip(item, location, text)
  494. onHideTooltip: base.hideTooltip()
  495. }
  496. SidebarAdvanced
  497. {
  498. id: sidebarAdvanced
  499. visible: false
  500. onShowTooltip: base.showTooltip(item, location, text)
  501. onHideTooltip: base.hideTooltip()
  502. }
  503. Component.onCompleted:
  504. {
  505. modesListModel.append({
  506. text: catalog.i18nc("@title:tab", "Recommended"),
  507. tooltipText: catalog.i18nc("@tooltip", "<b>Recommended Print Setup</b><br/><br/>Print with the recommended settings for the selected printer, material and quality."),
  508. item: sidebarSimple
  509. })
  510. modesListModel.append({
  511. text: catalog.i18nc("@title:tab", "Custom"),
  512. tooltipText: catalog.i18nc("@tooltip", "<b>Custom Print Setup</b><br/><br/>Print with finegrained control over every last bit of the slicing process."),
  513. item: sidebarAdvanced
  514. })
  515. var index = Math.round(UM.Preferences.getValue("cura/active_mode"))
  516. if(index != null && !isNaN(index))
  517. {
  518. currentModeIndex = index;
  519. }
  520. else
  521. {
  522. currentModeIndex = 0;
  523. }
  524. }
  525. UM.SettingPropertyProvider
  526. {
  527. id: machineExtruderCount
  528. containerStack: Cura.MachineManager.activeMachine
  529. key: "machine_extruder_count"
  530. watchedProperties: [ "value" ]
  531. storeIndex: 0
  532. }
  533. UM.SettingPropertyProvider
  534. {
  535. id: machineHeatedBed
  536. containerStack: Cura.MachineManager.activeMachine
  537. key: "machine_heated_bed"
  538. watchedProperties: [ "value" ]
  539. storeIndex: 0
  540. }
  541. }