Merge pull request #5187 from Ultimaker/CL-1165_missing_cloud_info

CL-1165 missing cloud info
This commit is contained in:
Ian Paschal 2019-01-23 12:12:12 +01:00 committed by GitHub
commit 9de3fb9bb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 613 additions and 28 deletions

View File

@ -9,12 +9,14 @@ import Cura 1.0 as Cura
Rectangle {
id: base
property var enabled: true
property var iconSource: null;
color: UM.Theme.getColor("monitor_icon_primary")
height: width;
radius: Math.round(0.5 * width);
width: 24 * screenScaleFactor;
property var enabled: true
UM.RecolorImage {
id: icon;

View File

@ -0,0 +1,227 @@
// 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
/**
* This is a generic pop-up element which can be supplied with a target and a content item. The
* content item will appear to the left, right, above, or below the target depending on the value of
* the direction property
*/
Popup
{
id: base
/**
* The target item is what the pop-up is "tied" to, usually a button
*/
property var target
/**
* Which direction should the pop-up "point"?
* Possible values include:
* - "up"
* - "down"
* - "left"
* - "right"
*/
property string direction: "down"
/**
* We save the default direction so that if a pop-up was flipped but later has space (i.e. it
* moved), we can unflip it back to the default direction.
*/
property string originalDirection: ""
/**
* Should the popup close when you click outside it? For example, this is
* disabled by the InfoBlurb component since it's opened and closed using mouse
* hovers, not clicks.
*/
property bool closeOnClick: true
/**
* Use white for context menus, dark grey for info blurbs!
*/
property var color: "#ffffff" // TODO: Theme!
Component.onCompleted:
{
recalculatePosition()
// Set the direction here so it's only set once and never mutated
originalDirection = (' ' + direction).slice(1)
}
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
{
horizontalCenter:
{
switch(direction)
{
case "left":
return bloop.left
case "right":
return bloop.right
default:
return bloop.horizontalCenter
}
}
verticalCenter:
{
switch(direction)
{
case "up":
return bloop.top
case "down":
return bloop.bottom
default:
return bloop.verticalCenter
}
}
}
color: base.color
height: 12 * screenScaleFactor
transform: Rotation
{
angle: 45
origin.x: point.width / 2
origin.y: point.height / 2
}
width: height
}
Rectangle
{
id: bloop
anchors
{
fill: parent
leftMargin: direction == "left" ? 8 * screenScaleFactor : 0
rightMargin: direction == "right" ? 8 * screenScaleFactor : 0
topMargin: direction == "up" ? 8 * screenScaleFactor : 0
bottomMargin: direction == "down" ? 8 * screenScaleFactor : 0
}
color: base.color
width: parent.width
}
}
}
visible: false
onClosed: visible = false
onOpened:
{
// Flip orientation if necessary
recalculateOrientation()
// Fix position if necessary
recalculatePosition()
// Show the pop up
visible = true
}
closePolicy: closeOnClick ? Popup.CloseOnPressOutside : Popup.NoAutoClose
clip: true
padding: UM.Theme.getSize("monitor_shadow_radius").width
topPadding: direction == "up" ? padding + 8 * screenScaleFactor : padding
bottomPadding: direction == "down" ? padding + 8 * screenScaleFactor : padding
leftPadding: direction == "left" ? padding + 8 * screenScaleFactor : padding
rightPadding: direction == "right" ? padding + 8 * screenScaleFactor : padding
function recalculatePosition() {
// Stupid pop-up logic causes the pop-up to resize, so let's compute what it SHOULD be
const realWidth = contentItem.implicitWidth + leftPadding + rightPadding
const realHeight = contentItem.implicitHeight + topPadding + bottomPadding
var centered = {
x: target.x + target.width / 2 - realWidth / 2,
y: target.y + target.height / 2 - realHeight / 2
}
switch(direction)
{
case "left":
x = target.x + target.width
y = centered.y
break
case "right":
x = target.x - realWidth
y = centered.y
break
case "up":
x = centered.x
y = target.y + target.height
break
case "down":
x = centered.x
y = target.y - realHeight
break
}
}
function recalculateOrientation() {
var availableSpace
var targetPosition = target.mapToItem(monitorFrame, 0, 0)
// Stupid pop-up logic causes the pop-up to resize, so let's compute what it SHOULD be
const realWidth = contentItem.implicitWidth + leftPadding + rightPadding
const realHeight = contentItem.implicitHeight + topPadding + bottomPadding
switch(originalDirection)
{
case "up":
availableSpace = monitorFrame.height - (targetPosition.y + target.height)
direction = availableSpace < realHeight ? "down" : originalDirection
break
case "down":
availableSpace = targetPosition.y
direction = availableSpace < realHeight ? "up" : originalDirection
break
case "right":
availableSpace = targetPosition.x
direction = availableSpace < realWidth ? "left" : originalDirection
break
case "left":
availableSpace = monitorFrame.width - (targetPosition.x + target.width)
direction = availableSpace < realWidth ? "right" : originalDirection
break
}
}
}

