Merge branch 'master' into temp_CURA-5864

This commit is contained in:
Remco Burema 2019-02-06 16:23:30 +01:00
commit da6ff7c5a9
95 changed files with 2061 additions and 1277 deletions

View File

@ -17,6 +17,7 @@ if(CURA_DEBUGMODE)
set(_cura_debugmode "ON") set(_cura_debugmode "ON")
endif() endif()
set(CURA_APP_NAME "cura" CACHE STRING "Short name of Cura, used for configuration folder")
set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura") set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura")
set(CURA_VERSION "master" CACHE STRING "Version name of Cura") set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")

View File

@ -2,14 +2,22 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
# --------- # ---------
# Genearl constants used in Cura # General constants used in Cura
# --------- # ---------
DEFAULT_CURA_APP_NAME = "cura"
DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura" DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura"
DEFAULT_CURA_VERSION = "master" DEFAULT_CURA_VERSION = "master"
DEFAULT_CURA_BUILD_TYPE = "" DEFAULT_CURA_BUILD_TYPE = ""
DEFAULT_CURA_DEBUG_MODE = False DEFAULT_CURA_DEBUG_MODE = False
DEFAULT_CURA_SDK_VERSION = "6.0.0" DEFAULT_CURA_SDK_VERSION = "6.0.0"
try:
from cura.CuraVersion import CuraAppName # type: ignore
if CuraAppName == "":
CuraAppName = DEFAULT_CURA_APP_NAME
except ImportError:
CuraAppName = DEFAULT_CURA_APP_NAME
try: try:
from cura.CuraVersion import CuraAppDisplayName # type: ignore from cura.CuraVersion import CuraAppDisplayName # type: ignore
if CuraAppDisplayName == "": if CuraAppDisplayName == "":

View File

@ -156,7 +156,7 @@ class CuraApplication(QtApplication):
Q_ENUMS(ResourceTypes) Q_ENUMS(ResourceTypes)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(name = "cura", super().__init__(name = ApplicationMetadata.CuraAppName,
app_display_name = ApplicationMetadata.CuraAppDisplayName, app_display_name = ApplicationMetadata.CuraAppDisplayName,
version = ApplicationMetadata.CuraVersion, version = ApplicationMetadata.CuraVersion,
api_version = ApplicationMetadata.CuraSDKVersion, api_version = ApplicationMetadata.CuraSDKVersion,

View File

@ -1,6 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
CuraAppName = "@CURA_APP_NAME@"
CuraAppDisplayName = "@CURA_APP_DISPLAY_NAME@" CuraAppDisplayName = "@CURA_APP_DISPLAY_NAME@"
CuraVersion = "@CURA_VERSION@" CuraVersion = "@CURA_VERSION@"
CuraBuildType = "@CURA_BUILDTYPE@" CuraBuildType = "@CURA_BUILDTYPE@"

View File

@ -1,12 +1,11 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtProperty, Qt from PyQt5.QtCore import Qt
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Settings.ContainerRegistry import ContainerRegistry
from cura.PrinterOutputDevice import ConnectionType from cura.PrinterOutputDevice import ConnectionType
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
class GlobalStacksModel(ListModel): class GlobalStacksModel(ListModel):
@ -21,14 +20,13 @@ class GlobalStacksModel(ListModel):
self.addRoleName(self.NameRole, "name") self.addRoleName(self.NameRole, "name")
self.addRoleName(self.IdRole, "id") self.addRoleName(self.IdRole, "id")
self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection") self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection")
self.addRoleName(self.ConnectionTypeRole, "connectionType")
self.addRoleName(self.MetaDataRole, "metadata") self.addRoleName(self.MetaDataRole, "metadata")
self._container_stacks = [] self._container_stacks = []
# Listen to changes # Listen to changes
ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged)
ContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged)
ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged)
self._filter_dict = {} self._filter_dict = {}
self._update() self._update()
@ -43,19 +41,20 @@ class GlobalStacksModel(ListModel):
def _update(self) -> None: def _update(self) -> None:
items = [] items = []
container_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") container_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine")
for container_stack in container_stacks: for container_stack in container_stacks:
connection_type = int(container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) has_remote_connection = False
has_remote_connection = connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value]
for connection_type in container_stack.configuredConnectionTypes:
has_remote_connection |= connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value]
if container_stack.getMetaDataEntry("hidden", False) in ["True", True]: if container_stack.getMetaDataEntry("hidden", False) in ["True", True]:
continue continue
# TODO: Remove reference to connect group name. items.append({"name": container_stack.getMetaDataEntry("group_name", container_stack.getName()),
items.append({"name": container_stack.getMetaDataEntry("connect_group_name", container_stack.getName()),
"id": container_stack.getId(), "id": container_stack.getId(),
"hasRemoteConnection": has_remote_connection, "hasRemoteConnection": has_remote_connection,
"connectionType": connection_type,
"metadata": container_stack.getMetaData().copy()}) "metadata": container_stack.getMetaData().copy()})
items.sort(key=lambda i: not i["hasRemoteConnection"]) items.sort(key=lambda i: not i["hasRemoteConnection"])
self.setItems(items) self.setItems(items)

View File

@ -7,43 +7,36 @@ from UM.Mesh.MeshBuilder import MeshBuilder
from .LayerData import LayerData from .LayerData import LayerData
import numpy import numpy
from typing import Dict, Optional
## Builder class for constructing a LayerData object ## Builder class for constructing a LayerData object
class LayerDataBuilder(MeshBuilder): class LayerDataBuilder(MeshBuilder):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._layers = {} self._layers = {} # type: Dict[int, Layer]
self._element_counts = {} self._element_counts = {} # type: Dict[int, int]
def addLayer(self, layer): def addLayer(self, layer: int) -> None:
if layer not in self._layers: if layer not in self._layers:
self._layers[layer] = Layer(layer) self._layers[layer] = Layer(layer)
def addPolygon(self, layer, polygon_type, data, line_width, line_thickness, line_feedrate): def getLayer(self, layer: int) -> Optional[Layer]:
if layer not in self._layers: return self._layers.get(layer)
self.addLayer(layer)
p = LayerPolygon(self, polygon_type, data, line_width, line_thickness, line_feedrate) def getLayers(self) -> Dict[int, Layer]:
self._layers[layer].polygons.append(p)
def getLayer(self, layer):
if layer in self._layers:
return self._layers[layer]
def getLayers(self):
return self._layers return self._layers
def getElementCounts(self): def getElementCounts(self) -> Dict[int, int]:
return self._element_counts return self._element_counts
def setLayerHeight(self, layer, height): def setLayerHeight(self, layer: int, height: float) -> None:
if layer not in self._layers: if layer not in self._layers:
self.addLayer(layer) self.addLayer(layer)
self._layers[layer].setHeight(height) self._layers[layer].setHeight(height)
def setLayerThickness(self, layer, thickness): def setLayerThickness(self, layer: int, thickness: float) -> None:
if layer not in self._layers: if layer not in self._layers:
self.addLayer(layer) self.addLayer(layer)
@ -71,7 +64,7 @@ class LayerDataBuilder(MeshBuilder):
vertex_offset = 0 vertex_offset = 0
index_offset = 0 index_offset = 0
for layer, data in sorted(self._layers.items()): for layer, data in sorted(self._layers.items()):
( vertex_offset, index_offset ) = data.build( vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices) vertex_offset, index_offset = data.build(vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices)
self._element_counts[layer] = data.elementCount self._element_counts[layer] = data.elementCount
self.addVertices(vertices) self.addVertices(vertices)

View File

@ -1,13 +1,25 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from cura.LayerData import LayerData
## Simple decorator to indicate a scene node holds layer data. ## Simple decorator to indicate a scene node holds layer data.
class LayerDataDecorator(SceneNodeDecorator): class LayerDataDecorator(SceneNodeDecorator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._layer_data = None self._layer_data = None # type: Optional[LayerData]
def getLayerData(self): def getLayerData(self) -> Optional["LayerData"]:
return self._layer_data return self._layer_data
def setLayerData(self, layer_data): def setLayerData(self, layer_data: LayerData) -> None:
self._layer_data = layer_data self._layer_data = layer_data
def __deepcopy__(self, memo) -> "LayerDataDecorator":
copied_decorator = LayerDataDecorator()
copied_decorator._layer_data = self._layer_data
return copied_decorator

View File

@ -2,7 +2,7 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from UM.Application import Application from UM.Application import Application
from typing import Any from typing import Any, Optional
import numpy import numpy
from UM.Logger import Logger from UM.Logger import Logger
@ -26,13 +26,13 @@ class LayerPolygon:
__jump_map = numpy.logical_or(numpy.logical_or(numpy.arange(__number_of_types) == NoneType, numpy.arange(__number_of_types) == MoveCombingType), numpy.arange(__number_of_types) == MoveRetractionType) __jump_map = numpy.logical_or(numpy.logical_or(numpy.arange(__number_of_types) == NoneType, numpy.arange(__number_of_types) == MoveCombingType), numpy.arange(__number_of_types) == MoveRetractionType)
## LayerPolygon, used in ProcessSlicedLayersJob ## LayerPolygon, used in ProcessSlicedLayersJob
# \param extruder # \param extruder The position of the extruder
# \param line_types array with line_types # \param line_types array with line_types
# \param data new_points # \param data new_points
# \param line_widths array with line widths # \param line_widths array with line widths
# \param line_thicknesses: array with type as index and thickness as value # \param line_thicknesses: array with type as index and thickness as value
# \param line_feedrates array with line feedrates # \param line_feedrates array with line feedrates
def __init__(self, extruder, line_types, data, line_widths, line_thicknesses, line_feedrates): def __init__(self, extruder: int, line_types: numpy.ndarray, data: numpy.ndarray, line_widths: numpy.ndarray, line_thicknesses: numpy.ndarray, line_feedrates: numpy.ndarray) -> None:
self._extruder = extruder self._extruder = extruder
self._types = line_types self._types = line_types
for i in range(len(self._types)): for i in range(len(self._types)):
@ -57,16 +57,16 @@ class LayerPolygon:
# Buffering the colors shouldn't be necessary as it is not # Buffering the colors shouldn't be necessary as it is not
# re-used and can save alot of memory usage. # re-used and can save alot of memory usage.
self._color_map = LayerPolygon.getColorMap() self._color_map = LayerPolygon.getColorMap()
self._colors = self._color_map[self._types] self._colors = self._color_map[self._types] # type: numpy.ndarray
# When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType # When type is used as index returns true if type == LayerPolygon.InfillType or type == LayerPolygon.SkinType or type == LayerPolygon.SupportInfillType
# Should be generated in better way, not hardcoded. # Should be generated in better way, not hardcoded.
self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1], dtype=numpy.bool) self._isInfillOrSkinTypeMap = numpy.array([0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1], dtype=numpy.bool)
self._build_cache_line_mesh_mask = None self._build_cache_line_mesh_mask = None # type: Optional[numpy.ndarray]
self._build_cache_needed_points = None self._build_cache_needed_points = None # type: Optional[numpy.ndarray]
def buildCache(self): def buildCache(self) -> None:
# For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out. # For the line mesh we do not draw Infill or Jumps. Therefore those lines are filtered out.
self._build_cache_line_mesh_mask = numpy.ones(self._jump_mask.shape, dtype=bool) self._build_cache_line_mesh_mask = numpy.ones(self._jump_mask.shape, dtype=bool)
mesh_line_count = numpy.sum(self._build_cache_line_mesh_mask) mesh_line_count = numpy.sum(self._build_cache_line_mesh_mask)
@ -94,10 +94,14 @@ class LayerPolygon:
# \param extruders : vertex numpy array to be filled # \param extruders : vertex numpy array to be filled
# \param line_types : vertex numpy array to be filled # \param line_types : vertex numpy array to be filled
# \param indices : index numpy array to be filled # \param indices : index numpy array to be filled
def build(self, vertex_offset, index_offset, vertices, colors, line_dimensions, feedrates, extruders, line_types, indices): def build(self, vertex_offset: int, index_offset: int, vertices: numpy.ndarray, colors: numpy.ndarray, line_dimensions: numpy.ndarray, feedrates: numpy.ndarray, extruders: numpy.ndarray, line_types: numpy.ndarray, indices: numpy.ndarray) -> None:
if self._build_cache_line_mesh_mask is None or self._build_cache_needed_points is None: if self._build_cache_line_mesh_mask is None or self._build_cache_needed_points is None:
self.buildCache() self.buildCache()
if self._build_cache_line_mesh_mask is None or self._build_cache_needed_points is None:
Logger.log("w", "Failed to build cache for layer polygon")
return
line_mesh_mask = self._build_cache_line_mesh_mask line_mesh_mask = self._build_cache_line_mesh_mask
needed_points_list = self._build_cache_needed_points needed_points_list = self._build_cache_needed_points

View File

@ -52,14 +52,14 @@ class MachineManagementModel(ListModel):
"um_network_key": "*", "um_network_key": "*",
"hidden": "False"} "hidden": "False"}
self._network_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**network_filter_printers) self._network_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**network_filter_printers)
self._network_container_stacks.sort(key = lambda i: i.getMetaDataEntry("connect_group_name")) self._network_container_stacks.sort(key = lambda i: i.getMetaDataEntry("group_name", ""))
for container in self._network_container_stacks: for container in self._network_container_stacks:
metadata = container.getMetaData().copy() metadata = container.getMetaData().copy()
if container.getBottom(): if container.getBottom():
metadata["definition_name"] = container.getBottom().getName() metadata["definition_name"] = container.getBottom().getName()
items.append({"name": metadata["connect_group_name"], items.append({"name": metadata.get("group_name", ""),
"id": container.getId(), "id": container.getId(),
"metadata": metadata, "metadata": metadata,
"group": catalog.i18nc("@info:title", "Network enabled printers")}) "group": catalog.i18nc("@info:title", "Network enabled printers")})

View File

@ -81,8 +81,8 @@ class GenericOutputController(PrinterOutputController):
self._output_device.cancelPrint() self._output_device.cancelPrint()
pass pass
def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int) -> None: def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: float) -> None:
self._output_device.sendCommand("M140 S%s" % temperature) self._output_device.sendCommand("M140 S%s" % round(temperature)) # The API doesn't allow floating point.
def _onTargetBedTemperatureChanged(self) -> None: def _onTargetBedTemperatureChanged(self) -> None:
if self._preheat_bed_timer.isActive() and self._preheat_printer and self._preheat_printer.targetBedTemperature == 0: if self._preheat_bed_timer.isActive() and self._preheat_printer and self._preheat_printer.targetBedTemperature == 0:
@ -96,14 +96,14 @@ class GenericOutputController(PrinterOutputController):
except ValueError: except ValueError:
return # Got invalid values, can't pre-heat. return # Got invalid values, can't pre-heat.
self.setTargetBedTemperature(printer, temperature=temperature) self.setTargetBedTemperature(printer, temperature = temperature)
self._preheat_bed_timer.setInterval(duration * 1000) self._preheat_bed_timer.setInterval(duration * 1000)
self._preheat_bed_timer.start() self._preheat_bed_timer.start()
self._preheat_printer = printer self._preheat_printer = printer
printer.updateIsPreheating(True) printer.updateIsPreheating(True)
def cancelPreheatBed(self, printer: "PrinterOutputModel") -> None: def cancelPreheatBed(self, printer: "PrinterOutputModel") -> None:
self.setTargetBedTemperature(printer, temperature=0) self.setTargetBedTemperature(printer, temperature = 0)
self._preheat_bed_timer.stop() self._preheat_bed_timer.stop()
printer.updateIsPreheating(False) printer.updateIsPreheating(False)

View File

@ -132,8 +132,7 @@ class PrintJobOutputModel(QObject):
@pyqtProperty(float, notify = timeElapsedChanged) @pyqtProperty(float, notify = timeElapsedChanged)
def progress(self) -> float: def progress(self) -> float:
time_elapsed = max(float(self.timeElapsed), 1.0) # Prevent a division by zero exception result = float(self.timeElapsed) / max(self.timeTotal, 1.0) # Prevent a division by zero exception.
result = time_elapsed / self.timeTotal
return min(result, 1.0) # Never get a progress past 1.0 return min(result, 1.0) # Never get a progress past 1.0
@pyqtProperty(str, notify=stateChanged) @pyqtProperty(str, notify=stateChanged)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from UM.Logger import Logger from UM.Logger import Logger
@ -25,10 +25,10 @@ class PrinterOutputController:
self.can_update_firmware = False self.can_update_firmware = False
self._output_device = output_device self._output_device = output_device
def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: Union[int, float]) -> None: def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: float) -> None:
Logger.log("w", "Set target hotend temperature not implemented in controller") Logger.log("w", "Set target hotend temperature not implemented in controller")
def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int) -> None: def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: float) -> None:
Logger.log("w", "Set target bed temperature not implemented in controller") Logger.log("w", "Set target bed temperature not implemented in controller")
def setJobState(self, job: "PrintJobOutputModel", state: str) -> None: def setJobState(self, job: "PrintJobOutputModel", state: str) -> None:

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot, QUrl from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot, QUrl
@ -30,8 +30,8 @@ class PrinterOutputModel(QObject):
def __init__(self, output_controller: "PrinterOutputController", number_of_extruders: int = 1, parent=None, firmware_version = "") -> None: def __init__(self, output_controller: "PrinterOutputController", number_of_extruders: int = 1, parent=None, firmware_version = "") -> None:
super().__init__(parent) super().__init__(parent)
self._bed_temperature = -1 # Use -1 for no heated bed. self._bed_temperature = -1 # type: float # Use -1 for no heated bed.
self._target_bed_temperature = 0 self._target_bed_temperature = 0 # type: float
self._name = "" self._name = ""
self._key = "" # Unique identifier self._key = "" # Unique identifier
self._controller = output_controller self._controller = output_controller
@ -188,19 +188,19 @@ class PrinterOutputModel(QObject):
self.nameChanged.emit() self.nameChanged.emit()
## Update the bed temperature. This only changes it locally. ## Update the bed temperature. This only changes it locally.
def updateBedTemperature(self, temperature: int) -> None: def updateBedTemperature(self, temperature: float) -> None:
if self._bed_temperature != temperature: if self._bed_temperature != temperature:
self._bed_temperature = temperature self._bed_temperature = temperature
self.bedTemperatureChanged.emit() self.bedTemperatureChanged.emit()
def updateTargetBedTemperature(self, temperature: int) -> None: def updateTargetBedTemperature(self, temperature: float) -> None:
if self._target_bed_temperature != temperature: if self._target_bed_temperature != temperature:
self._target_bed_temperature = temperature self._target_bed_temperature = temperature
self.targetBedTemperatureChanged.emit() self.targetBedTemperatureChanged.emit()
## Set the target bed temperature. This ensures that it's actually sent to the remote. ## Set the target bed temperature. This ensures that it's actually sent to the remote.
@pyqtSlot(int) @pyqtSlot(float)
def setTargetBedTemperature(self, temperature: int) -> None: def setTargetBedTemperature(self, temperature: float) -> None:
self._controller.setTargetBedTemperature(self, temperature) self._controller.setTargetBedTemperature(self, temperature)
self.updateTargetBedTemperature(temperature) self.updateTargetBedTemperature(temperature)
@ -225,55 +225,55 @@ class PrinterOutputModel(QObject):
def activePrintJob(self) -> Optional["PrintJobOutputModel"]: def activePrintJob(self) -> Optional["PrintJobOutputModel"]:
return self._active_print_job return self._active_print_job
@pyqtProperty(str, notify=stateChanged) @pyqtProperty(str, notify = stateChanged)
def state(self) -> str: def state(self) -> str:
return self._printer_state return self._printer_state
@pyqtProperty(int, notify=bedTemperatureChanged) @pyqtProperty(float, notify = bedTemperatureChanged)
def bedTemperature(self) -> int: def bedTemperature(self) -> float:
return self._bed_temperature return self._bed_temperature
@pyqtProperty(int, notify=targetBedTemperatureChanged) @pyqtProperty(float, notify = targetBedTemperatureChanged)
def targetBedTemperature(self) -> int: def targetBedTemperature(self) -> float:
return self._target_bed_temperature return self._target_bed_temperature
# Does the printer support pre-heating the bed at all # Does the printer support pre-heating the bed at all
@pyqtProperty(bool, constant=True) @pyqtProperty(bool, constant = True)
def canPreHeatBed(self) -> bool: def canPreHeatBed(self) -> bool:
if self._controller: if self._controller:
return self._controller.can_pre_heat_bed return self._controller.can_pre_heat_bed
return False return False
# Does the printer support pre-heating the bed at all # Does the printer support pre-heating the bed at all
@pyqtProperty(bool, constant=True) @pyqtProperty(bool, constant = True)
def canPreHeatHotends(self) -> bool: def canPreHeatHotends(self) -> bool:
if self._controller: if self._controller:
return self._controller.can_pre_heat_hotends return self._controller.can_pre_heat_hotends
return False return False
# Does the printer support sending raw G-code at all # Does the printer support sending raw G-code at all
@pyqtProperty(bool, constant=True) @pyqtProperty(bool, constant = True)
def canSendRawGcode(self) -> bool: def canSendRawGcode(self) -> bool:
if self._controller: if self._controller:
return self._controller.can_send_raw_gcode return self._controller.can_send_raw_gcode
return False return False
# Does the printer support pause at all # Does the printer support pause at all
@pyqtProperty(bool, constant=True) @pyqtProperty(bool, constant = True)
def canPause(self) -> bool: def canPause(self) -> bool:
if self._controller: if self._controller:
return self._controller.can_pause return self._controller.can_pause
return False return False
# Does the printer support abort at all # Does the printer support abort at all
@pyqtProperty(bool, constant=True) @pyqtProperty(bool, constant = True)
def canAbort(self) -> bool: def canAbort(self) -> bool:
if self._controller: if self._controller:
return self._controller.can_abort return self._controller.can_abort
return False return False
# Does the printer support manual control at all # Does the printer support manual control at all
@pyqtProperty(bool, constant=True) @pyqtProperty(bool, constant = True)
def canControlManually(self) -> bool: def canControlManually(self) -> bool:
if self._controller: if self._controller:
return self._controller.can_control_manually return self._controller.can_control_manually

View File

@ -10,10 +10,10 @@ class GCodeListDecorator(SceneNodeDecorator):
def getGCodeList(self) -> List[str]: def getGCodeList(self) -> List[str]:
return self._gcode_list return self._gcode_list
def setGCodeList(self, list: List[str]): def setGCodeList(self, list: List[str]) -> None:
self._gcode_list = list self._gcode_list = list
def __deepcopy__(self, memo) -> "GCodeListDecorator": def __deepcopy__(self, memo) -> "GCodeListDecorator":
copied_decorator = GCodeListDecorator() copied_decorator = GCodeListDecorator()
copied_decorator.setGCodeList(self.getGCodeList()) copied_decorator.setGCodeList(self.getGCodeList())
return copied_decorator return copied_decorator

View File

