diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 9427e15552..a5ae286b1e 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1,6 +1,5 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. - from PyQt5.QtNetwork import QLocalServer from PyQt5.QtNetwork import QLocalSocket @@ -32,6 +31,7 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.SetTransformOperation import SetTransformOperation + from cura.Arrange import Arrange from cura.ShapeArray import ShapeArray from cura.ConvexHullDecorator import ConvexHullDecorator @@ -128,6 +128,7 @@ class CuraApplication(QtApplication): stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished def __init__(self): + # this list of dir names will be used by UM to detect an old cura directory for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]: Resources.addExpectedDirNameInData(dir_name) @@ -156,7 +157,6 @@ class CuraApplication(QtApplication): SettingDefinition.addSettingType("extruder", None, str, Validator) SettingDefinition.addSettingType("optional_extruder", None, str, None) - SettingDefinition.addSettingType("[int]", None, str, None) SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues) @@ -181,7 +181,8 @@ class CuraApplication(QtApplication): ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.DefinitionChangesContainer) ## Initialise the version upgrade manager with Cura's storage paths. - import UM.VersionUpgradeManager #Needs to be here to prevent circular dependencies. + # Needs to be here to prevent circular dependencies. + import UM.VersionUpgradeManager UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions( { @@ -227,7 +228,9 @@ class CuraApplication(QtApplication): "TranslateTool", "FileLogger", "XmlMaterialProfile", - "PluginBrowser" + "PluginBrowser", + "PrepareStage", + "MonitorStage" ]) self._physics = None self._volume = None @@ -388,7 +391,6 @@ class CuraApplication(QtApplication): def needToShowUserAgreement(self): return self._need_to_show_user_agreement - def setNeedToShowUserAgreement(self, set_value = True): self._need_to_show_user_agreement = set_value @@ -666,14 +668,14 @@ class CuraApplication(QtApplication): controller = self.getController() + controller.setActiveStage("PrepareStage") controller.setActiveView("SolidView") - controller.setCameraTool("CameraTool") controller.setSelectionTool("SelectionTool") t = controller.getTool("TranslateTool") if t: - t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis,ToolHandle.ZAxis]) + t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis]) Selection.selectionChanged.connect(self.onSelectionChanged) @@ -717,6 +719,7 @@ class CuraApplication(QtApplication): run_headless = self.getCommandLineOption("headless", False) if not run_headless: self.initializeEngine() + controller.setActiveStage("PrepareStage") if run_headless or self._engine.rootObjects: self.closeSplash() diff --git a/cura/Stages/CuraStage.py b/cura/Stages/CuraStage.py new file mode 100644 index 0000000000..8b7822ed7a --- /dev/null +++ b/cura/Stages/CuraStage.py @@ -0,0 +1,22 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from PyQt5.QtCore import pyqtProperty, QUrl, QObject + +from UM.Stage import Stage + +class CuraStage(Stage): + + def __init__(self, parent = None): + super().__init__(parent) + + @pyqtProperty(str, constant = True) + def stageId(self): + return self.getPluginId() + + @pyqtProperty(QUrl, constant = True) + def mainComponent(self): + return self.getDisplayComponent("main") + + @pyqtProperty(QUrl, constant = True) + def sidebarComponent(self): + return self.getDisplayComponent("sidebar") diff --git a/cura/Stages/__init__.py b/cura/Stages/__init__.py new file mode 100644 index 0000000000..2977645166 --- /dev/null +++ b/cura/Stages/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. diff --git a/cura_app.py b/cura_app.py index d725bc1200..dd795e5aa4 100755 --- a/cura_app.py +++ b/cura_app.py @@ -22,9 +22,10 @@ if Platform.isLinux(): # Needed for platform.linux_distribution, which is not av if Platform.isWindows() and hasattr(sys, "frozen"): try: del os.environ["PYTHONPATH"] - except KeyError: pass + except KeyError: + pass -#WORKAROUND: GITHUB-704 GITHUB-708 +# WORKAROUND: GITHUB-704 GITHUB-708 # It looks like setuptools creates a .pth file in # the default /usr/lib which causes the default site-packages # to be inserted into sys.path before PYTHONPATH. @@ -45,6 +46,7 @@ def exceptHook(hook_type, value, traceback): _crash_handler = CrashHandler(hook_type, value, traceback) _crash_handler.show() + sys.excepthook = exceptHook # Workaround for a race condition on certain systems where there @@ -75,7 +77,7 @@ faulthandler.enable() # Force an instance of CuraContainerRegistry to be created and reused later. cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance() -# This prestart up check is needed to determine if we should start the application at all. +# This pre-start up check is needed to determine if we should start the application at all. if not cura.CuraApplication.CuraApplication.preStartUp(): sys.exit(0) diff --git a/plugins/MonitorStage/MonitorMainView.qml b/plugins/MonitorStage/MonitorMainView.qml new file mode 100644 index 0000000000..038403e6d3 --- /dev/null +++ b/plugins/MonitorStage/MonitorMainView.qml @@ -0,0 +1,39 @@ +// Copyright (c) 2017 Ultimaker B.V. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +Item +{ + // We show a nice overlay on the 3D viewer when the current output device has no monitor view + Rectangle + { + id: viewportOverlay + + color: UM.Theme.getColor("viewport_overlay") + width: parent.width + height: parent.height + visible: monitorViewComponent.sourceComponent == null ? 1 : 0 + + MouseArea + { + anchors.fill: parent + acceptedButtons: Qt.AllButtons + onWheel: wheel.accepted = true + } + } + + Loader + { + id: monitorViewComponent + + property real maximumWidth: parent.width + property real maximumHeight: parent.height + + sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem: null + visible: sourceComponent != null + } +} diff --git a/plugins/MonitorStage/MonitorStage.py b/plugins/MonitorStage/MonitorStage.py new file mode 100644 index 0000000000..0736f49858 --- /dev/null +++ b/plugins/MonitorStage/MonitorStage.py @@ -0,0 +1,73 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import os.path +from UM.Application import Application +from UM.PluginRegistry import PluginRegistry +from UM.Resources import Resources +from cura.Stages.CuraStage import CuraStage + + +## Stage for monitoring a 3D printing while it's printing. +class MonitorStage(CuraStage): + + def __init__(self, parent = None): + super().__init__(parent) + + # Wait until QML engine is created, otherwise creating the new QML components will fail + Application.getInstance().engineCreatedSignal.connect(self._setComponents) + + # Update the status icon when the output device is changed + Application.getInstance().getOutputDeviceManager().activeDeviceChanged.connect(self._setIconSource) + + def _setComponents(self): + self._setMainOverlay() + self._setSidebar() + self._setIconSource() + + def _setMainOverlay(self): + main_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("MonitorStage"), "MonitorMainView.qml") + self.addDisplayComponent("main", main_component_path) + + def _setSidebar(self): + # TODO: currently the sidebar component for prepare and monitor stages is the same, this will change with the printer output device refactor! + sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), "Sidebar.qml") + self.addDisplayComponent("sidebar", sidebar_component_path) + + def _setIconSource(self): + if Application.getInstance().getTheme() is not None: + icon_name = self._getActiveOutputDeviceStatusIcon() + self.setIconSource(Application.getInstance().getTheme().getIcon(icon_name)) + + ## Find the correct status icon depending on the active output device state + def _getActiveOutputDeviceStatusIcon(self): + output_device = Application.getInstance().getOutputDeviceManager().getActiveDevice() + + if not output_device: + return "tab_status_unknown" + + if hasattr(output_device, "acceptsCommands") and not output_device.acceptsCommands: + return "tab_status_unknown" + + if not hasattr(output_device, "printerState") or not hasattr(output_device, "jobState"): + return "tab_status_unknown" + + # TODO: refactor to use enum instead of hardcoded strings? + if output_device.printerState == "maintenance": + return "tab_status_busy" + + if output_device.jobState in ["printing", "pre_print", "pausing", "resuming"]: + return "tab_status_busy" + + if output_device.jobState == "wait_cleanup": + return "tab_status_finished" + + if output_device.jobState in ["ready", ""]: + return "tab_status_connected" + + if output_device.jobState == "paused": + return "tab_status_paused" + + if output_device.jobState == "error": + return "tab_status_stopped" + + return "tab_status_unknown" diff --git a/plugins/MonitorStage/__init__.py b/plugins/MonitorStage/__init__.py new file mode 100644 index 0000000000..884d43a8af --- /dev/null +++ b/plugins/MonitorStage/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from . import MonitorStage + +from UM.i18n import i18nCatalog +i18n_catalog = i18nCatalog("cura") + +def getMetaData(): + return { + "stage": { + "name": i18n_catalog.i18nc("@item:inmenu", "Monitor"), + "weight": 1 + } + } + +def register(app): + return { + "stage": MonitorStage.MonitorStage() + } diff --git a/plugins/MonitorStage/plugin.json b/plugins/MonitorStage/plugin.json new file mode 100644 index 0000000000..cb3f55a80d --- /dev/null +++ b/plugins/MonitorStage/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Monitor Stage", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Provides a monitor stage in Cura.", + "api": 4, + "i18n-catalog": "cura" +} \ No newline at end of file diff --git a/plugins/PrepareStage/PrepareStage.py b/plugins/PrepareStage/PrepareStage.py new file mode 100644 index 0000000000..9d4d632845 --- /dev/null +++ b/plugins/PrepareStage/PrepareStage.py @@ -0,0 +1,18 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import os.path +from UM.Application import Application +from UM.Resources import Resources +from cura.Stages.CuraStage import CuraStage + + +## Stage for preparing model (slicing). +class PrepareStage(CuraStage): + + def __init__(self, parent = None): + super().__init__(parent) + Application.getInstance().engineCreatedSignal.connect(self._engineCreated) + + def _engineCreated(self): + sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), "Sidebar.qml") + self.addDisplayComponent("sidebar", sidebar_component_path) diff --git a/plugins/PrepareStage/__init__.py b/plugins/PrepareStage/__init__.py new file mode 100644 index 0000000000..f085d788f9 --- /dev/null +++ b/plugins/PrepareStage/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from . import PrepareStage + +from UM.i18n import i18nCatalog +i18n_catalog = i18nCatalog("cura") + +def getMetaData(): + return { + "stage": { + "name": i18n_catalog.i18nc("@item:inmenu", "Prepare"), + "weight": 0 + } + } + +def register(app): + return { + "stage": PrepareStage.PrepareStage() + } diff --git a/plugins/PrepareStage/plugin.json b/plugins/PrepareStage/plugin.json new file mode 100644 index 0000000000..4fd55e955e --- /dev/null +++ b/plugins/PrepareStage/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Prepare Stage", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Provides a prepare stage in Cura.", + "api": 4, + "i18n-catalog": "cura" +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py b/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py index 44a2e8b743..853ef72f72 100644 --- a/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py @@ -698,7 +698,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte if self._reply: self._reply.abort() self._stage = OutputStage.ready - Application.getInstance().showPrintMonitor.emit(False) + Application.getInstance().getController().setActiveStage("PrepareStage") @pyqtSlot(int, result=str) def formatDuration(self, seconds): diff --git a/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py b/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py index d8dd780ed5..3a48bab11b 100755 --- a/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py @@ -672,7 +672,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): Logger.log("d", "Attempting to perform an action without authentication for printer %s. Auth state is %s", self._key, self._authentication_state) return - Application.getInstance().showPrintMonitor.emit(True) + Application.getInstance().getController().setActiveStage("MonitorStage") self._print_finished = True self.writeStarted.emit(self) self._gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list") @@ -767,7 +767,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): if button == QMessageBox.Yes: self.startPrint() else: - Application.getInstance().showPrintMonitor.emit(False) + Application.getInstance().getController().setActiveStage("PrepareStage") # For some unknown reason Cura on OSX will hang if we do the call back code # immediately without first returning and leaving QML's event system. QTimer.singleShot(100, delayedCallback) @@ -850,7 +850,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice): self._write_finished = True # post_reply does not always exist, so make sure we unblock writing if self._post_reply: self._finalizePostReply() - Application.getInstance().showPrintMonitor.emit(False) + Application.getInstance().getController().setActiveStage("PrepareStage") ## Attempt to start a new print. # This function can fail to actually start a print due to not being authenticated or another print already diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 77f45ee6d4..1930f5402b 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -490,7 +490,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self.setJobName(file_name) self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds)) - Application.getInstance().showPrintMonitor.emit(True) + Application.getInstance().getController().setActiveStage("MonitorStage") self.startPrint() def _setEndstopState(self, endstop_key, value): @@ -698,7 +698,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._is_printing = False self._is_paused = False self._updateJobState("ready") - Application.getInstance().showPrintMonitor.emit(False) + Application.getInstance().getController().setActiveStage("PrepareStage") ## Check if the process did not encounter an error yet. def hasError(self): diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index e144048af7..aedf5d0fa8 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -20,14 +20,16 @@ UM.MainWindow viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0) property bool showPrintMonitor: false + // This connection is here to support legacy printer output devices that use the showPrintMonitor signal on Application to switch to the monitor stage + // It should be phased out in newer plugin versions. Connections { target: Printer onShowPrintMonitor: { if (show) { - topbar.startMonitoringPrint() + UM.Controller.setActiveStage("MonitorStage") } else { - topbar.stopMonitoringPrint() + UM.Controller.setActiveStage("PrepareStage") } } } @@ -331,7 +333,7 @@ UM.MainWindow text: catalog.i18nc("@action:button","Open File"); iconSource: UM.Theme.getIcon("load") style: UM.Theme.styles.tool_button - tooltip: ''; + tooltip: "" anchors { top: topbar.bottom; @@ -358,62 +360,49 @@ UM.MainWindow Topbar { id: topbar - anchors.left:parent.left + anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - monitoringPrint: base.showPrintMonitor - onStartMonitoringPrint: base.showPrintMonitor = true - onStopMonitoringPrint: base.showPrintMonitor = false - } - - Sidebar - { - id: sidebar; - - anchors - { - top: topbar.bottom; - bottom: parent.bottom; - right: parent.right; - } - z: 1 - width: UM.Theme.getSize("sidebar").width; - monitoringPrint: base.showPrintMonitor - } - - Rectangle - { - id: viewportOverlay - - color: UM.Theme.getColor("viewport_overlay") - anchors - { - top: topbar.bottom - bottom: parent.bottom - left:parent.left - right: sidebar.left - } - visible: opacity > 0 - opacity: base.showPrintMonitor ? 1 : 0 - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.AllButtons - - onWheel: wheel.accepted = true - } } Loader { - sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem: null - visible: base.showPrintMonitor - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenterOffset: - UM.Theme.getSize("sidebar").width / 2 - anchors.verticalCenterOffset: UM.Theme.getSize("sidebar_header").height / 2 - property real maximumWidth: viewportOverlay.width - property real maximumHeight: viewportOverlay.height + id: sidebar + + anchors + { + top: topbar.bottom + bottom: parent.bottom + right: parent.right + } + + width: UM.Theme.getSize("sidebar").width + z: 1 + + source: UM.Controller.activeStage.sidebarComponent + } + + Loader + { + id: main + + anchors + { + top: topbar.bottom + bottom: parent.bottom + left: parent.left + right: sidebar.left + } + + MouseArea + { + visible: UM.Controller.activeStage.mainComponent != "" + anchors.fill: parent + acceptedButtons: Qt.AllButtons + onWheel: wheel.accepted = true + } + + source: UM.Controller.activeStage.mainComponent } UM.MessageStack diff --git a/resources/qml/Menus/ViewMenu.qml b/resources/qml/Menus/ViewMenu.qml index bb5999edb9..a610bb0009 100644 --- a/resources/qml/Menus/ViewMenu.qml +++ b/resources/qml/Menus/ViewMenu.qml @@ -12,21 +12,23 @@ Menu title: catalog.i18nc("@title:menu menubar:toplevel", "&View"); id: menu enabled: !PrintInformation.preSliced + + // main views Instantiator { - model: UM.ViewModel { } + model: UM.ViewModel{} MenuItem { - text: model.name; - checkable: true; - checked: model.active; - exclusiveGroup: group; - onTriggered: UM.Controller.setActiveView(model.id); + text: model.name + checkable: true + checked: model.active + exclusiveGroup: group + onTriggered: UM.Controller.setActiveView(model.id) } onObjectAdded: menu.insertItem(index, object) onObjectRemoved: menu.removeItem(object) } - ExclusiveGroup { id: group; } + ExclusiveGroup { id: group } MenuSeparator {} MenuItem { action: Cura.Actions.homeCamera; } diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml index b258ecad43..390b868a9b 100644 --- a/resources/qml/SaveButton.qml +++ b/resources/qml/SaveButton.qml @@ -46,7 +46,7 @@ Item { } function sliceOrStopSlicing() { - if ([1, 5].indexOf(UM.Backend.state) != -1) { + if (backend != "undefined" && [1, 5].indexOf(UM.Backend.state) != -1) { backend.forceSlice(); } else { backend.stopSlicing(); diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index bed5b4c873..a459b481db 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -24,7 +24,7 @@ Rectangle property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null property int backendState: UM.Backend.state - property bool monitoringPrint: false + property bool monitoringPrint: UM.Controller.activeStage.stageId == "MonitorStage" property variant printDuration: PrintInformation.currentPrintTime property variant printMaterialLengths: PrintInformation.materialLengths @@ -263,7 +263,7 @@ Rectangle { id: controlItem anchors.bottom: footerSeparator.top - anchors.top: headerSeparator.bottom + anchors.top: monitoringPrint ? base.top : headerSeparator.bottom anchors.left: base.left anchors.right: base.right sourceComponent: @@ -282,7 +282,7 @@ Rectangle Loader { anchors.bottom: footerSeparator.top - anchors.top: headerSeparator.bottom + anchors.top: monitoringPrint ? base.top : headerSeparator.bottom anchors.left: base.left anchors.right: base.right source: diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index e923963355..62cf6f9d34 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -403,8 +403,6 @@ Item } } - - // // Infill // @@ -568,18 +566,20 @@ Item model: infillModel anchors.fill: parent - property int activeIndex: { + function activeIndex () { for (var i = 0; i < infillModel.count; i++) { var density = parseInt(infillDensity.properties.value) var steps = parseInt(infillSteps.properties.value) var infillModelItem = infillModel.get(i) - if (density >= infillModelItem.percentageMin + if (infillModelItem != "undefined" + && density >= infillModelItem.percentageMin && density <= infillModelItem.percentageMax && steps >= infillModelItem.stepsMin - && steps <= infillModelItem.stepsMax){ - return i - } + && steps <= infillModelItem.stepsMax + ){ + return i + } } return -1 } @@ -587,7 +587,7 @@ Item Rectangle { anchors.fill: parent - visible: infillIconList.activeIndex == index + visible: infillIconList.activeIndex() == index border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("quality_slider_unavailable") diff --git a/resources/qml/Topbar.qml b/resources/qml/Topbar.qml index db9abafb5c..99910b24a2 100644 --- a/resources/qml/Topbar.qml +++ b/resources/qml/Topbar.qml @@ -6,7 +6,7 @@ import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import QtQuick.Layouts 1.1 -import UM 1.2 as UM +import UM 1.4 as UM import Cura 1.0 as Cura import "Menus" @@ -16,27 +16,10 @@ Rectangle anchors.left: parent.left anchors.right: parent.right height: UM.Theme.getSize("sidebar_header").height - color: base.monitoringPrint ? UM.Theme.getColor("topbar_background_color_monitoring") : UM.Theme.getColor("topbar_background_color") + color: UM.Controller.activeStage.stageId == "MonitorStage" ? UM.Theme.getColor("topbar_background_color_monitoring") : UM.Theme.getColor("topbar_background_color") property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0 property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - property bool monitoringPrint: false - - // outgoing signal - signal startMonitoringPrint() - signal stopMonitoringPrint() - - // update monitoring status when event was triggered outside topbar - Component.onCompleted: { - startMonitoringPrint.connect(function () { - base.monitoringPrint = true - UM.Controller.disableModelRendering() - }) - stopMonitoringPrint.connect(function () { - base.monitoringPrint = false - UM.Controller.enableModelRendering() - }) - } UM.I18nCatalog { @@ -67,92 +50,30 @@ Rectangle anchors.rightMargin: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width - Button + // The topbar is dynamically filled with all available stages + Repeater { - id: showSettings - height: UM.Theme.getSize("sidebar_header").height - text: catalog.i18nc("@title:tab", "Prepare") - checkable: true - checked: isChecked() - exclusiveGroup: sidebarHeaderBarGroup - style: UM.Theme.styles.topbar_header_tab + id: stagesMenu - // We use a Qt.binding to re-bind the checkbox state after manually setting it - // https://stackoverflow.com/questions/38798450/qt-5-7-qml-why-are-my-checkbox-property-bindings-disappearing - onClicked: { - base.stopMonitoringPrint() - checked = Qt.binding(isChecked) - } + model: UM.StageModel{} - function isChecked () { - return !base.monitoringPrint - } - - property color overlayColor: "transparent" - property string overlayIconSource: "" - } - - Button - { - id: showMonitor - width: UM.Theme.getSize("topbar_button").width - height: UM.Theme.getSize("sidebar_header").height - text: catalog.i18nc("@title:tab", "Monitor") - checkable: true - checked: isChecked() - exclusiveGroup: sidebarHeaderBarGroup - style: UM.Theme.styles.topbar_header_tab_no_overlay - - // We use a Qt.binding to re-bind the checkbox state after manually setting it - // https://stackoverflow.com/questions/38798450/qt-5-7-qml-why-are-my-checkbox-property-bindings-disappearing - onClicked: { - base.startMonitoringPrint() - checked = Qt.binding(isChecked) - } - - function isChecked () { - return base.monitoringPrint - } - - property string iconSource: + delegate: Button { - if (!printerConnected) - { - return UM.Theme.getIcon("tab_status_unknown"); - } - else if (!printerAcceptsCommands) - { - return UM.Theme.getIcon("tab_status_unknown"); - } + text: model.name + checkable: true + checked: model.active + exclusiveGroup: topbarMenuGroup + style: (model.stage.iconSource != "") ? UM.Theme.styles.topbar_header_tab_no_overlay : UM.Theme.styles.topbar_header_tab + height: UM.Theme.getSize("sidebar_header").height + onClicked: UM.Controller.setActiveStage(model.id) + iconSource: model.stage.iconSource - if (Cura.MachineManager.printerOutputDevices[0].printerState == "maintenance") - { - return UM.Theme.getIcon("tab_status_busy"); - } - - switch (Cura.MachineManager.printerOutputDevices[0].jobState) - { - case "printing": - case "pre_print": - case "pausing": - case "resuming": - return UM.Theme.getIcon("tab_status_busy"); - case "wait_cleanup": - return UM.Theme.getIcon("tab_status_finished"); - case "ready": - case "": - return UM.Theme.getIcon("tab_status_connected") - case "paused": - return UM.Theme.getIcon("tab_status_paused") - case "error": - return UM.Theme.getIcon("tab_status_stopped") - default: - return UM.Theme.getIcon("tab_status_unknown") - } + property color overlayColor: "transparent" + property string overlayIconSource: "" } } - ExclusiveGroup { id: sidebarHeaderBarGroup } + ExclusiveGroup { id: topbarMenuGroup } } ToolButton @@ -220,17 +141,16 @@ Rectangle menu: PrinterMenu { } } - //View orientation Item + // View orientation Item Row { id: viewOrientationControl height: 30 - spacing: 2 + visible: UM.Controller.activeStage.stageId != "MonitorStage" - visible: !base.monitoringPrint - - anchors { + anchors + { verticalCenter: base.verticalCenter right: viewModeButton.right rightMargin: UM.Theme.getSize("default_margin").width + viewModeButton.width @@ -308,7 +228,7 @@ Rectangle } style: UM.Theme.styles.combobox - visible: !base.monitoringPrint + visible: UM.Controller.activeStage.stageId != "MonitorStage" model: UM.ViewModel { } textRole: "name"