MonitorPrinterCard.qml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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 UM 1.5 as UM
  6. import Cura 1.0 as Cura
  7. /**
  8. * A Printer Card is has two main components: the printer portion and the print job portion, the latter being paired in
  9. * the UI when a print job is paired a printer in-cluster.
  10. *
  11. * NOTE: For most labels, a fixed height with vertical alignment is used to make layouts more deterministic (like the
  12. * fixed-size textboxes used in original mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
  13. * with '// FIXED-LINE-HEIGHT:'.
  14. */
  15. Item
  16. {
  17. id: base
  18. // The printer which all printer data is derived from
  19. property var printer: null
  20. property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here
  21. // If the printer card's controls are enabled. This is used by the carousel to prevent opening the context menu or
  22. // camera while the printer card is not "in focus"
  23. property var enabled: true
  24. // If the printer is a cloud printer or not. Other items base their enabled state off of this boolean. In the future
  25. // they might not need to though.
  26. property bool cloudConnection: Cura.MachineManager.activeMachineIsUsingCloudConnection
  27. width: 834 * screenScaleFactor // TODO: Theme!
  28. height: childrenRect.height
  29. Rectangle
  30. {
  31. id: background
  32. anchors.fill: parent
  33. color: UM.Theme.getColor("monitor_card_background")
  34. border
  35. {
  36. color: UM.Theme.getColor("monitor_card_border")
  37. width: borderSize // TODO: Remove once themed
  38. }
  39. radius: 2 * screenScaleFactor // TODO: Theme!
  40. }
  41. // Printer portion
  42. Item
  43. {
  44. id: printerInfo
  45. width: parent.width
  46. height: 144 * screenScaleFactor // TODO: Theme!
  47. Row
  48. {
  49. anchors
  50. {
  51. left: parent.left
  52. leftMargin: 36 * screenScaleFactor // TODO: Theme!
  53. verticalCenter: parent.verticalCenter
  54. }
  55. spacing: UM.Theme.getSize("default_margin").width
  56. Rectangle
  57. {
  58. id: printerImage
  59. width: 108 * screenScaleFactor // TODO: Theme!
  60. height: 108 * screenScaleFactor // TODO: Theme!
  61. color: printer ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
  62. radius: 8 // TODO: Theme!
  63. Image
  64. {
  65. anchors.fill: parent
  66. fillMode: Image.PreserveAspectFit
  67. source: printer ? "../png/" + printer.type + ".png" : ""
  68. mipmap: true
  69. }
  70. }
  71. Item
  72. {
  73. anchors
  74. {
  75. verticalCenter: parent.verticalCenter
  76. }
  77. width: 180 * screenScaleFactor // TODO: Theme!
  78. height: childrenRect.height
  79. Rectangle
  80. {
  81. id: printerNameLabel
  82. color: printer ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
  83. height: UM.Theme.getSize("default_margin").width
  84. width: parent.width
  85. radius: UM.Theme.getSize("default_radius").width
  86. UM.Label
  87. {
  88. text: printer && printer.name ? printer.name : ""
  89. elide: Text.ElideRight
  90. font: UM.Theme.getFont("large") // 16pt, bold
  91. width: parent.width
  92. visible: printer
  93. height: parent.height
  94. }
  95. }
  96. Rectangle
  97. {
  98. color: UM.Theme.getColor("monitor_skeleton_loading")
  99. height: 18 * screenScaleFactor // TODO: Theme!
  100. radius: UM.Theme.getSize("default_radius").width
  101. visible: !printer
  102. width: 48 * screenScaleFactor // TODO: Theme!
  103. }
  104. MonitorPrinterPill
  105. {
  106. id: printerFamilyPill
  107. anchors
  108. {
  109. top: printerNameLabel.bottom
  110. topMargin: UM.Theme.getSize("narrow_margin").height
  111. left: printerNameLabel.left
  112. }
  113. text: printer ? printer.type : ""
  114. }
  115. Item
  116. {
  117. id: managePrinterLink
  118. anchors
  119. {
  120. top: printerFamilyPill.bottom
  121. topMargin: UM.Theme.getSize("narrow_margin").height
  122. }
  123. height: 18 * screenScaleFactor // TODO: Theme!
  124. width: childrenRect.width
  125. UM.Label
  126. {
  127. id: managePrinterText
  128. anchors.verticalCenter: managePrinterLink.verticalCenter
  129. color: UM.Theme.getColor("text_link")
  130. text: catalog.i18nc("@label link to Connect and Cloud interfaces", "Manage printer")
  131. }
  132. UM.ColorImage
  133. {
  134. id: externalLinkIcon
  135. anchors
  136. {
  137. left: managePrinterText.right
  138. leftMargin: UM.Theme.getSize("narrow_margin").width
  139. verticalCenter: managePrinterText.verticalCenter
  140. }
  141. color: UM.Theme.getColor("text_link")
  142. source: UM.Theme.getIcon("LinkExternal")
  143. width: UM.Theme.getSize("icon").width
  144. height: UM.Theme.getSize("icon").height
  145. }
  146. }
  147. MouseArea
  148. {
  149. anchors.fill: managePrinterLink
  150. onClicked: OutputDevice.openPrinterControlPanel()
  151. onEntered: manageQueueText.font.underline = true
  152. onExited: manageQueueText.font.underline = false
  153. }
  154. }
  155. MonitorPrinterConfiguration
  156. {
  157. id: printerConfiguration
  158. anchors.verticalCenter: parent.verticalCenter
  159. buildplate: {
  160. switch (printer.buildplate) {
  161. case "glass":
  162. return catalog.i18nc("@label", "Glass");
  163. default:
  164. return null
  165. }
  166. }
  167. configurations:
  168. {
  169. var configs = []
  170. if (printer)
  171. {
  172. configs = configs.concat(printer.printerConfiguration.extruderConfigurations)
  173. }
  174. else
  175. {
  176. configs.push(null, null)
  177. }
  178. return configs
  179. }
  180. height: 72 * screenScaleFactor // TODO: Theme!te theRect's x property
  181. }
  182. }
  183. MonitorContextMenuButton
  184. {
  185. id: contextMenuButton
  186. anchors
  187. {
  188. right: parent.right
  189. rightMargin: 12 * screenScaleFactor // TODO: Theme!
  190. top: parent.top
  191. topMargin: 12 * screenScaleFactor // TODO: Theme!
  192. }
  193. width: 36 * screenScaleFactor // TODO: Theme!
  194. height: 36 * screenScaleFactor // TODO: Theme!
  195. enabled: OutputDevice.supportsPrintJobActions
  196. onClicked: enabled ? contextMenu.switchPopupState() : {}
  197. visible:
  198. {
  199. if(!printer || !printer.activePrintJob)
  200. {
  201. return false;
  202. }
  203. if(!contextMenu.hasItems)
  204. {
  205. return false;
  206. }
  207. var states = ["queued", "error", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]
  208. return states.indexOf(printer.activePrintJob.state) !== -1
  209. }
  210. }
  211. MonitorContextMenu
  212. {
  213. id: contextMenu
  214. printJob: printer ? printer.activePrintJob : null
  215. target: contextMenuButton
  216. }
  217. // For cloud printing, add this mouse area over the disabled contextButton to indicate that it's not available
  218. MouseArea
  219. {
  220. id: contextMenuDisabledButtonArea
  221. anchors.fill: contextMenuButton
  222. hoverEnabled: contextMenuButton.visible && !contextMenuButton.enabled
  223. onEntered: contextMenuDisabledInfo.open()
  224. onExited: contextMenuDisabledInfo.close()
  225. enabled: !contextMenuButton.enabled
  226. }
  227. MonitorInfoBlurb
  228. {
  229. id: contextMenuDisabledInfo
  230. text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
  231. target: contextMenuButton
  232. }
  233. CameraButton
  234. {
  235. id: cameraButton
  236. anchors
  237. {
  238. right: parent.right
  239. rightMargin: 20 * screenScaleFactor // TODO: Theme!
  240. bottom: parent.bottom
  241. bottomMargin: 20 * screenScaleFactor // TODO: Theme!
  242. }
  243. iconSource: Qt.resolvedUrl("../svg/icons/CameraPhoto.svg")
  244. enabled: !cloudConnection
  245. visible: printer
  246. }
  247. // For cloud printing, add this mouse area over the disabled cameraButton to indicate that it's not available
  248. // Fix CURA-7637 to allow camera connections via cloud.
  249. MouseArea
  250. {
  251. id: cameraDisabledButtonArea
  252. anchors.fill: cameraButton
  253. hoverEnabled: cameraButton.visible && !cameraButton.enabled
  254. onEntered: cameraDisabledInfo.open()
  255. onExited: cameraDisabledInfo.close()
  256. enabled: !cameraButton.enabled
  257. }
  258. MonitorInfoBlurb
  259. {
  260. id: cameraDisabledInfo
  261. text: catalog.i18nc("@info", "Webcam feeds for cloud printers cannot be viewed from Ultimaker Cura." +
  262. " Click \"Manage printer\" to visit Ultimaker Digital Factory and view this webcam.")
  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: UM.Theme.getSize("default_margin").width
  306. UM.Label
  307. {
  308. id: printerStatus
  309. anchors
  310. {
  311. verticalCenter: parent.verticalCenter
  312. }
  313. color: printer ? UM.Theme.getColor("text") : 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.state == "disabled")
  320. {
  321. return catalog.i18nc("@label:status", "Unavailable")
  322. }
  323. if (printer.state == "unreachable")
  324. {
  325. return catalog.i18nc("@label:status", "Unreachable")
  326. }
  327. if (!printer.activePrintJob && printer.state == "idle")
  328. {
  329. return catalog.i18nc("@label:status", "Idle")
  330. }
  331. if (!printer.activePrintJob && printer.state == "pre_print")
  332. {
  333. return catalog.i18nc("@label:status", "Preparing...")
  334. }
  335. if (!printer.activePrintJob && printer.state == "printing")
  336. {
  337. // The print job isn't quite updated yet.
  338. return catalog.i18nc("@label:status", "Printing")
  339. }
  340. return ""
  341. }
  342. visible: text !== ""
  343. }
  344. Item
  345. {
  346. anchors
  347. {
  348. verticalCenter: parent.verticalCenter
  349. }
  350. width: printerImage.width
  351. height: 60 * screenScaleFactor // TODO: Theme!
  352. MonitorPrintJobPreview
  353. {
  354. anchors.centerIn: parent
  355. printJob: printer ? printer.activePrintJob : null
  356. size: parent.height
  357. }
  358. visible: printer && printer.activePrintJob && !printerStatus.visible
  359. }
  360. Item
  361. {
  362. anchors
  363. {
  364. verticalCenter: parent.verticalCenter
  365. }
  366. width: 180 * screenScaleFactor // TODO: Theme!
  367. height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
  368. visible: printer && printer.activePrintJob && !printerStatus.visible
  369. UM.Label
  370. {
  371. id: printerJobNameLabel
  372. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("text") : UM.Theme.getColor("monitor_text_disabled")
  373. elide: Text.ElideRight
  374. wrapMode: Text.NoWrap
  375. font: UM.Theme.getFont("large") // 16pt, bold
  376. text: printer && printer.activePrintJob ? printer.activePrintJob.name : catalog.i18nc("@label", "Untitled")
  377. width: parent.width
  378. }
  379. UM.Label
  380. {
  381. id: printerJobOwnerLabel
  382. anchors
  383. {
  384. top: printerJobNameLabel.bottom
  385. topMargin: UM.Theme.getSize("narrow_margin").height
  386. left: printerJobNameLabel.left
  387. }
  388. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("text") : UM.Theme.getColor("monitor_text_disabled")
  389. elide: Text.ElideRight
  390. text: printer && printer.activePrintJob ? printer.activePrintJob.owner : catalog.i18nc("@label", "Anonymous")
  391. width: parent.width
  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. UM.Label
  404. {
  405. anchors
  406. {
  407. verticalCenter: parent.verticalCenter
  408. }
  409. text: catalog.i18nc("@label:status", "Requires configuration changes")
  410. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  411. }
  412. }
  413. Cura.SecondaryButton
  414. {
  415. id: detailsButton
  416. anchors
  417. {
  418. verticalCenter: parent.verticalCenter
  419. right: parent.right
  420. rightMargin: UM.Theme.getSize("default_margin").width
  421. }
  422. text: catalog.i18nc("@action:button", "Details")
  423. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  424. onClicked: base.enabled ? overrideConfirmationDialog.open() : {}
  425. enabled: OutputDevice.supportsPrintJobActions
  426. }
  427. // For cloud printing, add this mouse area over the disabled details button to indicate that it's not available
  428. MouseArea
  429. {
  430. id: detailsButtonDisabledButtonArea
  431. anchors.fill: detailsButton
  432. hoverEnabled: detailsButton.visible && !detailsButton.enabled
  433. onEntered: overrideButtonDisabledInfo.open()
  434. onExited: overrideButtonDisabledInfo.close()
  435. enabled: !detailsButton.enabled
  436. }
  437. MonitorInfoBlurb
  438. {
  439. id: overrideButtonDisabledInfo
  440. text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
  441. target: detailsButton
  442. }
  443. }
  444. MonitorConfigOverrideDialog
  445. {
  446. id: overrideConfirmationDialog
  447. printer: base.printer
  448. }
  449. }