Browse Source

Merge pull request #4436 from Ultimaker/clean_print_job_info_block

CL-897, CL-1051, CL-1111 Cura 3.6 Monitor Tab
Ian Paschal 6 years ago
parent
commit
be5c1c8596

+ 2 - 3
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)
+        self._output_controller.setJobState(self, state)

+ 27 - 33
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
-
-    width: 36 * screenScaleFactor
-    height: width
-    radius: 0.5 * width
-    color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary")
+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;
 
-    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);
             }
         }
     }

+ 86 - 780
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 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"
+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;
+
+        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")
+        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");
         }
 
-        MouseArea
-        {
-            anchors.fill: managePrintersLabel
-            hoverEnabled: true
-            onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel()
-            onEntered: managePrintersLabel.font.underline = true
-            onExited: managePrintersLabel.font.underline = false
+        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
+        // 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;
 
-            style: UM.Theme.styles.scrollview
+            PrinterCard {
+                printer: null;
+            }
+            PrinterCard {
+                printer: null;
+            }
+        }
 
-            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
+        // 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;
             }
         }
     }

+ 105 - 81
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"
+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);
+            }
         }
+        width: maximumWidth;
 
-        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")
+        UM.I18nCatalog {
+            id: catalog;
+            name: "cura";
         }
 
-        MouseArea
-        {
-            anchors.fill: manageQueueLabel
-            hoverEnabled: true
-            onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel()
-            onEntered: manageQueueLabel.font.underline = true
-            onExited: manageQueueLabel.font.underline = false
+        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");
         }
 
-        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")
+        MouseArea {
+            anchors.fill: manageQueueLabel;
+            hoverEnabled: true;
+            onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel();
+            onEntered: manageQueueLabel.font.underline = true;
+            onExited: manageQueueLabel.font.underline = false;
         }
 
-        ScrollView
-        {
-            id: queuedPrintJobs
+        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");
+        }
 
-            anchors
-            {
-                top: queuedLabel.bottom
-                topMargin: UM.Theme.getSize("default_margin").height
-                horizontalCenter: parent.horizontalCenter
-                bottomMargin: 0
-                bottom: parent.bottom
+        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;
             }
-            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
+            visible: !queuedPrintJobs.visible;
+            width: Math.min(800 * screenScaleFactor, maximumWidth);
 
-                model: OutputDevice.queuedPrintJobs
+            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
+            }
 
-                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
+            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);
 
-        onVisibleChanged:
-        {
-            if (monitorFrame != null && !monitorFrame.visible)
-            {
-                OutputDevice.setActiveCamera(null)
+            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;
             }
         }
+
+        PrinterVideoStream {
+            anchors.fill: parent;
+            camera: OutputDevice.activeCamera;
+            visible: OutputDevice.activeCamera != null;
+        }
     }
 }

+ 3 - 0
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
 

+ 12 - 0
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;
+}

+ 29 - 37
plugins/UM3NetworkPrinting/resources/qml/MonitorItem.qml

@@ -1,54 +1,46 @@
-import QtQuick 2.2
-
+// 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;
         }
     }
 }

+ 95 - 67
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
+        // 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;
+            }
+            radius: Math.round(width / 2);
+            visible: printCoreConfiguration;
 
-        anchors.verticalCenter: printAndMaterialLabel.verticalCenter
-        opacity:
-        {
-            if(printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null)
-            {
-                return 0.5
+            Label {
+                anchors.centerIn: parent;
+                color: UM.Theme.getColor("text");
+                font: UM.Theme.getFont("default_bold");
+                text: printCoreConfiguration ? printCoreConfiguration.position + 1 : 0;
             }
-            return 1
         }
+    }
+
+    // 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: UM.Theme.getSize("monitor_text_line").height;
 
-        Rectangle
-        {
-            anchors.fill: parent
-            radius: Math.round(width / 2)
-            border.width: 2
-            border.color: "black"
+        // Loading skeleton
+        Rectangle {
+            anchors.fill: parent;
+            color: UM.Theme.getColor("monitor_skeleton_fill");
+            visible: !extruderInfo.printCoreConfiguration;
         }
 
-        Label
-        {
-            anchors.centerIn: parent
-            font: UM.Theme.getFont("default_bold")
-            text:  printCoreConfiguration.position + 1
+        // 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 "";
+            }
+            visible: extruderInfo.printCoreConfiguration;
         }
     }
 
-    Item
-    {
-        id: printAndMaterialLabel
-        anchors
-        {
-            right: parent.right
-            left: extruderCircle.right
-            margins: UM.Theme.getSize("default_margin").width
+    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: 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 {
+            color: UM.Theme.getColor("monitor_skeleton_fill");
+            height: parent.height;
+            visible: !extruderInfo.printCoreConfiguration;
+            width: Math.round(parent.width / 3);
         }
 
-        Label
-        {
-            id: printCoreLabel
-            text:
-            {
-                if(printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined)
-                {
-                    return printCoreConfiguration.hotendID
+        // 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 ""
+                return "";
             }
-            anchors.top: materialLabel.bottom
-            elide: Text.ElideRight
-            width: parent.width
-            opacity: 0.6
-            font: UM.Theme.getFont("default")
+            visible: extruderInfo.printCoreConfiguration;
         }
     }
 }

+ 212 - 0
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;
+    }
+}

+ 24 - 0
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;
+}

Some files were not shown because too many files changed in this diff