Sidebar.qml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Cura is released under the terms of the AGPLv3 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. // 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 int backendState: UM.Backend.state
  20. property bool monitoringPrint: false
  21. property variant printDuration: PrintInformation.currentPrintTime
  22. property variant printDurationPerFeature: PrintInformation.printTimesPerFeature
  23. property variant printMaterialLengths: PrintInformation.materialLengths
  24. property variant printMaterialWeights: PrintInformation.materialWeights
  25. property variant printMaterialCosts: PrintInformation.materialCosts
  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:1, y:item.y}, text);
  37. }
  38. }
  39. function showTooltip(item, position, text)
  40. {
  41. tooltip.text = text;
  42. position = item.mapToItem(base, position.x, 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. SidebarHeader {
  72. id: header
  73. width: parent.width
  74. onShowTooltip: base.showTooltip(item, location, text)
  75. onHideTooltip: base.hideTooltip()
  76. }
  77. Rectangle {
  78. id: headerSeparator
  79. width: parent.width
  80. visible: !monitoringPrint && !hideSettings
  81. height: visible ? UM.Theme.getSize("sidebar_lining").height : 0
  82. color: UM.Theme.getColor("sidebar_lining")
  83. anchors.top: header.bottom
  84. anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0
  85. }
  86. onCurrentModeIndexChanged:
  87. {
  88. UM.Preferences.setValue("cura/active_mode", currentModeIndex);
  89. if(modesListModel.count > base.currentModeIndex)
  90. {
  91. sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "replace": true });
  92. }
  93. }
  94. Text {
  95. id: settingsModeLabel
  96. text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox","Print Setup disabled\nG-code files cannot be modified");
  97. anchors.left: parent.left
  98. anchors.leftMargin: UM.Theme.getSize("default_margin").width;
  99. anchors.top: headerSeparator.bottom
  100. anchors.topMargin: UM.Theme.getSize("default_margin").height
  101. width: parent.width * 0.45 - 2 * UM.Theme.getSize("default_margin").width
  102. font: UM.Theme.getFont("large")
  103. color: UM.Theme.getColor("text")
  104. visible: !monitoringPrint
  105. elide: Text.ElideRight
  106. }
  107. Rectangle {
  108. id: settingsModeSelection
  109. color: "transparent"
  110. width: parent.width * 0.55
  111. height: UM.Theme.getSize("sidebar_header_mode_toggle").height
  112. anchors.right: parent.right
  113. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  114. anchors.top: headerSeparator.bottom
  115. anchors.topMargin: UM.Theme.getSize("default_margin").height
  116. visible: !monitoringPrint && !hideSettings
  117. Component{
  118. id: wizardDelegate
  119. Button {
  120. height: settingsModeSelection.height
  121. anchors.left: parent.left
  122. anchors.leftMargin: model.index * (settingsModeSelection.width / 2)
  123. anchors.verticalCenter: parent.verticalCenter
  124. width: 0.5 * parent.width
  125. text: model.text
  126. exclusiveGroup: modeMenuGroup;
  127. checkable: true;
  128. checked: base.currentModeIndex == index
  129. onClicked: base.currentModeIndex = index
  130. onHoveredChanged: {
  131. if (hovered)
  132. {
  133. tooltipDelayTimer.item = settingsModeSelection
  134. tooltipDelayTimer.text = model.tooltipText
  135. tooltipDelayTimer.start();
  136. }
  137. else
  138. {
  139. tooltipDelayTimer.stop();
  140. base.hideTooltip();
  141. }
  142. }
  143. style: ButtonStyle {
  144. background: Rectangle {
  145. border.width: UM.Theme.getSize("default_lining").width
  146. border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") :
  147. control.pressed ? UM.Theme.getColor("toggle_active_border") :
  148. control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border")
  149. color: control.checked ? UM.Theme.getColor("toggle_checked") :
  150. control.pressed ? UM.Theme.getColor("toggle_active") :
  151. control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
  152. Behavior on color { ColorAnimation { duration: 50; } }
  153. Label {
  154. anchors.centerIn: parent
  155. color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
  156. control.pressed ? UM.Theme.getColor("toggle_active_text") :
  157. control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
  158. font: UM.Theme.getFont("default")
  159. text: control.text;
  160. }
  161. }
  162. label: Item { }
  163. }
  164. }
  165. }
  166. ExclusiveGroup { id: modeMenuGroup; }
  167. Label
  168. {
  169. id: toggleLeftText
  170. anchors.right: modeToggleSwitch.left
  171. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  172. anchors.verticalCenter: parent.verticalCenter
  173. text: ""
  174. color:
  175. {
  176. if(toggleLeftTextMouseArea.containsMouse)
  177. {
  178. return UM.Theme.getColor("mode_switch_text_hover");
  179. }
  180. else if(!modeToggleSwitch.checked)
  181. {
  182. return UM.Theme.getColor("mode_switch_text_checked");
  183. }
  184. else
  185. {
  186. return UM.Theme.getColor("mode_switch_text");
  187. }
  188. }
  189. font: UM.Theme.getFont("default")
  190. MouseArea
  191. {
  192. id: toggleLeftTextMouseArea
  193. hoverEnabled: true
  194. anchors.fill: parent
  195. onClicked:
  196. {
  197. modeToggleSwitch.checked = false;
  198. }
  199. Component.onCompleted:
  200. {
  201. clicked.connect(modeToggleSwitch.clicked)
  202. }
  203. }
  204. }
  205. Switch
  206. {
  207. id: modeToggleSwitch
  208. checked: false
  209. anchors.right: toggleRightText.left
  210. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  211. anchors.verticalCenter: parent.verticalCenter
  212. property bool _hovered: modeToggleSwitchMouseArea.containsMouse || toggleLeftTextMouseArea.containsMouse || toggleRightTextMouseArea.containsMouse
  213. MouseArea
  214. {
  215. id: modeToggleSwitchMouseArea
  216. anchors.fill: parent
  217. hoverEnabled: true
  218. acceptedButtons: Qt.NoButton
  219. }
  220. onCheckedChanged:
  221. {
  222. var index = 0;
  223. if (checked)
  224. {
  225. index = 1;
  226. }
  227. updateActiveMode(index);
  228. }
  229. function updateActiveMode(index)
  230. {
  231. base.currentModeIndex = index;
  232. UM.Preferences.setValue("cura/active_mode", index);
  233. }
  234. style: UM.Theme.styles.mode_switch
  235. }
  236. Label
  237. {
  238. id: toggleRightText
  239. anchors.right: parent.right
  240. anchors.verticalCenter: parent.verticalCenter
  241. text: ""
  242. color:
  243. {
  244. if(toggleRightTextMouseArea.containsMouse)
  245. {
  246. return UM.Theme.getColor("mode_switch_text_hover");
  247. }
  248. else if(modeToggleSwitch.checked)
  249. {
  250. return UM.Theme.getColor("mode_switch_text_checked");
  251. }
  252. else
  253. {
  254. return UM.Theme.getColor("mode_switch_text");
  255. }
  256. }
  257. font: UM.Theme.getFont("default")
  258. MouseArea
  259. {
  260. id: toggleRightTextMouseArea
  261. hoverEnabled: true
  262. anchors.fill: parent
  263. onClicked:
  264. {
  265. modeToggleSwitch.checked = true;
  266. }
  267. Component.onCompleted:
  268. {
  269. clicked.connect(modeToggleSwitch.clicked)
  270. }
  271. }
  272. }
  273. }
  274. StackView
  275. {
  276. id: sidebarContents
  277. anchors.bottom: footerSeparator.top
  278. anchors.top: settingsModeSelection.bottom
  279. anchors.topMargin: UM.Theme.getSize("default_margin").height
  280. anchors.left: base.left
  281. anchors.right: base.right
  282. visible: !monitoringPrint && !hideSettings
  283. delegate: StackViewDelegate
  284. {
  285. function transitionFinished(properties)
  286. {
  287. properties.exitItem.opacity = 1
  288. }
  289. pushTransition: StackViewTransition
  290. {
  291. PropertyAnimation
  292. {
  293. target: enterItem
  294. property: "opacity"
  295. from: 0
  296. to: 1
  297. duration: 100
  298. }
  299. PropertyAnimation
  300. {
  301. target: exitItem
  302. property: "opacity"
  303. from: 1
  304. to: 0
  305. duration: 100
  306. }
  307. }
  308. }
  309. }
  310. Loader
  311. {
  312. id: controlItem
  313. anchors.bottom: footerSeparator.top
  314. anchors.top: headerSeparator.bottom
  315. anchors.left: base.left
  316. anchors.right: base.right
  317. sourceComponent:
  318. {
  319. if(monitoringPrint && connectedPrinter != null)
  320. {
  321. if(connectedPrinter.controlItem != null)
  322. {
  323. return connectedPrinter.controlItem
  324. }
  325. }
  326. return null
  327. }
  328. }
  329. Loader
  330. {
  331. anchors.bottom: footerSeparator.top
  332. anchors.top: headerSeparator.bottom
  333. anchors.left: base.left
  334. anchors.right: base.right
  335. source:
  336. {
  337. if(controlItem.sourceComponent == null)
  338. {
  339. if(monitoringPrint)
  340. {
  341. return "PrintMonitor.qml"
  342. } else
  343. {
  344. return "SidebarContents.qml"
  345. }
  346. }
  347. else
  348. {
  349. return ""
  350. }
  351. }
  352. }
  353. Rectangle
  354. {
  355. id: footerSeparator
  356. width: parent.width
  357. height: UM.Theme.getSize("sidebar_lining").height
  358. color: UM.Theme.getColor("sidebar_lining")
  359. anchors.bottom: printSpecs.top
  360. anchors.bottomMargin: UM.Theme.getSize("default_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize
  361. }
  362. Rectangle
  363. {
  364. id: printSpecs
  365. anchors.left: parent.left
  366. anchors.bottom: parent.bottom
  367. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  368. anchors.bottomMargin: UM.Theme.getSize("default_margin").height
  369. height: childrenRect.height
  370. UM.TooltipArea
  371. {
  372. id: timeSpecPerFeatureTooltipArea
  373. width: timeSpec.width
  374. height: timeSpec.height
  375. anchors.left: parent.left
  376. anchors.bottom: timeSpecDescription.top
  377. text: {
  378. var order = ["inset_0", "inset_x", "skin", "infill", "support_infill", "support_interface", "support", "travel", "retract", "none"];
  379. var visible_names = {
  380. "inset_0": catalog.i18nc("@tooltip", "Outer Wall"),
  381. "inset_x": catalog.i18nc("@tooltip", "Inner Walls"),
  382. "skin": catalog.i18nc("@tooltip", "Skin"),
  383. "infill": catalog.i18nc("@tooltip", "Infill"),
  384. "support_infill": catalog.i18nc("@tooltip", "Support Infill"),
  385. "support_interface": catalog.i18nc("@tooltip", "Support Interface"),
  386. "support": catalog.i18nc("@tooltip", "Support"),
  387. "travel": catalog.i18nc("@tooltip", "Travel"),
  388. "retract": catalog.i18nc("@tooltip", "Retractions"),
  389. "none": catalog.i18nc("@tooltip", "Other")
  390. };
  391. var result = "";
  392. for(var feature in order)
  393. {
  394. feature = order[feature];
  395. if(base.printDurationPerFeature[feature] && base.printDurationPerFeature[feature].totalSeconds > 0)
  396. {
  397. result += "<br/>" + visible_names[feature] + ": " + base.printDurationPerFeature[feature].getDisplayString(UM.DurationFormat.Short);
  398. }
  399. }
  400. result = result.replace(/^\<br\/\>/, ""); // remove newline before first item
  401. return result;
  402. }
  403. Text
  404. {
  405. id: timeSpec
  406. anchors.left: parent.left
  407. anchors.bottom: parent.bottom
  408. font: UM.Theme.getFont("large")
  409. color: UM.Theme.getColor("text_subtext")
  410. text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
  411. }
  412. }
  413. Text
  414. {
  415. id: timeSpecDescription
  416. anchors.left: parent.left
  417. anchors.bottom: lengthSpec.top
  418. font: UM.Theme.getFont("very_small")
  419. color: UM.Theme.getColor("text_subtext")
  420. text: catalog.i18nc("@description", "Print time")
  421. }
  422. Text
  423. {
  424. id: lengthSpec
  425. anchors.left: parent.left
  426. anchors.bottom: parent.bottom
  427. font: UM.Theme.getFont("very_small")
  428. color: UM.Theme.getColor("text_subtext")
  429. text:
  430. {
  431. var lengths = [];
  432. var weights = [];
  433. var costs = [];
  434. var someCostsKnown = false;
  435. if(base.printMaterialLengths) {
  436. for(var index = 0; index < base.printMaterialLengths.length; index++)
  437. {
  438. if(base.printMaterialLengths[index] > 0)
  439. {
  440. lengths.push(base.printMaterialLengths[index].toFixed(2));
  441. weights.push(String(Math.floor(base.printMaterialWeights[index])));
  442. var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
  443. costs.push(cost);
  444. if(cost > 0)
  445. {
  446. someCostsKnown = true;
  447. }
  448. }
  449. }
  450. }
  451. if(lengths.length == 0)
  452. {
  453. lengths = ["0.00"];
  454. weights = ["0"];
  455. costs = ["0.00"];
  456. }
  457. if(someCostsKnown)
  458. {
  459. return catalog.i18nc("@label", "%1 m / ~ %2 g / ~ %4 %3").arg(lengths.join(" + "))
  460. .arg(weights.join(" + ")).arg(costs.join(" + ")).arg(UM.Preferences.getValue("cura/currency"));
  461. }
  462. else
  463. {
  464. return catalog.i18nc("@label", "%1 m / ~ %2 g").arg(lengths.join(" + ")).arg(weights.join(" + "));
  465. }
  466. }
  467. }
  468. }
  469. // SaveButton and MonitorButton are actually the bottom footer panels.
  470. // "!monitoringPrint" currently means "show-settings-mode"
  471. SaveButton
  472. {
  473. id: saveButton
  474. implicitWidth: base.width
  475. anchors.top: footerSeparator.bottom
  476. anchors.topMargin: UM.Theme.getSize("default_margin").height
  477. anchors.bottom: parent.bottom
  478. visible: !monitoringPrint
  479. }
  480. MonitorButton
  481. {
  482. id: monitorButton
  483. implicitWidth: base.width
  484. anchors.top: footerSeparator.bottom
  485. anchors.topMargin: UM.Theme.getSize("default_margin").height
  486. anchors.bottom: parent.bottom
  487. visible: monitoringPrint
  488. }
  489. SidebarTooltip
  490. {
  491. id: tooltip;
  492. }
  493. // Setting mode: Recommended or Custom
  494. ListModel
  495. {
  496. id: modesListModel;
  497. }
  498. SidebarSimple
  499. {
  500. id: sidebarSimple;
  501. visible: false;
  502. onShowTooltip: base.showTooltip(item, location, text)
  503. onHideTooltip: base.hideTooltip()
  504. }
  505. SidebarAdvanced
  506. {
  507. id: sidebarAdvanced;
  508. visible: false;
  509. onShowTooltip: base.showTooltip(item, location, text)
  510. onHideTooltip: base.hideTooltip()
  511. }
  512. Component.onCompleted:
  513. {
  514. modesListModel.append({
  515. text: catalog.i18nc("@title:tab", "Recommended"),
  516. tooltipText: catalog.i18nc("@tooltip", "<b>Recommended Print Setup</b><br/><br/>Print with the recommended settings for the selected printer, material and quality."),
  517. item: sidebarSimple
  518. })
  519. modesListModel.append({
  520. text: catalog.i18nc("@title:tab", "Custom"),
  521. tooltipText: catalog.i18nc("@tooltip", "<b>Custom Print Setup</b><br/><br/>Print with finegrained control over every last bit of the slicing process."),
  522. item: sidebarAdvanced
  523. })
  524. sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true });
  525. toggleLeftText.text = modesListModel.get(0).text;
  526. toggleRightText.text = modesListModel.get(1).text;
  527. var index = parseInt(UM.Preferences.getValue("cura/active_mode"));
  528. if (index)
  529. {
  530. currentModeIndex = index;
  531. modeToggleSwitch.checked = index > 0;
  532. }
  533. }
  534. UM.SettingPropertyProvider
  535. {
  536. id: machineExtruderCount
  537. containerStackId: Cura.MachineManager.activeMachineId
  538. key: "machine_extruder_count"
  539. watchedProperties: [ "value" ]
  540. storeIndex: 0
  541. }
  542. UM.SettingPropertyProvider
  543. {
  544. id: machineHeatedBed
  545. containerStackId: Cura.MachineManager.activeMachineId
  546. key: "machine_heated_bed"
  547. watchedProperties: [ "value" ]
  548. storeIndex: 0
  549. }
  550. }