Merge remote-tracking branch 'origin/master' into add_42_43_version_upgrader

This commit is contained in:
Lipu Fei 2019-07-25 14:56:27 +02:00
commit 9f18ceda51
37 changed files with 380 additions and 249 deletions

View file

@ -47,7 +47,7 @@ function(cura_add_test)
if (NOT ${test_exists}) if (NOT ${test_exists})
add_test( add_test(
NAME ${_NAME} NAME ${_NAME}
COMMAND ${Python3_EXECUTABLE} -m pytest --verbose --full-trace --capture=no --no-print-log --junitxml=${CMAKE_BINARY_DIR}/junit-${_NAME}.xml ${_DIRECTORY} COMMAND ${Python3_EXECUTABLE} -m pytest --junitxml=${CMAKE_BINARY_DIR}/junit-${_NAME}.xml ${_DIRECTORY}
) )
set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT LANG=C) set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT LANG=C)
set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${_PYTHONPATH}") set_tests_properties(${_NAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${_PYTHONPATH}")

View file

@ -9,7 +9,7 @@ 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.1.0" DEFAULT_CURA_SDK_VERSION = "6.2.0"
try: try:
from cura.CuraVersion import CuraAppName # type: ignore from cura.CuraVersion import CuraAppName # type: ignore
@ -45,4 +45,4 @@ except ImportError:
# Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for # Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for
# example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the # example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the
# CuraVersion.py.in template. # CuraVersion.py.in template.
CuraSDKVersion = "6.1.0" CuraSDKVersion = "6.2.0"

View file

@ -770,7 +770,7 @@ class BuildVolume(SceneNode):
self._has_errors = len(self._error_areas) > 0 self._has_errors = len(self._error_areas) > 0
self._disallowed_areas = [] # type: List[Polygon] self._disallowed_areas = []
for extruder_id in result_areas: for extruder_id in result_areas:
self._disallowed_areas.extend(result_areas[extruder_id]) self._disallowed_areas.extend(result_areas[extruder_id])
self._disallowed_areas_no_brim = [] self._disallowed_areas_no_brim = []

View file

@ -421,7 +421,7 @@ class CuraApplication(QtApplication):
# Add empty variant, material and quality containers. # Add empty variant, material and quality containers.
# Since they are empty, they should never be serialized and instead just programmatically created. # Since they are empty, they should never be serialized and instead just programmatically created.
# We need them to simplify the switching between materials. # We need them to simplify the switching between materials.
self.empty_container = cura.Settings.cura_empty_instance_containers.empty_container # type: EmptyInstanceContainer self.empty_container = cura.Settings.cura_empty_instance_containers.empty_container
self._container_registry.addContainer( self._container_registry.addContainer(
cura.Settings.cura_empty_instance_containers.empty_definition_changes_container) cura.Settings.cura_empty_instance_containers.empty_definition_changes_container)
@ -1262,7 +1262,7 @@ class CuraApplication(QtApplication):
@pyqtSlot() @pyqtSlot()
def arrangeObjectsToAllBuildPlates(self) -> None: def arrangeObjectsToAllBuildPlates(self) -> None:
nodes_to_arrange = [] nodes_to_arrange = []
for node in DepthFirstIterator(self.getController().getScene().getRoot()): # type: ignore for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if not isinstance(node, SceneNode): if not isinstance(node, SceneNode):
continue continue
@ -1289,7 +1289,7 @@ class CuraApplication(QtApplication):
def arrangeAll(self) -> None: def arrangeAll(self) -> None:
nodes_to_arrange = [] nodes_to_arrange = []
active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate
for node in DepthFirstIterator(self.getController().getScene().getRoot()): # type: ignore for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if not isinstance(node, SceneNode): if not isinstance(node, SceneNode):
continue continue
@ -1327,7 +1327,7 @@ class CuraApplication(QtApplication):
Logger.log("i", "Reloading all loaded mesh data.") Logger.log("i", "Reloading all loaded mesh data.")
nodes = [] nodes = []
has_merged_nodes = False has_merged_nodes = False
for node in DepthFirstIterator(self.getController().getScene().getRoot()): # type: ignore for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if not isinstance(node, CuraSceneNode) or not node.getMeshData(): if not isinstance(node, CuraSceneNode) or not node.getMeshData():
if node.getName() == "MergedMesh": if node.getName() == "MergedMesh":
has_merged_nodes = True has_merged_nodes = True
@ -1339,9 +1339,9 @@ class CuraApplication(QtApplication):
return return
for node in nodes: for node in nodes:
file_name = node.getMeshData().getFileName() mesh_data = node.getMeshData()
if file_name: if mesh_data and mesh_data.getFileName():
job = ReadMeshJob(file_name) job = ReadMeshJob(mesh_data.getFileName())
job._node = node # type: ignore job._node = node # type: ignore
job.finished.connect(self._reloadMeshFinished) job.finished.connect(self._reloadMeshFinished)
if has_merged_nodes: if has_merged_nodes:

View file

@ -93,7 +93,7 @@ class MaterialManager(QObject):
self._container_registry.findContainersMetadata(type = "material") if self._container_registry.findContainersMetadata(type = "material") if
metadata.get("GUID")} # type: Dict[str, Dict[str, Any]] metadata.get("GUID")} # type: Dict[str, Dict[str, Any]]
self._material_group_map = dict() # type: Dict[str, MaterialGroup] self._material_group_map = dict()
# Map #1 # Map #1
# root_material_id -> MaterialGroup # root_material_id -> MaterialGroup
@ -120,7 +120,7 @@ class MaterialManager(QObject):
# Map #1.5 # Map #1.5
# GUID -> material group list # GUID -> material group list
self._guid_material_groups_map = defaultdict(list) # type: Dict[str, List[MaterialGroup]] self._guid_material_groups_map = defaultdict(list)
for root_material_id, material_group in self._material_group_map.items(): for root_material_id, material_group in self._material_group_map.items():
guid = material_group.root_material_node.getMetaDataEntry("GUID", "") guid = material_group.root_material_node.getMetaDataEntry("GUID", "")
self._guid_material_groups_map[guid].append(material_group) self._guid_material_groups_map[guid].append(material_group)
@ -202,7 +202,7 @@ class MaterialManager(QObject):
# Map #4 # Map #4
# "machine" -> "nozzle name" -> "buildplate name" -> "root material ID" -> specific material InstanceContainer # "machine" -> "nozzle name" -> "buildplate name" -> "root material ID" -> specific material InstanceContainer
self._diameter_machine_nozzle_buildplate_material_map = dict() # type: Dict[str, Dict[str, MaterialNode]] self._diameter_machine_nozzle_buildplate_material_map = dict()
for material_metadata in material_metadatas.values(): for material_metadata in material_metadatas.values():
self.__addMaterialMetadataIntoLookupTree(material_metadata) self.__addMaterialMetadataIntoLookupTree(material_metadata)

View file