@ -107,17 +107,19 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
# that signal. Application.globalContainerStackChanged doesn't fill this # that signal. Application.globalContainerStackChanged doesn't fill this
# signal; it's assumed to be the current printer in that case. # signal; it's assumed to be the current printer in that case.
def _extrudersChanged(self, machine_id = None): def _extrudersChanged(self, machine_id = None):
machine_manager = Application.getInstance().getMachineManager()
if machine_id is not None: if machine_id is not None:
if Application.getInstance().getGlobalContainerStack() is None: if machine_manager.activeMachine is None:
# No machine, don't need to update the current machine's extruders # No machine, don't need to update the current machine's extruders
return return
if machine_id != Application.getInstance().getGlobalContainerStack().getId(): if machine_id != machine_manager.activeMachine.getId():
# Not the current machine # Not the current machine
return return
# Unlink from old extruders # Unlink from old extruders
for extruder in self._active_machine_extruders: for extruder in self._active_machine_extruders:
extruder.containersChanged.disconnect(self._onExtruderStackContainersChanged) extruder.containersChanged.disconnect(self._onExtruderStackContainersChanged)
extruder.enabledChanged.disconnect(self._updateExtruders)
# Link to new extruders # Link to new extruders
self._active_machine_extruders = [] self._active_machine_extruders = []
@ -126,6 +128,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
if extruder is None: #This extruder wasn't loaded yet. This happens asynchronously while this model is constructed from QML. if extruder is None: #This extruder wasn't loaded yet. This happens asynchronously while this model is constructed from QML.
continue continue
extruder.containersChanged.connect(self._onExtruderStackContainersChanged) extruder.containersChanged.connect(self._onExtruderStackContainersChanged)
extruder.enabledChanged.connect(self._updateExtruders)
self._active_machine_extruders.append(extruder) self._active_machine_extruders.append(extruder)
self._updateExtruders() # Since the new extruders may have different properties, update our own model. self._updateExtruders() # Since the new extruders may have different properties, update our own model.

View File

@ -42,7 +42,12 @@ class GlobalStack(CuraContainerStack):
# Per thread we have our own resolving_settings, or strange things sometimes occur. # Per thread we have our own resolving_settings, or strange things sometimes occur.
self._resolving_settings = defaultdict(set) #type: Dict[str, Set[str]] # keys are thread names self._resolving_settings = defaultdict(set) #type: Dict[str, Set[str]] # keys are thread names
# Since the metadatachanged is defined in container stack, we can't use it here as a notifier for pyqt
# properties. So we need to tie them together like this.
self.metaDataChanged.connect(self.configuredConnectionTypesChanged)
extrudersChanged = pyqtSignal() extrudersChanged = pyqtSignal()
configuredConnectionTypesChanged = pyqtSignal()
## Get the list of extruders of this stack. ## Get the list of extruders of this stack.
# #
@ -63,6 +68,37 @@ class GlobalStack(CuraContainerStack):
def getLoadingPriority(cls) -> int: def getLoadingPriority(cls) -> int:
return 2 return 2
## The configured connection types can be used to find out if the global
# stack is configured to be connected with a printer, without having to
# know all the details as to how this is exactly done (and without
# actually setting the stack to be active).
#
# This data can then in turn also be used when the global stack is active;
# If we can't get a network connection, but it is configured to have one,
# we can display a different icon to indicate the difference.
@pyqtProperty("QVariantList", notify=configuredConnectionTypesChanged)
def configuredConnectionTypes(self) -> List[int]:
# Requesting it from the metadata actually gets them as strings (as that's what you get from serializing).
# But we do want them returned as a list of ints (so the rest of the code can directly compare)
connection_types = self.getMetaDataEntry("connection_type", "").split(",")
return [int(connection_type) for connection_type in connection_types if connection_type != ""]
## \sa configuredConnectionTypes
def addConfiguredConnectionType(self, connection_type: int) -> None:
configured_connection_types = self.configuredConnectionTypes
if connection_type not in configured_connection_types:
# Store the values as a string.
configured_connection_types.append(connection_type)
self.setMetaDataEntry("connection_type", ",".join([str(c_type) for c_type in configured_connection_types]))
## \sa configuredConnectionTypes
def removeConfiguredConnectionType(self, connection_type: int) -> None:
configured_connection_types = self.configuredConnectionTypes
if connection_type in self.configured_connection_types:
# Store the values as a string.
configured_connection_types.remove(connection_type)
self.setMetaDataEntry("connection_type", ",".join([str(c_type) for c_type in configured_connection_types]))
@classmethod @classmethod
def getConfigurationTypeFromSerialized(cls, serialized: str) -> Optional[str]: def getConfigurationTypeFromSerialized(cls, serialized: str) -> Optional[str]:
configuration_type = super().getConfigurationTypeFromSerialized(serialized) configuration_type = super().getConfigurationTypeFromSerialized(serialized)

View File

@ -115,10 +115,6 @@ class MachineManager(QObject):
self._application.callLater(self.setInitialActiveMachine) self._application.callLater(self.setInitialActiveMachine)
self._material_incompatible_message = Message(catalog.i18nc("@info:status",
"The selected material is incompatible with the selected machine or configuration."),
title = catalog.i18nc("@info:title", "Incompatible Material")) # type: Message
containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) # type: List[InstanceContainer] containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) # type: List[InstanceContainer]
if containers: if containers:
containers[0].nameChanged.connect(self._onMaterialNameChanged) containers[0].nameChanged.connect(self._onMaterialNameChanged)
@ -505,7 +501,7 @@ class MachineManager(QObject):
@pyqtProperty(str, notify = globalContainerChanged) @pyqtProperty(str, notify = globalContainerChanged)
def activeMachineName(self) -> str: def activeMachineName(self) -> str:
if self._global_container_stack: if self._global_container_stack:
return self._global_container_stack.getName() return self._global_container_stack.getMetaDataEntry("group_name", self._global_container_stack.getName())
return "" return ""
@pyqtProperty(str, notify = globalContainerChanged) @pyqtProperty(str, notify = globalContainerChanged)
@ -521,10 +517,20 @@ class MachineManager(QObject):
@pyqtProperty(bool, notify = printerConnectedStatusChanged) @pyqtProperty(bool, notify = printerConnectedStatusChanged)
def activeMachineHasRemoteConnection(self) -> bool: def activeMachineHasRemoteConnection(self) -> bool:
if self._global_container_stack: if self._global_container_stack:
connection_type = int(self._global_container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) has_remote_connection = False
return connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value]
for connection_type in self._global_container_stack.configuredConnectionTypes:
has_remote_connection |= connection_type in [ConnectionType.NetworkConnection.value,
ConnectionType.CloudConnection.value]
return has_remote_connection
return False return False
@pyqtProperty("QVariantList", notify=globalContainerChanged)
def activeMachineConfiguredConnectionTypes(self):
if self._global_container_stack:
return self._global_container_stack.configuredConnectionTypes
return []
@pyqtProperty(bool, notify = printerConnectedStatusChanged) @pyqtProperty(bool, notify = printerConnectedStatusChanged)
def activeMachineIsGroup(self) -> bool: def activeMachineIsGroup(self) -> bool:
return bool(self._printer_output_devices) and len(self._printer_output_devices[0].printers) > 1 return bool(self._printer_output_devices) and len(self._printer_output_devices[0].printers) > 1
@ -547,7 +553,7 @@ class MachineManager(QObject):
@pyqtProperty(str, notify = printerConnectedStatusChanged) @pyqtProperty(str, notify = printerConnectedStatusChanged)
def activeMachineNetworkGroupName(self) -> str: def activeMachineNetworkGroupName(self) -> str:
if self._global_container_stack: if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("connect_group_name", "") return self._global_container_stack.getMetaDataEntry("group_name", "")
return "" return ""
@pyqtProperty(QObject, notify = globalContainerChanged) @pyqtProperty(QObject, notify = globalContainerChanged)
@ -1339,7 +1345,7 @@ class MachineManager(QObject):
if not new_machine: if not new_machine:
return return
new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey()) new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey())
new_machine.setMetaDataEntry("connect_group_name", self.activeMachineNetworkGroupName) new_machine.setMetaDataEntry("group_name", self.activeMachineNetworkGroupName)
new_machine.setMetaDataEntry("hidden", False) new_machine.setMetaDataEntry("hidden", False)
new_machine.setMetaDataEntry("connection_type", self._global_container_stack.getMetaDataEntry("connection_type")) new_machine.setMetaDataEntry("connection_type", self._global_container_stack.getMetaDataEntry("connection_type"))
else: else:
@ -1358,25 +1364,56 @@ class MachineManager(QObject):
self.blurSettings.emit() self.blurSettings.emit()
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
self.switchPrinterType(configuration.printerType) self.switchPrinterType(configuration.printerType)
used_extruder_stack_list = ExtruderManager.getInstance().getUsedExtruderStacks()
disabled_used_extruder_position_set = set()
extruders_to_disable = set()
# If an extruder that's currently used to print a model gets disabled due to the syncing, we need to show
# a message explaining why.
need_to_show_message = False
for extruder_configuration in configuration.extruderConfigurations:
extruder_has_hotend = extruder_configuration.hotendID != ""
extruder_has_material = extruder_configuration.material.guid != ""
# If the machine doesn't have a hotend or material, disable this extruder
if not extruder_has_hotend or not extruder_has_material:
extruders_to_disable.add(extruder_configuration.position)
# If there's no material and/or nozzle on the printer, enable the first extruder and disable the rest.
if len(extruders_to_disable) == len(self._global_container_stack.extruders):
extruders_to_disable.remove(min(extruders_to_disable))
for extruder_configuration in configuration.extruderConfigurations: for extruder_configuration in configuration.extruderConfigurations:
position = str(extruder_configuration.position) position = str(extruder_configuration.position)
variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), extruder_configuration.hotendID)
material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack,
position,
extruder_configuration.hotendID,
configuration.buildplateConfiguration,
extruder_configuration.material.guid)
if variant_container_node: # If the machine doesn't have a hotend or material, disable this extruder
self._setVariantNode(position, variant_container_node) if int(position) in extruders_to_disable:
else: self._global_container_stack.extruders[position].setEnabled(False)
self._global_container_stack.extruders[position].variant = empty_variant_container
need_to_show_message = True
disabled_used_extruder_position_set.add(int(position))
if material_container_node:
self._setMaterial(position, material_container_node)
else: else:
self._global_container_stack.extruders[position].material = empty_material_container variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(),
self.updateMaterialWithVariant(position) extruder_configuration.hotendID)
material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack,
position,
extruder_configuration.hotendID,
configuration.buildplateConfiguration,
extruder_configuration.material.guid)
if variant_container_node:
self._setVariantNode(position, variant_container_node)
else:
self._global_container_stack.extruders[position].variant = empty_variant_container
if material_container_node:
self._setMaterial(position, material_container_node)
else:
self._global_container_stack.extruders[position].material = empty_material_container
self._global_container_stack.extruders[position].setEnabled(True)
self.updateMaterialWithVariant(position)
if configuration.buildplateConfiguration is not None: if configuration.buildplateConfiguration is not None:
global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration) global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration)
@ -1388,6 +1425,21 @@ class MachineManager(QObject):
self._global_container_stack.variant = empty_variant_container self._global_container_stack.variant = empty_variant_container
self._updateQualityWithMaterial() self._updateQualityWithMaterial()
if need_to_show_message:
msg_str = "{extruders} is disabled because there is no material loaded. Please load a material or use custom configurations."
# Show human-readable extruder names such as "Extruder Left", "Extruder Front" instead of "Extruder 1, 2, 3".
extruder_names = []
for position in sorted(disabled_used_extruder_position_set):
extruder_stack = self._global_container_stack.extruders[str(position)]
extruder_name = extruder_stack.definition.getName()
extruder_names.append(extruder_name)
extruders_str = ", ".join(extruder_names)
msg_str = msg_str.format(extruders = extruders_str)
message = Message(catalog.i18nc("@info:status", msg_str),
title = catalog.i18nc("@info:title", "Extruder(s) Disabled"))
message.show()
# See if we need to show the Discard or Keep changes screen # See if we need to show the Discard or Keep changes screen
if self.hasUserSettings and self._application.getPreferences().getValue("cura/active_mode") == 1: if self.hasUserSettings and self._application.getPreferences().getValue("cura/active_mode") == 1:
self._application.discardOrKeepProfileChanges() self._application.discardOrKeepProfileChanges()
@ -1404,12 +1456,12 @@ class MachineManager(QObject):
# then all the container stacks are updated, both the current and the hidden ones. # then all the container stacks are updated, both the current and the hidden ones.
def checkCorrectGroupName(self, device_id: str, group_name: str) -> None: def checkCorrectGroupName(self, device_id: str, group_name: str) -> None:
if self._global_container_stack and device_id == self.activeMachineNetworkKey(): if self._global_container_stack and device_id == self.activeMachineNetworkKey():
# Check if the connect_group_name is correct. If not, update all the containers connected to the same printer # Check if the group_name is correct. If not, update all the containers connected to the same printer
if self.activeMachineNetworkGroupName != group_name: if self.activeMachineNetworkGroupName != group_name:
metadata_filter = {"um_network_key": self.activeMachineNetworkKey()} metadata_filter = {"um_network_key": self.activeMachineNetworkKey()}
containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
for container in containers: for container in containers:
container.setMetaDataEntry("connect_group_name", group_name) container.setMetaDataEntry("group_name", group_name)
## This method checks if there is an instance connected to the given network_key ## This method checks if there is an instance connected to the given network_key
def existNetworkInstances(self, network_key: str) -> bool: def existNetworkInstances(self, network_key: str) -> bool:

View File

@ -9,6 +9,7 @@ import os
import sys import sys
from UM.Platform import Platform from UM.Platform import Platform
from cura.ApplicationMetadata import CuraAppName
parser = argparse.ArgumentParser(prog = "cura", parser = argparse.ArgumentParser(prog = "cura",
add_help = False) add_help = False)
@ -22,11 +23,11 @@ known_args = vars(parser.parse_known_args()[0])
if not known_args["debug"]: if not known_args["debug"]:
def get_cura_dir_path(): def get_cura_dir_path():
if Platform.isWindows(): if Platform.isWindows():
return os.path.expanduser("~/AppData/Roaming/cura") return os.path.expanduser("~/AppData/Roaming/" + CuraAppName)
elif Platform.isLinux(): elif Platform.isLinux():
return os.path.expanduser("~/.local/share/cura") return os.path.expanduser("~/.local/share/" + CuraAppName)
elif Platform.isOSX(): elif Platform.isOSX():
return os.path.expanduser("~/Library/Logs/cura") return os.path.expanduser("~/Library/Logs/" + CuraAppName)
if hasattr(sys, "frozen"): if hasattr(sys, "frozen"):
dirpath = get_cura_dir_path() dirpath = get_cura_dir_path()

View File

@ -500,7 +500,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
is_printer_group = False is_printer_group = False
if machine_conflict: if machine_conflict:
group_name = existing_global_stack.getMetaDataEntry("connect_group_name") group_name = existing_global_stack.getMetaDataEntry("group_name")
if group_name is not None: if group_name is not None:
is_printer_group = True is_printer_group = True
machine_name = group_name machine_name = group_name

View File

@ -1,9 +1,9 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os import os
from datetime import datetime from datetime import datetime
from typing import Optional, List, Dict, Any from typing import Any, cast, Dict, List, Optional
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
@ -68,7 +68,7 @@ class DrivePluginExtension(QObject, Extension):
def showDriveWindow(self) -> None: def showDriveWindow(self) -> None:
if not self._drive_window: if not self._drive_window:
plugin_dir_path = CuraApplication.getInstance().getPluginRegistry().getPluginPath("CuraDrive") plugin_dir_path = cast(str, CuraApplication.getInstance().getPluginRegistry().getPluginPath(self.getPluginId())) # We know this plug-in exists because that's us, so this always returns str.
path = os.path.join(plugin_dir_path, "src", "qml", "main.qml") path = os.path.join(plugin_dir_path, "src", "qml", "main.qml")
self._drive_window = CuraApplication.getInstance().createQmlComponent(path, {"CuraDrive": self}) self._drive_window = CuraApplication.getInstance().createQmlComponent(path, {"CuraDrive": self})
self.refreshBackups() self.refreshBackups()

View File

@ -28,7 +28,7 @@ class FirmwareUpdateCheckerMessage(Message):
"[no_icon]", "[no_icon]",
"[no_description]", "[no_description]",
button_style = Message.ActionButtonStyle.LINK, button_style = Message.ActionButtonStyle.LINK,
button_align = Message.ActionButtonStyle.BUTTON_ALIGN_LEFT) button_align = Message.ActionButtonAlignment.ALIGN_LEFT)
def getMachineId(self) -> int: def getMachineId(self) -> int:
return self._machine_id return self._machine_id

View File

@ -57,7 +57,7 @@ class FirmwareUpdaterMachineAction(MachineAction):
outputDeviceCanUpdateFirmwareChanged = pyqtSignal() outputDeviceCanUpdateFirmwareChanged = pyqtSignal()
@pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged) @pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged)
def firmwareUpdater(self) -> Optional["FirmwareUpdater"]: def firmwareUpdater(self) -> Optional["FirmwareUpdater"]:
if self._active_output_device and self._active_output_device.activePrinter and self._active_output_device.activePrinter.getController().can_update_firmware: if self._active_output_device and self._active_output_device.activePrinter and self._active_output_device.activePrinter.getController() is not None and self._active_output_device.activePrinter.getController().can_update_firmware:
self._active_firmware_updater = self._active_output_device.getFirmwareUpdater() self._active_firmware_updater = self._active_output_device.getFirmwareUpdater()
return self._active_firmware_updater return self._active_firmware_updater

View File

@ -107,6 +107,8 @@ class FlavorParser:
self._layer_data_builder.setLayerHeight(self._layer_number, path[0][2]) self._layer_data_builder.setLayerHeight(self._layer_number, path[0][2])
self._layer_data_builder.setLayerThickness(self._layer_number, layer_thickness) self._layer_data_builder.setLayerThickness(self._layer_number, layer_thickness)
this_layer = self._layer_data_builder.getLayer(self._layer_number) this_layer = self._layer_data_builder.getLayer(self._layer_number)
if not this_layer:
return False
except ValueError: except ValueError:
return False return False
count = len(path) count = len(path)

View File

@ -2,20 +2,43 @@
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
import QtQuick.Controls 1.4 import QtQuick.Controls 2.0
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
// We show a nice overlay on the 3D viewer when the current output device has no monitor view // We show a nice overlay on the 3D viewer when the current output device has no monitor view
Rectangle Rectangle
{ {
id: viewportOverlay id: viewportOverlay
property bool isConnected: Cura.MachineManager.activeMachineHasActiveNetworkConnection || Cura.MachineManager.activeMachineHasActiveCloudConnection
property bool isNetworkConfigurable: ["Ultimaker 3", "Ultimaker 3 Extended", "Ultimaker S5"].indexOf(Cura.MachineManager.activeMachineDefinitionName) > -1
property bool isNetworkConfigured:
{
// Readability:
var connectedTypes = [2, 3];
var types = Cura.MachineManager.activeMachineConfiguredConnectionTypes
// Check if configured connection types includes either 2 or 3 (LAN or cloud)
for (var i = 0; i < types.length; i++)
{
if (connectedTypes.indexOf(types[i]) >= 0)
{
return true
}
}
return false
}
color: UM.Theme.getColor("viewport_overlay") color: UM.Theme.getColor("viewport_overlay")
anchors.fill: parent anchors.fill: parent
UM.I18nCatalog
{
id: catalog
name: "cura"
}
// This mouse area is to prevent mouse clicks to be passed onto the scene. // This mouse area is to prevent mouse clicks to be passed onto the scene.
MouseArea MouseArea
{ {
@ -29,6 +52,8 @@ Rectangle
{ {
anchors.fill: parent anchors.fill: parent
} }
// CASE 1: CAN MONITOR & CONNECTED
Loader Loader
{ {
id: monitorViewComponent id: monitorViewComponent
@ -42,4 +67,118 @@ Rectangle
sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem : null sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem : null
} }
// CASE 2 & 3: Empty states
Column
{
anchors
{
top: parent.top
topMargin: UM.Theme.getSize("monitor_empty_state_offset").height
horizontalCenter: parent.horizontalCenter
}
width: UM.Theme.getSize("monitor_empty_state_size").width
spacing: UM.Theme.getSize("default_margin").height
visible: monitorViewComponent.sourceComponent == null
// CASE 2: CAN MONITOR & NOT CONNECTED
Label
{
anchors
{
horizontalCenter: parent.horizontalCenter
}
visible: isNetworkConfigured && !isConnected
text: catalog.i18nc("@info", "Please make sure your printer has a connection:\n- Check if the printer is turned on.\n- Check if the printer is connected to the network.")
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("monitor_text_primary")
wrapMode: Text.WordWrap
lineHeight: UM.Theme.getSize("monitor_text_line_large").height
lineHeightMode: Text.FixedHeight
width: contentWidth
}
// CASE 3: CAN NOT MONITOR
Label
{
id: noNetworkLabel
anchors
{
horizontalCenter: parent.horizontalCenter
}
visible: !isNetworkConfigured
text: catalog.i18nc("@info", "Please select a network connected printer to monitor.")
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("monitor_text_primary")
wrapMode: Text.WordWrap
width: contentWidth
lineHeight: UM.Theme.getSize("monitor_text_line_large").height
lineHeightMode: Text.FixedHeight
}
Label
{
id: noNetworkUltimakerLabel
anchors
{
horizontalCenter: parent.horizontalCenter
}
visible: !isNetworkConfigured && isNetworkConfigurable
text: catalog.i18nc("@info", "Please connect your Ultimaker printer to your local network.")
font: UM.Theme.getFont("medium")
color: UM.Theme.getColor("monitor_text_primary")
wrapMode: Text.WordWrap
width: contentWidth
lineHeight: UM.Theme.getSize("monitor_text_line_large").height
lineHeightMode: Text.FixedHeight
}
Item
{
anchors
{
left: noNetworkUltimakerLabel.left
}
visible: !isNetworkConfigured && isNetworkConfigurable
height: UM.Theme.getSize("monitor_text_line").height
width: childrenRect.width
UM.RecolorImage
{
id: externalLinkIcon
anchors.verticalCenter: parent.verticalCenter
color: UM.Theme.getColor("monitor_text_link")
source: UM.Theme.getIcon("external_link")
width: UM.Theme.getSize("monitor_external_link_icon").width
height: UM.Theme.getSize("monitor_external_link_icon").height
}
Label
{
id: manageQueueText
anchors
{
left: externalLinkIcon.right
leftMargin: UM.Theme.getSize("narrow_margin").width
verticalCenter: externalLinkIcon.verticalCenter
}
color: UM.Theme.getColor("monitor_text_link")
font: UM.Theme.getFont("medium") // 14pt, regular
linkColor: UM.Theme.getColor("monitor_text_link")
text: catalog.i18nc("@label link to technical assistance", "View user manuals online")
renderType: Text.NativeRendering
}
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onClicked: Qt.openUrlExternally("https://ultimaker.com/en/resources/manuals/ultimaker-3d-printers")
onEntered:
{
manageQueueText.font.underline = true
}
onExited:
{
manageQueueText.font.underline = false
}
}
}
}
} }

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. # The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
from typing import Optional, Tuple from typing import Optional, Tuple
@ -45,6 +45,22 @@ class FilamentChange(Script):
"unit": "mm", "unit": "mm",
"type": "float", "type": "float",
"default_value": 300.0 "default_value": 300.0
},
"x_position":
{
"label": "X Position",
"description": "Extruder X position. The print head will move here for filament change.",
"unit": "mm",
"type": "float",
"default_value": 0
},
"y_position":
{
"label": "Y Position",
"description": "Extruder Y position. The print head will move here for filament change.",
"unit": "mm",
"type": "float",
"default_value": 0
} }
} }
}""" }"""
@ -55,6 +71,8 @@ class FilamentChange(Script):
layer_nums = self.getSettingValueByKey("layer_number") layer_nums = self.getSettingValueByKey("layer_number")
initial_retract = self.getSettingValueByKey("initial_retract") initial_retract = self.getSettingValueByKey("initial_retract")
later_retract = self.getSettingValueByKey("later_retract") later_retract = self.getSettingValueByKey("later_retract")
x_pos = self.getSettingValueByKey("x_position")
y_pos = self.getSettingValueByKey("y_position")
color_change = "M600" color_change = "M600"
@ -64,6 +82,12 @@ class FilamentChange(Script):
if later_retract is not None and later_retract > 0.: if later_retract is not None and later_retract > 0.:
color_change = color_change + (" L%.2f" % later_retract) color_change = color_change + (" L%.2f" % later_retract)
if x_pos is not None:
color_change = color_change + (" X%.2f" % x_pos)
if y_pos is not None:
color_change = color_change + (" Y%.2f" % y_pos)
color_change = color_change + " ; Generated by FilamentChange plugin" color_change = color_change + " ; Generated by FilamentChange plugin"
layer_targets = layer_nums.split(",") layer_targets = layer_nums.split(",")

