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