MonitorPrinterCard.qml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. // Copyright (c) 2018 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: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
  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. }
  121. MonitorPrinterConfiguration
  122. {
  123. id: printerConfiguration
  124. anchors.verticalCenter: parent.verticalCenter
  125. buildplate: printer ? catalog.i18nc("@label", "Glass") : null // 'Glass' as a default
  126. configurations:
  127. {
  128. var configs = []
  129. if (printer)
  130. {
  131. configs.push(printer.printerConfiguration.extruderConfigurations[0])
  132. configs.push(printer.printerConfiguration.extruderConfigurations[1])
  133. }
  134. else
  135. {
  136. configs.push(null, null)
  137. }
  138. return configs
  139. }
  140. height: 72 * screenScaleFactor // TODO: Theme!te theRect's x property
  141. }
  142. }
  143. MonitorContextMenuButton
  144. {
  145. id: contextMenuButton
  146. anchors
  147. {
  148. right: parent.right
  149. rightMargin: 12 * screenScaleFactor // TODO: Theme!
  150. top: parent.top
  151. topMargin: 12 * screenScaleFactor // TODO: Theme!
  152. }
  153. width: 36 * screenScaleFactor // TODO: Theme!
  154. height: 36 * screenScaleFactor // TODO: Theme!
  155. enabled: OutputDevice.supportsPrintJobActions
  156. onClicked: enabled ? contextMenu.switchPopupState() : {}
  157. visible:
  158. {
  159. if (!printer || !printer.activePrintJob) {
  160. return false
  161. }
  162. var states = ["queued", "error", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]
  163. return states.indexOf(printer.activePrintJob.state) !== -1
  164. }
  165. }
  166. MonitorContextMenu
  167. {
  168. id: contextMenu
  169. printJob: printer ? printer.activePrintJob : null
  170. target: contextMenuButton
  171. }
  172. // For cloud printing, add this mouse area over the disabled contextButton to indicate that it's not available
  173. MouseArea
  174. {
  175. id: contextMenuDisabledButtonArea
  176. anchors.fill: contextMenuButton
  177. hoverEnabled: contextMenuButton.visible && !contextMenuButton.enabled
  178. onEntered: contextMenuDisabledInfo.open()
  179. onExited: contextMenuDisabledInfo.close()
  180. enabled: !contextMenuButton.enabled
  181. }
  182. // TODO: uncomment this tooltip as soon as the required firmware is released
  183. // MonitorInfoBlurb
  184. // {
  185. // id: contextMenuDisabledInfo
  186. // text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
  187. // target: contextMenuButton
  188. // }
  189. CameraButton
  190. {
  191. id: cameraButton
  192. anchors
  193. {
  194. right: parent.right
  195. rightMargin: 20 * screenScaleFactor // TODO: Theme!
  196. bottom: parent.bottom
  197. bottomMargin: 20 * screenScaleFactor // TODO: Theme!
  198. }
  199. iconSource: "../svg/icons/camera.svg"
  200. enabled: !cloudConnection
  201. visible: printer
  202. }
  203. // For cloud printing, add this mouse area over the disabled cameraButton to indicate that it's not available
  204. MouseArea
  205. {
  206. id: cameraDisabledButtonArea
  207. anchors.fill: cameraButton
  208. hoverEnabled: cameraButton.visible && !cameraButton.enabled
  209. onEntered: cameraDisabledInfo.open()
  210. onExited: cameraDisabledInfo.close()
  211. enabled: !cameraButton.enabled
  212. }
  213. MonitorInfoBlurb
  214. {
  215. id: cameraDisabledInfo
  216. text: catalog.i18nc("@info", "The webcam is not available because you are monitoring a cloud printer.")
  217. target: cameraButton
  218. }
  219. }
  220. // Divider
  221. Rectangle
  222. {
  223. anchors
  224. {
  225. top: printJobInfo.top
  226. left: printJobInfo.left
  227. right: printJobInfo.right
  228. }
  229. height: borderSize // Remove once themed
  230. color: background.border.color
  231. }
  232. // Print job portion
  233. Rectangle
  234. {
  235. id: printJobInfo
  236. anchors
  237. {
  238. top: printerInfo.bottom
  239. topMargin: -borderSize * screenScaleFactor // TODO: Theme!
  240. }
  241. border
  242. {
  243. color: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? UM.Theme.getColor("warning") : "transparent" // TODO: Theme!
  244. width: borderSize // TODO: Remove once themed
  245. }
  246. color: "transparent" // TODO: Theme!
  247. height: 84 * screenScaleFactor + borderSize // TODO: Remove once themed
  248. width: parent.width
  249. Row
  250. {
  251. anchors
  252. {
  253. fill: parent
  254. topMargin: 12 * screenScaleFactor + borderSize // TODO: Theme!
  255. bottomMargin: 12 * screenScaleFactor // TODO: Theme!
  256. leftMargin: 36 * screenScaleFactor // TODO: Theme!
  257. }
  258. height: childrenRect.height
  259. spacing: 18 * screenScaleFactor // TODO: Theme!
  260. Label
  261. {
  262. id: printerStatus
  263. anchors
  264. {
  265. verticalCenter: parent.verticalCenter
  266. }
  267. color: printer ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  268. font: UM.Theme.getFont("large_bold") // 16pt, bold
  269. text: {
  270. if (!printer) {
  271. return catalog.i18nc("@label:status", "Loading...")
  272. }
  273. if (printer && printer.state == "disabled")
  274. {
  275. return catalog.i18nc("@label:status", "Unavailable")
  276. }
  277. if (printer && printer.state == "unreachable")
  278. {
  279. return catalog.i18nc("@label:status", "Unreachable")
  280. }
  281. if (printer && !printer.activePrintJob && printer.state == "idle")
  282. {
  283. return catalog.i18nc("@label:status", "Idle")
  284. }
  285. return ""
  286. }
  287. visible: text !== ""
  288. renderType: Text.NativeRendering
  289. }
  290. Item
  291. {
  292. anchors
  293. {
  294. verticalCenter: parent.verticalCenter
  295. }
  296. width: printerImage.width
  297. height: 60 * screenScaleFactor // TODO: Theme!
  298. MonitorPrintJobPreview
  299. {
  300. anchors.centerIn: parent
  301. printJob: printer ? printer.activePrintJob : null
  302. size: parent.height
  303. }
  304. visible: printer && printer.activePrintJob && !printerStatus.visible
  305. }
  306. Item
  307. {
  308. anchors
  309. {
  310. verticalCenter: parent.verticalCenter
  311. }
  312. width: 180 * screenScaleFactor // TODO: Theme!
  313. height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
  314. visible: printer && printer.activePrintJob && !printerStatus.visible
  315. Label
  316. {
  317. id: printerJobNameLabel
  318. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  319. elide: Text.ElideRight
  320. font: UM.Theme.getFont("large") // 16pt, bold
  321. text: printer && printer.activePrintJob ? printer.activePrintJob.name : catalog.i18nc("@label", "Untitled")
  322. width: parent.width
  323. // FIXED-LINE-HEIGHT:
  324. height: 18 * screenScaleFactor // TODO: Theme!
  325. verticalAlignment: Text.AlignVCenter
  326. renderType: Text.NativeRendering
  327. }
  328. Label
  329. {
  330. id: printerJobOwnerLabel
  331. anchors
  332. {
  333. top: printerJobNameLabel.bottom
  334. topMargin: 6 * screenScaleFactor // TODO: Theme!
  335. left: printerJobNameLabel.left
  336. }
  337. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  338. elide: Text.ElideRight
  339. font: UM.Theme.getFont("default") // 12pt, regular
  340. text: printer && printer.activePrintJob ? printer.activePrintJob.owner : catalog.i18nc("@label", "Anonymous")
  341. width: parent.width
  342. // FIXED-LINE-HEIGHT:
  343. height: 18 * screenScaleFactor // TODO: Theme!
  344. verticalAlignment: Text.AlignVCenter
  345. renderType: Text.NativeRendering
  346. }
  347. }
  348. MonitorPrintJobProgressBar
  349. {
  350. anchors
  351. {
  352. verticalCenter: parent.verticalCenter
  353. }
  354. printJob: printer && printer.activePrintJob
  355. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length === 0 && !printerStatus.visible
  356. }
  357. Label
  358. {
  359. anchors
  360. {
  361. verticalCenter: parent.verticalCenter
  362. }
  363. font: UM.Theme.getFont("default")
  364. text: catalog.i18nc("@label:status", "Requires configuration changes")
  365. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  366. color: UM.Theme.getColor("monitor_text_primary")
  367. // FIXED-LINE-HEIGHT:
  368. height: 18 * screenScaleFactor // TODO: Theme!
  369. verticalAlignment: Text.AlignVCenter
  370. renderType: Text.NativeRendering
  371. }
  372. }
  373. Button
  374. {
  375. id: detailsButton
  376. anchors
  377. {
  378. verticalCenter: parent.verticalCenter
  379. right: parent.right
  380. rightMargin: 18 * screenScaleFactor // TODO: Theme!
  381. }
  382. background: Rectangle
  383. {
  384. color: UM.Theme.getColor("monitor_secondary_button_shadow")
  385. radius: 2 * screenScaleFactor // Todo: Theme!
  386. Rectangle
  387. {
  388. anchors.fill: parent
  389. anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
  390. color: detailsButton.hovered ? UM.Theme.getColor("monitor_secondary_button_hover") : UM.Theme.getColor("monitor_secondary_button")
  391. radius: 2 * screenScaleFactor // Todo: Theme!
  392. }
  393. }
  394. contentItem: Label
  395. {
  396. anchors.fill: parent
  397. anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
  398. color: UM.Theme.getColor("monitor_secondary_button_text")
  399. font: UM.Theme.getFont("medium") // 14pt, regular
  400. text: catalog.i18nc("@action:button","Details");
  401. verticalAlignment: Text.AlignVCenter
  402. horizontalAlignment: Text.AlignHCenter
  403. height: 18 * screenScaleFactor // TODO: Theme!
  404. renderType: Text.NativeRendering
  405. }
  406. implicitHeight: 32 * screenScaleFactor // TODO: Theme!
  407. implicitWidth: 96 * screenScaleFactor // TODO: Theme!
  408. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  409. onClicked: base.enabled ? overrideConfirmationDialog.open() : {}
  410. }
  411. }
  412. MonitorConfigOverrideDialog
  413. {
  414. id: overrideConfirmationDialog
  415. printer: base.printer
  416. }
  417. }