View File

@ -0,0 +1,24 @@
//Copyright (c) 2019 Ultimaker B.V.
//Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM
import Cura 1.0 as Cura
Item
{
id: prepareMain
Cura.ActionPanelWidget
{
id: actionPanelWidget
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
}
}

View File

@ -1,13 +1,11 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os.path import os.path
from UM.Application import Application from UM.Application import Application
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Resources import Resources
from cura.Stages.CuraStage import CuraStage from cura.Stages.CuraStage import CuraStage
## Stage for preparing model (slicing). ## Stage for preparing model (slicing).
class PrepareStage(CuraStage): class PrepareStage(CuraStage):
def __init__(self, parent = None): def __init__(self, parent = None):
@ -16,4 +14,6 @@ class PrepareStage(CuraStage):
def _engineCreated(self): def _engineCreated(self):
menu_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("PrepareStage"), "PrepareMenu.qml") menu_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("PrepareStage"), "PrepareMenu.qml")
main_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("PrepareStage"), "PrepareMain.qml")
self.addDisplayComponent("menu", menu_component_path) self.addDisplayComponent("menu", menu_component_path)
self.addDisplayComponent("main", main_component_path)

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.4 import QtQuick 2.4
@ -9,10 +9,22 @@ import QtQuick.Controls.Styles 1.1
import UM 1.0 as UM import UM 1.0 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Item
Loader
{ {
id: previewMain Loader
{
id: previewMain
source: UM.Controller.activeView != null && UM.Controller.activeView.mainComponent != null ? UM.Controller.activeView.mainComponent : "" source: UM.Controller.activeView != null && UM.Controller.activeView.mainComponent != null ? UM.Controller.activeView.mainComponent : ""
}
Cura.ActionPanelWidget
{
id: actionPanelWidget
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
hasPreviewButton: false
}
} }

View File

@ -49,6 +49,7 @@ Rectangle
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium_bold") font: UM.Theme.getFont("medium_bold")
color: UM.Theme.getColor("text")
} }
UM.RecolorImage UM.RecolorImage
{ {

View File

@ -37,7 +37,7 @@ class Toolbox(QObject, Extension):
self._application = application # type: CuraApplication self._application = application # type: CuraApplication
self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int] self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int]
self._cloud_api_version = UltimakerCloudAuthentication.CuraCloudAPIVersion # type: int self._cloud_api_version = UltimakerCloudAuthentication.CuraCloudAPIVersion # type: str
self._cloud_api_root = UltimakerCloudAuthentication.CuraCloudAPIRoot # type: str self._cloud_api_root = UltimakerCloudAuthentication.CuraCloudAPIRoot # type: str
self._api_url = None # type: Optional[str] self._api_url = None # type: Optional[str]

View File

@ -95,10 +95,14 @@ class UFPWriter(MeshWriter):
added_materials = [] added_materials = []
for extruder_stack in global_stack.extruders.values(): for extruder_stack in global_stack.extruders.values():
material = extruder_stack.material material = extruder_stack.material
material_file_name = material.getMetaData()["base_file"] + ".xml.fdm_material" try:
material_file_name = material.getMetaData()["base_file"] + ".xml.fdm_material"
except KeyError:
Logger.log("w", "Unable to get base_file for the material %s", material.getId())
continue
material_file_name = "/Materials/" + material_file_name material_file_name = "/Materials/" + material_file_name
#Same material cannot be added # The same material should not be added again.
if material_file_name in added_materials: if material_file_name in added_materials:
continue continue

View File

