Merge branch '3.0'

Conflict in ClusterControlItem.qml where there was a new element in Master that wasn't present in 3.0. That element wasn't referenced anywhere else so I just removed it.
This commit is contained in:
Ghostkeeper 2017-10-02 17:40:24 +02:00
commit 1d7792861d
No known key found for this signature in database
GPG Key ID: C5F96EE2BC0F7E75
20 changed files with 221 additions and 73 deletions

View File

@ -304,6 +304,7 @@ class MachineManager(QObject):
quality.nameChanged.connect(self._onQualityNameChanged) quality.nameChanged.connect(self._onQualityNameChanged)
self._active_container_stack = self._global_container_stack self._active_container_stack = self._global_container_stack
self.activeStackChanged.emit()
self._error_check_timer.start() self._error_check_timer.start()

View File

@ -370,7 +370,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
## Overrides an ExtruderStack in the given GlobalStack and returns the new ExtruderStack. ## Overrides an ExtruderStack in the given GlobalStack and returns the new ExtruderStack.
def _overrideExtruderStack(self, global_stack, extruder_file_content): def _overrideExtruderStack(self, global_stack, extruder_file_content):
# get extruder position first # Get extruder position first
extruder_config = configparser.ConfigParser() extruder_config = configparser.ConfigParser()
extruder_config.read_string(extruder_file_content) extruder_config.read_string(extruder_file_content)
if not extruder_config.has_option("metadata", "position"): if not extruder_config.has_option("metadata", "position"):
@ -378,10 +378,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
Logger.log("e", "Could not find 'metadata/position' in extruder stack file") Logger.log("e", "Could not find 'metadata/position' in extruder stack file")
raise RuntimeError(msg) raise RuntimeError(msg)
extruder_position = extruder_config.get("metadata", "position") extruder_position = extruder_config.get("metadata", "position")
extruder_stack = global_stack.extruders[extruder_position] extruder_stack = global_stack.extruders[extruder_position]
# override the given extruder stack # Override the given extruder stack
extruder_stack.deserialize(extruder_file_content) extruder_stack.deserialize(extruder_file_content)
# return the new ExtruderStack # return the new ExtruderStack
@ -699,7 +698,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8") extruder_file_content = archive.open(extruder_stack_file, "r").read().decode("utf-8")
if self._resolve_strategies["machine"] == "override": if self._resolve_strategies["machine"] == "override":
# deserialize new extruder stack over the current ones if global_stack.getProperty("machine_extruder_count", "value") > 1:
# deserialize new extruder stack over the current ones (if any)
stack = self._overrideExtruderStack(global_stack, extruder_file_content) stack = self._overrideExtruderStack(global_stack, extruder_file_content)
elif self._resolve_strategies["machine"] == "new": elif self._resolve_strategies["machine"] == "new":
@ -732,7 +732,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# Create a new definition_changes container if it was empty # Create a new definition_changes container if it was empty
if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer(): if stack.definitionChanges == self._container_registry.getEmptyInstanceContainer():
stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack._id + "_settings")) stack.setDefinitionChanges(CuraStackBuilder.createDefinitionChangesContainer(stack, stack._id + "_settings"))
if global_stack.getProperty("machine_extruder_count", "value") > 1:
extruder_stacks.append(stack) extruder_stacks.append(stack)
except: except:
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.") Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")

View File

