Merge branch 'feature_preheat_bed' of github.com:Ultimaker/Cura

This commit is contained in:
Jaime van Kessel 2017-02-13 14:16:50 +01:00
commit e8c5f81c79
8 changed files with 652 additions and 63 deletions

View File

@ -1,3 +1,6 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.OutputDevice.OutputDevice import OutputDevice from UM.OutputDevice.OutputDevice import OutputDevice
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
@ -45,6 +48,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = "" self._job_name = ""
self._error_text = "" self._error_text = ""
self._accepts_commands = True self._accepts_commands = True
self._preheat_bed_timeout = 900 #Default time-out for pre-heating the bed, in seconds.
self._printer_state = "" self._printer_state = ""
self._printer_type = "unknown" self._printer_type = "unknown"
@ -161,6 +165,17 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = name self._job_name = name
self.jobNameChanged.emit() self.jobNameChanged.emit()
## Gives a human-readable address where the device can be found.
@pyqtProperty(str, constant = True)
def address(self):
Logger.log("w", "address is not implemented by this output device.")
## A human-readable name for the device.
@pyqtProperty(str, constant = True)
def name(self):
Logger.log("w", "name is not implemented by this output device.")
return ""
@pyqtProperty(str, notify = errorTextChanged) @pyqtProperty(str, notify = errorTextChanged)
def errorText(self): def errorText(self):
return self._error_text return self._error_text
@ -199,6 +214,13 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._target_bed_temperature = temperature self._target_bed_temperature = temperature
self.targetBedTemperatureChanged.emit() self.targetBedTemperatureChanged.emit()
## The duration of the time-out to pre-heat the bed, in seconds.
#
# \return The duration of the time-out to pre-heat the bed, in seconds.
@pyqtProperty(int)
def preheatBedTimeout(self):
return self._preheat_bed_timeout
## Time the print has been printing. ## Time the print has been printing.
# Note that timeTotal - timeElapsed should give time remaining. # Note that timeTotal - timeElapsed should give time remaining.
@pyqtProperty(float, notify = timeElapsedChanged) @pyqtProperty(float, notify = timeElapsedChanged)
@ -254,6 +276,22 @@ class PrinterOutputDevice(QObject, OutputDevice):
def _setTargetBedTemperature(self, temperature): def _setTargetBedTemperature(self, temperature):
Logger.log("w", "_setTargetBedTemperature is not implemented by this output device") Logger.log("w", "_setTargetBedTemperature is not implemented by this output device")
## Pre-heats the heated bed of the printer.
#
# \param temperature The temperature to heat the bed to, in degrees
# Celsius.
# \param duration How long the bed should stay warm, in seconds.
@pyqtSlot(float, float)
def preheatBed(self, temperature, duration):
Logger.log("w", "preheatBed is not implemented by this output device.")
## Cancels pre-heating the heated bed of the printer.
#
# If the bed is not pre-heated, nothing happens.
@pyqtSlot()
def cancelPreheatBed(self):
Logger.log("w", "cancelPreheatBed is not implemented by this output device.")
## Protected setter for the current bed temperature. ## Protected setter for the current bed temperature.
# This simply sets the bed temperature, but ensures that a signal is emitted. # This simply sets the bed temperature, but ensures that a signal is emitted.
# /param temperature temperature of the bed. # /param temperature temperature of the bed.
@ -323,6 +361,28 @@ class PrinterOutputDevice(QObject, OutputDevice):
result.append(i18n_catalog.i18nc("@item:material", "Unknown material")) result.append(i18n_catalog.i18nc("@item:material", "Unknown material"))
return result return result
## List of the colours of the currently loaded materials.
#
# The list is in order of extruders. If there is no material in an
# extruder, the colour is shown as transparent.
#
# The colours are returned in hex-format AARRGGBB or RRGGBB
# (e.g. #800000ff for transparent blue or #00ff00 for pure green).
@pyqtProperty("QVariantList", notify = materialIdChanged)
def materialColors(self):
result = []
for material_id in self._material_ids:
if material_id is None:
result.append("#00000000") #No material.
continue
containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_id)
if containers:
result.append(containers[0].getMetaDataEntry("color_code"))
else:
result.append("#00000000") #Unknown material.
return result
## Protected setter for the current material id. ## Protected setter for the current material id.
# /param index Index of the extruder # /param index Index of the extruder
# /param material_id id of the material # /param material_id id of the material