@ -9,12 +9,14 @@ import Cura 1.0 as Cura
Rectangle { Rectangle {
id: base id: base
property var enabled: true
property var iconSource: null; property var iconSource: null;
color: "#0a0850" // TODO: Theme! color: UM.Theme.getColor("monitor_icon_primary")
height: width; height: width;
radius: Math.round(0.5 * width); radius: Math.round(0.5 * width);
width: 24 * screenScaleFactor; width: 24 * screenScaleFactor;
property var enabled: true
UM.RecolorImage { UM.RecolorImage {
id: icon; id: icon;
@ -22,7 +24,7 @@ Rectangle {
horizontalCenter: parent.horizontalCenter; horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter; verticalCenter: parent.verticalCenter;
} }
color: UM.Theme.getColor("primary_text"); color: UM.Theme.getColor("monitor_icon_accent");
height: width; height: width;
source: iconSource; source: iconSource;
width: Math.round(parent.width / 2); width: Math.round(parent.width / 2);

View File

@ -6,10 +6,11 @@ import QtQuick.Controls 2.0
import UM 1.3 as UM import UM 1.3 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
// TODO: Theme & documentation! /**
// The expandable component has 3 major sub components: * The expandable component has 3 major sub components:
// * The headerItem Always visible and should hold some info about what happens if the component is expanded * - The headerItem Always visible and should hold some info about what happens if the component is expanded
// * The popupItem The content that needs to be shown if the component is expanded. * - The popupItem The content that needs to be shown if the component is expanded.
*/
Item Item
{ {
id: base id: base
@ -17,10 +18,10 @@ Item
property bool expanded: false property bool expanded: false
property bool enabled: true property bool enabled: true
property var borderWidth: 1 property var borderWidth: 1
property color borderColor: "#CCCCCC" property color borderColor: UM.Theme.getColor("monitor_card_border")
property color headerBackgroundColor: "white" property color headerBackgroundColor: UM.Theme.getColor("monitor_icon_accent")
property color headerHoverColor: "#e8f2fc" property color headerHoverColor: UM.Theme.getColor("monitor_card_hover")
property color drawerBackgroundColor: "white" property color drawerBackgroundColor: UM.Theme.getColor("monitor_icon_accent")
property alias headerItem: header.children property alias headerItem: header.children
property alias drawerItem: drawer.children property alias drawerItem: drawer.children
@ -38,6 +39,7 @@ Item
color: base.enabled && headerMouseArea.containsMouse ? headerHoverColor : headerBackgroundColor color: base.enabled && headerMouseArea.containsMouse ? headerHoverColor : headerBackgroundColor
height: childrenRect.height height: childrenRect.height
width: parent.width width: parent.width
radius: 2 * screenScaleFactor // TODO: Theme!
Behavior on color Behavior on color
{ {
ColorAnimation ColorAnimation
@ -76,6 +78,7 @@ Item
color: headerBackgroundColor color: headerBackgroundColor
height: base.expanded ? childrenRect.height : 0 height: base.expanded ? childrenRect.height : 0
width: parent.width width: parent.width
radius: 2 * screenScaleFactor // TODO: Theme!
Behavior on height Behavior on height
{ {
NumberAnimation NumberAnimation

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

@ -41,7 +41,7 @@ Item
anchors.centerIn: parent anchors.centerIn: parent
height: parent.height height: parent.height
width: height width: height
color: buildplateIcon.visible > 0 ? "transparent" : "#eeeeee" // TODO: Theme! color: buildplateIcon.visible > 0 ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
radius: Math.floor(height / 2) radius: Math.floor(height / 2)
} }
@ -49,7 +49,7 @@ Item
{ {
id: buildplateIcon id: buildplateIcon
anchors.centerIn: parent anchors.centerIn: parent
color: "#0a0850" // TODO: Theme! (Standard purple) color: UM.Theme.getColor("monitor_icon_primary")
height: parent.height height: parent.height
source: "../svg/icons/buildplate.svg" source: "../svg/icons/buildplate.svg"
width: height width: height
@ -60,7 +60,7 @@ Item
Label Label
{ {
id: buildplateLabel id: buildplateLabel
color: "#191919" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("default") // 12pt, regular font: UM.Theme.getFont("default") // 12pt, regular
text: buildplate ? buildplate : "" text: buildplate ? buildplate : ""

View File

@ -49,12 +49,12 @@ Item
GradientStop GradientStop
{ {
position: 0.0 position: 0.0
color: "#fff6f6f6" // TODO: Theme! color: UM.Theme.getColor("monitor_stage_background")
} }
GradientStop GradientStop
{ {
position: 1.0 position: 1.0
color: "#66f6f6f6" // TODO: Theme! color: UM.Theme.getColor("monitor_stage_background_fade")
} }
} }
} }
@ -82,9 +82,9 @@ Item
onClicked: navigateTo(currentIndex - 1) onClicked: navigateTo(currentIndex - 1)
background: Rectangle background: Rectangle
{ {
color: leftButton.hovered ? "#e8f2fc" : "#ffffff" // TODO: Theme! color: leftButton.hovered ? UM.Theme.getColor("monitor_card_hover") : UM.Theme.getColor("monitor_card_background")
border.width: 1 * screenScaleFactor // TODO: Theme! border.width: 1 * screenScaleFactor // TODO: Theme!
border.color: "#cccccc" // TODO: Theme! border.color: UM.Theme.getColor("monitor_card_border")
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
} }
contentItem: Item contentItem: Item
@ -97,7 +97,7 @@ Item
height: width // TODO: Theme! height: width // TODO: Theme!
sourceSize.width: width // TODO: Theme! sourceSize.width: width // TODO: Theme!
sourceSize.height: width // TODO: Theme! sourceSize.height: width // TODO: Theme!
color: "#152950" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
source: UM.Theme.getIcon("arrow_left") source: UM.Theme.getIcon("arrow_left")
} }
} }
@ -161,9 +161,9 @@ Item
hoverEnabled: true hoverEnabled: true
background: Rectangle background: Rectangle
{ {
color: rightButton.hovered ? "#e8f2fc" : "#ffffff" // TODO: Theme! color: rightButton.hovered ? UM.Theme.getColor("monitor_card_hover") : UM.Theme.getColor("monitor_card_background")
border.width: 1 * screenScaleFactor // TODO: Theme! border.width: 1 * screenScaleFactor // TODO: Theme!
border.color: "#cccccc" // TODO: Theme! border.color: UM.Theme.getColor("monitor_card_border")
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
} }
contentItem: Item contentItem: Item
@ -176,7 +176,7 @@ Item
height: width // TODO: Theme! height: width // TODO: Theme!
sourceSize.width: width // TODO: Theme! sourceSize.width: width // TODO: Theme!
sourceSize.height: width // TODO: Theme! sourceSize.height: width // TODO: Theme!
color: "#152950" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
source: UM.Theme.getIcon("arrow_right") source: UM.Theme.getIcon("arrow_right")
} }
} }
@ -204,12 +204,12 @@ Item
GradientStop GradientStop
{ {
position: 0.0 position: 0.0
color: "#66f6f6f6" // TODO: Theme! color: UM.Theme.getColor("monitor_stage_background_fade")
} }
GradientStop GradientStop
{ {
position: 1.0 position: 1.0
color: "#fff6f6f6" // TODO: Theme! color: UM.Theme.getColor("monitor_stage_background")
} }
} }
} }
@ -238,7 +238,7 @@ Item
{ {
background: Rectangle background: Rectangle
{ {
color: model.index == currentIndex ? "#777777" : "#d8d8d8" // TODO: Theme! color: model.index == currentIndex ? UM.Theme.getColor("monitor_carousel_dot_current") : UM.Theme.getColor("monitor_carousel_dot")
radius: Math.floor(width / 2) radius: Math.floor(width / 2)
width: 12 * screenScaleFactor // TODO: Theme! width: 12 * screenScaleFactor // TODO: Theme!
height: width // TODO: Theme! height: width // TODO: Theme!

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: UM.Theme.getColor("monitor_context_menu")
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" || printJob.state == "error") && !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", "error", "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_text_primary")
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

@ -36,7 +36,7 @@ Item
MonitorIconExtruder MonitorIconExtruder
{ {
id: extruderIcon id: extruderIcon
color: "#eeeeee" // TODO: Theme! color: UM.Theme.getColor("monitor_skeleton_loading")
position: 0 position: 0
} }
@ -48,7 +48,7 @@ Item
left: extruderIcon.right left: extruderIcon.right
leftMargin: 12 * screenScaleFactor // TODO: Theme! leftMargin: 12 * screenScaleFactor // TODO: Theme!
} }
color: materialLabel.visible > 0 ? "transparent" : "#eeeeee" // TODO: Theme! color: materialLabel.visible > 0 ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
height: 18 * screenScaleFactor // TODO: Theme! height: 18 * screenScaleFactor // TODO: Theme!
width: Math.max(materialLabel.contentWidth, 60 * screenScaleFactor) // TODO: Theme! width: Math.max(materialLabel.contentWidth, 60 * screenScaleFactor) // TODO: Theme!
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
@ -57,7 +57,7 @@ Item
{ {
id: materialLabel id: materialLabel
color: "#191919" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("default") // 12pt, regular font: UM.Theme.getFont("default") // 12pt, regular
text: "" text: ""
@ -77,7 +77,7 @@ Item
left: materialLabelWrapper.left left: materialLabelWrapper.left
bottom: parent.bottom bottom: parent.bottom
} }
color: printCoreLabel.visible > 0 ? "transparent" : "#eeeeee" // TODO: Theme! color: printCoreLabel.visible > 0 ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
height: 18 * screenScaleFactor // TODO: Theme! height: 18 * screenScaleFactor // TODO: Theme!
width: Math.max(printCoreLabel.contentWidth, 36 * screenScaleFactor) // TODO: Theme! width: Math.max(printCoreLabel.contentWidth, 36 * screenScaleFactor) // TODO: Theme!
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
@ -86,7 +86,7 @@ Item
{ {
id: printCoreLabel id: printCoreLabel
color: "#191919" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("default_bold") // 12pt, bold font: UM.Theme.getFont("default_bold") // 12pt, bold
text: "" text: ""

View File

@ -39,6 +39,7 @@ Item
{ {
id: positionLabel id: positionLabel
font: UM.Theme.getFont("small") font: UM.Theme.getFont("small")
color: UM.Theme.getColor("monitor_text_primary")
height: Math.round(size / 2) height: Math.round(size / 2)
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: position + 1 text: position + 1

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 2.2
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import UM 1.3 as UM 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 * A Print Job Card is essentially just a filled-in Expandable Card item. All
@ -21,13 +22,17 @@ Item
// The print job which all other data is derived from // The print job which all other data is derived from
property var printJob: null 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 width: parent.width
height: childrenRect.height height: childrenRect.height
ExpandableCard ExpandableCard
{ {
enabled: printJob != null enabled: printJob != null
borderColor: printJob.configurationChanges.length !== 0 ? "#f5a623" : "#CCCCCC" // TODO: Theme! borderColor: printJob && printJob.configurationChanges.length !== 0 ? UM.Theme.getColor("warning") : UM.Theme.getColor("monitor_card_border")
headerItem: Row headerItem: Row
{ {
height: 48 * screenScaleFactor // TODO: Theme! height: 48 * screenScaleFactor // TODO: Theme!
@ -49,15 +54,16 @@ Item
width: 216 * screenScaleFactor // TODO: Theme! (Should match column size) width: 216 * screenScaleFactor // TODO: Theme! (Should match column size)
Rectangle Rectangle
{ {
color: "#eeeeee" color: UM.Theme.getColor("monitor_skeleton_loading")
width: Math.round(parent.width / 2) width: Math.round(parent.width / 2)
height: parent.height height: parent.height
visible: !printJob visible: !printJob
radius: 2 * screenScaleFactor // TODO: Theme!
} }
Label Label
{ {
text: printJob && printJob.name ? printJob.name : "" text: printJob && printJob.name ? printJob.name : ""
color: "#374355" color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
visible: printJob visible: printJob
@ -75,15 +81,16 @@ Item
width: 216 * screenScaleFactor // TODO: Theme! (Should match column size) width: 216 * screenScaleFactor // TODO: Theme! (Should match column size)
Rectangle Rectangle
{ {
color: "#eeeeee" color: UM.Theme.getColor("monitor_skeleton_loading")
width: Math.round(parent.width / 3) width: Math.round(parent.width / 3)
height: parent.height height: parent.height
visible: !printJob visible: !printJob
radius: 2 * screenScaleFactor // TODO: Theme!
} }
Label Label
{ {
text: printJob ? OutputDevice.formatDuration(printJob.timeTotal) : "" text: printJob ? OutputDevice.formatDuration(printJob.timeTotal) : ""
color: "#374355" color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
visible: printJob visible: printJob
@ -102,17 +109,18 @@ Item
Rectangle Rectangle
{ {
color: "#eeeeee" color: UM.Theme.getColor("monitor_skeleton_loading")
width: 72 * screenScaleFactor // TODO: Theme! width: 72 * screenScaleFactor // TODO: Theme!
height: parent.height height: parent.height
visible: !printJob visible: !printJob
radius: 2 * screenScaleFactor // TODO: Theme!
} }
Label Label
{ {
id: printerAssignmentLabel id: printerAssignmentLabel
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: "#374355" color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
text: { text: {
@ -176,7 +184,7 @@ Item
{ {
id: printerConfiguration id: printerConfiguration
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
buildplate: "Glass" buildplate: catalog.i18nc("@label", "Glass")
configurations: configurations:
[ [
base.printJob.configuration.extruderConfigurations[0], base.printJob.configuration.extruderConfigurations[0],
@ -186,7 +194,7 @@ Item
} }
Label { Label {
text: printJob && printJob.owner ? printJob.owner : "" text: printJob && printJob.owner ? printJob.owner : ""
color: "#374355" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
anchors.top: printerConfiguration.top anchors.top: printerConfiguration.top
@ -198,18 +206,52 @@ Item
} }
} }
PrintJobContextMenu MonitorContextMenuButton
{ {
id: contextButton id: contextMenuButton
anchors anchors
{ {
right: parent.right; right: parent.right
rightMargin: 8 * screenScaleFactor // TODO: Theme! rightMargin: 8 * screenScaleFactor // TODO: Theme!
top: parent.top top: parent.top
topMargin: 8 * screenScaleFactor // TODO: Theme! topMargin: 8 * screenScaleFactor // TODO: Theme!
} }
printJob: base.printJob
width: 32 * screenScaleFactor // TODO: Theme! width: 32 * screenScaleFactor // TODO: Theme!
height: 32 * screenScaleFactor // TODO: Theme! height: 32 * screenScaleFactor // TODO: Theme!
enabled: !cloudConnection
onClicked: enabled ? contextMenu.switchPopupState() : {}
visible:
{
if (!printJob) {
return false
}
var states = ["queued", "error", "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

@ -19,7 +19,7 @@ Item
Rectangle Rectangle
{ {
anchors.fill: parent anchors.fill: parent
color: printJob ? "transparent" : "#eeeeee" // TODO: Theme! color: printJob ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
radius: 8 // TODO: Theme! radius: 8 // TODO: Theme!
Image Image
{ {

View File

@ -34,15 +34,15 @@ Item
{ {
background: Rectangle background: Rectangle
{ {
color: "#f5f5f5" // TODO: Theme! color: UM.Theme.getColor("monitor_progress_bar_empty")
implicitHeight: visible ? 8 * screenScaleFactor : 0 // TODO: Theme! implicitHeight: visible ? 12 * screenScaleFactor : 0 // TODO: Theme!
implicitWidth: 180 * screenScaleFactor // TODO: Theme! implicitWidth: 180 * screenScaleFactor // TODO: Theme!
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
} }
progress: Rectangle progress: Rectangle
{ {
id: progressItem; id: progressItem;
color: printJob && printJob.isActive ? "#3282ff" : "#CCCCCC" // TODO: Theme! color: printJob && printJob.isActive ? UM.Theme.getColor("monitor_progress_bar_fill") : UM.Theme.getColor("monitor_progress_bar_deactive")
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
} }
} }
@ -56,7 +56,7 @@ Item
leftMargin: 18 * screenScaleFactor // TODO: Theme! leftMargin: 18 * screenScaleFactor // TODO: Theme!
} }
text: printJob ? Math.round(printJob.progress * 100) + "%" : "0%" text: printJob ? Math.round(printJob.progress * 100) + "%" : "0%"
color: printJob && printJob.isActive ? "#374355" : "#babac1" // TODO: Theme! color: printJob && printJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
width: contentWidth width: contentWidth
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
@ -72,7 +72,7 @@ Item
left: percentLabel.right left: percentLabel.right
leftMargin: 18 * screenScaleFactor // TODO: Theme! leftMargin: 18 * screenScaleFactor // TODO: Theme!
} }
color: "#374355" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
text: text:
{ {

View File

@ -5,15 +5,14 @@ import QtQuick 2.3
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import UM 1.3 as UM 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 * A Printer Card is has two main components: the printer portion and the print job portion, the latter being paired in
* job portion, the latter being paired in the UI when a print job is paired * the UI when a print job is paired a printer in-cluster.
* a printer in-cluster.
* *
* NOTE: For most labels, a fixed height with vertical alignment is used to make * NOTE: For most labels, a fixed height with vertical alignment is used to make layouts more deterministic (like the
* layouts more deterministic (like the fixed-size textboxes used in original * fixed-size textboxes used in original mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
* mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted
* with '// FIXED-LINE-HEIGHT:'. * with '// FIXED-LINE-HEIGHT:'.
*/ */
Item Item
@ -25,11 +24,14 @@ Item
property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here 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 // If the printer card's controls are enabled. This is used by the carousel to prevent opening the context menu or
// to prevent opening the context menu or camera while the printer card is not // camera while the printer card is not "in focus"
// "in focus"
property var enabled: true 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! width: 834 * screenScaleFactor // TODO: Theme!
height: childrenRect.height height: childrenRect.height
@ -37,10 +39,10 @@ Item
{ {
id: background id: background
anchors.fill: parent anchors.fill: parent
color: "#FFFFFF" // TODO: Theme! color: UM.Theme.getColor("monitor_card_background")
border border
{ {
color: "#CCCCCC" // TODO: Theme! color: UM.Theme.getColor("monitor_card_border")
width: borderSize // TODO: Remove once themed width: borderSize // TODO: Remove once themed
} }
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
@ -69,7 +71,7 @@ Item
id: printerImage id: printerImage
width: 108 * screenScaleFactor // TODO: Theme! width: 108 * screenScaleFactor // TODO: Theme!
height: 108 * screenScaleFactor // TODO: Theme! height: 108 * screenScaleFactor // TODO: Theme!
color: printer ? "transparent" : "#eeeeee" // TODO: Theme! color: printer ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
radius: 8 // TODO: Theme! radius: 8 // TODO: Theme!
Image Image
{ {
@ -93,8 +95,7 @@ Item
Rectangle Rectangle
{ {
id: printerNameLabel id: printerNameLabel
// color: "#414054" // TODO: Theme! color: printer ? "transparent" : UM.Theme.getColor("monitor_skeleton_loading")
color: printer ? "transparent" : "#eeeeee" // TODO: Theme!
height: 18 * screenScaleFactor // TODO: Theme! height: 18 * screenScaleFactor // TODO: Theme!
width: parent.width width: parent.width
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
@ -102,7 +103,7 @@ Item
Label Label
{ {
text: printer && printer.name ? printer.name : "" text: printer && printer.name ? printer.name : ""
color: "#414054" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("large") // 16pt, bold font: UM.Theme.getFont("large") // 16pt, bold
width: parent.width width: parent.width
@ -116,7 +117,7 @@ Item
Rectangle Rectangle
{ {
color: "#eeeeee" // TODO: Theme! color: UM.Theme.getColor("monitor_skeleton_loading")
height: 18 * screenScaleFactor // TODO: Theme! height: 18 * screenScaleFactor // TODO: Theme!
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
visible: !printer visible: !printer
@ -156,16 +157,11 @@ Item
} }
height: 72 * screenScaleFactor // TODO: Theme!te theRect's x property 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 }
} }
MonitorContextMenuButton
PrintJobContextMenu
{ {
id: contextButton id: contextMenuButton
anchors anchors
{ {
right: parent.right right: parent.right
@ -173,15 +169,49 @@ Item
top: parent.top top: parent.top
topMargin: 12 * screenScaleFactor // TODO: Theme! topMargin: 12 * screenScaleFactor // TODO: Theme!
} }
printJob: printer ? printer.activePrintJob : null
width: 36 * screenScaleFactor // TODO: Theme! width: 36 * screenScaleFactor // TODO: Theme!
height: 36 * screenScaleFactor // TODO: Theme! height: 36 * screenScaleFactor // TODO: Theme!
enabled: base.enabled enabled: !cloudConnection
visible: printer
onClicked: enabled ? contextMenu.switchPopupState() : {}
visible:
{
if (!printer || !printer.activePrintJob) {
return false
}
var states = ["queued", "error", "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 CameraButton
{ {
id: cameraButton; id: cameraButton
anchors anchors
{ {
right: parent.right right: parent.right
@ -190,9 +220,27 @@ Item
bottomMargin: 20 * screenScaleFactor // TODO: Theme! bottomMargin: 20 * screenScaleFactor // TODO: Theme!
} }
iconSource: "../svg/icons/camera.svg" iconSource: "../svg/icons/camera.svg"
enabled: base.enabled enabled: !cloudConnection
visible: printer 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
}
} }
@ -220,7 +268,7 @@ Item
} }
border border
{ {
color: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? "#f5a623" : "transparent" // TODO: Theme! color: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? UM.Theme.getColor("warning") : "transparent" // TODO: Theme!
width: borderSize // TODO: Remove once themed width: borderSize // TODO: Remove once themed
} }
color: "transparent" // TODO: Theme! color: "transparent" // TODO: Theme!
@ -246,7 +294,7 @@ Item
{ {
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
color: printer ? "#414054" : "#aaaaaa" // TODO: Theme! color: printer ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
font: UM.Theme.getFont("large_bold") // 16pt, bold font: UM.Theme.getFont("large_bold") // 16pt, bold
text: { text: {
if (!printer) { if (!printer) {
@ -258,7 +306,7 @@ Item
} }
if (printer && printer.state == "unreachable") if (printer && printer.state == "unreachable")
{ {
return catalog.i18nc("@label:status", "Unavailable") return catalog.i18nc("@label:status", "Unreachable")
} }
if (printer && !printer.activePrintJob && printer.state == "idle") if (printer && !printer.activePrintJob && printer.state == "idle")
{ {
@ -299,10 +347,10 @@ Item
Label Label
{ {
id: printerJobNameLabel id: printerJobNameLabel
color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? "#414054" : "#babac1" // TODO: Theme! color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("large") // 16pt, bold font: UM.Theme.getFont("large") // 16pt, bold
text: printer && printer.activePrintJob ? printer.activePrintJob.name : "Untitled" // TODO: I18N text: printer && printer.activePrintJob ? printer.activePrintJob.name : catalog.i18nc("@label", "Untitled")
width: parent.width width: parent.width
// FIXED-LINE-HEIGHT: // FIXED-LINE-HEIGHT:
@ -319,10 +367,10 @@ Item
topMargin: 6 * screenScaleFactor // TODO: Theme! topMargin: 6 * screenScaleFactor // TODO: Theme!
left: printerJobNameLabel.left left: printerJobNameLabel.left
} }
color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? "#53657d" : "#babac1" // TODO: Theme! color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("default") // 12pt, regular font: UM.Theme.getFont("default") // 12pt, regular
text: printer && printer.activePrintJob ? printer.activePrintJob.owner : "Anonymous" // TODO: I18N text: printer && printer.activePrintJob ? printer.activePrintJob.owner : catalog.i18nc("@label", "Anonymous")
width: parent.width width: parent.width
// FIXED-LINE-HEIGHT: // FIXED-LINE-HEIGHT:
@ -348,8 +396,9 @@ Item
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
} }
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
text: "Requires configuration changes" text: catalog.i18nc("@label:status", "Requires configuration changes")
visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible
color: UM.Theme.getColor("monitor_text_primary")
// FIXED-LINE-HEIGHT: // FIXED-LINE-HEIGHT:
height: 18 * screenScaleFactor // TODO: Theme! height: 18 * screenScaleFactor // TODO: Theme!
@ -368,13 +417,13 @@ Item
} }
background: Rectangle background: Rectangle
{ {
color: "#d8d8d8" // TODO: Theme! color: UM.Theme.getColor("monitor_secondary_button_shadow")
radius: 2 * screenScaleFactor // Todo: Theme! radius: 2 * screenScaleFactor // Todo: Theme!
Rectangle Rectangle
{ {
anchors.fill: parent anchors.fill: parent
anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme! anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
color: detailsButton.hovered ? "#e4e4e4" : "#f0f0f0" // TODO: Theme! color: detailsButton.hovered ? UM.Theme.getColor("monitor_secondary_button_hover") : UM.Theme.getColor("monitor_secondary_button")
radius: 2 * screenScaleFactor // Todo: Theme! radius: 2 * screenScaleFactor // Todo: Theme!
} }
} }
@ -382,9 +431,9 @@ Item
{ {
anchors.fill: parent anchors.fill: parent
anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme! anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme!
color: "#1e66d7" // TODO: Theme! color: UM.Theme.getColor("monitor_secondary_button_text")
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
text: "Details" // TODO: I18NC! text: catalog.i18nc("@action:button","Details");
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
height: 18 * screenScaleFactor // TODO: Theme! height: 18 * screenScaleFactor // TODO: Theme!

View File

@ -37,7 +37,7 @@ Item
MonitorExtruderConfiguration MonitorExtruderConfiguration
{ {
color: modelData && modelData.activeMaterial ? modelData.activeMaterial.color : "#eeeeee" // TODO: Theme! color: modelData && modelData.activeMaterial ? modelData.activeMaterial.color : UM.Theme.getColor("monitor_skeleton_loading")
material: modelData && modelData.activeMaterial ? modelData.activeMaterial.name : "" material: modelData && modelData.activeMaterial ? modelData.activeMaterial.name : ""
position: modelData && typeof(modelData.position) === "number" ? modelData.position : -1 // Use negative one to create empty extruder number position: modelData && typeof(modelData.position) === "number" ? modelData.position : -1 // Use negative one to create empty extruder number
printCore: modelData ? modelData.hotendID : "" printCore: modelData ? modelData.hotendID : ""

View File

@ -32,14 +32,14 @@ Item
Rectangle { Rectangle {
id: background id: background
anchors.fill: parent anchors.fill: parent
color: printerNameLabel.visible ? "#e4e4f2" : "#eeeeee"// TODO: Theme! color: printerNameLabel.visible ? UM.Theme.getColor("monitor_printer_family_tag") : UM.Theme.getColor("monitor_skeleton_loading")
radius: 2 * screenScaleFactor // TODO: Theme! radius: 2 * screenScaleFactor // TODO: Theme!
} }
Label { Label {
id: printerNameLabel id: printerNameLabel
anchors.centerIn: parent anchors.centerIn: parent
color: "#535369" // TODO: Theme! color: UM.Theme.getColor("monitor_text_primary")
text: tagText text: tagText
font.pointSize: 10 // TODO: Theme! font.pointSize: 10 // TODO: Theme!
visible: text !== "" visible: text !== ""

View File

@ -22,7 +22,7 @@ Item
left: queuedPrintJobs.left left: queuedPrintJobs.left
top: parent.top top: parent.top
} }
color: UM.Theme.getColor("text") color: UM.Theme.getColor("monitor_text_primary")
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
text: catalog.i18nc("@label", "Queued") text: catalog.i18nc("@label", "Queued")
} }
@ -42,7 +42,7 @@ Item
{ {
id: externalLinkIcon id: externalLinkIcon
anchors.verticalCenter: manageQueueLabel.verticalCenter anchors.verticalCenter: manageQueueLabel.verticalCenter
color: UM.Theme.getColor("text_link") color: UM.Theme.getColor("monitor_text_link")
source: UM.Theme.getIcon("external_link") source: UM.Theme.getIcon("external_link")
width: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!) width: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
height: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!) height: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
@ -56,10 +56,10 @@ Item
leftMargin: 6 * screenScaleFactor // TODO: Theme! leftMargin: 6 * screenScaleFactor // TODO: Theme!
verticalCenter: externalLinkIcon.verticalCenter verticalCenter: externalLinkIcon.verticalCenter
} }
color: UM.Theme.getColor("text_link") color: UM.Theme.getColor("monitor_text_link")
font: UM.Theme.getFont("default") // 12pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
linkColor: UM.Theme.getColor("text_link") linkColor: UM.Theme.getColor("monitor_text_link")
text: catalog.i18nc("@label link to connect manager", "Manage queue in Cura Connect") text: catalog.i18nc("@label link to connect manager", "Go to Cura Connect")
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
} }
@ -94,7 +94,7 @@ Item
Label Label
{ {
text: catalog.i18nc("@label", "Print jobs") text: catalog.i18nc("@label", "Print jobs")
color: "#666666" color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -108,7 +108,7 @@ Item
Label Label
{ {
text: catalog.i18nc("@label", "Total print time") text: catalog.i18nc("@label", "Total print time")
color: "#666666" color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -122,7 +122,7 @@ Item
Label Label
{ {
text: catalog.i18nc("@label", "Waiting for") text: catalog.i18nc("@label", "Waiting for")
color: "#666666" color: UM.Theme.getColor("monitor_text_primary")
elide: Text.ElideRight elide: Text.ElideRight
font: UM.Theme.getFont("medium") // 14pt, regular font: UM.Theme.getFont("medium") // 14pt, regular
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -160,8 +160,101 @@ Item
} }
printJob: modelData printJob: modelData
} }
model: OutputDevice.receivedPrintJobs ? OutputDevice.queuedPrintJobs : [null,null] model:
{
// When printing over the cloud we don't recieve print jobs until there is one, so
// unless there's at least one print job we'll be stuck with skeleton loading
// indefinitely.
if (Cura.MachineManager.activeMachineHasActiveCloudConnection)
{
return OutputDevice.queuedPrintJobs
}
return OutputDevice.receivedPrintJobs ? OutputDevice.queuedPrintJobs : [null,null]
}
spacing: 6 // TODO: Theme! spacing: 6 // TODO: Theme!
} }
} }
Rectangle
{
anchors
{
horizontalCenter: parent.horizontalCenter
top: printJobQueueHeadings.bottom
topMargin: 12 * screenScaleFactor // TODO: Theme!
}
height: 48 * screenScaleFactor // TODO: Theme!
width: parent.width
color: UM.Theme.getColor("monitor_card_background")
border.color: UM.Theme.getColor("monitor_card_border")
radius: 2 * screenScaleFactor // TODO: Theme!
visible: printJobList.model.length == 0
Row
{
anchors
{
left: parent.left
leftMargin: 18 * screenScaleFactor // TODO: Theme!
verticalCenter: parent.verticalCenter
}
spacing: 18 * screenScaleFactor // TODO: Theme!
height: 18 * screenScaleFactor // TODO: Theme!
Label
{
text: "All jobs are printed."
color: UM.Theme.getColor("monitor_text_primary")
font: UM.Theme.getFont("medium") // 14pt, regular
}
Item
{
id: viewPrintHistoryLabel
height: 18 * screenScaleFactor // TODO: Theme!
width: childrenRect.width
UM.RecolorImage
{
id: printHistoryIcon
anchors.verticalCenter: parent.verticalCenter
color: UM.Theme.getColor("monitor_text_link")
source: UM.Theme.getIcon("external_link")
width: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
height: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!)
}
Label
{
id: viewPrintHistoryText
anchors
{
left: printHistoryIcon.right
leftMargin: 6 * screenScaleFactor // TODO: Theme!
verticalCenter: printHistoryIcon.verticalCenter
}
color: UM.Theme.getColor("monitor_text_link")
font: UM.Theme.getFont("medium") // 14pt, regular
linkColor: UM.Theme.getColor("monitor_text_link")
text: catalog.i18nc("@label link to connect manager", "View print history")
renderType: Text.NativeRendering
}
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel()
onEntered:
{
viewPrintHistoryText.font.underline = true
}
onExited:
{
viewPrintHistoryText.font.underline = false
}
}
}
}
}
} }

View File

@ -11,7 +11,7 @@ import QtGraphicalEffects 1.0
// This is the root component for the monitor stage. // This is the root component for the monitor stage.
Component Component
{ {
Item Rectangle
{ {
id: monitorFrame id: monitorFrame
@ -24,6 +24,7 @@ Component
} }
} }
width: maximumWidth width: maximumWidth
color: UM.Theme.getColor("monitor_stage_background")
// Enable keyboard navigation. NOTE: This is done here so that we can also potentially // Enable keyboard navigation. NOTE: This is done here so that we can also potentially
// forward to the queue items in the future. (Deleting selected print job, etc.) // forward to the queue items in the future. (Deleting selected print job, etc.)
@ -36,24 +37,6 @@ Component
name: "cura" name: "cura"
} }
LinearGradient
{
anchors.fill: parent
gradient: Gradient
{
GradientStop
{
position: 0.0
color: "#f6f6f6" // TODO: Theme!
}
GradientStop
{
position: 1.0
color: "#ffffff" // TODO: Theme!
}
}
}
Item Item
{ {
id: printers id: printers

View File

@ -1,274 +0,0 @@
// Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.1
import QtGraphicalEffects 1.0
import UM 1.3 as UM
Item {
id: root;
property var printJob: null;
property var started: isStarted(printJob);
property var assigned: isAssigned(printJob);
property var enabled: true
Button {
id: button;
background: Rectangle {
color: UM.Theme.getColor("viewport_background"); // TODO: Theme!
height: button.height;
opacity: button.down || button.hovered ? 1 : 0;
radius: Math.round(0.5 * width);
width: button.width;
}
contentItem: Label {
color: UM.Theme.getColor("monitor_context_menu_dots");
font.pixelSize: 32 * screenScaleFactor;
horizontalAlignment: Text.AlignHCenter;
text: button.text;
verticalAlignment: Text.AlignVCenter;
}
height: width;
hoverEnabled: base.enabled
onClicked: base.enabled ? parent.switchPopupState() : {}
text: "\u22EE"; //Unicode; Three stacked points.
visible: {
if (!printJob) {
return false;
}
var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"];
return states.indexOf(printJob.state) !== -1;
}
width: 36 * screenScaleFactor; // TODO: Theme!
}
Popup {
id: popup;
background: Item {
anchors.fill: parent;
DropShadow {
anchors.fill: pointedRectangle;
color: UM.Theme.getColor("monitor_shadow");
radius: UM.Theme.getSize("monitor_shadow_radius").width;
source: pointedRectangle;
transparentBorder: true;
verticalOffset: 2 * screenScaleFactor;
}
Item {
id: pointedRectangle;
anchors {
horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter;
}
height: parent.height - 10 * screenScaleFactor; // Because of the shadow
width: parent.width - 10 * screenScaleFactor; // Because of the shadow
Rectangle {
id: point;
anchors {
right: bloop.right;
rightMargin: 24 * screenScaleFactor;
}
color: UM.Theme.getColor("monitor_context_menu_background");
height: 14 * screenScaleFactor;
transform: Rotation {
angle: 45;
}
width: 14 * screenScaleFactor;
y: 1 * screenScaleFactor;
}
Rectangle {
id: bloop;
anchors {
bottom: parent.bottom;
bottomMargin: 8 * screenScaleFactor; // Because of the shadow
top: parent.top;
topMargin: 8 * screenScaleFactor; // Because of the shadow + point
}
color: UM.Theme.getColor("monitor_context_menu_background");
width: parent.width;
}
}
}
clip: true;
closePolicy: Popup.CloseOnPressOutside;
contentItem: Column {
id: popupOptions;
anchors {
top: parent.top;
topMargin: UM.Theme.getSize("default_margin").height + 10 * screenScaleFactor; // Account for the point of the box
}
height: childrenRect.height + spacing * popupOptions.children.length + UM.Theme.getSize("default_margin").height;
spacing: Math.floor(UM.Theme.getSize("default_margin").height / 2);
width: parent.width;
PrintJobContextMenuItem {
onClicked: {
sendToTopConfirmationDialog.visible = true;
popup.close();
}
text: catalog.i18nc("@label", "Move to top");
visible: {
if (printJob && printJob.state == "queued" && !assigned) {
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;
}
}
}
enter: Transition {
NumberAnimation {
duration: 75;
property: "visible";
}
}
exit: Transition {
NumberAnimation {
duration: 75;
property: "visible";
}
}
height: contentItem.height + 2 * padding;
onClosed: visible = false;
onOpened: visible = true;
padding: UM.Theme.getSize("monitor_shadow_radius").width;
transformOrigin: Popup.Top;
visible: false;
width: 182 * screenScaleFactor;
x: (button.width - width) + 26 * screenScaleFactor;
y: button.height + 5 * screenScaleFactor; // Because shadow
}
MessageDialog {
id: sendToTopConfirmationDialog;
Component.onCompleted: visible = false;
icon: StandardIcon.Warning;
onYes: OutputDevice.sendJobToTop(printJob.key);
standardButtons: StandardButton.Yes | StandardButton.No;
text: printJob && printJob.name ? catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to move %1 to the top of the queue?").arg(printJob.name) : "";
title: catalog.i18nc("@window:title", "Move print job to top");
}
MessageDialog {
id: deleteConfirmationDialog;
Component.onCompleted: visible = false;
icon: StandardIcon.Warning;
onYes: OutputDevice.deleteJobFromQueue(printJob.key);
standardButtons: StandardButton.Yes | StandardButton.No;
text: printJob && printJob.name ? catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to delete %1?").arg(printJob.name) : "";
title: catalog.i18nc("@window:title", "Delete print job");
}
MessageDialog {
id: abortConfirmationDialog;
Component.onCompleted: visible = false;
icon: StandardIcon.Warning;
onYes: printJob.setState("abort");
standardButtons: StandardButton.Yes | StandardButton.No;
text: printJob && printJob.name ? catalog.i18nc("@label %1 is the name of a print job.", "Are you sure you want to abort %1?").arg(printJob.name) : "";
title: catalog.i18nc("@window:title", "Abort print");
}
// Utils
function switchPopupState() {
popup.visible ? popup.close() : popup.open();
}
function isStarted(job) {
if (!job) {
return false;
}
return ["pre_print", "printing", "pausing", "paused", "resuming", "aborting"].indexOf(job.state) !== -1;
}
function isAssigned(job) {
if (!job) {
return false;
}
return job.assignedPrinter ? true : false;
}
function getMenuLength() {
var visible = 0;
for (var i = 0; i < popupOptions.children.length; i++) {
if (popupOptions.children[i].visible) {
visible++;
}
}
return visible;
}
}

View File

@ -9,10 +9,10 @@ import UM 1.3 as UM
Button { Button {
background: Rectangle { background: Rectangle {
opacity: parent.down || parent.hovered ? 1 : 0; opacity: parent.down || parent.hovered ? 1 : 0;
color: UM.Theme.getColor("monitor_context_menu_highlight"); color: UM.Theme.getColor("monitor_context_menu_hover")
} }
contentItem: Label { contentItem: Label {
color: enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("text_inactive"); color: enabled ? UM.Theme.getColor("monitor_text_primary") : UM.Theme.getColor("monitor_text_disabled");
text: parent.text text: parent.text
horizontalAlignment: Text.AlignLeft; horizontalAlignment: Text.AlignLeft;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;

View File

@ -111,7 +111,7 @@ class CloudOutputDeviceManager:
stored_cluster_id = active_machine.getMetaDataEntry(self.META_CLUSTER_ID) stored_cluster_id = active_machine.getMetaDataEntry(self.META_CLUSTER_ID)
if stored_cluster_id in self._remote_clusters: if stored_cluster_id in self._remote_clusters:
device = self._remote_clusters[stored_cluster_id] device = self._remote_clusters[stored_cluster_id]
self._connectToOutputDevice(device) self._connectToOutputDevice(device, active_machine)
Logger.log("d", "Device connected by metadata cluster ID %s", stored_cluster_id) Logger.log("d", "Device connected by metadata cluster ID %s", stored_cluster_id)
else: else:
self._connectByNetworkKey(active_machine) self._connectByNetworkKey(active_machine)
@ -129,12 +129,13 @@ class CloudOutputDeviceManager:
Logger.log("i", "Found cluster %s with network key %s", device, local_network_key) Logger.log("i", "Found cluster %s with network key %s", device, local_network_key)
active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
self._connectToOutputDevice(device) self._connectToOutputDevice(device, active_machine)
## Connects to an output device and makes sure it is registered in the output device manager. ## Connects to an output device and makes sure it is registered in the output device manager.
def _connectToOutputDevice(self, device: CloudOutputDevice) -> None: def _connectToOutputDevice(self, device: CloudOutputDevice, active_machine: GlobalStack) -> None:
device.connect() device.connect()
self._output_device_manager.addOutputDevice(device) self._output_device_manager.addOutputDevice(device)
active_machine.addConfiguredConnectionType(device.connectionType.value)
## Handles an API error received from the cloud. ## Handles an API error received from the cloud.
# \param errors: The errors received # \param errors: The errors received

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Any, cast, Tuple, Union, Optional, Dict, List from typing import Any, cast, Tuple, Union, Optional, Dict, List
@ -13,6 +13,7 @@ from UM.FileHandler.WriteFileJob import WriteFileJob # To call the file writer
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Qt.Duration import Duration, DurationFormat
from UM.Message import Message from UM.Message import Message
from UM.Scene.SceneNode import SceneNode # For typing. from UM.Scene.SceneNode import SceneNode # For typing.
@ -194,7 +195,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0,
dismissable = False, progress = -1, dismissable = False, progress = -1,
title = i18n_catalog.i18nc("@info:title", "Sending Data")) title = i18n_catalog.i18nc("@info:title", "Sending Data"))
self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = None, self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = "",
description = "") description = "")
self._progress_message.actionTriggered.connect(self._progressMessageActionTriggered) self._progress_message.actionTriggered.connect(self._progressMessageActionTriggered)
self._progress_message.show() self._progress_message.show()
@ -255,7 +256,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
# Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get # Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get
# timeout responses if this happens. # timeout responses if this happens.
self._last_response_time = time() self._last_response_time = time()
if self._progress_message is not None and new_progress > self._progress_message.getProgress(): if self._progress_message is not None and new_progress != self._progress_message.getProgress():
self._progress_message.show() # Ensure that the message is visible. self._progress_message.show() # Ensure that the message is visible.
self._progress_message.setProgress(bytes_sent / bytes_total * 100) self._progress_message.setProgress(bytes_sent / bytes_total * 100)
@ -267,7 +268,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
i18n_catalog.i18nc("@info:status", "Print job was successfully sent to the printer."), i18n_catalog.i18nc("@info:status", "Print job was successfully sent to the printer."),
lifetime=5, dismissable=True, lifetime=5, dismissable=True,
title=i18n_catalog.i18nc("@info:title", "Data Sent")) title=i18n_catalog.i18nc("@info:title", "Data Sent"))
self._success_message.addAction("View", i18n_catalog.i18nc("@action:button", "View in Monitor"), icon=None, self._success_message.addAction("View", i18n_catalog.i18nc("@action:button", "View in Monitor"), icon = "",
description="") description="")
self._success_message.actionTriggered.connect(self._successMessageActionTriggered) self._success_message.actionTriggered.connect(self._successMessageActionTriggered)
self._success_message.show() self._success_message.show()
@ -346,12 +347,16 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
def getDateCompleted(self, time_remaining: int) -> str: def getDateCompleted(self, time_remaining: int) -> str:
return formatDateCompleted(time_remaining) return formatDateCompleted(time_remaining)
@pyqtSlot(int, result = str)
def formatDuration(self, seconds: int) -> str:
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
@pyqtSlot(str) @pyqtSlot(str)
def sendJobToTop(self, print_job_uuid: str) -> None: def sendJobToTop(self, print_job_uuid: str) -> None:
# This function is part of the output device (and not of the printjob output model) as this type of operation # This function is part of the output device (and not of the printjob output model) as this type of operation
# is a modification of the cluster queue and not of the actual job. # is a modification of the cluster queue and not of the actual job.
data = "{\"to_position\": 0}" data = "{\"list\": \"queued\",\"to_position\": 0}"
self.put("print_jobs/{uuid}/move_to_position".format(uuid = print_job_uuid), data, on_finished=None) self.post("print_jobs/{uuid}/action/move".format(uuid = print_job_uuid), data, on_finished=None)
@pyqtSlot(str) @pyqtSlot(str)
def deleteJobFromQueue(self, print_job_uuid: str) -> None: def deleteJobFromQueue(self, print_job_uuid: str) -> None:

View File

@ -13,6 +13,7 @@ from UM.i18n import i18nCatalog
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.MachineAction import MachineAction from cura.MachineAction import MachineAction
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
from .UM3OutputDevicePlugin import UM3OutputDevicePlugin from .UM3OutputDevicePlugin import UM3OutputDevicePlugin
@ -105,13 +106,13 @@ class DiscoverUM3Action(MachineAction):
global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
if global_container_stack: if global_container_stack:
meta_data = global_container_stack.getMetaData() meta_data = global_container_stack.getMetaData()
if "connect_group_name" in meta_data: if "group_name" in meta_data:
previous_connect_group_name = meta_data["connect_group_name"] previous_connect_group_name = meta_data["group_name"]
global_container_stack.setMetaDataEntry("connect_group_name", group_name) global_container_stack.setMetaDataEntry("group_name", group_name)
# Find all the places where there is the same group name and change it accordingly # Find all the places where there is the same group name and change it accordingly
CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "connect_group_name", value = previous_connect_group_name, new_value = group_name) CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "group_name", value = previous_connect_group_name, new_value = group_name)
else: else:
global_container_stack.setMetaDataEntry("connect_group_name", group_name) global_container_stack.setMetaDataEntry("group_name", group_name)
# Set the default value for "hidden", which is used when you have a group with multiple types of printers # Set the default value for "hidden", which is used when you have a group with multiple types of printers
global_container_stack.setMetaDataEntry("hidden", False) global_container_stack.setMetaDataEntry("hidden", False)
@ -133,23 +134,29 @@ class DiscoverUM3Action(MachineAction):
return return
meta_data = global_container_stack.getMetaData() meta_data = global_container_stack.getMetaData()
if "um_network_key" in meta_data:
previous_network_key = meta_data["um_network_key"]
global_container_stack.setMetaDataEntry("um_network_key", printer_device.key)
# Delete old authentication data.
Logger.log("d", "Removing old authentication id %s for device %s",
global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key)
global_container_stack.removeMetaDataEntry("network_authentication_id")
global_container_stack.removeMetaDataEntry("network_authentication_key")
CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = printer_device.key)
if "connection_type" in meta_data: if "um_network_key" in meta_data: # Global stack already had a connection, but it's changed.
previous_connection_type = meta_data["connection_type"] old_network_key = meta_data["um_network_key"]
global_container_stack.setMetaDataEntry("connection_type", printer_device.connectionType.value) # Since we might have a bunch of hidden stacks, we also need to change it there.
CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "connection_type", value = previous_connection_type, new_value = printer_device.connectionType.value) metadata_filter = {"um_network_key": old_network_key}
else: containers = CuraContainerRegistry.getInstance().findContainerStacks(type="machine", **metadata_filter)
for container in containers:
container.setMetaDataEntry("um_network_key", printer_device.key)
# Delete old authentication data.
Logger.log("d", "Removing old authentication id %s for device %s",
global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key)
container.removeMetaDataEntry("network_authentication_id")
container.removeMetaDataEntry("network_authentication_key")
# Ensure that these containers do know that they are configured for network connection
container.addConfiguredConnectionType(printer_device.connectionType.value)
else: # Global stack didn't have a connection yet, configure it.
global_container_stack.setMetaDataEntry("um_network_key", printer_device.key) global_container_stack.setMetaDataEntry("um_network_key", printer_device.key)
global_container_stack.setMetaDataEntry("connection_type", printer_device.connectionType.value) global_container_stack.addConfiguredConnectionType(printer_device.connectionType.value)
if self._network_plugin: if self._network_plugin:
# Ensure that the connection states are refreshed. # Ensure that the connection states are refreshed.

View File

@ -1,4 +1,4 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
@ -33,9 +33,9 @@ class LegacyUM3PrinterOutputController(PrinterOutputController):
data = "{\"target\": \"%s\"}" % state data = "{\"target\": \"%s\"}" % state
self._output_device.put("print_job/state", data, on_finished=None) self._output_device.put("print_job/state", data, on_finished=None)
def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: float):
data = str(temperature) data = str(temperature)
self._output_device.put("printer/bed/temperature/target", data, on_finished=self._onPutBedTemperatureCompleted) self._output_device.put("printer/bed/temperature/target", data, on_finished = self._onPutBedTemperatureCompleted)
def _onPutBedTemperatureCompleted(self, reply): def _onPutBedTemperatureCompleted(self, reply):
if Version(self._preheat_printer.firmwareVersion) < Version("3.5.92"): if Version(self._preheat_printer.firmwareVersion) < Version("3.5.92"):

View File

@ -1,14 +1,14 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import json import json
import os import os
from typing import Dict, TYPE_CHECKING, Set, Optional from typing import Dict, TYPE_CHECKING, Set, Optional
from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
from UM.Application import Application
from UM.Job import Job from UM.Job import Job
from UM.Logger import Logger from UM.Logger import Logger
from cura.CuraApplication import CuraApplication
# Absolute imports don't work in plugins # Absolute imports don't work in plugins
from .Models import ClusterMaterial, LocalMaterial from .Models import ClusterMaterial, LocalMaterial
@ -86,8 +86,8 @@ class SendMaterialJob(Job):
# #
# \param materials_to_send A set with id's of materials that must be sent. # \param materials_to_send A set with id's of materials that must be sent.
def _sendMaterials(self, materials_to_send: Set[str]) -> None: def _sendMaterials(self, materials_to_send: Set[str]) -> None:
container_registry = Application.getInstance().getContainerRegistry() container_registry = CuraApplication.getInstance().getContainerRegistry()
material_manager = Application.getInstance().getMaterialManager() material_manager = CuraApplication.getInstance().getMaterialManager()
material_group_dict = material_manager.getAllMaterialGroups() material_group_dict = material_manager.getAllMaterialGroups()
for root_material_id in material_group_dict: for root_material_id in material_group_dict:
@ -166,7 +166,7 @@ class SendMaterialJob(Job):
# \return a dictionary of LocalMaterial objects by GUID # \return a dictionary of LocalMaterial objects by GUID
def _getLocalMaterials(self) -> Dict[str, LocalMaterial]: def _getLocalMaterials(self) -> Dict[str, LocalMaterial]:
result = {} # type: Dict[str, LocalMaterial] result = {} # type: Dict[str, LocalMaterial]
material_manager = Application.getInstance().getMaterialManager() material_manager = CuraApplication.getInstance().getMaterialManager()
material_group_dict = material_manager.getAllMaterialGroups() material_group_dict = material_manager.getAllMaterialGroups()

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import json import json
from queue import Queue from queue import Queue
@ -9,7 +9,7 @@ from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from UM.Application import Application from cura.CuraApplication import CuraApplication
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Logger import Logger from UM.Logger import Logger
from UM.Signal import Signal, signalemitter from UM.Signal import Signal, signalemitter
@ -41,7 +41,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self.addDeviceSignal.connect(self._onAddDevice) self.addDeviceSignal.connect(self._onAddDevice)
self.removeDeviceSignal.connect(self._onRemoveDevice) self.removeDeviceSignal.connect(self._onRemoveDevice)
Application.getInstance().globalContainerStackChanged.connect(self.reCheckConnections) CuraApplication.getInstance().globalContainerStackChanged.connect(self.reCheckConnections)
self._discovered_devices = {} self._discovered_devices = {}
@ -56,7 +56,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._cluster_api_prefix = "/cluster-api/v" + self._cluster_api_version + "/" self._cluster_api_prefix = "/cluster-api/v" + self._cluster_api_version + "/"
# Get list of manual instances from preferences # Get list of manual instances from preferences
self._preferences = Application.getInstance().getPreferences() self._preferences = CuraApplication.getInstance().getPreferences()
self._preferences.addPreference("um3networkprinting/manual_instances", self._preferences.addPreference("um3networkprinting/manual_instances",
"") # A comma-separated list of ip adresses or hostnames "") # A comma-separated list of ip adresses or hostnames
@ -108,7 +108,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self.resetLastManualDevice() self.resetLastManualDevice()
def reCheckConnections(self): def reCheckConnections(self):
active_machine = Application.getInstance().getGlobalContainerStack() active_machine = CuraApplication.getInstance().getGlobalContainerStack()
if not active_machine: if not active_machine:
return return
@ -118,7 +118,8 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
if key == um_network_key: if key == um_network_key:
if not self._discovered_devices[key].isConnected(): if not self._discovered_devices[key].isConnected():
Logger.log("d", "Attempting to connect with [%s]" % key) Logger.log("d", "Attempting to connect with [%s]" % key)
active_machine.setMetaDataEntry("connection_type", self._discovered_devices[key].connectionType.value) # It should already be set, but if it actually connects we know for sure it's supported!
active_machine.addConfiguredConnectionType(self._discovered_devices[key].connectionType.value)
self._discovered_devices[key].connect() self._discovered_devices[key].connect()
self._discovered_devices[key].connectionStateChanged.connect(self._onDeviceConnectionStateChanged) self._discovered_devices[key].connectionStateChanged.connect(self._onDeviceConnectionStateChanged)
else: else:
@ -134,7 +135,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
return return
if self._discovered_devices[key].isConnected(): if self._discovered_devices[key].isConnected():
# Sometimes the status changes after changing the global container and maybe the device doesn't belong to this machine # Sometimes the status changes after changing the global container and maybe the device doesn't belong to this machine
um_network_key = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("um_network_key") um_network_key = CuraApplication.getInstance().getGlobalContainerStack().getMetaDataEntry("um_network_key")
if key == um_network_key: if key == um_network_key:
self.getOutputDeviceManager().addOutputDevice(self._discovered_devices[key]) self.getOutputDeviceManager().addOutputDevice(self._discovered_devices[key])
else: else:
@ -244,7 +245,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
properties = device.getProperties().copy() properties = device.getProperties().copy()
if b"incomplete" in properties: if b"incomplete" in properties:
del properties[b"incomplete"] del properties[b"incomplete"]
properties[b'cluster_size'] = len(cluster_printers_list) properties[b"cluster_size"] = len(cluster_printers_list)
self._onRemoveDevice(instance_name) self._onRemoveDevice(instance_name)
self._onAddDevice(instance_name, address, properties) self._onAddDevice(instance_name, address, properties)
@ -287,9 +288,10 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._discovered_devices[device.getId()] = device self._discovered_devices[device.getId()] = device
self.discoveredDevicesChanged.emit() self.discoveredDevicesChanged.emit()
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = CuraApplication.getInstance().getGlobalContainerStack()
if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"): if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"):
global_container_stack.setMetaDataEntry("connection_type", device.connectionType.value) # Ensure that the configured connection type is set.
global_container_stack.addConfiguredConnectionType(device.connectionType.value)
device.connect() device.connect()
device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged) device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged)
@ -306,7 +308,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._service_changed_request_event.wait(timeout = 5.0) self._service_changed_request_event.wait(timeout = 5.0)
# Stop if the application is shutting down # Stop if the application is shutting down
if Application.getInstance().isShuttingDown(): if CuraApplication.getInstance().isShuttingDown():
return return
self._service_changed_request_event.clear() self._service_changed_request_event.clear()

View File

@ -72,9 +72,9 @@ class AutoDetectBaudJob(Job):
while timeout_time > time(): while timeout_time > time():
line = serial.readline() line = serial.readline()
if b"ok " in line and b"T:" in line: if b"ok" in line and b"T:" in line:
successful_responses += 1 successful_responses += 1
if successful_responses >= 3: if successful_responses >= 1:
self.setResult(baud_rate) self.setResult(baud_rate)
Logger.log("d", "Detected baud rate {baud_rate} on serial {serial} on retry {retry} with after {time_elapsed:0.2f} seconds.".format( Logger.log("d", "Detected baud rate {baud_rate} on serial {serial} on retry {retry} with after {time_elapsed:0.2f} seconds.".format(
serial = self._serial_port, baud_rate = baud_rate, retry = retry, time_elapsed = time() - start_timeout_time)) serial = self._serial_port, baud_rate = baud_rate, retry = retry, time_elapsed = time() - start_timeout_time))

View File

@ -55,6 +55,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._update_thread = Thread(target = self._update, daemon = True) self._update_thread = Thread(target = self._update, daemon = True)
self._last_temperature_request = None # type: Optional[int] self._last_temperature_request = None # type: Optional[int]
self._firmware_idle_count = 0
self._is_printing = False # A print is being sent. self._is_printing = False # A print is being sent.
@ -114,7 +115,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None, **kwargs): def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None, **kwargs):
if self._is_printing: if self._is_printing:
return # Aleady printing return # Aleady printing
self.writeStarted.emit(self)
# cancel any ongoing preheat timer before starting a print # cancel any ongoing preheat timer before starting a print
self._printers[0].getController().stopPreheatTimers() self._printers[0].getController().stopPreheatTimers()

View File

@ -1,9 +1,12 @@
import configparser import configparser
from typing import Tuple, List, Set from typing import Tuple, List, Set, Dict
import io import io
from UM.VersionUpgrade import VersionUpgrade from UM.VersionUpgrade import VersionUpgrade
from cura.PrinterOutputDevice import ConnectionType from cura.PrinterOutputDevice import ConnectionType
deleted_settings = {"bridge_wall_max_overhang"} # type: Set[str] deleted_settings = {"bridge_wall_max_overhang"} # type: Set[str]
renamed_configurations = {"connect_group_name": "group_name"} # type: Dict[str, str]
class VersionUpgrade35to40(VersionUpgrade): class VersionUpgrade35to40(VersionUpgrade):
@ -20,10 +23,16 @@ class VersionUpgrade35to40(VersionUpgrade):
# Set the connection type if um_network_key or the octoprint key is set. # Set the connection type if um_network_key or the octoprint key is set.
parser["metadata"]["connection_type"] = str(ConnectionType.NetworkConnection.value) parser["metadata"]["connection_type"] = str(ConnectionType.NetworkConnection.value)
if "metadata" in parser:
for old_name, new_name in renamed_configurations.items():
if old_name not in parser["metadata"]:
continue
parser["metadata"][new_name] = parser["metadata"][old_name]
del parser["metadata"][old_name]
result = io.StringIO() result = io.StringIO()
parser.write(result) parser.write(result)
return [filename], [result.getvalue()] return [filename], [result.getvalue()]
pass
def getCfgVersion(self, serialised: str) -> int: def getCfgVersion(self, serialised: str) -> int:
parser = configparser.ConfigParser(interpolation = None) parser = configparser.ConfigParser(interpolation = None)
@ -65,4 +74,4 @@ class VersionUpgrade35to40(VersionUpgrade):
result = io.StringIO() result = io.StringIO()
parser.write(result) parser.write(result)
return [filename], [result.getvalue()] return [filename], [result.getvalue()]

View File

@ -0,0 +1,51 @@
{
"id": "CR-X",
"version": 2,
"name": "Creality CR-X",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "SRC",
"manufacturer": "Creality3D",
"category": "Other",
"file_formats": "text/x-gcode",
"platform": "cr-x.stl",
"has_variants": false,
"has_machine_quality": false,
"preferred_quality_type": "draft",
"machine_extruder_trains": {
"0": "cr-x_extruder_0",
"1": "cr-x_extruder_1"
}
},
"overrides": {
"machine_name": { "default_value": "Creality CR-X" },
"machine_extruder_count": { "default_value": 2 },
"machine_heated_bed": { "default_value": true },
"machine_width": { "default_value": 300 },
"machine_depth": { "default_value": 300 },
"machine_height": { "default_value": 400 },
"machine_center_is_zero": { "default_value": false },
"retraction_amount": { "default_value": 3 },
"retraction_speed": { "default_value": 70},
"adhesion_type": { "default_value": "skirt" },
"gantry_height": { "default_value": 30 },
"speed_print": { "default_value": 60 },
"speed_travel": { "default_value": 120 },
"machine_max_acceleration_x": { "default_value": 500 },
"machine_max_acceleration_y": { "default_value": 500 },
"machine_max_acceleration_z": { "default_value": 100 },
"machine_max_acceleration_e": { "default_value": 5000 },
"machine_max_jerk_xy": { "default_value": 5.0 },
"machine_max_jerk_z": { "default_value": 0.4 },
"machine_max_jerk_e": { "default_value": 5.0 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "default_value": "G21 ;metric values\nG28 ;home all\nG90 ;absolute positioning\nM107 ;start with the fan off\nG1 F2400 Z15.0 ;raise the nozzle 15mm\nM109 S{material_print_temperature} ;Set Extruder Temperature and Wait\nM190 S{material_bed_temperature}; Wait for bed temperature to reach target temp\nT0 ;Switch to Extruder 1\nG1 F3000 X5 Y10 Z0.2 ;move to prime start position\nG92 E0 ;reset extrusion distance\nG1 F600 X160 E15 ;prime nozzle in a line\nG1 F5000 X180 ;quick wipe\nG92 E0 ;reset extrusion distance" },
"machine_end_gcode": { "default_value": "M104 S0 ;hotend off\nM140 S0 ;bed off\nG92 E0\nG1 F2000 E-100 ;retract filament 100mm\nG92 E0\nG1 F3000 X0 Y270 ;move bed for easy part removal\nM84 ;disable steppers" },
"material_print_temperature": { "default_value": 200 },
"wall_thickness": { "default_value": 1 },
"top_bottom_thickness": { "default_value": 1 },
"bottom_thickness": { "default_value": 1 }
}
}

View File

@ -3395,7 +3395,7 @@
"infill": "Within Infill" "infill": "Within Infill"
}, },
"default_value": "all", "default_value": "all",
"resolve": "'noskin' if 'noskin' in extruderValues('retraction_combing') else ('all' if 'all' in extruderValues('retraction_combing') else 'off')", "resolve": "'noskin' if 'noskin' in extruderValues('retraction_combing') else ('infill' if 'infill' in extruderValues('retraction_combing') else ('all' if 'all' in extruderValues('retraction_combing') else 'off'))",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false "settable_per_extruder": false
}, },

View File

@ -15,6 +15,7 @@
"has_machine_materials": true, "has_machine_materials": true,
"has_machine_quality": true, "has_machine_quality": true,
"first_start_actions": [], "first_start_actions": [],
"supported_actions": [],
"machine_extruder_trains": "machine_extruder_trains":
{ {
"0": "ultimaker2_plus_extruder_0" "0": "ultimaker2_plus_extruder_0"

View File

@ -0,0 +1,27 @@
{
"id": "cr-x_extruder_0",
"version": 2,
"name": "Left Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "Creality CR-X",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_extruder_start_code": {
"default_value": "\nT0 ;switch to extruder 1\nG92 E0 ;reset extruder distance\nG1 F2000 E93 ;load filament\nG92 E0 ;reset extruder distance\nM104 S{material_print_temperature}"
},
"machine_extruder_end_code": {
"default_value": "\nG92 E0 ;reset extruder distance\nG1 F800 E-5 ;short retract\nG1 F2400 X295 Y265 ;move near prime tower\nG1 F2000 E-93 ;long retract for filament removal\nG92 E0 ;reset extruder distance\nG90"
}
}
}

View File

@ -0,0 +1,27 @@
{
"id": "cr-x_extruder_1",
"version": 2,
"name": "Right Extruder",
"inherits": "fdmextruder",
"metadata": {
"machine": "Creality CR-X",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"material_diameter": { "default_value": 1.75 },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_extruder_start_code": {
"default_value": "\nT1 ;switch to extruder 2\nG92 E0 ;reset extruder distance\nG1 F2000 E93 ;load filament\nG92 E0 ;reset extruder distance\nM104 S{material_print_temperature}"
},
"machine_extruder_end_code": {
"default_value": "\nG92 E0 ;reset extruder distance\nG1 F800 E-5 ;short retract\nG1 F2400 X295 Y265 ;move near prime tower\nG1 F2000 E-93 ;long retract for filament removal\nG92 E0 ;reset extruder distance\nG90"
}
}
}

BIN
resources/meshes/cr-x.stl Normal file

Binary file not shown.

View File

@ -1,8 +1,8 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.10
import QtQuick.Controls 2.1 import QtQuick.Controls 2.3
import UM 1.4 as UM import UM 1.4 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
@ -16,38 +16,6 @@ Column
padding: UM.Theme.getSize("wide_margin").height padding: UM.Theme.getSize("wide_margin").height
spacing: UM.Theme.getSize("wide_margin").height spacing: UM.Theme.getSize("wide_margin").height
AvatarImage
{
id: avatar
width: UM.Theme.getSize("avatar_image").width
height: UM.Theme.getSize("avatar_image").height
anchors.horizontalCenter: parent.horizontalCenter
source:
{
if(loggedIn)
{
if(profileImage)
{
return profileImage
}
return UM.Theme.getImage("avatar_no_user")
}
return UM.Theme.getImage("avatar_no_user")
}
outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
}
Label
{
id: information
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
text: loggedIn ? profile["username"] : catalog.i18nc("@label", "Please log in or create an account to\nenjoy all features of Ultimaker Cura.")
font: loggedIn ? UM.Theme.getFont("large_bold") : UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
}
Loader Loader
{ {
id: accountOperations id: accountOperations

View File

@ -1,46 +1,115 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.10
import QtQuick.Controls 2.1 import QtQuick.Controls 2.3
import UM 1.4 as UM import UM 1.4 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
Button Item
{ {
id: accountWidget
property var profile: Cura.API.account.userProfile property var profile: Cura.API.account.userProfile
property var loggedIn: Cura.API.account.isLoggedIn property var loggedIn: Cura.API.account.isLoggedIn
implicitHeight: UM.Theme.getSize("main_window_header").height height: signInButton.height > accountWidget.height ? signInButton.height : accountWidget.height
implicitWidth: UM.Theme.getSize("main_window_header").height width: signInButton.width > accountWidget.width ? signInButton.width : accountWidget.width
background: AvatarImage Button
{ {
id: avatar id: signInButton
width: Math.round(0.8 * accountWidget.width) anchors.verticalCenter: parent.verticalCenter
height: Math.round(0.8 * accountWidget.height)
anchors.verticalCenter: accountWidget.verticalCenter
anchors.horizontalCenter: accountWidget.horizontalCenter
source: text: catalog.i18nc("@action:button", "Sign in")
height: Math.round(0.5 * UM.Theme.getSize("main_window_header").height)
onClicked: popup.opened ? popup.close() : popup.open()
visible: !loggedIn
hoverEnabled: true
background: Rectangle
{ {
if(loggedIn) radius: UM.Theme.getSize("action_button_radius").width
{ color: signInButton.hovered ? UM.Theme.getColor("primary_text") : UM.Theme.getColor("main_window_header_background")
if(profile["profile_image_url"]) border.width: UM.Theme.getSize("default_lining").width
{ border.color: UM.Theme.getColor("primary_text")
return profile["profile_image_url"] }
}
return UM.Theme.getImage("avatar_no_user") contentItem: Label
} {
return UM.Theme.getImage("avatar_no_user") id: label
text: signInButton.text
font: UM.Theme.getFont("default")
color: signInButton.hovered ? UM.Theme.getColor("main_window_header_background") : UM.Theme.getColor("primary_text")
width: contentWidth
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
} }
outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
} }
onClicked: popup.opened ? popup.close() : popup.open() Button
{
id: accountWidget
anchors.verticalCenter: parent.verticalCenter
implicitHeight: UM.Theme.getSize("main_window_header").height
implicitWidth: UM.Theme.getSize("main_window_header").height
hoverEnabled: true
visible: loggedIn
text: (loggedIn && profile["profile_image_url"] == "") ? profile["username"].charAt(0).toUpperCase() : ""
background: AvatarImage
{
id: avatar
width: Math.round(0.8 * accountWidget.width)
height: Math.round(0.8 * accountWidget.height)
anchors.verticalCenter: accountWidget.verticalCenter
anchors.horizontalCenter: accountWidget.horizontalCenter
source: (loggedIn && profile["profile_image_url"]) ? profile["profile_image_url"] : ""
outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
}
contentItem: Item
{
anchors.verticalCenter: accountWidget.verticalCenter
anchors.horizontalCenter: accountWidget.horizontalCenter
visible: avatar.source == ""
Rectangle
{
id: initialCircle
anchors.centerIn: parent
width: Math.min(parent.width, parent.height)
height: width
radius: width
color: accountWidget.hovered ? UM.Theme.getColor("primary_text") : "transparent"
border.width: 1
border.color: UM.Theme.getColor("primary_text")
}
Label
{
id: initialLabel
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
text: accountWidget.text
font: UM.Theme.getFont("large_bold")
color: accountWidget.hovered ? UM.Theme.getColor("main_window_header_background") : UM.Theme.getColor("primary_text")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
}
}
onClicked: popup.opened ? popup.close() : popup.open()
}
Popup Popup
{ {

View File

@ -1,8 +1,8 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.10
import QtQuick.Controls 2.1 import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import UM 1.4 as UM import UM 1.4 as UM
@ -16,6 +16,7 @@ Item
property alias source: profileImage.source property alias source: profileImage.source
property alias outlineColor: profileImageOutline.color property alias outlineColor: profileImageOutline.color
property bool hasAvatar: source != ""
Image Image
{ {
@ -32,6 +33,7 @@ Item
id: profileImageMask id: profileImageMask
anchors.fill: parent anchors.fill: parent
radius: width radius: width
color: hasAvatar ? "white" : "transparent"
} }
OpacityMask OpacityMask
@ -39,6 +41,7 @@ Item
anchors.fill: parent anchors.fill: parent
source: profileImage source: profileImage
maskSource: profileImageMask maskSource: profileImageMask
visible: hasAvatar
cached: true cached: true
} }
@ -49,8 +52,9 @@ Item
// Make it a bit bigger than it has to, otherwise it sometimes shows a white border. // Make it a bit bigger than it has to, otherwise it sometimes shows a white border.
width: parent.width + 2 width: parent.width + 2
height: parent.height + 2 height: parent.height + 2
visible: hasAvatar
source: UM.Theme.getIcon("circle_outline") source: UM.Theme.getIcon("circle_outline")
sourceSize: Qt.size(parent.width, parent.height) sourceSize: Qt.size(parent.width, parent.height)
color: UM.Theme.getColor("account_widget_ouline_active") color: UM.Theme.getColor("account_widget_ouline_active")
} }
} }

View File

@ -1,31 +1,82 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.10
import QtQuick.Controls 1.1 import QtQuick.Controls 2.3
import UM 1.4 as UM import UM 1.4 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
Row Column
{ {
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
Image
{
id: machinesImage
anchors.horizontalCenter: parent.horizontalCenter
source: UM.Theme.getIcon("sign_in_to_cloud")
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
}
Label
{
id: title
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
text: catalog.i18nc("@label", "Ultimaker Cloud")
font: UM.Theme.getFont("large_bold")
color: UM.Theme.getColor("text")
}
Label
{
id: generalInformation
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
text: catalog.i18nc("@label", "The next generation 3D printing workflow")
font: UM.Theme.getFont("default_bold")
color: UM.Theme.getColor("text")
}
Label
{
id: generalInformationPoints
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignLeft
renderType: Text.NativeRendering
text: catalog.i18nc("@text", "- Send print jobs to Ultimaker printers outside your local network\n- Store your Ultimaker Cura settings in the cloud for use anywhere\n- Get exclusive access to material profiles from leading brands")
lineHeight: 1.4
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
}
// placeholder
Label
{
text: " "
}
Cura.PrimaryButton
{
anchors.horizontalCenter: parent.horizontalCenter
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Sign in")
onClicked: Cura.API.account.login()
fixedWidthMode: true
}
Cura.SecondaryButton Cura.SecondaryButton
{ {
anchors.horizontalCenter: parent.horizontalCenter
width: UM.Theme.getSize("account_button").width width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Create account") text: catalog.i18nc("@button", "Create account")
onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl + "/app/create") onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl + "/app/create")
fixedWidthMode: true fixedWidthMode: true
} }
Cura.PrimaryButton
{
width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Login")
onClicked: Cura.API.account.login()
fixedWidthMode: true
}
} }

View File

@ -1,31 +1,63 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.10
import QtQuick.Controls 1.1 import QtQuick.Controls 2.3
import UM 1.4 as UM import UM 1.4 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
Row Column
{ {
width: Math.max(title.width,
accountButton.width) * 1.5
spacing: UM.Theme.getSize("default_margin").width spacing: UM.Theme.getSize("default_margin").width
Label
{
id: title
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
text: catalog.i18nc("@label", "Hi " + profile.username)
font: UM.Theme.getFont("large_bold")
color: UM.Theme.getColor("text")
}
// placeholder
Label
{
text: " "
}
Cura.SecondaryButton Cura.SecondaryButton
{ {
id: accountButton
anchors.horizontalCenter: parent.horizontalCenter
width: UM.Theme.getSize("account_button").width width: UM.Theme.getSize("account_button").width
height: UM.Theme.getSize("account_button").height height: UM.Theme.getSize("account_button").height
text: catalog.i18nc("@button", "Manage account") text: catalog.i18nc("@button", "Ultimaker account")
onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl) onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl)
fixedWidthMode: true fixedWidthMode: false
} }
Cura.PrimaryButton Label
{ {
width: UM.Theme.getSize("account_button").width id: signOutButton
height: UM.Theme.getSize("account_button").height anchors.horizontalCenter: parent.horizontalCenter
text: catalog.i18nc("@button", "Logout") text: catalog.i18nc("@button", "Sign out")
onClicked: Cura.API.account.logout() color: UM.Theme.getColor("secondary_button_text")
fixedWidthMode: true font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering
MouseArea
{
anchors.fill: parent
onClicked: Cura.API.account.logout()
hoverEnabled: true
onEntered: signOutButton.font.underline = true
onExited: signOutButton.font.underline = false
}
} }
} }

View File

@ -48,12 +48,13 @@ Button
contentItem: Row contentItem: Row
{ {
spacing: UM.Theme.getSize("narrow_margin").width spacing: UM.Theme.getSize("narrow_margin").width
height: button.height
//Left side icon. Only displayed if !isIconOnRightSide. //Left side icon. Only displayed if !isIconOnRightSide.
UM.RecolorImage UM.RecolorImage
{ {
id: buttonIconLeft id: buttonIconLeft
source: "" source: ""
height: UM.Theme.getSize("action_button_icon").height height: visible ? UM.Theme.getSize("action_button_icon").height : 0
width: visible ? height : 0 width: visible ? height : 0
sourceSize.width: width sourceSize.width: width
sourceSize.height: height sourceSize.height: height
@ -70,9 +71,11 @@ Button
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
visible: text != "" visible: text != ""
renderType: Text.NativeRendering renderType: Text.NativeRendering
height: parent.height
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: fixedWidthMode ? button.width - button.leftPadding - button.rightPadding : undefined width: fixedWidthMode ? button.width - button.leftPadding - button.rightPadding : undefined
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -81,7 +84,7 @@ Button
{ {
id: buttonIconRight id: buttonIconRight
source: buttonIconLeft.source source: buttonIconLeft.source
height: UM.Theme.getSize("action_button_icon").height height: visible ? UM.Theme.getSize("action_button_icon").height : 0
width: visible ? height : 0 width: visible ? height : 0
sourceSize.width: width sourceSize.width: width
sourceSize.height: height sourceSize.height: height

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.7
@ -12,45 +12,95 @@ import Cura 1.0 as Cura
// This element hold all the elements needed for the user to trigger the slicing process, and later // This element hold all the elements needed for the user to trigger the slicing process, and later
// to get information about the printing times, material consumption and the output process (such as // to get information about the printing times, material consumption and the output process (such as
// saving to a file, printing over network, ... // saving to a file, printing over network, ...
Rectangle Item
{ {
id: actionPanelWidget id: base
width: childrenRect.width
height: childrenRect.height
visible: CuraApplication.platformActivity
width: UM.Theme.getSize("action_panel_widget").width property bool hasPreviewButton: true
height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
color: UM.Theme.getColor("main_background") Rectangle
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
radius: UM.Theme.getSize("default_radius").width
z: 10
property bool outputAvailable: UM.Backend.state == UM.Backend.Done || UM.Backend.state == UM.Backend.Disabled
Loader
{ {
id: loader id: actionPanelWidget
anchors
width: UM.Theme.getSize("action_panel_widget").width
height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
anchors. right: parent.right
color: UM.Theme.getColor("main_background")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
radius: UM.Theme.getSize("default_radius").width
z: 10
property bool outputAvailable: UM.Backend.state == UM.Backend.Done || UM.Backend.state == UM.Backend.Disabled
Loader
{ {
top: parent.top id: loader
topMargin: UM.Theme.getSize("thick_margin").height anchors
left: parent.left {
leftMargin: UM.Theme.getSize("thick_margin").width top: parent.top
right: parent.right topMargin: UM.Theme.getSize("thick_margin").height
rightMargin: UM.Theme.getSize("thick_margin").width left: parent.left
leftMargin: UM.Theme.getSize("thick_margin").width
right: parent.right
rightMargin: UM.Theme.getSize("thick_margin").width
}
sourceComponent: actionPanelWidget.outputAvailable ? outputProcessWidget : sliceProcessWidget
onLoaded:
{
if(actionPanelWidget.outputAvailable)
{
loader.item.hasPreviewButton = base.hasPreviewButton;
}
}
}
Component
{
id: sliceProcessWidget
SliceProcessWidget { }
}
Component
{
id: outputProcessWidget
OutputProcessWidget { }
} }
sourceComponent: outputAvailable ? outputProcessWidget : sliceProcessWidget
} }
Component Item
{ {
id: sliceProcessWidget id: additionalComponents
SliceProcessWidget { } width: childrenRect.width
anchors.right: actionPanelWidget.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: actionPanelWidget.bottom
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height * 2
visible: actionPanelWidget.visible
Row
{
id: additionalComponentsRow
anchors.verticalCenter: parent.verticalCenter
spacing: UM.Theme.getSize("default_margin").width
}
} }
Component Component.onCompleted: base.addAdditionalComponents()
Connections
{ {
id: outputProcessWidget target: CuraApplication
OutputProcessWidget { } onAdditionalComponentsChanged: base.addAdditionalComponents()
}
function addAdditionalComponents()
{
for (var component in CuraApplication.additionalComponents["saveButton"])
{
CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow
}
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.7
@ -19,6 +19,7 @@ Column
spacing: UM.Theme.getSize("thin_margin").height spacing: UM.Theme.getSize("thin_margin").height
property bool preSlicedData: PrintInformation.preSliced property bool preSlicedData: PrintInformation.preSliced
property alias hasPreviewButton: previewStageShortcut.visible
UM.I18nCatalog UM.I18nCatalog
{ {
@ -120,7 +121,6 @@ Column
toolTipContentAlignment: Cura.ToolTip.ContentAlignment.AlignLeft toolTipContentAlignment: Cura.ToolTip.ContentAlignment.AlignLeft
onClicked: UM.Controller.setActiveStage("PreviewStage") onClicked: UM.Controller.setActiveStage("PreviewStage")
visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage"
} }
Cura.OutputDevicesActionButton Cura.OutputDevicesActionButton

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.7
@ -36,30 +36,63 @@ Column
Label Label
{ {
property var printDuration: PrintInformation.currentPrintTime id: byLineType
text: property var printDuration: PrintInformation.currentPrintTime
property var columnWidthMultipliers: [ 0.4, 0.3, 0.3 ]
property var columnHorizontalAligns: [ TextInput.AlignLeft, TextInput.AlignHCenter, TextInput.AlignHCenter ]
function getMaterialTable()
{ {
var result = []
// All the time information for the different features is achieved // All the time information for the different features is achieved
var printTime = PrintInformation.getFeaturePrintTimes() var printTime = PrintInformation.getFeaturePrintTimes()
var totalSeconds = parseInt(printDuration.getDisplayString(UM.DurationFormat.Seconds)) var totalSeconds = parseInt(printDuration.getDisplayString(UM.DurationFormat.Seconds))
// A message is created and displayed when the user hover the time label // A message is created and displayed when the user hover the time label
var text = "<table width=\"100%\">"
for(var feature in printTime) for(var feature in printTime)
{ {
if(!printTime[feature].isTotalDurationZero) if(!printTime[feature].isTotalDurationZero)
{ {
text += "<tr><td>" + feature + ":</td>" + var row = []
"<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) + row.push(feature + ": ")
"<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1%</td>".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds)) + row.push("%1".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)))
"</tr>" row.push("%1%".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds)))
result.push(row)
} }
} }
text += "</table>"
return text return result
} }
Column
{
Repeater
{
model: byLineType.getMaterialTable()
Row
{
Repeater
{
model: modelData
Label
{
width: Math.round(byLineType.width * byLineType.columnWidthMultipliers[index])
height: contentHeight
horizontalAlignment: byLineType.columnHorizontalAligns[index]
font: UM.Theme.getFont("default")
wrapMode: Text.WrapAnywhere
text: modelData
renderType: Text.NativeRendering
}
}
}
}
}
width: parent.width - 2 * UM.Theme.getSize("default_margin").width width: parent.width - 2 * UM.Theme.getSize("default_margin").width
height: childrenRect.height
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
renderType: Text.NativeRendering renderType: Text.NativeRendering
@ -85,31 +118,19 @@ Column
Label Label
{ {
id: byMaterialType
property var printMaterialLengths: PrintInformation.materialLengths property var printMaterialLengths: PrintInformation.materialLengths
property var printMaterialWeights: PrintInformation.materialWeights property var printMaterialWeights: PrintInformation.materialWeights
property var printMaterialCosts: PrintInformation.materialCosts property var printMaterialCosts: PrintInformation.materialCosts
property var printMaterialNames: PrintInformation.materialNames property var printMaterialNames: PrintInformation.materialNames
property var columnWidthMultipliers: [ 0.4, 0.2, 0.2, 0.2 ]
property var columnHorizontalAligns: [ TextInput.AlignLeft, TextInput.AlignHCenter, TextInput.AlignHCenter, TextInput.AlignHCenter ]
function formatRow(items) function getMaterialTable()
{ {
var rowHTML = "<tr>" var result = []
for(var item = 0; item < items.length; item++)
{
if (item == 0)
{
rowHTML += "<td valign=\"bottom\">%1</td>".arg(items[item])
}
else
{
rowHTML += "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(items[item])
}
}
rowHTML += "</tr>"
return rowHTML
}
text:
{
var lengths = [] var lengths = []
var weights = [] var weights = []
var costs = [] var costs = []
@ -135,21 +156,46 @@ Column
costs = ["0.00"] costs = ["0.00"]
} }
var text = "<table width=\"100%\">"
for(var index = 0; index < lengths.length; index++) for(var index = 0; index < lengths.length; index++)
{ {
text += formatRow([ var row = []
"%1:".arg(names[index]), row.push("%1".arg(names[index]))
catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]), row.push(catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]))
catalog.i18nc("@label g for grams", "%1g").arg(weights[index]), row.push(catalog.i18nc("@label g for grams", "%1g").arg(weights[index]))
"%1&nbsp;%2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]), row.push("%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]))
]) result.push(row)
} }
text += "</table>"
return text return result
} }
Column
{
Repeater
{
model: byMaterialType.getMaterialTable()
Row
{
Repeater
{
model: modelData
Label
{
width: Math.round(byMaterialType.width * byMaterialType.columnWidthMultipliers[index])
height: contentHeight
horizontalAlignment: byLineType.columnHorizontalAligns[index]
font: UM.Theme.getFont("default")
wrapMode: Text.WrapAnywhere
text: modelData
renderType: Text.NativeRendering
}
}
}
}
}
width: parent.width - 2 * UM.Theme.getSize("default_margin").width width: parent.width - 2 * UM.Theme.getSize("default_margin").width
height: childrenRect.height
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
renderType: Text.NativeRendering renderType: Text.NativeRendering

View File

@ -246,63 +246,6 @@ UM.MainWindow
} }
} }
Cura.ActionPanelWidget
{
id: actionPanelWidget
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: UM.Theme.getSize("thick_margin").width
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height
/*
Show this panel only if there is something on the build plate, and there is NOT an opaque item in front of the build plate.
This cannot be solved by Z indexing! If you want to try solving this, please increase this counter when you're done:
Number of people having tried to fix this by z-indexing: 2
The problem arises from the following render order requirements:
- The stage menu must be rendered above the stage main.
- The stage main must be rendered above the action panel (because the monitor page must be rendered above the action panel).
- The action panel must be rendered above the expandable components drop-down.
However since the expandable components drop-downs are child elements of the stage menu,
they can't be rendered lower than elements that are lower than the stage menu.
Therefore we opted to forego the second requirement and hide the action panel instead when something obscures it (except the expandable components).
We assume that QQuickRectangles are always opaque and any other item is not.
*/
visible: CuraApplication.platformActivity && (main.item == null || !qmlTypeOf(main.item, "QQuickRectangle"))
}
Item
{
id: additionalComponents
width: childrenRect.width
anchors.right: actionPanelWidget.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.bottom: actionPanelWidget.bottom
anchors.bottomMargin: UM.Theme.getSize("thick_margin").height * 2
visible: actionPanelWidget.visible
Row
{
id: additionalComponentsRow
anchors.verticalCenter: parent.verticalCenter
spacing: UM.Theme.getSize("default_margin").width
}
}
Component.onCompleted: contentItem.addAdditionalComponents()
Connections
{
target: CuraApplication
onAdditionalComponentsChanged: contentItem.addAdditionalComponents("saveButton")
}
function addAdditionalComponents()
{
for (var component in CuraApplication.additionalComponents["saveButton"])
{
CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow
}
}
Loader Loader
{ {
// A stage can control this area. If nothing is set, it will therefore show the 3D view. // A stage can control this area. If nothing is set, it will therefore show the 3D view.
@ -373,6 +316,24 @@ UM.MainWindow
bottom: parent.bottom bottom: parent.bottom
bottomMargin: UM.Theme.getSize("default_margin").height bottomMargin: UM.Theme.getSize("default_margin").height
} }
primaryButton: Component
{
Cura.PrimaryButton
{
text: model.name
height: UM.Theme.getSize("message_action_button").height
}
}
secondaryButton: Component
{
Cura.SecondaryButton
{
text: model.name
height: UM.Theme.getSize("message_action_button").height
}
}
} }
} }

