MonitorPrinterCard.qml 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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: !cloudConnection
  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. MonitorInfoBlurb
  183. {
  184. id: contextMenuDisabledInfo
  185. text: catalog.i18nc("@info", "These options are not available because you are monitoring a cloud printer.")
  186. target: contextMenuButton
  187. }
  188. CameraButton
  189. {
  190. id: cameraButton
  191. anchors
  192. {
  193. right: parent.right
  194. rightMargin: 20 * screenScaleFactor // TODO: Theme!
  195. bottom: parent.bottom
  196. bottomMargin: 20 * screenScaleFactor // TODO: Theme!
  197. }
  198. iconSource: "../svg/icons/camera.svg"
  199. enabled: !cloudConnection
  200. visible: printer
  201. }
  202. // For cloud printing, add this mouse area over the disabled cameraButton to indicate that it's not available
  203. MouseArea
  204. {
  205. id: cameraDisabledButtonArea
  206. anchors.fill: cameraButton
  207. hoverEnabled: cameraButton.visible && !cameraButton.enabled
  208. onEntered: cameraDisabledInfo.open()
  209. onExited: cameraDisabledInfo.close()
  210. enabled: !cameraButton.enabled
  211. }
  212. MonitorInfoBlurb
  213. {
  214. id: cameraDisabledInfo
  215. text: catalog.i18nc("@info", "The webcam is not available because you are monitoring a cloud printer.")
  216. target: cameraButton
  217. }
  218. }
  219. // Divider
  220. Rectangle
  221. {
  222. anchors
  223. {
  224. top: printJobInfo.top
  225. left: printJobInfo.left
  226. right: printJobInfo.right
  227. }
  228. height: borderSize // Remove once themed
  229. color: background.border.color
  230. }
  231. // Print job portion
  232. Rectangle
  233. {
  234. id: printJobInfo
  235. anchors
  236. {
  237. top: printerInfo.bottom
  238. topMargin: -borderSize * screenScaleFactor // TODO: Theme!
  239. }
  240. border
  241. {
  242. color: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? UM.Theme.getColor("warning") : "transparent" // TODO: Theme!
  243. width: borderSize // TODO: Remove once themed
  244. }
  245. color: "transparent" // TODO: Theme!
  246. height: 84 * screenScaleFactor + borderSize // TODO: Remove once themed
  247. width: parent.width
  248. Row
  249. {
  250. anchors
  251. {
  252. fill: parent
  253. topMargin: 12 * screenScaleFactor + borderSize // TODO: Theme!
  254. bottomMargin: 12 * screenScaleFactor // TODO: Theme!
  255. leftMargin: 36 * screenScaleFactor // TODO: Theme!
  256. rightMargin: 36 * screenScaleFactor // TODO: Theme!
  257. }
  258. width: parent.width
  259. height: childrenRect.height
  260. spacing: 18 * screenScaleFactor // TODO: Theme!
  261. Label
  262. {
  263. id: printerStatus
  264. anchors
  265. {
  266. verticalCenter: parent.verticalCenter
  267. }
  268. color: printer ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  269. font: UM.Theme.getFont("large_bold") // 16pt, bold
  270. text: {
  271. if (!printer) {
  272. return catalog.i18nc("@label:status", "Loading...")
  273. }
  274. if (printer && printer.state == "disabled")
  275. {
  276. return catalog.i18nc("@label:status", "Unavailable")
  277. }
  278. if (printer && printer.state == "unreachable")
  279. {
  280. return catalog.i18nc("@label:status", "Unreachable")
  281. }
  282. if (printer && !printer.activePrintJob && printer.state == "idle")
  283. {
  284. return catalog.i18nc("@label:status", "Idle")
  285. }
  286. return ""
  287. }
  288. visible: text !== ""
  289. renderType: Text.NativeRendering
  290. }
  291. Item
  292. {
  293. anchors
  294. {
  295. verticalCenter: parent.verticalCenter
  296. }
  297. width: printerImage.width
  298. height: 60 * screenScaleFactor // TODO: Theme!
  299. MonitorPrintJobPreview
  300. {
  301. anchors.centerIn: parent
  302. printJob: printer ? printer.activePrintJob : null
  303. size: parent.height
  304. }
  305. visible: printer && printer.activePrintJob && !printerStatus.visible
  306. }
  307. Item
  308. {
  309. anchors
  310. {
  311. verticalCenter: parent.verticalCenter
  312. }
  313. width: 180 * screenScaleFactor // TODO: Theme!
  314. height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme!
  315. visible: printer && printer.activePrintJob && !printerStatus.visible
  316. Label
  317. {
  318. id: printerJobNameLabel
  319. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  320. elide: Text.ElideRight
  321. font: UM.Theme.getFont("large") // 16pt, bold
  322. text: printer && printer.activePrintJob ? printer.activePrintJob.name : catalog.i18nc("@label", "Untitled")
  323. width: parent.width
  324. // FIXED-LINE-HEIGHT:
  325. height: 18 * screenScaleFactor // TODO: Theme!
  326. verticalAlignment: Text.AlignVCenter
  327. renderType: Text.NativeRendering
  328. }
  329. Label
  330. {
  331. id: printerJobOwnerLabel
  332. anchors
  333. {
  334. top: printerJobNameLabel.bottom
  335. topMargin: 6 * screenScaleFactor // TODO: Theme!
  336. left: printerJobNameLabel.left
  337. }
  338. color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
  339. elide: Text.ElideRight
  340. font: UM.Theme.getFont("default") // 12pt, regular
  341. text: printer && printer.activePrintJob ? printer.activePrintJob.owner : catalog.i18nc("@label", "Anonymous")
  342. width: parent.width
  343. // FIXED-LINE-HEIGHT:
  344. height: 18 * screenScaleFactor // TODO: Theme!
  345. verticalAlignment: Text.AlignVCenter
  346. renderType: Text.NativeRendering
  347. }
  348. }
  349. MonitorPrintJobProgressBar
  350. {
  351. anchors
  352. {
  353. verticalCenter: parent.verticalCenter
  354. }
  355. printJob: printer && printer.activePrintJob
  356. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length === 0 && !printerStatus.visible
  357. }
  358. Label
  359. {
  360. anchors
  361. {
  362. verticalCenter: parent.verticalCenter
  363. }
  364. font: UM.Theme.getFont("default")
  365. text: catalog.i18nc("@label:status", "Requires configuration changes")
  366. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  367. color: UM.Theme.getColor("monitor_text_primary")
  368. // FIXED-LINE-HEIGHT:
  369. height: 18 * screenScaleFactor // TODO: Theme!
  370. verticalAlignment: Text.AlignVCenter
  371. renderType: Text.NativeRendering
  372. }
  373. }
  374. Button
  375. {
  376. id: detailsButton
  377. anchors
  378. {
  379. verticalCenter: parent.verticalCenter
  380. right: parent.right
  381. rightMargin: 18 * screenScaleFactor // TODO: Theme!
  382. }
  383. background: Rectangle
  384. {
  385. color: UM.Theme.getColor("monitor_secondary_button_shadow")
  386. radius: 2 * screenScaleFactor // Todo: Theme!
  387. Rectangle
  388. {
  389. anchors.fill: parent
  390. anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
  391. color: detailsButton.hovered ? UM.Theme.getColor("monitor_secondary_button_hover") : UM.Theme.getColor("monitor_secondary_button")
  392. radius: 2 * screenScaleFactor // Todo: Theme!
  393. }
  394. }
  395. contentItem: Label
  396. {
  397. anchors.fill: parent
  398. anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
  399. color: UM.Theme.getColor("monitor_secondary_button_text")
  400. font: UM.Theme.getFont("medium") // 14pt, regular
  401. text: catalog.i18nc("@action:button","Details");
  402. verticalAlignment: Text.AlignVCenter
  403. horizontalAlignment: Text.AlignHCenter
  404. height: 18 * screenScaleFactor // TODO: Theme!
  405. renderType: Text.NativeRendering
  406. }
  407. implicitHeight: 32 * screenScaleFactor // TODO: Theme!
  408. implicitWidth: 96 * screenScaleFactor // TODO: Theme!
  409. visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
  410. onClicked: base.enabled ? overrideConfirmationDialog.open() : {}
  411. }
  412. }
  413. MonitorConfigOverrideDialog
  414. {
  415. id: overrideConfirmationDialog
  416. printer: base.printer
  417. }
  418. }