@ -6,11 +6,13 @@ import Cura 1.0 as Cura
Component Component
{ {
Item Rectangle
{ {
id: base id: base
property var manager: Cura.MachineManager.printerOutputDevices[0] property var manager: Cura.MachineManager.printerOutputDevices[0]
anchors.fill: parent anchors.fill: parent
color: UM.Theme.getColor("viewport_background")
property var lineColor: "#DCDCDC" // TODO: Should be linked to theme. property var lineColor: "#DCDCDC" // TODO: Should be linked to theme.
property var cornerRadius: 4 * screenScaleFactor // TODO: Should be linked to theme. property var cornerRadius: 4 * screenScaleFactor // TODO: Should be linked to theme.
@ -27,24 +29,17 @@ Component
id: activePrintersLabel id: activePrintersLabel
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.top: parent.top
text: Cura.MachineManager.printerOutputDevices[0].name text: Cura.MachineManager.printerOutputDevices[0].name
} }
Label
{
id: printerGroupLabel
anchors.top: activePrintersLabel.bottom
text: catalog.i18nc("@label", "Printer Group").toUpperCase()
anchors.horizontalCenter: parent.horizontalCenter
font: UM.Theme.getFont("very_small")
opacity: 0.65
}
Rectangle Rectangle
{ {
id: printJobArea id: printJobArea
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
border.color: lineColor border.color: lineColor
anchors.top: printerGroupLabel.bottom anchors.top: activePrintersLabel.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.leftMargin: UM.Theme.getSize("default_margin").width

View File

@ -11,7 +11,7 @@ Component
{ {
width: maximumWidth width: maximumWidth
height: maximumHeight height: maximumHeight
color: "#FFFFFF" // TODO; Should not be hardcoded. color: UM.Theme.getColor("viewport_background")
property var emphasisColor: "#44c0ff" //TODO: should be linked to theme. property var emphasisColor: "#44c0ff" //TODO: should be linked to theme.
property var lineColor: "#DCDCDC" // TODO: Should be linked to theme. property var lineColor: "#DCDCDC" // TODO: Should be linked to theme.

View File

@ -13,10 +13,12 @@ from PyQt5.QtGui import QDesktopServices
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply
from PyQt5.QtQml import QQmlComponent, QQmlContext from PyQt5.QtQml import QQmlComponent, QQmlContext
from UM.Application import Application from UM.Application import Application
from UM.Decorators import override
from UM.Logger import Logger from UM.Logger import Logger
from UM.Message import Message from UM.Message import Message
from UM.OutputDevice import OutputDeviceError from UM.OutputDevice import OutputDeviceError
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Qt.Duration import Duration, DurationFormat
from . import NetworkPrinterOutputDevice from . import NetworkPrinterOutputDevice
@ -44,6 +46,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
else: else:
name = key name = key
self._authentication_state = NetworkPrinterOutputDevice.AuthState.Authenticated # The printer is always authenticated
self._plugin_path = plugin_path self._plugin_path = plugin_path
self.setName(name) self.setName(name)
@ -110,6 +113,20 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
temporary_translation3 = i18n_catalog.i18n("{printer_name} has finished printing '{job_name}'. Please collect the print and confirm clearing the build plate.") #When finished. temporary_translation3 = i18n_catalog.i18n("{printer_name} has finished printing '{job_name}'. Please collect the print and confirm clearing the build plate.") #When finished.
temporary_translation4 = i18n_catalog.i18n("{printer_name} is reserved to print '{job_name}'. Please change the printer's configuration to match the job, for it to start printing.") #When configuration changed. temporary_translation4 = i18n_catalog.i18n("{printer_name} is reserved to print '{job_name}'. Please change the printer's configuration to match the job, for it to start printing.") #When configuration changed.
## No authentication, so requestAuthentication should do exactly nothing
@pyqtSlot()
def requestAuthentication(self, message_id = None, action_id = "Retry"):
pass # Cura Connect doesn't do any authorization
def setAuthenticationState(self, auth_state):
self._authentication_state = NetworkPrinterOutputDevice.AuthState.Authenticated # The printer is always authenticated
def _verifyAuthentication(self):
pass
def _checkAuthentication(self):
Logger.log("d", "_checkAuthentication Cura Connect - nothing to be done")
@pyqtProperty(QObject, notify=selectedPrinterChanged) @pyqtProperty(QObject, notify=selectedPrinterChanged)
def controlItem(self): def controlItem(self):
# TODO: Probably not the nicest way to do this. This needs to be done better at some point in time. # TODO: Probably not the nicest way to do this. This needs to be done better at some point in time.
@ -173,18 +190,19 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
def _requestClusterStatus(self): def _requestClusterStatus(self):
# TODO: Handle timeout. We probably want to know if the cluster is still reachable or not. # TODO: Handle timeout. We probably want to know if the cluster is still reachable or not.
url = QUrl(self._api_base_uri + "print_jobs/")
print_jobs_request = QNetworkRequest(url)
self._addUserAgentHeader(print_jobs_request)
self._manager.get(print_jobs_request)
# See _finishedPrintJobsRequest()
url = QUrl(self._api_base_uri + "printers/") url = QUrl(self._api_base_uri + "printers/")
printers_request = QNetworkRequest(url) printers_request = QNetworkRequest(url)
self._addUserAgentHeader(printers_request) self._addUserAgentHeader(printers_request)
self._manager.get(printers_request) self._manager.get(printers_request)
# See _finishedPrintersRequest() # See _finishedPrintersRequest()
if self._printers: # if printers is not empty
url = QUrl(self._api_base_uri + "print_jobs/")
print_jobs_request = QNetworkRequest(url)
self._addUserAgentHeader(print_jobs_request)
self._manager.get(print_jobs_request)
# See _finishedPrintJobsRequest()
def _finishedPrintJobsRequest(self, reply): def _finishedPrintJobsRequest(self, reply):
try: try:
json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
@ -275,7 +293,10 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
self._file_name = "%s.gcode.gz" % file_name self._file_name = "%s.gcode.gz" % file_name
self._showProgressMessage() self._showProgressMessage()
self._request = self._buildSendPrintJobHttpRequest(require_printer_name) new_request = self._buildSendPrintJobHttpRequest(require_printer_name)
if new_request is None or self._stage != OutputStage.uploading:
return
self._request = new_request
self._reply = self._manager.post(self._request, self._multipart) self._reply = self._manager.post(self._request, self._multipart)
self._reply.uploadProgress.connect(self._onUploadProgress) self._reply.uploadProgress.connect(self._onUploadProgress)
# See _finishedPostPrintJobRequest() # See _finishedPostPrintJobRequest()
@ -294,7 +315,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list") gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list")
compressed_gcode = self._compressGcode(gcode) compressed_gcode = self._compressGcode(gcode)
if compressed_gcode is None: if compressed_gcode is None:
return # User aborted print, so stop trying. return None # User aborted print, so stop trying.
part.setBody(compressed_gcode) part.setBody(compressed_gcode)
self._multipart.append(part) self._multipart.append(part)
@ -331,7 +352,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
for line in gcode: for line in gcode:
if not self._compressing_print: if not self._compressing_print:
self._progress_message.hide() self._progress_message.hide()
return # Stop trying to zip, abort was called. return None # Stop trying to zip, abort was called.
batched_line += line batched_line += line
# if the gcode was read from a gcode file, self._gcode will be a list of all lines in that file. # if the gcode was read from a gcode file, self._gcode will be a list of all lines in that file.
# Compressing line by line in this case is extremely slow, so we need to batch them. # Compressing line by line in this case is extremely slow, so we need to batch them.
@ -489,7 +510,8 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
printer_name = self.__getPrinterNameFromUuid(print_job["assigned_to"]) printer_name = self.__getPrinterNameFromUuid(print_job["assigned_to"])
if printer_name is None: if printer_name is None:
printer_name = i18n_catalog.i18nc("@info:status", "Unknown printer") # don't report on yet unknown printers
continue
message_text = (i18n_catalog.i18n("{printer_name} is reserved to print '{job_name}'. Please change the printer's configuration to match the job, for it to start printing.") message_text = (i18n_catalog.i18n("{printer_name} is reserved to print '{job_name}'. Please change the printer's configuration to match the job, for it to start printing.")
.format(printer_name=printer_name, job_name=print_job["name"])) .format(printer_name=printer_name, job_name=print_job["name"]))
@ -625,9 +647,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
request.setRawHeader(b"User-agent", b"CuraPrintClusterOutputDevice Plugin") request.setRawHeader(b"User-agent", b"CuraPrintClusterOutputDevice Plugin")
def _cleanupRequest(self): def _cleanupRequest(self):
self._reply = None
self._request = None self._request = None
self._multipart = None
self._stage = OutputStage.ready self._stage = OutputStage.ready
self._file_name = None self._file_name = None
@ -680,8 +700,11 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
Logger.log("d", "User aborted sending print to remote.") Logger.log("d", "User aborted sending print to remote.")
self._progress_message.hide() self._progress_message.hide()
self._compressing_print = False self._compressing_print = False
self._stage = OutputStage.ready
if self._reply: if self._reply:
self._reply.abort() self._reply.abort()
self._reply = None self._stage = OutputStage.ready
Application.getInstance().showPrintMonitor.emit(False) Application.getInstance().showPrintMonitor.emit(False)
@pyqtSlot(int, result=str)
def formatDuration(self, seconds):
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)

View File

@ -335,8 +335,11 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
if self._image_reply: if self._image_reply:
try: try:
self._image_reply.abort() try:
self._image_reply.downloadProgress.disconnect(self._onStreamDownloadProgress) self._image_reply.downloadProgress.disconnect(self._onStreamDownloadProgress)
except TypeError:
pass #The signal was never connected.
self._image_reply.abort()
except RuntimeError: except RuntimeError:
pass # It can happen that the wrapped c++ object is already deleted. pass # It can happen that the wrapped c++ object is already deleted.
self._image_reply = None self._image_reply = None
@ -427,7 +430,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
Logger.log("d", "Requestion authentication for %s due to action %s" % (self._key, action_id)) Logger.log("d", "Requestion authentication for %s due to action %s" % (self._key, action_id))
self._authentication_failed_message.hide() self._authentication_failed_message.hide()
self._not_authenticated_message.hide() self._not_authenticated_message.hide()
self._authentication_state = AuthState.NotAuthenticated self.setAuthenticationState(AuthState.NotAuthenticated)
self._authentication_counter = 0 self._authentication_counter = 0
self._authentication_requested_message.setProgress(0) self._authentication_requested_message.setProgress(0)
self._authentication_id = None self._authentication_id = None
@ -614,7 +617,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
# Reset authentication state # Reset authentication state
self._authentication_requested_message.hide() self._authentication_requested_message.hide()
self._authentication_state = AuthState.NotAuthenticated self.setAuthenticationState(AuthState.NotAuthenticated)
self._authentication_counter = 0 self._authentication_counter = 0
self._authentication_timer.stop() self._authentication_timer.stop()

View File

@ -14,5 +14,58 @@ Button {
tooltip: catalog.i18nc("@info:tooltip", "Opens the print jobs page with your default web browser.") tooltip: catalog.i18nc("@info:tooltip", "Opens the print jobs page with your default web browser.")
text: catalog.i18nc("@action:button", "View print jobs") text: catalog.i18nc("@action:button", "View print jobs")
style: UM.Theme.styles.sidebar_action_button // FIXME: This button style is copied and duplicated from SaveButton.qml
style: ButtonStyle {
background: Rectangle
{
border.width: UM.Theme.getSize("default_lining").width
border.color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled_border");
else if(control.pressed)
return UM.Theme.getColor("print_button_ready_pressed_border");
else if(control.hovered)
return UM.Theme.getColor("print_button_ready_hovered_border");
else
return UM.Theme.getColor("print_button_ready_border");
}
color:
{
if(!control.enabled)
return UM.Theme.getColor("action_button_disabled");
else if(control.pressed)
return UM.Theme.getColor("print_button_ready_pressed");
else if(control.hovered)
return UM.Theme.getColor("print_button_ready_hovered");
else
return UM.Theme.getColor("print_button_ready");
}
Behavior on color { ColorAnimation { duration: 50; } }
implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("sidebar_margin").width * 2)
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("print_button_ready_text");
else if(control.hovered)
return UM.Theme.getColor("print_button_ready_text");
else
return UM.Theme.getColor("print_button_ready_text");
}
font: UM.Theme.getFont("action_button")
text: control.text;
}
}
label: Item { }
}
} }

