// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.2 as UM
import Cura 1.0 as Cura
import "Menus"
Rectangle
{
id: base;
property int currentModeIndex;
property bool hideSettings: PrintInformation.preSliced
// Is there an output device for this printer?
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
property int backendState: UM.Backend.state
property bool monitoringPrint: false
property variant printDuration: PrintInformation.currentPrintTime
property variant printDurationPerFeature: PrintInformation.printTimesPerFeature
property variant printMaterialLengths: PrintInformation.materialLengths
property variant printMaterialWeights: PrintInformation.materialWeights
property variant printMaterialCosts: PrintInformation.materialCosts
color: UM.Theme.getColor("sidebar")
UM.I18nCatalog { id: catalog; name:"cura"}
Timer {
id: tooltipDelayTimer
interval: 500
repeat: false
property var item
property string text
onTriggered:
{
base.showTooltip(base, {x:1, y:item.y}, text);
}
}
function showTooltip(item, position, text)
{
tooltip.text = text;
position = item.mapToItem(base, position.x, position.y);
tooltip.show(position);
}
function hideTooltip()
{
tooltip.hide();
}
function strPadLeft(string, pad, length) {
return (new Array(length + 1).join(pad) + string).slice(-length);
}
function getPrettyTime(time)
{
var hours = Math.floor(time / 3600)
time -= hours * 3600
var minutes = Math.floor(time / 60);
time -= minutes * 60
var seconds = Math.floor(time);
var finalTime = strPadLeft(hours, "0", 2) + ':' + strPadLeft(minutes,'0',2)+ ':' + strPadLeft(seconds,'0',2);
return finalTime;
}
MouseArea
{
anchors.fill: parent
acceptedButtons: Qt.AllButtons;
onWheel:
{
wheel.accepted = true;
}
}
SidebarHeader {
id: header
width: parent.width
onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
}
Rectangle {
id: headerSeparator
width: parent.width
visible: !monitoringPrint && !hideSettings
height: visible ? UM.Theme.getSize("sidebar_lining").height : 0
color: UM.Theme.getColor("sidebar_lining")
anchors.top: header.bottom
anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0
}
onCurrentModeIndexChanged:
{
UM.Preferences.setValue("cura/active_mode", currentModeIndex);
if(modesListModel.count > base.currentModeIndex)
{
sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "replace": true });
}
}
Text {
id: settingsModeLabel
text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox","Print Setup disabled\nG-code files cannot be modified");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width;
anchors.top: headerSeparator.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width * 0.45 - 2 * UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text")
visible: !monitoringPrint
elide: Text.ElideRight
}
Rectangle {
id: settingsModeSelection
color: "transparent"
width: parent.width * 0.55
height: UM.Theme.getSize("sidebar_header_mode_toggle").height
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.top: headerSeparator.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
visible: !monitoringPrint && !hideSettings
Component{
id: wizardDelegate
Button {
height: settingsModeSelection.height
anchors.left: parent.left
anchors.leftMargin: model.index * (settingsModeSelection.width / 2)
anchors.verticalCenter: parent.verticalCenter
width: 0.5 * parent.width
text: model.text
exclusiveGroup: modeMenuGroup;
checkable: true;
checked: base.currentModeIndex == index
onClicked: base.currentModeIndex = index
onHoveredChanged: {
if (hovered)
{
tooltipDelayTimer.item = settingsModeSelection
tooltipDelayTimer.text = model.tooltipText
tooltipDelayTimer.start();
}
else
{
tooltipDelayTimer.stop();
base.hideTooltip();
}
}
style: ButtonStyle {
background: Rectangle {
border.width: UM.Theme.getSize("default_lining").width
border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") :
control.pressed ? UM.Theme.getColor("toggle_active_border") :
control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border")
color: control.checked ? UM.Theme.getColor("toggle_checked") :
control.pressed ? UM.Theme.getColor("toggle_active") :
control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked")
Behavior on color { ColorAnimation { duration: 50; } }
Label {
anchors.centerIn: parent
color: control.checked ? UM.Theme.getColor("toggle_checked_text") :
control.pressed ? UM.Theme.getColor("toggle_active_text") :
control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text")
font: UM.Theme.getFont("default")
text: control.text;
}
}
label: Item { }
}
}
}
ExclusiveGroup { id: modeMenuGroup; }
Label
{
id: toggleLeftText
anchors.right: modeToggleSwitch.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
text: ""
color:
{
if(toggleLeftTextMouseArea.containsMouse)
{
return UM.Theme.getColor("mode_switch_text_hover");
}
else if(!modeToggleSwitch.checked)
{
return UM.Theme.getColor("mode_switch_text_checked");
}
else
{
return UM.Theme.getColor("mode_switch_text");
}
}
font: UM.Theme.getFont("default")
MouseArea
{
id: toggleLeftTextMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked:
{
modeToggleSwitch.checked = false;
}
Component.onCompleted:
{
clicked.connect(modeToggleSwitch.clicked)
}
}
}
Switch
{
id: modeToggleSwitch
checked: false
anchors.right: toggleRightText.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: parent.verticalCenter
property bool _hovered: modeToggleSwitchMouseArea.containsMouse || toggleLeftTextMouseArea.containsMouse || toggleRightTextMouseArea.containsMouse
MouseArea
{
id: modeToggleSwitchMouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
onCheckedChanged:
{
var index = 0;
if (checked)
{
index = 1;
}
updateActiveMode(index);
}
function updateActiveMode(index)
{
base.currentModeIndex = index;
UM.Preferences.setValue("cura/active_mode", index);
}
style: UM.Theme.styles.mode_switch
}
Label
{
id: toggleRightText
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: ""
color:
{
if(toggleRightTextMouseArea.containsMouse)
{
return UM.Theme.getColor("mode_switch_text_hover");
}
else if(modeToggleSwitch.checked)
{
return UM.Theme.getColor("mode_switch_text_checked");
}
else
{
return UM.Theme.getColor("mode_switch_text");
}
}
font: UM.Theme.getFont("default")
MouseArea
{
id: toggleRightTextMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked:
{
modeToggleSwitch.checked = true;
}
Component.onCompleted:
{
clicked.connect(modeToggleSwitch.clicked)
}
}
}
}
StackView
{
id: sidebarContents
anchors.bottom: footerSeparator.top
anchors.top: settingsModeSelection.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: base.left
anchors.right: base.right
visible: !monitoringPrint && !hideSettings
delegate: StackViewDelegate
{
function transitionFinished(properties)
{
properties.exitItem.opacity = 1
}
pushTransition: StackViewTransition
{
PropertyAnimation
{
target: enterItem
property: "opacity"
from: 0
to: 1
duration: 100
}
PropertyAnimation
{
target: exitItem
property: "opacity"
from: 1
to: 0
duration: 100
}
}
}
}
Loader
{
id: controlItem
anchors.bottom: footerSeparator.top
anchors.top: headerSeparator.bottom
anchors.left: base.left
anchors.right: base.right
sourceComponent:
{
if(monitoringPrint && connectedPrinter != null)
{
if(connectedPrinter.controlItem != null)
{
return connectedPrinter.controlItem
}
}
return null
}
}
Loader
{
anchors.bottom: footerSeparator.top
anchors.top: headerSeparator.bottom
anchors.left: base.left
anchors.right: base.right
source:
{
if(controlItem.sourceComponent == null)
{
if(monitoringPrint)
{
return "PrintMonitor.qml"
} else
{
return "SidebarContents.qml"
}
}
else
{
return ""
}
}
}
Rectangle
{
id: footerSeparator
width: parent.width
height: UM.Theme.getSize("sidebar_lining").height
color: UM.Theme.getColor("sidebar_lining")
anchors.bottom: printSpecs.top
anchors.bottomMargin: UM.Theme.getSize("default_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize
}
Rectangle
{
id: printSpecs
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
height: childrenRect.height
UM.TooltipArea
{
id: timeSpecPerFeatureTooltipArea
width: timeSpec.width
height: timeSpec.height
anchors.left: parent.left
anchors.bottom: timeSpecDescription.top
text: {
var order = ["inset_0", "inset_x", "skin", "infill", "support_infill", "support_interface", "support", "travel", "retract", "none"];
var visible_names = {
"inset_0": catalog.i18nc("@tooltip", "Outer Wall"),
"inset_x": catalog.i18nc("@tooltip", "Inner Walls"),
"skin": catalog.i18nc("@tooltip", "Skin"),
"infill": catalog.i18nc("@tooltip", "Infill"),
"support_infill": catalog.i18nc("@tooltip", "Support Infill"),
"support_interface": catalog.i18nc("@tooltip", "Support Interface"),
"support": catalog.i18nc("@tooltip", "Support"),
"travel": catalog.i18nc("@tooltip", "Travel"),
"retract": catalog.i18nc("@tooltip", "Retractions"),
"none": catalog.i18nc("@tooltip", "Other")
};
var result = "";
for(var feature in order)
{
feature = order[feature];
if(base.printDurationPerFeature[feature] && base.printDurationPerFeature[feature].totalSeconds > 0)
{
result += "
" + visible_names[feature] + ": " + base.printDurationPerFeature[feature].getDisplayString(UM.DurationFormat.Short);
}
}
result = result.replace(/^\
/, ""); // remove newline before first item
return result;
}
Text
{
id: timeSpec
anchors.left: parent.left
anchors.bottom: parent.bottom
font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text_subtext")
text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short)
}
}
Text
{
id: timeSpecDescription
anchors.left: parent.left
anchors.bottom: lengthSpec.top
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text_subtext")
text: catalog.i18nc("@description", "Print time")
}
Text
{
id: lengthSpec
anchors.left: parent.left
anchors.bottom: parent.bottom
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text_subtext")
text:
{
var lengths = [];
var weights = [];
var costs = [];
var someCostsKnown = false;
if(base.printMaterialLengths) {
for(var index = 0; index < base.printMaterialLengths.length; index++)
{
if(base.printMaterialLengths[index] > 0)
{
lengths.push(base.printMaterialLengths[index].toFixed(2));
weights.push(String(Math.floor(base.printMaterialWeights[index])));
var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2);
costs.push(cost);
if(cost > 0)
{
someCostsKnown = true;
}
}
}
}
if(lengths.length == 0)
{
lengths = ["0.00"];
weights = ["0"];
costs = ["0.00"];
}
if(someCostsKnown)
{
return catalog.i18nc("@label", "%1 m / ~ %2 g / ~ %4 %3").arg(lengths.join(" + "))
.arg(weights.join(" + ")).arg(costs.join(" + ")).arg(UM.Preferences.getValue("cura/currency"));
}
else
{
return catalog.i18nc("@label", "%1 m / ~ %2 g").arg(lengths.join(" + ")).arg(weights.join(" + "));
}
}
}
}
// SaveButton and MonitorButton are actually the bottom footer panels.
// "!monitoringPrint" currently means "show-settings-mode"
SaveButton
{
id: saveButton
implicitWidth: base.width
anchors.top: footerSeparator.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.bottom: parent.bottom
visible: !monitoringPrint
}
MonitorButton
{
id: monitorButton
implicitWidth: base.width
anchors.top: footerSeparator.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.bottom: parent.bottom
visible: monitoringPrint
}
SidebarTooltip
{
id: tooltip;
}
// Setting mode: Recommended or Custom
ListModel
{
id: modesListModel;
}
SidebarSimple
{
id: sidebarSimple;
visible: false;
onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
}
SidebarAdvanced
{
id: sidebarAdvanced;
visible: false;
onShowTooltip: base.showTooltip(item, location, text)
onHideTooltip: base.hideTooltip()
}
Component.onCompleted:
{
modesListModel.append({
text: catalog.i18nc("@title:tab", "Recommended"),
tooltipText: catalog.i18nc("@tooltip", "Recommended Print Setup
Print with the recommended settings for the selected printer, material and quality."),
item: sidebarSimple
})
modesListModel.append({
text: catalog.i18nc("@title:tab", "Custom"),
tooltipText: catalog.i18nc("@tooltip", "Custom Print Setup
Print with finegrained control over every last bit of the slicing process."),
item: sidebarAdvanced
})
sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true });
toggleLeftText.text = modesListModel.get(0).text;
toggleRightText.text = modesListModel.get(1).text;
var index = parseInt(UM.Preferences.getValue("cura/active_mode"));
if (index)
{
currentModeIndex = index;
modeToggleSwitch.checked = index > 0;
}
}
UM.SettingPropertyProvider
{
id: machineExtruderCount
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_extruder_count"
watchedProperties: [ "value" ]
storeIndex: 0
}
UM.SettingPropertyProvider
{
id: machineHeatedBed
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_heated_bed"
watchedProperties: [ "value" ]
storeIndex: 0
}
}