View File

@ -35,9 +35,9 @@ UM.Dialog
{ {
id: logo id: logo
width: (base.minimumWidth * 0.85) | 0 width: (base.minimumWidth * 0.85) | 0
height: (width * (UM.Theme.getSize("logo").height / UM.Theme.getSize("logo").width)) | 0 source: UM.Theme.getImage("logo")
sourceSize.width: width
source: UM.Theme.getImage("logo_about") sourceSize.height: height
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: ((base.minimumWidth - width) / 2) | 0 anchors.topMargin: ((base.minimumWidth - width) / 2) | 0

View File

@ -29,7 +29,7 @@ Item
source: UM.Theme.getImage("logo") source: UM.Theme.getImage("logo")
width: UM.Theme.getSize("logo").width width: UM.Theme.getSize("logo").width
height: UM.Theme.getSize("logo").height height: UM.Theme.getSize("logo").height
fillMode: Image.PreserveAspectFit
sourceSize.width: width sourceSize.width: width
sourceSize.height: height sourceSize.height: height
} }
@ -122,6 +122,7 @@ Item
id: accountWidget id: accountWidget
anchors anchors
{ {
verticalCenter: parent.verticalCenter
right: parent.right right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width rightMargin: UM.Theme.getSize("default_margin").width
} }