@ -3,6 +3,8 @@
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from numpy import cast
from UM.Application import Application from UM.Application import Application
from UM.Resources import Resources from UM.Resources import Resources
@ -12,6 +14,7 @@ from UM.View.RenderBatch import RenderBatch
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from cura.Scene.CuraSceneNode import CuraSceneNode
if TYPE_CHECKING: if TYPE_CHECKING:
from UM.View.GL.ShaderProgram import ShaderProgram from UM.View.GL.ShaderProgram import ShaderProgram
@ -44,9 +47,9 @@ class PreviewPass(RenderPass):
self._renderer = Application.getInstance().getRenderer() self._renderer = Application.getInstance().getRenderer()
self._shader = None #type: Optional[ShaderProgram] self._shader = None # type: Optional[ShaderProgram]
self._non_printing_shader = None #type: Optional[ShaderProgram] self._non_printing_shader = None # type: Optional[ShaderProgram]
self._support_mesh_shader = None #type: Optional[ShaderProgram] self._support_mesh_shader = None # type: Optional[ShaderProgram]
self._scene = Application.getInstance().getController().getScene() self._scene = Application.getInstance().getController().getScene()
# Set the camera to be used by this render pass # Set the camera to be used by this render pass
@ -83,8 +86,8 @@ class PreviewPass(RenderPass):
batch_support_mesh = RenderBatch(self._support_mesh_shader) batch_support_mesh = RenderBatch(self._support_mesh_shader)
# Fill up the batch with objects that can be sliced. # Fill up the batch with objects that can be sliced.
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
if hasattr(node, "_outside_buildarea") and not node._outside_buildarea: if hasattr(node, "_outside_buildarea") and not getattr(node, "_outside_buildarea"):
if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible(): if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
per_mesh_stack = node.callDecoration("getStack") per_mesh_stack = node.callDecoration("getStack")
if node.callDecoration("isNonThumbnailVisibleMesh"): if node.callDecoration("isNonThumbnailVisibleMesh"):
@ -94,7 +97,7 @@ class PreviewPass(RenderPass):
# Support mesh # Support mesh
uniforms = {} uniforms = {}
shade_factor = 0.6 shade_factor = 0.6
diffuse_color = node.getDiffuseColor() diffuse_color = cast(CuraSceneNode, node).getDiffuseColor()
diffuse_color2 = [ diffuse_color2 = [
diffuse_color[0] * shade_factor, diffuse_color[0] * shade_factor,
diffuse_color[1] * shade_factor, diffuse_color[1] * shade_factor,
@ -106,7 +109,7 @@ class PreviewPass(RenderPass):
else: else:
# Normal scene node # Normal scene node
uniforms = {} uniforms = {}
uniforms["diffuse_color"] = prettier_color(node.getDiffuseColor()) uniforms["diffuse_color"] = prettier_color(cast(CuraSceneNode, node).getDiffuseColor())
batch.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = uniforms) batch.addItem(node.getWorldTransformation(), node.getMeshData(), uniforms = uniforms)
self.bind() self.bind()

View file

@ -55,7 +55,7 @@ class GenericOutputController(PrinterOutputController):
self._preheat_hotends_timer.stop() self._preheat_hotends_timer.stop()
for extruder in self._preheat_hotends: for extruder in self._preheat_hotends:
extruder.updateIsPreheating(False) extruder.updateIsPreheating(False)
self._preheat_hotends = set() # type: Set[ExtruderOutputModel] self._preheat_hotends = set()
def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed) -> None: def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed) -> None:
self._output_device.sendCommand("G91") self._output_device.sendCommand("G91")
@ -159,7 +159,7 @@ class GenericOutputController(PrinterOutputController):
def _onPreheatHotendsTimerFinished(self) -> None: def _onPreheatHotendsTimerFinished(self) -> None:
for extruder in self._preheat_hotends: for extruder in self._preheat_hotends:
self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0)
self._preheat_hotends = set() #type: Set[ExtruderOutputModel] self._preheat_hotends = set()
# Cancel any ongoing preheating timers, without setting back the temperature to 0 # Cancel any ongoing preheating timers, without setting back the temperature to 0
# This can be used eg at the start of a print # This can be used eg at the start of a print
@ -167,7 +167,7 @@ class GenericOutputController(PrinterOutputController):
if self._preheat_hotends_timer.isActive(): if self._preheat_hotends_timer.isActive():
for extruder in self._preheat_hotends: for extruder in self._preheat_hotends:
extruder.updateIsPreheating(False) extruder.updateIsPreheating(False)
self._preheat_hotends = set() #type: Set[ExtruderOutputModel] self._preheat_hotends = set()
self._preheat_hotends_timer.stop() self._preheat_hotends_timer.stop()

View file

@ -115,7 +115,7 @@ class ExtruderManager(QObject):
selected_nodes = [] # type: List["SceneNode"] selected_nodes = [] # type: List["SceneNode"]
for node in Selection.getAllSelectedObjects(): for node in Selection.getAllSelectedObjects():
if node.callDecoration("isGroup"): if node.callDecoration("isGroup"):
for grouped_node in BreadthFirstIterator(node): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for grouped_node in BreadthFirstIterator(node):
if grouped_node.callDecoration("isGroup"): if grouped_node.callDecoration("isGroup"):
continue continue
@ -132,7 +132,7 @@ class ExtruderManager(QObject):
elif current_extruder_trains: elif current_extruder_trains:
object_extruders.add(current_extruder_trains[0].getId()) object_extruders.add(current_extruder_trains[0].getId())
self._selected_object_extruders = list(object_extruders) # type: List[Union[str, "ExtruderStack"]] self._selected_object_extruders = list(object_extruders)
return self._selected_object_extruders return self._selected_object_extruders
@ -141,7 +141,7 @@ class ExtruderManager(QObject):
# This will trigger a recalculation of the extruders used for the # This will trigger a recalculation of the extruders used for the
# selection. # selection.
def resetSelectedObjectExtruders(self) -> None: def resetSelectedObjectExtruders(self) -> None:
self._selected_object_extruders = [] # type: List[Union[str, "ExtruderStack"]] self._selected_object_extruders = []
self.selectedObjectExtrudersChanged.emit() self.selectedObjectExtrudersChanged.emit()
@pyqtSlot(result = QObject) @pyqtSlot(result = QObject)

View file

@ -949,7 +949,7 @@ class MachineManager(QObject):
# Check to see if any objects are set to print with an extruder that will no longer exist # Check to see if any objects are set to print with an extruder that will no longer exist
root_node = self._application.getController().getScene().getRoot() root_node = self._application.getController().getScene().getRoot()
for node in DepthFirstIterator(root_node): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(root_node):
if node.getMeshData(): if node.getMeshData():
extruder_nr = node.callDecoration("getActiveExtruderPosition") extruder_nr = node.callDecoration("getActiveExtruderPosition")

View file

@ -369,7 +369,7 @@ class CuraEngineBackend(QObject, Backend):
elif job.getResult() == StartJobResult.ObjectSettingError: elif job.getResult() == StartJobResult.ObjectSettingError:
errors = {} errors = {}
for node in DepthFirstIterator(self._application.getController().getScene().getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._application.getController().getScene().getRoot()):
stack = node.callDecoration("getStack") stack = node.callDecoration("getStack")
if not stack: if not stack:
continue continue
@ -438,7 +438,7 @@ class CuraEngineBackend(QObject, Backend):
if not self._application.getPreferences().getValue("general/auto_slice"): if not self._application.getPreferences().getValue("general/auto_slice"):
enable_timer = False enable_timer = False
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("isBlockSlicing"): if node.callDecoration("isBlockSlicing"):
enable_timer = False enable_timer = False
self.setState(BackendState.Disabled) self.setState(BackendState.Disabled)
@ -460,7 +460,7 @@ class CuraEngineBackend(QObject, Backend):
## Return a dict with number of objects per build plate ## Return a dict with number of objects per build plate
def _numObjectsPerBuildPlate(self) -> Dict[int, int]: def _numObjectsPerBuildPlate(self) -> Dict[int, int]:
num_objects = defaultdict(int) #type: Dict[int, int] num_objects = defaultdict(int) #type: Dict[int, int]
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
# Only count sliceable objects # Only count sliceable objects
if node.callDecoration("isSliceable"): if node.callDecoration("isSliceable"):
build_plate_number = node.callDecoration("getBuildPlateNumber") build_plate_number = node.callDecoration("getBuildPlateNumber")
@ -548,10 +548,11 @@ class CuraEngineBackend(QObject, Backend):
# Clear out any old gcode # Clear out any old gcode
self._scene.gcode_dict = {} # type: ignore self._scene.gcode_dict = {} # type: ignore
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("getLayerData"): if node.callDecoration("getLayerData"):
if not build_plate_numbers or node.callDecoration("getBuildPlateNumber") in build_plate_numbers: if not build_plate_numbers or node.callDecoration("getBuildPlateNumber") in build_plate_numbers:
node.getParent().removeChild(node) # We can asume that all nodes have a parent as we're looping through the scene (and filter out root)
cast(SceneNode, node.getParent()).removeChild(node)
def markSliceAll(self) -> None: def markSliceAll(self) -> None:
for build_plate_number in range(self._application.getMultiBuildPlateModel().maxBuildPlate + 1): for build_plate_number in range(self._application.getMultiBuildPlateModel().maxBuildPlate + 1):

View file