View File

@ -103,6 +103,16 @@ class ExtruderManager(QObject):
def activeExtruderIndex(self): def activeExtruderIndex(self):
return self._active_extruder_index return self._active_extruder_index
## Gets the extruder name of an extruder of the currently active machine.
#
# \param index The index of the extruder whose name to get.
@pyqtSlot(int, result = str)
def getExtruderName(self, index):
try:
return list(self.getActiveExtruderStacks())[index].getName()
except IndexError:
return ""
def getActiveExtruderStack(self): def getActiveExtruderStack(self):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack() global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
if global_container_stack: if global_container_stack:

View File

@ -1,4 +1,4 @@
# Copyright (c) 2016 Ultimaker B.V. # Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -9,6 +9,7 @@ from UM.Signal import signalemitter
from UM.Message import Message from UM.Message import Message
import UM.Settings import UM.Settings
import UM.Version #To compare firmware version numbers.
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
import cura.Settings.ExtruderManager import cura.Settings.ExtruderManager
@ -97,6 +98,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._material_ids = [""] * self._num_extruders self._material_ids = [""] * self._num_extruders
self._hotend_ids = [""] * self._num_extruders self._hotend_ids = [""] * self._num_extruders
self._target_bed_temperature = 0
self.setPriority(2) # Make sure the output device gets selected above local file output self.setPriority(2) # Make sure the output device gets selected above local file output
self.setName(key) self.setName(key)
@ -220,12 +222,17 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
def getKey(self): def getKey(self):
return self._key return self._key
## Name of the printer (as returned from the zeroConf properties) ## The IP address of the printer.
@pyqtProperty(str, constant = True)
def address(self):
return self._properties.get(b"address", b"").decode("utf-8")
## Name of the printer (as returned from the ZeroConf properties)
@pyqtProperty(str, constant = True) @pyqtProperty(str, constant = True)
def name(self): def name(self):
return self._properties.get(b"name", b"").decode("utf-8") return self._properties.get(b"name", b"").decode("utf-8")
## Firmware version (as returned from the zeroConf properties) ## Firmware version (as returned from the ZeroConf properties)
@pyqtProperty(str, constant=True) @pyqtProperty(str, constant=True)
def firmwareVersion(self): def firmwareVersion(self):
return self._properties.get(b"firmware_version", b"").decode("utf-8") return self._properties.get(b"firmware_version", b"").decode("utf-8")
@ -235,6 +242,49 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
def ipAddress(self): def ipAddress(self):
return self._address return self._address
## Pre-heats the heated bed of the printer.
#
# \param temperature The temperature to heat the bed to, in degrees
# Celsius.
# \param duration How long the bed should stay warm, in seconds.
@pyqtSlot(float, float)
def preheatBed(self, temperature, duration):
temperature = round(temperature) #The API doesn't allow floating point.
duration = round(duration)
if UM.Version(self.firmwareVersion) < UM.Version("3.5.92"): #Real bed pre-heating support is implemented from 3.5.92 and up.
self.setTargetBedTemperature(temperature = temperature) #No firmware-side duration support then.
return
url = QUrl("http://" + self._address + self._api_prefix + "printer/bed/pre_heat")
if duration > 0:
data = """{"temperature": "%i", "timeout": "%i"}""" % (temperature, duration)
else:
data = """{"temperature": "%i"}""" % temperature
put_request = QNetworkRequest(url)
put_request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
self._manager.put(put_request, data.encode())
## Cancels pre-heating the heated bed of the printer.
#
# If the bed is not pre-heated, nothing happens.
@pyqtSlot()
def cancelPreheatBed(self):
self.preheatBed(temperature = 0, duration = 0)
## Changes the target bed temperature on the printer.
#
# /param temperature The new target temperature of the bed.
def _setTargetBedTemperature(self, temperature):
if self._target_bed_temperature == temperature:
return
self._target_bed_temperature = temperature
self.targetBedTemperatureChanged.emit()
url = QUrl("http://" + self._address + self._api_prefix + "printer/bed/temperature/target")
data = str(temperature)
put_request = QNetworkRequest(url)
put_request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
self._manager.put(put_request, data.encode())
def _stopCamera(self): def _stopCamera(self):
self._camera_timer.stop() self._camera_timer.stop()
if self._image_reply: if self._image_reply:
@ -271,14 +321,14 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
if auth_state == AuthState.AuthenticationRequested: if auth_state == AuthState.AuthenticationRequested:
Logger.log("d", "Authentication state changed to authentication requested.") Logger.log("d", "Authentication state changed to authentication requested.")
self.setAcceptsCommands(False) self.setAcceptsCommands(False)
self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network to {0}. Please approve the access request on the printer.").format(self.name)) self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network. Please approve the access request on the printer."))
self._authentication_requested_message.show() self._authentication_requested_message.show()
self._authentication_request_active = True self._authentication_request_active = True
self._authentication_timer.start() # Start timer so auth will fail after a while. self._authentication_timer.start() # Start timer so auth will fail after a while.
elif auth_state == AuthState.Authenticated: elif auth_state == AuthState.Authenticated:
Logger.log("d", "Authentication state changed to authenticated") Logger.log("d", "Authentication state changed to authenticated")
self.setAcceptsCommands(True) self.setAcceptsCommands(True)
self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network to {0}.").format(self.name)) self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network."))
self._authentication_requested_message.hide() self._authentication_requested_message.hide()
if self._authentication_request_active: if self._authentication_request_active:
self._authentication_succeeded_message.show() self._authentication_succeeded_message.show()
@ -291,7 +341,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self.sendMaterialProfiles() self.sendMaterialProfiles()
elif auth_state == AuthState.AuthenticationDenied: elif auth_state == AuthState.AuthenticationDenied:
self.setAcceptsCommands(False) self.setAcceptsCommands(False)
self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network to {0}. No access to control the printer.").format(self.name)) self.setConnectionText(i18n_catalog.i18nc("@info:status", "Connected over the network. No access to control the printer."))
self._authentication_requested_message.hide() self._authentication_requested_message.hide()
if self._authentication_request_active: if self._authentication_request_active:
if self._authentication_timer.remainingTime() > 0: if self._authentication_timer.remainingTime() > 0:
@ -466,6 +516,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
bed_temperature = self._json_printer_state["bed"]["temperature"]["current"] bed_temperature = self._json_printer_state["bed"]["temperature"]["current"]
self._setBedTemperature(bed_temperature) self._setBedTemperature(bed_temperature)
target_bed_temperature = self._json_printer_state["bed"]["temperature"]["target"]
self._setTargetBedTemperature(target_bed_temperature)
head_x = self._json_printer_state["heads"][0]["position"]["x"] head_x = self._json_printer_state["heads"][0]["position"]["x"]
head_y = self._json_printer_state["heads"][0]["position"]["y"] head_y = self._json_printer_state["heads"][0]["position"]["y"]
@ -974,10 +1026,20 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._progress_message.hide() self._progress_message.hide()
elif reply.operation() == QNetworkAccessManager.PutOperation: elif reply.operation() == QNetworkAccessManager.PutOperation:
if status_code == 204: if status_code in [200, 201, 202, 204]:
pass # Request was successful! pass # Request was successful!
else: else:
Logger.log("d", "Something went wrong when trying to update data of API (%s). Message: %s Statuscode: %s", reply_url, reply.readAll(), status_code) operation_type = "Unknown"
if reply.operation() == QNetworkAccessManager.GetOperation:
operation_type = "Get"
elif reply.operation() == QNetworkAccessManager.PutOperation:
operation_type = "Put"
elif reply.operation() == QNetworkAccessManager.PostOperation:
operation_type = "Post"
elif reply.operation() == QNetworkAccessManager.DeleteOperation:
operation_type = "Delete"
Logger.log("d", "Something went wrong when trying to update data of API (%s). Message: %s Statuscode: %s, operation: %s", reply_url, reply.readAll(), status_code, operation_type)
else: else:
Logger.log("d", "NetworkPrinterOutputDevice got an unhandled operation %s", reply.operation()) Logger.log("d", "NetworkPrinterOutputDevice got an unhandled operation %s", reply.operation())