View File

@ -0,0 +1,182 @@
// 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 QtQuick.Dialogs 1.1
import UM 1.3 as UM
/**
* A MonitorInfoBlurb is an extension of the GenericPopUp used to show static information (vs. interactive context
* menus). It accepts some text (text), an item to link to to (target), and a specification of which side of the target
* to appear on (direction). It also sets the GenericPopUp's color to black, to differentiate itself from a menu.
*/
Item
{
property alias target: popUp.target
property var printJob: null
GenericPopUp
{
id: popUp
// Which way should the pop-up point? Default is up, but will flip when required
direction: "up"
// Use dark grey for info blurbs and white for context menus
color: "#ffffff" // TODO: Theme!
contentItem: Item
{
id: contentWrapper
implicitWidth: childrenRect.width
implicitHeight: menuItems.height + UM.Theme.getSize("default_margin").height
Column
{
id: menuItems
width: 144 * screenScaleFactor
anchors
{
top: parent.top
topMargin: Math.floor(UM.Theme.getSize("default_margin").height / 2)
}
spacing: Math.floor(UM.Theme.getSize("default_margin").height / 2)
PrintJobContextMenuItem {
onClicked: {
sendToTopConfirmationDialog.visible = true;
popUp.close();
}
text: catalog.i18nc("@label", "Move to top");
visible: {
if (printJob && printJob.state == "queued" && !isAssigned(printJob)) {
if (OutputDevice && OutputDevice.queuedPrintJobs[0]) {
return OutputDevice.queuedPrintJobs[0].key != printJob.key;
}
}
return false;
}
}
PrintJobContextMenuItem {
onClicked: {
deleteConfirmationDialog.visible = true;
popUp.close();
}
text: catalog.i18nc("@label", "Delete");
visible: {
if (!printJob) {
return false;
}
var states = ["queued", "sent_to_printer"];
return states.indexOf(printJob.state) !== -1;
}
}
PrintJobContextMenuItem {
enabled: visible && !(printJob.state == "pausing" || printJob.state == "resuming");
onClicked: {
if (printJob.state == "paused") {
printJob.setState("print");
popUp.close();
return;
}
if (printJob.state == "printing") {
printJob.setState("pause");
popUp.close();
return;
}
}
text: {
if (!printJob) {
return "";
}
switch(printJob.state) {
case "paused":
return catalog.i18nc("@label", "Resume");
case "pausing":
return catalog.i18nc("@label", "Pausing...");
case "resuming":
return catalog.i18nc("@label", "Resuming...");
default:
catalog.i18nc("@label", "Pause");
}
}
visible: {
if (!printJob) {
return false;
}
var states = ["printing", "pausing", "paused", "resuming"];
return states.indexOf(printJob.state) !== -1;
}
}
PrintJobContextMenuItem {
enabled: visible && printJob.state !== "aborting";
onClicked: {
abortConfirmationDialog.visible = true;
popUp.close();
}
text: printJob && printJob.state == "aborting" ? catalog.i18nc("@label", "Aborting...") : catalog.i18nc("@label", "Abort");
visible: {
if (!printJob) {
return false;
}
var states = ["pre_print", "printing", "pausing", "paused", "resuming"];
return states.indexOf(printJob.state) !== -1;
}
}
}
}
}
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")
}
function switchPopupState() {
popUp.visible ? popUp.close() : popUp.open()
}
function open() {
popUp.open()
}
function close() {
popUp.close()
}
function isAssigned(job) {
if (!job) {
return false;
}
return job.assignedPrinter ? true : false;
}
}

View File