View File

@ -218,7 +218,8 @@ Button
{ {
if(isValidMaterial) if(isValidMaterial)
{ {
Cura.MachineManager.applyRemoteConfiguration(configuration); toggleContent()
Cura.MachineManager.applyRemoteConfiguration(configuration)
} }
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.6 import QtQuick 2.6
@ -288,6 +288,58 @@ Item
menu: Cura.NozzleMenu { extruderIndex: Cura.ExtruderManager.activeExtruderIndex } menu: Cura.NozzleMenu { extruderIndex: Cura.ExtruderManager.activeExtruderIndex }
} }
} }
Row
{
id: warnings
height: UM.Theme.getSize("print_setup_big_item").height
visible: buildplateCompatibilityError || buildplateCompatibilityWarning
property bool buildplateCompatibilityError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable
property bool buildplateCompatibilityWarning: Cura.MachineManager.variantBuildplateUsable
// This is a space holder aligning the warning messages.
Label
{
text: ""
width: selectors.textWidth
renderType: Text.NativeRendering
}
Item
{
width: selectors.controlWidth
height: parent.height
UM.RecolorImage
{
id: warningImage
anchors.left: parent.left
source: UM.Theme.getIcon("warning")
width: UM.Theme.getSize("section_icon").width
height: UM.Theme.getSize("section_icon").height
sourceSize.width: width
sourceSize.height: height
color: UM.Theme.getColor("material_compatibility_warning")
visible: !Cura.MachineManager.isCurrentSetupSupported || warnings.buildplateCompatibilityError || warnings.buildplateCompatibilityWarning
}
Label
{
id: materialCompatibilityLabel
anchors.left: warningImage.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
verticalAlignment: Text.AlignVCenter
width: selectors.controlWidth - warningImage.width - UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@label", "Use glue for better adhesion with this material combination.")
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
visible: CuraSDKVersion == "dev" ? false : warnings.buildplateCompatibilityError || warnings.buildplateCompatibilityWarning
wrapMode: Text.WordWrap
renderType: Text.NativeRendering
}
}
}
} }
} }
} }

