Merge pull request #4436 from Ultimaker/clean_print_job_info_block

CL-897, CL-1051, CL-1111 Cura 3.6 Monitor Tab
This commit is contained in:
Ian Paschal 2018-10-24 12:29:46 +02:00 committed by GitHub
commit be5c1c8596
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2070 additions and 1675 deletions

View File

@ -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. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot
@ -12,7 +12,6 @@ if TYPE_CHECKING:
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
class PrintJobOutputModel(QObject): class PrintJobOutputModel(QObject):
stateChanged = pyqtSignal() stateChanged = pyqtSignal()
timeTotalChanged = pyqtSignal() timeTotalChanged = pyqtSignal()

View File

@ -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 2.3
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import QtQuick.Controls 2.0 as Controls2
import QtGraphicalEffects 1.0
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Rectangle Rectangle {
{ property var iconSource: null;
property var iconSource: null color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary"); // "Cura Blue"
height: width;
radius: Math.round(0.5 * width);
width: 36 * screenScaleFactor;
width: 36 * screenScaleFactor UM.RecolorImage {
height: width id: icon;
radius: 0.5 * width anchors {
color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary") horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter;
UM.RecolorImage }
{ color: UM.Theme.getColor("primary_text");
id: icon height: width;
width: parent.width / 2 source: iconSource;
height: width width: Math.round(parent.width / 2);
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: UM.Theme.getColor("primary_text")
source: iconSource
} }
MouseArea MouseArea {
{ id: clickArea;
id: clickArea anchors.fill: parent;
anchors.fill:parent hoverEnabled: true;
hoverEnabled: true onClicked: {
onClicked: if (OutputDevice.activeCamera !== null) {
{
if (OutputDevice.activeCamera !== null)
{
OutputDevice.setActiveCamera(null) OutputDevice.setActiveCamera(null)
} } else {
else OutputDevice.setActiveCamera(modelData.camera);
{
OutputDevice.setActiveCamera(modelData.camera)
} }
} }
} }

View File

@ -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 2.3
import QtQuick.Dialogs 1.1
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls 2.0 as Controls2
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Component {
Rectangle {
id: base;
property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width;
property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width;
anchors.fill: parent;
color: UM.Theme.getColor("sidebar");
visible: OutputDevice != null;
Component UM.I18nCatalog {
{ id: catalog;
Rectangle name: "cura";
{
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"
} }
Label Label {
{ id: printingLabel;
id: printingLabel anchors {
font: UM.Theme.getFont("large") left: parent.left;
anchors leftMargin: 4 * UM.Theme.getSize("default_margin").width;
{ margins: 2 * UM.Theme.getSize("default_margin").width;
margins: 2 * UM.Theme.getSize("default_margin").width right: parent.right;
leftMargin: 4 * UM.Theme.getSize("default_margin").width top: parent.top;
top: parent.top }
left: parent.left color: UM.Theme.getColor("text");
right: parent.right elide: Text.ElideRight;
font: UM.Theme.getFont("large");
text: catalog.i18nc("@label", "Printing");
} }
text: catalog.i18nc("@label", "Printing") Label {
elide: Text.ElideRight 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");
} }
Label MouseArea {
{ anchors.fill: managePrintersLabel;
id: managePrintersLabel hoverEnabled: true;
anchors.rightMargin: 4 * UM.Theme.getSize("default_margin").width onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel();
anchors.right: printerScrollView.right onEntered: managePrintersLabel.font.underline = true;
anchors.bottom: printingLabel.bottom onExited: managePrintersLabel.font.underline = false;
text: catalog.i18nc("@label link to connect manager", "Manage printers")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("primary")
linkColor: UM.Theme.getColor("primary")
} }
MouseArea // Skeleton loading
{ Column {
anchors.fill: managePrintersLabel id: skeletonLoader;
hoverEnabled: true anchors {
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel() left: parent.left;
onEntered: managePrintersLabel.font.underline = true leftMargin: UM.Theme.getSize("wide_margin").width;
onExited: managePrintersLabel.font.underline = false 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;
ScrollView PrinterCard {
{ printer: null;
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
}
style: UM.Theme.styles.scrollview
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
}
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
} }
PrinterCard {
printer: null;
} }
} }
Item // Actual content
{ ScrollView {
id: machineIcon id: printerScrollView;
// Yeah, this is hardcoded now, but I can't think of a good way to fix this. anchors {
// The UI is going to get another update soon, so it's probably not worth the effort... bottom: parent.bottom;
width: 58 left: parent.left;
height: 58 right: parent.right;
anchors.top: parent.top top: printingLabel.bottom;
anchors.leftMargin: UM.Theme.getSize("default_margin").width topMargin: UM.Theme.getSize("default_margin").height;
anchors.left: parent.left }
style: UM.Theme.styles.scrollview;
UM.RecolorImage ListView {
{ id: printerList;
anchors.centerIn: parent property var currentIndex: -1;
source: anchors {
{ fill: parent;
switch(modelData.type) leftMargin: UM.Theme.getSize("wide_margin").width;
{ rightMargin: UM.Theme.getSize("wide_margin").width;
case "Ultimaker 3": }
return "../svg/UM3-icon.svg" delegate: PrinterCard {
case "Ultimaker 3 Extended": printer: modelData;
return "../svg/UM3x-icon.svg" }
case "Ultimaker S5": model: OutputDevice.printers;
return "../svg/UMs5-icon.svg" spacing: UM.Theme.getSize("default_margin").height - 10;
}
}
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")
}
}
}
}
}
}
} }
} }
} }

View File

@ -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 2.2
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Component Component {
{ Rectangle {
Rectangle id: monitorFrame;
{ property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight");
id: monitorFrame property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width;
width: maximumWidth color: UM.Theme.getColor("viewport_background");
height: maximumHeight height: maximumHeight;
color: UM.Theme.getColor("viewport_background") onVisibleChanged: {
property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight") if (monitorFrame != null && !monitorFrame.visible) {
property var lineColor: "#DCDCDC" // TODO: Should be linked to theme. OutputDevice.setActiveCamera(null);
property var cornerRadius: 4 * screenScaleFactor // TODO: Should be linked to theme. }
}
width: maximumWidth;
UM.I18nCatalog UM.I18nCatalog {
{ id: catalog;
id: catalog name: "cura";
name: "cura"
} }
Label Label {
{ id: manageQueueLabel;
id: manageQueueLabel anchors {
anchors.rightMargin: 3 * UM.Theme.getSize("default_margin").width bottom: queuedLabel.bottom;
anchors.right: queuedPrintJobs.right right: queuedPrintJobs.right;
anchors.bottom: queuedLabel.bottom rightMargin: 3 * UM.Theme.getSize("default_margin").width;
text: catalog.i18nc("@label link to connect manager", "Manage queue") }
font: UM.Theme.getFont("default") color: UM.Theme.getColor("primary");
color: UM.Theme.getColor("primary") font: UM.Theme.getFont("default");
linkColor: UM.Theme.getColor("primary") linkColor: UM.Theme.getColor("primary");
text: catalog.i18nc("@label link to connect manager", "Manage queue");
} }
MouseArea MouseArea {
{ anchors.fill: manageQueueLabel;
anchors.fill: manageQueueLabel hoverEnabled: true;
hoverEnabled: true onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel();
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel() onEntered: manageQueueLabel.font.underline = true;
onEntered: manageQueueLabel.font.underline = true onExited: manageQueueLabel.font.underline = false;
onExited: manageQueueLabel.font.underline = false
} }
Label Label {
{ id: queuedLabel;
id: queuedLabel anchors {
anchors.left: queuedPrintJobs.left left: queuedPrintJobs.left;
anchors.top: parent.top leftMargin: 3 * UM.Theme.getSize("default_margin").width + 5 * screenScaleFactor;
anchors.topMargin: 2 * UM.Theme.getSize("default_margin").height top: parent.top;
anchors.leftMargin: 3 * UM.Theme.getSize("default_margin").width + 5 topMargin: 2 * UM.Theme.getSize("default_margin").height;
text: catalog.i18nc("@label", "Queued") }
font: UM.Theme.getFont("large") color: UM.Theme.getColor("text");
color: UM.Theme.getColor("text") font: UM.Theme.getFont("large");
text: catalog.i18nc("@label", "Queued");
} }
ScrollView Column {
{ id: skeletonLoader;
id: queuedPrintJobs anchors {
bottom: parent.bottom;
anchors bottomMargin: UM.Theme.getSize("default_margin").height;
{ horizontalCenter: parent.horizontalCenter;
top: queuedLabel.bottom top: queuedLabel.bottom;
topMargin: UM.Theme.getSize("default_margin").height topMargin: UM.Theme.getSize("default_margin").height;
horizontalCenter: parent.horizontalCenter
bottomMargin: 0
bottom: parent.bottom
} }
style: UM.Theme.styles.scrollview visible: !queuedPrintJobs.visible;
width: Math.min(800 * screenScaleFactor, maximumWidth) 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
model: OutputDevice.queuedPrintJobs PrintJobInfoBlock {
anchors {
delegate: PrintJobInfoBlock left: parent.left;
{ leftMargin: UM.Theme.getSize("default_margin").width;
printJob: modelData right: parent.right;
anchors.left: parent.left rightMargin: UM.Theme.getSize("default_margin").width;
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").height
anchors.leftMargin: UM.Theme.getSize("default_margin").height
height: 175 * screenScaleFactor
} }
printJob: null; // Use as skeleton
}
PrintJobInfoBlock {
anchors {
left: parent.left;
leftMargin: UM.Theme.getSize("default_margin").width;
right: parent.right;
rightMargin: UM.Theme.getSize("default_margin").width;
}
printJob: null; // Use as skeleton
} }
} }
PrinterVideoStream ScrollView {
{ id: queuedPrintJobs;
visible: OutputDevice.activeCamera != null anchors {
anchors.fill: parent top: queuedLabel.bottom;
camera: OutputDevice.activeCamera topMargin: UM.Theme.getSize("default_margin").height;
horizontalCenter: parent.horizontalCenter;
bottomMargin: UM.Theme.getSize("default_margin").height;
bottom: parent.bottom;
}
style: UM.Theme.styles.scrollview;
visible: OutputDevice.receivedPrintJobs;
width: Math.min(800 * screenScaleFactor, maximumWidth);
ListView {
id: printJobList;
anchors.fill: parent;
delegate: PrintJobInfoBlock {
anchors {
left: parent.left;
leftMargin: UM.Theme.getSize("default_margin").width;
right: parent.right;
rightMargin: UM.Theme.getSize("default_margin").width;
}
printJob: modelData;
}
model: OutputDevice.queuedPrintJobs;
spacing: UM.Theme.getSize("default_margin").height - 2 * UM.Theme.getSize("monitor_shadow_radius").width;
}
} }
onVisibleChanged: PrinterVideoStream {
{ anchors.fill: parent;
if (monitorFrame != null && !monitorFrame.visible) camera: OutputDevice.activeCamera;
{ visible: OutputDevice.activeCamera != null;
OutputDevice.setActiveCamera(null)
}
} }
} }
} }