View File

@ -14,14 +14,7 @@ Rectangle
function getPrettyTime(time) function getPrettyTime(time)
{ {
var hours = Math.floor(time / 3600) return OutputDevice.formatDuration(time)
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;
} }
function formatPrintJobPercent(printJob) function formatPrintJobPercent(printJob)
@ -37,6 +30,23 @@ Rectangle
return Math.min(100, Math.round(printJob.time_elapsed / printJob.time_total * 100)) + "%"; return Math.min(100, Math.round(printJob.time_elapsed / printJob.time_total * 100)) + "%";
} }
function printerStatusText(printer)
{
switch (printer.status)
{
case "pre_print":
return catalog.i18nc("@label", "Preparing to print")
case "printing":
return catalog.i18nc("@label:status", "Printing");
case "idle":
return catalog.i18nc("@label:status", "Available");
case "unreachable": // TODO: new string
case "maintenance": // TODO: new string
case "unknown":
default:
return catalog.i18nc("@label", "Unknown");
}
}
id: printerDelegate id: printerDelegate
property var printer property var printer
@ -143,14 +153,14 @@ Rectangle
anchors.right: printProgressArea.left anchors.right: printProgressArea.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.rightMargin: UM.Theme.getSize("default_margin").width
color: emphasisColor color: emphasisColor
UM.RecolorImage
Image
{ {
anchors.verticalCenter: parent.verticalCenter width: 40 * screenScaleFactor
anchors.horizontalCenter: parent.horizontalCenter height: width
anchors.right: parent.right
anchors.rightMargin: parent.rightMargin
source: "camera-icon.svg" source: "camera-icon.svg"
width: sourceSize.width
height: sourceSize.height * width / sourceSize.width
color: "white"
} }
} }
@ -217,6 +227,9 @@ Rectangle
//border.color: lineColor //border.color: lineColor
height: 40 * screenScaleFactor height: 40 * screenScaleFactor
anchors.left: parent.left anchors.left: parent.left
property var showPercent: {
return printJob != null && (["printing", "post_print", "pre_print", "sent_to_printer"].indexOf(printJob.status) !== -1);
}
Label Label
{ {
@ -232,7 +245,7 @@ Rectangle
return catalog.i18nc("@label:status", "Disabled"); return catalog.i18nc("@label:status", "Disabled");
} }
if(printJob != null) if ((printJob != null) && ((printer.status === "pre_print") || (printer.status === "printing")))
{ {
switch (printJob.status) switch (printJob.status)
{ {
@ -263,16 +276,17 @@ Rectangle
case "aborted": case "aborted":
return catalog.i18nc("@label:status", "Print aborted"); return catalog.i18nc("@label:status", "Print aborted");
default: default:
return ""; return printerStatusText(printer);
} }
} }
return catalog.i18nc("@label:status", "Available"); return printerStatusText(printer);
} }
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("small") font: UM.Theme.getFont("small")
} }
Label Label
{ {
id: progressText id: progressText
@ -282,10 +296,44 @@ Rectangle
anchors.top: statusText.top anchors.top: statusText.top
text: formatPrintJobPercent(printJob) text: formatPrintJobPercent(printJob)
visible: printJob != null && (["printing", "post_print", "pre_print", "sent_to_printer"].indexOf(printJob.status) !== -1) visible: printProgressTitleBar.showPercent
opacity: 0.65 opacity: 0.65
font: UM.Theme.getFont("very_small") font: UM.Theme.getFont("very_small")
} }
Image
{
width: statusText.height
height: width
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.top: statusText.top
visible: ! printProgressTitleBar.showPercent
source: {
if ( ! printer.enabled)
{
return "blocked-icon.svg";
}
if (printJob != null)
{
if(printJob.status === "queued")
{
if (printJob.configuration_changes_required != null && printJob.configuration_changes_required.length !== 0)
{
return "action-required-icon.svg";
}
}
else if (printJob.status === "wait_cleanup")
{
return "checkmark-icon.svg";
}
}
return ""; // We're not going to show it, so it will not be resolved as a url.
}
}
Rectangle Rectangle
{ {
//TODO: This will become a progress bar in the future //TODO: This will become a progress bar in the future
@ -308,7 +356,7 @@ Rectangle
width: parent.width - 2 * UM.Theme.getSize("default_margin").width width: parent.width - 2 * UM.Theme.getSize("default_margin").width
visible: showExtended visible: printProgressArea.showExtended
Label // Status detail Label // Status detail
{ {

View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<defs>
<path id="a" d="M13.774 1.412l9.706 18.665A2 2 0 0 1 21.706 23H2.294A2 2 0 0 1 .52 20.077l9.706-18.665a2 2 0 0 1 3.548 0z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<use fill="#FFF" xlink:href="#a"/>
<path stroke="#000" stroke-width="2.4" d="M12.71 1.966a.8.8 0 0 0-1.42 0L1.584 20.631a.8.8 0 0 0 .71 1.169h19.412a.8.8 0 0 0 .71-1.17L12.71 1.967z"/>
<path fill="#000" d="M13.144 14.995h-2.29L10.5 8h2.998l-.354 6.995zm-2.612 2.502c0-.475.13-.844.388-1.108.258-.263.633-.395 1.125-.395.488 0 .857.132 1.108.395.251.264.377.633.377 1.108 0 .47-.13.836-.39 1.1-.261.263-.626.395-1.095.395-.473 0-.843-.132-1.111-.396-.268-.263-.402-.63-.402-1.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 844 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="#000" fill-rule="evenodd" d="M6 10h12v4H6v-4zm6 14c6.627 0 12-5.373 12-12S18.627 0 12 0 0 5.373 0 12s5.373 12 12 12z"/>
</svg>

After

Width:  |  Height:  |  Size: 227 B

View File

@ -1,3 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="14" viewBox="0 0 21 14"> <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
<path fill="none" fill-rule="evenodd" stroke="#464B4E" stroke-width="1.5" d="M19.295 2.83L16.25 4.31V2c0-.69-.56-1.25-1.25-1.25H2C1.31.75.75 1.31.75 2v10c0 .69.56 1.25 1.25 1.25h13c.69 0 1.25-.56 1.25-1.25V9.69l3.045 1.48a.85.85 0 0 0 .367.08c.355 0 .584-.181.584-.31V3.06c0-.026-.011-.058-.04-.096-.16-.206-.592-.289-.911-.134z" opacity=".85"/> <g fill="none" fill-rule="evenodd">
<!-- <rect width="48" height="48" fill="#00A6EC" rx="24"/>-->
<path stroke="#FFF" stroke-width="2.5" d="M32.75 16.25h-19.5v15.5h19.5v-4.51l3.501 1.397c.181.072.405.113.638.113.333 0 .627-.081.81-.2.036-.024.048-.028.051-.011V18.487c-.26-.23-.976-.332-1.499-.124L32.75 19.76v-3.51z"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 441 B

After

Width:  |  Height:  |  Size: 438 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" fill-rule="evenodd" stroke="#000" stroke-width="3" d="M3 10.71L10.068 17 21 5"/>
</svg>

After

Width:  |  Height:  |  Size: 194 B

View File

@ -14,6 +14,7 @@
"platform_texture": "Ultimaker2backplate.png", "platform_texture": "Ultimaker2backplate.png",
"platform_offset": [9, 0, 0], "platform_offset": [9, 0, 0],
"has_materials": false, "has_materials": false,
"has_machine_quality": true,
"first_start_actions": ["UM2UpgradeSelection"], "first_start_actions": ["UM2UpgradeSelection"],
"supported_actions":["UM2UpgradeSelection", "UpgradeFirmware"] "supported_actions":["UM2UpgradeSelection", "UpgradeFirmware"]
}, },

View File

@ -386,8 +386,6 @@ UM.MainWindow
visible: opacity > 0 visible: opacity > 0
opacity: base.showPrintMonitor ? 1 : 0 opacity: base.showPrintMonitor ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 100; } }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.AllButtons acceptedButtons: Qt.AllButtons
@ -818,7 +816,7 @@ UM.MainWindow
Connections Connections
{ {
target: Printer target: CuraApplication
onShowDiscardOrKeepProfileChanges: onShowDiscardOrKeepProfileChanges:
{ {
discardOrKeepProfileChangesDialog.show() discardOrKeepProfileChangesDialog.show()

View File

@ -76,7 +76,7 @@ Item
property var totalTicks: 0 property var totalTicks: 0
property var availableTotalTicks: 0 property var availableTotalTicks: 0
property var activeQualityId: 0 property var activeQualityIndex: 0
property var qualitySliderStepWidth: 0 property var qualitySliderStepWidth: 0
property var qualitySliderAvailableMin : 0 property var qualitySliderAvailableMin : 0
@ -97,7 +97,7 @@ Item
// Set selected value // Set selected value
if (Cura.MachineManager.activeQualityId == qualityItem.id) { if (Cura.MachineManager.activeQualityId == qualityItem.id) {
qualityModel.activeQualityId = i qualityModel.activeQualityIndex = i
} }
// Set min available // Set min available
@ -144,11 +144,15 @@ Item
// check, the ticks count cannot be less than zero // check, the ticks count cannot be less than zero
if(Cura.ProfilesModel.rowCount() != 0) if(Cura.ProfilesModel.rowCount() != 0)
{
qualityModel.totalTicks = Cura.ProfilesModel.rowCount() - 1 // minus one, because slider starts from 0 qualityModel.totalTicks = Cura.ProfilesModel.rowCount() - 1 // minus one, because slider starts from 0
}
else else
{
qualityModel.totalTicks = 0 qualityModel.totalTicks = 0
} }
} }
}
Text Text
{ {
@ -264,7 +268,7 @@ Item
maximumValue: qualityModel.qualitySliderAvailableMax >= 0 ? qualityModel.qualitySliderAvailableMax : 0 maximumValue: qualityModel.qualitySliderAvailableMax >= 0 ? qualityModel.qualitySliderAvailableMax : 0
stepSize: 1 stepSize: 1
value: qualityModel.activeQualityId value: qualityModel.activeQualityIndex
width: qualityModel.qualitySliderStepWidth * qualityModel.availableTotalTicks width: qualityModel.qualitySliderStepWidth * qualityModel.availableTotalTicks
@ -292,10 +296,11 @@ Item
} }
onValueChanged: { onValueChanged: {
if(Cura.MachineManager.activeMachine != null) // Only change if an active machine is set and the slider is visible at all.
if(Cura.MachineManager.activeMachine != null && visible)
{ {
//Prevent updating during view initializing. Trigger only if the value changed by user //Prevent updating during view initializing. Trigger only if the value changed by user
if(qualitySlider.value != qualityModel.activeQualityId) if(qualitySlider.value != qualityModel.activeQualityIndex)
{ {
//start updating with short delay //start updating with short delay
qualitySliderChangeTimer.start(); qualitySliderChangeTimer.start();

View File

@ -16,7 +16,7 @@
"secondary": [241, 242, 242, 255], "secondary": [241, 242, 242, 255],
"topbar_background_color": [0, 0, 0, 0], "topbar_background_color": [0, 0, 0, 0],
"topbar_background_color_monitoring": [39, 44, 48, 255], "topbar_background_color_monitoring": [0, 0, 0, 0],
"topbar_button_text_active": [255, 255, 255, 255], "topbar_button_text_active": [255, 255, 255, 255],
"topbar_button_text_inactive": [128, 128, 128, 255], "topbar_button_text_inactive": [128, 128, 128, 255],

View File

@ -68,7 +68,7 @@
"secondary": [245, 245, 245, 255], "secondary": [245, 245, 245, 255],
"topbar_background_color": [255, 255, 255, 0], "topbar_background_color": [255, 255, 255, 0],
"topbar_background_color_monitoring": [255, 255, 255, 255], "topbar_background_color_monitoring": [255, 255, 255, 0],
"topbar_button_text_active": [0, 0, 0, 255], "topbar_button_text_active": [0, 0, 0, 255],
"topbar_button_text_inactive": [128, 128, 128, 255], "topbar_button_text_inactive": [128, 128, 128, 255],

View File

@ -1,6 +1,8 @@
#Todo: Write tests #Todo: Write tests
import pytest import pytest
# QtApplication needs to be imported first to prevent import errors.
from UM.Qt.QtApplication import QtApplication
from cura.MachineAction import MachineAction from cura.MachineAction import MachineAction
from cura.MachineActionManager import MachineActionManager, NotUniqueMachineActionError, UnknownMachineActionError from cura.MachineActionManager import MachineActionManager, NotUniqueMachineActionError, UnknownMachineActionError