View File

@ -1,3 +1,6 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from . import NetworkPrinterOutputDevice from . import NetworkPrinterOutputDevice
@ -75,9 +78,13 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
self._manual_instances.append(address) self._manual_instances.append(address)
self._preferences.setValue("um3networkprinting/manual_instances", ",".join(self._manual_instances)) self._preferences.setValue("um3networkprinting/manual_instances", ",".join(self._manual_instances))
name = address
instance_name = "manual:%s" % address instance_name = "manual:%s" % address
properties = { b"name": name.encode("utf-8"), b"manual": b"true", b"incomplete": b"true" } properties = {
b"name": address.encode("utf-8"),
b"address": address.encode("utf-8"),
b"manual": b"true",
b"incomplete": b"true"
}
if instance_name not in self._printers: if instance_name not in self._printers:
# Add a preliminary printer instance # Add a preliminary printer instance
@ -112,10 +119,14 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
if status_code == 200: if status_code == 200:
system_info = json.loads(bytes(reply.readAll()).decode("utf-8")) system_info = json.loads(bytes(reply.readAll()).decode("utf-8"))
address = reply.url().host() address = reply.url().host()
name = ("%s (%s)" % (system_info["name"], address))
instance_name = "manual:%s" % address instance_name = "manual:%s" % address
properties = { b"name": name.encode("utf-8"), b"firmware_version": system_info["firmware"].encode("utf-8"), b"manual": b"true" } properties = {
b"name": system_info["name"].encode("utf-8"),
b"address": address.encode("utf-8"),
b"firmware_version": system_info["firmware"].encode("utf-8"),
b"manual": b"true"
}
if instance_name in self._printers: if instance_name in self._printers:
# Only replace the printer if it is still in the list of (manual) printers # Only replace the printer if it is still in the list of (manual) printers
self.removePrinter(instance_name) self.removePrinter(instance_name)

