ClusterControlItem.qml 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. import QtQuick 2.3
  2. import QtQuick.Controls 1.4
  3. import QtQuick.Controls.Styles 1.3
  4. import QtGraphicalEffects 1.0
  5. import QtQuick.Controls 2.0 as Controls2
  6. import UM 1.3 as UM
  7. import Cura 1.0 as Cura
  8. Component
  9. {
  10. Rectangle
  11. {
  12. id: base
  13. property var lineColor: "#DCDCDC" // TODO: Should be linked to theme.
  14. property var cornerRadius: 4 * screenScaleFactor // TODO: Should be linked to theme.
  15. visible: OutputDevice != null
  16. anchors.fill: parent
  17. color: "white"
  18. UM.I18nCatalog
  19. {
  20. id: catalog
  21. name: "cura"
  22. }
  23. Label
  24. {
  25. id: printingLabel
  26. font: UM.Theme.getFont("large")
  27. anchors
  28. {
  29. margins: 2 * UM.Theme.getSize("default_margin").width
  30. leftMargin: 4 * UM.Theme.getSize("default_margin").width
  31. top: parent.top
  32. left: parent.left
  33. right: parent.right
  34. }
  35. text: catalog.i18nc("@label", "Printing")
  36. elide: Text.ElideRight
  37. }
  38. Label
  39. {
  40. id: managePrintersLabel
  41. anchors.rightMargin: 4 * UM.Theme.getSize("default_margin").width
  42. anchors.right: printerScrollView.right
  43. anchors.bottom: printingLabel.bottom
  44. text: catalog.i18nc("@label link to connect manager", "Manage printers")
  45. font: UM.Theme.getFont("default")
  46. color: UM.Theme.getColor("primary")
  47. linkColor: UM.Theme.getColor("primary")
  48. }
  49. MouseArea
  50. {
  51. anchors.fill: managePrintersLabel
  52. hoverEnabled: true
  53. onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel()
  54. onEntered: managePrintersLabel.font.underline = true
  55. onExited: managePrintersLabel.font.underline = false
  56. }
  57. ScrollView
  58. {
  59. id: printerScrollView
  60. anchors
  61. {
  62. top: printingLabel.bottom
  63. left: parent.left
  64. right: parent.right
  65. topMargin: UM.Theme.getSize("default_margin").height
  66. bottom: parent.bottom
  67. bottomMargin: UM.Theme.getSize("default_margin").height
  68. }
  69. style: UM.Theme.styles.scrollview
  70. ListView
  71. {
  72. anchors
  73. {
  74. top: parent.top
  75. bottom: parent.bottom
  76. left: parent.left
  77. right: parent.right
  78. leftMargin: 2 * UM.Theme.getSize("default_margin").width
  79. rightMargin: 2 * UM.Theme.getSize("default_margin").width
  80. }
  81. spacing: UM.Theme.getSize("default_margin").height -10
  82. model: OutputDevice.printers
  83. delegate: Item
  84. {
  85. width: parent.width
  86. height: base.height + 2 * base.shadowRadius // To ensure that the shadow doesn't get cut off.
  87. Rectangle
  88. {
  89. width: parent.width - 2 * shadowRadius
  90. height: childrenRect.height + UM.Theme.getSize("default_margin").height
  91. anchors.horizontalCenter: parent.horizontalCenter
  92. anchors.verticalCenter: parent.verticalCenter
  93. id: base
  94. property var shadowRadius: 5
  95. property var collapsed: true
  96. layer.enabled: true
  97. layer.effect: DropShadow
  98. {
  99. radius: base.shadowRadius
  100. verticalOffset: 2
  101. color: "#3F000000" // 25% shadow
  102. }
  103. Item
  104. {
  105. id: printerInfo
  106. height: machineIcon.height
  107. anchors
  108. {
  109. top: parent.top
  110. left: parent.left
  111. right: parent.right
  112. margins: UM.Theme.getSize("default_margin").width
  113. }
  114. MouseArea
  115. {
  116. anchors.fill: parent
  117. onClicked: base.collapsed = !base.collapsed
  118. }
  119. Item
  120. {
  121. id: machineIcon
  122. // Yeah, this is hardcoded now, but I can't think of a good way to fix this.
  123. // The UI is going to get another update soon, so it's probably not worth the effort...
  124. width: 58
  125. height: 58
  126. anchors.top: parent.top
  127. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  128. anchors.left: parent.left
  129. UM.RecolorImage
  130. {
  131. anchors.centerIn: parent
  132. source:
  133. {
  134. switch(modelData.type)
  135. {
  136. case "Ultimaker 3":
  137. return "UM3-icon.svg"
  138. case "Ultimaker 3 Extended":
  139. return "UM3x-icon.svg"
  140. case "Ultimaker S5":
  141. return "UMs5-icon.svg"
  142. }
  143. }
  144. width: sourceSize.width
  145. height: sourceSize.height
  146. color: modelData.activePrintJob != undefined ? UM.Theme.getColor("primary") : UM.Theme.getColor("setting_control_disabled")
  147. }
  148. }
  149. Item
  150. {
  151. height: childrenRect.height
  152. anchors
  153. {
  154. right: collapseIcon.left
  155. rightMargin: UM.Theme.getSize("default_margin").width
  156. left: machineIcon.right
  157. leftMargin: UM.Theme.getSize("default_margin").width
  158. verticalCenter: machineIcon.verticalCenter
  159. }
  160. Label
  161. {
  162. id: machineNameLabel
  163. text: modelData.name
  164. width: parent.width
  165. elide: Text.ElideRight
  166. font: UM.Theme.getFont("default_bold")
  167. }
  168. Label
  169. {
  170. id: activeJobLabel
  171. text: modelData.activePrintJob != null ? modelData.activePrintJob.name : "waiting"
  172. anchors.top: machineNameLabel.bottom
  173. width: parent.width
  174. elide: Text.ElideRight
  175. font: UM.Theme.getFont("default")
  176. opacity: 0.6
  177. }
  178. }
  179. UM.RecolorImage
  180. {
  181. id: collapseIcon
  182. width: 15
  183. height: 15
  184. sourceSize.width: width
  185. sourceSize.height: height
  186. source: base.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom")
  187. anchors.verticalCenter: parent.verticalCenter
  188. anchors.right: parent.right
  189. anchors.rightMargin: UM.Theme.getSize("default_margin").width
  190. color: "black"
  191. }
  192. }
  193. Item
  194. {
  195. id: detailedInfo
  196. property var printJob: modelData.activePrintJob
  197. visible: height == childrenRect.height
  198. anchors.top: printerInfo.bottom
  199. width: parent.width
  200. height: !base.collapsed ? childrenRect.height : 0
  201. opacity: visible ? 1 : 0
  202. Behavior on height { NumberAnimation { duration: 100 } }
  203. Behavior on opacity { NumberAnimation { duration: 100 } }
  204. Rectangle
  205. {
  206. id: topSpacer
  207. color: UM.Theme.getColor("viewport_background")
  208. height: 2
  209. anchors
  210. {
  211. left: parent.left
  212. right: parent.right
  213. margins: UM.Theme.getSize("default_margin").width
  214. top: parent.top
  215. topMargin: UM.Theme.getSize("default_margin").width
  216. }
  217. }
  218. PrinterFamilyPill
  219. {
  220. id: printerFamilyPill
  221. color: UM.Theme.getColor("viewport_background")
  222. anchors.top: topSpacer.bottom
  223. anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height
  224. text: modelData.type
  225. anchors.left: parent.left
  226. anchors.leftMargin: UM.Theme.getSize("default_margin").width
  227. padding: 3
  228. }
  229. Row
  230. {
  231. id: extrudersInfo
  232. anchors.top: printerFamilyPill.bottom
  233. anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height
  234. anchors.left: parent.left
  235. anchors.leftMargin: 2 * UM.Theme.getSize("default_margin").width
  236. anchors.right: parent.right
  237. anchors.rightMargin: 2 * UM.Theme.getSize("default_margin").width
  238. height: childrenRect.height
  239. spacing: UM.Theme.getSize("default_margin").width
  240. PrintCoreConfiguration
  241. {
  242. id: leftExtruderInfo
  243. width: Math.round(parent.width / 2)
  244. printCoreConfiguration: modelData.printerConfiguration.extruderConfigurations[0]
  245. }
  246. PrintCoreConfiguration
  247. {
  248. id: rightExtruderInfo
  249. width: Math.round(parent.width / 2)
  250. printCoreConfiguration: modelData.printerConfiguration.extruderConfigurations[1]
  251. }
  252. }
  253. Rectangle
  254. {
  255. id: jobSpacer
  256. color: UM.Theme.getColor("viewport_background")
  257. height: 2
  258. anchors
  259. {
  260. left: parent.left
  261. right: parent.right
  262. margins: UM.Theme.getSize("default_margin").width
  263. top: extrudersInfo.bottom
  264. topMargin: 2 * UM.Theme.getSize("default_margin").height
  265. }
  266. }
  267. Item
  268. {
  269. id: jobInfo
  270. property var showJobInfo: modelData.activePrintJob != null && modelData.activePrintJob.state != "queued"
  271. anchors.top: jobSpacer.bottom
  272. anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height
  273. anchors.left: parent.left
  274. anchors.right: parent.right
  275. anchors.margins: UM.Theme.getSize("default_margin").width
  276. anchors.leftMargin: 2 * UM.Theme.getSize("default_margin").width
  277. height: showJobInfo ? childrenRect.height + 2 * UM.Theme.getSize("default_margin").height: 0
  278. visible: showJobInfo
  279. Label
  280. {
  281. id: printJobName
  282. text: modelData.activePrintJob != null ? modelData.activePrintJob.name : ""
  283. font: UM.Theme.getFont("default_bold")
  284. width: parent.width
  285. elide: Text.ElideRight
  286. }
  287. Label
  288. {
  289. id: ownerName
  290. anchors.top: printJobName.bottom
  291. text: modelData.activePrintJob != null ? modelData.activePrintJob.owner : ""
  292. font: UM.Theme.getFont("default")
  293. opacity: 0.6
  294. width: parent.width
  295. elide: Text.ElideRight
  296. }
  297. function switchPopupState()
  298. {
  299. popup.visible ? popup.close() : popup.open()
  300. }
  301. Controls2.Button
  302. {
  303. id: contextButton
  304. text: "\u22EE" //Unicode; Three stacked points.
  305. font.pixelSize: 25
  306. width: 35
  307. height: width
  308. anchors
  309. {
  310. right: parent.right
  311. top: parent.top
  312. }
  313. hoverEnabled: true
  314. background: Rectangle
  315. {
  316. opacity: contextButton.down || contextButton.hovered ? 1 : 0
  317. width: contextButton.width
  318. height: contextButton.height
  319. radius: 0.5 * width
  320. color: UM.Theme.getColor("viewport_background")
  321. }
  322. onClicked: parent.switchPopupState()
  323. }
  324. Controls2.Popup
  325. {
  326. // TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property
  327. id: popup
  328. clip: true
  329. closePolicy: Controls2.Popup.CloseOnPressOutsideParent
  330. x: parent.width - width
  331. y: contextButton.height
  332. width: 160
  333. height: contentItem.height + 2 * padding
  334. visible: false
  335. transformOrigin: Controls2.Popup.Top
  336. contentItem: Item
  337. {
  338. width: popup.width - 2 * popup.padding
  339. height: childrenRect.height + 15
  340. Controls2.Button
  341. {
  342. id: pauseButton
  343. text: modelData.activePrintJob != null && modelData.activePrintJob.state == "paused" ? catalog.i18nc("@label", "Resume") : catalog.i18nc("@label", "Pause")
  344. onClicked:
  345. {
  346. if(modelData.activePrintJob.state == "paused")
  347. {
  348. modelData.activePrintJob.setState("print")
  349. }
  350. else if(modelData.activePrintJob.state == "printing")
  351. {
  352. modelData.activePrintJob.setState("pause")
  353. }
  354. popup.close()
  355. }
  356. width: parent.width
  357. enabled: modelData.activePrintJob != null && ["paused", "printing"].indexOf(modelData.activePrintJob.state) >= 0
  358. anchors.top: parent.top
  359. anchors.topMargin: 10
  360. hoverEnabled: true
  361. background: Rectangle
  362. {
  363. opacity: pauseButton.down || pauseButton.hovered ? 1 : 0
  364. color: UM.Theme.getColor("viewport_background")
  365. }
  366. }
  367. Controls2.Button
  368. {
  369. id: abortButton
  370. text: catalog.i18nc("@label", "Abort")
  371. onClicked:
  372. {
  373. modelData.activePrintJob.setState("abort")
  374. popup.close()
  375. }
  376. width: parent.width
  377. anchors.top: pauseButton.bottom
  378. hoverEnabled: true
  379. enabled: modelData.activePrintJob != null && ["paused", "printing", "pre_print"].indexOf(modelData.activePrintJob.state) >= 0
  380. background: Rectangle
  381. {
  382. opacity: abortButton.down || abortButton.hovered ? 1 : 0
  383. color: UM.Theme.getColor("viewport_background")
  384. }
  385. }
  386. }
  387. background: Item
  388. {
  389. width: popup.width
  390. height: popup.height
  391. DropShadow
  392. {
  393. anchors.fill: pointedRectangle
  394. radius: 5
  395. color: "#3F000000" // 25% shadow
  396. source: pointedRectangle
  397. transparentBorder: true
  398. verticalOffset: 2
  399. }
  400. Item
  401. {
  402. id: pointedRectangle
  403. width: parent.width -10
  404. height: parent.height -10
  405. anchors.horizontalCenter: parent.horizontalCenter
  406. anchors.verticalCenter: parent.verticalCenter
  407. Rectangle
  408. {
  409. id: point
  410. height: 13
  411. width: 13
  412. color: UM.Theme.getColor("setting_control")
  413. transform: Rotation { angle: 45}
  414. anchors.right: bloop.right
  415. y: 1
  416. }
  417. Rectangle
  418. {
  419. id: bloop
  420. color: UM.Theme.getColor("setting_control")
  421. width: parent.width
  422. anchors.top: parent.top
  423. anchors.topMargin: 10
  424. anchors.bottom: parent.bottom
  425. anchors.bottomMargin: 5
  426. }
  427. }
  428. }
  429. exit: Transition
  430. {
  431. // This applies a default NumberAnimation to any changes a state change makes to x or y properties
  432. NumberAnimation { property: "visible"; duration: 75; }
  433. }
  434. enter: Transition
  435. {
  436. // This applies a default NumberAnimation to any changes a state change makes to x or y properties
  437. NumberAnimation { property: "visible"; duration: 75; }
  438. }
  439. onClosed: visible = false
  440. onOpened: visible = true
  441. }
  442. Image
  443. {
  444. id: printJobPreview
  445. source: modelData.activePrintJob != null ? modelData.activePrintJob.previewImageUrl : ""
  446. anchors.top: ownerName.bottom
  447. anchors.horizontalCenter: parent.horizontalCenter
  448. width: parent.width / 2
  449. height: width
  450. opacity:
  451. {
  452. if(modelData.activePrintJob == null)
  453. {
  454. return 1.0
  455. }
  456. switch(modelData.activePrintJob.state)
  457. {
  458. case "wait_cleanup":
  459. case "wait_user_action":
  460. case "paused":
  461. return 0.5
  462. default:
  463. return 1.0
  464. }
  465. }
  466. }
  467. UM.RecolorImage
  468. {
  469. id: statusImage
  470. anchors.centerIn: printJobPreview
  471. source:
  472. {
  473. if(modelData.activePrintJob == null)
  474. {
  475. return ""
  476. }
  477. switch(modelData.activePrintJob.state)
  478. {
  479. case "paused":
  480. return "paused-icon.svg"
  481. case "wait_cleanup":
  482. if(modelData.activePrintJob.timeElapsed < modelData.activePrintJob.timeTotal)
  483. {
  484. return "aborted-icon.svg"
  485. }
  486. return "approved-icon.svg"
  487. case "wait_user_action":
  488. return "aborted-icon.svg"
  489. default:
  490. return ""
  491. }
  492. }
  493. visible: source != ""
  494. width: 0.5 * printJobPreview.width
  495. height: 0.5 * printJobPreview.height
  496. sourceSize.width: width
  497. sourceSize.height: height
  498. color: "black"
  499. }
  500. Rectangle
  501. {
  502. id: showCameraIcon
  503. width: 35 * screenScaleFactor
  504. height: width
  505. radius: 0.5 * width
  506. anchors.left: parent.left
  507. anchors.bottom: printJobPreview.bottom
  508. color: UM.Theme.getColor("setting_control_border_highlight")
  509. Image
  510. {
  511. width: parent.width
  512. height: width
  513. anchors.right: parent.right
  514. anchors.rightMargin: parent.rightMargin
  515. source: "camera-icon.svg"
  516. }
  517. MouseArea
  518. {
  519. anchors.fill:parent
  520. onClicked:
  521. {
  522. OutputDevice.setActiveCamera(modelData.camera)
  523. }
  524. }
  525. }
  526. }
  527. }
  528. ProgressBar
  529. {
  530. property var progress:
  531. {
  532. if(modelData.activePrintJob == null)
  533. {
  534. return 0
  535. }
  536. var result = modelData.activePrintJob.timeElapsed / modelData.activePrintJob.timeTotal
  537. if(result > 1.0)
  538. {
  539. result = 1.0
  540. }
  541. return result
  542. }
  543. id: jobProgressBar
  544. width: parent.width
  545. value: progress
  546. anchors.top: detailedInfo.bottom
  547. anchors.topMargin: UM.Theme.getSize("default_margin").height
  548. visible: modelData.activePrintJob != null && modelData.activePrintJob != undefined
  549. style: ProgressBarStyle
  550. {
  551. property var progressText:
  552. {
  553. if(modelData.activePrintJob == null)
  554. {
  555. return ""
  556. }
  557. switch(modelData.activePrintJob.state)
  558. {
  559. case "wait_cleanup":
  560. if(modelData.activePrintJob.timeTotal > modelData.activePrintJob.timeElapsed)
  561. {
  562. return catalog.i18nc("@label:status", "Aborted")
  563. }
  564. return catalog.i18nc("@label:status", "Finished")
  565. case "pre_print":
  566. case "sent_to_printer":
  567. return catalog.i18nc("@label:status", "Preparing")
  568. case "aborted":
  569. case "wait_user_action":
  570. return catalog.i18nc("@label:status", "Aborted")
  571. case "pausing":
  572. case "paused":
  573. return catalog.i18nc("@label:status", "Paused")
  574. case "resuming":
  575. return catalog.i18nc("@label:status", "Resuming")
  576. case "queued":
  577. return catalog.i18nc("@label:status", "Configuration change")
  578. default:
  579. OutputDevice.formatDuration(modelData.activePrintJob.timeTotal - modelData.activePrintJob.timeElapsed)
  580. }
  581. }
  582. background: Rectangle
  583. {
  584. implicitWidth: 100
  585. implicitHeight: visible ? 24 : 0
  586. color: UM.Theme.getColor("viewport_background")
  587. }
  588. progress: Rectangle
  589. {
  590. color: UM.Theme.getColor("primary")
  591. id: progressItem
  592. function getTextOffset()
  593. {
  594. if(progressItem.width + progressLabel.width < control.width)
  595. {
  596. return progressItem.width + UM.Theme.getSize("default_margin").width
  597. }
  598. else
  599. {
  600. return progressItem.width - progressLabel.width - UM.Theme.getSize("default_margin").width
  601. }
  602. }
  603. Label
  604. {
  605. id: progressLabel
  606. anchors.left: parent.left
  607. anchors.leftMargin: getTextOffset()
  608. text: progressText
  609. anchors.verticalCenter: parent.verticalCenter
  610. color: progressItem.width + progressLabel.width < control.width ? "black" : "white"
  611. width: contentWidth
  612. font: UM.Theme.getFont("default")
  613. }
  614. }
  615. }
  616. }
  617. }
  618. }
  619. }
  620. }
  621. }
  622. }