diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index 25b168e6fd..256c9dffe9 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -118,17 +118,40 @@ class PrintJobOutputModel(QObject): self.nameChanged.emit() @pyqtProperty(int, notify = timeTotalChanged) - def timeTotal(self): + def timeTotal(self) -> int: return self._time_total @pyqtProperty(int, notify = timeElapsedChanged) - def timeElapsed(self): + def timeElapsed(self) -> int: return self._time_elapsed + @pyqtProperty(int, notify = timeElapsedChanged) + def timeRemaining(self) -> int: + # Never get a negative time remaining + return max(self.timeTotal - self.timeElapsed, 0) + + @pyqtProperty(float, notify = timeElapsedChanged) + def progress(self) -> float: + result = self.timeElapsed / self.timeTotal + # Never get a progress past 1.0 + return min(result, 1.0) + @pyqtProperty(str, notify=stateChanged) - def state(self): + def state(self) -> str: return self._state + @pyqtProperty(bool, notify=stateChanged) + def isActive(self) -> bool: + inactiveStates = [ + "pausing", + "paused", + "resuming", + "wait_cleanup" + ] + if self.state in inactiveStates and self.timeRemaining > 0: + return False + return True + def updateTimeTotal(self, new_time_total): if self._time_total != new_time_total: self._time_total = new_time_total diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 15e2c67c33..53390ca88d 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -527,12 +527,6 @@ class MachineManager(QObject): return self._global_container_stack.getMetaDataEntry("um_network_key", "") return "" - @pyqtProperty(str, notify=printerConnectedStatusChanged) - def activeMachineCloudKey(self) -> str: - if self._global_container_stack: - return self._global_container_stack.getMetaDataEntry("um_cloud_cluster_id", "") - return "" - @pyqtProperty(str, notify = printerConnectedStatusChanged) def activeMachineNetworkGroupName(self) -> str: if self._global_container_stack: diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml index 1a69d2dc12..ec26bbe568 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml @@ -21,7 +21,14 @@ Item { id: previewImage anchors.fill: parent - opacity: printJob && printJob.state == "error" ? 0.5 : 1.0 + opacity: + { + if (printJob && (printJob.state == "error" || !printJob.isActive)) + { + return 0.5 + } + return 1.0 + } source: printJob ? printJob.previewImageUrl : "" visible: printJob } @@ -47,11 +54,28 @@ Item UM.RecolorImage { - id: statusImage + id: overlayIcon anchors.centerIn: printJobPreview color: UM.Theme.getColor("monitor_image_overlay") height: 0.5 * printJobPreview.height - source: printJob && printJob.state == "error" ? "../svg/aborted-icon.svg" : "" + source: + { + switch(printJob.state) + { + case "error": + return "../svg/aborted-icon.svg" + case "wait_cleanup": + return printJob.timeTotal > printJob.timeElapsed ? "../svg/aborted-icon.svg" : "" + case "pausing": + return "../svg/paused-icon.svg" + case "paused": + return "../svg/paused-icon.svg" + case "resuming": + return "../svg/paused-icon.svg" + default: + return "" + } + } sourceSize { height: height diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml index f70e1175a1..88418516ed 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml @@ -15,63 +15,10 @@ import UM 1.3 as UM Item { id: base + + // The print job which all other information is dervied from property var printJob: null - property var progress: - { - if (!printJob) - { - return 0 - } - var result = printJob.timeElapsed / printJob.timeTotal - if (result > 1.0) - { - result = 1.0 - } - return result - } - property var remainingTime: - { - if (!printJob) { - 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 (!printJob) - { - return ""; - } - switch (printJob.state) - { - case "wait_cleanup": - if (printJob.timeTotal > printJob.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 ) - } - } + width: childrenRect.width height: 18 * screenScaleFactor // TODO: Theme! @@ -82,12 +29,12 @@ Item { verticalCenter: parent.verticalCenter } - value: progress; + value: printJob ? printJob.progress : 0 style: ProgressBarStyle { background: Rectangle { - color: "#e4e4f2" // TODO: Theme! + color: printJob && printJob.isActive ? "#e4e4f2" : "#f3f3f9" // TODO: Theme! implicitHeight: visible ? 8 * screenScaleFactor : 0 // TODO: Theme! implicitWidth: 180 * screenScaleFactor // TODO: Theme! radius: 4 * screenScaleFactor // TODO: Theme! @@ -95,41 +42,74 @@ Item progress: Rectangle { id: progressItem; - color: - { - if (printJob) - { - var state = printJob.state - var inactiveStates = [ - "pausing", - "paused", - "resuming", - "wait_cleanup" - ] - if (inactiveStates.indexOf(state) > -1 && remainingTime > 0) - { - return UM.Theme.getColor("monitor_progress_fill_inactive") - } - } - return "#0a0850" // TODO: Theme! - } + color: printJob && printJob.isActive ? "#0a0850" : "#9392b2" // TODO: Theme! radius: 4 * screenScaleFactor // TODO: Theme! } } } Label { - id: progressLabel + id: percentLabel anchors { left: progressBar.right leftMargin: 18 * screenScaleFactor // TODO: Theme! } - text: progressText - color: "#374355" // TODO: Theme! + text: Math.round(printJob.progress * 100) + "%" + color: printJob && printJob.isActive ? "#374355" : "#babac1" // TODO: Theme! width: contentWidth font: UM.Theme.getFont("medium") // 14pt, regular + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + Label + { + id: statusLabel + anchors + { + left: percentLabel.right + leftMargin: 18 * screenScaleFactor // TODO: Theme! + } + color: "#374355" // TODO: Theme! + font: UM.Theme.getFont("medium") // 14pt, regular + text: + { + if (!printJob) + { + return "" + } + switch (printJob.state) + { + case "wait_cleanup": + if (printJob.timeTotal > printJob.timeElapsed) + { + return catalog.i18nc("@label:status", "Aborted") + } + return catalog.i18nc("@label:status", "Finished") + case "sent_to_printer": + return catalog.i18nc("@label:status", "Preparing...") + case "pre_print": + return catalog.i18nc("@label:status", "Preparing...") + case "aborting": // NOTE: Doesn't exist but maybe should someday + return catalog.i18nc("@label:status", "Aborting...") + case "aborted": // NOTE: Unused, see above + return catalog.i18nc("@label:status", "Aborted") + case "pausing": + return catalog.i18nc("@label:status", "Pausing...") + case "paused": + return catalog.i18nc("@label:status", "Paused") + case "resuming": + return catalog.i18nc("@label:status", "Resuming...") + case "queued": + return catalog.i18nc("@label:status", "Action required") + default: + return catalog.i18nc("@label:status", "Finishes %1 at %2".arg(OutputDevice.getDateCompleted( printJob.timeRemaining )).arg(OutputDevice.getTimeCompleted( printJob.timeRemaining ))) + } + } + width: contentWidth + // FIXED-LINE-HEIGHT: height: 18 * screenScaleFactor // TODO: Theme! verticalAlignment: Text.AlignVCenter diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml index 975fe12244..8659037cb8 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml @@ -169,6 +169,30 @@ Item height: childrenRect.height spacing: 18 * screenScaleFactor // TODO: Theme! + Label + { + id: printerStatus + anchors + { + verticalCenter: parent.verticalCenter + } + color: "#414054" // TODO: Theme! + font: UM.Theme.getFont("large") // 16pt, bold + text: { + if (printer && printer.state == "disabled"){ + return catalog.i18nc("@label:status", "Unavailable") + } + if (printer && printer.state == "unreachable"){ + return catalog.i18nc("@label:status", "Unavailable") + } + if (printer && !printer.activePrintJob) + { + return catalog.i18nc("@label:status", "Idle") + } + return "" + } + } + Item { anchors @@ -183,6 +207,7 @@ Item printJob: base.printer.activePrintJob size: parent.height } + visible: printer.activePrintJob } Item @@ -193,14 +218,15 @@ Item } width: 216 * screenScaleFactor // TODO: Theme! height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme! + visible: printer.activePrintJob Label { id: printerJobNameLabel - text: base.printer.activePrintJob ? base.printer.activePrintJob.name : "Untitled" // TODO: I18N - color: "#414054" // TODO: Theme! + color: printer.activePrintJob && printer.activePrintJob.isActive ? "#414054" : "#babac1" // TODO: Theme! elide: Text.ElideRight font: UM.Theme.getFont("large") // 16pt, bold + text: base.printer.activePrintJob ? base.printer.activePrintJob.name : "Untitled" // TODO: I18N width: parent.width // FIXED-LINE-HEIGHT: @@ -217,10 +243,10 @@ Item topMargin: 6 * screenScaleFactor // TODO: Theme! left: printerJobNameLabel.left } - text: printer.activePrintJob ? printer.activePrintJob.owner : "Anonymous" // TODO: I18N - color: "#53657d" // TODO: Theme! + color: printer.activePrintJob && printer.activePrintJob.isActive ? "#53657d" : "#babac1" // TODO: Theme! elide: Text.ElideRight font: UM.Theme.getFont("very_small") // 12pt, regular + text: printer.activePrintJob ? printer.activePrintJob.owner : "Anonymous" // TODO: I18N width: parent.width // FIXED-LINE-HEIGHT: @@ -236,6 +262,7 @@ Item verticalCenter: parent.verticalCenter } printJob: printer.activePrintJob + visible: printer.activePrintJob } } } diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index 772d40edd4..0fbeeb82b6 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -63,8 +63,6 @@ class CloudOutputDeviceManager: found_clusters = {c.cluster_id: c for c in clusters} Logger.log("i", "Parsed remote clusters to %s", found_clusters) - if not found_clusters: - return known_cluster_ids = set(self._remote_clusters.keys()) found_cluster_ids = set(found_clusters.keys()) @@ -85,8 +83,7 @@ class CloudOutputDeviceManager: device = CloudOutputDevice(self._api, cluster.cluster_id) self._output_device_manager.addOutputDevice(device) self._remote_clusters[cluster.cluster_id] = device - device.connect() # TODO: remove this - self._connectToActiveMachine(cluster.cluster_id, cluster.host_name) + self._connectToActiveMachine(cluster.cluster_id) ## Remove a CloudOutputDevice # \param cluster: The cluster that was removed @@ -95,16 +92,16 @@ class CloudOutputDeviceManager: if cluster.cluster_id in self._remote_clusters: del self._remote_clusters[cluster.cluster_id] - ## Callback for when the active machine was changed by the user. - def _connectToActiveMachine(self, cluster_id: Optional[str] = None, host_name: Optional[str] = None) -> None: + ## Callback for when the active machine was changed by the user or a new remote cluster was found. + def _connectToActiveMachine(self, cluster_id: Optional[str] = None) -> None: active_machine = CuraApplication.getInstance().getGlobalContainerStack() if not active_machine: return # TODO: Remove this once correct pairing has been added (see below). + # TODO: This just adds any available cluster to the active device for testing. if cluster_id: active_machine.setMetaDataEntry("um_cloud_cluster_id", cluster_id) - active_machine.setMetaDataEntry("connect_group_name", host_name) # Check if the stored cluster_id for the active machine is in our list of remote clusters. stored_cluster_id = active_machine.getMetaDataEntry("um_cloud_cluster_id") diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py index 7015f71be4..a1530c128d 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py @@ -385,8 +385,24 @@ class ClusterUM3OutputDevice(BaseCuraConnectDevice): @pyqtSlot(int, result = str) def getDateCompleted(self, time_remaining: int) -> str: current_time = time() - datetime_completed = datetime.fromtimestamp(current_time + time_remaining) - return (datetime_completed.strftime("%a %b ") + "{day}".format(day=datetime_completed.day)).upper() + completed = datetime.fromtimestamp(current_time + time_remaining) + today = datetime.fromtimestamp(current_time) + + # If finishing date is more than 7 days out, using "Mon Dec 3 at HH:MM" format + if completed.toordinal() > today.toordinal() + 7: + return completed.strftime("%a %b ") + "{day}".format(day=completed.day) + + # If finishing date is within the next week, use "Monday at HH:MM" format + elif completed.toordinal() > today.toordinal() + 1: + return completed.strftime("%a") + + # If finishing tomorrow, use "tomorrow at HH:MM" format + elif completed.toordinal() > today.toordinal(): + return "tomorrow" + + # If finishing today, use "today at HH:MM" format + else: + return "today" @pyqtSlot(str) def sendJobToTop(self, print_job_uuid: str) -> None: diff --git a/plugins/USBPrinting/AutoDetectBaudJob.py b/plugins/USBPrinting/AutoDetectBaudJob.py index 6f1af6727a..78de864e57 100644 --- a/plugins/USBPrinting/AutoDetectBaudJob.py +++ b/plugins/USBPrinting/AutoDetectBaudJob.py @@ -3,8 +3,8 @@ from UM.Job import Job from UM.Logger import Logger -from plugins.USBPrinting.avr_isp import ispBase +from .avr_isp import ispBase from .avr_isp.stk500v2 import Stk500v2 from time import time, sleep diff --git a/plugins/USBPrinting/plugin.json b/plugins/USBPrinting/plugin.json index 3484c8a48a..5d3cba8415 100644 --- a/plugins/USBPrinting/plugin.json +++ b/plugins/USBPrinting/plugin.json @@ -1,7 +1,7 @@ { "name": "USB printing", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "api": 5, "description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.", "i18n-catalog": "cura" diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index 678ea0a697..384b7d0412 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -532,7 +532,7 @@ "package_type": "plugin", "display_name": "USB Printing", "description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.", - "package_version": "1.0.0", + "package_version": "1.0.1", "sdk_version": 5, "website": "https://ultimaker.com", "author": { diff --git a/resources/qml/ActionPanel/SliceProcessWidget.qml b/resources/qml/ActionPanel/SliceProcessWidget.qml index 14e149dddb..03d91db530 100644 --- a/resources/qml/ActionPanel/SliceProcessWidget.qml +++ b/resources/qml/ActionPanel/SliceProcessWidget.qml @@ -137,6 +137,10 @@ Column { var autoSlice = UM.Preferences.getValue("general/auto_slice") prepareButtons.autoSlice = autoSlice + if(autoSlice) + { + CuraApplication.backend.forceSlice() + } } } diff --git a/resources/qml/Menus/CloudPrinterMenu.qml b/resources/qml/Menus/CloudPrinterMenu.qml deleted file mode 100644 index bd03890642..0000000000 --- a/resources/qml/Menus/CloudPrinterMenu.qml +++ /dev/null @@ -1,26 +0,0 @@ -// 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 -import Cura 1.0 as Cura - -Instantiator { - - model: UM.ContainerStacksModel { - filter: {"type": "machine", "um_cloud_cluster_id": "*"} - } - - MenuItem { - // iconSource: UM.Theme.getIcon("printer_single") TODO: use cloud icon here - text: model.metadata["connect_group_name"] - checkable: true - checked: true // cloud printers are only listed if they are actually online - exclusiveGroup: group; - onTriggered: Cura.MachineManager.setActiveMachine(model.id); - } - - onObjectAdded: menu.insertItem(index, object) - onObjectRemoved: menu.removeItem(object) -} diff --git a/resources/qml/Menus/PrinterMenu.qml b/resources/qml/Menus/PrinterMenu.qml index a924b0e589..741d927c13 100644 --- a/resources/qml/Menus/PrinterMenu.qml +++ b/resources/qml/Menus/PrinterMenu.qml @@ -37,23 +37,6 @@ Menu visible: networkPrinterMenu.count > 0 } - MenuItem - { - text: catalog.i18nc("@label:category menu label", "Cloud enabled printers") - enabled: false - visible: cloudPrinterMenu.count > 0 - } - - CloudPrinterMenu - { - id: cloudPrinterMenu - } - - MenuSeparator - { - visible: cloudPrinterMenu.count > 0 - } - MenuItem { text: catalog.i18nc("@label:category menu label", "Local printers") diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 1b964cad0c..2edbeee960 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -25,11 +25,7 @@ UM.PreferencesPage function reset() { - UM.Preferences.resetPreference("general/visible_settings") - - // After calling this function update Setting visibility preset combobox. - // Reset should set default setting preset ("Basic") - visibilityPreset.currentIndex = 1 + settingVisibilityPresetsModel.setActivePreset("basic") } resetEnabled: true; diff --git a/resources/qml/PrinterSelector/MachineSelector.qml b/resources/qml/PrinterSelector/MachineSelector.qml index 780b5baa74..15cd773c90 100644 --- a/resources/qml/PrinterSelector/MachineSelector.qml +++ b/resources/qml/PrinterSelector/MachineSelector.qml @@ -12,7 +12,6 @@ Cura.ExpandableComponent id: machineSelector property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" - property bool isCloudConnected: Cura.MachineManager.activeMachineCloudKey != "" property bool isPrinterConnected: Cura.MachineManager.printerConnected property var outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null @@ -56,7 +55,7 @@ Cura.ExpandableComponent leftMargin: UM.Theme.getSize("thick_margin").width } - source: isCloudConnected ? UM.Theme.getIcon("printer_cloud_connected") : UM.Theme.getIcon("printer_connected") + source: UM.Theme.getIcon("printer_connected") width: UM.Theme.getSize("printer_status_icon").width height: UM.Theme.getSize("printer_status_icon").height @@ -64,7 +63,7 @@ Cura.ExpandableComponent sourceSize.height: height color: UM.Theme.getColor("primary") - visible: isNetworkPrinter && (isPrinterConnected || isCloudConnected) + visible: isNetworkPrinter && isPrinterConnected // Make a themable circle in the background so we can change it in other themes Rectangle diff --git a/resources/qml/PrinterSelector/MachineSelectorList.qml b/resources/qml/PrinterSelector/MachineSelectorList.qml index e605f23f73..445940ab50 100644 --- a/resources/qml/PrinterSelector/MachineSelectorList.qml +++ b/resources/qml/PrinterSelector/MachineSelectorList.qml @@ -32,7 +32,8 @@ Column id: networkedPrintersModel filter: { - "type": "machine", "um_network_key": "*", "hidden": "False" + "type": "machine", + "um_network_key": "*" } } @@ -50,46 +51,6 @@ Column } } - Label - { - text: catalog.i18nc("@label", "Cloud connected printers") - visible: cloudPrintersModel.items.length > 0 - leftPadding: UM.Theme.getSize("default_margin").width - height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0 - renderType: Text.NativeRendering - font: UM.Theme.getFont("medium") - color: UM.Theme.getColor("text_medium") - verticalAlignment: Text.AlignVCenter - } - - Repeater - { - id: cloudPrinters - - model: UM.ContainerStacksModel - { - id: cloudPrintersModel - filter: - { - "type": "machine", - "um_cloud_cluster_id": "*" - } - } - - delegate: MachineSelectorButton - { - text: model.metadata["connect_group_name"] - checked: true // cloud devices are always online if they are available - outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null - - Connections - { - target: Cura.MachineManager - onActiveMachineNetworkGroupNameChanged: checked = Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] - } - } - } - Label { text: catalog.i18nc("@label", "Preset printers") @@ -112,8 +73,7 @@ Column filter: { "type": "machine", - "um_network_key": null, - "um_cloud_cluster_id": null + "um_network_key": null } } diff --git a/resources/themes/cura-light/icons/printer_cloud_connected.svg b/resources/themes/cura-light/icons/printer_cloud_connected.svg index ef6f0f2910..59ca67e93e 100644 --- a/resources/themes/cura-light/icons/printer_cloud_connected.svg +++ b/resources/themes/cura-light/icons/printer_cloud_connected.svg @@ -1,5 +1,5 @@ - + noun_Cloud_377836 Created with Sketch.