@ -0,0 +1,31 @@
// 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
import Cura 1.0 as Cura
Button
{
id: base
background: Rectangle
{
color: UM.Theme.getColor("viewport_background") // TODO: Theme!
height: base.height
opacity: base.down || base.hovered ? 1 : 0
radius: Math.round(0.5 * width)
width: base.width
}
contentItem: Label {
color: UM.Theme.getColor("monitor_context_menu_dots")
font.pixelSize: 32 * screenScaleFactor
horizontalAlignment: Text.AlignHCenter
text: base.text
verticalAlignment: Text.AlignVCenter
}
height: width
hoverEnabled: enabled
text: "\u22EE" //Unicode Three stacked points.
width: 36 * screenScaleFactor // TODO: Theme!
}

View File

@ -0,0 +1,53 @@
// 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
/**
* A MonitorInfoBlurb is an extension of the GenericPopUp used to show static information (vs. interactive context
* menus). It accepts some text (text), an item to link to to (target), and a specification of which side of the target
* to appear on (direction). It also sets the GenericPopUp's color to black, to differentiate itself from a menu.
*/
Item
{
property alias text: innerLabel.text
property alias target: popUp.target
property alias direction: popUp.direction
GenericPopUp
{
id: popUp
// Which way should the pop-up point? Default is up, but will flip when required
direction: "up"
// Use dark grey for info blurbs and white for context menus
color: UM.Theme.getColor("monitor_tooltip")
contentItem: Item
{
id: contentWrapper
implicitWidth: childrenRect.width
implicitHeight: innerLabel.contentHeight + 2 * innerLabel.padding
Label
{
id: innerLabel
padding: 12 * screenScaleFactor // TODO: Theme!
text: ""
wrapMode: Text.WordWrap
width: 240 * screenScaleFactor // TODO: Theme!
color: UM.Theme.getColor("monitor_tooltip_text")
font: UM.Theme.getFont("default")
}
}
}
function open() {
popUp.open()
}
function close() {
popUp.close()
}
}

View File