View File

@ -124,6 +124,16 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
def _homeBed(self): def _homeBed(self):
self._sendCommand("G28 Z") self._sendCommand("G28 Z")
## A name for the device.
@pyqtProperty(str, constant = True)
def name(self):
return self.getName()
## The address of the device.
@pyqtProperty(str, constant = True)
def address(self):
return self._serial_port
def startPrint(self): def startPrint(self):
self.writeStarted.emit(self) self.writeStarted.emit(self)
gcode_list = getattr( Application.getInstance().getController().getScene(), "gcode_list") gcode_list = getattr( Application.getInstance().getController().getScene(), "gcode_list")
@ -631,3 +641,20 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._update_firmware_thread.daemon = True self._update_firmware_thread.daemon = True
self.connect() self.connect()
## Pre-heats the heated bed of the printer, if it has one.
#
# \param temperature The temperature to heat the bed to, in degrees
# Celsius.
# \param duration How long the bed should stay warm, in seconds. This is
# ignored because there is no g-code to set this.
@pyqtSlot(float, float)
def preheatBed(self, temperature, duration):
self._setTargetBedTemperature(temperature)
## Cancels pre-heating the heated bed of the printer.
#
# If the bed is not pre-heated, nothing happens.
@pyqtSlot()
def cancelPreheatBed(self):
self._setTargetBedTemperature(0)

View File