View File

@ -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 UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura

View File

@ -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;
}

View File

@ -1,54 +1,46 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Component Component {
{ Item {
Item height: maximumHeight;
{ width: maximumWidth;
width: maximumWidth
height: maximumHeight Image {
Image id: cameraImage;
{ anchors {
id: cameraImage horizontalCenter: parent.horizontalCenter;
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth) verticalCenter: parent.verticalCenter;
height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width) }
anchors.horizontalCenter: parent.horizontalCenter Component.onCompleted: {
anchors.verticalCenter: parent.verticalCenter if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) {
z: 1 OutputDevice.activePrinter.camera.start();
Component.onCompleted:
{
if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null)
{
OutputDevice.activePrinter.camera.start()
} }
} }
onVisibleChanged: height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width);
{ onVisibleChanged: {
if(visible) if (visible) {
{ if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) {
if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) OutputDevice.activePrinter.camera.start();
{
OutputDevice.activePrinter.camera.start()
} }
} else } else {
{ if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) {
if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null) OutputDevice.activePrinter.camera.stop();
{
OutputDevice.activePrinter.camera.stop()
} }
} }
} }
source: source: {
{ if (OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null && OutputDevice.activePrinter.camera.latestImage) {
if(OutputDevice.activePrinter != null && OutputDevice.activePrinter.camera != null && OutputDevice.activePrinter.camera.latestImage)
{
return OutputDevice.activePrinter.camera.latestImage; return OutputDevice.activePrinter.camera.latestImage;
} }
return ""; return "";
} }
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth);
z: 1;
} }
} }
} }

View File

