MonitorPrinterCard.qml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. // Copyright (c) 2019 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.3
  4. import QtQuick.Controls 2.0
  5. import QtQuick.Dialogs 1.1
  6. import UM 1.3 as UM
  7. import Cura 1.0 as Cura
  8. /**
  9. * A Printer Card is has two main components: the printer portion and the print job portion, the latter being paired in
  10. * the UI when a print job is paired a printer in-cluster.
  11. *
  12. * NOTE: For most labels, a fixed height with vertical alignment is used to make layouts more deterministic (like the
  13. * fixed-size textboxes used in original mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
  14. * with '// FIXED-LINE-HEIGHT:'.
  15. */
  16. Item
  17. {
  18. id: base
  19. // The printer which all printer data is derived from
  20. property var printer: null
  21. property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here
  22. // If the printer card's controls are enabled. This is used by the carousel to prevent opening the context menu or
  23. // camera while the printer card is not "in focus"
  24. property var enabled: true
  25. // If the printer is a cloud printer or not. Other items base their enabled state off of this boolean. In the future
  26. // they might not need to though.
  27. property bool cloudConnection: Cura.MachineManager.activeMachineIsUsingCloudConnection
  28. width: 834 * screenScaleFactor // TODO: Theme!
  29. height: childrenRect.height
  30. Rectangle
  31. {
  32. id: background
  33. anchors.fill: parent
  34. color: UM.Theme.getColor("monitor_card_background")
  35. border
  36. {
  37. color: UM.Theme.getColor("monitor_card_border")
  38. width: borderSize // TODO: Remove once themed
  39. }
  40. radius: 2 * screenScaleFactor // TODO: Theme!
  41. }
  42. // Printer portion
  43. Item
  44. {
  45. id: printerInfo
  46. width: parent.width
  47. height: 144 * screenScaleFactor // TODO: Theme!
  48. Row
  49. {
  50. anchors
  51. {
  52. left: parent.left
  53. leftMargin: 36 * screenScaleFactor // TODO: Theme!
  54. verticalCenter: parent.verticalCenter
  55. }
  56. spacing: 18 * screenScaleFactor // TODO: Theme!
  57. Rectangle
  58. {
  59. id: printerImage
  60. width: 108 * screenScaleFactor // TODO: Theme!
  61. height: 108 * screenScaleFactor // TODO: Theme!
  62. color: printer ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
  63. radius: 8 // TODO: Theme!
  64. Image
  65. {
  66. anchors.fill: parent
  67. fillMode: Image.PreserveAspectFit
  68. source: printer ? "../png/" + printer.type + ".png" : ""
  69. mipmap: true
  70. }
  71. }
  72. Item
  73. {
  74. anchors
  75. {
  76. verticalCenter: parent.verticalCenter
  77. }
  78. width: 180 * screenScaleFactor // TODO: Theme!
  79. height: childrenRect.height
  80. Rectangle
  81. {
  82. id: printerNameLabel
  83. color: printer ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
  84. height: 18 * screenScaleFactor // TODO: Theme!
  85. width: parent.width
  86. radius: 2 * screenScaleFactor // TODO: Theme!
  87. Label
  88. {
  89. text: printer && printer.name ? printer.name : ""
  90. color: UM.Theme.getColor("monitor_text_primary")
  91. elide: Text.ElideRight
  92. font: UM.Theme.getFont("large") // 16pt, bold
  93. width: parent.width
  94. visible: printer
  95. // FIXED-LINE-HEIGHT:
  96. height: parent.height
  97. verticalAlignment: Text.AlignVCenter
  98. renderType: Text.NativeRendering
  99. }
  100. }
  101. Rectangle
  102. {
  103. color: UM.Theme.getColor("monitor_skeleton_loading")
  104. height: 18 * screenScaleFactor // TODO: Theme!
  105. radius: 2 * screenScaleFactor // TODO: Theme!
  106. visible: !printer
  107. width: 48 * screenScaleFactor // TODO: Theme!
  108. }
  109. MonitorPrinterPill
  110. {
  111. id: printerFamilyPill
  112. anchors
  113. {
  114. top: printerNameLabel.bottom
  115. topMargin: 6 * screenScaleFactor // TODO: Theme!
  116. left: printerNameLabel.left
  117. }
  118. text: printer ? printer.type : ""
  119. }
  120. Item
  121. {
  122. id: managePrinterLink
  123. anchors {
  124. top: printerFamilyPill.bottom
  125. topMargin: 6 * screenScaleFactor
  126. }
  127. height: 18 * screenScaleFactor // TODO: Theme!
  128. width: childrenRect.width
  129. Label
  130. {
  131. id: managePrinterText
  132. anchors.verticalCenter: managePrinterLink.verticalCenter
  133. color: UM.Theme.getColor("monitor_text_link")
  134. font: UM.Theme.getFont("default")
  135. linkColor: UM.Theme.getColor("monitor_text_link")
  136. text: catalog.i18nc("@label link to Connect and Cloud interfaces", "Manage printer")
  137. renderType: Text.NativeRendering
  138. }
  139. UM.RecolorImage
  140. {
  141. id: externalLinkIcon
  142. anchors
  143. {
  144. left: managePrinterText.right
  145. leftMargin: 6 * screenScaleFactor
  146. verticalCenter: managePrinterText.verticalCenter
  147. }
  148. color: UM.Theme.getColor("monitor_text_link")
  149. source: UM.Theme.getIcon("external_link")
  150. width: 12 * screenScaleFactor
  151. height: 12 * screenScaleFactor
  152. }
  153. }
  154. MouseArea
  155. {
  156. anchors.fill: managePrinterLink
  157. onClicked: OutputDevice.openPrintJobControlPanel()
  158. onEntered:
  159. {
  160. manageQueueText.font.underline = true
  161. }
  162. onExited:
  163. {
  164. manageQueueText.font.underline = false
  165. }
  166. }
  167. }
  168. MonitorPrinterConfiguration
  169. {
  170. id: printerConfiguration
  171. anchors.verticalCenter: parent.verticalCenter
  172. buildplate: printer ? catalog.i18nc("@label", "Glass") : null // 'Glass' as a default
  173. configurations:
  174. {
  175. var configs = []
  176. if (printer)
  177. {
  178. configs.push(printer.printerConfiguration.extruderConfigurations[0])
  179. configs.push(printer.printerConfiguration.extruderConfigurations[1])
  180. }
  181. else
  182. {
  183. configs.push(null, null)
  184. }
  185. return configs
  186. }
  187. height: 72 * screenScaleFactor // TODO: Theme!te theRect's x property
  188. }
  189. }
  190. MonitorContextMenuButton
  191. {
  192. id: contextMenuButton
  193. anchors
  194. {
  195. right: parent.right
  196. rightMargin: 12 * screenScaleFactor // TODO: Theme!
  197. top: parent.top
  198. topMargin: 12 * screenScaleFactor // TODO: Theme!
  199. }
  200. width: 36 * screenScaleFactor // TODO: Theme!
  201. height: 36 * screenScaleFactor // TODO: Theme!
  202. enabled: OutputDevice.supportsPrintJobActions
  203. onClicked: enabled ? contextMenu.switchPopupState() : {}
  204. visible:
  205. {
  206. if (!printer || !printer.activePrintJob) {
  207. return false
  208. }
  209. var states = ["queued", "error", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]
  210. return states.indexOf(printer.activePrintJob.state) !== -1
  211. }
  212. }
  213. MonitorContextMenu
  214. {
  215. id: contextMenu
  216. printJob: printer ? printer.activePrintJob : null
  217. target: contextMenuButton
  218. }
  219. // For cloud printing, add this mouse area over the disabled contextButton to indicate that it's not available
  220. MouseArea
  221. {
  222. id: contextMenuDisabledButtonArea
  223. anchors.fill: contextMenuButton
  224. hoverEnabled: contextMenuButton.visible && !contextMenuButton.enabled
  225. onEntered: contextMenuDisabledInfo.open()
  226. onExited: contextMenuDisabledInfo.close()
  227. enabled: !contextMenuButton.enabled
  228. }
  229. MonitorInfoBlurb
  230. {
  231. id: contextMenuDisabledInfo
  232. text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
  233. target: contextMenuButton
  234. }
  235. CameraButton
  236. {
  237. id: cameraButton
  238. anchors
  239. {
  240. right: parent.right
  241. rightMargin: 20 * screenScaleFactor // TODO: Theme!
  242. bottom: parent.bottom
  243. bottomMargin: 20 * screenScaleFactor // TODO: Theme!
  244. }
  245. iconSource: "../svg/icons/camera.svg"
  246. enabled: !cloudConnection
  247. visible: printer
  248. }
  249. // For cloud printing, add this mouse area over the disabled cameraButton to indicate that it's not available
  250. MouseArea
  251. {
  252. id: cameraDisabledButtonArea
  253. anchors.fill: cameraButton
  254. hoverEnabled: cameraButton.visible && !cameraButton.enabled
  255. onEntered: cameraDisabledInfo.open()
  256. onExited: cameraDisabledInfo.close()
  257. enabled: !cameraButton.enabled
  258. }
  259. MonitorInfoBlurb
  260. {
  261. id: cameraDisabledInfo
  262. text: catalog.i18nc("@info", "The webcam is not available because you are monitoring a cloud printer.")
  263. target: cameraButton
  264. }
  265. }
  266. // Divider
  267. Rectangle
  268. {
  269. anchors
  270. {
  271. top: printJobInfo.top
  272. left: printJobInfo.left
  273. right: printJobInfo.right
  274. }
  275. height: borderSize // Remove once themed
  276. color: background.border.color
  277. }
  278. // Print job portion
  279. Rectangle
  280. {
  281. id: printJobInfo
  282. anchors
  283. {
  284. top: printerInfo.bottom
  285. topMargin: -borderSize * screenScaleFactor // TODO: Theme!
  286. }
  287. border
  288. {
  289. color: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? UM.Theme.getColor("warning") : "transparent" // TODO: Theme!
  290. width: borderSize // TODO: Remove once themed
  291. }
  292. color: "transparent" // TODO: Theme!
  293. height: 84 * screenScaleFactor + borderSize // TODO: Remove once themed
  294. width: parent.width
  295. Row
  296. {
  297. anchors
  298. {
  299. fill: parent
  300. topMargin: 12 * screenScaleFactor + borderSize // TODO: Theme!
  301. bottomMargin: 12 * screenScaleFactor // TODO: Theme!
  302. leftMargin: 36 * screenScaleFactor // TODO: Theme!
  303. }
  304. height: childrenRect.height
  305. spacing: 18 * screenScaleFactor // TODO: Theme!
  306. Label
  307. {
  308. id: printerStatus
  309. anchors
  310. {
  311. verticalCenter: parent.verticalCenter
  312. }
  313. color: printer ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  314. font: UM.Theme.getFont("large_bold") // 16pt, bold
  315. text: {
  316. if (!printer) {
  317. return catalog.i18nc("@label:status", "Loading...")
  318. }
  319. if (printer && printer.state == "disabled")
  320. {
  321. return catalog.i18nc("@label:status", "Unavailable")
  322. }
  323. if (printer && printer.state == "unreachable")
  324. {
  325. return catalog.i18nc("@label:status", "Unreachable")
  326. }
  327. if (printer && !printer.activePrintJob && printer.state == "idle")
  328. {
  329. return catalog.i18nc("@label:status", "Idle")
  330. }
  331. return ""
  332. }
  333. visible: text !== ""
  334. renderType: Text.NativeRendering
  335. }
  336. Item
  337. {
  338. anchors
  339. {
  340. verticalCenter: parent.verticalCenter
  341. }
  342. width: printerImage.width
  343. height: 60 * screenScaleFactor // TODO: Theme!
  344. MonitorPrintJobPreview
  345. {
  346. anchors.centerIn: parent
  347. printJob: printer ? printer.activePrintJob : null
  348. size: parent.height
  349. }
  350. visible: printer && printer.activePrintJob && !printerStatus.visible
  351. }
  352. Item
  353. {
  354. anchors
  355. {
  356. verticalCenter: parent.verticalCenter
  357. }
  358. width: 180 * screenScaleFactor // TODO: Theme!
  359. height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
  360. visible: printer && printer.activePrintJob && !printerStatus.visible
  361. Label
  362. {
  363. id: printerJobNameLabel
  364. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  365. elide: Text.ElideRight
  366. font: UM.Theme.getFont("large") // 16pt, bold
  367. text: printer && printer.activePrintJob ? printer.activePrintJob.name : catalog.i18nc("@label", "Untitled")
  368. width: parent.width
  369. // FIXED-LINE-HEIGHT:
  370. height: 18 * screenScaleFactor // TODO: Theme!
  371. verticalAlignment: Text.AlignVCenter
  372. renderType: Text.NativeRendering
  373. }
  374. Label
  375. {
  376. id: printerJobOwnerLabel
  377. anchors
  378. {
  379. top: printerJobNameLabel.bottom
  380. topMargin: 6 * screenScaleFactor // TODO: Theme!
  381. left: printerJobNameLabel.left
  382. }
  383. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  384. elide: Text.ElideRight
  385. font: UM.Theme.getFont("default") // 12pt, regular
  386. text: printer && printer.activePrintJob ? printer.activePrintJob.owner : catalog.i18nc("@label", "Anonymous")
  387. width: parent.width
  388. // FIXED-LINE-HEIGHT:
  389. height: 18 * screenScaleFactor // TODO: Theme!
  390. verticalAlignment: Text.AlignVCenter
  391. renderType: Text.NativeRendering
  392. }
  393. }
  394. MonitorPrintJobProgressBar
  395. {
  396. anchors
  397. {
  398. verticalCenter: parent.verticalCenter
  399. }
  400. printJob: printer && printer.activePrintJob
  401. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length === 0 && !printerStatus.visible
  402. }
  403. Label
  404. {
  405. anchors
  406. {
  407. verticalCenter: parent.verticalCenter
  408. }
  409. font: UM.Theme.getFont("default")
  410. text: catalog.i18nc("@label:status", "Requires configuration changes")
  411. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  412. color: UM.Theme.getColor("monitor_text_primary")
  413. // FIXED-LINE-HEIGHT:
  414. height: 18 * screenScaleFactor // TODO: Theme!
  415. verticalAlignment: Text.AlignVCenter
  416. renderType: Text.NativeRendering
  417. }
  418. }
  419. Button
  420. {
  421. id: detailsButton
  422. anchors
  423. {
  424. verticalCenter: parent.verticalCenter
  425. right: parent.right
  426. rightMargin: 18 * screenScaleFactor // TODO: Theme!
  427. }
  428. background: Rectangle
  429. {
  430. color: UM.Theme.getColor("monitor_secondary_button_shadow")
  431. radius: 2 * screenScaleFactor // Todo: Theme!
  432. Rectangle
  433. {
  434. anchors.fill: parent
  435. anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
  436. color: detailsButton.hovered ? UM.Theme.getColor("monitor_secondary_button_hover") : UM.Theme.getColor("monitor_secondary_button")
  437. radius: 2 * screenScaleFactor // Todo: Theme!
  438. }
  439. }
  440. contentItem: Label
  441. {
  442. anchors.fill: parent
  443. anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
  444. color: UM.Theme.getColor("monitor_secondary_button_text")
  445. font: UM.Theme.getFont("medium") // 14pt, regular
  446. text: catalog.i18nc("@action:button","Details");
  447. verticalAlignment: Text.AlignVCenter
  448. horizontalAlignment: Text.AlignHCenter
  449. height: 18 * screenScaleFactor // TODO: Theme!
  450. renderType: Text.NativeRendering
  451. }
  452. implicitHeight: 32 * screenScaleFactor // TODO: Theme!
  453. implicitWidth: 96 * screenScaleFactor // TODO: Theme!
  454. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  455. onClicked: base.enabled ? overrideConfirmationDialog.open() : {}
  456. enabled: OutputDevice.supportsPrintJobActions
  457. }
  458. // For cloud printing, add this mouse area over the disabled details button to indicate that it's not available
  459. MouseArea
  460. {
  461. id: detailsButtonDisabledButtonArea
  462. anchors.fill: detailsButton
  463. hoverEnabled: detailsButton.visible && !detailsButton.enabled
  464. onEntered: overrideButtonDisabledInfo.open()
  465. onExited: overrideButtonDisabledInfo.close()
  466. enabled: !detailsButton.enabled
  467. }
  468. MonitorInfoBlurb
  469. {
  470. id: overrideButtonDisabledInfo
  471. text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
  472. target: detailsButton
  473. }
  474. }
  475. MonitorConfigOverrideDialog
  476. {
  477. id: overrideConfirmationDialog
  478. printer: base.printer
  479. }
  480. }