PrepareSidebar.qml 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  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 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. property var index: 0
  226. model: modesListModel
  227. delegate: wizardDelegate
  228. anchors.top: parent.top
  229. anchors.left: parent.left
  230. width: parent.width
  231. }
  232. }
  233. StackView
  234. {
  235. id: sidebarContents
  236. anchors.bottom: footerSeparator.top
  237. anchors.top: settingsModeSelection.bottom
  238. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  239. anchors.left: base.left
  240. anchors.right: base.right
  241. visible: !hideSettings
  242. replaceEnter: Transition {
  243. PropertyAnimation {
  244. property: "opacity"
  245. from: 0
  246. to:1
  247. duration: 100
  248. }
  249. }
  250. replaceExit: Transition {
  251. PropertyAnimation {
  252. property: "opacity"
  253. from: 1
  254. to:0
  255. duration: 100
  256. }
  257. }
  258. }
  259. Loader
  260. {
  261. anchors.bottom: footerSeparator.top
  262. anchors.top: headerSeparator.bottom
  263. anchors.left: base.left
  264. anchors.right: base.right
  265. source: "SidebarContents.qml"
  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.round(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. clip: true
  286. Label
  287. {
  288. id: timeDetails
  289. anchors.left: parent.left
  290. anchors.bottom: costSpec.top
  291. font: UM.Theme.getFont("large")
  292. color: UM.Theme.getColor("text_subtext")
  293. text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
  294. renderType: Text.NativeRendering
  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.round(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. renderType: Text.NativeRendering
  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.round(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. var result = lengths.join(" + ") + "m / ~ " + weights.join(" + ") + "g";
  446. if(someCostsKnown)
  447. {
  448. result += " / ~ " + costs.join(" + ") + " " + UM.Preferences.getValue("cura/currency");
  449. }
  450. return result;
  451. }
  452. MouseArea
  453. {
  454. id: costSpecMouseArea
  455. anchors.fill: parent
  456. hoverEnabled: true
  457. onEntered:
  458. {
  459. if(base.printDuration.valid && !base.printDuration.isTotalDurationZero)
  460. {
  461. var show_data = costSpec.getSpecsData()
  462. base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), show_data);
  463. }
  464. }
  465. onExited:
  466. {
  467. base.hideTooltip();
  468. }
  469. }
  470. }
  471. }
  472. // SaveButton is actually the bottom footer panel.
  473. SaveButton
  474. {
  475. id: saveButton
  476. implicitWidth: base.width
  477. anchors.top: footerSeparator.bottom
  478. anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
  479. anchors.bottom: parent.bottom
  480. }
  481. SidebarTooltip
  482. {
  483. id: tooltip
  484. }
  485. // Setting mode: Recommended or Custom
  486. ListModel
  487. {
  488. id: modesListModel
  489. }
  490. SidebarSimple
  491. {
  492. id: sidebarSimple
  493. visible: false
  494. onShowTooltip: base.showTooltip(item, location, text)
  495. onHideTooltip: base.hideTooltip()
  496. }
  497. SidebarAdvanced
  498. {
  499. id: sidebarAdvanced
  500. visible: false
  501. onShowTooltip: base.showTooltip(item, location, text)
  502. onHideTooltip: base.hideTooltip()
  503. }
  504. Component.onCompleted:
  505. {
  506. modesListModel.append({
  507. text: catalog.i18nc("@title:tab", "Recommended"),
  508. tooltipText: catalog.i18nc("@tooltip", "<b>Recommended Print Setup</b><br/><br/>Print with the recommended settings for the selected printer, material and quality."),
  509. item: sidebarSimple
  510. })
  511. modesListModel.append({
  512. text: catalog.i18nc("@title:tab", "Custom"),
  513. tooltipText: catalog.i18nc("@tooltip", "<b>Custom Print Setup</b><br/><br/>Print with finegrained control over every last bit of the slicing process."),
  514. item: sidebarAdvanced
  515. })
  516. sidebarContents.replace(modesListModel.get(base.currentModeIndex).item, { "immediate": true })
  517. var index = Math.round(UM.Preferences.getValue("cura/active_mode"))
  518. if(index)
  519. {
  520. currentModeIndex = index;
  521. }
  522. }
  523. UM.SettingPropertyProvider
  524. {
  525. id: machineExtruderCount
  526. containerStack: Cura.MachineManager.activeMachine
  527. key: "machine_extruder_count"
  528. watchedProperties: [ "value" ]
  529. storeIndex: 0
  530. }
  531. UM.SettingPropertyProvider
  532. {
  533. id: machineHeatedBed
  534. containerStack: Cura.MachineManager.activeMachine
  535. key: "machine_heated_bed"
  536. watchedProperties: [ "value" ]
  537. storeIndex: 0
  538. }
  539. }