@ -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 2.2
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import UM 1.2 as UM import UM 1.2 as UM
Item {
id: extruderInfo;
property var printCoreConfiguration: null;
height: childrenRect.height;
width: Math.round(parent.width / 2);
Item // Extruder circle
{ Item {
id: extruderInfo id: extruderCircle;
property var printCoreConfiguration height: UM.Theme.getSize("monitor_extruder_circle").height;
width: UM.Theme.getSize("monitor_extruder_circle").width;
width: Math.round(parent.width / 2) // Loading skeleton
height: childrenRect.height Rectangle {
anchors.fill: parent;
Item color: UM.Theme.getColor("monitor_skeleton_fill");
{ radius: Math.round(width / 2);
id: extruderCircle visible: !printCoreConfiguration;
width: 30
height: 30
anchors.verticalCenter: printAndMaterialLabel.verticalCenter
opacity:
{
if(printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null)
{
return 0.5
}
return 1
} }
Rectangle // Actual content
{ Rectangle {
anchors.fill: parent anchors.fill: parent;
radius: Math.round(width / 2) border.width: UM.Theme.getSize("monitor_thick_lining").width;
border.width: 2 border.color: UM.Theme.getColor("monitor_lining_heavy");
border.color: "black" color: "transparent";
opacity: {
if (printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null) {
return 0.5;
} }
return 1;
}
radius: Math.round(width / 2);
visible: printCoreConfiguration;
Label Label {
{ anchors.centerIn: parent;
anchors.centerIn: parent color: UM.Theme.getColor("text");
font: UM.Theme.getFont("default_bold") font: UM.Theme.getFont("default_bold");
text: printCoreConfiguration.position + 1 text: printCoreConfiguration ? printCoreConfiguration.position + 1 : 0;
}
} }
} }
Item // Print core and material labels
{ Item {
id: printAndMaterialLabel
anchors
{
right: parent.right
left: extruderCircle.right
margins: UM.Theme.getSize("default_margin").width
}
height: childrenRect.height
Label
{
id: materialLabel id: materialLabel
text: anchors {
{ left: extruderCircle.right;
if(printCoreConfiguration != undefined && printCoreConfiguration.activeMaterial != undefined) leftMargin: UM.Theme.getSize("default_margin").width;
{ right: parent.right;
return printCoreConfiguration.activeMaterial.name top: parent.top;
} }
return "" height: UM.Theme.getSize("monitor_text_line").height;
}
font: UM.Theme.getFont("default") // Loading skeleton
elide: Text.ElideRight Rectangle {
width: parent.width anchors.fill: parent;
color: UM.Theme.getColor("monitor_skeleton_fill");
visible: !extruderInfo.printCoreConfiguration;
} }
Label // Actual content
{ Label {
id: printCoreLabel anchors.fill: parent;
text: elide: Text.ElideRight;
{ color: UM.Theme.getColor("text");
if(printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined) font: UM.Theme.getFont("default");
{ text: {
return printCoreConfiguration.hotendID if (printCoreConfiguration && printCoreConfiguration.activeMaterial != undefined) {
return printCoreConfiguration.activeMaterial.name;
} }
return "" return "";
} }
anchors.top: materialLabel.bottom visible: extruderInfo.printCoreConfiguration;
elide: Text.ElideRight }
width: parent.width }
opacity: 0.6
font: UM.Theme.getFont("default") Item {
id: printCoreLabel;
anchors {
left: extruderCircle.right;
leftMargin: UM.Theme.getSize("default_margin").width;
right: parent.right;
top: materialLabel.bottom;
topMargin: Math.floor(UM.Theme.getSize("default_margin").height/4);
}
height: UM.Theme.getSize("monitor_text_line").height;
// Loading skeleton
Rectangle {
color: UM.Theme.getColor("monitor_skeleton_fill");
height: parent.height;
visible: !extruderInfo.printCoreConfiguration;
width: Math.round(parent.width / 3);
}
// Actual content
Label {
color: UM.Theme.getColor("text");
elide: Text.ElideRight;
font: UM.Theme.getFont("default");
opacity: 0.6;
text: {
if (printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined) {
return printCoreConfiguration.hotendID;
}
return "";
}
visible: extruderInfo.printCoreConfiguration;
} }
} }
} }

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -1,429 +1,476 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.1
import UM 1.3 as UM import UM 1.3 as UM
Item {
id: root;
property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width;
property var shadowOffset: 2 * screenScaleFactor;
property var debug: false;
property var printJob: null;
width: parent.width; // Bubbles downward
height: childrenRect.height + shadowRadius * 2; // Bubbles upward
Item UM.I18nCatalog {
{ id: catalog;
id: base name: "cura";
property var printJob: null
property var shadowRadius: 5 * screenScaleFactor
function getPrettyTime(time)
{
return OutputDevice.formatDuration(time)
} }
width: parent.width // The actual card (white block)
Rectangle {
UM.I18nCatalog // 5px margin, but shifted 2px vertically because of the shadow
{ anchors {
id: catalog bottomMargin: root.shadowRadius + root.shadowOffset;
name: "cura" leftMargin: root.shadowRadius;
rightMargin: root.shadowRadius;
topMargin: root.shadowRadius - root.shadowOffset;
} }
color: UM.Theme.getColor("monitor_card_background");
Rectangle height: childrenRect.height;
{
id: background
anchors
{
top: parent.top
topMargin: 3 * screenScaleFactor
left: parent.left
leftMargin: base.shadowRadius
rightMargin: base.shadowRadius
right: parent.right
bottom: parent.bottom
bottomMargin: base.shadowRadius
}
layer.enabled: true layer.enabled: true
layer.effect: DropShadow layer.effect: DropShadow {
{ radius: root.shadowRadius
radius: base.shadowRadius
verticalOffset: 2 * screenScaleFactor verticalOffset: 2 * screenScaleFactor
color: "#3F000000" // 25% shadow color: "#3F000000" // 25% shadow
} }
width: parent.width - shadowRadius * 2;
Item Column {
{ height: childrenRect.height;
// Content on the left of the infobox width: parent.width;
anchors
{ // Main content
top: parent.top Item {
bottom: parent.bottom id: mainContent;
left: parent.left height: 200 * screenScaleFactor; // TODO: Theme!
right: parent.horizontalCenter width: parent.width;
margins: UM.Theme.getSize("wide_margin").width
rightMargin: UM.Theme.getSize("default_margin").width // Left content
Item {
anchors {
bottom: parent.bottom;
left: parent.left;
margins: UM.Theme.getSize("wide_margin").width;
right: parent.horizontalCenter;
top: parent.top;
} }
Label Item {
{ id: printJobName;
id: printJobName width: parent.width;
text: printJob.name height: UM.Theme.getSize("monitor_text_line").height;
font: UM.Theme.getFont("default_bold")
width: parent.width
elide: Text.ElideRight
}
Label Rectangle {
{ color: UM.Theme.getColor("monitor_skeleton_fill");
id: ownerName height: parent.height;
anchors.top: printJobName.bottom visible: !printJob;
text: printJob.owner width: Math.round(parent.width / 3);
font: UM.Theme.getFont("default")
opacity: 0.6
width: parent.width
elide: Text.ElideRight
} }
Label {
Image anchors.fill: parent;
{ color: UM.Theme.getColor("text");
id: printJobPreview elide: Text.ElideRight;
source: printJob.previewImageUrl font: UM.Theme.getFont("default_bold");
anchors.top: ownerName.bottom text: printJob && printJob.name ? printJob.name : ""; // Supress QML warnings
anchors.horizontalCenter: parent.horizontalCenter visible: printJob;
anchors.bottom: totalTimeLabel.bottom
width: height
opacity: printJob.state == "error" ? 0.5 : 1.0
}
UM.RecolorImage
{
id: statusImage
anchors.centerIn: printJobPreview
source: printJob.state == "error" ? "../svg/aborted-icon.svg" : ""
visible: source != ""
width: 0.5 * printJobPreview.width
height: 0.5 * printJobPreview.height
sourceSize.width: width
sourceSize.height: height
color: "black"
}
Label
{
id: totalTimeLabel
anchors.bottom: parent.bottom
anchors.right: parent.right
font: UM.Theme.getFont("default")
text: printJob != null ? getPrettyTime(printJob.timeTotal) : ""
elide: Text.ElideRight
} }
} }
Item Item {
{ id: printJobOwnerName;
// Content on the right side of the infobox. anchors {
anchors top: printJobName.bottom;
{ topMargin: Math.floor(UM.Theme.getSize("default_margin").height / 2);
top: parent.top
bottom: parent.bottom
left: parent.horizontalCenter
right: parent.right
margins: 2 * UM.Theme.getSize("default_margin").width
leftMargin: UM.Theme.getSize("default_margin").width
rightMargin: UM.Theme.getSize("default_margin").width / 2
} }
height: UM.Theme.getSize("monitor_text_line").height;
width: parent.width;
Label Rectangle {
{ color: UM.Theme.getColor("monitor_skeleton_fill");
id: targetPrinterLabel height: parent.height;
elide: Text.ElideRight visible: !printJob;
font: UM.Theme.getFont("default_bold") width: Math.round(parent.width / 2);
text:
{
if(printJob.assignedPrinter == null)
{
if(printJob.state == "error")
{
return catalog.i18nc("@label", "Waiting for: Unavailable printer")
} }
return catalog.i18nc("@label", "Waiting for: First available") Label {
} anchors.fill: parent;
else color: UM.Theme.getColor("text");
{ elide: Text.ElideRight;
return catalog.i18nc("@label", "Waiting for: ") + printJob.assignedPrinter.name font: UM.Theme.getFont("default");
} text: printJob ? printJob.owner : ""; // Supress QML warnings
visible: printJob;
}
anchors
{
left: parent.left
right: contextButton.left
rightMargin: UM.Theme.getSize("default_margin").width
} }
} }
Item {
id: printJobPreview;
property var useUltibot: false;
anchors {
bottom: parent.bottom;
horizontalCenter: parent.horizontalCenter;
top: printJobOwnerName.bottom;
topMargin: UM.Theme.getSize("default_margin").height;
}
width: height;
function switchPopupState() // Skeleton
{ Rectangle {
popup.visible ? popup.close() : popup.open() anchors.fill: parent;
color: UM.Theme.getColor("monitor_skeleton_fill");
radius: UM.Theme.getSize("default_margin").width;
visible: !printJob;
} }
Button // Actual content
{ Image {
id: contextButton id: previewImage;
text: "\u22EE" //Unicode; Three stacked points. anchors.fill: parent;
width: 35 opacity: printJob && printJob.state == "error" ? 0.5 : 1.0;
height: width source: printJob ? printJob.previewImageUrl : "";
anchors visible: printJob;
{
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() UM.RecolorImage {
id: ultiBotImage;
anchors.centerIn: printJobPreview;
color: UM.Theme.getColor("monitor_placeholder_image");
height: printJobPreview.height;
source: "../svg/ultibot.svg";
sourceSize {
height: height;
width: width;
}
/* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or
not in order to determine if we show the placeholder (ultibot) image instead. */
visible: printJob && previewImage.status == Image.Error;
width: printJobPreview.width;
} }
Popup UM.RecolorImage {
{ id: statusImage;
// TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property anchors.centerIn: printJobPreview;
id: popup color: UM.Theme.getColor("monitor_image_overlay");
clip: true height: 0.5 * printJobPreview.height;
closePolicy: Popup.CloseOnPressOutside source: printJob && printJob.state == "error" ? "../svg/aborted-icon.svg" : "";
x: (parent.width - width) + 26 * screenScaleFactor sourceSize {
y: contextButton.height - 5 * screenScaleFactor // Because shadow height: height;
width: 182 * screenScaleFactor width: width;
height: contentItem.height + 2 * padding
visible: false
padding: 5 * screenScaleFactor // Because shadow
transformOrigin: Popup.Top
contentItem: Item
{
width: popup.width
height: childrenRect.height + 36 * screenScaleFactor
anchors.topMargin: 10 * screenScaleFactor
anchors.bottomMargin: 10 * screenScaleFactor
Button
{
id: sendToTopButton
text: catalog.i18nc("@label", "Move to top")
onClicked:
{
sendToTopConfirmationDialog.visible = true;
popup.close();
} }
width: parent.width visible: source != "";
enabled: OutputDevice.queuedPrintJobs[0].key != printJob.key width: 0.5 * printJobPreview.width;
visible: enabled
anchors.top: parent.top
anchors.topMargin: 18 * screenScaleFactor
height: visible ? 39 * screenScaleFactor : 0 * screenScaleFactor
hoverEnabled: true
background: Rectangle
{
opacity: sendToTopButton.down || sendToTopButton.hovered ? 1 : 0
color: UM.Theme.getColor("viewport_background")
}
contentItem: Label
{
text: sendToTopButton.text
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
}
MessageDialog
{
id: sendToTopConfirmationDialog
title: catalog.i18nc("@window:title", "Move print job to top")
icon: StandardIcon.Warning
text: catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to move %1 to the top of the queue?").arg(printJob.name)
standardButtons: StandardButton.Yes | StandardButton.No
Component.onCompleted: visible = false
onYes: OutputDevice.sendJobToTop(printJob.key)
}
Button
{
id: deleteButton
text: catalog.i18nc("@label", "Delete")
onClicked:
{
deleteConfirmationDialog.visible = true;
popup.close();
}
width: parent.width
height: 39 * screenScaleFactor
anchors.top: sendToTopButton.bottom
hoverEnabled: true
background: Rectangle
{
opacity: deleteButton.down || deleteButton.hovered ? 1 : 0
color: UM.Theme.getColor("viewport_background")
}
contentItem: Label
{
text: deleteButton.text
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
}
MessageDialog
{
id: deleteConfirmationDialog
title: catalog.i18nc("@window:title", "Delete print job")
icon: StandardIcon.Warning
text: catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to delete %1?").arg(printJob.name)
standardButtons: StandardButton.Yes | StandardButton.No
Component.onCompleted: visible = false
onYes: OutputDevice.deleteJobFromQueue(printJob.key)
}
}
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 // Divider
{ Rectangle {
// This applies a default NumberAnimation to any changes a state change makes to x or y properties anchors {
NumberAnimation { property: "visible"; duration: 75; } horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter;
} }
enter: Transition color: !printJob ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_lining_light");
{ height: parent.height - 2 * UM.Theme.getSize("default_margin").height;
// This applies a default NumberAnimation to any changes a state change makes to x or y properties width: UM.Theme.getSize("default_lining").width;
NumberAnimation { property: "visible"; duration: 75; }
} }
onClosed: visible = false // Right content
onOpened: visible = true Item {
anchors {
bottom: parent.bottom;
left: parent.horizontalCenter;
margins: UM.Theme.getSize("wide_margin").width;
right: parent.right;
top: parent.top;
} }
Row Item {
{ id: targetPrinterLabel;
id: printerFamilyPills height: UM.Theme.getSize("monitor_text_line").height;
spacing: 0.5 * UM.Theme.getSize("default_margin").width width: parent.width;
anchors
{
left: parent.left
right: parent.right
bottom: extrudersInfo.top
bottomMargin: UM.Theme.getSize("default_margin").height
}
height: childrenRect.height
Repeater
{
model: printJob.compatibleMachineFamilies
delegate: PrinterFamilyPill Rectangle {
{ visible: !printJob;
text: modelData color: UM.Theme.getColor("monitor_skeleton_fill");
color: UM.Theme.getColor("viewport_background") anchors.fill: parent;
padding: 3 * screenScaleFactor
}
}
}
// PrintCore && Material config
Row
{
id: extrudersInfo
anchors.bottom: parent.bottom
anchors
{
left: parent.left
right: parent.right
}
height: childrenRect.height
spacing: UM.Theme.getSize("default_margin").width
PrintCoreConfiguration
{
id: leftExtruderInfo
width: Math.round(parent.width / 2) * screenScaleFactor
printCoreConfiguration: printJob.configuration.extruderConfigurations[0]
} }
PrintCoreConfiguration Label {
{ color: UM.Theme.getColor("text");
id: rightExtruderInfo elide: Text.ElideRight;
width: Math.round(parent.width / 2) * screenScaleFactor font: UM.Theme.getFont("default_bold");
printCoreConfiguration: printJob.configuration.extruderConfigurations[1] text: {
if (printJob !== null) {
if (printJob.assignedPrinter == null) {
if (printJob.state == "error") {
return catalog.i18nc("@label", "Waiting for: Unavailable printer");
}
return catalog.i18nc("@label", "Waiting for: First available");
} else {
return catalog.i18nc("@label", "Waiting for: ") + printJob.assignedPrinter.name;
}
}
return "";
}
visible: printJob;
} }
} }
PrinterInfoBlock {
anchors.bottom: parent.bottom;
printer: root.printJon && root.printJob.assignedPrinter;
printJob: root.printJob;
}
} }
Rectangle PrintJobContextMenu {
{ id: contextButton;
color: UM.Theme.getColor("viewport_background") anchors {
width: 2 * screenScaleFactor right: mainContent.right;
anchors.top: parent.top rightMargin: UM.Theme.getSize("default_margin").width * 3 + root.shadowRadius;
anchors.bottom: parent.bottom top: mainContent.top;
anchors.margins: UM.Theme.getSize("default_margin").height topMargin: UM.Theme.getSize("default_margin").height;
anchors.horizontalCenter: parent.horizontalCenter }
printJob: root.printJob;
visible: root.printJob;
}
}
Item {
id: configChangesBox;
height: childrenRect.height;
visible: printJob && printJob.configurationChanges.length !== 0;
width: parent.width;
// Config change toggle
Rectangle {
id: configChangeToggle;
color: {
if (configChangeToggleArea.containsMouse) {
return UM.Theme.getColor("viewport_background"); // TODO: Theme!
} else {
return "transparent";
}
}
width: parent.width;
height: UM.Theme.getSize("default_margin").height * 4; // TODO: Theme!
anchors {
left: parent.left;
right: parent.right;
top: parent.top;
}
Rectangle {
color: !printJob ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_lining_light");
height: UM.Theme.getSize("default_lining").height;
width: parent.width;
}
UM.RecolorImage {
anchors {
right: configChangeToggleLabel.left;
rightMargin: UM.Theme.getSize("default_margin").width;
verticalCenter: parent.verticalCenter;
}
color: UM.Theme.getColor("text");
height: 23 * screenScaleFactor; // TODO: Theme!
source: "../svg/warning-icon.svg";
sourceSize {
height: height;
width: width;
}
width: 23 * screenScaleFactor; // TODO: Theme!
}
Label {
id: configChangeToggleLabel;
anchors {
horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter;
}
color: UM.Theme.getColor("text");
text: catalog.i18nc("@label", "Configuration change");
}
UM.RecolorImage {
anchors {
left: configChangeToggleLabel.right;
leftMargin: UM.Theme.getSize("default_margin").width;
verticalCenter: parent.verticalCenter;
}
color: UM.Theme.getColor("text");
height: 15 * screenScaleFactor; // TODO: Theme!
source: {
if (configChangeDetails.visible) {
return UM.Theme.getIcon("arrow_top");
} else {
return UM.Theme.getIcon("arrow_bottom");
}
}
sourceSize {
width: width;
height: height;
}
width: 15 * screenScaleFactor; // TODO: Theme!
}
MouseArea {
id: configChangeToggleArea;
anchors.fill: parent;
hoverEnabled: true;
onClicked: {
configChangeDetails.visible = !configChangeDetails.visible;
} }
} }
} }
// Config change details
Item {
id: configChangeDetails;
anchors.top: configChangeToggle.bottom;
Behavior on height { NumberAnimation { duration: 100 } }
// In case of really massive multi-line configuration changes
height: visible ? Math.max(UM.Theme.getSize("monitor_config_override_box").height, childrenRect.height) : 0;
visible: false;
width: parent.width;
Item {
anchors {
bottomMargin: UM.Theme.getSize("wide_margin").height;
fill: parent;
leftMargin: UM.Theme.getSize("wide_margin").height * 4;
rightMargin: UM.Theme.getSize("wide_margin").height * 4;
topMargin: UM.Theme.getSize("wide_margin").height;
}
clip: true;
Label {
anchors.fill: parent;
elide: Text.ElideRight;
color: UM.Theme.getColor("text");
font: UM.Theme.getFont("large_nonbold");
text: {
if (!printJob || printJob.configurationChanges.length === 0) {
return "";
}
var topLine;
if (materialsAreKnown(printJob)) {
topLine = catalog.i18nc("@label", "The assigned printer, %1, requires the following configuration change(s):").arg(printJob.assignedPrinter.name);
} else {
topLine = catalog.i18nc("@label", "The printer %1 is assigned, but the job contains an unknown material configuration.").arg(printJob.assignedPrinter.name);
}
var result = "<p>" + topLine +"</p>";
for (var i = 0; i < printJob.configurationChanges.length; i++) {
var change = printJob.configurationChanges[i];
var text;
switch (change.typeOfChange) {
case "material_change":
text = catalog.i18nc("@label", "Change material %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName);
break;
case "material_insert":
text = catalog.i18nc("@label", "Load %3 as material %1 (This cannot be overridden).").arg(change.index + 1).arg(change.targetName);
break;
case "print_core_change":
text = catalog.i18nc("@label", "Change print core %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName);
break;
case "buildplate_change":
text = catalog.i18nc("@label", "Change build plate to %1 (This cannot be overridden).").arg(formatBuildPlateType(change.target_name));
break;
default:
text = "";
}
result += "<p><b>" + text + "</b></p>";
}
return result;
}
wrapMode: Text.WordWrap;
}
Button {
anchors {
bottom: parent.bottom;
left: parent.left;
}
onClicked: {
overrideConfirmationDialog.visible = true;
}
text: catalog.i18nc("@label", "Override");
visible: {
if (printJob && printJob.configurationChanges) {
var length = printJob.configurationChanges.length;
for (var i = 0; i < length; i++) {
var typeOfChange = printJob.configurationChanges[i].typeOfChange;
if (typeOfChange === "material_insert" || typeOfChange === "buildplate_change") {
return false;
}
}
}
return true;
}
}
}
}
MessageDialog {
id: overrideConfirmationDialog;
Component.onCompleted: visible = false;
icon: StandardIcon.Warning;
onYes: OutputDevice.forceSendJob(printJob.key);
standardButtons: StandardButton.Yes | StandardButton.No;
text: {
if (!printJob) {
return "";
}
var printJobName = formatPrintJobName(printJob.name);
var confirmText = catalog.i18nc("@label", "Starting a print job with an incompatible configuration could damage your 3D printer. Are you sure you want to override the configuration and print %1?").arg(printJobName);
return confirmText;
}
title: catalog.i18nc("@window:title", "Override configuration configuration and start print");
}
}
}
}
// Utils
function formatPrintJobName(name) {
var extensions = [ ".gz", ".gcode", ".ufp" ];
for (var i = 0; i < extensions.length; i++) {
var extension = extensions[i];
if (name.slice(-extension.length) === extension) {
name = name.substring(0, name.length - extension.length);
}
}
return name;
}
function materialsAreKnown(job) {
var conf0 = job.configuration[0];
if (conf0 && !conf0.material.material) {
return false;
}
var conf1 = job.configuration[1];
if (conf1 && !conf1.material.material) {
return false;
}
return true;
}
function formatBuildPlateType(buildPlateType) {
var translationText = "";
switch (buildPlateType) {
case "glass":
translationText = catalog.i18nc("@label", "Glass");
break;
case "aluminum":
translationText = catalog.i18nc("@label", "Aluminum");
break;
default:
translationText = null;
}
return translationText;
}
}

View File

@ -0,0 +1,75 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Dialogs 1.1
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4 as LegacyControls
import UM 1.3 as UM
// Includes print job name, owner, and preview
Item {
property var job: null;
property var useUltibot: false;
height: 100 * screenScaleFactor;
width: height;
// Skeleton
Rectangle {
anchors.fill: parent;
color: UM.Theme.getColor("monitor_skeleton_fill");
radius: UM.Theme.getSize("default_margin").width;
visible: !job;
}
// Actual content
Image {
id: previewImage;
visible: job;
source: job ? job.previewImageUrl : "";
opacity: {
if (job == null) {
return 1.0;
}
var states = ["wait_cleanup", "wait_user_action", "error", "paused"];
if (states.indexOf(job.state) !== -1) {
return 0.5;
}
return 1.0;
}
anchors.fill: parent;
}
UM.RecolorImage {
id: ultibotImage;
anchors.centerIn: parent;
color: UM.Theme.getColor("monitor_placeholder_image"); // TODO: Theme!
height: parent.height;
source: "../svg/ultibot.svg";
sourceSize {
height: height;
width: width;
}
/* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or
not in order to determine if we show the placeholder (ultibot) image instead. */
visible: job && previewImage.status == Image.Error;
width: parent.width;
}
UM.RecolorImage {
id: statusImage;
anchors.centerIn: parent;
color: "black"; // TODO: Theme!
height: Math.round(0.5 * parent.height);
source: job && job.state == "error" ? "../svg/aborted-icon.svg" : "";
sourceSize {
height: height;
width: width;
}
visible: source != "";
width: Math.round(0.5 * parent.width);
}
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Controls 2.0
import UM 1.3 as UM
Column {
property var job: null;
height: childrenRect.height;
spacing: Math.floor( UM.Theme.getSize("default_margin").height / 2); // TODO: Use explicit theme size
width: parent.width;
Item {
id: jobName;
height: UM.Theme.getSize("monitor_text_line").height;
width: parent.width;
// Skeleton loading
Rectangle {
color: UM.Theme.getColor("monitor_skeleton_fill");
height: parent.height;
visible: !job;
width: Math.round(parent.width / 3);
}
Label {
anchors.fill: parent;
color: UM.Theme.getColor("text");
elide: Text.ElideRight;
font: UM.Theme.getFont("default_bold");
text: job && job.name ? job.name : "";
visible: job;
}
}
Item {
id: ownerName;
height: UM.Theme.getSize("monitor_text_line").height;
width: parent.width;
// Skeleton loading
Rectangle {
color: UM.Theme.getColor("monitor_skeleton_fill");
height: parent.height;
visible: !job;
width: Math.round(parent.width / 2);
}
Label {
anchors.fill: parent;
color: UM.Theme.getColor("text")
elide: Text.ElideRight;
font: UM.Theme.getFont("default");
text: job ? job.owner : "";
visible: job;
}
}
}

View File

@ -4,112 +4,101 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Window 2.2 import QtQuick.Window 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import UM 1.1 as UM import UM 1.1 as UM
UM.Dialog UM.Dialog {
{
id: base; id: base;
property var printersModel: {
minimumWidth: 500 * screenScaleFactor return ListModel{};
minimumHeight: 140 * screenScaleFactor
maximumWidth: minimumWidth
maximumHeight: minimumHeight
width: minimumWidth
height: minimumHeight
visible: true
modality: Qt.ApplicationModal
onVisibleChanged:
{
if(visible)
{
resetPrintersModel()
} }
else height: minimumHeight;
{
OutputDevice.cancelPrintSelection()
}
}
title: catalog.i18nc("@title:window", "Print over network")
property var printersModel: ListModel{}
function resetPrintersModel() {
printersModel.clear()
printersModel.append({ name: "Automatic", key: ""})
for (var index in OutputDevice.printers)
{
printersModel.append({name: OutputDevice.printers[index].name, key: OutputDevice.printers[index].key})
}
}
Column
{
id: printerSelection
anchors.fill: parent
anchors.top: parent.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.rightMargin: UM.Theme.getSize("default_margin").width
height: 50 * screenScaleFactor
Label
{
id: manualPrinterSelectionLabel
anchors
{
left: parent.left
topMargin: UM.Theme.getSize("default_margin").height
right: parent.right
}
text: catalog.i18nc("@label", "Printer selection")
wrapMode: Text.Wrap
height: 20 * screenScaleFactor
}
ComboBox
{
id: printerSelectionCombobox
model: base.printersModel
textRole: "name"
width: parent.width
height: 40 * screenScaleFactor
Behavior on height { NumberAnimation { duration: 100 } }
}
SystemPalette
{
id: palette
}
UM.I18nCatalog { id: catalog; name: "cura"; }
}
leftButtons: [ leftButtons: [
Button Button {
{ enabled: true;
text: catalog.i18nc("@action:button","Cancel")
enabled: true
onClicked: { onClicked: {
base.visible = false; base.visible = false;
printerSelectionCombobox.currentIndex = 0 printerSelectionCombobox.currentIndex = 0;
OutputDevice.cancelPrintSelection() OutputDevice.cancelPrintSelection();
} }
text: catalog.i18nc("@action:button","Cancel");
} }
] ]
maximumHeight: minimumHeight;
maximumWidth: minimumWidth;
minimumHeight: 140 * screenScaleFactor;
minimumWidth: 500 * screenScaleFactor;
modality: Qt.ApplicationModal;
onVisibleChanged: {
if (visible) {
resetPrintersModel();
} else {
OutputDevice.cancelPrintSelection();
}
}
rightButtons: [ rightButtons: [
Button Button {
{ enabled: true;
text: catalog.i18nc("@action:button","Print")
enabled: true
onClicked: { onClicked: {
base.visible = false; base.visible = false;
OutputDevice.selectPrinter(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key) OutputDevice.selectPrinter(printerSelectionCombobox.model.get(printerSelectionCombobox.currentIndex).key);
// reset to defaults // reset to defaults
printerSelectionCombobox.currentIndex = 0 printerSelectionCombobox.currentIndex = 0;
} }
text: catalog.i18nc("@action:button","Print");
} }
] ]
title: catalog.i18nc("@title:window", "Print over network");
visible: true;
width: minimumWidth;
Column {
id: printerSelection;
anchors {
fill: parent;
leftMargin: UM.Theme.getSize("default_margin").width;
rightMargin: UM.Theme.getSize("default_margin").width;
top: parent.top;
topMargin: UM.Theme.getSize("default_margin").height;
}
height: 50 * screenScaleFactor;
SystemPalette {
id: palette;
}
UM.I18nCatalog {
id: catalog;
name: "cura";
}
Label {
id: manualPrinterSelectionLabel;
anchors {
left: parent.left;
right: parent.right;
topMargin: UM.Theme.getSize("default_margin").height;
}
height: 20 * screenScaleFactor;
text: catalog.i18nc("@label", "Printer selection");
wrapMode: Text.Wrap;
}
ComboBox {
id: printerSelectionCombobox;
Behavior on height { NumberAnimation { duration: 100 } }
height: 40 * screenScaleFactor;
model: base.printersModel;
textRole: "name";
width: parent.width;
}
}
// Utils
function resetPrintersModel() {
printersModel.clear();
printersModel.append({ name: "Automatic", key: ""});
for (var index in OutputDevice.printers) {
printersModel.append({name: OutputDevice.printers[index].name, key: OutputDevice.printers[index].key});
}
}
} }

View File

@ -0,0 +1,236 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Dialogs 1.1
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import UM 1.3 as UM
Item {
id: root;
property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width;
property var shadowOffset: UM.Theme.getSize("monitor_shadow_offset").width;
property var printer: null;
property var collapsed: true;
height: childrenRect.height + shadowRadius * 2; // Bubbles upward
width: parent.width; // Bubbles downward
// The actual card (white block)
Rectangle {
// 5px margin, but shifted 2px vertically because of the shadow
anchors {
bottomMargin: root.shadowRadius + root.shadowOffset;
leftMargin: root.shadowRadius;
rightMargin: root.shadowRadius;
topMargin: root.shadowRadius - root.shadowOffset;
}
color: {
if (!printer) {
return UM.Theme.getColor("monitor_card_background_inactive");
}
if (printer.state == "disabled") {
return UM.Theme.getColor("monitor_card_background_inactive");
} else {
return UM.Theme.getColor("monitor_card_background");
}
}
height: childrenRect.height;
layer.effect: DropShadow {
radius: root.shadowRadius;
verticalOffset: root.shadowOffset;
color: "#3F000000"; // 25% shadow
}
layer.enabled: true
width: parent.width - 2 * shadowRadius;
Column {
height: childrenRect.height;
width: parent.width;
// Main card
Item {
id: mainCard;
height: 60 * screenScaleFactor + 2 * UM.Theme.getSize("default_margin").width;
width: parent.width;
// Machine icon
Item {
id: machineIcon;
anchors {
leftMargin: UM.Theme.getSize("wide_margin").width;
top: parent.top;
left: parent.left;
margins: UM.Theme.getSize("default_margin").width;
}
height: parent.height - 2 * UM.Theme.getSize("default_margin").width;
width: height;
// Skeleton
Rectangle {
anchors.fill: parent;
color: UM.Theme.getColor("monitor_skeleton_fill_dark");
radius: UM.Theme.getSize("default_margin").width;
visible: !printer;
}
// Content
UM.RecolorImage {
anchors.centerIn: parent;
color: {
if (printer && printer.activePrintJob != undefined) {
return UM.Theme.getColor("monitor_printer_icon");
}
return UM.Theme.getColor("monitor_printer_icon_inactive");
}
height: sourceSize.height;
source: {
if (!printer) {
return "";
}
switch(printer.type) {
case "Ultimaker 3":
return "../svg/UM3-icon.svg";
case "Ultimaker 3 Extended":
return "../svg/UM3x-icon.svg";
case "Ultimaker S5":
return "../svg/UMs5-icon.svg";
}
}
visible: printer;
width: sourceSize.width;
}
}
// Printer info
Item {
id: printerInfo;
anchors {
left: machineIcon.right;
leftMargin: UM.Theme.getSize("default_margin").width;
right: collapseIcon.left;
verticalCenter: machineIcon.verticalCenter;
}
height: childrenRect.height;
// Machine name
Item {
id: machineNameLabel;
height: UM.Theme.getSize("monitor_text_line").height;
width: Math.round(parent.width * 0.3);
// Skeleton
Rectangle {
anchors.fill: parent;
color: UM.Theme.getColor("monitor_skeleton_fill_dark");
visible: !printer;
}
// Actual content
Label {
anchors.fill: parent;
color: UM.Theme.getColor("text");
elide: Text.ElideRight;
font: UM.Theme.getFont("default_bold");
text: printer ? printer.name : "";
visible: printer;
width: parent.width;
}
}
// Job name
Item {
id: activeJobLabel;
anchors {
top: machineNameLabel.bottom;
topMargin: Math.round(UM.Theme.getSize("default_margin").height / 2);
}
height: UM.Theme.getSize("monitor_text_line").height;
width: Math.round(parent.width * 0.75);
// Skeleton
Rectangle {
anchors.fill: parent;
color: UM.Theme.getColor("monitor_skeleton_fill_dark");
visible: !printer;
}
// Actual content
Label {
anchors.fill: parent;
color: UM.Theme.getColor("monitor_text_inactive");
elide: Text.ElideRight;
font: UM.Theme.getFont("default");
text: {
if (!printer) {
return "";
}
if (printer.state == "disabled") {
return catalog.i18nc("@label", "Not available");
} else if (printer.state == "unreachable") {
return catalog.i18nc("@label", "Unreachable");
}
if (printer.activePrintJob != null && printer.activePrintJob.name) {
return printer.activePrintJob.name;
}
return catalog.i18nc("@label", "Available");
}
visible: printer;
}
}
}
// Collapse icon
UM.RecolorImage {
id: collapseIcon;
anchors {
right: parent.right;
rightMargin: UM.Theme.getSize("default_margin").width;
verticalCenter: parent.verticalCenter;
}
color: UM.Theme.getColor("text");
height: 15 * screenScaleFactor; // TODO: Theme!
source: root.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom");
sourceSize {
height: height;
width: width;
}
visible: printer;
width: 15 * screenScaleFactor; // TODO: Theme!
}
MouseArea {
anchors.fill: parent;
enabled: printer;
onClicked: {
if (model && root.collapsed) {
printerList.currentIndex = model.index;
} else {
printerList.currentIndex = -1;
}
}
}
Connections {
target: printerList;
onCurrentIndexChanged: {
root.collapsed = printerList.currentIndex != model.index;
}
}
}
// Detailed card
PrinterCardDetails {
collapsed: root.collapsed;
printer: root.printer;
visible: root.printer;
}
// Progress bar
PrinterCardProgressBar {
visible: printer && printer.activePrintJob != null;
}
}
}
}

View File

@ -0,0 +1,84 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Dialogs 1.1
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4 as LegacyControls
import UM 1.3 as UM
Item {
id: root;
property var printer: null;
property var printJob: printer ? printer.activePrintJob : null;
property var collapsed: true;
Behavior on height { NumberAnimation { duration: 100 } }
Behavior on opacity { NumberAnimation { duration: 100 } }
height: collapsed ? 0 : childrenRect.height;
opacity: collapsed ? 0 : 1;
width: parent.width;
Column {
id: contentColumn;
anchors {
left: parent.left;
leftMargin: UM.Theme.getSize("default_margin").width;
right: parent.right;
rightMargin: UM.Theme.getSize("default_margin").width;
}
height: childrenRect.height + UM.Theme.getSize("wide_margin").height;
spacing: UM.Theme.getSize("default_margin").height;
width: parent.width;
HorizontalLine {}
PrinterInfoBlock {
printer: root.printer;
printJob: root.printer ? root.printer.activePrintJob : null;
}
HorizontalLine {
visible: root.printJob;
}
Row {
height: childrenRect.height;
visible: root.printJob;
width: parent.width;
PrintJobTitle {
job: root.printer ? root.printer.activePrintJob : null;
}
PrintJobContextMenu {
id: contextButton;
anchors {
right: parent.right;
rightMargin: UM.Theme.getSize("wide_margin").width;
}
printJob: root.printer ? root.printer.activePrintJob : null;
visible: printJob;
}
}
PrintJobPreview {
anchors.horizontalCenter: parent.horizontalCenter;
job: root.printer && root.printer.activePrintJob ? root.printer.activePrintJob : null;
visible: root.printJob;
}
}
CameraButton {
id: showCameraButton;
anchors {
bottom: contentColumn.bottom;
bottomMargin: Math.round(1.5 * UM.Theme.getSize("default_margin").height);
left: contentColumn.left;
leftMargin: Math.round(0.5 * UM.Theme.getSize("default_margin").width);
}
iconSource: "../svg/camera-icon.svg";
visible: root.printJob;
}
}

View File

@ -0,0 +1,108 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Controls.Styles 1.3
import QtQuick.Controls 1.4
import UM 1.3 as UM
ProgressBar {
property var progress: {
if (!printer || printer.activePrintJob == null) {
return 0;
}
var result = printer.activePrintJob.timeElapsed / printer.activePrintJob.timeTotal;
if (result > 1.0) {
result = 1.0;
}
return result;
}
style: ProgressBarStyle {
property var remainingTime: {
if (!printer || printer.activePrintJob == null) {
return 0;
}
/* Sometimes total minus elapsed is less than 0. Use Math.max() to prevent remaining
time from ever being less than 0. Negative durations cause strange behavior such
as displaying "-1h -1m". */
return Math.max(printer.activePrintJob.timeTotal - printer.activePrintJob.timeElapsed, 0);
}
property var progressText: {
if (printer === null ) {
return "";
}
switch (printer.activePrintJob.state) {
case "wait_cleanup":
if (printer.activePrintJob.timeTotal > printer.activePrintJob.timeElapsed) {
return catalog.i18nc("@label:status", "Aborted");
}
return catalog.i18nc("@label:status", "Finished");
case "pre_print":
case "sent_to_printer":
return catalog.i18nc("@label:status", "Preparing");
case "aborted":
return catalog.i18nc("@label:status", "Aborted");
case "wait_user_action":
return catalog.i18nc("@label:status", "Aborted");
case "pausing":
return catalog.i18nc("@label:status", "Pausing");
case "paused":
return OutputDevice.formatDuration( remainingTime );
case "resuming":
return catalog.i18nc("@label:status", "Resuming");
case "queued":
return catalog.i18nc("@label:status", "Action required");
default:
return OutputDevice.formatDuration( remainingTime );
}
}
background: Rectangle {
color: UM.Theme.getColor("monitor_progress_background");
implicitHeight: visible ? 24 : 0;
implicitWidth: 100;
}
progress: Rectangle {
id: progressItem;
color: {
if (! printer || !printer.activePrintJob) {
return "black";
}
var state = printer.activePrintJob.state
var inactiveStates = [
"pausing",
"paused",
"resuming",
"wait_cleanup"
];
if (inactiveStates.indexOf(state) > -1 && remainingTime > 0) {
return UM.Theme.getColor("monitor_progress_fill_inactive");
} else {
return UM.Theme.getColor("monitor_progress_fill");
}
}
Label {
id: progressLabel;
anchors {
left: parent.left;
leftMargin: getTextOffset();
}
text: progressText;
anchors.verticalCenter: parent.verticalCenter;
color: progressItem.width + progressLabel.width < control.width ? UM.Theme.getColor("text") : UM.Theme.getColor("monitor_progress_fill_text");
width: contentWidth;
font: UM.Theme.getFont("default");
}
function getTextOffset() {
if (progressItem.width + progressLabel.width + 16 < control.width) {
return progressItem.width + UM.Theme.getSize("default_margin").width;
} else {
return progressItem.width - progressLabel.width - UM.Theme.getSize("default_margin").width;
}
}
}
}
value: progress;
width: parent.width;
}

View File

@ -1,28 +1,32 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import UM 1.2 as UM import UM 1.2 as UM
Item Item {
{ property alias text: familyNameLabel.text;
property alias color: background.color property var padding: 3 * screenScaleFactor; // TODO: Theme!
property alias text: familyNameLabel.text implicitHeight: familyNameLabel.contentHeight + 2 * padding; // Apply the padding to top and bottom.
property var padding: 0 implicitWidth: Math.max(48 * screenScaleFactor, familyNameLabel.contentWidth + implicitHeight); // The extra height is added to ensure the radius doesn't cut something off.
implicitHeight: familyNameLabel.contentHeight + 2 * padding // Apply the padding to top and bottom.
implicitWidth: familyNameLabel.contentWidth + implicitHeight // The extra height is added to ensure the radius doesn't cut something off. Rectangle {
Rectangle id: background;
{ anchors {
id: background horizontalCenter: parent.horizontalCenter;
height: parent.height right: parent.right;
width: parent.width
color: parent.color
anchors.right: parent.right
anchors.horizontalCenter: parent.horizontalCenter
radius: 0.5 * height
} }
Label color: familyNameLabel.text.length < 1 ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_pill_background");
{ height: parent.height;
id: familyNameLabel radius: 0.5 * height;
anchors.centerIn: parent width: parent.width;
text: "" }
Label {
id: familyNameLabel;
anchors.centerIn: parent;
color: UM.Theme.getColor("text");
text: "";
} }
} }

View File

@ -0,0 +1,83 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.3
import QtQuick.Dialogs 1.1
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4 as LegacyControls
import UM 1.3 as UM
// Includes printer type pill and extuder configurations
Item {
id: root;
property var printer: null;
property var printJob: null;
width: parent.width;
height: childrenRect.height;
// Printer family pills
Row {
id: printerFamilyPills;
anchors {
left: parent.left;
right: parent.right;
}
height: childrenRect.height;
spacing: Math.round(0.5 * UM.Theme.getSize("default_margin").width);
width: parent.width;
Repeater {
id: compatiblePills;
delegate: PrinterFamilyPill {
text: modelData;
}
model: printJob ? printJob.compatibleMachineFamilies : [];
visible: printJob;
}
PrinterFamilyPill {
text: printer ? printer.type : "";
visible: !compatiblePills.visible && printer;
}
}
// Extruder info
Row {
id: extrudersInfo;
anchors {
left: parent.left;
right: parent.right;
rightMargin: UM.Theme.getSize("default_margin").width;
top: printerFamilyPills.bottom;
topMargin: UM.Theme.getSize("default_margin").height;
}
height: childrenRect.height;
spacing: UM.Theme.getSize("default_margin").width;
width: parent.width;
PrintCoreConfiguration {
width: Math.round(parent.width / 2) * screenScaleFactor;
printCoreConfiguration: getExtruderConfig(0);
}
PrintCoreConfiguration {
width: Math.round(parent.width / 2) * screenScaleFactor;
printCoreConfiguration: getExtruderConfig(1);
}
}
function getExtruderConfig( i ) {
if (root.printJob) {
// Use more-specific print job if possible
return root.printJob.configuration.extruderConfigurations[i];
}
if (root.printer) {
return root.printer.printerConfiguration.extruderConfigurations[i];
}
return null;
}
}

View File

@ -1,84 +1,69 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.4 import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Styles 1.4
import UM 1.3 as UM import UM 1.3 as UM
Item {
property var camera: null;
Item Rectangle {
{ anchors.fill:parent;
property var camera: null color: UM.Theme.getColor("viewport_overlay");
opacity: 0.5;
Rectangle
{
anchors.fill:parent
color: UM.Theme.getColor("viewport_overlay")
opacity: 0.5
} }
MouseArea MouseArea {
{ anchors.fill: parent;
anchors.fill: parent onClicked: OutputDevice.setActiveCamera(null);
onClicked: OutputDevice.setActiveCamera(null) z: 0;
z: 0
} }
CameraButton CameraButton {
{ id: closeCameraButton;
id: closeCameraButton anchors {
iconSource: UM.Theme.getIcon("cross1")
anchors
{
top: cameraImage.top
topMargin: UM.Theme.getSize("default_margin").height
right: cameraImage.right right: cameraImage.right
rightMargin: UM.Theme.getSize("default_margin").width rightMargin: UM.Theme.getSize("default_margin").width
top: cameraImage.top
topMargin: UM.Theme.getSize("default_margin").height
} }
z: 999 iconSource: UM.Theme.getIcon("cross1");
z: 999;
} }
Image Image {
{
id: cameraImage id: cameraImage
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth) anchors.horizontalCenter: parent.horizontalCenter;
height: Math.round((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width) anchors.verticalCenter: parent.verticalCenter;
anchors.horizontalCenter: parent.horizontalCenter height: Math.round((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width);
anchors.verticalCenter: parent.verticalCenter onVisibleChanged: {
z: 1 if (visible) {
onVisibleChanged: if (camera != null) {
{ camera.start();
if(visible)
{
if(camera != null)
{
camera.start()
} }
} else } else {
{ if (camera != null) {
if(camera != null) camera.stop();
{
camera.stop()
} }
} }
} }
source: {
source: if (camera != null && camera.latestImage != null) {
{
if(camera != null && camera.latestImage != null)
{
return camera.latestImage; return camera.latestImage;
} }
return ""; return "";
} }
} width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth);
MouseArea
{
anchors.fill: cameraImage
onClicked:
{
OutputDevice.setActiveCamera(null)
}
z: 1 z: 1
} }
MouseArea {
anchors.fill: cameraImage;
onClicked: {
OutputDevice.setActiveCamera(null);
}
z: 1;
}
} }

View File

@ -1,125 +1,126 @@
import UM 1.2 as UM // Copyright (c) 2018 Ultimaker B.V.
import Cura 1.0 as Cura // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import UM 1.2 as UM
import Cura 1.0 as Cura
Item Item {
{ id: base;
id: base property string activeQualityDefinitionId: Cura.MachineManager.activeQualityDefinitionId;
property bool isUM3: activeQualityDefinitionId == "ultimaker3" || activeQualityDefinitionId.match("ultimaker_") != null;
property bool printerConnected: Cura.MachineManager.printerConnected;
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands;
property bool authenticationRequested: printerConnected && (Cura.MachineManager.printerOutputDevices[0].authenticationState == 2 || Cura.MachineManager.printerOutputDevices[0].authenticationState == 5); // AuthState.AuthenticationRequested or AuthenticationReceived.
property string activeQualityDefinitionId: Cura.MachineManager.activeQualityDefinitionId UM.I18nCatalog {
property bool isUM3: activeQualityDefinitionId == "ultimaker3" || activeQualityDefinitionId.match("ultimaker_") != null id: catalog;
property bool printerConnected: Cura.MachineManager.printerConnected name: "cura";
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
property bool authenticationRequested: printerConnected && (Cura.MachineManager.printerOutputDevices[0].authenticationState == 2 || Cura.MachineManager.printerOutputDevices[0].authenticationState == 5) // AuthState.AuthenticationRequested or AuthenticationReceived.
Row
{
objectName: "networkPrinterConnectButton"
visible: isUM3
spacing: UM.Theme.getSize("default_margin").width
Button
{
height: UM.Theme.getSize("save_button_save_to_button").height
tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer")
text: catalog.i18nc("@action:button", "Request Access")
style: UM.Theme.styles.sidebar_action_button
onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication()
visible: printerConnected && !printerAcceptsCommands && !authenticationRequested
} }
Button Row {
{ objectName: "networkPrinterConnectButton";
height: UM.Theme.getSize("save_button_save_to_button").height spacing: UM.Theme.getSize("default_margin").width;
tooltip: catalog.i18nc("@info:tooltip", "Connect to a printer") visible: isUM3;
text: catalog.i18nc("@action:button", "Connect")
style: UM.Theme.styles.sidebar_action_button Button {
onClicked: connectActionDialog.show() height: UM.Theme.getSize("save_button_save_to_button").height;
visible: !printerConnected onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication();
style: UM.Theme.styles.sidebar_action_button;
text: catalog.i18nc("@action:button", "Request Access");
tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer");
visible: printerConnected && !printerAcceptsCommands && !authenticationRequested;
}
Button {
height: UM.Theme.getSize("save_button_save_to_button").height;
onClicked: connectActionDialog.show();
style: UM.Theme.styles.sidebar_action_button;
text: catalog.i18nc("@action:button", "Connect");
tooltip: catalog.i18nc("@info:tooltip", "Connect to a printer");
visible: !printerConnected;
} }
} }
UM.Dialog UM.Dialog {
{ id: connectActionDialog;
id: connectActionDialog rightButtons: Button {
Loader iconName: "dialog-close";
{ onClicked: connectActionDialog.reject();
anchors.fill: parent text: catalog.i18nc("@action:button", "Close");
source: "DiscoverUM3Action.qml"
} }
rightButtons: Button
{ Loader {
text: catalog.i18nc("@action:button", "Close") anchors.fill: parent;
iconName: "dialog-close" source: "DiscoverUM3Action.qml";
onClicked: connectActionDialog.reject()
} }
} }
Column {
anchors.fill: parent;
objectName: "networkPrinterConnectionInfo";
spacing: UM.Theme.getSize("default_margin").width;
visible: isUM3;
Column Button {
{ onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication();
objectName: "networkPrinterConnectionInfo" text: catalog.i18nc("@action:button", "Request Access");
visible: isUM3 tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer");
spacing: UM.Theme.getSize("default_margin").width visible: printerConnected && !printerAcceptsCommands && !authenticationRequested;
anchors.fill: parent
Button
{
tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer")
text: catalog.i18nc("@action:button", "Request Access")
onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication()
visible: printerConnected && !printerAcceptsCommands && !authenticationRequested
} }
Row Row {
{ anchors {
visible: printerConnected left: parent.left;
spacing: UM.Theme.getSize("default_margin").width right: parent.right;
}
height: childrenRect.height;
spacing: UM.Theme.getSize("default_margin").width;
visible: printerConnected;
anchors.left: parent.left Column {
anchors.right: parent.right Repeater {
height: childrenRect.height model: Cura.ExtrudersModel {
simpleNames: true;
}
Column Label {
{ text: model.name;
Repeater
{
model: Cura.ExtrudersModel { simpleNames: true }
Label { text: model.name }
}
}
Column
{
Repeater
{
id: nozzleColumn
model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].hotendIds : null
Label { text: nozzleColumn.model[index] }
}
}
Column
{
Repeater
{
id: materialColumn
model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].materialNames : null
Label { text: materialColumn.model[index] }
} }
} }
} }
Button Column {
{ Repeater {
tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura") id: nozzleColumn;
text: catalog.i18nc("@action:button", "Activate Configuration") model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].hotendIds : null;
visible: false // printerConnected && !isClusterPrinter()
onClicked: manager.loadConfigurationFromPrinter() Label {
text: nozzleColumn.model[index];
}
} }
} }
UM.I18nCatalog{id: catalog; name:"cura"} Column {
Repeater {
id: materialColumn;
model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].materialNames : null;
Label {
text: materialColumn.model[index];
}
}
}
}
Button {
onClicked: manager.loadConfigurationFromPrinter();
text: catalog.i18nc("@action:button", "Activate Configuration");
tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura");
visible: false; // printerConnected && !isClusterPrinter()
}
}
} }

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1 +1,4 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><title>warning-icon</title><path d="M18.09,1.31A2.35,2.35,0,0,0,16,0a2.31,2.31,0,0,0-2.09,1.31L.27,28.44A2.49,2.49,0,0,0,.11,30.3a2.38,2.38,0,0,0,1.16,1.42A2.33,2.33,0,0,0,2.36,32H29.64A2.4,2.4,0,0,0,32,29.57a2.55,2.55,0,0,0-.27-1.14ZM3.34,29,16,3.83,28.66,29Z"/><polygon points="13.94 25.19 13.94 25.19 13.94 25.19 13.94 25.19"/><polygon points="14.39 21.68 17.61 21.68 18.11 11.85 13.89 11.85 14.39 21.68"/><path d="M16.06,23.08a2.19,2.19,0,0,0-1.56,3.66,2.14,2.14,0,0,0,1.56.55,2.06,2.06,0,0,0,1.54-.55,2.1,2.1,0,0,0,.55-1.55,2.17,2.17,0,0,0-.53-1.55A2.05,2.05,0,0,0,16.06,23.08Z"/></svg> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title>warning-icon</title>
<path d="M18.09,1.31A2.35,2.35,0,0,0,16,0a2.31,2.31,0,0,0-2.09,1.31L.27,28.44A2.49,2.49,0,0,0,.11,30.3a2.38,2.38,0,0,0,1.16,1.42A2.33,2.33,0,0,0,2.36,32H29.64A2.4,2.4,0,0,0,32,29.57a2.55,2.55,0,0,0-.27-1.14ZM3.34,29,16,3.83,28.66,29Z"/><polygon points="13.94 25.19 13.94 25.19 13.94 25.19 13.94 25.19"/><polygon points="14.39 21.68 17.61 21.68 18.11 11.85 13.89 11.85 14.39 21.68"/><path d="M16.06,23.08a2.19,2.19,0,0,0-1.56,3.66,2.14,2.14,0,0,0,1.56.55,2.06,2.06,0,0,0,1.54-.55,2.1,2.1,0,0,0,.55-1.55,2.17,2.17,0,0,0-.53-1.55A2.05,2.05,0,0,0,16.06,23.08Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 684 B

After

Width:  |  Height:  |  Size: 695 B

View File

@ -21,12 +21,13 @@ from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
from cura.PrinterOutput.NetworkCamera import NetworkCamera from cura.PrinterOutput.NetworkCamera import NetworkCamera
from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController
from .SendMaterialJob import SendMaterialJob from .SendMaterialJob import SendMaterialJob
from .ConfigurationChangeModel import ConfigurationChangeModel
from .UM3PrintJobOutputModel import UM3PrintJobOutputModel
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
from PyQt5.QtGui import QDesktopServices, QImage from PyQt5.QtGui import QDesktopServices, QImage
@ -47,6 +48,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
printJobsChanged = pyqtSignal() printJobsChanged = pyqtSignal()
activePrinterChanged = pyqtSignal() activePrinterChanged = pyqtSignal()
activeCameraChanged = pyqtSignal() activeCameraChanged = pyqtSignal()
receivedPrintJobsChanged = pyqtSignal()
# This is a bit of a hack, as the notify can only use signals that are defined by the class that they are in. # This is a bit of a hack, as the notify can only use signals that are defined by the class that they are in.
# Inheritance doesn't seem to work. Tying them together does work, but i'm open for better suggestions. # Inheritance doesn't seem to work. Tying them together does work, but i'm open for better suggestions.
@ -60,7 +62,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self._dummy_lambdas = ("", {}, io.BytesIO()) #type: Tuple[str, Dict, Union[io.StringIO, io.BytesIO]] self._dummy_lambdas = ("", {}, io.BytesIO()) #type: Tuple[str, Dict, Union[io.StringIO, io.BytesIO]]
self._print_jobs = [] # type: List[PrintJobOutputModel] self._print_jobs = [] # type: List[UM3PrintJobOutputModel]
self._received_print_jobs = False # type: bool
self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterMonitorItem.qml") self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterMonitorItem.qml")
self._control_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterControlItem.qml") self._control_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterControlItem.qml")
@ -90,7 +93,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self._printer_uuid_to_unique_name_mapping = {} # type: Dict[str, str] self._printer_uuid_to_unique_name_mapping = {} # type: Dict[str, str]
self._finished_jobs = [] # type: List[PrintJobOutputModel] self._finished_jobs = [] # type: List[UM3PrintJobOutputModel]
self._cluster_size = int(properties.get(b"cluster_size", 0)) # type: int self._cluster_size = int(properties.get(b"cluster_size", 0)) # type: int
@ -349,15 +352,19 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers")) QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
@pyqtProperty("QVariantList", notify = printJobsChanged) @pyqtProperty("QVariantList", notify = printJobsChanged)
def printJobs(self)-> List[PrintJobOutputModel]: def printJobs(self)-> List[UM3PrintJobOutputModel]:
return self._print_jobs return self._print_jobs
@pyqtProperty(bool, notify = receivedPrintJobsChanged)
def receivedPrintJobs(self) -> bool:
return self._received_print_jobs
@pyqtProperty("QVariantList", notify = printJobsChanged) @pyqtProperty("QVariantList", notify = printJobsChanged)
def queuedPrintJobs(self) -> List[PrintJobOutputModel]: def queuedPrintJobs(self) -> List[UM3PrintJobOutputModel]:
return [print_job for print_job in self._print_jobs if print_job.state == "queued" or print_job.state == "error"] return [print_job for print_job in self._print_jobs if print_job.state == "queued" or print_job.state == "error"]
@pyqtProperty("QVariantList", notify = printJobsChanged) @pyqtProperty("QVariantList", notify = printJobsChanged)
def activePrintJobs(self) -> List[PrintJobOutputModel]: def activePrintJobs(self) -> List[UM3PrintJobOutputModel]:
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"] return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"]
@pyqtProperty("QVariantList", notify = clusterPrintersChanged) @pyqtProperty("QVariantList", notify = clusterPrintersChanged)
@ -406,6 +413,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
# is a modification of the cluster queue and not of the actual job. # is a modification of the cluster queue and not of the actual job.
self.delete("print_jobs/{uuid}".format(uuid = print_job_uuid), on_finished=None) self.delete("print_jobs/{uuid}".format(uuid = print_job_uuid), on_finished=None)
@pyqtSlot(str)
def forceSendJob(self, print_job_uuid: str) -> None:
data = "{\"force\": true}"
self.put("print_jobs/{uuid}".format(uuid=print_job_uuid), data, on_finished=None)
def _printJobStateChanged(self) -> None: def _printJobStateChanged(self) -> None:
username = self._getUserName() username = self._getUserName()
@ -455,6 +467,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self.get("print_jobs/{uuid}/preview_image".format(uuid=print_job.key), on_finished=self._onGetPreviewImageFinished) self.get("print_jobs/{uuid}/preview_image".format(uuid=print_job.key), on_finished=self._onGetPreviewImageFinished)
def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None: def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None:
self._received_print_jobs = True
self.receivedPrintJobsChanged.emit()
if not checkValidGetReply(reply): if not checkValidGetReply(reply):
return return
@ -537,8 +552,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self._printers.append(printer) self._printers.append(printer)
return printer return printer
def _createPrintJobModel(self, data: Dict[str, Any]) -> PrintJobOutputModel: def _createPrintJobModel(self, data: Dict[str, Any]) -> UM3PrintJobOutputModel:
print_job = PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self), print_job = UM3PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
key=data["uuid"], name= data["name"]) key=data["uuid"], name= data["name"])
configuration = ConfigurationModel() configuration = ConfigurationModel()
@ -558,7 +573,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
print_job.stateChanged.connect(self._printJobStateChanged) print_job.stateChanged.connect(self._printJobStateChanged)
return print_job return print_job
def _updatePrintJob(self, print_job: PrintJobOutputModel, data: Dict[str, Any]) -> None: def _updatePrintJob(self, print_job: UM3PrintJobOutputModel, data: Dict[str, Any]) -> None:
print_job.updateTimeTotal(data["time_total"]) print_job.updateTimeTotal(data["time_total"])
print_job.updateTimeElapsed(data["time_elapsed"]) print_job.updateTimeElapsed(data["time_elapsed"])
impediments_to_printing = data.get("impediments_to_printing", []) impediments_to_printing = data.get("impediments_to_printing", [])
@ -574,6 +589,16 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
if not status_set_by_impediment: if not status_set_by_impediment:
print_job.updateState(data["status"]) print_job.updateState(data["status"])
print_job.updateConfigurationChanges(self._createConfigurationChanges(data["configuration_changes_required"]))
def _createConfigurationChanges(self, data: List[Dict[str, Any]]) -> List[ConfigurationChangeModel]:
result = []
for change in data:
result.append(ConfigurationChangeModel(type_of_change=change["type_of_change"],
index=change["index"],
target_name=change["target_name"],
origin_name=change["origin_name"]))
return result
def _createMaterialOutputModel(self, material_data) -> MaterialOutputModel: def _createMaterialOutputModel(self, material_data) -> MaterialOutputModel:
containers = ContainerRegistry.getInstance().findInstanceContainers(type="material", GUID=material_data["guid"]) containers = ContainerRegistry.getInstance().findInstanceContainers(type="material", GUID=material_data["guid"])
@ -631,7 +656,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
material = self._createMaterialOutputModel(material_data) material = self._createMaterialOutputModel(material_data)
extruder.updateActiveMaterial(material) extruder.updateActiveMaterial(material)
def _removeJob(self, job: PrintJobOutputModel) -> bool: def _removeJob(self, job: UM3PrintJobOutputModel) -> bool:
if job not in self._print_jobs: if job not in self._print_jobs:
return False return False
@ -675,7 +700,7 @@ def checkValidGetReply(reply: QNetworkReply) -> bool:
return True return True
def findByKey(lst: List[Union[PrintJobOutputModel, PrinterOutputModel]], key: str) -> Optional[PrintJobOutputModel]: def findByKey(lst: List[Union[UM3PrintJobOutputModel, PrinterOutputModel]], key: str) -> Optional[UM3PrintJobOutputModel]:
for item in lst: for item in lst:
if item.key == key: if item.key == key:
return item return item