@ -1,4 +1,4 @@
// Copyright (c) 2016 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher. // Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -12,7 +12,7 @@ import Cura 1.0 as Cura
Column Column
{ {
id: printMonitor id: printMonitor
property var connectedPrinter: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
Cura.ExtrudersModel Cura.ExtrudersModel
{ {
@ -20,47 +20,475 @@ Column
simpleNames: true simpleNames: true
} }
Item Rectangle
{ {
width: base.width - 2 * UM.Theme.getSize("default_margin").width id: connectedPrinterHeader
height: childrenRect.height + UM.Theme.getSize("default_margin").height width: parent.width
anchors.left: parent.left height: childrenRect.height + UM.Theme.getSize("default_margin").height * 2
anchors.leftMargin: UM.Theme.getSize("default_margin").width color: UM.Theme.getColor("setting_category")
Label Label
{ {
text: printerConnected ? connectedPrinter.connectionText : catalog.i18nc("@info:status", "The printer is not connected.") id: connectedPrinterNameLabel
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") text: connectedPrinter != null ? connectedPrinter.name : catalog.i18nc("@info:status", "No printer connected")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text")
anchors.left: parent.left
anchors.top: parent.top
anchors.margins: UM.Theme.getSize("default_margin").width
}
Label
{
id: connectedPrinterAddressLabel
text: (connectedPrinter != null && connectedPrinter.address != null) ? connectedPrinter.address : ""
font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_inactive")
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: UM.Theme.getSize("default_margin").width
}
Label
{
text: connectedPrinter != null ? connectedPrinter.connectionText : catalog.i18nc("@info:status", "The printer is not connected.")
color: connectedPrinter != null && connectedPrinter.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("very_small")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
width: parent.width anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.top: connectedPrinterNameLabel.bottom
} }
} }
Loader Rectangle
{ {
sourceComponent: monitorSection color: UM.Theme.getColor("sidebar_lining")
property string label: catalog.i18nc("@label", "Temperatures") width: parent.width
} height: childrenRect.height
Repeater
{ Flow
model: machineExtruderCount.properties.value
delegate: Loader
{ {
sourceComponent: monitorItem id: extrudersGrid
property string label: machineExtruderCount.properties.value > 1 ? extrudersModel.getItem(index).name : catalog.i18nc("@label", "Hotend") spacing: UM.Theme.getSize("sidebar_lining_thin").width
property string value: printerConnected ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : "" width: parent.width
Repeater
{
id: extrudersRepeater
model: machineExtruderCount.properties.value
delegate: Rectangle
{
id: extruderRectangle
color: UM.Theme.getColor("sidebar")
width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2
height: UM.Theme.getSize("sidebar_extruder_box").height
Label //Extruder name.
{
text: ExtruderManager.getExtruderName(index) != "" ? ExtruderManager.getExtruderName(index) : catalog.i18nc("@label", "Hotend")
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default")
anchors.left: parent.left
anchors.top: parent.top
anchors.margins: UM.Theme.getSize("default_margin").width
}
Label //Temperature indication.
{
text: (connectedPrinter != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : ""
font: UM.Theme.getFont("large")
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: UM.Theme.getSize("default_margin").width
}
Rectangle //Material colour indication.
{
id: materialColor
width: materialName.height * 0.75
height: materialName.height * 0.75
color: (connectedPrinter != null && connectedPrinter.materialColors[index] != null && connectedPrinter.materialIds[index] != "") ? connectedPrinter.materialColors[index] : "#00000000"
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: connectedPrinter != null && connectedPrinter.materialColors[index] != null && connectedPrinter.materialIds[index] != ""
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: materialName.verticalCenter
}
Label //Material name.
{
id: materialName
text: (connectedPrinter != null && connectedPrinter.materialNames[index] != null && connectedPrinter.materialIds[index] != "") ? connectedPrinter.materialNames[index] : ""
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
anchors.left: materialColor.right
anchors.bottom: parent.bottom
anchors.margins: UM.Theme.getSize("default_margin").width
}
Label //Variant name.
{
text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null) ? connectedPrinter.hotendIds[index] : ""
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: UM.Theme.getSize("default_margin").width
}
}
}
} }
} }
Repeater
Rectangle
{ {
model: machineHeatedBed.properties.value == "True" ? 1 : 0 color: UM.Theme.getColor("sidebar_lining")
delegate: Loader width: parent.width
height: UM.Theme.getSize("sidebar_lining_thin").width
}
Rectangle
{
color: UM.Theme.getColor("sidebar")
width: parent.width
height: machineHeatedBed.properties.value == "True" ? UM.Theme.getSize("sidebar_extruder_box").height : 0
visible: machineHeatedBed.properties.value == "True"
Label //Build plate label.
{ {
sourceComponent: monitorItem text: catalog.i18nc("@label", "Build plate")
property string label: catalog.i18nc("@label", "Build plate") font: UM.Theme.getFont("default")
property string value: printerConnected ? Math.round(connectedPrinter.bedTemperature) + "°C" : "" color: UM.Theme.getColor("text")
anchors.left: parent.left
anchors.top: parent.top
anchors.margins: UM.Theme.getSize("default_margin").width
} }
Label //Target temperature.
{
id: bedTargetTemperature
text: connectedPrinter != null ? connectedPrinter.targetBedTemperature + "°C" : ""
font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_inactive")
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: bedCurrentTemperature.bottom
}
Label //Current temperature.
{
id: bedCurrentTemperature
text: connectedPrinter != null ? connectedPrinter.bedTemperature + "°C" : ""
font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text")
anchors.right: bedTargetTemperature.left
anchors.top: parent.top
anchors.margins: UM.Theme.getSize("default_margin").width
}
Rectangle //Input field for pre-heat temperature.
{
id: preheatTemperatureControl
color: UM.Theme.getColor("setting_validation_ok")
border.width: UM.Theme.getSize("default_lining").width
border.color: mouseArea.containsMouse ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border")
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: parent.bottom
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("setting_control").width
height: UM.Theme.getSize("setting_control").height
Rectangle //Highlight of input field.
{
anchors.fill: parent
anchors.margins: UM.Theme.getSize("default_lining").width
color: UM.Theme.getColor("setting_control_highlight")
opacity: preheatTemperatureControl.hovered ? 1.0 : 0
}
Label //Maximum temperature indication.
{
text: (bedTemperature.properties.maximum_value != "None" ? bedTemperature.properties.maximum_value : "") + "°C"
color: UM.Theme.getColor("setting_unit")
font: UM.Theme.getFont("default")
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.verticalCenter: parent.verticalCenter
}
MouseArea //Change cursor on hovering.
{
id: mouseArea
hoverEnabled: true
anchors.fill: parent
cursorShape: Qt.IBeamCursor
}
TextInput
{
id: preheatTemperatureInput
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("setting_control_text")
selectByMouse: true
maximumLength: 10
validator: RegExpValidator { regExp: /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } //Floating point regex.
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Binding
{
target: preheatTemperatureInput
property: "text"
value:
{
// Stacklevels
// 0: user -> unsaved change
// 1: quality changes -> saved change
// 2: quality
// 3: material -> user changed material in materialspage
// 4: variant
// 5: machine_changes
// 6: machine
if ((bedTemperature.resolve != "None" && bedTemperature.resolve) && (bedTemperature.stackLevels[0] != 0) && (bedTemperature.stackLevels[0] != 1))
{
// We have a resolve function. Indicates that the setting is not settable per extruder and that
// we have to choose between the resolved value (default) and the global value
// (if user has explicitly set this).
return bedTemperature.resolve;
}
else
{
return bedTemperature.properties.value;
}
}
when: !preheatTemperatureInput.activeFocus
}
}
}
UM.RecolorImage
{
id: preheatCountdownIcon
width: UM.Theme.getSize("save_button_specs_icons").width
height: UM.Theme.getSize("save_button_specs_icons").height
sourceSize.width: width
sourceSize.height: height
color: UM.Theme.getColor("text")
visible: preheatCountdown.visible
source: UM.Theme.getIcon("print_time")
anchors.right: preheatCountdown.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2
anchors.verticalCenter: preheatCountdown.verticalCenter
}
Timer
{
id: preheatCountdownTimer
interval: 100 //Update every 100ms. You want to update every 1s, but then you have one timer for the updating running out of sync with the actual date timer and you might skip seconds.
running: false
repeat: true
onTriggered: update()
property var endTime: new Date() //Set initial endTime to be the current date, so that the endTime has initially already passed and the timer text becomes invisible if you were to update.
function update()
{
var now = new Date();
if (now.getTime() < endTime.getTime())
{
var remaining = endTime - now; //This is in milliseconds.
var minutes = Math.floor(remaining / 60 / 1000);
var seconds = Math.floor((remaining / 1000) % 60);
preheatCountdown.text = minutes + ":" + (seconds < 10 ? "0" + seconds : seconds);
preheatCountdown.visible = true;
}
else
{
preheatCountdown.visible = false;
running = false;
if (connectedPrinter != null)
{
connectedPrinter.cancelPreheatBed()
}
}
}
}
Label
{
id: preheatCountdown
text: "0:00"
visible: false //It only becomes visible when the timer is running.
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
anchors.right: preheatButton.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.verticalCenter: preheatButton.verticalCenter
}
Button //The pre-heat button.
{
id: preheatButton
height: UM.Theme.getSize("setting_control").height
enabled:
{
if (connectedPrinter == null)
{
return false; //Can't preheat if not connected.
}
if (!connectedPrinter.acceptsCommands)
{
return false; //Not allowed to do anything.
}
if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline")
{
return false; //Printer is in a state where it can't react to pre-heating.
}
if (preheatCountdownTimer.running)
{
return true; //Can always cancel if the timer is running.
}
if (bedTemperature.properties.minimum_value != "None" && parseInt(preheatTemperatureInput.text) < parseInt(bedTemperature.properties.minimum_value))
{
return false; //Target temperature too low.
}
if (bedTemperature.properties.maximum_value != "None" && parseInt(preheatTemperatureInput.text) > parseInt(bedTemperature.properties.maximum_value))
{
return false; //Target temperature too high.
}
return true; //Preconditions are met.
}
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: UM.Theme.getSize("default_margin").width
style: ButtonStyle {
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("default_margin").width * 2)
border.color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_border");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active_border");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_border");
}
else
{
return UM.Theme.getColor("action_button_border");
}
}
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered");
}
else
{
return UM.Theme.getColor("action_button");
}
}
Behavior on color
{
ColorAnimation
{
duration: 50
}
}
Label
{
id: actualLabel
anchors.centerIn: parent
color:
{
if(!control.enabled)
{
return UM.Theme.getColor("action_button_disabled_text");
}
else if(control.pressed)
{
return UM.Theme.getColor("action_button_active_text");
}
else if(control.hovered)
{
return UM.Theme.getColor("action_button_hovered_text");
}
else
{
return UM.Theme.getColor("action_button_text");
}
}
font: UM.Theme.getFont("action_button")
text: preheatCountdownTimer.running ? catalog.i18nc("@button Cancel pre-heating", "Cancel") : catalog.i18nc("@button", "Pre-heat")
}
}
}
onClicked:
{
if (!preheatCountdownTimer.running)
{
connectedPrinter.preheatBed(preheatTemperatureInput.text, connectedPrinter.preheatBedTimeout);
var now = new Date();
var end_time = new Date();
end_time.setTime(now.getTime() + connectedPrinter.preheatBedTimeout * 1000); //*1000 because time is in milliseconds here.
preheatCountdownTimer.endTime = end_time;
preheatCountdownTimer.start();
preheatCountdownTimer.update(); //Update once before the first timer is triggered.
}
else
{
connectedPrinter.cancelPreheatBed();
preheatCountdownTimer.endTime = new Date();
preheatCountdownTimer.update();
}
}
onHoveredChanged:
{
if (hovered)
{
base.showTooltip(
base,
{x: 0, y: preheatButton.mapToItem(base, 0, 0).y},
catalog.i18nc("@tooltip of pre-heat", "Heat the bed in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the bed to heat up when you're ready to print.")
);
}
else
{
base.hideTooltip();
}
}
}
}
UM.SettingPropertyProvider
{
id: bedTemperature
containerStackId: Cura.MachineManager.activeMachineId
key: "material_bed_temperature"
watchedProperties: ["value", "minimum_value", "maximum_value", "resolve"]
storeIndex: 0
property var resolve: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId ? properties.resolve : "None"
}
UM.SettingPropertyProvider
{
id: machineExtruderCount
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_extruder_count"
watchedProperties: ["value"]
} }
Loader Loader
@ -72,19 +500,19 @@ Column
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Job Name") property string label: catalog.i18nc("@label", "Job Name")
property string value: printerConnected ? connectedPrinter.jobName : "" property string value: connectedPrinter != null ? connectedPrinter.jobName : ""
} }
Loader Loader
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Printing Time") property string label: catalog.i18nc("@label", "Printing Time")
property string value: printerConnected ? getPrettyTime(connectedPrinter.timeTotal) : "" property string value: connectedPrinter != null ? getPrettyTime(connectedPrinter.timeTotal) : ""
} }
Loader Loader
{ {
sourceComponent: monitorItem sourceComponent: monitorItem
property string label: catalog.i18nc("@label", "Estimated time left") property string label: catalog.i18nc("@label", "Estimated time left")
property string value: printerConnected ? getPrettyTime(connectedPrinter.timeTotal - connectedPrinter.timeElapsed) : "" property string value: connectedPrinter != null ? getPrettyTime(connectedPrinter.timeTotal - connectedPrinter.timeElapsed) : ""
} }
Component Component
@ -103,7 +531,7 @@ Column
width: parent.width * 0.4 width: parent.width * 0.4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: label text: label
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") color: connectedPrinter != null && connectedPrinter.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -112,7 +540,7 @@ Column
width: parent.width * 0.6 width: parent.width * 0.6
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: value text: value
color: printerConnected && printerAcceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") color: connectedPrinter != null && connectedPrinter.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -125,7 +553,7 @@ Column
Rectangle Rectangle
{ {
color: UM.Theme.getColor("setting_category") color: UM.Theme.getColor("setting_category")
width: base.width - 2 * UM.Theme.getSize("default_margin").width width: base.width
height: UM.Theme.getSize("section").height height: UM.Theme.getSize("section").height
Label Label

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015 Ultimaker B.V. // Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher. // Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -455,19 +455,6 @@ Rectangle
} }
} }
Label {
id: monitorLabel
text: catalog.i18nc("@label","Printer Monitor");
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
font: UM.Theme.getFont("large")
color: UM.Theme.getColor("text")
visible: monitoringPrint
}
StackView StackView
{ {
id: sidebarContents id: sidebarContents
@ -511,10 +498,8 @@ Rectangle
Loader Loader
{ {
anchors.bottom: footerSeparator.top anchors.bottom: footerSeparator.top
anchors.top: monitorLabel.bottom anchors.top: headerSeparator.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: base.left anchors.left: base.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
anchors.right: base.right anchors.right: base.right
source: monitoringPrint ? "PrintMonitor.qml": "SidebarContents.qml" source: monitoringPrint ? "PrintMonitor.qml": "SidebarContents.qml"
} }

View File

@ -24,6 +24,10 @@
"bold": true, "bold": true,
"family": "Open Sans" "family": "Open Sans"
}, },
"very_small": {
"size": 1.0,
"family": "Open Sans"
},
"button_tooltip": { "button_tooltip": {
"size": 1.0, "size": 1.0,
"family": "Open Sans" "family": "Open Sans"
@ -247,9 +251,11 @@
"sidebar_header_mode_toggle": [0.0, 2.0], "sidebar_header_mode_toggle": [0.0, 2.0],
"sidebar_header_mode_tabs": [0.0, 3.0], "sidebar_header_mode_tabs": [0.0, 3.0],
"sidebar_lining": [0.5, 0.5], "sidebar_lining": [0.5, 0.5],
"sidebar_lining_thin": [0.2, 0.2],
"sidebar_setup": [0.0, 2.0], "sidebar_setup": [0.0, 2.0],
"sidebar_tabs": [0.0, 3.5], "sidebar_tabs": [0.0, 3.5],
"sidebar_inputfields": [0.0, 2.0], "sidebar_inputfields": [0.0, 2.0],
"sidebar_extruder_box": [0.0, 6.0],
"simple_mode_infill_caption": [0.0, 5.0], "simple_mode_infill_caption": [0.0, 5.0],
"simple_mode_infill_height": [0.0, 8.0], "simple_mode_infill_height": [0.0, 8.0],