@ -11,6 +11,7 @@ import Arcus #For typing.
from UM.Job import Job from UM.Job import Job
from UM.Logger import Logger from UM.Logger import Logger
from UM.Scene.SceneNode import SceneNode
from UM.Settings.ContainerStack import ContainerStack #For typing. from UM.Settings.ContainerStack import ContainerStack #For typing.
from UM.Settings.SettingRelation import SettingRelation #For typing. from UM.Settings.SettingRelation import SettingRelation #For typing.
@ -150,7 +151,7 @@ class StartSliceJob(Job):
# Don't slice if there is a per object setting with an error value. # Don't slice if there is a per object setting with an error value.
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
if not isinstance(node, CuraSceneNode) or not node.isSelectable(): if not isinstance(node, CuraSceneNode) or not node.isSelectable():
continue continue
@ -160,15 +161,16 @@ class StartSliceJob(Job):
with self._scene.getSceneLock(): with self._scene.getSceneLock():
# Remove old layer data. # Remove old layer data.
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("getLayerData") and node.callDecoration("getBuildPlateNumber") == self._build_plate_number: if node.callDecoration("getLayerData") and node.callDecoration("getBuildPlateNumber") == self._build_plate_number:
node.getParent().removeChild(node) # Singe we walk through all nodes in the scene, they always have a parent.
cast(SceneNode, node.getParent()).removeChild(node)
break break
# Get the objects in their groups to print. # Get the objects in their groups to print.
object_groups = [] object_groups = []
if stack.getProperty("print_sequence", "value") == "one_at_a_time": if stack.getProperty("print_sequence", "value") == "one_at_a_time":
for node in OneAtATimeIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in OneAtATimeIterator(self._scene.getRoot()):
temp_list = [] temp_list = []
# Node can't be printed, so don't bother sending it. # Node can't be printed, so don't bother sending it.
@ -183,7 +185,8 @@ class StartSliceJob(Job):
children = node.getAllChildren() children = node.getAllChildren()
children.append(node) children.append(node)
for child_node in children: for child_node in children:
if child_node.getMeshData() and child_node.getMeshData().getVertices() is not None: mesh_data = child_node.getMeshData()
if mesh_data and mesh_data.getVertices() is not None:
temp_list.append(child_node) temp_list.append(child_node)
if temp_list: if temp_list:
@ -194,8 +197,9 @@ class StartSliceJob(Job):
else: else:
temp_list = [] temp_list = []
has_printing_mesh = False has_printing_mesh = False
for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("isSliceable") and node.getMeshData() and node.getMeshData().getVertices() is not None: mesh_data = node.getMeshData()
if node.callDecoration("isSliceable") and mesh_data and mesh_data.getVertices() is not None:
is_non_printing_mesh = bool(node.callDecoration("isNonPrintingMesh")) is_non_printing_mesh = bool(node.callDecoration("isNonPrintingMesh"))
# Find a reason not to add the node # Find a reason not to add the node
@ -210,7 +214,7 @@ class StartSliceJob(Job):
Job.yieldThread() Job.yieldThread()
#If the list doesn't have any model with suitable settings then clean the list # If the list doesn't have any model with suitable settings then clean the list
# otherwise CuraEngine will crash # otherwise CuraEngine will crash
if not has_printing_mesh: if not has_printing_mesh:
temp_list.clear() temp_list.clear()
@ -261,10 +265,14 @@ class StartSliceJob(Job):
for group in filtered_object_groups: for group in filtered_object_groups:
group_message = self._slice_message.addRepeatedMessage("object_lists") group_message = self._slice_message.addRepeatedMessage("object_lists")
if group[0].getParent() is not None and group[0].getParent().callDecoration("isGroup"): parent = group[0].getParent()
self._handlePerObjectSettings(group[0].getParent(), group_message) if parent is not None and parent.callDecoration("isGroup"):
self._handlePerObjectSettings(cast(CuraSceneNode, parent), group_message)
for object in group: for object in group:
mesh_data = object.getMeshData() mesh_data = object.getMeshData()
if mesh_data is None:
continue
rot_scale = object.getWorldTransformation().getTransposed().getData()[0:3, 0:3] rot_scale = object.getWorldTransformation().getTransposed().getData()[0:3, 0:3]
translate = object.getWorldTransformation().getData()[:3, 3] translate = object.getWorldTransformation().getData()[:3, 3]
@ -288,7 +296,7 @@ class StartSliceJob(Job):
obj.vertices = flat_verts obj.vertices = flat_verts
self._handlePerObjectSettings(object, obj) self._handlePerObjectSettings(cast(CuraSceneNode, object), obj)
Job.yieldThread() Job.yieldThread()

View file

@ -85,7 +85,7 @@ class CuraProfileReader(ProfileReader):
profile = InstanceContainer(profile_id) profile = InstanceContainer(profile_id)
profile.setMetaDataEntry("type", "quality_changes") profile.setMetaDataEntry("type", "quality_changes")
try: try:
profile.deserialize(serialized) profile.deserialize(serialized, file_name = profile_id)
except ContainerFormatError as e: except ContainerFormatError as e:
Logger.log("e", "Error in the format of a container: %s", str(e)) Logger.log("e", "Error in the format of a container: %s", str(e))
return None return None

View file

@ -1,10 +1,13 @@
# Cura PostProcessingPlugin # Cura PostProcessingPlugin
# Author: Amanda de Castilho # Author: Amanda de Castilho
# Date: August 28, 2018 # Date: August 28, 2018
# Modified: November 16, 2018 by Joshua Pope-Lewis
# Description: This plugin inserts a line at the start of each layer, # Description: This plugin shows custom messages about your print on the Status bar...
# M117 - displays the filename and layer height to the LCD # Please look at the 3 options
# Alternatively, user can override the filename to display alt text + layer height # - Scolling (SCROLL_LONG_FILENAMES) if enabled in Marlin and you arent printing a small item select this option.
# - Name: By default it will use the name generated by Cura (EG: TT_Test_Cube) - Type a custom name in here
# - Max Layer: Enabling this will show how many layers are in the entire print (EG: Layer 1 of 265!)
from ..Script import Script from ..Script import Script
from UM.Application import Application from UM.Application import Application
@ -15,35 +18,72 @@ class DisplayFilenameAndLayerOnLCD(Script):
def getSettingDataString(self): def getSettingDataString(self):
return """{ return """{
"name": "Display filename and layer on LCD", "name": "Display Filename And Layer On LCD",
"key": "DisplayFilenameAndLayerOnLCD", "key": "DisplayFilenameAndLayerOnLCD",
"metadata": {}, "metadata": {},
"version": 2, "version": 2,
"settings": "settings":
{ {
"scroll":
{
"label": "Scroll enabled/Small layers?",
"description": "If SCROLL_LONG_FILENAMES is enabled select this setting however, if the model is small disable this setting!",
"type": "bool",
"default_value": false
},
"name": "name":
{ {
"label": "text to display:", "label": "Text to display:",
"description": "By default the current filename will be displayed on the LCD. Enter text here to override the filename and display something else.", "description": "By default the current filename will be displayed on the LCD. Enter text here to override the filename and display something else.",
"type": "str", "type": "str",
"default_value": "" "default_value": ""
},
"startNum":
{
"label": "Initial layer number:",
"description": "Choose which number you prefer for the initial layer, 0 or 1",
"type": "int",
"default_value": 0,
"minimum_value": 0,
"maximum_value": 1
},
"maxlayer":
{
"label": "Display max layer?:",
"description": "Display how many layers are in the entire print on status bar?",
"type": "bool",
"default_value": true
} }
} }
}""" }"""
def execute(self, data): def execute(self, data):
max_layer = 0
if self.getSettingValueByKey("name") != "": if self.getSettingValueByKey("name") != "":
name = self.getSettingValueByKey("name") name = self.getSettingValueByKey("name")
else: else:
name = Application.getInstance().getPrintInformation().jobName name = Application.getInstance().getPrintInformation().jobName
lcd_text = "M117 " + name + " layer " if not self.getSettingValueByKey("scroll"):
i = 0 if self.getSettingValueByKey("maxlayer"):
lcd_text = "M117 Layer "
else:
lcd_text = "M117 Printing Layer "
else:
lcd_text = "M117 Printing " + name + " - Layer "
i = self.getSettingValueByKey("startNum")
for layer in data: for layer in data:
display_text = lcd_text + str(i) display_text = lcd_text + str(i) + " " + name
layer_index = data.index(layer) layer_index = data.index(layer)
lines = layer.split("\n") lines = layer.split("\n")
for line in lines: for line in lines:
if line.startswith(";LAYER_COUNT:"):
max_layer = line
max_layer = max_layer.split(":")[1]
if line.startswith(";LAYER:"): if line.startswith(";LAYER:"):
if self.getSettingValueByKey("maxlayer"):
display_text = display_text + " of " + max_layer
else:
display_text = display_text + "!"
line_index = lines.index(line) line_index = lines.index(line)
lines.insert(line_index + 1, display_text) lines.insert(line_index + 1, display_text)
i += 1 i += 1