View File

@ -0,0 +1,29 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot
class ConfigurationChangeModel(QObject):
def __init__(self, type_of_change: str, index: int, target_name: str, origin_name: str) -> None:
super().__init__()
self._type_of_change = type_of_change
# enum = ["material", "print_core_change"]
self._index = index
self._target_name = target_name
self._origin_name = origin_name
@pyqtProperty(int, constant = True)
def index(self) -> int:
return self._index
@pyqtProperty(str, constant = True)
def typeOfChange(self) -> str:
return self._type_of_change
@pyqtProperty(str, constant = True)
def targetName(self) -> str:
return self._target_name
@pyqtProperty(str, constant = True)
def originName(self) -> str:
return self._origin_name

View File

@ -0,0 +1,29 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot
from typing import Optional, TYPE_CHECKING, List
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QImage
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
from .ConfigurationChangeModel import ConfigurationChangeModel
class UM3PrintJobOutputModel(PrintJobOutputModel):
configurationChangesChanged = pyqtSignal()
def __init__(self, output_controller: "PrinterOutputController", key: str = "", name: str = "", parent=None) -> None:
super().__init__(output_controller, key, name, parent)
self._configuration_changes = [] # type: List[ConfigurationChangeModel]
@pyqtProperty("QVariantList", notify=configurationChangesChanged)
def configurationChanges(self) -> List[ConfigurationChangeModel]:
return self._configuration_changes
def updateConfigurationChanges(self, changes: List[ConfigurationChangeModel]) -> None:
if len(self._configuration_changes) == 0 and len(changes) == 0:
return
self._configuration_changes = changes
self.configurationChangesChanged.emit()

