diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index 1415db16bd..b417e0aab3 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot @@ -12,7 +12,6 @@ if TYPE_CHECKING: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.ConfigurationModel import ConfigurationModel - class PrintJobOutputModel(QObject): stateChanged = pyqtSignal() timeTotalChanged = pyqtSignal() @@ -147,4 +146,4 @@ class PrintJobOutputModel(QObject): @pyqtSlot(str) def setState(self, state): - self._output_controller.setJobState(self, state) \ No newline at end of file + self._output_controller.setJobState(self, state) diff --git a/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml b/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml index 1ceebccf89..f8dd3bc467 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml @@ -1,46 +1,40 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.3 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.3 -import QtQuick.Controls 2.0 as Controls2 -import QtGraphicalEffects 1.0 - import UM 1.3 as UM import Cura 1.0 as Cura -Rectangle -{ - property var iconSource: null +Rectangle { + property var iconSource: null; + color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary"); // "Cura Blue" + height: width; + radius: Math.round(0.5 * width); + width: 36 * screenScaleFactor; - width: 36 * screenScaleFactor - height: width - radius: 0.5 * width - color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary") - - UM.RecolorImage - { - id: icon - width: parent.width / 2 - height: width - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - color: UM.Theme.getColor("primary_text") - source: iconSource + UM.RecolorImage { + id: icon; + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter; + } + color: UM.Theme.getColor("primary_text"); + height: width; + source: iconSource; + width: Math.round(parent.width / 2); } - MouseArea - { - id: clickArea - anchors.fill:parent - hoverEnabled: true - onClicked: - { - if (OutputDevice.activeCamera !== null) - { + MouseArea { + id: clickArea; + anchors.fill: parent; + hoverEnabled: true; + onClicked: { + if (OutputDevice.activeCamera !== null) { OutputDevice.setActiveCamera(null) - } - else - { - OutputDevice.setActiveCamera(modelData.camera) + } else { + OutputDevice.setActiveCamera(modelData.camera); } } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml b/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml index f8ad0e763e..068c369a3f 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml @@ -1,803 +1,109 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.3 -import QtQuick.Dialogs 1.1 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.3 -import QtGraphicalEffects 1.0 - -import QtQuick.Controls 2.0 as Controls2 - import UM 1.3 as UM import Cura 1.0 as Cura +Component { + Rectangle { + id: base; + property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; + property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width; + anchors.fill: parent; + color: UM.Theme.getColor("sidebar"); + visible: OutputDevice != null; -Component -{ - Rectangle - { - id: base - property var lineColor: "#DCDCDC" // TODO: Should be linked to theme. - property var shadowRadius: 5 * screenScaleFactor - property var cornerRadius: 4 * screenScaleFactor // TODO: Should be linked to theme. - visible: OutputDevice != null - anchors.fill: parent - color: "white" - - UM.I18nCatalog - { - id: catalog - name: "cura" + UM.I18nCatalog { + id: catalog; + name: "cura"; } - Label - { - id: printingLabel - font: UM.Theme.getFont("large") - anchors - { - margins: 2 * UM.Theme.getSize("default_margin").width - leftMargin: 4 * UM.Theme.getSize("default_margin").width - top: parent.top - left: parent.left - right: parent.right + Label { + id: printingLabel; + anchors { + left: parent.left; + leftMargin: 4 * UM.Theme.getSize("default_margin").width; + margins: 2 * UM.Theme.getSize("default_margin").width; + right: parent.right; + top: parent.top; } - - text: catalog.i18nc("@label", "Printing") - elide: Text.ElideRight + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("large"); + text: catalog.i18nc("@label", "Printing"); } - Label - { - id: managePrintersLabel - anchors.rightMargin: 4 * UM.Theme.getSize("default_margin").width - anchors.right: printerScrollView.right - anchors.bottom: printingLabel.bottom - text: catalog.i18nc("@label link to connect manager", "Manage printers") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("primary") - linkColor: UM.Theme.getColor("primary") - } - - MouseArea - { - anchors.fill: managePrintersLabel - hoverEnabled: true - onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel() - onEntered: managePrintersLabel.font.underline = true - onExited: managePrintersLabel.font.underline = false - } - - ScrollView - { - id: printerScrollView - anchors - { - top: printingLabel.bottom - left: parent.left - right: parent.right - topMargin: UM.Theme.getSize("default_margin").height - bottom: parent.bottom - bottomMargin: UM.Theme.getSize("default_margin").height + Label { + id: managePrintersLabel; + anchors { + bottom: printingLabel.bottom; + right: printerScrollView.right; + rightMargin: 4 * UM.Theme.getSize("default_margin").width; } + color: UM.Theme.getColor("primary"); // "Cura Blue" + font: UM.Theme.getFont("default"); + linkColor: UM.Theme.getColor("primary"); // "Cura Blue" + text: catalog.i18nc("@label link to connect manager", "Manage printers"); + } - style: UM.Theme.styles.scrollview + MouseArea { + anchors.fill: managePrintersLabel; + hoverEnabled: true; + onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel(); + onEntered: managePrintersLabel.font.underline = true; + onExited: managePrintersLabel.font.underline = false; + } - ListView - { - id: printer_list - property var current_index: -1 - anchors - { - top: parent.top - bottom: parent.bottom - left: parent.left - right: parent.right - leftMargin: 2 * UM.Theme.getSize("default_margin").width - rightMargin: 2 * UM.Theme.getSize("default_margin").width + // Skeleton loading + Column { + id: skeletonLoader; + anchors { + left: parent.left; + leftMargin: UM.Theme.getSize("wide_margin").width; + right: parent.right; + rightMargin: UM.Theme.getSize("wide_margin").width; + top: printingLabel.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + } + spacing: UM.Theme.getSize("default_margin").height - 10; + visible: printerList.count === 0; + + PrinterCard { + printer: null; + } + PrinterCard { + printer: null; + } + } + + // Actual content + ScrollView { + id: printerScrollView; + anchors { + bottom: parent.bottom; + left: parent.left; + right: parent.right; + top: printingLabel.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + } + style: UM.Theme.styles.scrollview; + + ListView { + id: printerList; + property var currentIndex: -1; + anchors { + fill: parent; + leftMargin: UM.Theme.getSize("wide_margin").width; + rightMargin: UM.Theme.getSize("wide_margin").width; } - spacing: UM.Theme.getSize("default_margin").height -10 - model: OutputDevice.printers - - delegate: Item - { - width: parent.width - height: base.height + 2 * base.shadowRadius // To ensure that the shadow doesn't get cut off. - Rectangle - { - width: parent.width - 2 * shadowRadius - height: childrenRect.height + UM.Theme.getSize("default_margin").height - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - color: - { - if(modelData.state == "disabled") - { - return UM.Theme.getColor("monitor_background_inactive") - } - else - { - return UM.Theme.getColor("monitor_background_active") - } - } - id: base - property var shadowRadius: 5 * screenScaleFactor - property var collapsed: true - - layer.enabled: true - layer.effect: DropShadow - { - radius: 5 * screenScaleFactor - verticalOffset: 2 - color: "#3F000000" // 25% shadow - } - - Connections - { - target: printer_list - onCurrent_indexChanged: { base.collapsed = printer_list.current_index != model.index } - } - - Item - { - id: printerInfo - height: machineIcon.height - anchors - { - top: parent.top - left: parent.left - right: parent.right - margins: UM.Theme.getSize("default_margin").width - } - - MouseArea - { - anchors.fill: parent - onClicked: - { - if (base.collapsed) { - printer_list.current_index = model.index - } - else - { - printer_list.current_index = -1 - } - } - } - - Item - { - id: machineIcon - // Yeah, this is hardcoded now, but I can't think of a good way to fix this. - // The UI is going to get another update soon, so it's probably not worth the effort... - width: 58 - height: 58 - anchors.top: parent.top - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.left: parent.left - - UM.RecolorImage - { - anchors.centerIn: parent - source: - { - switch(modelData.type) - { - case "Ultimaker 3": - return "../svg/UM3-icon.svg" - case "Ultimaker 3 Extended": - return "../svg/UM3x-icon.svg" - case "Ultimaker S5": - return "../svg/UMs5-icon.svg" - } - } - width: sourceSize.width - height: sourceSize.height - - color: - { - if(modelData.state == "disabled") - { - return UM.Theme.getColor("monitor_text_inactive") - } - - if(modelData.activePrintJob != undefined) - { - return UM.Theme.getColor("primary") - } - - return UM.Theme.getColor("monitor_text_inactive") - } - } - } - Item - { - height: childrenRect.height - anchors - { - right: collapseIcon.left - rightMargin: UM.Theme.getSize("default_margin").width - left: machineIcon.right - leftMargin: UM.Theme.getSize("default_margin").width - - verticalCenter: machineIcon.verticalCenter - } - - Label - { - id: machineNameLabel - text: modelData.name - width: parent.width - elide: Text.ElideRight - font: UM.Theme.getFont("default_bold") - } - - Label - { - id: activeJobLabel - text: - { - if (modelData.state == "disabled") - { - return catalog.i18nc("@label", "Not available") - } else if (modelData.state == "unreachable") - { - return catalog.i18nc("@label", "Unreachable") - } - if (modelData.activePrintJob != null) - { - return modelData.activePrintJob.name - } - return catalog.i18nc("@label", "Available") - } - anchors.top: machineNameLabel.bottom - width: parent.width - elide: Text.ElideRight - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("monitor_text_inactive") - } - } - - UM.RecolorImage - { - id: collapseIcon - width: 15 - height: 15 - sourceSize.width: width - sourceSize.height: height - source: base.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom") - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - color: "black" - } - } - - Item - { - id: detailedInfo - property var printJob: modelData.activePrintJob - visible: height == childrenRect.height - anchors.top: printerInfo.bottom - width: parent.width - height: !base.collapsed ? childrenRect.height : 0 - opacity: visible ? 1 : 0 - Behavior on height { NumberAnimation { duration: 100 } } - Behavior on opacity { NumberAnimation { duration: 100 } } - Rectangle - { - id: topSpacer - color: - { - if(modelData.state == "disabled") - { - return UM.Theme.getColor("monitor_lining_inactive") - } - return UM.Theme.getColor("viewport_background") - } - // UM.Theme.getColor("viewport_background") - height: 1 - anchors - { - left: parent.left - right: parent.right - margins: UM.Theme.getSize("default_margin").width - top: parent.top - topMargin: UM.Theme.getSize("default_margin").width - } - } - PrinterFamilyPill - { - id: printerFamilyPill - color: - { - if(modelData.state == "disabled") - { - return "transparent" - } - return UM.Theme.getColor("viewport_background") - } - anchors.top: topSpacer.bottom - anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height - text: modelData.type - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - padding: 3 - } - Row - { - id: extrudersInfo - anchors.top: printerFamilyPill.bottom - anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height - anchors.left: parent.left - anchors.leftMargin: 2 * UM.Theme.getSize("default_margin").width - anchors.right: parent.right - anchors.rightMargin: 2 * UM.Theme.getSize("default_margin").width - height: childrenRect.height - spacing: UM.Theme.getSize("default_margin").width - - PrintCoreConfiguration - { - id: leftExtruderInfo - width: Math.round(parent.width / 2) - printCoreConfiguration: modelData.printerConfiguration.extruderConfigurations[0] - } - - PrintCoreConfiguration - { - id: rightExtruderInfo - width: Math.round(parent.width / 2) - printCoreConfiguration: modelData.printerConfiguration.extruderConfigurations[1] - } - } - - Rectangle - { - id: jobSpacer - color: UM.Theme.getColor("viewport_background") - height: 2 - anchors - { - left: parent.left - right: parent.right - margins: UM.Theme.getSize("default_margin").width - top: extrudersInfo.bottom - topMargin: 2 * UM.Theme.getSize("default_margin").height - } - } - - Item - { - id: jobInfo - property var showJobInfo: modelData.activePrintJob != null && modelData.activePrintJob.state != "queued" - - anchors.top: jobSpacer.bottom - anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: UM.Theme.getSize("default_margin").width - anchors.leftMargin: 2 * UM.Theme.getSize("default_margin").width - height: showJobInfo ? childrenRect.height + 2 * UM.Theme.getSize("default_margin").height: 0 - visible: showJobInfo - Label - { - id: printJobName - text: modelData.activePrintJob != null ? modelData.activePrintJob.name : "" - font: UM.Theme.getFont("default_bold") - anchors.left: parent.left - anchors.right: contextButton.left - anchors.rightMargin: UM.Theme.getSize("default_margin").width - elide: Text.ElideRight - } - Label - { - id: ownerName - anchors.top: printJobName.bottom - text: modelData.activePrintJob != null ? modelData.activePrintJob.owner : "" - font: UM.Theme.getFont("default") - opacity: 0.6 - width: parent.width - elide: Text.ElideRight - } - - function switchPopupState() - { - popup.visible ? popup.close() : popup.open() - } - - Controls2.Button - { - id: contextButton - text: "\u22EE" //Unicode; Three stacked points. - width: 35 - height: width - anchors - { - right: parent.right - top: parent.top - } - hoverEnabled: true - - background: Rectangle - { - opacity: contextButton.down || contextButton.hovered ? 1 : 0 - width: contextButton.width - height: contextButton.height - radius: 0.5 * width - color: UM.Theme.getColor("viewport_background") - } - contentItem: Label - { - text: contextButton.text - color: UM.Theme.getColor("monitor_text_inactive") - font.pixelSize: 25 - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - } - - onClicked: parent.switchPopupState() - } - - Controls2.Popup - { - // TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property - id: popup - clip: true - closePolicy: Popup.CloseOnPressOutside - x: (parent.width - width) + 26 * screenScaleFactor - y: contextButton.height - 5 * screenScaleFactor // Because shadow - width: 182 * screenScaleFactor - height: contentItem.height + 2 * padding - visible: false - padding: 5 * screenScaleFactor // Because shadow - - transformOrigin: Popup.Top - contentItem: Item - { - width: popup.width - height: childrenRect.height + 36 * screenScaleFactor - anchors.topMargin: 10 * screenScaleFactor - anchors.bottomMargin: 10 * screenScaleFactor - Controls2.Button - { - id: pauseButton - text: modelData.activePrintJob != null && modelData.activePrintJob.state == "paused" ? catalog.i18nc("@label", "Resume") : catalog.i18nc("@label", "Pause") - onClicked: - { - if(modelData.activePrintJob.state == "paused") - { - modelData.activePrintJob.setState("print") - } - else if(modelData.activePrintJob.state == "printing") - { - modelData.activePrintJob.setState("pause") - } - popup.close() - } - width: parent.width - enabled: modelData.activePrintJob != null && ["paused", "printing"].indexOf(modelData.activePrintJob.state) >= 0 - visible: enabled - anchors.top: parent.top - anchors.topMargin: 18 * screenScaleFactor - height: visible ? 39 * screenScaleFactor : 0 * screenScaleFactor - hoverEnabled: true - background: Rectangle - { - opacity: pauseButton.down || pauseButton.hovered ? 1 : 0 - color: UM.Theme.getColor("viewport_background") - } - contentItem: Label - { - text: pauseButton.text - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - } - } - - Controls2.Button - { - id: abortButton - text: catalog.i18nc("@label", "Abort") - onClicked: - { - abortConfirmationDialog.visible = true; - popup.close(); - } - width: parent.width - height: 39 * screenScaleFactor - anchors.top: pauseButton.bottom - hoverEnabled: true - enabled: modelData.activePrintJob != null && ["paused", "printing", "pre_print"].indexOf(modelData.activePrintJob.state) >= 0 - background: Rectangle - { - opacity: abortButton.down || abortButton.hovered ? 1 : 0 - color: UM.Theme.getColor("viewport_background") - } - contentItem: Label - { - text: abortButton.text - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - } - } - - MessageDialog - { - id: abortConfirmationDialog - title: catalog.i18nc("@window:title", "Abort print") - icon: StandardIcon.Warning - text: catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to abort %1?").arg(modelData.activePrintJob.name) - standardButtons: StandardButton.Yes | StandardButton.No - Component.onCompleted: visible = false - onYes: modelData.activePrintJob.setState("abort") - } - } - - background: Item - { - width: popup.width - height: popup.height - - DropShadow - { - anchors.fill: pointedRectangle - radius: 5 - color: "#3F000000" // 25% shadow - source: pointedRectangle - transparentBorder: true - verticalOffset: 2 - } - - Item - { - id: pointedRectangle - width: parent.width - 10 * screenScaleFactor // Because of the shadow - height: parent.height - 10 * screenScaleFactor // Because of the shadow - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - - Rectangle - { - id: point - height: 14 * screenScaleFactor - width: 14 * screenScaleFactor - color: UM.Theme.getColor("setting_control") - transform: Rotation { angle: 45} - anchors.right: bloop.right - anchors.rightMargin: 24 - y: 1 - } - - Rectangle - { - id: bloop - color: UM.Theme.getColor("setting_control") - width: parent.width - anchors.top: parent.top - anchors.topMargin: 8 * screenScaleFactor // Because of the shadow + point - anchors.bottom: parent.bottom - anchors.bottomMargin: 8 * screenScaleFactor // Because of the shadow - } - } - } - - exit: Transition - { - // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { property: "visible"; duration: 75; } - } - enter: Transition - { - // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { property: "visible"; duration: 75; } - } - - onClosed: visible = false - onOpened: visible = true - } - - Image - { - id: printJobPreview - source: modelData.activePrintJob != null ? modelData.activePrintJob.previewImageUrl : "" - anchors.top: ownerName.bottom - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width / 2 - height: width - opacity: - { - if(modelData.activePrintJob == null) - { - return 1.0 - } - - switch(modelData.activePrintJob.state) - { - case "wait_cleanup": - case "wait_user_action": - case "paused": - return 0.5 - default: - return 1.0 - } - } - - - } - - UM.RecolorImage - { - id: statusImage - anchors.centerIn: printJobPreview - source: - { - if(modelData.activePrintJob == null) - { - return "" - } - switch(modelData.activePrintJob.state) - { - case "paused": - return "../svg/paused-icon.svg" - case "wait_cleanup": - if(modelData.activePrintJob.timeElapsed < modelData.activePrintJob.timeTotal) - { - return "../svg/aborted-icon.svg" - } - return "../svg/approved-icon.svg" - case "wait_user_action": - return "../svg/aborted-icon.svg" - default: - return "" - } - } - visible: source != "" - width: 0.5 * printJobPreview.width - height: 0.5 * printJobPreview.height - sourceSize.width: width - sourceSize.height: height - color: "black" - } - - CameraButton - { - id: showCameraButton - iconSource: "../svg/camera-icon.svg" - anchors - { - left: parent.left - bottom: printJobPreview.bottom - } - } - } - } - - ProgressBar - { - property var progress: - { - if(modelData.activePrintJob == null) - { - return 0 - } - var result = modelData.activePrintJob.timeElapsed / modelData.activePrintJob.timeTotal - if(result > 1.0) - { - result = 1.0 - } - return result - } - - id: jobProgressBar - width: parent.width - value: progress - anchors.top: detailedInfo.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - - visible: modelData.activePrintJob != null && modelData.activePrintJob != undefined - - style: ProgressBarStyle - { - property var remainingTime: - { - if(modelData.activePrintJob == null) - { - return 0 - } - /* Sometimes total minus elapsed is less than 0. Use Math.max() to prevent remaining - time from ever being less than 0. Negative durations cause strange behavior such - as displaying "-1h -1m". */ - var activeJob = modelData.activePrintJob - return Math.max(activeJob.timeTotal - activeJob.timeElapsed, 0); - } - property var progressText: - { - if(modelData.activePrintJob == null) - { - return "" - } - switch(modelData.activePrintJob.state) - { - case "wait_cleanup": - if(modelData.activePrintJob.timeTotal > modelData.activePrintJob.timeElapsed) - { - return catalog.i18nc("@label:status", "Aborted") - } - return catalog.i18nc("@label:status", "Finished") - case "pre_print": - case "sent_to_printer": - return catalog.i18nc("@label:status", "Preparing") - case "aborted": - return catalog.i18nc("@label:status", "Aborted") - case "wait_user_action": - return catalog.i18nc("@label:status", "Aborted") - case "pausing": - return catalog.i18nc("@label:status", "Pausing") - case "paused": - return OutputDevice.formatDuration( remainingTime ) - case "resuming": - return catalog.i18nc("@label:status", "Resuming") - case "queued": - return catalog.i18nc("@label:status", "Action required") - default: - return OutputDevice.formatDuration( remainingTime ) - } - } - - background: Rectangle - { - implicitWidth: 100 - implicitHeight: visible ? 24 : 0 - color: UM.Theme.getColor("viewport_background") - } - - progress: Rectangle - { - color: - { - var state = modelData.activePrintJob.state - var inactiveStates = [ - "pausing", - "paused", - "resuming", - "wait_cleanup" - ] - if(inactiveStates.indexOf(state) > -1 && remainingTime > 0) - { - return UM.Theme.getColor("monitor_text_inactive") - } - else - { - return UM.Theme.getColor("primary") - } - } - id: progressItem - function getTextOffset() - { - if(progressItem.width + progressLabel.width + 16 < control.width) - { - return progressItem.width + UM.Theme.getSize("default_margin").width - } - else - { - return progressItem.width - progressLabel.width - UM.Theme.getSize("default_margin").width - } - } - - Label - { - id: progressLabel - anchors.left: parent.left - anchors.leftMargin: getTextOffset() - text: progressText - anchors.verticalCenter: parent.verticalCenter - color: progressItem.width + progressLabel.width < control.width ? "black" : "white" - width: contentWidth - font: UM.Theme.getFont("default") - } - } - } - } - } + delegate: PrinterCard { + printer: modelData; } + model: OutputDevice.printers; + spacing: UM.Theme.getSize("default_margin").height - 10; } } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml b/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml index f6cf6607c7..c79092863e 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml @@ -1,108 +1,132 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 - import UM 1.3 as UM import Cura 1.0 as Cura -Component -{ - Rectangle - { - id: monitorFrame - width: maximumWidth - height: maximumHeight - color: UM.Theme.getColor("viewport_background") - property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight") - property var lineColor: "#DCDCDC" // TODO: Should be linked to theme. - property var cornerRadius: 4 * screenScaleFactor // TODO: Should be linked to theme. - - UM.I18nCatalog - { - id: catalog - name: "cura" - } - - Label - { - id: manageQueueLabel - anchors.rightMargin: 3 * UM.Theme.getSize("default_margin").width - anchors.right: queuedPrintJobs.right - anchors.bottom: queuedLabel.bottom - text: catalog.i18nc("@label link to connect manager", "Manage queue") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("primary") - linkColor: UM.Theme.getColor("primary") - } - - MouseArea - { - anchors.fill: manageQueueLabel - hoverEnabled: true - onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel() - onEntered: manageQueueLabel.font.underline = true - onExited: manageQueueLabel.font.underline = false - } - - Label - { - id: queuedLabel - anchors.left: queuedPrintJobs.left - anchors.top: parent.top - anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height - anchors.leftMargin: 3 * UM.Theme.getSize("default_margin").width + 5 - text: catalog.i18nc("@label", "Queued") - font: UM.Theme.getFont("large") - color: UM.Theme.getColor("text") - } - - ScrollView - { - id: queuedPrintJobs - - anchors - { - top: queuedLabel.bottom - topMargin: UM.Theme.getSize("default_margin").height - horizontalCenter: parent.horizontalCenter - bottomMargin: 0 - bottom: parent.bottom +Component { + Rectangle { + id: monitorFrame; + property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight"); + property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width; + color: UM.Theme.getColor("viewport_background"); + height: maximumHeight; + onVisibleChanged: { + if (monitorFrame != null && !monitorFrame.visible) { + OutputDevice.setActiveCamera(null); } - style: UM.Theme.styles.scrollview - width: Math.min(800 * screenScaleFactor, maximumWidth) - ListView - { - anchors.fill: parent - //anchors.margins: UM.Theme.getSize("default_margin").height - spacing: UM.Theme.getSize("default_margin").height - 10 // 2x the shadow radius + } + width: maximumWidth; - model: OutputDevice.queuedPrintJobs + UM.I18nCatalog { + id: catalog; + name: "cura"; + } - delegate: PrintJobInfoBlock - { - printJob: modelData - anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").height - anchors.leftMargin: UM.Theme.getSize("default_margin").height - height: 175 * screenScaleFactor + Label { + id: manageQueueLabel; + anchors { + bottom: queuedLabel.bottom; + right: queuedPrintJobs.right; + rightMargin: 3 * UM.Theme.getSize("default_margin").width; + } + color: UM.Theme.getColor("primary"); + font: UM.Theme.getFont("default"); + linkColor: UM.Theme.getColor("primary"); + text: catalog.i18nc("@label link to connect manager", "Manage queue"); + } + + MouseArea { + anchors.fill: manageQueueLabel; + hoverEnabled: true; + onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel(); + onEntered: manageQueueLabel.font.underline = true; + onExited: manageQueueLabel.font.underline = false; + } + + Label { + id: queuedLabel; + anchors { + left: queuedPrintJobs.left; + leftMargin: 3 * UM.Theme.getSize("default_margin").width + 5 * screenScaleFactor; + top: parent.top; + topMargin: 2 * UM.Theme.getSize("default_margin").height; + } + color: UM.Theme.getColor("text"); + font: UM.Theme.getFont("large"); + text: catalog.i18nc("@label", "Queued"); + } + + Column { + id: skeletonLoader; + anchors { + bottom: parent.bottom; + bottomMargin: UM.Theme.getSize("default_margin").height; + horizontalCenter: parent.horizontalCenter; + top: queuedLabel.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + } + visible: !queuedPrintJobs.visible; + width: Math.min(800 * screenScaleFactor, maximumWidth); + + PrintJobInfoBlock { + anchors { + left: parent.left; + leftMargin: UM.Theme.getSize("default_margin").width; + right: parent.right; + rightMargin: UM.Theme.getSize("default_margin").width; } + printJob: null; // Use as skeleton + } + + PrintJobInfoBlock { + anchors { + left: parent.left; + leftMargin: UM.Theme.getSize("default_margin").width; + right: parent.right; + rightMargin: UM.Theme.getSize("default_margin").width; + } + printJob: null; // Use as skeleton } } - PrinterVideoStream - { - visible: OutputDevice.activeCamera != null - anchors.fill: parent - camera: OutputDevice.activeCamera + ScrollView { + id: queuedPrintJobs; + anchors { + top: queuedLabel.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + horizontalCenter: parent.horizontalCenter; + bottomMargin: UM.Theme.getSize("default_margin").height; + bottom: parent.bottom; + } + style: UM.Theme.styles.scrollview; + visible: OutputDevice.receivedPrintJobs; + width: Math.min(800 * screenScaleFactor, maximumWidth); + + ListView { + id: printJobList; + anchors.fill: parent; + delegate: PrintJobInfoBlock { + anchors { + left: parent.left; + leftMargin: UM.Theme.getSize("default_margin").width; + right: parent.right; + rightMargin: UM.Theme.getSize("default_margin").width; + } + printJob: modelData; + } + model: OutputDevice.queuedPrintJobs; + spacing: UM.Theme.getSize("default_margin").height - 2 * UM.Theme.getSize("monitor_shadow_radius").width; + } } - onVisibleChanged: - { - if (monitorFrame != null && !monitorFrame.visible) - { - OutputDevice.setActiveCamera(null) - } + PrinterVideoStream { + anchors.fill: parent; + camera: OutputDevice.activeCamera; + visible: OutputDevice.activeCamera != null; } } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml index b5b80a3010..58443115a9 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml @@ -1,3 +1,6 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import UM 1.2 as UM import Cura 1.0 as Cura diff --git a/plugins/UM3NetworkPrinting/resources/qml/HorizontalLine.qml b/plugins/UM3NetworkPrinting/resources/qml/HorizontalLine.qml new file mode 100644 index 0000000000..aeb92697ad --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/HorizontalLine.qml @@ -0,0 +1,12 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +Rectangle { + color: UM.Theme.getColor("monitor_lining_light"); // TODO: Maybe theme separately? Maybe not. + height: UM.Theme.getSize("default_lining").height; + width: parent.width; +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorItem.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorItem.qml index bbbc3feee6..4b863ff9ed 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorItem.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorItem.qml @@ -1,54 +1,46 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 - - import UM 1.3 as UM import Cura 1.0 as Cura -Component -{ - Item - { - width: maximumWidth - height: maximumHeight - Image - { - id: cameraImage - width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth) - height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width) - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - z: 1 - Component.onCompleted: - { - if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) - { - OutputDevice.activePrinter.camera.start() +Component { + Item { + height: maximumHeight; + width: maximumWidth; + + Image { + id: cameraImage; + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter; + } + Component.onCompleted: { + if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) { + OutputDevice.activePrinter.camera.start(); } } - onVisibleChanged: - { - if(visible) - { - if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) - { - OutputDevice.activePrinter.camera.start() + height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width); + onVisibleChanged: { + if (visible) { + if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) { + OutputDevice.activePrinter.camera.start(); } - } else - { - if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) - { - OutputDevice.activePrinter.camera.stop() + } else { + if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) { + OutputDevice.activePrinter.camera.stop(); } } } - source: - { - if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null && OutputDevice.activePrinter.camera.latestImage) - { + source: { + if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null && OutputDevice.activePrinter.camera.latestImage) { return OutputDevice.activePrinter.camera.latestImage; } return ""; } + width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth); + z: 1; } } } \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml index b2f4e85f9a..7bcd9ce6e4 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml @@ -1,93 +1,121 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 - import UM 1.2 as UM +Item { + id: extruderInfo; + property var printCoreConfiguration: null; + height: childrenRect.height; + width: Math.round(parent.width / 2); -Item -{ - id: extruderInfo - property var printCoreConfiguration + // Extruder circle + Item { + id: extruderCircle; + height: UM.Theme.getSize("monitor_extruder_circle").height; + width: UM.Theme.getSize("monitor_extruder_circle").width; - width: Math.round(parent.width / 2) - height: childrenRect.height + // Loading skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill"); + radius: Math.round(width / 2); + visible: !printCoreConfiguration; + } - Item - { - id: extruderCircle - width: 30 - height: 30 - - anchors.verticalCenter: printAndMaterialLabel.verticalCenter - opacity: - { - if(printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null) - { - return 0.5 + // Actual content + Rectangle { + anchors.fill: parent; + border.width: UM.Theme.getSize("monitor_thick_lining").width; + border.color: UM.Theme.getColor("monitor_lining_heavy"); + color: "transparent"; + opacity: { + if (printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null) { + return 0.5; + } + return 1; } - return 1 - } + radius: Math.round(width / 2); + visible: printCoreConfiguration; - Rectangle - { - anchors.fill: parent - radius: Math.round(width / 2) - border.width: 2 - border.color: "black" - } - - Label - { - anchors.centerIn: parent - font: UM.Theme.getFont("default_bold") - text: printCoreConfiguration.position + 1 + Label { + anchors.centerIn: parent; + color: UM.Theme.getColor("text"); + font: UM.Theme.getFont("default_bold"); + text: printCoreConfiguration ? printCoreConfiguration.position + 1 : 0; + } } } - Item - { - id: printAndMaterialLabel - anchors - { - right: parent.right - left: extruderCircle.right - margins: UM.Theme.getSize("default_margin").width + // Print core and material labels + Item { + id: materialLabel + anchors { + left: extruderCircle.right; + leftMargin: UM.Theme.getSize("default_margin").width; + right: parent.right; + top: parent.top; } - height: childrenRect.height + height: UM.Theme.getSize("monitor_text_line").height; - Label - { - id: materialLabel - text: - { - if(printCoreConfiguration != undefined && printCoreConfiguration.activeMaterial != undefined) - { - return printCoreConfiguration.activeMaterial.name - } - return "" - } - font: UM.Theme.getFont("default") - elide: Text.ElideRight - width: parent.width + // Loading skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill"); + visible: !extruderInfo.printCoreConfiguration; } - Label - { - id: printCoreLabel - text: - { - if(printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined) - { - return printCoreConfiguration.hotendID + // Actual content + Label { + anchors.fill: parent; + elide: Text.ElideRight; + color: UM.Theme.getColor("text"); + font: UM.Theme.getFont("default"); + text: { + if (printCoreConfiguration && printCoreConfiguration.activeMaterial != undefined) { + return printCoreConfiguration.activeMaterial.name; } - return "" + return ""; } - anchors.top: materialLabel.bottom - elide: Text.ElideRight - width: parent.width - opacity: 0.6 - font: UM.Theme.getFont("default") + visible: extruderInfo.printCoreConfiguration; + } + } + + Item { + id: printCoreLabel; + anchors { + left: extruderCircle.right; + leftMargin: UM.Theme.getSize("default_margin").width; + right: parent.right; + top: materialLabel.bottom; + topMargin: Math.floor(UM.Theme.getSize("default_margin").height/4); + } + height: UM.Theme.getSize("monitor_text_line").height; + + // Loading skeleton + Rectangle { + color: UM.Theme.getColor("monitor_skeleton_fill"); + height: parent.height; + visible: !extruderInfo.printCoreConfiguration; + width: Math.round(parent.width / 3); + } + + // Actual content + Label { + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default"); + opacity: 0.6; + text: { + if (printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined) { + return printCoreConfiguration.hotendID; + } + return ""; + } + visible: extruderInfo.printCoreConfiguration; } } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml new file mode 100644 index 0000000000..55d3c66eb4 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml @@ -0,0 +1,212 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Dialogs 1.1 +import QtGraphicalEffects 1.0 +import UM 1.3 as UM + +Item { + id: root; + property var printJob: null; + property var running: isRunning(printJob); + + Button { + id: button; + background: Rectangle { + color: UM.Theme.getColor("viewport_background"); // TODO: Theme! + height: button.height; + opacity: button.down || button.hovered ? 1 : 0; + radius: Math.round(0.5 * width); + width: button.width; + } + contentItem: Label { + color: UM.Theme.getColor("monitor_context_menu_dots"); + font.pixelSize: 25 * screenScaleFactor; + horizontalAlignment: Text.AlignHCenter; + text: button.text; + verticalAlignment: Text.AlignVCenter; + } + height: width; + hoverEnabled: true; + onClicked: parent.switchPopupState(); + text: "\u22EE"; //Unicode; Three stacked points. + width: 35 * screenScaleFactor; // TODO: Theme! + } + + Popup { + id: popup; + background: Item { + anchors.fill: parent; + + DropShadow { + anchors.fill: pointedRectangle; + color: UM.Theme.getColor("monitor_shadow"); + radius: UM.Theme.getSize("monitor_shadow_radius").width; + source: pointedRectangle; + transparentBorder: true; + verticalOffset: 2 * screenScaleFactor; + } + + Item { + id: pointedRectangle; + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter; + } + height: parent.height - 10 * screenScaleFactor; // Because of the shadow + width: parent.width - 10 * screenScaleFactor; // Because of the shadow + + Rectangle { + id: point; + anchors { + right: bloop.right; + rightMargin: 24 * screenScaleFactor; + } + color: UM.Theme.getColor("monitor_context_menu_background"); + height: 14 * screenScaleFactor; + transform: Rotation { + angle: 45; + } + width: 14 * screenScaleFactor; + y: 1 * screenScaleFactor; + } + + Rectangle { + id: bloop; + anchors { + bottom: parent.bottom; + bottomMargin: 8 * screenScaleFactor; // Because of the shadow + top: parent.top; + topMargin: 8 * screenScaleFactor; // Because of the shadow + point + } + color: UM.Theme.getColor("monitor_context_menu_background"); + width: parent.width; + } + } + } + clip: true; + closePolicy: Popup.CloseOnPressOutside; + contentItem: Column { + id: popupOptions; + anchors { + top: parent.top; + topMargin: UM.Theme.getSize("default_margin").height + 10 * screenScaleFactor; // Account for the point of the box + } + height: childrenRect.height + spacing * popupOptions.children.length + UM.Theme.getSize("default_margin").height; + spacing: Math.floor(UM.Theme.getSize("default_margin").height / 2); + width: parent.width; + + PrintJobContextMenuItem { + enabled: { + if (printJob && !running) { + if (OutputDevice && OutputDevice.queuedPrintJobs[0]) { + return OutputDevice.queuedPrintJobs[0].key != printJob.key; + } + } + return false; + } + onClicked: { + sendToTopConfirmationDialog.visible = true; + popup.close(); + } + text: catalog.i18nc("@label", "Move to top"); + } + + PrintJobContextMenuItem { + enabled: printJob && !running; + onClicked: { + deleteConfirmationDialog.visible = true; + popup.close(); + } + text: catalog.i18nc("@label", "Delete"); + } + + PrintJobContextMenuItem { + enabled: printJob && running; + onClicked: { + if (printJob.state == "paused") { + printJob.setState("print"); + } else if(printJob.state == "printing") { + printJob.setState("pause"); + } + popup.close(); + } + text: printJob && printJob.state == "paused" ? catalog.i18nc("@label", "Resume") : catalog.i18nc("@label", "Pause"); + } + + PrintJobContextMenuItem { + enabled: printJob && running; + onClicked: { + abortConfirmationDialog.visible = true; + popup.close(); + } + text: catalog.i18nc("@label", "Abort"); + } + } + enter: Transition { + NumberAnimation { + duration: 75; + property: "visible"; + } + } + exit: Transition { + NumberAnimation { + duration: 75; + property: "visible"; + } + } + height: contentItem.height + 2 * padding; + onClosed: visible = false; + onOpened: visible = true; + padding: UM.Theme.getSize("monitor_shadow_radius").width; + transformOrigin: Popup.Top; + visible: false; + width: 182 * screenScaleFactor; + x: (button.width - width) + 26 * screenScaleFactor; + y: button.height + 5 * screenScaleFactor; // Because shadow + } + + MessageDialog { + id: sendToTopConfirmationDialog; + Component.onCompleted: visible = false; + icon: StandardIcon.Warning; + onYes: OutputDevice.sendJobToTop(printJob.key); + standardButtons: StandardButton.Yes | StandardButton.No; + text: printJob && printJob.name ? catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to move %1 to the top of the queue?").arg(printJob.name) : ""; + title: catalog.i18nc("@window:title", "Move print job to top"); + } + + MessageDialog { + id: deleteConfirmationDialog; + Component.onCompleted: visible = false; + icon: StandardIcon.Warning; + onYes: OutputDevice.deleteJobFromQueue(printJob.key); + standardButtons: StandardButton.Yes | StandardButton.No; + text: printJob && printJob.name ? catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to delete %1?").arg(printJob.name) : ""; + title: catalog.i18nc("@window:title", "Delete print job"); + } + + MessageDialog { + id: abortConfirmationDialog; + Component.onCompleted: visible = false; + icon: StandardIcon.Warning; + onYes: printJob.setState("abort"); + standardButtons: StandardButton.Yes | StandardButton.No; + text: printJob && printJob.name ? catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to abort %1?").arg(printJob.name) : ""; + title: catalog.i18nc("@window:title", "Abort print"); + } + + // Utils + function switchPopupState() { + popup.visible ? popup.close() : popup.open(); + } + function isRunning(job) { + if (!job) { + return false; + } + return ["paused", "printing", "pre_print"].indexOf(job.state) !== -1; + } +} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenuItem.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenuItem.qml new file mode 100644 index 0000000000..1b0777a8c0 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenuItem.qml @@ -0,0 +1,24 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.4 +import UM 1.3 as UM + +Button { + background: Rectangle { + opacity: parent.down || parent.hovered ? 1 : 0; + color: UM.Theme.getColor("monitor_context_menu_highlight"); + } + contentItem: Label { + color: UM.Theme.getColor("text"); + text: parent.text + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignVCenter; + } + height: 39 * screenScaleFactor; // TODO: Theme! + hoverEnabled: true; + visible: enabled; + width: parent.width; +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml index cfadabad5c..0fa65ba4c4 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml @@ -1,429 +1,476 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 import QtQuick.Dialogs 1.1 import QtQuick.Controls 2.0 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 - +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.1 import UM 1.3 as UM +Item { + id: root; + property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; + property var shadowOffset: 2 * screenScaleFactor; + property var debug: false; + property var printJob: null; + width: parent.width; // Bubbles downward + height: childrenRect.height + shadowRadius * 2; // Bubbles upward -Item -{ - id: base - property var printJob: null - property var shadowRadius: 5 * screenScaleFactor - function getPrettyTime(time) - { - return OutputDevice.formatDuration(time) + UM.I18nCatalog { + id: catalog; + name: "cura"; } - width: parent.width - - UM.I18nCatalog - { - id: catalog - name: "cura" - } - - Rectangle - { - id: background - anchors - { - top: parent.top - topMargin: 3 * screenScaleFactor - left: parent.left - leftMargin: base.shadowRadius - rightMargin: base.shadowRadius - right: parent.right - bottom: parent.bottom - bottomMargin: base.shadowRadius + // The actual card (white block) + Rectangle { + // 5px margin, but shifted 2px vertically because of the shadow + anchors { + bottomMargin: root.shadowRadius + root.shadowOffset; + leftMargin: root.shadowRadius; + rightMargin: root.shadowRadius; + topMargin: root.shadowRadius - root.shadowOffset; } - + color: UM.Theme.getColor("monitor_card_background"); + height: childrenRect.height; layer.enabled: true - layer.effect: DropShadow - { - radius: base.shadowRadius + layer.effect: DropShadow { + radius: root.shadowRadius verticalOffset: 2 * screenScaleFactor - color: "#3F000000" // 25% shadow + color: "#3F000000" // 25% shadow } + width: parent.width - shadowRadius * 2; - Item - { - // Content on the left of the infobox - anchors - { - top: parent.top - bottom: parent.bottom - left: parent.left - right: parent.horizontalCenter - margins: UM.Theme.getSize("wide_margin").width - rightMargin: UM.Theme.getSize("default_margin").width - } + Column { + height: childrenRect.height; + width: parent.width; - Label - { - id: printJobName - text: printJob.name - font: UM.Theme.getFont("default_bold") - width: parent.width - elide: Text.ElideRight - } + // Main content + Item { + id: mainContent; + height: 200 * screenScaleFactor; // TODO: Theme! + width: parent.width; - Label - { - id: ownerName - anchors.top: printJobName.bottom - text: printJob.owner - font: UM.Theme.getFont("default") - opacity: 0.6 - width: parent.width - elide: Text.ElideRight - } - - Image - { - id: printJobPreview - source: printJob.previewImageUrl - anchors.top: ownerName.bottom - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: totalTimeLabel.bottom - width: height - opacity: printJob.state == "error" ? 0.5 : 1.0 - } - - UM.RecolorImage - { - id: statusImage - anchors.centerIn: printJobPreview - source: printJob.state == "error" ? "../svg/aborted-icon.svg" : "" - visible: source != "" - width: 0.5 * printJobPreview.width - height: 0.5 * printJobPreview.height - sourceSize.width: width - sourceSize.height: height - color: "black" - } - - Label - { - id: totalTimeLabel - anchors.bottom: parent.bottom - anchors.right: parent.right - font: UM.Theme.getFont("default") - text: printJob != null ? getPrettyTime(printJob.timeTotal) : "" - elide: Text.ElideRight - } - } - - Item - { - // Content on the right side of the infobox. - anchors - { - top: parent.top - bottom: parent.bottom - left: parent.horizontalCenter - right: parent.right - margins: 2 * UM.Theme.getSize("default_margin").width - leftMargin: UM.Theme.getSize("default_margin").width - rightMargin: UM.Theme.getSize("default_margin").width / 2 - } - - Label - { - id: targetPrinterLabel - elide: Text.ElideRight - font: UM.Theme.getFont("default_bold") - text: - { - if(printJob.assignedPrinter == null) - { - if(printJob.state == "error") - { - return catalog.i18nc("@label", "Waiting for: Unavailable printer") - } - return catalog.i18nc("@label", "Waiting for: First available") - } - else - { - return catalog.i18nc("@label", "Waiting for: ") + printJob.assignedPrinter.name + // Left content + Item { + anchors { + bottom: parent.bottom; + left: parent.left; + margins: UM.Theme.getSize("wide_margin").width; + right: parent.horizontalCenter; + top: parent.top; } - } + Item { + id: printJobName; + width: parent.width; + height: UM.Theme.getSize("monitor_text_line").height; - anchors - { - left: parent.left - right: contextButton.left - rightMargin: UM.Theme.getSize("default_margin").width - } - } - - - function switchPopupState() - { - popup.visible ? popup.close() : popup.open() - } - - Button - { - id: contextButton - text: "\u22EE" //Unicode; Three stacked points. - width: 35 - height: width - anchors - { - right: parent.right - top: parent.top - } - hoverEnabled: true - - background: Rectangle - { - opacity: contextButton.down || contextButton.hovered ? 1 : 0 - width: contextButton.width - height: contextButton.height - radius: 0.5 * width - color: UM.Theme.getColor("viewport_background") - } - contentItem: Label - { - text: contextButton.text - color: UM.Theme.getColor("monitor_text_inactive") - font.pixelSize: 25 - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - } - - onClicked: parent.switchPopupState() - } - - Popup - { - // TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property - id: popup - clip: true - closePolicy: Popup.CloseOnPressOutside - x: (parent.width - width) + 26 * screenScaleFactor - y: contextButton.height - 5 * screenScaleFactor // Because shadow - width: 182 * screenScaleFactor - height: contentItem.height + 2 * padding - visible: false - padding: 5 * screenScaleFactor // Because shadow - - transformOrigin: Popup.Top - contentItem: Item - { - width: popup.width - height: childrenRect.height + 36 * screenScaleFactor - anchors.topMargin: 10 * screenScaleFactor - anchors.bottomMargin: 10 * screenScaleFactor - Button - { - id: sendToTopButton - text: catalog.i18nc("@label", "Move to top") - onClicked: - { - sendToTopConfirmationDialog.visible = true; - popup.close(); + Rectangle { + color: UM.Theme.getColor("monitor_skeleton_fill"); + height: parent.height; + visible: !printJob; + width: Math.round(parent.width / 3); } - width: parent.width - enabled: OutputDevice.queuedPrintJobs[0].key != printJob.key - visible: enabled - anchors.top: parent.top - anchors.topMargin: 18 * screenScaleFactor - height: visible ? 39 * screenScaleFactor : 0 * screenScaleFactor - hoverEnabled: true - background: Rectangle - { - opacity: sendToTopButton.down || sendToTopButton.hovered ? 1 : 0 - color: UM.Theme.getColor("viewport_background") - } - contentItem: Label - { - text: sendToTopButton.text - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter + Label { + anchors.fill: parent; + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default_bold"); + text: printJob && printJob.name ? printJob.name : ""; // Supress QML warnings + visible: printJob; } } - MessageDialog - { - id: sendToTopConfirmationDialog - title: catalog.i18nc("@window:title", "Move print job to top") - icon: StandardIcon.Warning - text: catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to move %1 to the top of the queue?").arg(printJob.name) - standardButtons: StandardButton.Yes | StandardButton.No - Component.onCompleted: visible = false - onYes: OutputDevice.sendJobToTop(printJob.key) - } + Item { + id: printJobOwnerName; + anchors { + top: printJobName.bottom; + topMargin: Math.floor(UM.Theme.getSize("default_margin").height / 2); + } + height: UM.Theme.getSize("monitor_text_line").height; + width: parent.width; - Button - { - id: deleteButton - text: catalog.i18nc("@label", "Delete") - onClicked: - { - deleteConfirmationDialog.visible = true; - popup.close(); + Rectangle { + color: UM.Theme.getColor("monitor_skeleton_fill"); + height: parent.height; + visible: !printJob; + width: Math.round(parent.width / 2); } - width: parent.width - height: 39 * screenScaleFactor - anchors.top: sendToTopButton.bottom - hoverEnabled: true - background: Rectangle - { - opacity: deleteButton.down || deleteButton.hovered ? 1 : 0 - color: UM.Theme.getColor("viewport_background") - } - contentItem: Label - { - text: deleteButton.text - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter + Label { + anchors.fill: parent; + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default"); + text: printJob ? printJob.owner : ""; // Supress QML warnings + visible: printJob; } } - MessageDialog - { - id: deleteConfirmationDialog - title: catalog.i18nc("@window:title", "Delete print job") - icon: StandardIcon.Warning - text: catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to delete %1?").arg(printJob.name) - standardButtons: StandardButton.Yes | StandardButton.No - Component.onCompleted: visible = false - onYes: OutputDevice.deleteJobFromQueue(printJob.key) - } - } + Item { + id: printJobPreview; + property var useUltibot: false; + anchors { + bottom: parent.bottom; + horizontalCenter: parent.horizontalCenter; + top: printJobOwnerName.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + } + width: height; - background: Item - { - width: popup.width - height: popup.height - - DropShadow - { - anchors.fill: pointedRectangle - radius: 5 - color: "#3F000000" // 25% shadow - source: pointedRectangle - transparentBorder: true - verticalOffset: 2 - } - - Item - { - id: pointedRectangle - width: parent.width - 10 * screenScaleFactor // Because of the shadow - height: parent.height - 10 * screenScaleFactor // Because of the shadow - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - - Rectangle - { - id: point - height: 14 * screenScaleFactor - width: 14 * screenScaleFactor - color: UM.Theme.getColor("setting_control") - transform: Rotation { angle: 45} - anchors.right: bloop.right - anchors.rightMargin: 24 - y: 1 + // Skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill"); + radius: UM.Theme.getSize("default_margin").width; + visible: !printJob; } - Rectangle - { - id: bloop - color: UM.Theme.getColor("setting_control") - width: parent.width - anchors.top: parent.top - anchors.topMargin: 8 * screenScaleFactor // Because of the shadow + point - anchors.bottom: parent.bottom - anchors.bottomMargin: 8 * screenScaleFactor // Because of the shadow + // Actual content + Image { + id: previewImage; + anchors.fill: parent; + opacity: printJob && printJob.state == "error" ? 0.5 : 1.0; + source: printJob ? printJob.previewImageUrl : ""; + visible: printJob; + } + + UM.RecolorImage { + id: ultiBotImage; + + anchors.centerIn: printJobPreview; + color: UM.Theme.getColor("monitor_placeholder_image"); + height: printJobPreview.height; + source: "../svg/ultibot.svg"; + sourceSize { + height: height; + width: width; + } + /* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or + not in order to determine if we show the placeholder (ultibot) image instead. */ + visible: printJob && previewImage.status == Image.Error; + width: printJobPreview.width; + } + + UM.RecolorImage { + id: statusImage; + anchors.centerIn: printJobPreview; + color: UM.Theme.getColor("monitor_image_overlay"); + height: 0.5 * printJobPreview.height; + source: printJob && printJob.state == "error" ? "../svg/aborted-icon.svg" : ""; + sourceSize { + height: height; + width: width; + } + visible: source != ""; + width: 0.5 * printJobPreview.width; } } } - exit: Transition - { - // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { property: "visible"; duration: 75; } - } - enter: Transition - { - // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { property: "visible"; duration: 75; } + // Divider + Rectangle { + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter; + } + color: !printJob ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_lining_light"); + height: parent.height - 2 * UM.Theme.getSize("default_margin").height; + width: UM.Theme.getSize("default_lining").width; } - onClosed: visible = false - onOpened: visible = true - } + // Right content + Item { + anchors { + bottom: parent.bottom; + left: parent.horizontalCenter; + margins: UM.Theme.getSize("wide_margin").width; + right: parent.right; + top: parent.top; + } - Row - { - id: printerFamilyPills - spacing: 0.5 * UM.Theme.getSize("default_margin").width - anchors - { - left: parent.left - right: parent.right - bottom: extrudersInfo.top - bottomMargin: UM.Theme.getSize("default_margin").height - } - height: childrenRect.height - Repeater - { - model: printJob.compatibleMachineFamilies + Item { + id: targetPrinterLabel; + height: UM.Theme.getSize("monitor_text_line").height; + width: parent.width; - delegate: PrinterFamilyPill - { - text: modelData - color: UM.Theme.getColor("viewport_background") - padding: 3 * screenScaleFactor + Rectangle { + visible: !printJob; + color: UM.Theme.getColor("monitor_skeleton_fill"); + anchors.fill: parent; + } + + Label { + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default_bold"); + text: { + if (printJob !== null) { + if (printJob.assignedPrinter == null) { + if (printJob.state == "error") { + return catalog.i18nc("@label", "Waiting for: Unavailable printer"); + } + return catalog.i18nc("@label", "Waiting for: First available"); + } else { + return catalog.i18nc("@label", "Waiting for: ") + printJob.assignedPrinter.name; + } + } + return ""; + } + visible: printJob; + } + } + + PrinterInfoBlock { + anchors.bottom: parent.bottom; + printer: root.printJon && root.printJob.assignedPrinter; + printJob: root.printJob; } } - } - // PrintCore && Material config - Row - { - id: extrudersInfo - anchors.bottom: parent.bottom - anchors - { - left: parent.left - right: parent.right - } - height: childrenRect.height - - spacing: UM.Theme.getSize("default_margin").width - - PrintCoreConfiguration - { - id: leftExtruderInfo - width: Math.round(parent.width / 2) * screenScaleFactor - printCoreConfiguration: printJob.configuration.extruderConfigurations[0] - } - - PrintCoreConfiguration - { - id: rightExtruderInfo - width: Math.round(parent.width / 2) * screenScaleFactor - printCoreConfiguration: printJob.configuration.extruderConfigurations[1] + PrintJobContextMenu { + id: contextButton; + anchors { + right: mainContent.right; + rightMargin: UM.Theme.getSize("default_margin").width * 3 + root.shadowRadius; + top: mainContent.top; + topMargin: UM.Theme.getSize("default_margin").height; + } + printJob: root.printJob; + visible: root.printJob; } } - } + Item { + id: configChangesBox; + height: childrenRect.height; + visible: printJob && printJob.configurationChanges.length !== 0; + width: parent.width; - Rectangle - { - color: UM.Theme.getColor("viewport_background") - width: 2 * screenScaleFactor - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.margins: UM.Theme.getSize("default_margin").height - anchors.horizontalCenter: parent.horizontalCenter + // Config change toggle + Rectangle { + id: configChangeToggle; + color: { + if (configChangeToggleArea.containsMouse) { + return UM.Theme.getColor("viewport_background"); // TODO: Theme! + } else { + return "transparent"; + } + } + width: parent.width; + height: UM.Theme.getSize("default_margin").height * 4; // TODO: Theme! + anchors { + left: parent.left; + right: parent.right; + top: parent.top; + } + + Rectangle { + color: !printJob ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_lining_light"); + height: UM.Theme.getSize("default_lining").height; + width: parent.width; + } + + UM.RecolorImage { + anchors { + right: configChangeToggleLabel.left; + rightMargin: UM.Theme.getSize("default_margin").width; + verticalCenter: parent.verticalCenter; + } + color: UM.Theme.getColor("text"); + height: 23 * screenScaleFactor; // TODO: Theme! + source: "../svg/warning-icon.svg"; + sourceSize { + height: height; + width: width; + } + width: 23 * screenScaleFactor; // TODO: Theme! + } + + Label { + id: configChangeToggleLabel; + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter; + } + color: UM.Theme.getColor("text"); + text: catalog.i18nc("@label", "Configuration change"); + } + + UM.RecolorImage { + anchors { + left: configChangeToggleLabel.right; + leftMargin: UM.Theme.getSize("default_margin").width; + verticalCenter: parent.verticalCenter; + } + color: UM.Theme.getColor("text"); + height: 15 * screenScaleFactor; // TODO: Theme! + source: { + if (configChangeDetails.visible) { + return UM.Theme.getIcon("arrow_top"); + } else { + return UM.Theme.getIcon("arrow_bottom"); + } + } + sourceSize { + width: width; + height: height; + } + width: 15 * screenScaleFactor; // TODO: Theme! + } + + MouseArea { + id: configChangeToggleArea; + anchors.fill: parent; + hoverEnabled: true; + onClicked: { + configChangeDetails.visible = !configChangeDetails.visible; + } + } + } + + // Config change details + Item { + id: configChangeDetails; + anchors.top: configChangeToggle.bottom; + Behavior on height { NumberAnimation { duration: 100 } } + // In case of really massive multi-line configuration changes + height: visible ? Math.max(UM.Theme.getSize("monitor_config_override_box").height, childrenRect.height) : 0; + visible: false; + width: parent.width; + + Item { + anchors { + bottomMargin: UM.Theme.getSize("wide_margin").height; + fill: parent; + leftMargin: UM.Theme.getSize("wide_margin").height * 4; + rightMargin: UM.Theme.getSize("wide_margin").height * 4; + topMargin: UM.Theme.getSize("wide_margin").height; + } + clip: true; + + Label { + anchors.fill: parent; + elide: Text.ElideRight; + color: UM.Theme.getColor("text"); + font: UM.Theme.getFont("large_nonbold"); + text: { + if (!printJob || printJob.configurationChanges.length === 0) { + return ""; + } + var topLine; + if (materialsAreKnown(printJob)) { + topLine = catalog.i18nc("@label", "The assigned printer, %1, requires the following configuration change(s):").arg(printJob.assignedPrinter.name); + } else { + topLine = catalog.i18nc("@label", "The printer %1 is assigned, but the job contains an unknown material configuration.").arg(printJob.assignedPrinter.name); + } + var result = "
" + topLine +"
"; + for (var i = 0; i < printJob.configurationChanges.length; i++) { + var change = printJob.configurationChanges[i]; + var text; + switch (change.typeOfChange) { + case "material_change": + text = catalog.i18nc("@label", "Change material %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName); + break; + case "material_insert": + text = catalog.i18nc("@label", "Load %3 as material %1 (This cannot be overridden).").arg(change.index + 1).arg(change.targetName); + break; + case "print_core_change": + text = catalog.i18nc("@label", "Change print core %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName); + break; + case "buildplate_change": + text = catalog.i18nc("@label", "Change build plate to %1 (This cannot be overridden).").arg(formatBuildPlateType(change.target_name)); + break; + default: + text = ""; + } + result += "" + text + "
"; + } + return result; + } + wrapMode: Text.WordWrap; + } + + Button { + anchors { + bottom: parent.bottom; + left: parent.left; + } + onClicked: { + overrideConfirmationDialog.visible = true; + } + text: catalog.i18nc("@label", "Override"); + visible: { + if (printJob && printJob.configurationChanges) { + var length = printJob.configurationChanges.length; + for (var i = 0; i < length; i++) { + var typeOfChange = printJob.configurationChanges[i].typeOfChange; + if (typeOfChange === "material_insert" || typeOfChange === "buildplate_change") { + return false; + } + } + } + return true; + } + } + } + } + + MessageDialog { + id: overrideConfirmationDialog; + Component.onCompleted: visible = false; + icon: StandardIcon.Warning; + onYes: OutputDevice.forceSendJob(printJob.key); + standardButtons: StandardButton.Yes | StandardButton.No; + text: { + if (!printJob) { + return ""; + } + var printJobName = formatPrintJobName(printJob.name); + var confirmText = catalog.i18nc("@label", "Starting a print job with an incompatible configuration could damage your 3D printer. Are you sure you want to override the configuration and print %1?").arg(printJobName); + return confirmText; + } + title: catalog.i18nc("@window:title", "Override configuration configuration and start print"); + } + } } } -} \ No newline at end of file + // Utils + function formatPrintJobName(name) { + var extensions = [ ".gz", ".gcode", ".ufp" ]; + for (var i = 0; i < extensions.length; i++) { + var extension = extensions[i]; + if (name.slice(-extension.length) === extension) { + name = name.substring(0, name.length - extension.length); + } + } + return name; + } + function materialsAreKnown(job) { + var conf0 = job.configuration[0]; + if (conf0 && !conf0.material.material) { + return false; + } + var conf1 = job.configuration[1]; + if (conf1 && !conf1.material.material) { + return false; + } + return true; + } + function formatBuildPlateType(buildPlateType) { + var translationText = ""; + switch (buildPlateType) { + case "glass": + translationText = catalog.i18nc("@label", "Glass"); + break; + case "aluminum": + translationText = catalog.i18nc("@label", "Aluminum"); + break; + default: + translationText = null; + } + return translationText; + } +} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml new file mode 100644 index 0000000000..b1a73255f4 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml @@ -0,0 +1,75 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.3 +import QtGraphicalEffects 1.0 +import QtQuick.Controls 1.4 as LegacyControls +import UM 1.3 as UM + +// Includes print job name, owner, and preview + +Item { + property var job: null; + property var useUltibot: false; + height: 100 * screenScaleFactor; + width: height; + + // Skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill"); + radius: UM.Theme.getSize("default_margin").width; + visible: !job; + } + + // Actual content + Image { + id: previewImage; + visible: job; + source: job ? job.previewImageUrl : ""; + opacity: { + if (job == null) { + return 1.0; + } + var states = ["wait_cleanup", "wait_user_action", "error", "paused"]; + if (states.indexOf(job.state) !== -1) { + return 0.5; + } + return 1.0; + } + anchors.fill: parent; + } + + UM.RecolorImage { + id: ultibotImage; + anchors.centerIn: parent; + color: UM.Theme.getColor("monitor_placeholder_image"); // TODO: Theme! + height: parent.height; + source: "../svg/ultibot.svg"; + sourceSize { + height: height; + width: width; + } + /* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or + not in order to determine if we show the placeholder (ultibot) image instead. */ + visible: job && previewImage.status == Image.Error; + width: parent.width; + } + + UM.RecolorImage { + id: statusImage; + anchors.centerIn: parent; + color: "black"; // TODO: Theme! + height: Math.round(0.5 * parent.height); + source: job && job.state == "error" ? "../svg/aborted-icon.svg" : ""; + sourceSize { + height: height; + width: width; + } + visible: source != ""; + width: Math.round(0.5 * parent.width); + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml new file mode 100644 index 0000000000..f9f7b5ae87 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml @@ -0,0 +1,59 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +Column { + property var job: null; + height: childrenRect.height; + spacing: Math.floor( UM.Theme.getSize("default_margin").height / 2); // TODO: Use explicit theme size + width: parent.width; + + Item { + id: jobName; + height: UM.Theme.getSize("monitor_text_line").height; + width: parent.width; + + // Skeleton loading + Rectangle { + color: UM.Theme.getColor("monitor_skeleton_fill"); + height: parent.height; + visible: !job; + width: Math.round(parent.width / 3); + } + + Label { + anchors.fill: parent; + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default_bold"); + text: job && job.name ? job.name : ""; + visible: job; + } + } + + Item { + id: ownerName; + height: UM.Theme.getSize("monitor_text_line").height; + width: parent.width; + + // Skeleton loading + Rectangle { + color: UM.Theme.getColor("monitor_skeleton_fill"); + height: parent.height; + visible: !job; + width: Math.round(parent.width / 2); + } + + Label { + anchors.fill: parent; + color: UM.Theme.getColor("text") + elide: Text.ElideRight; + font: UM.Theme.getFont("default"); + text: job ? job.owner : ""; + visible: job; + } + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintWindow.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintWindow.qml index 9793b218fc..a28167d260 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintWindow.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintWindow.qml @@ -4,112 +4,101 @@ import QtQuick 2.2 import QtQuick.Window 2.2 import QtQuick.Controls 1.2 - import UM 1.1 as UM -UM.Dialog -{ +UM.Dialog { id: base; - - minimumWidth: 500 * screenScaleFactor - minimumHeight: 140 * screenScaleFactor - maximumWidth: minimumWidth - maximumHeight: minimumHeight - width: minimumWidth - height: minimumHeight - - visible: true - modality: Qt.ApplicationModal - onVisibleChanged: - { - if(visible) - { - resetPrintersModel() - } - else - { - OutputDevice.cancelPrintSelection() - } + property var printersModel: { + return ListModel{}; } - title: catalog.i18nc("@title:window", "Print over network") - - property var printersModel: ListModel{} - function resetPrintersModel() { - printersModel.clear() - printersModel.append({ name: "Automatic", key: ""}) - - for (var index in OutputDevice.printers) - { - printersModel.append({name: OutputDevice.printers[index].name, key: OutputDevice.printers[index].key}) - } - } - - Column - { - id: printerSelection - anchors.fill: parent - anchors.top: parent.top - anchors.topMargin: UM.Theme.getSize("default_margin").height - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.rightMargin: UM.Theme.getSize("default_margin").width - height: 50 * screenScaleFactor - Label - { - id: manualPrinterSelectionLabel - anchors - { - left: parent.left - topMargin: UM.Theme.getSize("default_margin").height - right: parent.right - } - text: catalog.i18nc("@label", "Printer selection") - wrapMode: Text.Wrap - height: 20 * screenScaleFactor - } - - ComboBox - { - id: printerSelectionCombobox - model: base.printersModel - textRole: "name" - - width: parent.width - height: 40 * screenScaleFactor - Behavior on height { NumberAnimation { duration: 100 } } - } - - SystemPalette - { - id: palette - } - - UM.I18nCatalog { id: catalog; name: "cura"; } - } - + height: minimumHeight; leftButtons: [ - Button - { - text: catalog.i18nc("@action:button","Cancel") - enabled: true + Button { + enabled: true; onClicked: { base.visible = false; - printerSelectionCombobox.currentIndex = 0 - OutputDevice.cancelPrintSelection() + printerSelectionCombobox.currentIndex = 0; + OutputDevice.cancelPrintSelection(); } + text: catalog.i18nc("@action:button","Cancel"); } ] - + maximumHeight: minimumHeight; + maximumWidth: minimumWidth; + minimumHeight: 140 * screenScaleFactor; + minimumWidth: 500 * screenScaleFactor; + modality: Qt.ApplicationModal; + onVisibleChanged: { + if (visible) { + resetPrintersModel(); + } else { + OutputDevice.cancelPrintSelection(); + } + } rightButtons: [ - Button - { - text: catalog.i18nc("@action:button","Print") - enabled: true + Button { + enabled: true; onClicked: { base.visible = false; - OutputDevice.selectPrinter(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key) + OutputDevice.selectPrinter(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key); // reset to defaults - printerSelectionCombobox.currentIndex = 0 + printerSelectionCombobox.currentIndex = 0; } + text: catalog.i18nc("@action:button","Print"); } ] + title: catalog.i18nc("@title:window", "Print over network"); + visible: true; + width: minimumWidth; + + Column { + id: printerSelection; + anchors { + fill: parent; + leftMargin: UM.Theme.getSize("default_margin").width; + rightMargin: UM.Theme.getSize("default_margin").width; + top: parent.top; + topMargin: UM.Theme.getSize("default_margin").height; + } + height: 50 * screenScaleFactor; + + SystemPalette { + id: palette; + } + + UM.I18nCatalog { + id: catalog; + name: "cura"; + } + + Label { + id: manualPrinterSelectionLabel; + anchors { + left: parent.left; + right: parent.right; + topMargin: UM.Theme.getSize("default_margin").height; + } + height: 20 * screenScaleFactor; + text: catalog.i18nc("@label", "Printer selection"); + wrapMode: Text.Wrap; + } + + ComboBox { + id: printerSelectionCombobox; + Behavior on height { NumberAnimation { duration: 100 } } + height: 40 * screenScaleFactor; + model: base.printersModel; + textRole: "name"; + width: parent.width; + } + } + + // Utils + function resetPrintersModel() { + printersModel.clear(); + printersModel.append({ name: "Automatic", key: ""}); + for (var index in OutputDevice.printers) { + printersModel.append({name: OutputDevice.printers[index].name, key: OutputDevice.printers[index].key}); + } + } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml new file mode 100644 index 0000000000..79a915d0d1 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml @@ -0,0 +1,236 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.3 +import QtGraphicalEffects 1.0 +import UM 1.3 as UM + +Item { + id: root; + property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; + property var shadowOffset: UM.Theme.getSize("monitor_shadow_offset").width; + property var printer: null; + property var collapsed: true; + height: childrenRect.height + shadowRadius * 2; // Bubbles upward + width: parent.width; // Bubbles downward + + // The actual card (white block) + Rectangle { + // 5px margin, but shifted 2px vertically because of the shadow + anchors { + bottomMargin: root.shadowRadius + root.shadowOffset; + leftMargin: root.shadowRadius; + rightMargin: root.shadowRadius; + topMargin: root.shadowRadius - root.shadowOffset; + } + color: { + if (!printer) { + return UM.Theme.getColor("monitor_card_background_inactive"); + } + if (printer.state == "disabled") { + return UM.Theme.getColor("monitor_card_background_inactive"); + } else { + return UM.Theme.getColor("monitor_card_background"); + } + } + height: childrenRect.height; + layer.effect: DropShadow { + radius: root.shadowRadius; + verticalOffset: root.shadowOffset; + color: "#3F000000"; // 25% shadow + } + layer.enabled: true + width: parent.width - 2 * shadowRadius; + + Column { + height: childrenRect.height; + width: parent.width; + + // Main card + Item { + id: mainCard; + height: 60 * screenScaleFactor + 2 * UM.Theme.getSize("default_margin").width; + width: parent.width; + + // Machine icon + Item { + id: machineIcon; + anchors { + leftMargin: UM.Theme.getSize("wide_margin").width; + top: parent.top; + left: parent.left; + margins: UM.Theme.getSize("default_margin").width; + } + height: parent.height - 2 * UM.Theme.getSize("default_margin").width; + width: height; + + // Skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill_dark"); + radius: UM.Theme.getSize("default_margin").width; + visible: !printer; + } + + // Content + UM.RecolorImage { + anchors.centerIn: parent; + color: { + if (printer && printer.activePrintJob != undefined) { + return UM.Theme.getColor("monitor_printer_icon"); + } + return UM.Theme.getColor("monitor_printer_icon_inactive"); + } + height: sourceSize.height; + source: { + if (!printer) { + return ""; + } + switch(printer.type) { + case "Ultimaker 3": + return "../svg/UM3-icon.svg"; + case "Ultimaker 3 Extended": + return "../svg/UM3x-icon.svg"; + case "Ultimaker S5": + return "../svg/UMs5-icon.svg"; + } + } + visible: printer; + width: sourceSize.width; + } + } + + // Printer info + Item { + id: printerInfo; + anchors { + left: machineIcon.right; + leftMargin: UM.Theme.getSize("default_margin").width; + right: collapseIcon.left; + verticalCenter: machineIcon.verticalCenter; + } + height: childrenRect.height; + + // Machine name + Item { + id: machineNameLabel; + height: UM.Theme.getSize("monitor_text_line").height; + width: Math.round(parent.width * 0.3); + + // Skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill_dark"); + visible: !printer; + } + + // Actual content + Label { + anchors.fill: parent; + color: UM.Theme.getColor("text"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default_bold"); + text: printer ? printer.name : ""; + visible: printer; + width: parent.width; + } + } + + // Job name + Item { + id: activeJobLabel; + anchors { + top: machineNameLabel.bottom; + topMargin: Math.round(UM.Theme.getSize("default_margin").height / 2); + } + height: UM.Theme.getSize("monitor_text_line").height; + width: Math.round(parent.width * 0.75); + + // Skeleton + Rectangle { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_skeleton_fill_dark"); + visible: !printer; + } + + // Actual content + Label { + anchors.fill: parent; + color: UM.Theme.getColor("monitor_text_inactive"); + elide: Text.ElideRight; + font: UM.Theme.getFont("default"); + text: { + if (!printer) { + return ""; + } + if (printer.state == "disabled") { + return catalog.i18nc("@label", "Not available"); + } else if (printer.state == "unreachable") { + return catalog.i18nc("@label", "Unreachable"); + } + if (printer.activePrintJob != null && printer.activePrintJob.name) { + return printer.activePrintJob.name; + } + return catalog.i18nc("@label", "Available"); + } + visible: printer; + } + } + } + + // Collapse icon + UM.RecolorImage { + id: collapseIcon; + anchors { + right: parent.right; + rightMargin: UM.Theme.getSize("default_margin").width; + verticalCenter: parent.verticalCenter; + } + color: UM.Theme.getColor("text"); + height: 15 * screenScaleFactor; // TODO: Theme! + source: root.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom"); + sourceSize { + height: height; + width: width; + } + visible: printer; + width: 15 * screenScaleFactor; // TODO: Theme! + } + + MouseArea { + anchors.fill: parent; + enabled: printer; + onClicked: { + if (model && root.collapsed) { + printerList.currentIndex = model.index; + } else { + printerList.currentIndex = -1; + } + } + } + + Connections { + target: printerList; + onCurrentIndexChanged: { + root.collapsed = printerList.currentIndex != model.index; + } + } + } + + // Detailed card + PrinterCardDetails { + collapsed: root.collapsed; + printer: root.printer; + visible: root.printer; + } + + // Progress bar + PrinterCardProgressBar { + visible: printer && printer.activePrintJob != null; + } + } + } +} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml new file mode 100644 index 0000000000..d7102d5493 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml @@ -0,0 +1,84 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.3 +import QtGraphicalEffects 1.0 +import QtQuick.Controls 1.4 as LegacyControls +import UM 1.3 as UM + +Item { + id: root; + property var printer: null; + property var printJob: printer ? printer.activePrintJob : null; + property var collapsed: true; + Behavior on height { NumberAnimation { duration: 100 } } + Behavior on opacity { NumberAnimation { duration: 100 } } + height: collapsed ? 0 : childrenRect.height; + opacity: collapsed ? 0 : 1; + width: parent.width; + + Column { + id: contentColumn; + anchors { + left: parent.left; + leftMargin: UM.Theme.getSize("default_margin").width; + right: parent.right; + rightMargin: UM.Theme.getSize("default_margin").width; + } + height: childrenRect.height + UM.Theme.getSize("wide_margin").height; + spacing: UM.Theme.getSize("default_margin").height; + width: parent.width; + + HorizontalLine {} + + PrinterInfoBlock { + printer: root.printer; + printJob: root.printer ? root.printer.activePrintJob : null; + } + + HorizontalLine { + visible: root.printJob; + } + + Row { + height: childrenRect.height; + visible: root.printJob; + width: parent.width; + + PrintJobTitle { + job: root.printer ? root.printer.activePrintJob : null; + } + PrintJobContextMenu { + id: contextButton; + anchors { + right: parent.right; + rightMargin: UM.Theme.getSize("wide_margin").width; + } + printJob: root.printer ? root.printer.activePrintJob : null; + visible: printJob; + } + } + + + PrintJobPreview { + anchors.horizontalCenter: parent.horizontalCenter; + job: root.printer && root.printer.activePrintJob ? root.printer.activePrintJob : null; + visible: root.printJob; + } + } + + CameraButton { + id: showCameraButton; + anchors { + bottom: contentColumn.bottom; + bottomMargin: Math.round(1.5 * UM.Theme.getSize("default_margin").height); + left: contentColumn.left; + leftMargin: Math.round(0.5 * UM.Theme.getSize("default_margin").width); + } + iconSource: "../svg/camera-icon.svg"; + visible: root.printJob; + } +} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml new file mode 100644 index 0000000000..e86c959b8c --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml @@ -0,0 +1,108 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls 1.4 +import UM 1.3 as UM + +ProgressBar { + property var progress: { + if (!printer || printer.activePrintJob == null) { + return 0; + } + var result = printer.activePrintJob.timeElapsed / printer.activePrintJob.timeTotal; + if (result > 1.0) { + result = 1.0; + } + return result; + } + style: ProgressBarStyle { + property var remainingTime: { + if (!printer || printer.activePrintJob == null) { + return 0; + } + /* Sometimes total minus elapsed is less than 0. Use Math.max() to prevent remaining + time from ever being less than 0. Negative durations cause strange behavior such + as displaying "-1h -1m". */ + return Math.max(printer.activePrintJob.timeTotal - printer.activePrintJob.timeElapsed, 0); + } + property var progressText: { + if (printer === null ) { + return ""; + } + switch (printer.activePrintJob.state) { + case "wait_cleanup": + if (printer.activePrintJob.timeTotal > printer.activePrintJob.timeElapsed) { + return catalog.i18nc("@label:status", "Aborted"); + } + return catalog.i18nc("@label:status", "Finished"); + case "pre_print": + case "sent_to_printer": + return catalog.i18nc("@label:status", "Preparing"); + case "aborted": + return catalog.i18nc("@label:status", "Aborted"); + case "wait_user_action": + return catalog.i18nc("@label:status", "Aborted"); + case "pausing": + return catalog.i18nc("@label:status", "Pausing"); + case "paused": + return OutputDevice.formatDuration( remainingTime ); + case "resuming": + return catalog.i18nc("@label:status", "Resuming"); + case "queued": + return catalog.i18nc("@label:status", "Action required"); + default: + return OutputDevice.formatDuration( remainingTime ); + } + } + background: Rectangle { + color: UM.Theme.getColor("monitor_progress_background"); + implicitHeight: visible ? 24 : 0; + implicitWidth: 100; + } + progress: Rectangle { + id: progressItem; + color: { + if (! printer || !printer.activePrintJob) { + return "black"; + } + var state = printer.activePrintJob.state + var inactiveStates = [ + "pausing", + "paused", + "resuming", + "wait_cleanup" + ]; + if (inactiveStates.indexOf(state) > -1 && remainingTime > 0) { + return UM.Theme.getColor("monitor_progress_fill_inactive"); + } else { + return UM.Theme.getColor("monitor_progress_fill"); + } + } + + Label { + id: progressLabel; + anchors { + left: parent.left; + leftMargin: getTextOffset(); + } + text: progressText; + anchors.verticalCenter: parent.verticalCenter; + color: progressItem.width + progressLabel.width < control.width ? UM.Theme.getColor("text") : UM.Theme.getColor("monitor_progress_fill_text"); + width: contentWidth; + font: UM.Theme.getFont("default"); + } + + function getTextOffset() { + if (progressItem.width + progressLabel.width + 16 < control.width) { + return progressItem.width + UM.Theme.getSize("default_margin").width; + } else { + return progressItem.width - progressLabel.width - UM.Theme.getSize("default_margin").width; + } + } + } + } + value: progress; + width: parent.width; +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml index b785cd02b7..0a88b053a8 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml @@ -1,28 +1,32 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 import QtQuick.Controls 1.4 import UM 1.2 as UM -Item -{ - property alias color: background.color - property alias text: familyNameLabel.text - property var padding: 0 - implicitHeight: familyNameLabel.contentHeight + 2 * padding // Apply the padding to top and bottom. - implicitWidth: familyNameLabel.contentWidth + implicitHeight // The extra height is added to ensure the radius doesn't cut something off. - Rectangle - { - id: background - height: parent.height - width: parent.width - color: parent.color - anchors.right: parent.right - anchors.horizontalCenter: parent.horizontalCenter - radius: 0.5 * height +Item { + property alias text: familyNameLabel.text; + property var padding: 3 * screenScaleFactor; // TODO: Theme! + implicitHeight: familyNameLabel.contentHeight + 2 * padding; // Apply the padding to top and bottom. + implicitWidth: Math.max(48 * screenScaleFactor, familyNameLabel.contentWidth + implicitHeight); // The extra height is added to ensure the radius doesn't cut something off. + + Rectangle { + id: background; + anchors { + horizontalCenter: parent.horizontalCenter; + right: parent.right; + } + color: familyNameLabel.text.length < 1 ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_pill_background"); + height: parent.height; + radius: 0.5 * height; + width: parent.width; } - Label - { - id: familyNameLabel - anchors.centerIn: parent - text: "" + + Label { + id: familyNameLabel; + anchors.centerIn: parent; + color: UM.Theme.getColor("text"); + text: ""; } } \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml new file mode 100644 index 0000000000..92a8f1dcb3 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml @@ -0,0 +1,83 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.3 +import QtGraphicalEffects 1.0 +import QtQuick.Controls 1.4 as LegacyControls +import UM 1.3 as UM + +// Includes printer type pill and extuder configurations + +Item { + id: root; + property var printer: null; + property var printJob: null; + width: parent.width; + height: childrenRect.height; + + // Printer family pills + Row { + id: printerFamilyPills; + anchors { + left: parent.left; + right: parent.right; + } + height: childrenRect.height; + spacing: Math.round(0.5 * UM.Theme.getSize("default_margin").width); + width: parent.width; + + Repeater { + id: compatiblePills; + delegate: PrinterFamilyPill { + text: modelData; + } + model: printJob ? printJob.compatibleMachineFamilies : []; + visible: printJob; + + } + + PrinterFamilyPill { + text: printer ? printer.type : ""; + visible: !compatiblePills.visible && printer; + } + } + + // Extruder info + Row { + id: extrudersInfo; + anchors { + left: parent.left; + right: parent.right; + rightMargin: UM.Theme.getSize("default_margin").width; + top: printerFamilyPills.bottom; + topMargin: UM.Theme.getSize("default_margin").height; + } + height: childrenRect.height; + spacing: UM.Theme.getSize("default_margin").width; + width: parent.width; + + PrintCoreConfiguration { + width: Math.round(parent.width / 2) * screenScaleFactor; + printCoreConfiguration: getExtruderConfig(0); + } + + PrintCoreConfiguration { + width: Math.round(parent.width / 2) * screenScaleFactor; + printCoreConfiguration: getExtruderConfig(1); + } + } + + function getExtruderConfig( i ) { + if (root.printJob) { + // Use more-specific print job if possible + return root.printJob.configuration.extruderConfigurations[i]; + } + if (root.printer) { + return root.printer.printerConfiguration.extruderConfigurations[i]; + } + return null; + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterVideoStream.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterVideoStream.qml index d0213a4571..b9e2525dd5 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterVideoStream.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/PrinterVideoStream.qml @@ -1,84 +1,69 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 - import UM 1.3 as UM +Item { + property var camera: null; -Item -{ - property var camera: null - - Rectangle - { - anchors.fill:parent - color: UM.Theme.getColor("viewport_overlay") - opacity: 0.5 + Rectangle { + anchors.fill:parent; + color: UM.Theme.getColor("viewport_overlay"); + opacity: 0.5; } - MouseArea - { - anchors.fill: parent - onClicked: OutputDevice.setActiveCamera(null) - z: 0 + MouseArea { + anchors.fill: parent; + onClicked: OutputDevice.setActiveCamera(null); + z: 0; } - CameraButton - { - id: closeCameraButton - iconSource: UM.Theme.getIcon("cross1") - anchors - { - top: cameraImage.top - topMargin: UM.Theme.getSize("default_margin").height + CameraButton { + id: closeCameraButton; + anchors { right: cameraImage.right rightMargin: UM.Theme.getSize("default_margin").width + top: cameraImage.top + topMargin: UM.Theme.getSize("default_margin").height } - z: 999 + iconSource: UM.Theme.getIcon("cross1"); + z: 999; } - Image - { + Image { id: cameraImage - width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth) - height: Math.round((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width) - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - z: 1 - onVisibleChanged: - { - if(visible) - { - if(camera != null) - { - camera.start() + anchors.horizontalCenter: parent.horizontalCenter; + anchors.verticalCenter: parent.verticalCenter; + height: Math.round((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width); + onVisibleChanged: { + if (visible) { + if (camera != null) { + camera.start(); } - } else - { - if(camera != null) - { - camera.stop() + } else { + if (camera != null) { + camera.stop(); } } } - - source: - { - if(camera != null && camera.latestImage != null) - { + source: { + if (camera != null && camera.latestImage != null) { return camera.latestImage; } return ""; } - } - - MouseArea - { - anchors.fill: cameraImage - onClicked: - { - OutputDevice.setActiveCamera(null) - } + width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth); z: 1 } + + MouseArea { + anchors.fill: cameraImage; + onClicked: { + OutputDevice.setActiveCamera(null); + } + z: 1; + } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml index a19d1be60d..105143c851 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml @@ -1,125 +1,126 @@ -import UM 1.2 as UM -import Cura 1.0 as Cura +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.1 +import UM 1.2 as UM +import Cura 1.0 as Cura -Item -{ - id: base +Item { + id: base; + property string activeQualityDefinitionId: Cura.MachineManager.activeQualityDefinitionId; + property bool isUM3: activeQualityDefinitionId == "ultimaker3" || activeQualityDefinitionId.match("ultimaker_") != null; + property bool printerConnected: Cura.MachineManager.printerConnected; + property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands; + property bool authenticationRequested: printerConnected && (Cura.MachineManager.printerOutputDevices[0].authenticationState == 2 || Cura.MachineManager.printerOutputDevices[0].authenticationState == 5); // AuthState.AuthenticationRequested or AuthenticationReceived. - property string activeQualityDefinitionId: Cura.MachineManager.activeQualityDefinitionId - property bool isUM3: activeQualityDefinitionId == "ultimaker3" || activeQualityDefinitionId.match("ultimaker_") != null - property bool printerConnected: Cura.MachineManager.printerConnected - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - property bool authenticationRequested: printerConnected && (Cura.MachineManager.printerOutputDevices[0].authenticationState == 2 || Cura.MachineManager.printerOutputDevices[0].authenticationState == 5) // AuthState.AuthenticationRequested or AuthenticationReceived. + UM.I18nCatalog { + id: catalog; + name: "cura"; + } - Row - { - objectName: "networkPrinterConnectButton" - visible: isUM3 - spacing: UM.Theme.getSize("default_margin").width + Row { + objectName: "networkPrinterConnectButton"; + spacing: UM.Theme.getSize("default_margin").width; + visible: isUM3; - Button - { - height: UM.Theme.getSize("save_button_save_to_button").height - tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer") - text: catalog.i18nc("@action:button", "Request Access") - style: UM.Theme.styles.sidebar_action_button - onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication() - visible: printerConnected && !printerAcceptsCommands && !authenticationRequested + Button { + height: UM.Theme.getSize("save_button_save_to_button").height; + onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication(); + style: UM.Theme.styles.sidebar_action_button; + text: catalog.i18nc("@action:button", "Request Access"); + tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer"); + visible: printerConnected && !printerAcceptsCommands && !authenticationRequested; } - Button - { - height: UM.Theme.getSize("save_button_save_to_button").height - tooltip: catalog.i18nc("@info:tooltip", "Connect to a printer") - text: catalog.i18nc("@action:button", "Connect") - style: UM.Theme.styles.sidebar_action_button - onClicked: connectActionDialog.show() - visible: !printerConnected + Button { + height: UM.Theme.getSize("save_button_save_to_button").height; + onClicked: connectActionDialog.show(); + style: UM.Theme.styles.sidebar_action_button; + text: catalog.i18nc("@action:button", "Connect"); + tooltip: catalog.i18nc("@info:tooltip", "Connect to a printer"); + visible: !printerConnected; } } - UM.Dialog - { - id: connectActionDialog - Loader - { - anchors.fill: parent - source: "DiscoverUM3Action.qml" + UM.Dialog { + id: connectActionDialog; + rightButtons: Button { + iconName: "dialog-close"; + onClicked: connectActionDialog.reject(); + text: catalog.i18nc("@action:button", "Close"); } - rightButtons: Button - { - text: catalog.i18nc("@action:button", "Close") - iconName: "dialog-close" - onClicked: connectActionDialog.reject() + + Loader { + anchors.fill: parent; + source: "DiscoverUM3Action.qml"; } } + Column { + anchors.fill: parent; + objectName: "networkPrinterConnectionInfo"; + spacing: UM.Theme.getSize("default_margin").width; + visible: isUM3; - Column - { - objectName: "networkPrinterConnectionInfo" - visible: isUM3 - spacing: UM.Theme.getSize("default_margin").width - anchors.fill: parent - - Button - { - tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer") - text: catalog.i18nc("@action:button", "Request Access") - onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication() - visible: printerConnected && !printerAcceptsCommands && !authenticationRequested + Button { + onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication(); + text: catalog.i18nc("@action:button", "Request Access"); + tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer"); + visible: printerConnected && !printerAcceptsCommands && !authenticationRequested; } - Row - { - visible: printerConnected - spacing: UM.Theme.getSize("default_margin").width + Row { + anchors { + left: parent.left; + right: parent.right; + } + height: childrenRect.height; + spacing: UM.Theme.getSize("default_margin").width; + visible: printerConnected; - anchors.left: parent.left - anchors.right: parent.right - height: childrenRect.height + Column { + Repeater { + model: Cura.ExtrudersModel { + simpleNames: true; + } - Column - { - Repeater - { - model: Cura.ExtrudersModel { simpleNames: true } - Label { text: model.name } + Label { + text: model.name; + } } } - Column - { - Repeater - { - id: nozzleColumn - model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].hotendIds : null - Label { text: nozzleColumn.model[index] } + + Column { + Repeater { + id: nozzleColumn; + model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].hotendIds : null; + + Label { + text: nozzleColumn.model[index]; + } } } - Column - { - Repeater - { - id: materialColumn - model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].materialNames : null - Label { text: materialColumn.model[index] } + + Column { + Repeater { + id: materialColumn; + model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].materialNames : null; + + Label { + text: materialColumn.model[index]; + } } } } - Button - { - tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura") - text: catalog.i18nc("@action:button", "Activate Configuration") - visible: false // printerConnected && !isClusterPrinter() - onClicked: manager.loadConfigurationFromPrinter() + Button { + onClicked: manager.loadConfigurationFromPrinter(); + text: catalog.i18nc("@action:button", "Activate Configuration"); + tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura"); + visible: false; // printerConnected && !isClusterPrinter() } } - - UM.I18nCatalog{id: catalog; name:"cura"} } diff --git a/plugins/UM3NetworkPrinting/resources/svg/ultibot.svg b/plugins/UM3NetworkPrinting/resources/svg/ultibot.svg new file mode 100644 index 0000000000..be6ca64723 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/svg/ultibot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/svg/warning-icon.svg b/plugins/UM3NetworkPrinting/resources/svg/warning-icon.svg index 1e5359a5eb..064d0783e0 100644 --- a/plugins/UM3NetworkPrinting/resources/svg/warning-icon.svg +++ b/plugins/UM3NetworkPrinting/resources/svg/warning-icon.svg @@ -1 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py index 409ca7a84a..4c7b93c145 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py @@ -21,12 +21,13 @@ from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel -from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.PrinterOutput.NetworkCamera import NetworkCamera from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController from .SendMaterialJob import SendMaterialJob +from .ConfigurationChangeModel import ConfigurationChangeModel +from .UM3PrintJobOutputModel import UM3PrintJobOutputModel from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply from PyQt5.QtGui import QDesktopServices, QImage @@ -47,6 +48,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): printJobsChanged = pyqtSignal() activePrinterChanged = pyqtSignal() activeCameraChanged = pyqtSignal() + receivedPrintJobsChanged = pyqtSignal() # This is a bit of a hack, as the notify can only use signals that are defined by the class that they are in. # Inheritance doesn't seem to work. Tying them together does work, but i'm open for better suggestions. @@ -60,7 +62,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._dummy_lambdas = ("", {}, io.BytesIO()) #type: Tuple[str, Dict, Union[io.StringIO, io.BytesIO]] - self._print_jobs = [] # type: List[PrintJobOutputModel] + self._print_jobs = [] # type: List[UM3PrintJobOutputModel] + self._received_print_jobs = False # type: bool self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterMonitorItem.qml") self._control_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterControlItem.qml") @@ -90,7 +93,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._printer_uuid_to_unique_name_mapping = {} # type: Dict[str, str] - self._finished_jobs = [] # type: List[PrintJobOutputModel] + self._finished_jobs = [] # type: List[UM3PrintJobOutputModel] self._cluster_size = int(properties.get(b"cluster_size", 0)) # type: int @@ -349,15 +352,19 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers")) @pyqtProperty("QVariantList", notify = printJobsChanged) - def printJobs(self)-> List[PrintJobOutputModel]: + def printJobs(self)-> List[UM3PrintJobOutputModel]: return self._print_jobs + @pyqtProperty(bool, notify = receivedPrintJobsChanged) + def receivedPrintJobs(self) -> bool: + return self._received_print_jobs + @pyqtProperty("QVariantList", notify = printJobsChanged) - def queuedPrintJobs(self) -> List[PrintJobOutputModel]: + def queuedPrintJobs(self) -> List[UM3PrintJobOutputModel]: return [print_job for print_job in self._print_jobs if print_job.state == "queued" or print_job.state == "error"] @pyqtProperty("QVariantList", notify = printJobsChanged) - def activePrintJobs(self) -> List[PrintJobOutputModel]: + def activePrintJobs(self) -> List[UM3PrintJobOutputModel]: return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"] @pyqtProperty("QVariantList", notify = clusterPrintersChanged) @@ -406,6 +413,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # is a modification of the cluster queue and not of the actual job. self.delete("print_jobs/{uuid}".format(uuid = print_job_uuid), on_finished=None) + @pyqtSlot(str) + def forceSendJob(self, print_job_uuid: str) -> None: + data = "{\"force\": true}" + self.put("print_jobs/{uuid}".format(uuid=print_job_uuid), data, on_finished=None) + def _printJobStateChanged(self) -> None: username = self._getUserName() @@ -455,6 +467,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self.get("print_jobs/{uuid}/preview_image".format(uuid=print_job.key), on_finished=self._onGetPreviewImageFinished) def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None: + self._received_print_jobs = True + self.receivedPrintJobsChanged.emit() + if not checkValidGetReply(reply): return @@ -537,8 +552,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._printers.append(printer) return printer - def _createPrintJobModel(self, data: Dict[str, Any]) -> PrintJobOutputModel: - print_job = PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self), + def _createPrintJobModel(self, data: Dict[str, Any]) -> UM3PrintJobOutputModel: + print_job = UM3PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self), key=data["uuid"], name= data["name"]) configuration = ConfigurationModel() @@ -558,7 +573,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): print_job.stateChanged.connect(self._printJobStateChanged) return print_job - def _updatePrintJob(self, print_job: PrintJobOutputModel, data: Dict[str, Any]) -> None: + def _updatePrintJob(self, print_job: UM3PrintJobOutputModel, data: Dict[str, Any]) -> None: print_job.updateTimeTotal(data["time_total"]) print_job.updateTimeElapsed(data["time_elapsed"]) impediments_to_printing = data.get("impediments_to_printing", []) @@ -574,6 +589,16 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): if not status_set_by_impediment: print_job.updateState(data["status"]) + print_job.updateConfigurationChanges(self._createConfigurationChanges(data["configuration_changes_required"])) + + def _createConfigurationChanges(self, data: List[Dict[str, Any]]) -> List[ConfigurationChangeModel]: + result = [] + for change in data: + result.append(ConfigurationChangeModel(type_of_change=change["type_of_change"], + index=change["index"], + target_name=change["target_name"], + origin_name=change["origin_name"])) + return result def _createMaterialOutputModel(self, material_data) -> MaterialOutputModel: containers = ContainerRegistry.getInstance().findInstanceContainers(type="material", GUID=material_data["guid"]) @@ -631,7 +656,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): material = self._createMaterialOutputModel(material_data) extruder.updateActiveMaterial(material) - def _removeJob(self, job: PrintJobOutputModel) -> bool: + def _removeJob(self, job: UM3PrintJobOutputModel) -> bool: if job not in self._print_jobs: return False @@ -675,7 +700,7 @@ def checkValidGetReply(reply: QNetworkReply) -> bool: return True -def findByKey(lst: List[Union[PrintJobOutputModel, PrinterOutputModel]], key: str) -> Optional[PrintJobOutputModel]: +def findByKey(lst: List[Union[UM3PrintJobOutputModel, PrinterOutputModel]], key: str) -> Optional[UM3PrintJobOutputModel]: for item in lst: if item.key == key: return item diff --git a/plugins/UM3NetworkPrinting/src/ConfigurationChangeModel.py b/plugins/UM3NetworkPrinting/src/ConfigurationChangeModel.py new file mode 100644 index 0000000000..ef8a212b76 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/ConfigurationChangeModel.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot + +class ConfigurationChangeModel(QObject): + def __init__(self, type_of_change: str, index: int, target_name: str, origin_name: str) -> None: + super().__init__() + self._type_of_change = type_of_change + # enum = ["material", "print_core_change"] + self._index = index + self._target_name = target_name + self._origin_name = origin_name + + @pyqtProperty(int, constant = True) + def index(self) -> int: + return self._index + + @pyqtProperty(str, constant = True) + def typeOfChange(self) -> str: + return self._type_of_change + + @pyqtProperty(str, constant = True) + def targetName(self) -> str: + return self._target_name + + @pyqtProperty(str, constant = True) + def originName(self) -> str: + return self._origin_name diff --git a/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py b/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py new file mode 100644 index 0000000000..2ac3e6ba4f --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py @@ -0,0 +1,29 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot +from typing import Optional, TYPE_CHECKING, List +from PyQt5.QtCore import QUrl +from PyQt5.QtGui import QImage + +from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel + +from .ConfigurationChangeModel import ConfigurationChangeModel + + +class UM3PrintJobOutputModel(PrintJobOutputModel): + configurationChangesChanged = pyqtSignal() + + def __init__(self, output_controller: "PrinterOutputController", key: str = "", name: str = "", parent=None) -> None: + super().__init__(output_controller, key, name, parent) + self._configuration_changes = [] # type: List[ConfigurationChangeModel] + + @pyqtProperty("QVariantList", notify=configurationChangesChanged) + def configurationChanges(self) -> List[ConfigurationChangeModel]: + return self._configuration_changes + + def updateConfigurationChanges(self, changes: List[ConfigurationChangeModel]) -> None: + if len(self._configuration_changes) == 0 and len(changes) == 0: + return + self._configuration_changes = changes + self.configurationChangesChanged.emit() diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 26e6c2ac8b..39546b6370 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -221,6 +221,26 @@ "quality_slider_available": [255, 255, 255, 255], "quality_slider_handle": [255, 255, 255, 255], "quality_slider_handle_hover": [127, 127, 127, 255], - "quality_slider_text": [255, 255, 255, 255] + "quality_slider_text": [255, 255, 255, 255], + + "monitor_card_background_inactive": [43, 48, 52, 255], + "monitor_card_background": [43, 48, 52, 255], + "monitor_context_menu_background": [80, 84, 87, 255], + "monitor_context_menu_dots": [0, 167, 233, 255], + "monitor_context_menu_highlight": [0, 167, 233, 255], + "monitor_image_overlay": [255, 255, 255, 255], + "monitor_lining_heavy": [255, 255, 255, 255], + "monitor_lining_light": [102, 102, 102, 255], + "monitor_pill_background": [102, 102, 102, 255], + "monitor_placeholder_image": [102, 102, 102, 255], + "monitor_printer_icon": [255, 255, 255, 255], + "monitor_progress_background_text": [102, 102, 102, 255], + "monitor_progress_background": [80, 84, 87, 255], + "monitor_progress_fill_inactive": [216, 216, 216, 255], + "monitor_progress_fill_text": [0, 0, 0, 255], + "monitor_progress_fill": [216, 216, 216, 255], + "monotir_printer_icon_inactive": [154, 154, 154, 255], + "monitor_skeleton_fill": [31, 36, 39, 255], + "monitor_skeleton_fill_dark": [31, 36, 39, 255] } } diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 43d892c34c..25c9a678c1 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -323,10 +323,27 @@ "favorites_header_text_hover": [31, 36, 39, 255], "favorites_row_selected": [196, 239, 255, 255], - "monitor_text_inactive": [154, 154, 154, 255], - "monitor_background_inactive": [240, 240, 240, 255], - "monitor_background_active": [255, 255, 255, 255], - "monitor_lining_inactive": [230, 230, 230, 255] + "monitor_card_background_inactive": [240, 240, 240, 255], + "monitor_card_background": [255, 255, 255, 255], + "monitor_context_menu_background": [255, 255, 255, 255], + "monitor_context_menu_dots": [154, 154, 154, 255], + "monitor_context_menu_highlight": [245, 245, 245, 255], + "monitor_image_overlay": [0, 0, 0, 255], + "monitor_lining_heavy": [0, 0, 0, 255], + "monitor_lining_light": [230, 230, 230, 255], + "monitor_pill_background": [245, 245, 245, 255], + "monitor_placeholder_image": [230, 230, 230, 255], + "monitor_printer_icon_inactive": [154, 154, 154, 255], + "monitor_printer_icon": [12, 169, 227, 255], + "monitor_progress_background_text": [0,0,0,255], + "monitor_progress_background": [245, 245, 245, 255], + "monitor_progress_fill_inactive": [154, 154, 154, 255], + "monitor_progress_fill_text": [255,255,255,255], + "monitor_progress_fill": [12, 169, 227, 255], + "monitor_shadow": [0, 0, 0, 63], + "monitor_skeleton_fill": [245, 245, 245, 255], + "monitor_skeleton_fill_dark": [216, 216, 216, 255], + "monitor_text_inactive": [154, 154, 154, 255] }, "sizes": { @@ -476,6 +493,12 @@ "toolbox_action_button": [8.0, 2.5], "toolbox_loader": [2.0, 2.0], - "drop_shadow_radius": [1.0, 1.0] + "monitor_config_override_box": [1.0, 14.0], + "monitor_extruder_circle": [2.75, 2.75], + "monitor_text_line": [1.16, 1.16], + "monitor_thick_lining": [0.16, 0.16], + "monitor_corner_radius": [0.3, 0.3], + "monitor_shadow_radius": [0.4, 0.4], + "monitor_shadow_offset": [0.15, 0.15] } }