@ -4,6 +4,7 @@
import QtQuick 2.2
import QtQuick.Controls 2.0
import UM 1.3 as UM
import Cura 1.0 as Cura
/**
* A Print Job Card is essentially just a filled-in Expandable Card item. All
@ -21,6 +22,10 @@ Item
// The print job which all other data is derived from
property var printJob: null
// If the printer is a cloud printer or not. Other items base their enabled state off of this boolean. In the future
// they might not need to though.
property bool cloudConnection: Cura.MachineManager.activeMachineHasActiveCloudConnection
width: parent.width
height: childrenRect.height
@ -198,18 +203,52 @@ Item
}
}
PrintJobContextMenu
MonitorContextMenuButton
{
id: contextButton
id: contextMenuButton
anchors
{
right: parent.right;
right: parent.right
rightMargin: 8 * screenScaleFactor // TODO: Theme!
top: parent.top
topMargin: 8 * screenScaleFactor // TODO: Theme!
}
printJob: base.printJob
width: 32 * screenScaleFactor // TODO: Theme!
height: 32 * screenScaleFactor // TODO: Theme!
enabled: !cloudConnection
onClicked: enabled ? contextMenu.switchPopupState() : {}
visible:
{
if (!printJob) {
return false
}
var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]
return states.indexOf(printJob.state) !== -1
}
}
MonitorContextMenu
{
id: contextMenu
printJob: base.printJob ? base.printJob : null
target: contextMenuButton
}
// For cloud printing, add this mouse area over the disabled contextButton to indicate that it's not available
MouseArea
{
id: contextMenuDisabledButtonArea
anchors.fill: contextMenuButton
hoverEnabled: contextMenuButton.visible && !contextMenuButton.enabled
onEntered: contextMenuDisabledInfo.open()
onExited: contextMenuDisabledInfo.close()
enabled: !contextMenuButton.enabled
}
MonitorInfoBlurb
{
id: contextMenuDisabledInfo
text: catalog.i18nc("@info", "These options are not available because you are monitoring a cloud printer.")
target: contextMenuButton
}
}

View File

@ -5,15 +5,14 @@ import QtQuick 2.3
import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.1
import UM 1.3 as UM
import Cura 1.0 as Cura
/**
* A Printer Card is has two main components: the printer portion and the print
* job portion, the latter being paired in the UI when a print job is paired
* a printer in-cluster.
* A Printer Card is has two main components: the printer portion and the print job portion, the latter being paired in
* the UI when a print job is paired a printer in-cluster.
*
* NOTE: For most labels, a fixed height with vertical alignment is used to make
* layouts more deterministic (like the fixed-size textboxes used in original
* mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
* NOTE: For most labels, a fixed height with vertical alignment is used to make layouts more deterministic (like the
* fixed-size textboxes used in original mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
* with '// FIXED-LINE-HEIGHT:'.
*/
Item
@ -25,11 +24,14 @@ Item
property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here
// If the printer card's controls are enabled. This is used by the carousel
// to prevent opening the context menu or camera while the printer card is not
// "in focus"
// If the printer card's controls are enabled. This is used by the carousel to prevent opening the context menu or
// camera while the printer card is not "in focus"
property var enabled: true
// If the printer is a cloud printer or not. Other items base their enabled state off of this boolean. In the future
// they might not need to though.
property bool cloudConnection: Cura.MachineManager.activeMachineHasActiveCloudConnection
width: 834 * screenScaleFactor // TODO: Theme!
height: childrenRect.height
@ -155,16 +157,11 @@ Item
}
height: 72 * screenScaleFactor // TODO: Theme!te theRect's x property
}
// TODO: Make this work.
PropertyAnimation { target: printerConfiguration; property: "visible"; to: 0; loops: Animation.Infinite; duration: 500 }
}
PrintJobContextMenu
MonitorContextMenuButton
{
id: contextButton
id: contextMenuButton
anchors
{
right: parent.right
@ -172,15 +169,49 @@ Item
top: parent.top
topMargin: 12 * screenScaleFactor // TODO: Theme!
}
printJob: printer ? printer.activePrintJob : null
width: 36 * screenScaleFactor // TODO: Theme!
height: 36 * screenScaleFactor // TODO: Theme!
enabled: base.enabled
visible: printer
enabled: !cloudConnection
onClicked: enabled ? contextMenu.switchPopupState() : {}
visible:
{
if (!printer || !printer.activePrintJob) {
return false
}
var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]
return states.indexOf(printer.activePrintJob.state) !== -1
}
}
MonitorContextMenu
{
id: contextMenu
printJob: printer ? printer.activePrintJob : null
target: contextMenuButton
}
// For cloud printing, add this mouse area over the disabled contextButton to indicate that it's not available
MouseArea
{
id: contextMenuDisabledButtonArea
anchors.fill: contextMenuButton
hoverEnabled: contextMenuButton.visible && !contextMenuButton.enabled
onEntered: contextMenuDisabledInfo.open()
onExited: contextMenuDisabledInfo.close()
enabled: !contextMenuButton.enabled
}
MonitorInfoBlurb
{
id: contextMenuDisabledInfo
text: catalog.i18nc("@info", "These options are not available because you are monitoring a cloud printer.")
target: contextMenuButton
}
CameraButton
{
id: cameraButton;
id: cameraButton
anchors
{
right: parent.right
@ -189,9 +220,27 @@ Item
bottomMargin: 20 * screenScaleFactor // TODO: Theme!
}
iconSource: "../svg/icons/camera.svg"
enabled: base.enabled
enabled: !cloudConnection
visible: printer
}
// For cloud printing, add this mouse area over the disabled cameraButton to indicate that it's not available
MouseArea
{
id: cameraDisabledButtonArea
anchors.fill: cameraButton
hoverEnabled: cameraButton.visible && !cameraButton.enabled
onEntered: cameraDisabledInfo.open()
onExited: cameraDisabledInfo.close()
enabled: !cameraButton.enabled
}
MonitorInfoBlurb
{
id: cameraDisabledInfo
text: catalog.i18nc("@info", "The webcam is not available because you are monitoring a cloud printer.")
target: cameraButton
}
}

View File

@ -238,7 +238,8 @@
"monitor_progress_bar_deactive": [102, 102, 102, 255],
"monitor_progress_bar_empty": [67, 67, 67, 255],
"monitor_tooltips": [25, 25, 25, 255],
"monitor_tooltip": [25, 25, 25, 255],
"monitor_tooltip_text": [229, 229, 229, 255],
"monitor_context_menu": [67, 67, 67, 255],
"monitor_context_menu_hover": [30, 102, 215, 255],

View File

@ -422,7 +422,8 @@
"monitor_progress_bar_deactive": [192, 193, 194, 255],
"monitor_progress_bar_empty": [245, 245, 245, 255],
"monitor_tooltips": [25, 25, 25, 255],
"monitor_tooltip": [25, 25, 25, 255],
"monitor_tooltip_text": [255, 255, 255, 255],
"monitor_context_menu": [255, 255, 255, 255],
"monitor_context_menu_hover": [245, 245, 245, 255],