View File

@ -14,9 +14,9 @@ Instantiator
{ {
property string connectGroupName: property string connectGroupName:
{ {
if("connect_group_name" in model.metadata) if("group_name" in model.metadata)
{ {
return model.metadata["connect_group_name"] return model.metadata["group_name"]
} }
return "" return ""
} }

View File

@ -56,7 +56,7 @@ UM.ManagementPage
{ {
text: catalog.i18nc("@action:button", "Rename"); text: catalog.i18nc("@action:button", "Rename");
iconName: "edit-rename"; iconName: "edit-rename";
enabled: base.currentItem != null && base.currentItem.metadata.connect_group_name == null enabled: base.currentItem != null && base.currentItem.metadata.group_name == null
onClicked: renameDialog.open(); onClicked: renameDialog.open();
} }
] ]

View File

@ -173,6 +173,7 @@ Item
id: createQualityDialog id: createQualityDialog
title: catalog.i18nc("@title:window", "Create Profile") title: catalog.i18nc("@title:window", "Create Profile")
object: "<new name>" object: "<new name>"
explanation: catalog.i18nc("@info", "Please provide a name for this profile.")
onAccepted: onAccepted:
{ {
base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created base.newQualityNameToSelect = newName; // We want to switch to the new profile once it's created

View File

@ -38,7 +38,7 @@ ListView
var result = Cura.MachineManager.activeMachineId == model.id var result = Cura.MachineManager.activeMachineId == model.id
if (Cura.MachineManager.activeMachineHasRemoteConnection) if (Cura.MachineManager.activeMachineHasRemoteConnection)
{ {
result |= Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] result |= Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["group_name"]
} }
return result return result
} }

View File

@ -4,7 +4,7 @@ name = Best Quality
definition = nwa3d_a5 definition = nwa3d_a5
[metadata] [metadata]
setting_version = 6 setting_version = 7
type = quality type = quality
quality_type = best quality_type = best
weight = 1 weight = 1

View File

@ -4,7 +4,7 @@ name = Fast Quality
definition = nwa3d_a5 definition = nwa3d_a5
[metadata] [metadata]
setting_version = 6 setting_version = 7
type = quality type = quality
quality_type = fast quality_type = fast
weight = -1 weight = -1

View File

@ -4,7 +4,7 @@ name = Normal Quality
definition = nwa3d_a5 definition = nwa3d_a5
[metadata] [metadata]
setting_version = 6 setting_version = 7
type = quality type = quality
quality_type = normal quality_type = normal
weight = 0 weight = 0

View File