View File

@ -221,6 +221,26 @@
"quality_slider_available": [255, 255, 255, 255], "quality_slider_available": [255, 255, 255, 255],
"quality_slider_handle": [255, 255, 255, 255], "quality_slider_handle": [255, 255, 255, 255],
"quality_slider_handle_hover": [127, 127, 127, 255], "quality_slider_handle_hover": [127, 127, 127, 255],
"quality_slider_text": [255, 255, 255, 255] "quality_slider_text": [255, 255, 255, 255],
"monitor_card_background_inactive": [43, 48, 52, 255],
"monitor_card_background": [43, 48, 52, 255],
"monitor_context_menu_background": [80, 84, 87, 255],
"monitor_context_menu_dots": [0, 167, 233, 255],
"monitor_context_menu_highlight": [0, 167, 233, 255],
"monitor_image_overlay": [255, 255, 255, 255],
"monitor_lining_heavy": [255, 255, 255, 255],
"monitor_lining_light": [102, 102, 102, 255],
"monitor_pill_background": [102, 102, 102, 255],
"monitor_placeholder_image": [102, 102, 102, 255],
"monitor_printer_icon": [255, 255, 255, 255],
"monitor_progress_background_text": [102, 102, 102, 255],
"monitor_progress_background": [80, 84, 87, 255],
"monitor_progress_fill_inactive": [216, 216, 216, 255],
"monitor_progress_fill_text": [0, 0, 0, 255],
"monitor_progress_fill": [216, 216, 216, 255],
"monotir_printer_icon_inactive": [154, 154, 154, 255],
"monitor_skeleton_fill": [31, 36, 39, 255],
"monitor_skeleton_fill_dark": [31, 36, 39, 255]
} }
} }