View file

@ -128,9 +128,26 @@ class Stretcher():
onestep = GCodeStep(0, in_relative_movement) onestep = GCodeStep(0, in_relative_movement)
onestep.copyPosFrom(current) onestep.copyPosFrom(current)
elif _getValue(line, "G") == 1: elif _getValue(line, "G") == 1:
last_x = current.step_x
last_y = current.step_y
last_z = current.step_z
last_e = current.step_e
current.readStep(line) current.readStep(line)
onestep = GCodeStep(1, in_relative_movement) if (current.step_x == last_x and current.step_y == last_y and
onestep.copyPosFrom(current) current.step_z == last_z and current.step_e != last_e
):
# It's an extruder only move. Preserve it rather than process it as an
# extruded move. Otherwise, the stretched output might contain slight
# motion in X and Y in addition to E. This can cause problems with
# firmwares that implement pressure advance.
onestep = GCodeStep(-1, in_relative_movement)
onestep.copyPosFrom(current)
# Rather than copy the original line, write a new one with consistent
# extruder coordinates
onestep.comment = "G1 F{} E{}".format(onestep.step_f, onestep.step_e)
else:
onestep = GCodeStep(1, in_relative_movement)
onestep.copyPosFrom(current)
# end of relative movement # end of relative movement
elif _getValue(line, "G") == 90: elif _getValue(line, "G") == 90:

View file

@ -218,10 +218,10 @@ class SimulationView(CuraView):
if theme is not None: if theme is not None:
self._ghost_shader.setUniformValue("u_color", Color(*theme.getColor("layerview_ghost").getRgb())) self._ghost_shader.setUniformValue("u_color", Color(*theme.getColor("layerview_ghost").getRgb()))
for node in DepthFirstIterator(scene.getRoot()): # type: ignore for node in DepthFirstIterator(scene.getRoot()):
# We do not want to render ConvexHullNode as it conflicts with the bottom layers. # We do not want to render ConvexHullNode as it conflicts with the bottom layers.
# However, it is somewhat relevant when the node is selected, so do render it then. # However, it is somewhat relevant when the node is selected, so do render it then.
if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): if type(node) is ConvexHullNode and not Selection.isSelected(cast(ConvexHullNode, node).getWatchedNode()):
continue continue
if not node.render(renderer): if not node.render(renderer):
@ -572,14 +572,14 @@ class SimulationView(CuraView):
self._current_layer_jumps = job.getResult().get("jumps") self._current_layer_jumps = job.getResult().get("jumps")
self._controller.getScene().sceneChanged.emit(self._controller.getScene().getRoot()) self._controller.getScene().sceneChanged.emit(self._controller.getScene().getRoot())
self._top_layers_job = None # type: Optional["_CreateTopLayersJob"] self._top_layers_job = None
def _updateWithPreferences(self) -> None: def _updateWithPreferences(self) -> None:
self._solid_layers = int(Application.getInstance().getPreferences().getValue("view/top_layer_count")) self._solid_layers = int(Application.getInstance().getPreferences().getValue("view/top_layer_count"))
self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers")) self._only_show_top_layers = bool(Application.getInstance().getPreferences().getValue("view/only_show_top_layers"))
self._compatibility_mode = self._evaluateCompatibilityMode() self._compatibility_mode = self._evaluateCompatibilityMode()
self.setSimulationViewType(int(float(Application.getInstance().getPreferences().getValue("layerview/layer_view_type")))); self.setSimulationViewType(int(float(Application.getInstance().getPreferences().getValue("layerview/layer_view_type"))))
for extruder_nr, extruder_opacity in enumerate(Application.getInstance().getPreferences().getValue("layerview/extruder_opacities").split("|")): for extruder_nr, extruder_opacity in enumerate(Application.getInstance().getPreferences().getValue("layerview/extruder_opacities").split("|")):
try: try:

View file

@ -48,32 +48,32 @@ Window
ToolboxLoadingPage ToolboxLoadingPage
{ {
id: viewLoading id: viewLoading
visible: toolbox.viewCategory != "installed" && toolbox.viewPage == "loading" visible: toolbox.viewCategory !== "installed" && toolbox.viewPage === "loading"
} }
ToolboxErrorPage ToolboxErrorPage
{ {
id: viewErrored id: viewErrored
visible: toolbox.viewCategory != "installed" && toolbox.viewPage == "errored" visible: toolbox.viewCategory !== "installed" && toolbox.viewPage === "errored"
} }
ToolboxDownloadsPage ToolboxDownloadsPage
{ {
id: viewDownloads id: viewDownloads
visible: toolbox.viewCategory != "installed" && toolbox.viewPage == "overview" visible: toolbox.viewCategory !== "installed" && toolbox.viewPage === "overview"
} }
ToolboxDetailPage ToolboxDetailPage
{ {
id: viewDetail id: viewDetail
visible: toolbox.viewCategory != "installed" && toolbox.viewPage == "detail" visible: toolbox.viewCategory !== "installed" && toolbox.viewPage === "detail"
} }
ToolboxAuthorPage ToolboxAuthorPage
{ {
id: viewAuthor id: viewAuthor
visible: toolbox.viewCategory != "installed" && toolbox.viewPage == "author" visible: toolbox.viewCategory !== "installed" && toolbox.viewPage === "author"
} }
ToolboxInstalledPage ToolboxInstalledPage
{ {
id: installedPluginList id: installedPluginList
visible: toolbox.viewCategory == "installed" visible: toolbox.viewCategory === "installed"
} }
} }

View file