@ -6,10 +6,11 @@
"colors": { "colors": {
"main_background": [39, 44, 48, 255], "main_background": [39, 44, 48, 255],
"message_background": [39, 44, 48, 255],
"wide_lining": [31, 36, 39, 255], "wide_lining": [31, 36, 39, 255],
"thick_lining": [255, 255, 255, 30], "thick_lining": [255, 255, 255, 30],
"lining": [64, 69, 72, 255], "lining": [64, 69, 72, 255],
"viewport_overlay": [0, 6, 9, 222], "viewport_overlay": [30, 36, 39, 255],
"primary": [12, 169, 227, 255], "primary": [12, 169, 227, 255],
"primary_hover": [48, 182, 231, 255], "primary_hover": [48, 182, 231, 255],
@ -215,24 +216,40 @@
"toolbox_header_button_text_inactive": [128, 128, 128, 255], "toolbox_header_button_text_inactive": [128, 128, 128, 255],
"toolbox_header_button_text_hovered": [255, 255, 255, 255], "toolbox_header_button_text_hovered": [255, 255, 255, 255],
"monitor_card_background_inactive": [43, 48, 52, 255], "monitor_printer_family_tag": [86, 86, 106, 255],
"monitor_card_background": [43, 48, 52, 255], "monitor_text_primary": [229, 229, 229, 255],
"monitor_context_menu_background": [80, 84, 87, 255], "monitor_text_disabled": [102, 102, 102, 255],
"monitor_context_menu_dots": [0, 167, 233, 255], "monitor_text_link": [103, 160, 252, 255],
"monitor_context_menu_highlight": [0, 167, 233, 255], "monitor_icon_primary": [229, 229, 229, 255],
"monitor_image_overlay": [255, 255, 255, 255], "monitor_icon_accent": [51, 53, 54, 255],
"monitor_lining_heavy": [255, 255, 255, 255],
"monitor_lining_light": [102, 102, 102, 255], "monitor_secondary_button_hover": [80, 80, 80, 255],
"monitor_pill_background": [102, 102, 102, 255], "monitor_secondary_button": [92, 92, 92, 255],
"monitor_secondary_button_text": [250, 250, 250, 255],
"monitor_secondary_button_shadow": [74, 74, 74, 255],
"monitor_card_border": [102, 102, 102, 255],
"monitor_card_background": [51, 53, 54, 255],
"monitor_card_hover": [84, 89, 95, 255],
"monitor_stage_background": [30, 36, 39, 255],
"monitor_stage_background_fade": [30, 36, 39, 102],
"monitor_progress_bar_fill": [50, 130, 255, 255],
"monitor_progress_bar_deactive": [102, 102, 102, 255],
"monitor_progress_bar_empty": [67, 67, 67, 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],
"monitor_skeleton_loading": [102, 102, 102, 255],
"monitor_placeholder_image": [102, 102, 102, 255], "monitor_placeholder_image": [102, 102, 102, 255],
"monitor_printer_icon": [255, 255, 255, 255], "monitor_image_overlay": [0, 0, 0, 255],
"monitor_progress_background_text": [102, 102, 102, 255], "monitor_shadow": [4, 10, 13, 255],
"monitor_progress_background": [80, 84, 87, 255],
"monitor_progress_fill_inactive": [216, 216, 216, 255], "monitor_carousel_dot": [119, 119, 119, 255],
"monitor_progress_fill_text": [0, 0, 0, 255], "monitor_carousel_dot_current": [216, 216, 216, 255]
"monitor_progress_fill": [216, 216, 216, 255],
"monotir_printer_icon_inactive": [154, 154, 154, 255],
"monitor_skeleton_fill": [31, 36, 39, 255],
"monitor_skeleton_fill_dark": [31, 36, 39, 255]
} }
} }

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="78px" height="58px" viewBox="0 0 78 58" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->
<title>Group-cloud</title>
<desc>Created with Sketch.</desc>
<g id="Sign-in-/Message-restyle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Sign-in-open" transform="translate(-1013.000000, -128.000000)">
<g id="Group-cloud" transform="translate(1013.000000, 128.000000)">
<g id="Icon/-group-printer/-connected">
<g id="printer-group">
<g id="Group-Copy" transform="translate(0.000000, 2.122786)" fill="#08073F" fill-rule="nonzero">
<g id="UM3">
<path d="M34.2044094,0.202170085 L0.287432013,0.202170085 C0.164246864,0.202170085 0.0410617159,0.323472136 0.0410617159,0.444774187 L0.0410617159,38.5740521 C0.0410617159,38.6953542 0.164246864,38.8166563 0.287432013,38.8166563 L2.50476467,38.8166563 C2.99750527,38.8166563 3.49024586,38.7357883 3.73661615,38.3314482 L3.98298644,38.088844 C4.31148018,37.8058059 4.76315904,37.6440697 5.21483793,37.6036358 L29.2770035,37.6036358 C29.7697441,37.6036358 30.2624847,37.6845038 30.508855,38.088844 L30.7552253,38.3314482 C31.0837189,38.6144862 31.5353978,38.7762222 31.9870768,38.8166563 L34.2044094,38.8166563 C34.3275946,38.8166563 34.4507797,38.6953542 34.4507797,38.5740521 L34.4507797,0.444774187 C34.4507797,0.323472136 34.3275946,0.202170085 34.2044094,0.202170085 Z M30.6731017,29.4763984 C30.6731017,30.6085509 29.7286825,31.5385333 28.5789543,31.5385333 L5.83076366,31.5385333 C4.68103562,31.5385333 3.73661615,30.6085509 3.73661615,29.4763984 L3.73661615,4.44774187 C3.73661615,4.0434017 4.06510989,3.67949555 4.51678875,3.67949555 L29.9339908,3.67949555 C30.3446081,3.67949555 30.7141636,4.00296768 30.7141636,4.44774187 L30.7141636,29.4763984 L30.6731017,29.4763984 Z" id="Shape"></path>
</g>
</g>
<g id="Group-Copy-4" transform="translate(43.114802, 2.122786)" fill="#08073F" fill-rule="nonzero">
<g id="UM3">
<path d="M34.2044094,0.202170085 L0.287432013,0.202170085 C0.164246864,0.202170085 0.0410617159,0.323472136 0.0410617159,0.444774187 L0.0410617159,38.5740521 C0.0410617159,38.6953542 0.164246864,38.8166563 0.287432013,38.8166563 L2.50476467,38.8166563 C2.99750527,38.8166563 3.49024586,38.7357883 3.73661615,38.3314482 L3.98298644,38.088844 C4.31148018,37.8058059 4.76315904,37.6440697 5.21483793,37.6036358 L29.2770035,37.6036358 C29.7697441,37.6036358 30.2624847,37.6845038 30.508855,38.088844 L30.7552253,38.3314482 C31.0837189,38.6144862 31.5353978,38.7762222 31.9870768,38.8166563 L34.2044094,38.8166563 C34.3275946,38.8166563 34.4507797,38.6953542 34.4507797,38.5740521 L34.4507797,0.444774187 C34.4507797,0.323472136 34.3275946,0.202170085 34.2044094,0.202170085 Z M30.6731017,29.4763984 C30.6731017,30.6085509 29.7286825,31.5385333 28.5789543,31.5385333 L5.83076366,31.5385333 C4.68103562,31.5385333 3.73661615,30.6085509 3.73661615,29.4763984 L3.73661615,4.44774187 C3.73661615,4.0434017 4.06510989,3.67949555 4.51678875,3.67949555 L29.9339908,3.67949555 C30.3446081,3.67949555 30.7141636,4.00296768 30.7141636,4.44774187 L30.7141636,29.4763984 L30.6731017,29.4763984 Z" id="Shape"></path>
</g>
</g>
<g id="Group-Copy-2" transform="translate(19.401661, 0.000000)">
<rect id="Rectangle" fill="#FFFFFF" x="4.31148018" y="0" width="30.1803611" height="36.0873602"></rect>
<g id="UM3" fill="#08073F" fill-rule="nonzero">
<path d="M38.4799606,0.227441345 L0.323361012,0.227441345 C0.184777722,0.227441345 0.0461944303,0.363906153 0.0461944303,0.50037096 L0.0461944303,43.3958088 C0.0461944303,43.5322734 0.184777722,43.6687383 0.323361012,43.6687383 L2.81786025,43.6687383 C3.37219342,43.6687383 3.92652659,43.5777618 4.20369316,43.122879 L4.48085976,42.8499495 C4.8504152,42.5315316 5.35855393,42.3495785 5.86669267,42.3040902 L32.936629,42.3040902 C33.4909621,42.3040902 34.0452952,42.3950669 34.3224619,42.8499495 L34.5996285,43.122879 C34.9691838,43.4412969 35.4773225,43.62325 35.9854612,43.6687383 L38.4799606,43.6687383 C38.6185438,43.6687383 38.7571272,43.5322734 38.7571272,43.3958088 L38.7571272,0.50037096 C38.7571272,0.363906153 38.6185438,0.227441345 38.4799606,0.227441345 Z M34.5072395,33.1609482 C34.5072395,34.4346197 33.4447677,35.4808499 32.1513237,35.4808499 L6.55960911,35.4808499 C5.26616507,35.4808499 4.20369316,34.4346197 4.20369316,33.1609482 L4.20369316,5.0037096 C4.20369316,4.54882691 4.57324863,4.13943248 5.08138736,4.13943248 L33.6757398,4.13943248 C34.1376842,4.13943248 34.5534339,4.50333865 34.5534339,5.0037096 L34.5534339,33.1609482 L34.5072395,33.1609482 Z" id="Shape"></path>
</g>
</g>
</g>
</g>
<g id="Group" transform="translate(40.578299, 25.035294)">
<ellipse id="Oval-Copy" stroke="#FFFFFF" stroke-width="3.5636363" fill="#3282FF" cx="15.6684507" cy="15.5040369" rx="15.5251417" ry="15.3630911"></ellipse>
<path d="M22.3562041,13.3374471 C22.1651254,11.6632641 20.7320354,10.3830065 19.0123274,10.3830065 C18.5346308,10.3830065 18.1524734,10.4814879 17.7703161,10.6784506 C16.9104621,9.29971165 15.3818327,8.41337947 13.7576641,8.41337947 C11.0825627,8.41337947 8.98069738,10.5799693 8.98069738,13.3374471 C8.98069738,13.3374471 8.98069738,13.3374471 8.98069738,13.4359285 C7.3565287,13.6328912 6.11451736,15.1101115 6.11451736,16.7842945 C6.11451736,18.6554402 7.64314671,20.2311419 9.45839405,20.2311419 C10.8914841,20.2311419 20.1587994,20.2311419 21.8785074,20.2311419 C23.6937548,20.2311419 25.2223841,18.6554402 25.2223841,16.7842945 C25.2223841,15.0116302 23.9803728,13.6328912 22.3562041,13.3374471 Z" id="Path" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="500"
height="500"
viewBox="0 0 132.29167 132.29167"
version="1.1"
id="svg8"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="avatar_no_user.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="264.32988"
inkscape:cy="275.53798"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1137"
inkscape:window-x="2872"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-164.70834)">
<g
id="g819"
transform="matrix(2.4332992,0,0,2.4332992,27.213046,191.79972)"
style="fill:#afafaf;fill-opacity:1">
<path
id="path815"
d="m 16,15.7 c 3.6,0 6.4,-3.5 6.4,-7.8 C 22.4,3.6 21.5,0 16,0 10.5,0 9.6,3.5 9.6,7.8 c 0,4.4 2.8,7.9 6.4,7.9 z"
inkscape:connector-curvature="0"
style="fill:#afafaf;fill-opacity:1" />
<path
id="path817"
d="m 28.2,27.3 c -0.1,-7.5 -1.1,-9.7 -8.6,-11 -0.9,0.9 -2.2,1.4 -3.5,1.3 -1.3,0.1 -2.6,-0.4 -3.5,-1.3 C 5,17.6 4,19.7 3.8,27 c 0,0.2 0,0.4 0,0.6 v 0.8 c 0,0 1.8,3.7 12.2,3.7 10.4,0 12.2,-3.6 12.2,-3.6 v -0.6 c 0,-0.3 -0.1,-0.4 0,-0.6 z"
inkscape:connector-curvature="0"
style="fill:#afafaf;fill-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
@ -9,164 +7,31 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="110mm" width="82px"
height="33mm" height="18px"
viewBox="0 0 110 33" viewBox="0 0 82 18"
version="1.1" version="1.1"
id="svg8" id="svg12"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)" sodipodi:docname="logo2.svg"
sodipodi:docname="logo.svg"> inkscape:version="0.92.3 (2405546, 2018-03-11)">
<defs <polygon
id="defs2" /> fill="#20A6DB"
<sodipodi:namedview points="82 10.3797468 77.8757345 10.3797468 75.7721519 12.4764557 75.7721519 16.6075949 79.9067798 16.6075949 82 14.5108861"
id="base" id="polygon2" />
pagecolor="#ffffff" <path
bordercolor="#666666" fill="white"
borderopacity="1.0" d="M0,9.32538529 C0,14.168804 3.22511,17.6455696 8.53908129,17.6455696 L16.6075949,17.6455696 L16.6075949,13.294146 L8.53908129,13.294146 C5.8534025,13.2832128 4.53351762,11.4792306 4.53351762,9.32538529 C4.53351762,7.17153994 5.8534025,5.40035747 8.53908129,5.37849102 L16.6075949,5.37849102 L16.6075949,1.03800064 L8.53908129,1.03800064 C3.21363275,1.02706742 0,4.47103333 0,9.32538529 Z"
inkscape:pageopacity="0.0" id="path4"/>
inkscape:pageshadow="2" <path
inkscape:zoom="1.979899" fill="white"
inkscape:cx="97.165681" d="M33.004725,9.78605176 C33.004725,12.2613239 31.20074,13.5835846 29.0468913,13.5835846 C26.8930426,13.5835846 25.1218573,12.2613239 25.1218573,9.78605176 L25.1218573,1.03797468 L20.7594937,1.03797468 L20.7594937,9.78605176 C20.7594937,14.6837056 24.203465,17.6455696 29.0468913,17.6455696 C33.8903176,17.6455696 37.3670886,14.6731275 37.3670886,9.78605176 L37.3670886,1.03797468 L33.004725,1.03797468 L33.004725,9.78605176 L33.004725,9.78605176 Z"
inkscape:cy="69.313647" id="path6"/>
inkscape:document-units="mm" <path
inkscape:current-layer="g4570" fill="white"
showgrid="false" d="M62.1251127,1.03797468 C57.0530042,1.03797468 53.9746835,4.47968021 53.9746835,9.31992005 C53.9746835,14.1601599 57.0530042,17.6346436 62.1251127,17.6346436 L63.9217127,17.6346436 L63.9217127,13.297002 L62.1251127,13.297002 C59.5616713,13.2860759 58.3018603,11.4832778 58.3018603,9.3308461 C58.3018603,7.17841439 59.5616713,5.4083944 62.1251127,5.38654231 L66.2112822,5.38654231 L66.2112822,11.0680879 L66.2112822,13.297002 L66.2112822,17.6455696 L70.5822785,17.6455696 L70.5822785,17.3942705 L70.5822785,13.297002 L70.5822785,5.38654231 L70.5822785,1.80279813 L70.5822785,1.03797468 L62.1251127,1.03797468 Z"
inkscape:window-width="1920" id="path8"/>
inkscape:window-height="1137" <path
inkscape:window-x="2872" fill="white"
inkscape:window-y="-8" d="M 41.518987,9.13915 V 17.646 h 4.36332 V 9.13915 c 0,-2.1053391 1.273557,-3.8366328 3.86497,-3.8580068 h 3.189432 V 1.038405 h -3.189432 c -5.127454,0 -8.22829,3.3664044 -8.22829,8.100745 z"
inkscape:window-maximized="1" id="path10" />
inkscape:pagecheckerboard="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-264)">
<g
id="g4570"
transform="matrix(0.1443759,0,0,0.14575971,-5.7750359,237.12191)">
<polygon
id="polygon4506"
points="741.8,410.8 781.7,410.8 801.9,390.6 801.9,350.7 762,350.7 741.8,370.9 "
class="st0"
style="fill:#3282ff;fill-opacity:1" />
<path
id="path4508"
d="m 40,334.7 c 0,44.3 28.1,76.1 74.4,76.1 h 70.3 V 371 H 114.4 C 91,370.9 79.5,354.4 79.5,334.7 79.5,315 91,298.8 114.4,298.6 h 70.3 V 258.9 H 114.4 C 68.1,258.9 40,290.4 40,334.7 Z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4510"
d="m 336.7,338.8 c 0,22.6 -16.5,34.7 -36.2,34.7 -19.7,0 -35.9,-12.1 -35.9,-34.7 v -79.9 h -39.9 v 79.9 c 0,44.7 31.5,71.9 75.8,71.9 44.3,0 76.1,-27.1 76.1,-71.9 v -79.9 h -39.9 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4512"
d="m 624.1,258.9 c -46.3,0 -74.4,31.5 -74.4,75.8 0,44.3 28.1,76.1 74.4,76.1 h 16.4 V 371 h -16.4 c -23.4,-0.1 -34.9,-16.6 -34.9,-36.3 0,-19.7 11.5,-35.9 34.9,-36.1 h 37.3 v 52 20.4 39.8 h 39.9 v -2.3 -37.5 -72.4 -32.8 -7 h -77.2 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4514"
d="m 416.6,333 v 77.8 H 456 V 333 c 0,-19.3 11.5,-35.1 34.9,-35.3 h 28.8 V 258.8 H 491 c -46.3,0.1 -74.4,30.9 -74.4,74.2 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<g
id="g4542">
<path
id="path4518"
d="m 456.3,198.8 c -3.1,0 -5.3,1.8 -5.3,5.3 v 29.4 c 0,3.5 2.1,5.3 5.3,5.3 3.2,0 5.3,-1.8 5.3,-5.3 v -29.4 c -0.1,-3.5 -2.2,-5.3 -5.3,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4520"
d="m 456.3,184.4 c -2.9,0 -5.3,2.4 -5.3,5.4 0,0 0,0.1 0,0.1 0,3 2.5,5.3 5.5,5.3 3,0 5.3,-2.5 5.3,-5.5 -0.1,-3 -2.6,-5.3 -5.5,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4522"
d="m 408.8,184.6 v 0 l -9.4,-0.1 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 h 3.6 v 43 c 0,3.5 2.1,5.3 5.3,5.3 3.1,0 5.3,-1.8 5.3,-5.3 v -43.6 c -0.2,-3.4 -2,-5.1 -4.8,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4524"
d="m 521.3,204.9 c -1.1,-2.9 -3.8,-4.8 -6.8,-4.7 -0.4,0 -0.7,0.1 -1.1,0.1 -2.6,0.3 -4.8,2 -5.7,4.5 l -6.4,15.2 -6.4,-15.3 c -1.1,-2.8 -3.8,-4.6 -6.8,-4.6 -0.2,0 -0.3,0 -0.5,0 h -8.9 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 h 2.2 l -9.2,25.8 c -1,2.7 0.4,5.7 3.1,6.7 0.6,0.2 1.1,0.3 1.7,0.3 2.2,0 4.1,-1.4 4.9,-3.5 l 6.9,-19.2 7.9,18.8 c 0.5,1.7 1.8,3 3.5,3.5 0,0 0.1,0 0.1,0 0.2,0.1 0.4,0.1 0.6,0.1 0.3,0 0.5,0.1 0.8,0.1 0,0 0,0 0.1,0 0,0 0,0 0,0 v 0 0.1 c 2.1,0 4,-1.3 4.8,-3.2 l 8.1,-19.5 6.9,19.3 c 0.7,2.1 2.7,3.4 4.9,3.5 h 0.1 c 0.6,0 1.2,-0.1 1.7,-0.3 0,0 0,0 0,0 2.7,-1 4.1,-3.9 3.1,-6.6 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4526"
d="m 476.5,238.8 c 0,0 0,0 0,0 0,0 0,0 0,0 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4528"
d="m 608.9,215.4 7.8,-8.1 c 1.1,-0.8 1.6,-2.1 1.6,-3.5 -0.2,-2.6 -2.3,-4.7 -5,-4.8 -1.6,0.1 -3,0.8 -4,2 l -9.1,10.2 c -1.1,1.3 -1.7,2.9 -1.7,4.6 v 0 c 0,3.2 2.8,6.3 2.8,6.3 l 10,14.1 c 1,1.6 2.8,2.5 4.7,2.5 2.8,-0.1 5,-2.3 5,-5.1 0,-1.2 -0.4,-2.4 -1.1,-3.4 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4530"
d="m 590.9,184.6 v 0 l -9.4,-0.1 c -1.6,0 -3,1.3 -3,3 0,1.7 1.3,3 3,3 h 3.6 v 42.9 c 0,3.5 2.1,5.3 5.3,5.3 3.2,0 5.3,-1.8 5.3,-5.3 v -8 -35.5 c -0.1,-3.4 -1.9,-5.1 -4.8,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4532"
d="m 440.7,200.2 h -3.3 v -6.7 c 0,-3.5 -2.1,-5.3 -5.3,-5.3 -3.1,0 -5.3,1.8 -5.3,5.3 v 6.7 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 v 27.4 c 0,3.5 2.2,5.3 5.3,5.3 3.1,0 5.3,-1.8 5.3,-5.3 V 228 206.2 h 3.3 c 1.6,0 3,-1.3 3,-3 0,-1.7 -1.3,-3 -3,-3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4534"
d="m 573.4,227.7 v -18.6 c 0,-7.6 -7.7,-11.2 -21.5,-10.1 -2.3,0.2 -9.2,1.5 -9.2,1.5 -2.1,0.5 -4.2,1.6 -4.2,4.2 -0.1,2 1.4,3.7 3.4,3.8 0,0 0,0 0,0 0.3,0 0.6,0 0.8,0 0,0 7.4,-1.4 10,-1.6 1.3,-0.1 2.7,-0.1 4,-0.1 3.5,0.1 6.2,0.5 6.2,3.6 v 13.8 c 0,3.9 -3.5,7.6 -9.3,7.6 -3.6,0 -5.8,-1.9 -5.8,-4.3 0,-3.2 2.4,-4.5 6.8,-5.2 1.6,-0.3 2.6,-1.8 2.3,-3.4 0,0 0,0 0,0 0,-0.1 -0.1,-0.3 -0.1,-0.4 -0.8,-3.1 -4.7,-2.7 -4.7,-2.7 -8.1,0.9 -14.7,3.4 -14.7,12.1 0,6.6 5.9,10.7 11.9,10.7 5.5,0 10.3,-1.6 14.4,-6.1 0.2,3.2 1.7,6.1 6.2,6.1 2.5,0 4.8,-1.7 4.8,-4 -0.2,-1.4 -1.3,-2.5 -1.3,-6.9 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4536"
d="m 387.8,213 -0.1,0.1 v -22.7 c -0.2,-3 -2.6,-5.4 -5.5,-5.5 -3.3,-0.2 -6.1,2.3 -6.3,5.5 v 28.5 c 0,7 -4,10.2 -10.7,10.2 -6.8,0 -10.7,-3.2 -10.7,-10.2 v -28.5 c 0,-0.2 0,-0.5 0,-0.7 0,0 0,0 0,0 -0.2,-3.1 -2.8,-5.4 -5.9,-5.2 v 0 0 h -0.7 -8.7 c -1.6,0 -3,1.3 -3,3 0,1.7 1.3,3 3,3 h 3.5 c 0,0 0,0 0,0 l 0.1,27.5 c 0,14.3 8.8,20.7 22.5,20.7 5.3,0 9.9,-1 13.5,-3 0.9,1.7 2.5,2.9 5.4,2.9 2.5,0 4.8,-1.7 4.8,-4 0,-1.7 -1.1,-2.7 -1.1,-7.1 V 213 Z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4538"
d="m 645.5,199 c -12.5,0 -19.9,8.2 -19.9,20.5 0,9.2 5.4,19.1 20.3,19.1 2.9,0 12.5,-2.2 12.5,-2.2 2.5,-0.5 4.3,-1.7 3.7,-5 -0.5,-2.3 -2.3,-3.3 -5,-2.9 0,0 -8.3,1.6 -11.2,1.8 -6.1,0.5 -9.7,-4 -9.7,-9.6 0,0 -1.7,-14.4 9.6,-14.4 4.6,0 8.2,3.7 8.9,8.4 h -11.1 c -1.6,0 -3,1.3 -3,3 0,1.7 1.3,3 3,3 v 0 0 H 660 c 3.5,0 4.6,-0.9 4.6,-4.5 -0.1,-8.6 -7,-17.2 -19.1,-17.2 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
id="path4540"
d="m 696.9,198.9 c -0.3,0 -0.6,0 -0.9,0 h -5.5 c -2.9,0 -4.9,1.5 -5.2,4.4 -0.3,-2.9 -2.3,-4.3 -5.2,-4.3 h -9.4 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 h 4.2 v 28.6 c 0,3.5 2.1,5.3 5.3,5.3 3.1,0 5.3,-1.8 5.3,-5.3 v -21.1 c 0,-1.6 1.3,-3 3,-3 h 7.7 c 3.5,0 5.3,-2.1 5.3,-5.3 0,-2.8 -1.9,-5.1 -4.6,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
</g>
</g>
</g>
<style
id="style4504"
type="text/css">
.st0{fill:#333333;}
.st1{fill:#FFFFFF;}
</style>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,172 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="110mm"
height="33mm"
viewBox="0 0 110 33"
version="1.1"
id="svg8"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="logo.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="97.165681"
inkscape:cy="69.313647"
inkscape:document-units="mm"
inkscape:current-layer="g4570"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1137"
inkscape:window-x="2872"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-264)">
<g
id="g4570"
transform="matrix(0.1443759,0,0,0.14575971,-5.7750359,237.12191)">
<polygon
id="polygon4506"
points="741.8,410.8 781.7,410.8 801.9,390.6 801.9,350.7 762,350.7 741.8,370.9 "
class="st0"
style="fill:#3282ff;fill-opacity:1" />
<path
id="path4508"
d="m 40,334.7 c 0,44.3 28.1,76.1 74.4,76.1 h 70.3 V 371 H 114.4 C 91,370.9 79.5,354.4 79.5,334.7 79.5,315 91,298.8 114.4,298.6 h 70.3 V 258.9 H 114.4 C 68.1,258.9 40,290.4 40,334.7 Z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4510"
d="m 336.7,338.8 c 0,22.6 -16.5,34.7 -36.2,34.7 -19.7,0 -35.9,-12.1 -35.9,-34.7 v -79.9 h -39.9 v 79.9 c 0,44.7 31.5,71.9 75.8,71.9 44.3,0 76.1,-27.1 76.1,-71.9 v -79.9 h -39.9 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4512"
d="m 624.1,258.9 c -46.3,0 -74.4,31.5 -74.4,75.8 0,44.3 28.1,76.1 74.4,76.1 h 16.4 V 371 h -16.4 c -23.4,-0.1 -34.9,-16.6 -34.9,-36.3 0,-19.7 11.5,-35.9 34.9,-36.1 h 37.3 v 52 20.4 39.8 h 39.9 v -2.3 -37.5 -72.4 -32.8 -7 h -77.2 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4514"
d="m 416.6,333 v 77.8 H 456 V 333 c 0,-19.3 11.5,-35.1 34.9,-35.3 h 28.8 V 258.8 H 491 c -46.3,0.1 -74.4,30.9 -74.4,74.2 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<g
id="g4542">
<path
id="path4518"
d="m 456.3,198.8 c -3.1,0 -5.3,1.8 -5.3,5.3 v 29.4 c 0,3.5 2.1,5.3 5.3,5.3 3.2,0 5.3,-1.8 5.3,-5.3 v -29.4 c -0.1,-3.5 -2.2,-5.3 -5.3,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4520"
d="m 456.3,184.4 c -2.9,0 -5.3,2.4 -5.3,5.4 0,0 0,0.1 0,0.1 0,3 2.5,5.3 5.5,5.3 3,0 5.3,-2.5 5.3,-5.5 -0.1,-3 -2.6,-5.3 -5.5,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4522"
d="m 408.8,184.6 v 0 l -9.4,-0.1 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 h 3.6 v 43 c 0,3.5 2.1,5.3 5.3,5.3 3.1,0 5.3,-1.8 5.3,-5.3 v -43.6 c -0.2,-3.4 -2,-5.1 -4.8,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4524"
d="m 521.3,204.9 c -1.1,-2.9 -3.8,-4.8 -6.8,-4.7 -0.4,0 -0.7,0.1 -1.1,0.1 -2.6,0.3 -4.8,2 -5.7,4.5 l -6.4,15.2 -6.4,-15.3 c -1.1,-2.8 -3.8,-4.6 -6.8,-4.6 -0.2,0 -0.3,0 -0.5,0 h -8.9 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 h 2.2 l -9.2,25.8 c -1,2.7 0.4,5.7 3.1,6.7 0.6,0.2 1.1,0.3 1.7,0.3 2.2,0 4.1,-1.4 4.9,-3.5 l 6.9,-19.2 7.9,18.8 c 0.5,1.7 1.8,3 3.5,3.5 0,0 0.1,0 0.1,0 0.2,0.1 0.4,0.1 0.6,0.1 0.3,0 0.5,0.1 0.8,0.1 0,0 0,0 0.1,0 0,0 0,0 0,0 v 0 0.1 c 2.1,0 4,-1.3 4.8,-3.2 l 8.1,-19.5 6.9,19.3 c 0.7,2.1 2.7,3.4 4.9,3.5 h 0.1 c 0.6,0 1.2,-0.1 1.7,-0.3 0,0 0,0 0,0 2.7,-1 4.1,-3.9 3.1,-6.6 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4526"
d="m 476.5,238.8 c 0,0 0,0 0,0 0,0 0,0 0,0 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4528"
d="m 608.9,215.4 7.8,-8.1 c 1.1,-0.8 1.6,-2.1 1.6,-3.5 -0.2,-2.6 -2.3,-4.7 -5,-4.8 -1.6,0.1 -3,0.8 -4,2 l -9.1,10.2 c -1.1,1.3 -1.7,2.9 -1.7,4.6 v 0 c 0,3.2 2.8,6.3 2.8,6.3 l 10,14.1 c 1,1.6 2.8,2.5 4.7,2.5 2.8,-0.1 5,-2.3 5,-5.1 0,-1.2 -0.4,-2.4 -1.1,-3.4 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4530"
d="m 590.9,184.6 v 0 l -9.4,-0.1 c -1.6,0 -3,1.3 -3,3 0,1.7 1.3,3 3,3 h 3.6 v 42.9 c 0,3.5 2.1,5.3 5.3,5.3 3.2,0 5.3,-1.8 5.3,-5.3 v -8 -35.5 c -0.1,-3.4 -1.9,-5.1 -4.8,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4532"
d="m 440.7,200.2 h -3.3 v -6.7 c 0,-3.5 -2.1,-5.3 -5.3,-5.3 -3.1,0 -5.3,1.8 -5.3,5.3 v 6.7 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 v 27.4 c 0,3.5 2.2,5.3 5.3,5.3 3.1,0 5.3,-1.8 5.3,-5.3 V 228 206.2 h 3.3 c 1.6,0 3,-1.3 3,-3 0,-1.7 -1.3,-3 -3,-3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4534"
d="m 573.4,227.7 v -18.6 c 0,-7.6 -7.7,-11.2 -21.5,-10.1 -2.3,0.2 -9.2,1.5 -9.2,1.5 -2.1,0.5 -4.2,1.6 -4.2,4.2 -0.1,2 1.4,3.7 3.4,3.8 0,0 0,0 0,0 0.3,0 0.6,0 0.8,0 0,0 7.4,-1.4 10,-1.6 1.3,-0.1 2.7,-0.1 4,-0.1 3.5,0.1 6.2,0.5 6.2,3.6 v 13.8 c 0,3.9 -3.5,7.6 -9.3,7.6 -3.6,0 -5.8,-1.9 -5.8,-4.3 0,-3.2 2.4,-4.5 6.8,-5.2 1.6,-0.3 2.6,-1.8 2.3,-3.4 0,0 0,0 0,0 0,-0.1 -0.1,-0.3 -0.1,-0.4 -0.8,-3.1 -4.7,-2.7 -4.7,-2.7 -8.1,0.9 -14.7,3.4 -14.7,12.1 0,6.6 5.9,10.7 11.9,10.7 5.5,0 10.3,-1.6 14.4,-6.1 0.2,3.2 1.7,6.1 6.2,6.1 2.5,0 4.8,-1.7 4.8,-4 -0.2,-1.4 -1.3,-2.5 -1.3,-6.9 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4536"
d="m 387.8,213 -0.1,0.1 v -22.7 c -0.2,-3 -2.6,-5.4 -5.5,-5.5 -3.3,-0.2 -6.1,2.3 -6.3,5.5 v 28.5 c 0,7 -4,10.2 -10.7,10.2 -6.8,0 -10.7,-3.2 -10.7,-10.2 v -28.5 c 0,-0.2 0,-0.5 0,-0.7 0,0 0,0 0,0 -0.2,-3.1 -2.8,-5.4 -5.9,-5.2 v 0 0 h -0.7 -8.7 c -1.6,0 -3,1.3 -3,3 0,1.7 1.3,3 3,3 h 3.5 c 0,0 0,0 0,0 l 0.1,27.5 c 0,14.3 8.8,20.7 22.5,20.7 5.3,0 9.9,-1 13.5,-3 0.9,1.7 2.5,2.9 5.4,2.9 2.5,0 4.8,-1.7 4.8,-4 0,-1.7 -1.1,-2.7 -1.1,-7.1 V 213 Z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4538"
d="m 645.5,199 c -12.5,0 -19.9,8.2 -19.9,20.5 0,9.2 5.4,19.1 20.3,19.1 2.9,0 12.5,-2.2 12.5,-2.2 2.5,-0.5 4.3,-1.7 3.7,-5 -0.5,-2.3 -2.3,-3.3 -5,-2.9 0,0 -8.3,1.6 -11.2,1.8 -6.1,0.5 -9.7,-4 -9.7,-9.6 0,0 -1.7,-14.4 9.6,-14.4 4.6,0 8.2,3.7 8.9,8.4 h -11.1 c -1.6,0 -3,1.3 -3,3 0,1.7 1.3,3 3,3 v 0 0 H 660 c 3.5,0 4.6,-0.9 4.6,-4.5 -0.1,-8.6 -7,-17.2 -19.1,-17.2 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
<path
id="path4540"
d="m 696.9,198.9 c -0.3,0 -0.6,0 -0.9,0 h -5.5 c -2.9,0 -4.9,1.5 -5.2,4.4 -0.3,-2.9 -2.3,-4.3 -5.2,-4.3 h -9.4 c -1.6,0 -3,1.3 -3,3 0,1.6 1.3,3 3,3 h 4.2 v 28.6 c 0,3.5 2.1,5.3 5.3,5.3 3.1,0 5.3,-1.8 5.3,-5.3 v -21.1 c 0,-1.6 1.3,-3 3,-3 h 7.7 c 3.5,0 5.3,-2.1 5.3,-5.3 0,-2.8 -1.9,-5.1 -4.6,-5.3 z"
class="st1"
inkscape:connector-curvature="0"
style="fill:#000000" />
</g>
</g>
</g>
<style
id="style4504"
type="text/css">
.st0{fill:#333333;}
.st1{fill:#000000;}
</style>
</svg>

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -146,7 +146,7 @@
"wide_lining": [245, 245, 245, 255], "wide_lining": [245, 245, 245, 255],
"thick_lining": [127, 127, 127, 255], "thick_lining": [127, 127, 127, 255],
"lining": [192, 193, 194, 255], "lining": [192, 193, 194, 255],
"viewport_overlay": [0, 0, 0, 192], "viewport_overlay": [246, 246, 246, 255],
"primary": [50, 130, 255, 255], "primary": [50, 130, 255, 255],
"primary_shadow": [64, 47, 205, 255], "primary_shadow": [64, 47, 205, 255],
@ -294,7 +294,7 @@
"setting_validation_ok": [255, 255, 255, 255], "setting_validation_ok": [255, 255, 255, 255],
"setting_filter_field" : [153, 153, 153, 255], "setting_filter_field" : [153, 153, 153, 255],
"material_compatibility_warning": [0, 0, 0, 255], "material_compatibility_warning": [243, 166, 59, 255],
"progressbar_background": [245, 245, 245, 255], "progressbar_background": [245, 245, 245, 255],
"progressbar_control": [50, 130, 255, 255], "progressbar_control": [50, 130, 255, 255],
@ -320,17 +320,9 @@
"tooltip_text": [255, 255, 255, 255], "tooltip_text": [255, 255, 255, 255],
"message_background": [255, 255, 255, 255], "message_background": [255, 255, 255, 255],
"message_shadow": [0, 0, 0, 120],
"message_border": [192, 193, 194, 255], "message_border": [192, 193, 194, 255],
"message_text": [0, 0, 0, 255],
"message_close": [102, 102, 102, 255], "message_close": [102, 102, 102, 255],
"message_close_hover": [8, 7, 63, 255], "message_close_hover": [8, 7, 63, 255],
"message_button": [38, 113, 231, 255],
"message_button_hover": [81, 145, 247, 255],
"message_button_active": [38, 113, 231, 255],
"message_button_text": [255, 255, 255, 255],
"message_button_text_hover": [255, 255, 255, 255],
"message_button_text_active": [255, 255, 255, 255],
"message_progressbar_background": [245, 245, 245, 255], "message_progressbar_background": [245, 245, 245, 255],
"message_progressbar_control": [50, 130, 255, 255], "message_progressbar_control": [50, 130, 255, 255],
@ -400,27 +392,41 @@
"favorites_header_text_hover": [31, 36, 39, 255], "favorites_header_text_hover": [31, 36, 39, 255],
"favorites_row_selected": [196, 239, 255, 255], "favorites_row_selected": [196, 239, 255, 255],
"monitor_card_background_inactive": [240, 240, 240, 255], "monitor_printer_family_tag": [228, 228, 242, 255],
"monitor_text_primary": [65, 64, 84, 255],
"monitor_text_disabled": [238, 238, 238, 255],
"monitor_text_link": [50, 130, 255, 255],
"monitor_icon_primary": [10, 8, 80, 255],
"monitor_icon_accent": [255, 255, 255, 255],
"monitor_secondary_button_hover": [228, 228, 228, 255],
"monitor_secondary_button": [240, 240, 240, 255],
"monitor_secondary_button_text": [30, 102, 215, 255],
"monitor_secondary_button_shadow": [216, 216, 216, 255],
"monitor_card_border": [192, 193, 194, 255],
"monitor_card_background": [255, 255, 255, 255], "monitor_card_background": [255, 255, 255, 255],
"monitor_context_menu_background": [255, 255, 255, 255], "monitor_card_hover": [232, 242, 252, 255],
"monitor_context_menu_dots": [154, 154, 154, 255],
"monitor_context_menu_highlight": [245, 245, 245, 255], "monitor_stage_background": [246, 246, 246, 255],
"monitor_image_overlay": [0, 0, 0, 255], "monitor_stage_background_fade": [246, 246, 246, 102],
"monitor_lining_heavy": [0, 0, 0, 255],
"monitor_lining_light": [230, 230, 230, 255], "monitor_progress_bar_fill": [50, 130, 255, 255],
"monitor_pill_background": [245, 245, 245, 255], "monitor_progress_bar_deactive": [192, 193, 194, 255],
"monitor_progress_bar_empty": [245, 245, 245, 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],
"monitor_skeleton_loading": [238, 238, 238, 255],
"monitor_placeholder_image": [230, 230, 230, 255], "monitor_placeholder_image": [230, 230, 230, 255],
"monitor_printer_icon_inactive": [154, 154, 154, 255], "monitor_image_overlay": [0, 0, 0, 255],
"monitor_printer_icon": [50, 130, 255, 255], "monitor_shadow": [220, 220, 220, 255],
"monitor_progress_background_text": [0,0,0,255],
"monitor_progress_background": [245, 245, 245, 255], "monitor_carousel_dot": [216, 216, 216, 255],
"monitor_progress_fill_inactive": [154, 154, 154, 255], "monitor_carousel_dot_current": [119, 119, 119, 255]
"monitor_progress_fill_text": [255,255,255,255],
"monitor_progress_fill": [50, 130, 255, 255],
"monitor_shadow": [0, 0, 0, 63],
"monitor_skeleton_fill": [245, 245, 245, 255],
"monitor_skeleton_fill_dark": [216, 216, 216, 255],
"monitor_text_inactive": [154, 154, 154, 255]
}, },
"sizes": { "sizes": {
@ -432,7 +438,7 @@
"stage_menu": [0.0, 4.0], "stage_menu": [0.0, 4.0],
"account_button": [12, 3], "account_button": [12, 2.5],
"print_setup_widget": [38.0, 30.0], "print_setup_widget": [38.0, 30.0],
"print_setup_mode_toggle": [0.0, 2.0], "print_setup_mode_toggle": [0.0, 2.0],
@ -499,7 +505,7 @@
"button_icon": [2.5, 2.5], "button_icon": [2.5, 2.5],
"button_lining": [0, 0], "button_lining": [0, 0],
"action_button": [15.0, 3.0], "action_button": [15.0, 2.5],
"action_button_icon": [1.0, 1.0], "action_button_icon": [1.0, 1.0],
"action_button_radius": [0.15, 0.15], "action_button_radius": [0.15, 0.15],
@ -555,12 +561,8 @@
"message": [30.0, 5.0], "message": [30.0, 5.0],
"message_close": [1, 1], "message_close": [1, 1],
"message_button": [6.0, 1.8],
"message_shadow": [0, 0],
"message_margin": [0, 1.0],
"message_inner_margin": [1.5, 1.5],
"message_radius": [0.25, 0.25], "message_radius": [0.25, 0.25],
"message_button_radius": [0.15, 0.15], "message_action_button": [0, 2.0],
"infill_button_margin": [0.5, 0.5], "infill_button_margin": [0.5, 0.5],
@ -596,10 +598,14 @@
"monitor_config_override_box": [1.0, 14.0], "monitor_config_override_box": [1.0, 14.0],
"monitor_extruder_circle": [2.75, 2.75], "monitor_extruder_circle": [2.75, 2.75],
"monitor_text_line": [1.16, 1.16], "monitor_text_line": [1.5, 1.5],
"monitor_text_line_large": [2.33, 2.33],
"monitor_thick_lining": [0.16, 0.16], "monitor_thick_lining": [0.16, 0.16],
"monitor_corner_radius": [0.3, 0.3], "monitor_corner_radius": [0.3, 0.3],
"monitor_shadow_radius": [0.4, 0.4], "monitor_shadow_radius": [0.4, 0.4],
"monitor_shadow_offset": [0.15, 0.15] "monitor_shadow_offset": [0.15, 0.15],
"monitor_empty_state_offset": [5.6, 5.6],
"monitor_empty_state_size": [35.0, 25.0],
"monitor_external_link_icon": [1.16, 1.16]
} }
} }

View File

@ -0,0 +1,16 @@
from cura.Scene.GCodeListDecorator import GCodeListDecorator
def test_setAndGetList():
decorator = GCodeListDecorator()
decorator.setGCodeList(["Test"])
assert decorator.getGCodeList() == ["Test"]
def test_copyGCodeDecorator():
decorator = GCodeListDecorator()
decorator.setGCodeList(["Test"])
import copy
copied_decorator = copy.deepcopy(decorator)
assert decorator.getGCodeList() == copied_decorator.getGCodeList()

View File

@ -104,3 +104,18 @@ def test_addMachineAction(machine_action_manager):
machine_action_manager.addFirstStartAction(test_machine, "test_action") machine_action_manager.addFirstStartAction(test_machine, "test_action")
machine_action_manager.addFirstStartAction(test_machine, "test_action") machine_action_manager.addFirstStartAction(test_machine, "test_action")
assert machine_action_manager.getFirstStartActions(test_machine) == [test_action, test_action] assert machine_action_manager.getFirstStartActions(test_machine) == [test_action, test_action]
# Adding unknown action should not crash.
machine_action_manager.addFirstStartAction(test_machine, "key_that_doesnt_exists")
def test_removeMachineAction(machine_action_manager):
test_action = MachineAction(key="test_action")
test_machine = Machine("test_machine")
machine_action_manager.addMachineAction(test_action)
# Remove the machine action
machine_action_manager.removeMachineAction(test_action)
assert machine_action_manager.getMachineAction("test_action") is None
# Attempting to remove it again should not crash.
machine_action_manager.removeMachineAction(test_action)