View File

@ -323,10 +323,27 @@
"favorites_header_text_hover": [31, 36, 39, 255], "favorites_header_text_hover": [31, 36, 39, 255],
"favorites_row_selected": [196, 239, 255, 255], "favorites_row_selected": [196, 239, 255, 255],
"monitor_text_inactive": [154, 154, 154, 255], "monitor_card_background_inactive": [240, 240, 240, 255],
"monitor_background_inactive": [240, 240, 240, 255], "monitor_card_background": [255, 255, 255, 255],
"monitor_background_active": [255, 255, 255, 255], "monitor_context_menu_background": [255, 255, 255, 255],
"monitor_lining_inactive": [230, 230, 230, 255] "monitor_context_menu_dots": [154, 154, 154, 255],
"monitor_context_menu_highlight": [245, 245, 245, 255],
"monitor_image_overlay": [0, 0, 0, 255],
"monitor_lining_heavy": [0, 0, 0, 255],
"monitor_lining_light": [230, 230, 230, 255],
"monitor_pill_background": [245, 245, 245, 255],
"monitor_placeholder_image": [230, 230, 230, 255],
"monitor_printer_icon_inactive": [154, 154, 154, 255],
"monitor_printer_icon": [12, 169, 227, 255],
"monitor_progress_background_text": [0,0,0,255],
"monitor_progress_background": [245, 245, 245, 255],
"monitor_progress_fill_inactive": [154, 154, 154, 255],
"monitor_progress_fill_text": [255,255,255,255],
"monitor_progress_fill": [12, 169, 227, 255],
"monitor_shadow": [0, 0, 0, 63],
"monitor_skeleton_fill": [245, 245, 245, 255],
"monitor_skeleton_fill_dark": [216, 216, 216, 255],
"monitor_text_inactive": [154, 154, 154, 255]
}, },
"sizes": { "sizes": {
@ -476,6 +493,12 @@
"toolbox_action_button": [8.0, 2.5], "toolbox_action_button": [8.0, 2.5],
"toolbox_loader": [2.0, 2.0], "toolbox_loader": [2.0, 2.0],
"drop_shadow_radius": [1.0, 1.0] "monitor_config_override_box": [1.0, 14.0],
"monitor_extruder_circle": [2.75, 2.75],
"monitor_text_line": [1.16, 1.16],
"monitor_thick_lining": [0.16, 0.16],
"monitor_corner_radius": [0.3, 0.3],
"monitor_shadow_radius": [0.4, 0.4],
"monitor_shadow_offset": [0.15, 0.15]
} }
} }