@ -1,9 +1,9 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox 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 1.4
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
Item Item
@ -11,48 +11,17 @@ Item
id: base id: base
property var packageData property var packageData
property var technicalDataSheetUrl: property var technicalDataSheetUrl: packageData.links.technicalDataSheet
{ property var safetyDataSheetUrl: packageData.links.safetyDataSheet
var link = undefined property var printingGuidelinesUrl: packageData.links.printingGuidelines
if ("Technical Data Sheet" in packageData.links) property var materialWebsiteUrl: packageData.links.website
{
// HACK: This is the way the old API (used in 3.6-beta) used to do it. For safety it's still here,
// but it can be removed over time.
link = packageData.links["Technical Data Sheet"]
}
else if ("technicalDataSheet" in packageData.links)
{
link = packageData.links["technicalDataSheet"]
}
return link
}
property var safetyDataSheetUrl:
{
var sds_name = "safetyDataSheet"
return (sds_name in packageData.links) ? packageData.links[sds_name] : undefined
}
property var printingGuidelinesUrl:
{
var pg_name = "printingGuidelines"
return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined
}
property var materialWebsiteUrl: height: childrenRect.height
{ onVisibleChanged: packageData.type === "material" && (compatibilityItem.visible || dataSheetLinks.visible)
var pg_name = "website"
return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined
}
anchors.topMargin: UM.Theme.getSize("default_margin").height
height: visible ? childrenRect.height : 0
visible: packageData.type == "material" && Column
(packageData.has_configs || technicalDataSheetUrl !== undefined ||
safetyDataSheetUrl !== undefined || printingGuidelinesUrl !== undefined ||
materialWebsiteUrl !== undefined)
Item
{ {
id: combatibilityItem id: compatibilityItem
visible: packageData.has_configs visible: packageData.has_configs
width: parent.width width: parent.width
// This is a bit of a hack, but the whole QML is pretty messy right now. This needs a big overhaul. // This is a bit of a hack, but the whole QML is pretty messy right now. This needs a big overhaul.
@ -61,7 +30,6 @@ Item
Label Label
{ {
id: heading id: heading
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width width: parent.width
text: catalog.i18nc("@label", "Compatibility") text: catalog.i18nc("@label", "Compatibility")
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
@ -73,8 +41,6 @@ Item
TableView TableView
{ {
id: table id: table
anchors.top: heading.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: parent.width width: parent.width
frameVisible: false frameVisible: false
@ -155,32 +121,32 @@ Item
TableViewColumn TableViewColumn
{ {
role: "machine" role: "machine"
title: "Machine" title: catalog.i18nc("@label:table_header", "Machine")
width: Math.floor(table.width * 0.25) width: Math.floor(table.width * 0.25)
delegate: columnTextDelegate delegate: columnTextDelegate
} }
TableViewColumn TableViewColumn
{ {
role: "print_core" role: "print_core"
title: "Print Core" title: catalog.i18nc("@label:table_header", "Print Core")
width: Math.floor(table.width * 0.2) width: Math.floor(table.width * 0.2)
} }
TableViewColumn TableViewColumn
{ {
role: "build_plate" role: "build_plate"
title: "Build Plate" title: catalog.i18nc("@label:table_header", "Build Plate")
width: Math.floor(table.width * 0.225) width: Math.floor(table.width * 0.225)
} }
TableViewColumn TableViewColumn
{ {
role: "support_material" role: "support_material"
title: "Support" title: catalog.i18nc("@label:table_header", "Support")
width: Math.floor(table.width * 0.225) width: Math.floor(table.width * 0.225)
} }
TableViewColumn TableViewColumn
{ {
role: "quality" role: "quality"
title: "Quality" title: catalog.i18nc("@label:table_header", "Quality")
width: Math.floor(table.width * 0.1) width: Math.floor(table.width * 0.1)
} }
} }
@ -188,13 +154,14 @@ Item
Label Label
{ {
id: data_sheet_links id: dataSheetLinks
anchors.top: combatibilityItem.bottom anchors.top: compatibilityItem.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height / 2 anchors.topMargin: UM.Theme.getSize("narrow_margin").height
visible: base.technicalDataSheetUrl !== undefined || visible: base.technicalDataSheetUrl !== undefined ||
base.safetyDataSheetUrl !== undefined || base.printingGuidelinesUrl !== undefined || base.safetyDataSheetUrl !== undefined ||
base.materialWebsiteUrl !== undefined base.printingGuidelinesUrl !== undefined ||
height: visible ? contentHeight : 0 base.materialWebsiteUrl !== undefined
text: text:
{ {
var result = "" var result = ""

View file

@ -1,9 +1,8 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.10
import QtQuick.Controls 1.4 import QtQuick.Controls 2.3
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
Item Item
@ -11,10 +10,9 @@ Item
id: detailList id: detailList
ScrollView ScrollView
{ {
frameVisible: false clip: true
anchors.fill: detailList anchors.fill: detailList
style: UM.Theme.styles.scrollview
flickableItem.flickableDirection: Flickable.VerticalFlick
Column Column
{ {
anchors anchors

View file

@ -1,30 +1,30 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox 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.3
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
Item Item
{ {
id: tile id: tile
width: detailList.width - UM.Theme.getSize("wide_margin").width width: detailList.width - UM.Theme.getSize("wide_margin").width
height: normalData.height + compatibilityChart.height + 4 * UM.Theme.getSize("default_margin").height height: normalData.height + 2 * UM.Theme.getSize("wide_margin").height
Item Column
{ {
id: normalData id: normalData
height: childrenRect.height
anchors anchors
{ {
top: parent.top
left: parent.left left: parent.left
right: controls.left right: controls.left
rightMargin: UM.Theme.getSize("default_margin").width * 2 + UM.Theme.getSize("toolbox_loader").width rightMargin: UM.Theme.getSize("wide_margin").width
top: parent.top
} }
Label Label
{ {
id: packageName
width: parent.width width: parent.width
height: UM.Theme.getSize("toolbox_property_label").height height: UM.Theme.getSize("toolbox_property_label").height
text: model.name text: model.name
@ -33,9 +33,9 @@ Item
font: UM.Theme.getFont("medium_bold") font: UM.Theme.getFont("medium_bold")
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
Label Label
{ {
anchors.top: packageName.bottom
width: parent.width width: parent.width
text: model.description text: model.description
maximumLineCount: 25 maximumLineCount: 25
@ -45,6 +45,12 @@ Item
font: UM.Theme.getFont("default") font: UM.Theme.getFont("default")
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
ToolboxCompatibilityChart
{
width: parent.width
packageData: model
}
} }
ToolboxDetailTileActions ToolboxDetailTileActions
@ -57,20 +63,12 @@ Item
packageData: model packageData: model
} }
ToolboxCompatibilityChart
{
id: compatibilityChart
anchors.top: normalData.bottom
width: normalData.width
packageData: model
}
Rectangle Rectangle
{ {
color: UM.Theme.getColor("lining") color: UM.Theme.getColor("lining")
width: tile.width width: tile.width
height: UM.Theme.getSize("default_lining").height height: UM.Theme.getSize("default_lining").height
anchors.top: compatibilityChart.bottom anchors.top: normalData.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height + UM.Theme.getSize("wide_margin").height //Normal margin for spacing after chart, wide margin between items. anchors.topMargin: UM.Theme.getSize("default_margin").height + UM.Theme.getSize("wide_margin").height //Normal margin for spacing after chart, wide margin between items.
} }
} }

View file

@ -35,7 +35,7 @@ Column
// Don't allow installing while another download is running // Don't allow installing while another download is running
enabled: installed || (!(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired) enabled: installed || (!(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired)
opacity: enabled ? 1.0 : 0.5 opacity: enabled ? 1.0 : 0.5
visible: !updateButton.visible && !installed// Don't show when the update button is visible visible: !updateButton.visible && !installed // Don't show when the update button is visible
} }
Cura.SecondaryButton Cura.SecondaryButton

View file

@ -2,9 +2,7 @@
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox 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.3
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.3
import UM 1.1 as UM import UM 1.1 as UM
Column Column

View file

@ -1,25 +1,20 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.10
import QtQuick.Controls 1.4 import QtQuick.Controls 2.3
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
ScrollView ScrollView
{ {
frameVisible: false clip: true
width: parent.width width: parent.width
height: parent.height height: parent.height
style: UM.Theme.styles.scrollview
flickableItem.flickableDirection: Flickable.VerticalFlick
Column Column
{ {
width: base.width width: base.width
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
height: childrenRect.height
ToolboxDownloadsShowcase ToolboxDownloadsShowcase
{ {
@ -31,14 +26,14 @@ ScrollView
{ {
id: allPlugins id: allPlugins
width: parent.width width: parent.width
heading: toolbox.viewCategory == "material" ? catalog.i18nc("@label", "Community Contributions") : catalog.i18nc("@label", "Community Plugins") heading: toolbox.viewCategory === "material" ? catalog.i18nc("@label", "Community Contributions") : catalog.i18nc("@label", "Community Plugins")
model: toolbox.viewCategory == "material" ? toolbox.materialsAvailableModel : toolbox.pluginsAvailableModel model: toolbox.viewCategory === "material" ? toolbox.materialsAvailableModel : toolbox.pluginsAvailableModel
} }
ToolboxDownloadsGrid ToolboxDownloadsGrid
{ {
id: genericMaterials id: genericMaterials
visible: toolbox.viewCategory == "material" visible: toolbox.viewCategory === "material"
width: parent.width width: parent.width
heading: catalog.i18nc("@label", "Generic Materials") heading: catalog.i18nc("@label", "Generic Materials")
model: toolbox.materialsGenericModel model: toolbox.materialsGenericModel

View file

@ -1,50 +1,50 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
import QtQuick.Dialogs 1.1 import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
ScrollView ScrollView
{ {
id: page id: page
frameVisible: false clip: true
width: parent.width width: parent.width
height: parent.height height: parent.height
style: UM.Theme.styles.scrollview
flickableItem.flickableDirection: Flickable.VerticalFlick
Column Column
{ {
width: page.width
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
padding: UM.Theme.getSize("wide_margin").width
visible: toolbox.pluginsInstalledModel.items.length > 0 visible: toolbox.pluginsInstalledModel.items.length > 0
height: childrenRect.height + 4 * UM.Theme.getSize("default_margin").height height: childrenRect.height + 2 * UM.Theme.getSize("wide_margin").height
anchors
{
right: parent.right
left: parent.left
margins: UM.Theme.getSize("default_margin").width
top: parent.top
}
Label Label
{ {
width: page.width anchors
{
left: parent.left
right: parent.right
margins: parent.padding
}
text: catalog.i18nc("@title:tab", "Plugins") text: catalog.i18nc("@title:tab", "Plugins")
color: UM.Theme.getColor("text_medium") color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("large") font: UM.Theme.getFont("large")
renderType: Text.NativeRendering renderType: Text.NativeRendering
} }
Rectangle Rectangle
{ {
anchors
{
left: parent.left
right: parent.right
margins: parent.padding
}
id: installedPlugins id: installedPlugins
color: "transparent" color: "transparent"
width: parent.width
height: childrenRect.height + UM.Theme.getSize("default_margin").width height: childrenRect.height + UM.Theme.getSize("default_margin").width
border.color: UM.Theme.getColor("lining") border.color: UM.Theme.getColor("lining")
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width
@ -65,8 +65,15 @@ ScrollView
} }
} }
} }
Label Label
{ {
anchors
{
left: parent.left
right: parent.right
margins: parent.padding
}
text: catalog.i18nc("@title:tab", "Materials") text: catalog.i18nc("@title:tab", "Materials")
color: UM.Theme.getColor("text_medium") color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
@ -75,9 +82,14 @@ ScrollView
Rectangle Rectangle
{ {
anchors
{
left: parent.left
right: parent.right
margins: parent.padding
}
id: installedMaterials id: installedMaterials
color: "transparent" color: "transparent"
width: parent.width
height: childrenRect.height + UM.Theme.getSize("default_margin").width height: childrenRect.height + UM.Theme.getSize("default_margin").width
border.color: UM.Theme.getColor("lining") border.color: UM.Theme.getColor("lining")
border.width: UM.Theme.getSize("default_lining").width border.width: UM.Theme.getSize("default_lining").width

View file

@ -41,7 +41,7 @@ Item
Column Column
{ {
id: pluginInfo id: pluginInfo
topPadding: Math.floor(UM.Theme.getSize("default_margin").height / 2) topPadding: UM.Theme.getSize("narrow_margin").height
property var color: model.type === "plugin" && !isEnabled ? UM.Theme.getColor("lining") : UM.Theme.getColor("text") property var color: model.type === "plugin" && !isEnabled ? UM.Theme.getColor("lining") : UM.Theme.getColor("text")
width: Math.floor(tileRow.width - (authorInfo.width + pluginActions.width + 2 * tileRow.spacing + ((disableButton.visible) ? disableButton.width + tileRow.spacing : 0))) width: Math.floor(tileRow.width - (authorInfo.width + pluginActions.width + 2 * tileRow.spacing + ((disableButton.visible) ? disableButton.width + tileRow.spacing : 0)))
Label Label

View file

@ -1,16 +1,16 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2019 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher. // Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.10
import QtQuick.Controls 1.4 import QtQuick.Controls 2.3
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM import UM 1.1 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Item Cura.PrimaryButton
{ {
id: base id: button
property var active: false property var active: false
property var complete: false property var complete: false
@ -25,43 +25,36 @@ Item
width: UM.Theme.getSize("toolbox_action_button").width width: UM.Theme.getSize("toolbox_action_button").width
height: UM.Theme.getSize("toolbox_action_button").height height: UM.Theme.getSize("toolbox_action_button").height
fixedWidthMode: true
Cura.PrimaryButton text:
{ {
id: button if (complete)
width: UM.Theme.getSize("toolbox_action_button").width
height: UM.Theme.getSize("toolbox_action_button").height
fixedWidthMode: true
text:
{ {
if (complete) return completeLabel
{
return completeLabel
}
else if (active)
{
return activeLabel
}
else
{
return readyLabel
}
} }
onClicked: else if (active)
{ {
if (complete) return activeLabel
{ }
completeAction() else
} {
else if (active) return readyLabel
{
activeAction()
}
else
{
readyAction()
}
} }
busy: active
} }
onClicked:
{
if (complete)
{
completeAction()
}
else if (active)
{
activeAction()
}
else
{
readyAction()
}
}
busy: active
} }

View file

@ -655,8 +655,12 @@ class Toolbox(QObject, Extension):
# Check if the download was sucessfull # Check if the download was sucessfull
if self._download_reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: if self._download_reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
Logger.log("w", "Failed to download package. The following error was returned: %s", json.loads(bytes(self._download_reply.readAll()).decode("utf-8"))) try:
return Logger.log("w", "Failed to download package. The following error was returned: %s", json.loads(bytes(self._download_reply.readAll()).decode("utf-8")))
except json.decoder.JSONDecodeError:
Logger.logException("w", "Failed to download package and failed to parse a response from it")
finally:
return
# Must not delete the temporary file on Windows # Must not delete the temporary file on Windows
self._temp_plugin_file = tempfile.NamedTemporaryFile(mode = "w+b", suffix = ".curapackage", delete = False) self._temp_plugin_file = tempfile.NamedTemporaryFile(mode = "w+b", suffix = ".curapackage", delete = False)
file_path = self._temp_plugin_file.name file_path = self._temp_plugin_file.name

View file

@ -243,10 +243,11 @@ Item
enabled: !contextMenuButton.enabled enabled: !contextMenuButton.enabled
} }
MonitorInfoBlurb // TODO: uncomment this tooltip as soon as the required firmware is released
{ // MonitorInfoBlurb
id: contextMenuDisabledInfo // {
text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.") // id: contextMenuDisabledInfo
target: contextMenuButton // text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
} // target: contextMenuButton
// }
} }

View file

@ -202,12 +202,13 @@ Item
enabled: !contextMenuButton.enabled enabled: !contextMenuButton.enabled
} }
MonitorInfoBlurb // TODO: uncomment this tooltip as soon as the required firmware is released
{ // MonitorInfoBlurb
id: contextMenuDisabledInfo // {
text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.") // id: contextMenuDisabledInfo
target: contextMenuButton // text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
} // target: contextMenuButton
// }
CameraButton CameraButton
{ {

View file

@ -174,9 +174,13 @@ class CloudApiClient:
model: Type[CloudApiClientModel], model: Type[CloudApiClientModel],
) -> None: ) -> None:
def parse() -> None: def parse() -> None:
# Don't try to parse the reply if we didn't get one
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) is None:
return
status_code, response = self._parseReply(reply) status_code, response = self._parseReply(reply)
self._anti_gc_callbacks.remove(parse) self._anti_gc_callbacks.remove(parse)
return self._parseModels(response, on_finished, model) self._parseModels(response, on_finished, model)
return
self._anti_gc_callbacks.append(parse) self._anti_gc_callbacks.append(parse)
reply.finished.connect(parse) reply.finished.connect(parse)

View file

@ -969,7 +969,7 @@ class XmlMaterialProfile(InstanceContainer):
machine_compatibility = cls._parseCompatibleValue(entry.text) machine_compatibility = cls._parseCompatibleValue(entry.text)
for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces): for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces):
machine_id_list = product_id_map.get(identifier.get("product"), []) machine_id_list = product_id_map.get(identifier.get("product", ""), [])
if not machine_id_list: if not machine_id_list:
machine_id_list = cls.getPossibleDefinitionIDsFromName(identifier.get("product")) machine_id_list = cls.getPossibleDefinitionIDsFromName(identifier.get("product"))
@ -1001,7 +1001,7 @@ class XmlMaterialProfile(InstanceContainer):
result_metadata.append(new_material_metadata) result_metadata.append(new_material_metadata)
buildplates = machine.iterfind("./um:buildplate", cls.__namespaces) buildplates = machine.iterfind("./um:buildplate", cls.__namespaces)
buildplate_map = {} # type: Dict[str, Dict[str, bool]] buildplate_map = {} # type: Dict[str, Dict[str, bool]]
buildplate_map["buildplate_compatible"] = {} buildplate_map["buildplate_compatible"] = {}
buildplate_map["buildplate_recommended"] = {} buildplate_map["buildplate_recommended"] = {}
for buildplate in buildplates: for buildplate in buildplates:

View file

@ -162,6 +162,7 @@
"optimize_wall_printing_order": { "value": "True" }, "optimize_wall_printing_order": { "value": "True" },
"retraction_combing": { "default_value": "all" }, "retraction_combing": { "default_value": "all" },
"initial_layer_line_width_factor": { "value": "120" }, "initial_layer_line_width_factor": { "value": "120" },
"zig_zaggify_infill": { "value": "gradual_infill_steps == 0" } "zig_zaggify_infill": { "value": "gradual_infill_steps == 0" },
"build_volume_temperature": { "maximum_value": 50 }
} }
} }

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="78px" height="53px" viewBox="0 0 78 53" 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 Copy</title>
<desc>Created with Sketch.</desc>
<g id="Sign-in-/Message-restyle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-162.000000, -16.000000)">
<g id="Group-cloud-Copy" transform="translate(162.000000, 16.000000)">
<path d="M71.6139989,39.7264219 C71.5196898,37.5579439 70.9711289,35.5059663 70.0601048,33.6613194 L71.6937566,33.6613194 C72.8434847,33.6613194 73.787904,32.731337 73.787904,31.5991845 L73.8289659,31.5991845 L73.8289659,6.57052798 C73.8289659,6.1257538 73.4594104,5.80228166 73.0487931,5.80228166 L58.158788,5.80228166 L58.158788,25.1687374 C57.4862997,25.0807183 56.800231,25.0352941 56.103441,25.0352941 C55.374501,25.0352941 54.6572944,25.0850068 53.9550947,25.1811929 L53.9550947,5.80228166 L53.8935021,5.80228166 L53.8935021,4.68260671 C53.7612249,4.35507342 53.4329996,4.13943248 53.0774006,4.13943248 L24.4830482,4.13943248 C23.9749094,4.13943248 23.605354,4.54882691 23.605354,5.0037096 L23.605354,33.1609482 C23.605354,34.4346197 24.6678259,35.4808499 25.9612699,35.4808499 L41.3906551,35.4808499 C40.8638727,37.0247578 40.5782993,38.67857 40.5782993,40.3983852 C40.5782993,41.0436856 40.6185041,41.6796936 40.6965701,42.3040902 L25.2683535,42.3040902 C24.7602147,42.3495785 24.252076,42.5315316 23.8825205,42.8499495 L23.605354,43.122879 C23.3281874,43.5777618 22.7738542,43.6687383 22.219521,43.6687383 L19.7250218,43.6687383 C19.5864385,43.6687383 19.4478552,43.5322734 19.4478552,43.3958088 L19.4478552,39.7264219 L5.21483793,39.7264219 C4.76315904,39.7668558 4.31148018,39.928592 3.98298644,40.2116301 L3.73661615,40.4542343 C3.49024586,40.8585745 2.99750527,40.9394424 2.50476467,40.9394424 L0.287432013,40.9394424 C0.164246864,40.9394424 0.0410617159,40.8181403 0.0410617159,40.6968382 L0.0410617159,2.5675603 C0.0410617159,2.44625825 0.164246864,2.3249562 0.287432013,2.3249562 L19.4478552,2.3249562 L19.4478552,0.50037096 C19.4478552,0.363906153 19.5864385,0.227441345 19.7250218,0.227441345 L57.8816214,0.227441345 C58.0202046,0.227441345 58.158788,0.363906153 58.158788,0.50037096 L58.158788,2.3249562 L77.3192117,2.3249562 C77.4423969,2.3249562 77.565582,2.44625825 77.565582,2.5675603 L77.565582,40.6968382 C77.565582,40.8181403 77.4423969,40.9394424 77.3192117,40.9394424 L75.101879,40.9394424 C74.6502001,40.8990083 74.1985212,40.7372724 73.8700276,40.4542343 L73.6236573,40.2116301 C73.377287,39.8072899 72.8845464,39.7264219 72.3918058,39.7264219 L71.6139989,39.7264219 Z M19.4478552,5.80228166 L4.51678875,5.80228166 C4.06510989,5.80228166 3.73661615,6.16618781 3.73661615,6.57052798 L3.73661615,31.5991845 C3.73661615,32.731337 4.68103562,33.6613194 5.83076366,33.6613194 L19.4478552,33.6613194 L19.4478552,5.80228166 Z" id="Combined-Shape" fill="#E5E5E5" fill-rule="nonzero"></path>
<g id="Group" transform="translate(43.578299, 28.035294)" fill="#3282FF">
<path d="M12.5251415,24.7888094 C5.60769686,24.7888094 1.77635684e-14,19.2396454 1.77635684e-14,12.3944047 C1.77635684e-14,5.54916401 5.60769686,-4.26325641e-14 12.5251415,-4.26325641e-14 C19.4425861,-4.26325641e-14 25.050283,5.54916401 25.050283,12.3944047 C25.050283,19.2396454 19.4425861,24.7888094 12.5251415,24.7888094 Z M17.9438152,10.4266859 C17.7896596,9.07601357 16.6334927,8.04314651 15.2460924,8.04314651 C14.8607034,8.04314651 14.5523922,8.12259783 14.244081,8.28150044 C13.5503809,7.16918208 12.3171362,6.45412027 11.0068137,6.45412027 C8.84863548,6.45412027 7.15292402,8.20204914 7.15292402,10.4266859 C7.15292402,10.4266859 7.15292402,10.4266859 7.15292402,10.5061372 C5.84260152,10.6650398 4.8405902,11.8568095 4.8405902,13.2074818 C4.8405902,14.7170567 6.0738349,15.9882777 7.53831299,15.9882777 C8.69447989,15.9882777 16.1710259,15.9882777 17.5584262,15.9882777 C19.0229043,15.9882777 20.256149,14.7170567 20.256149,13.2074818 C20.256149,11.7773582 19.2541376,10.6650398 17.9438152,10.4266859 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,28 @@
{
"metadata": {
"name": "Colorblind Assist Dark",
"inherits": "cura-dark"
},
"colors": {
"x_axis": [212, 0, 0, 255],
"y_axis": [64, 64, 255, 255],
"model_default": [156, 201, 36, 255],
"model_overhang": [200, 0, 255, 255],
"xray": [26, 26, 62, 255],
"xray_error": [255, 0, 0, 255],
"layerview_inset_0": [255, 64, 0, 255],
"layerview_inset_x": [0, 156, 128, 255],
"layerview_skin": [255, 255, 86, 255],
"layerview_support": [255, 255, 0, 255],
"layerview_infill": [0, 255, 255, 255],
"layerview_support_infill": [0, 200, 200, 255],
"layerview_move_retraction": [0, 100, 255, 255]
}
}

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="78px" height="53px" viewBox="0 0 78 53" 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 Copy</title>
<desc>Created with Sketch.</desc>
<g id="Sign-in-/Message-restyle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard" transform="translate(-162.000000, -16.000000)">
<g id="Group-cloud-Copy" transform="translate(162.000000, 16.000000)">
<path d="M71.6139989,39.7264219 C71.5196898,37.5579439 70.9711289,35.5059663 70.0601048,33.6613194 L71.6937566,33.6613194 C72.8434847,33.6613194 73.787904,32.731337 73.787904,31.5991845 L73.8289659,31.5991845 L73.8289659,6.57052798 C73.8289659,6.1257538 73.4594104,5.80228166 73.0487931,5.80228166 L58.158788,5.80228166 L58.158788,25.1687374 C57.4862997,25.0807183 56.800231,25.0352941 56.103441,25.0352941 C55.374501,25.0352941 54.6572944,25.0850068 53.9550947,25.1811929 L53.9550947,5.80228166 L53.8935021,5.80228166 L53.8935021,4.68260671 C53.7612249,4.35507342 53.4329996,4.13943248 53.0774006,4.13943248 L24.4830482,4.13943248 C23.9749094,4.13943248 23.605354,4.54882691 23.605354,5.0037096 L23.605354,33.1609482 C23.605354,34.4346197 24.6678259,35.4808499 25.9612699,35.4808499 L41.3906551,35.4808499 C40.8638727,37.0247578 40.5782993,38.67857 40.5782993,40.3983852 C40.5782993,41.0436856 40.6185041,41.6796936 40.6965701,42.3040902 L25.2683535,42.3040902 C24.7602147,42.3495785 24.252076,42.5315316 23.8825205,42.8499495 L23.605354,43.122879 C23.3281874,43.5777618 22.7738542,43.6687383 22.219521,43.6687383 L19.7250218,43.6687383 C19.5864385,43.6687383 19.4478552,43.5322734 19.4478552,43.3958088 L19.4478552,39.7264219 L5.21483793,39.7264219 C4.76315904,39.7668558 4.31148018,39.928592 3.98298644,40.2116301 L3.73661615,40.4542343 C3.49024586,40.8585745 2.99750527,40.9394424 2.50476467,40.9394424 L0.287432013,40.9394424 C0.164246864,40.9394424 0.0410617159,40.8181403 0.0410617159,40.6968382 L0.0410617159,2.5675603 C0.0410617159,2.44625825 0.164246864,2.3249562 0.287432013,2.3249562 L19.4478552,2.3249562 L19.4478552,0.50037096 C19.4478552,0.363906153 19.5864385,0.227441345 19.7250218,0.227441345 L57.8816214,0.227441345 C58.0202046,0.227441345 58.158788,0.363906153 58.158788,0.50037096 L58.158788,2.3249562 L77.3192117,2.3249562 C77.4423969,2.3249562 77.565582,2.44625825 77.565582,2.5675603 L77.565582,40.6968382 C77.565582,40.8181403 77.4423969,40.9394424 77.3192117,40.9394424 L75.101879,40.9394424 C74.6502001,40.8990083 74.1985212,40.7372724 73.8700276,40.4542343 L73.6236573,40.2116301 C73.377287,39.8072899 72.8845464,39.7264219 72.3918058,39.7264219 L71.6139989,39.7264219 Z M19.4478552,5.80228166 L4.51678875,5.80228166 C4.06510989,5.80228166 3.73661615,6.16618781 3.73661615,6.57052798 L3.73661615,31.5991845 C3.73661615,32.731337 4.68103562,33.6613194 5.83076366,33.6613194 L19.4478552,33.6613194 L19.4478552,5.80228166 Z" id="Combined-Shape" fill="#E5E5E5" fill-rule="nonzero"></path>
<g id="Group" transform="translate(43.578299, 28.035294)" fill="#3282FF">
<path d="M12.5251415,24.7888094 C5.60769686,24.7888094 1.77635684e-14,19.2396454 1.77635684e-14,12.3944047 C1.77635684e-14,5.54916401 5.60769686,-4.26325641e-14 12.5251415,-4.26325641e-14 C19.4425861,-4.26325641e-14 25.050283,5.54916401 25.050283,12.3944047 C25.050283,19.2396454 19.4425861,24.7888094 12.5251415,24.7888094 Z M17.9438152,10.4266859 C17.7896596,9.07601357 16.6334927,8.04314651 15.2460924,8.04314651 C14.8607034,8.04314651 14.5523922,8.12259783 14.244081,8.28150044 C13.5503809,7.16918208 12.3171362,6.45412027 11.0068137,6.45412027 C8.84863548,6.45412027 7.15292402,8.20204914 7.15292402,10.4266859 C7.15292402,10.4266859 7.15292402,10.4266859 7.15292402,10.5061372 C5.84260152,10.6650398 4.8405902,11.8568095 4.8405902,13.2074818 C4.8405902,14.7170567 6.0738349,15.9882777 7.53831299,15.9882777 C8.69447989,15.9882777 16.1710259,15.9882777 17.5584262,15.9882777 C19.0229043,15.9882777 20.256149,14.7170567 20.256149,13.2074818 C20.256149,11.7773582 19.2541376,10.6650398 17.9438152,10.4266859 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,29 @@
{
"metadata": {
"name": "Colorblind Assist Light",
"inherits": "cura-light"
},
"colors": {
"x_axis": [200, 0, 0, 255],
"y_axis": [64, 64, 255, 255],
"model_default": [156, 201, 36, 255],
"model_overhang": [200, 0, 255, 255],
"model_selection_outline": [12, 169, 227, 255],
"xray": [26, 26, 62, 255],
"xray_error": [255, 0, 0, 255],
"layerview_inset_0": [255, 64, 0, 255],
"layerview_inset_x": [0, 156, 128, 255],
"layerview_skin": [255, 255, 86, 255],
"layerview_support": [255, 255, 0, 255],
"layerview_infill": [0, 255, 255, 255],
"layerview_support_infill": [0, 200, 200, 255],
"layerview_move_retraction": [0, 100, 255, 255]
}
}

View file

@ -6,7 +6,7 @@ import pytest
from unittest.mock import patch from unittest.mock import patch
class TestConvexHullDecorator(SceneNodeDecorator): class MockedConvexHullDecorator(SceneNodeDecorator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -14,7 +14,7 @@ class TestConvexHullDecorator(SceneNodeDecorator):
return Polygon([[5, 5], [-5, 5], [-5, -5], [5, -5]]) return Polygon([[5, 5], [-5, 5], [-5, -5], [5, -5]])
class TestInvalidConvexHullDecorator(SceneNodeDecorator): class InvalidConvexHullDecorator(SceneNodeDecorator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -34,16 +34,16 @@ class TestCollidesWithAreas:
assert not cura_scene_node.collidesWithAreas([Polygon([[10, 10], [-10, 10], [-10, -10], [10, -10]])]) assert not cura_scene_node.collidesWithAreas([Polygon([[10, 10], [-10, 10], [-10, -10], [10, -10]])])
def test_convexHullIntersects(self, cura_scene_node): def test_convexHullIntersects(self, cura_scene_node):
cura_scene_node.addDecorator(TestConvexHullDecorator()) cura_scene_node.addDecorator(MockedConvexHullDecorator())
assert cura_scene_node.collidesWithAreas([Polygon([[10, 10], [-10, 10], [-10, -10], [10, -10]])]) assert cura_scene_node.collidesWithAreas([Polygon([[10, 10], [-10, 10], [-10, -10], [10, -10]])])
def test_convexHullNoIntersection(self, cura_scene_node): def test_convexHullNoIntersection(self, cura_scene_node):
cura_scene_node.addDecorator(TestConvexHullDecorator()) cura_scene_node.addDecorator(MockedConvexHullDecorator())
assert not cura_scene_node.collidesWithAreas([Polygon([[60, 60], [40, 60], [40, 40], [60, 40]])]) assert not cura_scene_node.collidesWithAreas([Polygon([[60, 60], [40, 60], [40, 40], [60, 40]])])
def test_invalidConvexHull(self, cura_scene_node): def test_invalidConvexHull(self, cura_scene_node):
cura_scene_node.addDecorator(TestInvalidConvexHullDecorator()) cura_scene_node.addDecorator(InvalidConvexHullDecorator())
assert not cura_scene_node.collidesWithAreas([Polygon([[10, 10], [-10, 10], [-10, -10], [10, -10]])]) assert not cura_scene_node.collidesWithAreas([Polygon([[10, 10], [-10, 10], [-10, -10], [10, -10]])])

View file

@ -61,6 +61,7 @@ def test_getQualityChangesGroup(quality_mocked_application):
assert "herp" in manager.getQualityChangesGroups(mocked_stack) assert "herp" in manager.getQualityChangesGroups(mocked_stack)
@pytest.mark.skip("Doesn't work on remote")
def test_getDefaultQualityType(quality_mocked_application): def test_getDefaultQualityType(quality_mocked_application):
manager = QualityManager(quality_mocked_application) manager = QualityManager(quality_mocked_application)
manager.initialize() manager.initialize()