Sidebar.qml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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 || control.pressed) ? UM.Theme.getColor("action_button_active_border") :
  147. control.hovered ? UM.Theme.getColor("action_button_hovered_border") :
  148. UM.Theme.getColor("action_button_border")
  149. color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") :
  150. control.hovered ? UM.Theme.getColor("action_button_hovered") :
  151. UM.Theme.getColor("action_button")
  152. Behavior on color { ColorAnimation { duration: 50; } }
  153. Label {
  154. anchors.centerIn: parent
  155. color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") :
  156. control.hovered ? UM.Theme.getColor("action_button_hovered_text") :
  157. UM.Theme.getColor("action_button_text")
  158. font: UM.Theme.getFont("default")
  159. text: control.text;
  160. }
  161. }
  162. label: Item { }
  163. }
  164. }
  165. }
  166. ExclusiveGroup { id: modeMenuGroup; }
  167. ListView
  168. {
  169. id: modesList
  170. property var index: 0
  171. model: modesListModel
  172. delegate: wizardDelegate
  173. anchors.top: parent.top
  174. anchors.left: parent.left
  175. width: parent.width
  176. }
  177. }
  178. Item
  179. {
  180. id: globalProfileRow
  181. height: UM.Theme.getSize("sidebar_setup").height
  182. visible: !sidebar.monitoringPrint && !sidebar.hideSettings
  183. anchors
  184. {
  185. top: settingsModeSelection.bottom
  186. topMargin: UM.Theme.getSize("default_margin").width
  187. left: parent.left
  188. leftMargin: UM.Theme.getSize("default_margin").width
  189. right: parent.right
  190. rightMargin: UM.Theme.getSize("default_margin").width
  191. }
  192. Text
  193. {
  194. id: globalProfileLabel
  195. text: catalog.i18nc("@label","Profile:");
  196. width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width
  197. font: UM.Theme.getFont("default");
  198. color: UM.Theme.getColor("text");
  199. verticalAlignment: Text.AlignVCenter
  200. anchors.top: parent.top
  201. anchors.bottom: parent.bottom
  202. }
  203. ToolButton
  204. {
  205. id: globalProfileSelection
  206. text: {
  207. var result = Cura.MachineManager.activeQualityName;
  208. if (Cura.MachineManager.activeQualityLayerHeight > 0) {
  209. result += " <font color=\"" + UM.Theme.getColor("text_detail") + "\">";
  210. result += " - ";
  211. result += Cura.MachineManager.activeQualityLayerHeight + "mm";
  212. result += "</font>";
  213. }
  214. return result;
  215. }
  216. enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1
  217. width: parent.width * 0.7 + UM.Theme.getSize("default_margin").width
  218. height: UM.Theme.getSize("setting_control").height
  219. anchors.right: parent.right
  220. tooltip: Cura.MachineManager.activeQualityName
  221. style: UM.Theme.styles.sidebar_header_button
  222. activeFocusOnPress: true;
  223. property var valueWarning: !Cura.MachineManager.isActiveQualitySupported
  224. menu: ProfileMenu { }
  225. UM.SimpleButton
  226. {
  227. id: customisedSettings
  228. visible: Cura.MachineManager.hasUserSettings
  229. height: parent.height * 0.6
  230. width: parent.height * 0.6
  231. anchors.verticalCenter: parent.verticalCenter
  232. anchors.right: parent.right
  233. anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("default_margin").width
  234. color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
  235. iconSource: UM.Theme.getIcon("star");
  236. onClicked:
  237. {
  238. forceActiveFocus();
  239. Cura.Actions.manageProfiles.trigger()
  240. }
  241. onEntered:
  242. {
  243. var content = catalog.i18nc("@tooltip","Some setting/override values are different from the values stored in the profile.\n\nClick to open the profile manager.")
  244. base.showTooltip(globalProfileRow, Qt.point(-UM.Theme.getSize("default_margin").width, 0), content)
  245. }
  246. onExited: base.hideTooltip()
  247. }
  248. }
  249. }
  250. StackView
  251. {
  252. id: sidebarContents
  253. anchors.bottom: footerSeparator.top
  254. anchors.top: globalProfileRow.bottom
  255. anchors.topMargin: UM.Theme.getSize("default_margin").height
  256. anchors.left: base.left
  257. anchors.right: base.right
  258. visible: !monitoringPrint && !hideSettings
  259. delegate: StackViewDelegate
  260. {
  261. function transitionFinished(properties)
  262. {
  263. properties.exitItem.opacity = 1
  264. }
  265. pushTransition: StackViewTransition
  266. {
  267. PropertyAnimation
  268. {
  269. target: enterItem
  270. property: "opacity"
  271. from: 0
  272. to: 1
  273. duration: 100
  274. }
  275. PropertyAnimation
  276. {
  277. target: exitItem
  278. property: "opacity"
  279. from: 1
  280. to: 0
  281. duration: 100
  282. }
  283. }
  284. }
  285. }
  286. Loader
  287. {
  288. id: controlItem
  289. anchors.bottom: footerSeparator.top
  290. anchors.top: headerSeparator.bottom
  291. anchors.left: base.left
  292. anchors.right: base.right
  293. sourceComponent:
  294. {
  295. if(monitoringPrint && connectedPrinter != null)
  296. {
  297. if(connectedPrinter.controlItem != null)
  298. {
  299. return connectedPrinter.controlItem
  300. }
  301. }
  302. return null
  303. }
  304. }
  305. Loader
  306. {
  307. anchors.bottom: footerSeparator.top
  308. anchors.top: headerSeparator.bottom
  309. anchors.left: base.left
  310. anchors.right: base.right
  311. source:
  312. {
  313. if(controlItem.sourceComponent == null)
  314. {
  315. if(monitoringPrint)
  316. {
  317. return "PrintMonitor.qml"
  318. } else
  319. {
  320. return "SidebarContents.qml"
  321. }
  322. }
  323. else
  324. {
  325. return ""
  326. }
  327. }
  328. }
  329. Rectangle
  330. {
  331. id: footerSeparator
  332. width: parent.width
  333. height: UM.Theme.getSize("sidebar_lining").height
  334. color: UM.Theme.getColor("sidebar_lining")
  335. anchors.bottom: printSpecs.top
  336. anchors.bottomMargin: UM.Theme.getSize("default_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize
  337. }
  338. Rectangle
  339. {
  340. id: printSpecs
  341. anchors.left: parent.left
  342. anchors.bottom: parent.bottom
  343. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  344. anchors.bottomMargin: UM.Theme.getSize("default_margin").height
  345. height: childrenRect.height
  346. UM.TooltipArea
  347. {
  348. id: timeSpecPerFeatureTooltipArea
  349. width: timeSpec.width
  350. height: timeSpec.height
  351. anchors.left: parent.left
  352. anchors.bottom: timeSpecDescription.top
  353. text: {
  354. var order = ["inset_0", "inset_x", "skin", "infill", "support_infill", "support_interface", "support", "travel", "retract", "none"];
  355. var visible_names = {
  356. "inset_0": catalog.i18nc("@tooltip", "Outer Wall"),
  357. "inset_x": catalog.i18nc("@tooltip", "Inner Walls"),
  358. "skin": catalog.i18nc("@tooltip", "Skin"),
  359. "infill": catalog.i18nc("@tooltip", "Infill"),
  360. "support_infill": catalog.i18nc("@tooltip", "Support Infill"),
  361. "support_interface": catalog.i18nc("@tooltip", "Support Interface"),
  362. "support": catalog.i18nc("@tooltip", "Support"),
  363. "travel": catalog.i18nc("@tooltip", "Travel"),
  364. "retract": catalog.i18nc("@tooltip", "Retractions"),
  365. "none": catalog.i18nc("@tooltip", "Other")
  366. };
  367. var result = "";
  368. for(var feature in order)
  369. {
  370. feature = order[feature];
  371. if(base.printDurationPerFeature[feature] && base.printDurationPerFeature[feature].totalSeconds > 0)
  372. {
  373. result += "<br/>" + visible_names[feature] + ": " + base.printDurationPerFeature[feature].getDisplayString(UM.DurationFormat.Short);
  374. }
  375. }
  376. result = result.replace(/^\<br\/\>/, ""); // remove newline before first item
  377. return result;
  378. }
  379. Text
  380. {
  381. id: timeSpec
  382. anchors.left: parent.left
  383. anchors.bottom: parent.bottom
  384. font: UM.Theme.getFont("large")
  385. color: UM.Theme.getColor("text_emphasis")
  386. text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
  387. }
  388. }
  389. Text
  390. {
  391. id: timeSpecDescription
  392. anchors.left: parent.left
  393. anchors.bottom: lengthSpec.top
  394. font: UM.Theme.getFont("very_small")
  395. color: UM.Theme.getColor("text_subtext")
  396. text: catalog.i18nc("@description", "Print time")
  397. }
  398. Text
  399. {
  400. id: lengthSpec
  401. anchors.left: parent.left
  402. anchors.bottom: parent.bottom
  403. font: UM.Theme.getFont("very_small")
  404. color: UM.Theme.getColor("text_subtext")
  405. text:
  406. {
  407. var lengths = [];
  408. var weights = [];
  409. var costs = [];
  410. var someCostsKnown = false;
  411. if(base.printMaterialLengths) {
  412. for(var index = 0; index < base.printMaterialLengths.length; index++)
  413. {
  414. if(base.printMaterialLengths[index] > 0)
  415. {
  416. lengths.push(base.printMaterialLengths[index].toFixed(2));
  417. weights.push(String(Math.floor(base.printMaterialWeights[index])));
  418. var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
  419. costs.push(cost);
  420. if(cost > 0)
  421. {
  422. someCostsKnown = true;
  423. }
  424. }
  425. }
  426. }
  427. if(lengths.length == 0)
  428. {
  429. lengths = ["0.00"];
  430. weights = ["0"];
  431. costs = ["0.00"];
  432. }
  433. if(someCostsKnown)
  434. {
  435. return catalog.i18nc("@label", "%1m / ~ %2g / ~ %4 %3").arg(lengths.join(" + "))
  436. .arg(weights.join(" + ")).arg(costs.join(" + ")).arg(UM.Preferences.getValue("cura/currency"));
  437. }
  438. else
  439. {
  440. return catalog.i18nc("@label", "%1m / ~ %2g").arg(lengths.join(" + ")).arg(weights.join(" + "));
  441. }
  442. }
  443. }
  444. }
  445. // SaveButton and MonitorButton are actually the bottom footer panels.
  446. // "!monitoringPrint" currently means "show-settings-mode"
  447. SaveButton
  448. {
  449. id: saveButton
  450. implicitWidth: base.width
  451. anchors.top: footerSeparator.bottom
  452. anchors.topMargin: UM.Theme.getSize("default_margin").height
  453. anchors.bottom: parent.bottom
  454. visible: !monitoringPrint
  455. }
  456. MonitorButton
  457. {
  458. id: monitorButton
  459. implicitWidth: base.width
  460. anchors.top: footerSeparator.bottom
  461. anchors.topMargin: UM.Theme.getSize("default_margin").height
  462. anchors.bottom: parent.bottom
  463. visible: monitoringPrint
  464. }
  465. SidebarTooltip
  466. {
  467. id: tooltip;
  468. }
  469. // Setting mode: Recommended or Custom
  470. ListModel
  471. {
  472. id: modesListModel;
  473. }
  474. SidebarSimple
  475. {
  476. id: sidebarSimple;
  477. visible: false;
  478. onShowTooltip: base.showTooltip(item, location, text)
  479. onHideTooltip: base.hideTooltip()
  480. }
  481. SidebarAdvanced
  482. {
  483. id: sidebarAdvanced;
  484. visible: false;
  485. onShowTooltip: base.showTooltip(item, location, text)
  486. onHideTooltip: base.hideTooltip()
  487. }
  488. Component.onCompleted:
  489. {
  490. modesListModel.append({
  491. text: catalog.i18nc("@title:tab", "Recommended"),
  492. tooltipText: catalog.i18nc("@tooltip", "<b>Recommended Print Setup</b><br/><br/>Print with the recommended settings for the selected printer, material and quality."),
  493. item: sidebarSimple
  494. })
  495. modesListModel.append({
  496. text: catalog.i18nc("@title:tab", "Custom"),
  497. tooltipText: catalog.i18nc("@tooltip", "<b>Custom Print Setup</b><br/><br/>Print with finegrained control over every last bit of the slicing process."),
  498. item: sidebarAdvanced
  499. })
  500. sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true });
  501. var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
  502. if(index)
  503. {
  504. currentModeIndex = index;
  505. }
  506. }
  507. UM.SettingPropertyProvider
  508. {
  509. id: machineExtruderCount
  510. containerStackId: Cura.MachineManager.activeMachineId
  511. key: "machine_extruder_count"
  512. watchedProperties: [ "value" ]
  513. storeIndex: 0
  514. }
  515. UM.SettingPropertyProvider
  516. {
  517. id: machineHeatedBed
  518. containerStackId: Cura.MachineManager.activeMachineId
  519. key: "machine_heated_bed"
  520. watchedProperties: [ "value" ]
  521. storeIndex: 0
  522. }
  523. }