diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index c87e07a974..290b8ee2de 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -871,7 +871,7 @@ class BuildVolume(SceneNode): else: extruder_index = self._global_container_stack.getProperty(extruder_setting_key, "value") - if extruder_index == "-1": # If extruder index is -1 use global instead + if str(extruder_index) == "-1": # If extruder index is -1 use global instead stack = self._global_container_stack else: extruder_stack_id = ExtruderManager.getInstance().extruderIds[str(extruder_index)] diff --git a/cura/CrashHandler.py b/cura/CrashHandler.py index 4048b409a7..7008ba64d2 100644 --- a/cura/CrashHandler.py +++ b/cura/CrashHandler.py @@ -2,6 +2,9 @@ import sys import platform import traceback import webbrowser +import faulthandler +import tempfile +import os import urllib from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QCoreApplication @@ -91,6 +94,17 @@ def show(exception_type, value, tb): crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}" crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace) + tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True) + os.close(tmp_file_fd) + with open(tmp_file_path, "w") as f: + faulthandler.dump_traceback(f, all_threads=True) + with open(tmp_file_path, "r") as f: + data = f.read() + + msg = "-------------------------\n" + msg += data + crash_info += "\n\n" + msg + textarea.setText(crash_info) buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b85c1a2f54..b5aecb9b56 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -138,13 +138,14 @@ class CuraApplication(QtApplication): # From which stack the setting would inherit if not defined per object (handled in the engine) # AND for settings which are not settable_per_mesh: # which extruder is the only extruder this setting is obtained from - SettingDefinition.addSupportedProperty("limit_to_extruder", DefinitionPropertyType.Function, default = "-1") + SettingDefinition.addSupportedProperty("limit_to_extruder", DefinitionPropertyType.Function, default = "-1", depends_on = "value") # For settings which are not settable_per_mesh and not settable_per_extruder: # A function which determines the glabel/meshgroup value by looking at the values of the setting in all (used) extruders SettingDefinition.addSupportedProperty("resolve", DefinitionPropertyType.Function, default = None, depends_on = "value") SettingDefinition.addSettingType("extruder", None, str, Validator) + SettingDefinition.addSettingType("optional_extruder", None, str, None) SettingDefinition.addSettingType("[int]", None, str, None) @@ -178,7 +179,8 @@ class CuraApplication(QtApplication): ("machine_stack", ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"), ("extruder_train", ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"), ("preferences", Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"), - ("user", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer") + ("user", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer"), + ("definition_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.DefinitionChangesContainer, "application/x-uranium-instancecontainer"), } ) @@ -488,7 +490,7 @@ class CuraApplication(QtApplication): self._plugin_registry.loadPlugins() - if self.getBackend() == None: + if self.getBackend() is None: raise RuntimeError("Could not load the backend plugin!") self._plugins_loaded = True @@ -625,7 +627,9 @@ class CuraApplication(QtApplication): camera.lookAt(Vector(0, 0, 0)) controller.getScene().setActiveCamera("3d") - self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0)) + camera_tool = self.getController().getTool("CameraTool") + camera_tool.setOrigin(Vector(0, 100, 0)) + camera_tool.setZoomRange(0.1, 200000) self._camera_animation = CameraAnimation.CameraAnimation() self._camera_animation.setCameraTool(self.getController().getTool("CameraTool")) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index b5c76f1f17..fc256e37be 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -700,7 +700,7 @@ class ContainerManager(QObject): self._container_registry.addContainer(duplicated_container) return self._getMaterialContainerIdForActiveMachine(new_id) - ## Create a new material by cloning Generic PLA and setting the GUID to something unqiue + ## Create a new material by cloning Generic PLA for the current material diameter and setting the GUID to something unqiue # # \return \type{str} the id of the newly created container. @pyqtSlot(result = str) @@ -708,14 +708,25 @@ class ContainerManager(QObject): # Ensure all settings are saved. Application.getInstance().saveSettings() - containers = self._container_registry.findInstanceContainers(id="generic_pla") + global_stack = Application.getInstance().getGlobalContainerStack() + if not global_stack: + return "" + + approximate_diameter = round(global_stack.getProperty("material_diameter", "value")) + containers = self._container_registry.findInstanceContainers(id = "generic_pla*", approximate_diameter = approximate_diameter) if not containers: - Logger.log("d", "Unable to create a new material by cloning generic_pla, because it doesn't exist.") + Logger.log("d", "Unable to create a new material by cloning Generic PLA, because it cannot be found for the material diameter for this machine.") + return "" + + base_file = containers[0].getMetaDataEntry("base_file") + containers = self._container_registry.findInstanceContainers(id = base_file) + if not containers: + Logger.log("d", "Unable to create a new material by cloning Generic PLA, because the base file for Generic PLA for this machine can not be found.") return "" # Create a new ID & container to hold the data. new_id = self._container_registry.uniqueName("custom_material") - container_type = type(containers[0]) # Could be either a XMLMaterialProfile or a InstanceContainer + container_type = type(containers[0]) # Always XMLMaterialProfile, since we specifically clone the base_file duplicated_container = container_type(new_id) # Instead of duplicating we load the data from the basefile again. diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 10934c2d31..ce6fd47de6 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -15,7 +15,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.SettingFunction import SettingFunction from UM.Settings.ContainerStack import ContainerStack -from UM.Settings.DefinitionContainer import DefinitionContainer +from UM.Settings.Interfaces import DefinitionContainerInterface from typing import Optional, List, TYPE_CHECKING, Union if TYPE_CHECKING: @@ -74,11 +74,12 @@ class ExtruderManager(QObject): except KeyError: return 0 - @pyqtProperty("QVariantMap", notify=extrudersChanged) + @pyqtProperty("QVariantMap", notify = extrudersChanged) def extruderIds(self): map = {} - for position in self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()]: - map[position] = self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][position].getId() + global_stack_id = Application.getInstance().getGlobalContainerStack().getId() + for position in self._extruder_trains[global_stack_id]: + map[position] = self._extruder_trains[global_stack_id][position].getId() return map @pyqtSlot(str, result = str) @@ -150,14 +151,14 @@ class ExtruderManager(QObject): selected_nodes.append(node) # Then, figure out which nodes are used by those selected nodes. + global_stack = Application.getInstance().getGlobalContainerStack() + current_extruder_trains = self._extruder_trains.get(global_stack.getId()) for node in selected_nodes: extruder = node.callDecoration("getActiveExtruder") if extruder: object_extruders.add(extruder) - else: - global_stack = Application.getInstance().getGlobalContainerStack() - if global_stack.getId() in self._extruder_trains: - object_extruders.add(self._extruder_trains[global_stack.getId()]["0"].getId()) + elif current_extruder_trains: + object_extruders.add(current_extruder_trains["0"].getId()) self._selected_object_extruders = list(object_extruders) @@ -202,7 +203,7 @@ class ExtruderManager(QObject): # \param machine_definition The machine definition to add the extruders for. # \param machine_id The machine_id to add the extruders for. @deprecated("Use CuraStackBuilder", "2.6") - def addMachineExtruders(self, machine_definition: DefinitionContainer, machine_id: str) -> None: + def addMachineExtruders(self, machine_definition: DefinitionContainerInterface, machine_id: str) -> None: changed = False machine_definition_id = machine_definition.getId() if machine_id not in self._extruder_trains: @@ -236,6 +237,13 @@ class ExtruderManager(QObject): if machine_id not in self._extruder_trains: self._extruder_trains[machine_id] = {} changed = True + + # do not register if an extruder has already been registered at the position on this machine + if any(item.getId() == extruder_train.getId() for item in self._extruder_trains[machine_id].values()): + Logger.log("w", "Extruder [%s] has already been registered on machine [%s], not doing anything", + extruder_train.getId(), machine_id) + return + if extruder_train: self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train changed = True @@ -255,7 +263,7 @@ class ExtruderManager(QObject): # \param position The position of this extruder train in the extruder slots of the machine. # \param machine_id The id of the "global" stack this extruder is linked to. @deprecated("Use CuraStackBuilder::createExtruderStack", "2.6") - def createExtruderTrain(self, extruder_definition: DefinitionContainer, machine_definition: DefinitionContainer, + def createExtruderTrain(self, extruder_definition: DefinitionContainerInterface, machine_definition: DefinitionContainerInterface, position, machine_id: str) -> None: # Cache some things. container_registry = ContainerRegistry.getInstance() @@ -462,6 +470,8 @@ class ExtruderManager(QObject): for extruder in self.getMachineExtruders(machine_id): ContainerRegistry.getInstance().removeContainer(extruder.userChanges.getId()) ContainerRegistry.getInstance().removeContainer(extruder.getId()) + if machine_id in self._extruder_trains: + del self._extruder_trains[machine_id] ## Returns extruders for a specific machine. # @@ -515,7 +525,7 @@ class ExtruderManager(QObject): # # This is exposed to SettingFunction so it can be used in value functions. # - # \param key The key of the setting to retieve values for. + # \param key The key of the setting to retrieve values for. # # \return A list of values for all extruders. If an extruder does not have a value, it will not be in the list. # If no extruder has the value, the list will contain the global value. diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index 18a9969828..002778038b 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -1,22 +1,21 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from typing import Any - -from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot +from typing import Any, TYPE_CHECKING, Optional from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase -from UM.Settings.ContainerStack import ContainerStack, InvalidContainerStackError +from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerRegistry import ContainerRegistry -from UM.Settings.InstanceContainer import InstanceContainer -from UM.Settings.DefinitionContainer import DefinitionContainer from UM.Settings.Interfaces import ContainerInterface from . import Exceptions from .CuraContainerStack import CuraContainerStack from .ExtruderManager import ExtruderManager +if TYPE_CHECKING: + from cura.Settings.GlobalStack import GlobalStack + ## Represents an Extruder and its related containers. # # @@ -38,6 +37,10 @@ class ExtruderStack(CuraContainerStack): # For backward compatibility: Register the extruder with the Extruder Manager ExtruderManager.getInstance().registerExtruder(self, stack.id) + @override(ContainerStack) + def getNextStack(self) -> Optional["GlobalStack"]: + return super().getNextStack() + @classmethod def getLoadingPriority(cls) -> int: return 3 @@ -59,6 +62,13 @@ class ExtruderStack(CuraContainerStack): if not super().getProperty(key, "settable_per_extruder"): return self.getNextStack().getProperty(key, property_name) + limit_to_extruder = super().getProperty(key, "limit_to_extruder") + if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder): + if str(limit_to_extruder) in self.getNextStack().extruders: + result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name) + if result is not None: + return result + return super().getProperty(key, property_name) @override(CuraContainerStack) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 7491f8aa93..d46a9cbae1 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -1,12 +1,15 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer +from typing import Iterable import UM.Qt.ListModel from UM.Application import Application import UM.FlameProfiler from cura.Settings.ExtruderManager import ExtruderManager +from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders. +from cura.Settings.MachineManager import MachineManager #To listen to changes on the extruders of the currently active machine. ## Model that holds extruders. # @@ -66,16 +69,13 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self._add_global = False self._simple_names = False - self._active_extruder_stack = None + self._active_machine_extruders = [] # type: Iterable[ExtruderStack] + self._use_optional_extruder = False #Listen to changes. - Application.getInstance().globalContainerStackChanged.connect(self._updateExtruders) - manager = ExtruderManager.getInstance() - - self._updateExtruders() - - manager.activeExtruderChanged.connect(self._onActiveExtruderChanged) - self._onActiveExtruderChanged() + Application.getInstance().globalContainerStackChanged.connect(self._extrudersChanged) #When the machine is swapped we must update the active machine extruders. + ExtruderManager.getInstance().extrudersChanged.connect(self._extrudersChanged) #When the extruders change we must link to the stack-changed signal of the new extruder. + self._extrudersChanged() #Also calls _updateExtruders. def setAddGlobal(self, add): if add != self._add_global: @@ -89,6 +89,18 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def addGlobal(self): return self._add_global + useOptionalExtruderChanged = pyqtSignal() + + def setUseOptionalExtruder(self, use_optional_extruder): + if use_optional_extruder != self._use_optional_extruder: + self._use_optional_extruder = use_optional_extruder + self.useOptionalExtruderChanged.emit() + self._updateExtruders() + + @pyqtProperty(bool, fset = setUseOptionalExtruder, notify = useOptionalExtruderChanged) + def useOptionalExtruder(self): + return self._use_optional_extruder + ## Set the simpleNames property. def setSimpleNames(self, simple_names): if simple_names != self._simple_names: @@ -104,17 +116,31 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def simpleNames(self): return self._simple_names - def _onActiveExtruderChanged(self): - manager = ExtruderManager.getInstance() - active_extruder_stack = manager.getActiveExtruderStack() - if self._active_extruder_stack != active_extruder_stack: - if self._active_extruder_stack: - self._active_extruder_stack.containersChanged.disconnect(self._onExtruderStackContainersChanged) + ## Links to the stack-changed signal of the new extruders when an extruder + # is swapped out or added in the current machine. + # + # \param machine_id The machine for which the extruders changed. This is + # filled by the ExtruderManager.extrudersChanged signal when coming from + # that signal. Application.globalContainerStackChanged doesn't fill this + # signal; it's assumed to be the current printer in that case. + def _extrudersChanged(self, machine_id = None): + if machine_id is not None: + if Application.getInstance().getGlobalContainerStack() is None: + return #No machine, don't need to update the current machine's extruders. + if machine_id != Application.getInstance().getGlobalContainerStack().getId(): + return #Not the current machine. + #Unlink from old extruders. + for extruder in self._active_machine_extruders: + extruder.containersChanged.disconnect(self._onExtruderStackContainersChanged) - if active_extruder_stack: - # Update the model when the material container is changed - active_extruder_stack.containersChanged.connect(self._onExtruderStackContainersChanged) - self._active_extruder_stack = active_extruder_stack + #Link to new extruders. + self._active_machine_extruders = [] + extruder_manager = ExtruderManager.getInstance() + for extruder in extruder_manager.getExtruderStacks(): + extruder.containersChanged.connect(self._onExtruderStackContainersChanged) + self._active_machine_extruders.append(extruder) + + self._updateExtruders() #Since the new extruders may have different properties, update our own model. def _onExtruderStackContainersChanged(self, container): # Update when there is an empty container or material change @@ -184,5 +210,16 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): if changed: items.sort(key = lambda i: i["index"]) + # We need optional extruder to be last, so add it after we do sorting. + # This way we can simply intrepret the -1 of the index as the last item (which it now always is) + if self._use_optional_extruder: + item = { + "id": "zomg", + "name": "Not overridden", + "color": "#ffffff", + "index": -1, + "definition": "" + } + items.append(item) self.setItems(items) self.modelChanged.emit() diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index cee141cf93..9dfb8523b3 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -1,7 +1,7 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from typing import Any +from typing import Any, Dict from PyQt5.QtCore import pyqtProperty @@ -24,7 +24,7 @@ class GlobalStack(CuraContainerStack): self.addMetaDataEntry("type", "machine") # For backward compatibility - self._extruders = [] + self._extruders = {} # This property is used to track which settings we are calculating the "resolve" for # and if so, to bypass the resolve to prevent an infinite recursion that would occur @@ -34,8 +34,8 @@ class GlobalStack(CuraContainerStack): ## Get the list of extruders of this stack. # # \return The extruders registered with this stack. - @pyqtProperty("QVariantList") - def extruders(self) -> list: + @pyqtProperty("QVariantMap") + def extruders(self) -> Dict[str, "ExtruderStack"]: return self._extruders @classmethod @@ -52,8 +52,17 @@ class GlobalStack(CuraContainerStack): extruder_count = self.getProperty("machine_extruder_count", "value") if extruder_count and len(self._extruders) + 1 > extruder_count: Logger.log("w", "Adding extruder {meta} to {id} but its extruder count is {count}".format(id = self.id, count = extruder_count, meta = str(extruder.getMetaData()))) + return - self._extruders.append(extruder) + position = extruder.getMetaDataEntry("position") + if position is None: + Logger.log("w", "No position defined for extruder {extruder}, cannot add it to stack {stack}", extruder = extruder.id, stack = self.id) + return + + if any(item.getId() == extruder.id for item in self._extruders.values()): + Logger.log("w", "Extruder [%s] has already been added to this stack [%s]", extruder.id, self._id) + return + self._extruders[position] = extruder ## Overridden from ContainerStack # @@ -71,6 +80,7 @@ class GlobalStack(CuraContainerStack): if not self.definition.findDefinitions(key = key): return None + # Handle the "resolve" property. if self._shouldResolve(key, property_name): self._resolving_settings.add(key) resolve = super().getProperty(key, "resolve") @@ -78,6 +88,16 @@ class GlobalStack(CuraContainerStack): if resolve is not None: return resolve + # Handle the "limit_to_extruder" property. + limit_to_extruder = super().getProperty(key, "limit_to_extruder") + if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in self._extruders: + if super().getProperty(key, "settable_per_extruder"): + result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name) + if result is not None: + return result + else: + Logger.log("e", "Setting {setting} has limit_to_extruder but is not settable per extruder!", setting = key) + return super().getProperty(key, property_name) ## Overridden from ContainerStack diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0eafd33e94..6f1b82a7b8 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -220,6 +220,7 @@ class MachineManager(QObject): if old_index is not None: extruder_manager.setActiveExtruderIndex(old_index) + self._auto_materials_changed = {} #Processed all of them now. def _autoUpdateHotends(self): extruder_manager = ExtruderManager.getInstance() @@ -236,6 +237,7 @@ class MachineManager(QObject): if old_index is not None: extruder_manager.setActiveExtruderIndex(old_index) + self._auto_hotends_changed = {} #Processed all of them now. def _onGlobalContainerChanged(self): if self._global_container_stack: @@ -703,7 +705,7 @@ class MachineManager(QObject): # Depending on from/to material+current variant, a quality profile is chosen and set. @pyqtSlot(str) def setActiveMaterial(self, material_id: str): - with postponeSignals(*self._getContainerChangedSignals(), compress = True): + with postponeSignals(*self._getContainerChangedSignals()): containers = ContainerRegistry.getInstance().findInstanceContainers(id = material_id) if not containers or not self._active_container_stack: return @@ -768,7 +770,7 @@ class MachineManager(QObject): @pyqtSlot(str) def setActiveVariant(self, variant_id: str): - with postponeSignals(*self._getContainerChangedSignals(), compress = True): + with postponeSignals(*self._getContainerChangedSignals()): containers = ContainerRegistry.getInstance().findInstanceContainers(id = variant_id) if not containers or not self._active_container_stack: return @@ -1061,19 +1063,19 @@ class MachineManager(QObject): # If the machine that is being removed is the currently active machine, set another machine as the active machine. activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id) - ExtruderManager.getInstance().removeMachineExtruders(machine_id) + # activate a new machine before removing a machine because this is safer + if activate_new_machine: + machine_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") + other_machine_stacks = [s for s in machine_stacks if s.getId() != machine_id] + if other_machine_stacks: + Application.getInstance().setGlobalContainerStack(other_machine_stacks[0]) + ExtruderManager.getInstance().removeMachineExtruders(machine_id) containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id) for container in containers: ContainerRegistry.getInstance().removeContainer(container.getId()) ContainerRegistry.getInstance().removeContainer(machine_id) - if activate_new_machine: - stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") - if stacks: - Application.getInstance().setGlobalContainerStack(stacks[0]) - - @pyqtProperty(bool, notify = globalContainerChanged) def hasMaterials(self) -> bool: if self._global_container_stack: diff --git a/cura/Settings/SettingInheritanceManager.py b/cura/Settings/SettingInheritanceManager.py index ff0d1d81c0..d3a1655889 100644 --- a/cura/Settings/SettingInheritanceManager.py +++ b/cura/Settings/SettingInheritanceManager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal @@ -35,7 +35,7 @@ class SettingInheritanceManager(QObject): ## Get the keys of all children settings with an override. @pyqtSlot(str, result = "QStringList") def getChildrenKeysWithOverride(self, key): - definitions = self._global_container_stack.getBottom().findDefinitions(key=key) + definitions = self._global_container_stack.definition.findDefinitions(key=key) if not definitions: Logger.log("w", "Could not find definition for key [%s]", key) return [] @@ -55,7 +55,7 @@ class SettingInheritanceManager(QObject): Logger.log("w", "Unable to find extruder for current machine with index %s", extruder_index) return [] - definitions = self._global_container_stack.getBottom().findDefinitions(key=key) + definitions = self._global_container_stack.definition.findDefinitions(key=key) if not definitions: Logger.log("w", "Could not find definition for key [%s] (2)", key) return [] @@ -93,7 +93,7 @@ class SettingInheritanceManager(QObject): def _onPropertyChanged(self, key, property_name): if (property_name == "value" or property_name == "enabled") and self._global_container_stack: - definitions = self._global_container_stack.getBottom().findDefinitions(key = key) + definitions = self._global_container_stack.definition.findDefinitions(key = key) if not definitions: return @@ -198,6 +198,10 @@ class SettingInheritanceManager(QObject): def _update(self): self._settings_with_inheritance_warning = [] # Reset previous data. + # Make sure that the GlobalStack is not None. sometimes the globalContainerChanged signal gets here late. + if self._global_container_stack is None: + return + # Check all setting keys that we know of and see if they are overridden. for setting_key in self._global_container_stack.getAllKeys(): override = self._settingIsOverwritingInheritance(setting_key) @@ -205,7 +209,7 @@ class SettingInheritanceManager(QObject): self._settings_with_inheritance_warning.append(setting_key) # Check all the categories if any of their children have their inheritance overwritten. - for category in self._global_container_stack.getBottom().findDefinitions(type = "category"): + for category in self._global_container_stack.definition.findDefinitions(type = "category"): if self._recursiveCheck(category): self._settings_with_inheritance_warning.append(category.key) diff --git a/cura/ZOffsetDecorator.py b/cura/ZOffsetDecorator.py index 66dddfd390..d3ee5c8454 100644 --- a/cura/ZOffsetDecorator.py +++ b/cura/ZOffsetDecorator.py @@ -3,6 +3,7 @@ from UM.Scene.SceneNodeDecorator import SceneNodeDecorator ## A decorator that stores the amount an object has been moved below the platform. class ZOffsetDecorator(SceneNodeDecorator): def __init__(self): + super().__init__() self._z_offset = 0 def setZOffset(self, offset): diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index c0b8e73a8c..4d668b17ac 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -312,31 +312,20 @@ class ThreeMFWorkspaceReader(WorkspaceReader): return WorkspaceReader.PreReadResult.accepted ## Overrides an ExtruderStack in the given GlobalStack and returns the new ExtruderStack. - def _overrideExtruderStack(self, global_stack, extruder_index, extruder_file_content): - extruder_stack = global_stack.extruders[extruder_index] - machine_extruder_count = len(global_stack.extruders) + def _overrideExtruderStack(self, global_stack, extruder_file_content): + # get extruder position first + extruder_config = configparser.ConfigParser() + extruder_config.read_string(extruder_file_content) + if not extruder_config.has_option("metadata", "position"): + msg = "Could not find 'metadata/position' in extruder stack file" + Logger.log("e", "Could not find 'metadata/position' in extruder stack file") + raise RuntimeError(msg) + extruder_position = extruder_config.get("metadata", "position") - old_extruder_stack_id = extruder_stack.getId() - - # HACK: There are two cases: - # - the new ExtruderStack has the same ID as the one we are overriding - # - they don't have the same ID - # In the second case, directly overriding the existing ExtruderStack will leave the old stack file - # in the Cura directory, and this will cause a problem when we restart Cura. So, we always delete - # the existing file first. - self._container_registry._deleteFiles(extruder_stack) + extruder_stack = global_stack.extruders[extruder_position] # override the given extruder stack extruder_stack.deserialize(extruder_file_content) - # HACK: The deserialize() of ExtruderStack will add itself to the GlobalStack, which is redundant here. - # So we need to remove the new entries in the GlobalStack. - global_stack._extruders = global_stack._extruders[:machine_extruder_count] - - # HACK: clean and fill the container query cache again - if old_extruder_stack_id in self._container_registry._id_container_cache: - del self._container_registry._id_container_cache[old_extruder_stack_id] - new_extruder_stack_id = extruder_stack.getId() - self._container_registry._id_container_cache[new_extruder_stack_id] = extruder_stack # return the new ExtruderStack return extruder_stack @@ -393,12 +382,23 @@ class ThreeMFWorkspaceReader(WorkspaceReader): global_stack_id_original = self._stripFileToId(global_stack_file) global_stack_id_new = global_stack_id_original global_stack_need_rename = False + + extruder_stack_id_map = {} # new and old ExtruderStack IDs map if self._resolve_strategies["machine"] == "new": # We need a new id if the id already exists if self._container_registry.findContainerStacks(id = global_stack_id_original): global_stack_id_new = self.getNewId(global_stack_id_original) global_stack_need_rename = True + for each_extruder_stack_file in extruder_stack_files: + old_container_id = self._stripFileToId(each_extruder_stack_file) + new_container_id = old_container_id + if self._container_registry.findContainerStacks(id = old_container_id): + # get a new name for this extruder + new_container_id = self.getNewId(old_container_id) + + extruder_stack_id_map[old_container_id] = new_container_id + # TODO: For the moment we use pretty naive existence checking. If the ID is the same, we assume in quite a few # TODO: cases that the container loaded is the same (most notable in materials & definitions). # TODO: It might be possible that we need to add smarter checking in the future. @@ -454,13 +454,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_id = self._stripFileToId(instance_container_file) serialized = archive.open(instance_container_file).read().decode("utf-8") - # HACK! we ignore the "metadata/type = quality" instance containers! + # HACK! we ignore "quality" and "variant" instance containers! parser = configparser.ConfigParser() parser.read_string(serialized) if not parser.has_option("metadata", "type"): Logger.log("w", "Cannot find metadata/type in %s, ignoring it", instance_container_file) continue - if parser.get("metadata", "type") == "quality": + if parser.get("metadata", "type") in self._ignored_instance_container_types: continue instance_container = InstanceContainer(container_id) @@ -470,6 +470,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader): container_type = instance_container.getMetaDataEntry("type") Job.yieldThread() + # + # IMPORTANT: + # If an instance container (or maybe other type of container) exists, and user chooses "Create New", + # we need to rename this container and all references to it, and changing those references are VERY + # HARD. + # if container_type in self._ignored_instance_container_types: # Ignore certain instance container types Logger.log("w", "Ignoring instance container [%s] with type [%s]", container_id, container_type) @@ -486,9 +492,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): instance_container.setDirty(True) elif self._resolve_strategies["machine"] == "new": # The machine is going to get a spiffy new name, so ensure that the id's of user settings match. - extruder_id = instance_container.getMetaDataEntry("extruder", None) - if extruder_id: - new_extruder_id = self.getNewId(extruder_id) + old_extruder_id = instance_container.getMetaDataEntry("extruder", None) + if old_extruder_id: + new_extruder_id = extruder_stack_id_map[old_extruder_id] new_id = new_extruder_id + "_current_settings" instance_container._id = new_id instance_container.setName(new_id) @@ -521,17 +527,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader): elif self._resolve_strategies[container_type] == "new": # TODO: how should we handle the case "new" for quality_changes and definition_changes? + instance_container.setName(self._container_registry.uniqueName(instance_container.getName())) new_changes_container_id = self.getNewId(instance_container.getId()) instance_container._id = new_changes_container_id - instance_container.setName(new_changes_container_id) # TODO: we don't know the following is correct or not, need to verify # AND REFACTOR!!! if self._resolve_strategies["machine"] == "new": # The machine is going to get a spiffy new name, so ensure that the id's of user settings match. - extruder_id = instance_container.getMetaDataEntry("extruder", None) - if extruder_id: - new_extruder_id = self.getNewId(extruder_id) + old_extruder_id = instance_container.getMetaDataEntry("extruder", None) + if old_extruder_id: + new_extruder_id = extruder_stack_id_map[old_extruder_id] instance_container.setMetaDataEntry("extruder", new_extruder_id) machine_id = instance_container.getMetaDataEntry("machine", None) @@ -631,13 +637,26 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if self._resolve_strategies["machine"] == "override": # NOTE: This is the same code as those in the lower part # deserialize new extruder stack over the current ones - stack = self._overrideExtruderStack(global_stack, index, extruder_file_content) + stack = self._overrideExtruderStack(global_stack, extruder_file_content) elif self._resolve_strategies["machine"] == "new": # create a new extruder stack from this one - new_id = self.getNewId(container_id) + new_id = extruder_stack_id_map[container_id] stack = ExtruderStack(new_id) - stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8")) + + # HACK: the global stack can have a new name, so we need to make sure that this extruder stack + # references to the new name instead of the old one. Normally, this can be done after + # deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize() + # also does addExtruder() to its machine stack, so we have to make sure that it's pointing + # to the right machine BEFORE deserialization. + extruder_config = configparser.ConfigParser() + extruder_config.read_string(extruder_file_content) + extruder_config.set("metadata", "machine", global_stack_id_new) + tmp_string_io = io.StringIO() + extruder_config.write(tmp_string_io) + extruder_file_content = tmp_string_io.getvalue() + + stack.deserialize(extruder_file_content) # Ensure a unique ID and name stack._id = new_id @@ -649,22 +668,31 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # No extruder stack with the same ID can be found if self._resolve_strategies["machine"] == "override": # deserialize new extruder stack over the current ones - stack = self._overrideExtruderStack(global_stack, index, extruder_file_content) + stack = self._overrideExtruderStack(global_stack, extruder_file_content) elif self._resolve_strategies["machine"] == "new": # container not found, create a new one stack = ExtruderStack(container_id) - stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8")) + + # HACK: the global stack can have a new name, so we need to make sure that this extruder stack + # references to the new name instead of the old one. Normally, this can be done after + # deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize() + # also does addExtruder() to its machine stack, so we have to make sure that it's pointing + # to the right machine BEFORE deserialization. + extruder_config = configparser.ConfigParser() + extruder_config.read_string(extruder_file_content) + extruder_config.set("metadata", "machine", global_stack_id_new) + tmp_string_io = io.StringIO() + extruder_config.write(tmp_string_io) + extruder_file_content = tmp_string_io.getvalue() + + stack.deserialize(extruder_file_content) self._container_registry.addContainer(stack) extruder_stacks_added.append(stack) containers_added.append(stack) else: Logger.log("w", "Unknown resolve strategy: %s" % str(self._resolve_strategies["machine"])) - if global_stack_need_rename: - if stack.getMetaDataEntry("machine"): - stack.setMetaDataEntry("machine", global_stack_id_new) - extruder_stacks.append(stack) except: Logger.logException("w", "We failed to serialize the stack. Trying to clean up.") @@ -700,13 +728,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if self._resolve_strategies[changes_container_type] == "new": # Quality changes needs to get a new ID, added to registry and to the right stacks for each_changes_container in quality_and_definition_changes_instance_containers: - old_id = each_changes_container.getId() - each_changes_container.setName(self._container_registry.uniqueName(each_changes_container.getName())) - # We're not really supposed to change the ID in normal cases, but this is an exception. - each_changes_container._id = self.getNewId(each_changes_container.getId()) - - # The container was not added yet, as it didn't have an unique ID. It does now, so add it. - self._container_registry.addContainer(each_changes_container) + # NOTE: The renaming and giving new IDs are possibly redundant because they are done in the + # instance container loading part. + new_id = each_changes_container.getId() # Find the old (current) changes container in the global stack if changes_container_type == "quality_changes": @@ -723,7 +747,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Replace the quality/definition changes container if it's in the GlobalStack # NOTE: we can get an empty container here, but the IDs will not match, # so this comparison is fine. - if old_container.getId() == old_id: + if self._id_mapping.get(old_container.getId()) == new_id: if changes_container_type == "quality_changes": global_stack.qualityChanges = each_changes_container elif changes_container_type == "definition_changes": @@ -746,7 +770,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # NOTE: we can get an empty container here, but the IDs will not match, # so this comparison is fine. - if changes_container.getId() == old_id: + if self._id_mapping.get(changes_container.getId()) == new_id: if changes_container_type == "quality_changes": each_extruder_stack.qualityChanges = each_changes_container elif changes_container_type == "definition_changes": diff --git a/plugins/GCodeWriter/GCodeWriter.py b/plugins/GCodeWriter/GCodeWriter.py index ad730fbe2a..47ccc21bcd 100644 --- a/plugins/GCodeWriter/GCodeWriter.py +++ b/plugins/GCodeWriter/GCodeWriter.py @@ -85,6 +85,7 @@ class GCodeWriter(MeshWriter): for key in instance_container1.getAllKeys(): flat_container.setProperty(key, "value", instance_container1.getProperty(key, "value")) + return flat_container @@ -106,6 +107,9 @@ class GCodeWriter(MeshWriter): return "" flat_global_container = self._createFlattenedContainerInstance(stack.getTop(), container_with_profile) + # If the quality changes is not set, we need to set type manually + if flat_global_container.getMetaDataEntry("type", None) is None: + flat_global_container.addMetaDataEntry("type", "quality_changes") # Ensure that quality_type is set. (Can happen if we have empty quality changes). if flat_global_container.getMetaDataEntry("quality_type", None) is None: @@ -120,6 +124,9 @@ class GCodeWriter(MeshWriter): Logger.log("w", "No extruder quality profile found, not writing quality for extruder %s to file!", extruder.getId()) continue flat_extruder_quality = self._createFlattenedContainerInstance(extruder.getTop(), extruder_quality) + # If the quality changes is not set, we need to set type manually + if flat_extruder_quality.getMetaDataEntry("type", None) is None: + flat_extruder_quality.addMetaDataEntry("type", "quality_changes") # Ensure that extruder is set. (Can happen if we have empty quality changes). if flat_extruder_quality.getMetaDataEntry("extruder", None) is None: diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index 654030b013..23dc7f073f 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -341,7 +341,6 @@ Cura.MachineAction sourceComponent: numericTextFieldWithUnit property var propertyProvider: gantryHeightProvider property string unit: catalog.i18nc("@label", "mm") - property bool forceUpdateOnChange: false } Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height } @@ -385,7 +384,6 @@ Cura.MachineAction sourceComponent: numericTextFieldWithUnit property var propertyProvider: materialDiameterProvider property string unit: catalog.i18nc("@label", "mm") - property bool forceUpdateOnChange: false } Label { @@ -399,7 +397,6 @@ Cura.MachineAction sourceComponent: numericTextFieldWithUnit property var propertyProvider: machineNozzleSizeProvider property string unit: catalog.i18nc("@label", "mm") - property bool forceUpdateOnChange: false } } } @@ -550,7 +547,6 @@ Cura.MachineAction sourceComponent: numericTextFieldWithUnit property var propertyProvider: extruderNozzleSizeProvider property string unit: catalog.i18nc("@label", "mm") - property bool forceUpdateOnChange: false } Label @@ -564,6 +560,7 @@ Cura.MachineAction property var propertyProvider: extruderOffsetXProvider property string unit: catalog.i18nc("@label", "mm") property bool forceUpdateOnChange: true + property bool allowNegative: true } Label { @@ -576,6 +573,7 @@ Cura.MachineAction property var propertyProvider: extruderOffsetYProvider property string unit: catalog.i18nc("@label", "mm") property bool forceUpdateOnChange: true + property bool allowNegative: true } } @@ -655,17 +653,21 @@ Cura.MachineAction Item { height: textField.height width: textField.width + + property bool _allowNegative: (typeof(allowNegative) === 'undefined') ? false : allowNegative + property bool _forceUpdateOnChange: (typeof(forceUpdateOnChange) === 'undefined') ? false: forceUpdateOnChange + TextField { id: textField text: (propertyProvider.properties.value) ? propertyProvider.properties.value : "" - validator: RegExpValidator { regExp: /[0-9\.]{0,6}/ } + validator: RegExpValidator { regExp: _allowNegative ? /-?[0-9\.]{0,6}/ : /[0-9\.]{0,6}/ } onEditingFinished: { if (propertyProvider && text != propertyProvider.properties.value) { propertyProvider.setPropertyValue("value", text); - if(forceUpdateOnChange) + if(_forceUpdateOnChange) { var extruderIndex = ExtruderManager.activeExtruderIndex; manager.forceUpdate(); diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml index 27271f0d15..f9af47fc7a 100644 --- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml @@ -12,7 +12,6 @@ Cura.MachineAction anchors.fill: parent; property var selectedPrinter: null property bool completeProperties: true - property var connectingToPrinter: null Connections { @@ -33,9 +32,8 @@ Cura.MachineAction if(base.selectedPrinter && base.completeProperties) { var printerKey = base.selectedPrinter.getKey() - if(connectingToPrinter != printerKey) { - // prevent an infinite loop - connectingToPrinter = printerKey; + if(manager.getStoredKey() != printerKey) + { manager.setKey(printerKey); completed(); } diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py b/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py index d5bb08bb5c..055d28b3ab 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py @@ -70,8 +70,8 @@ _printer_translations_profiles = { # as a set for which profiles were built-in. _profile_translations = { "Low Quality": "low", - "Fine": "normal", - "Extra Fine": "high", + "Normal Quality": "normal", + "High Quality": "high", "Ulti Quality": "high", #This one doesn't have an equivalent. Map it to high. "abs_0.25_normal": "um2p_abs_0.25_normal", "abs_0.4_fast": "um2p_abs_0.4_fast", diff --git a/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py b/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py index a24473f65d..5ff589c4e3 100644 --- a/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py @@ -22,9 +22,10 @@ def getMetaData(): ("preferences", 4000000): ("preferences", 4000001, upgrade.upgradePreferences), # NOTE: All the instance containers share the same general/version, so we have to update all of them # if any is updated. - ("quality_changes", 2000000): ("quality_changes", 2000001, upgrade.upgradeInstanceContainer), - ("user", 2000000): ("user", 2000001, upgrade.upgradeInstanceContainer), - ("quality", 2000000): ("quality", 2000001, upgrade.upgradeInstanceContainer), + ("quality_changes", 2000000): ("quality_changes", 2000001, upgrade.upgradeInstanceContainer), + ("user", 2000000): ("user", 2000001, upgrade.upgradeInstanceContainer), + ("quality", 2000000): ("quality", 2000001, upgrade.upgradeInstanceContainer), + ("definition_changes", 2000000): ("definition_changes", 2000001, upgrade.upgradeInstanceContainer), }, "sources": { "quality_changes": { @@ -39,6 +40,10 @@ def getMetaData(): "get_version": upgrade.getCfgVersion, "location": {"./user"} }, + "definition_changes": { + "get_version": upgrade.getCfgVersion, + "location": {"./machine_instances"} + } } } diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 7bdfaf404d..bddb801030 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -14,9 +14,13 @@ from cura.CuraApplication import CuraApplication import UM.Dictionary from UM.Settings.InstanceContainer import InstanceContainer, InvalidInstanceError from UM.Settings.ContainerRegistry import ContainerRegistry +from cura.Settings.CuraContainerRegistry import CuraContainerRegistry + ## Handles serializing and deserializing material containers from an XML file class XmlMaterialProfile(InstanceContainer): + Version = 1 + def __init__(self, container_id, *args, **kwargs): super().__init__(container_id, *args, **kwargs) self._inherited_files = [] @@ -386,11 +390,13 @@ class XmlMaterialProfile(InstanceContainer): self._path = "" def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]: - return "material" + return "materials" def getVersionFromSerialized(self, serialized: str) -> Optional[int]: - version = None data = ET.fromstring(serialized) + + # get format version + version = None metadata = data.iterfind("./um:metadata/*", self.__namespaces) for entry in metadata: tag_name = _tag_without_namespace(entry) @@ -402,14 +408,29 @@ class XmlMaterialProfile(InstanceContainer): break if version is None: raise InvalidInstanceError("Missing version in metadata") - return version + + # get setting version + if "version" in data.attrib: + setting_version = self.xmlVersionToSettingVersion(data.attrib["version"]) + else: + setting_version = self.xmlVersionToSettingVersion("1.2") + + if version is None: + raise InvalidInstanceError("Missing version in metadata") + + return version * 1000000 + setting_version ## Overridden from InstanceContainer def deserialize(self, serialized): # update the serialized data first from UM.Settings.Interfaces import ContainerInterface serialized = ContainerInterface.deserialize(self, serialized) - data = ET.fromstring(serialized) + + try: + data = ET.fromstring(serialized) + except: + Logger.logException("e", "An exception occured while parsing the material profile") + return # Reset previous metadata self.clearData() # Ensure any previous data is gone. @@ -544,7 +565,7 @@ class XmlMaterialProfile(InstanceContainer): variant_containers = ContainerRegistry.getInstance().findInstanceContainers(definition = definition.id, name = hotend_id) if not variant_containers: - Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id) + #Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id) continue hotend_compatibility = machine_compatibility diff --git a/plugins/XmlMaterialProfile/XmlMaterialUpgrader.py b/plugins/XmlMaterialProfile/XmlMaterialUpgrader.py new file mode 100644 index 0000000000..8f1d1e9ec6 --- /dev/null +++ b/plugins/XmlMaterialProfile/XmlMaterialUpgrader.py @@ -0,0 +1,62 @@ +# Copyright (c) 2017 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +import xml.etree.ElementTree as ET + +from UM.VersionUpgrade import VersionUpgrade + + +class XmlMaterialUpgrader(VersionUpgrade): + def getXmlVersion(self, serialized): + data = ET.fromstring(serialized) + + # get format version + version = None + metadata = data.iterfind("./um:metadata/*") + for entry in metadata: + tag_name = entry.tag + if tag_name == "version": + try: + version = int(entry.text) + except Exception as e: + raise ValueError("Invalid version string '%s': %s" % (entry.text, e)) + break + if version is None: + raise RuntimeError("Missing version in metadata") + + # get setting version + if "version" in data.attrib: + setting_version = self._xmlVersionToSettingVersion(data.attrib["version"]) + else: + setting_version = self._xmlVersionToSettingVersion("1.2") + + if version is None: + raise RuntimeError("Missing version in metadata") + + return version * 1000000 + setting_version + + def _xmlVersionToSettingVersion(self, xml_version: str) -> int: + if xml_version == "1.3": + return 1 + return 0 #Older than 1.3. + + def upgradeMaterial(self, serialised, filename): + data = ET.fromstring(serialised) + + # update version + metadata = data.iterfind("./um:metadata/*", {"um": "http://www.ultimaker.com/material"}) + for entry in metadata: + if _tag_without_namespace(entry) == "version": + entry.text = "2" + break + + data.attrib["version"] = "1.3" + + # this makes sure that the XML header states encoding="utf-8" + new_serialised = ET.tostring(data, encoding="utf-8").decode("utf-8") + + return [filename], [new_serialised] + + +def _tag_without_namespace(element): + return element.tag[element.tag.rfind("}") + 1:] diff --git a/plugins/XmlMaterialProfile/__init__.py b/plugins/XmlMaterialProfile/__init__.py index 213b9a358a..d98f2efb3d 100644 --- a/plugins/XmlMaterialProfile/__init__.py +++ b/plugins/XmlMaterialProfile/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. from . import XmlMaterialProfile +from . import XmlMaterialUpgrader from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.i18n import i18nCatalog + + catalog = i18nCatalog("cura") +upgrader = XmlMaterialUpgrader.XmlMaterialUpgrader() + def getMetaData(): return { @@ -19,15 +24,36 @@ def getMetaData(): "settings_container": { "type": "material", "mimetype": "application/x-ultimaker-material-profile" + }, + "version_upgrade": { + ("materials", 1000000): ("materials", 1000001, upgrader.upgradeMaterial), + }, + "sources": { + "materials": { + "get_version": upgrader.getXmlVersion, + "location": {"./materials"} + }, } } + def register(app): + # add Mime type mime_type = MimeType( name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile", suffixes = [ "xml.fdm_material" ] ) MimeTypeDatabase.addMimeType(mime_type) - return { "settings_container": XmlMaterialProfile.XmlMaterialProfile("default_xml_material_profile") } + # add upgrade version + from cura.CuraApplication import CuraApplication + from UM.VersionUpgradeManager import VersionUpgradeManager + VersionUpgradeManager.getInstance().registerCurrentVersion( + ("materials", XmlMaterialProfile.XmlMaterialProfile.Version * 1000000 + CuraApplication.SettingVersion), + (CuraApplication.ResourceTypes.MaterialInstanceContainer, "application/x-uranium-instancecontainer") + ) + + return {"version_upgrade": upgrader, + "settings_container": XmlMaterialProfile.XmlMaterialProfile("default_xml_material_profile"), + } diff --git a/resources/definitions/cartesio.def.json b/resources/definitions/cartesio.def.json index 6567f61fb3..f14f6572e4 100644 --- a/resources/definitions/cartesio.def.json +++ b/resources/definitions/cartesio.def.json @@ -19,7 +19,7 @@ "variants_name": "Nozzle size", "preferred_variant": "*0.8*", "preferred_material": "*pla*", - "preferred_quality": "*high*", + "preferred_quality": "*normal*", "machine_extruder_trains": { @@ -29,7 +29,7 @@ "3": "cartesio_extruder_3" }, "platform": "cartesio_platform.stl", - "platform_offset": [ -120, -1.5, 130], + "platform_offset": [ -220, -5, 150], "first_start_actions": ["MachineSettingsAction"], "supported_actions": ["MachineSettingsAction"] }, diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ea4322d580..aba2d632df 100755 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -778,7 +778,7 @@ "type": "float", "enabled": "support_enable and support_roof_enable", "limit_to_extruder": "support_roof_extruder_nr", - "value": "support_interface_line_width", + "value": "extruderValue(support_roof_extruder_nr, 'support_interface_line_width')", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -794,7 +794,7 @@ "type": "float", "enabled": "support_enable and support_bottom_enable", "limit_to_extruder": "support_bottom_extruder_nr", - "value": "support_interface_line_width", + "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_line_width')", "settable_per_mesh": false, "settable_per_extruder": true } @@ -2072,7 +2072,7 @@ "minimum_value": "0.1", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "150", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "support_interface_enable and support_enable", "limit_to_extruder": "support_interface_extruder_nr", "value": "speed_support / 1.5", "settable_per_mesh": false, @@ -2089,9 +2089,9 @@ "minimum_value": "0.1", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "150", - "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "support_roof_enable and support_enable", "limit_to_extruder": "support_roof_extruder_nr", - "value": "speed_support_interface", + "value": "extruderValue(support_roof_extruder_nr, 'speed_support_interface')", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -2105,9 +2105,9 @@ "minimum_value": "0.1", "maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)", "maximum_value_warning": "150", - "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "support_bottom_enable and support_enable", "limit_to_extruder": "support_bottom_extruder_nr", - "value": "speed_support_interface", + "value": "extruderValue(support_bottom_extruder_nr, 'speed_support_interface')", "settable_per_mesh": false, "settable_per_extruder": true } @@ -2399,7 +2399,7 @@ "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "resolveOrValue('acceleration_enabled') and support_interface_enable and support_enable", "limit_to_extruder": "support_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true, @@ -2412,11 +2412,11 @@ "unit": "mm/s²", "type": "float", "default_value": 3000, - "value": "acceleration_support_interface", + "value": "extruderValue(support_roof_extruder_nr, 'acceleration_support_interface')", "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "acceleration_enabled and support_roof_enable and support_enable", "limit_to_extruder": "support_roof_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true @@ -2428,11 +2428,11 @@ "unit": "mm/s²", "type": "float", "default_value": 3000, - "value": "acceleration_support_interface", + "value": "extruderValue(support_bottom_extruder_nr, 'acceleration_support_interface')", "minimum_value": "0.1", "minimum_value_warning": "100", "maximum_value_warning": "10000", - "enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "acceleration_enabled and support_bottom_enable and support_enable", "limit_to_extruder": "support_bottom_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true @@ -2669,7 +2669,7 @@ "value": "jerk_support", "minimum_value": "0.1", "maximum_value_warning": "50", - "enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "resolveOrValue('jerk_enabled') and support_interface_enable and support_enable", "limit_to_extruder": "support_interface_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true, @@ -2682,10 +2682,10 @@ "unit": "mm/s", "type": "float", "default_value": 20, - "value": "jerk_support_interface", + "value": "extruderValue(support_roof_extruder_nr, 'jerk_support_interface')", "minimum_value": "0.1", "maximum_value_warning": "50", - "enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "resolveOrValue('jerk_enabled') and support_roof_enable and support_enable", "limit_to_extruder": "support_roof_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true @@ -2697,10 +2697,10 @@ "unit": "mm/s", "type": "float", "default_value": 20, - "value": "jerk_support_interface", + "value": "extruderValue(support_roof_extruder_nr, 'jerk_support_interface')", "minimum_value": "0.1", "maximum_value_warning": "50", - "enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "resolveOrValue('jerk_enabled') and support_bottom_enable and support_enable", "limit_to_extruder": "support_bottom_extruder_nr", "settable_per_mesh": false, "settable_per_extruder": true @@ -3285,7 +3285,7 @@ "default_value": 0.1, "type": "float", "enabled": "support_enable", - "value": "extruderValue(support_extruder_nr, 'support_z_distance')", + "value": "extruderValue(support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr, 'support_z_distance')", "limit_to_extruder": "support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr", "settable_per_mesh": true }, @@ -3297,7 +3297,7 @@ "minimum_value": "0", "maximum_value_warning": "machine_nozzle_size", "default_value": 0.1, - "value": "extruderValue(support_extruder_nr, 'support_z_distance') if resolveOrValue('support_type') == 'everywhere' else 0", + "value": "extruderValue(support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr, 'support_z_distance') if support_type == 'everywhere' else 0", "limit_to_extruder": "support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr", "type": "float", "enabled": "support_enable and resolveOrValue('support_type') == 'everywhere'", @@ -3340,11 +3340,11 @@ "unit": "mm", "type": "float", "minimum_value": "0", - "maximum_value_warning": "extruderValue(support_infill_extruder_nr, 'support_xy_distance')", + "maximum_value_warning": "support_xy_distance", "default_value": 0.2, "value": "machine_nozzle_size / 2", "limit_to_extruder": "support_infill_extruder_nr", - "enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_xy_overrides_z') == 'z_overrides_xy'", + "enabled": "support_enable and support_xy_overrides_z == 'z_overrides_xy'", "settable_per_mesh": true }, "support_bottom_stair_step_height": @@ -3416,7 +3416,7 @@ "description": "Generate a dense slab of material between the top of support and the model. This will create a skin between the model and support.", "type": "bool", "default_value": false, - "value": "support_interface_enable", + "value": "extruderValue(support_roof_extruder_nr, 'support_interface_enable')", "limit_to_extruder": "support_roof_extruder_nr", "enabled": "support_enable", "settable_per_mesh": true @@ -3427,7 +3427,7 @@ "description": "Generate a dense slab of material between the bottom of the support and the model. This will create a skin between the model and support.", "type": "bool", "default_value": false, - "value": "support_interface_enable", + "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_enable')", "limit_to_extruder": "support_bottom_extruder_nr", "enabled": "support_enable", "settable_per_mesh": true @@ -3442,10 +3442,10 @@ "type": "float", "default_value": 1, "minimum_value": "0", - "minimum_value_warning": "0.2 + resolveOrValue('layer_height')", + "minimum_value_warning": "0.2 + layer_height", "maximum_value_warning": "10", "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "support_interface_enable and support_enable", "settable_per_mesh": true, "children": { @@ -3457,11 +3457,11 @@ "type": "float", "default_value": 1, "minimum_value": "0", - "minimum_value_warning": "0.2 + resolveOrValue('layer_height')", + "minimum_value_warning": "0.2 + layer_height", "maximum_value_warning": "10", "value": "extruderValue(support_roof_extruder_nr, 'support_interface_height')", "limit_to_extruder": "support_roof_extruder_nr", - "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": true }, "support_bottom_height": @@ -3473,10 +3473,10 @@ "default_value": 1, "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_height')", "minimum_value": "0", - "minimum_value_warning": "min(0.2 + resolveOrValue('layer_height'), extruderValue(support_bottom_extruder_nr, 'support_bottom_stair_step_height'))", + "minimum_value_warning": "min(0.2 + layer_height, support_bottom_stair_step_height)", "maximum_value_warning": "10", "limit_to_extruder": "support_bottom_extruder_nr", - "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "support_bottom_enable and support_enable", "settable_per_mesh": true } } @@ -3490,7 +3490,7 @@ "minimum_value": "0", "maximum_value_warning": "support_interface_height", "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "support_interface_enable and support_enable", "settable_per_mesh": true }, "support_interface_density": @@ -3503,7 +3503,7 @@ "minimum_value": "0", "maximum_value_warning": "100", "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "support_interface_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": true, "children": @@ -3518,7 +3518,8 @@ "minimum_value": "0", "maximum_value": "100", "limit_to_extruder": "support_roof_extruder_nr", - "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "support_roof_enable and support_enable", + "value": "extruderValue(support_roof_extruder_nr, 'support_interface_density')", "settable_per_mesh": false, "settable_per_extruder": true, "children": @@ -3534,7 +3535,7 @@ "minimum_value_warning": "support_roof_line_width - 0.0001", "value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == 'grid' else (3 if support_roof_pattern == 'triangles' else 1))", "limit_to_extruder": "support_roof_extruder_nr", - "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": true } @@ -3550,7 +3551,8 @@ "minimum_value": "0", "maximum_value": "100", "limit_to_extruder": "support_bottom_extruder_nr", - "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "support_bottom_enable and support_enable", + "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_density')", "settable_per_mesh": false, "settable_per_extruder": true, "children": @@ -3566,7 +3568,7 @@ "minimum_value_warning": "support_bottom_line_width - 0.0001", "value": "0 if support_bottom_density == 0 else (support_bottom_line_width * 100) / support_bottom_density * (2 if support_bottom_pattern == 'grid' else (3 if support_bottom_pattern == 'triangles' else 1))", "limit_to_extruder": "support_bottom_extruder_nr", - "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "support_bottom_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": true } @@ -3590,7 +3592,7 @@ }, "default_value": "concentric", "limit_to_extruder": "support_interface_extruder_nr", - "enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable", + "enabled": "support_interface_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": true, "children": @@ -3610,9 +3612,9 @@ "zigzag": "Zig Zag" }, "default_value": "concentric", - "value": "support_interface_pattern", + "value": "extruderValue(support_roof_extruder_nr, 'support_interface_pattern')", "limit_to_extruder": "support_roof_extruder_nr", - "enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable", + "enabled": "support_roof_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": true }, @@ -3631,9 +3633,9 @@ "zigzag": "Zig Zag" }, "default_value": "concentric", - "value": "support_interface_pattern", + "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_pattern')", "limit_to_extruder": "support_bottom_extruder_nr", - "enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable", + "enabled": "support_bottom_enable and support_enable", "settable_per_mesh": false, "settable_per_extruder": true } @@ -3660,7 +3662,7 @@ "minimum_value": "0", "minimum_value_warning": "2 * machine_nozzle_size", "maximum_value_warning": "20", - "enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_use_towers')", + "enabled": "support_enable and support_use_towers", "settable_per_mesh": true }, "support_minimal_diameter": @@ -3674,8 +3676,8 @@ "minimum_value": "0", "minimum_value_warning": "2 * machine_nozzle_size", "maximum_value_warning": "20", - "maximum_value": "extruderValue(support_infill_extruder_nr, 'support_tower_diameter')", - "enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_use_towers')", + "maximum_value": "support_tower_diameter", + "enabled": "support_enable and support_use_towers", "settable_per_mesh": true }, "support_tower_roof_angle": @@ -3688,7 +3690,7 @@ "maximum_value": "90", "default_value": 65, "limit_to_extruder": "support_infill_extruder_nr", - "enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_use_towers')", + "enabled": "support_enable and support_use_towers", "settable_per_mesh": true } } @@ -3914,7 +3916,7 @@ "value": "resolveOrValue('layer_height')", "minimum_value": "0.001", "minimum_value_warning": "0.04", - "maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'machine_nozzle_size')", + "maximum_value_warning": "0.75 * machine_nozzle_size", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, @@ -3929,8 +3931,8 @@ "default_value": 0.4, "value": "line_width", "minimum_value": "0.001", - "minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 0.1", - "maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 2", + "minimum_value_warning": "machine_nozzle_size * 0.1", + "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, @@ -3944,8 +3946,8 @@ "type": "float", "default_value": 0.4, "minimum_value": "0", - "minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_surface_line_width')", - "maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_surface_line_width') * 3", + "minimum_value_warning": "raft_surface_line_width", + "maximum_value_warning": "raft_surface_line_width * 3", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "value": "raft_surface_line_width", "settable_per_mesh": false, @@ -3962,7 +3964,7 @@ "value": "resolveOrValue('layer_height') * 1.5", "minimum_value": "0.001", "minimum_value_warning": "0.04", - "maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'machine_nozzle_size')", + "maximum_value_warning": "0.75 * machine_nozzle_size", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, @@ -3977,8 +3979,8 @@ "default_value": 0.7, "value": "line_width * 2", "minimum_value": "0.001", - "minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 0.5", - "maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 3", + "minimum_value_warning": "machine_nozzle_size * 0.5", + "maximum_value_warning": "machine_nozzle_size * 3", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, @@ -3993,7 +3995,7 @@ "default_value": 0.9, "value": "raft_interface_line_width + 0.2", "minimum_value": "0", - "minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_interface_line_width')", + "minimum_value_warning": "raft_interface_line_width", "maximum_value_warning": "15.0", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, @@ -4010,7 +4012,7 @@ "value": "resolveOrValue('layer_height_0') * 1.2", "minimum_value": "0.001", "minimum_value_warning": "0.04", - "maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'raft_base_line_width')", + "maximum_value_warning": "0.75 * raft_base_line_width", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, @@ -4024,9 +4026,9 @@ "type": "float", "default_value": 0.8, "minimum_value": "0.001", - "value": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 2", - "minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 0.5", - "maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 3", + "value": "machine_nozzle_size * 2", + "minimum_value_warning": "machine_nozzle_size * 0.5", + "maximum_value_warning": "machine_nozzle_size * 3", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, "settable_per_extruder": true, @@ -4041,7 +4043,7 @@ "default_value": 1.6, "value": "raft_base_line_width * 2", "minimum_value": "0", - "minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_base_line_width')", + "minimum_value_warning": "raft_base_line_width", "maximum_value_warning": "100", "enabled": "resolveOrValue('adhesion_type') == 'raft'", "settable_per_mesh": false, @@ -4634,6 +4636,18 @@ "settable_per_mesh": true, "enabled": "mold_enabled" }, + "mold_roof_height": + { + "label": "Mold Roof Height", + "description": "The height above horizontal parts in your model which to print mold.", + "unit": "mm", + "type": "float", + "minimum_value": "0", + "maximum_value_warning": "5", + "default_value": 0.5, + "settable_per_mesh": true, + "enabled": "mold_enabled" + }, "mold_angle": { "label": "Mold Angle", diff --git a/resources/meshes/cartesio_platform.stl b/resources/meshes/cartesio_platform.stl index 65f0204881..d73581838b 100644 Binary files a/resources/meshes/cartesio_platform.stl and b/resources/meshes/cartesio_platform.stl differ diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 92d2da31e8..4a946d16f8 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -17,7 +17,7 @@ SettingItem id: control anchors.fill: parent - model: Cura.ExtrudersModel { } + model: Cura.ExtrudersModel { onModelChanged: control.color = getItem(control.currentIndex).color } textRole: "name" @@ -36,6 +36,17 @@ SettingItem onWheel: wheel.accepted = true; } + property string color: "#fff" + + Binding + { + // We override the color property's value when the ExtruderModel changes. So we need to use an + // explicit binding here otherwise we do not handle value changes after the model changes. + target: control + property: "color" + value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : "" + } + style: ComboBoxStyle { background: Rectangle @@ -83,7 +94,7 @@ SettingItem border.width: UM.Theme.getSize("default_lining").width border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") - color: control.currentText != "" ? control.model.getItem(control.currentIndex).color : "" + color: control.color } Label { diff --git a/resources/qml/Settings/SettingOptionalExtruder.qml b/resources/qml/Settings/SettingOptionalExtruder.qml new file mode 100644 index 0000000000..07b15e404d --- /dev/null +++ b/resources/qml/Settings/SettingOptionalExtruder.qml @@ -0,0 +1,153 @@ +// Copyright (c) 2016 Ultimaker B.V. +// Uranium is released under the terms of the AGPLv3 or higher. + +import QtQuick 2.1 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +SettingItem +{ + id: base + + contents: ComboBox + { + id: control + anchors.fill: parent + + model: Cura.ExtrudersModel + { + onModelChanged: control.color = getItem(control.currentIndex).color + useOptionalExtruder: true + } + + textRole: "name" + + onActivated: + { + forceActiveFocus(); + propertyProvider.setPropertyValue("value", model.getItem(index).index); + } + + Binding + { + target: control + property: "currentIndex" + value: + { + if(propertyProvider.properties.value == -1) + { + return control.model.items.length - 1 + } + return propertyProvider.properties.value + } + // Sometimes when the value is already changed, the model is still being built. + // The when clause ensures that the current index is not updated when this happens. + when: control.model.items.length > 0 + } + + MouseArea + { + anchors.fill: parent + acceptedButtons: Qt.NoButton + onWheel: wheel.accepted = true; + } + + property string color: "#fff" + + Binding + { + // We override the color property's value when the ExtruderModel changes. So we need to use an + // explicit binding here otherwise we do not handle value changes after the model changes. + target: control + property: "color" + value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : "" + } + + style: ComboBoxStyle + { + background: Rectangle + { + color: + { + if (!enabled) + { + return UM.Theme.getColor("setting_control_disabled"); + } + if(control.hovered || base.activeFocus) + { + return UM.Theme.getColor("setting_control_highlight"); + } + else + { + return UM.Theme.getColor("setting_control"); + } + } + border.width: UM.Theme.getSize("default_lining").width + border.color: + { + if(!enabled) + { + return UM.Theme.getColor("setting_control_disabled_border"); + } + if(control.hovered || base.activeFocus) + { + UM.Theme.getColor("setting_control_border_highlight") + } + + return UM.Theme.getColor("setting_control_border") + } + } + label: Item + { + Rectangle + { + id: swatch + height: UM.Theme.getSize("setting_control").height / 2 + width: height + + anchors.verticalCenter: parent.verticalCenter + + border.width: UM.Theme.getSize("default_lining").width + border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") + + color: control.color + } + Label + { + anchors + { + left: swatch.right; + right: arrow.left; + verticalCenter: parent.verticalCenter + margins: UM.Theme.getSize("default_lining").width + } + width: parent.width - swatch.width; + + text: control.currentText + font: UM.Theme.getFont("default") + color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") + + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + UM.RecolorImage + { + id: arrow + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + source: UM.Theme.getIcon("arrow_bottom") + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + 5 + sourceSize.height: width + 5 + + color: UM.Theme.getColor("setting_control_text") + } + } + } + } +} diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 85d19b0cf0..7cb45ff75f 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -195,7 +195,7 @@ Item //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. - asynchronous: model.type != "enum" && model.type != "extruder" + asynchronous: model.type != "enum" && model.type != "extruder" && model.type != "optional_extruder" active: model.type != undefined source: @@ -218,6 +218,8 @@ Item return "SettingTextField.qml" case "category": return "SettingCategory.qml" + case "optional_extruder": + return "SettingOptionalExtruder.qml" default: return "SettingUnknown.qml" } diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg index 2e99229d95..44cd4540d5 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg @@ -45,6 +45,5 @@ speed_wall = =math.ceil(speed_print * 50 / 50) speed_wall_0 = =math.ceil(speed_wall * 40 / 50) support_bottom_distance = =support_z_distance support_z_distance = =layer_height -travel_avoid_distance = 3 wall_0_inset = 0 wall_thickness = 1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg index 57f784a923..a0d09c97c2 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg @@ -45,5 +45,4 @@ speed_wall = =math.ceil(speed_print * 45 / 45) speed_wall_0 = =math.ceil(speed_wall * 35 / 45) support_bottom_distance = =support_z_distance support_z_distance = =layer_height -travel_avoid_distance = 3 wall_0_inset = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg index 91daa94988..ebd7cd2d07 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg @@ -47,5 +47,4 @@ speed_wall = =math.ceil(speed_print * 35 / 40) speed_wall_0 = =math.ceil(speed_wall * 30 / 35) support_bottom_distance = =support_z_distance support_z_distance = =layer_height -travel_avoid_distance = 3 wall_0_inset = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg index c11ed30ed4..96cbc59a48 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg @@ -46,5 +46,4 @@ speed_wall = =math.ceil(speed_print * 35 / 40) speed_wall_0 = =math.ceil(speed_wall * 30 / 35) support_bottom_distance = =support_z_distance support_z_distance = =layer_height -travel_avoid_distance = 3 wall_0_inset = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg index a7d3f76ac6..da9abb519d 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg @@ -59,7 +59,6 @@ support_interface_pattern = lines switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) wall_thickness = 1.2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg index 7fdcb28d82..01db3adb1f 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg @@ -58,7 +58,6 @@ support_interface_pattern = lines switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) wall_thickness = 1.2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg index 72e9d918c9..d2dc42b015 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg @@ -59,7 +59,6 @@ support_interface_pattern = lines switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) wall_thickness = 1.2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg index 6a271f548b..0580271647 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg @@ -56,7 +56,6 @@ support_interface_pattern = lines switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =round(line_width * 0.4 / 0.35, 2) wall_thickness = 1.2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg index 1982ba2c11..3f815fac3d 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg @@ -44,7 +44,7 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True +retraction_hop_enabled = False retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 @@ -56,11 +56,12 @@ speed_travel = 300 speed_wall = =math.ceil(speed_print * 25 / 25) speed_wall_0 = =math.ceil(speed_wall * 25 / 25) support_angle = 50 +skin_overlap = 5 switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 top_bottom_thickness = 0.7 -travel_avoid_distance = 3 +travel_avoid_distance = 0.5 wall_0_inset = 0 wall_line_width_x = =line_width wall_thickness = 0.76 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg index 8e65408ea4..e45ec15dec 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg @@ -45,10 +45,11 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True +retraction_hop_enabled = False retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 +skin_overlap = 5 speed_equalize_flow_enabled = True speed_layer_0 = 18 speed_print = 25 @@ -61,7 +62,7 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 top_bottom_thickness = 0.7 -travel_avoid_distance = 3 +travel_avoid_distance = 0.5 wall_0_inset = 0 wall_line_width_x = =line_width wall_thickness = 0.76 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg index 4ab5a3072f..707e535947 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg @@ -42,10 +42,11 @@ retraction_count_max = 12 retraction_extra_prime_amount = 0.8 retraction_extrusion_window = 1 retraction_hop = 2 -retraction_hop_enabled = True +retraction_hop_enabled = False retraction_hop_only_when_collides = True retraction_min_travel = 0.8 retraction_prime_speed = 15 +skin_overlap = 5 speed_equalize_flow_enabled = True speed_layer_0 = 18 speed_print = 25 @@ -58,7 +59,7 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 35 top_bottom_thickness = 0.7 -travel_avoid_distance = 3 +travel_avoid_distance = 0.5 wall_0_inset = 0 wall_line_width_x = =line_width wall_thickness = 0.76 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg index eefaeaaa58..41ac43a840 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg @@ -38,11 +38,11 @@ retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 retraction_hop = 0.5 +retraction_hop_enabled = False retraction_hop_only_when_collides = False retraction_min_travel = 0.8 retraction_prime_speed = 15 skin_line_width = =round(line_width * 0.78 / 0.8, 2) -skin_overlap = 15 speed_print = 30 speed_topbottom = =math.ceil(speed_print * 25 / 30) speed_travel = 300 @@ -56,6 +56,7 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 45 top_bottom_thickness = 1.2 +travel_avoid_distance = 0.5 travel_compensate_overlapping_walls_0_enabled = False wall_0_wipe_dist = =line_width * 2 wall_line_width_x = =round(line_width * 0.6 / 0.8, 2) diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg index bd527242d8..66c0281b78 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg @@ -39,11 +39,11 @@ retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 retraction_hop = 0.5 +retraction_hop_enabled = False retraction_hop_only_when_collides = False retraction_min_travel = 0.8 retraction_prime_speed = 15 skin_line_width = =round(line_width * 0.78 / 0.8, 2) -skin_overlap = 15 speed_print = 30 speed_topbottom = =math.ceil(speed_print * 20 / 30) speed_travel = 300 @@ -57,6 +57,7 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 45 top_bottom_thickness = 1.2 +travel_avoid_distance = 0.5 travel_compensate_overlapping_walls_0_enabled = False wall_0_wipe_dist = =line_width * 2 wall_line_width_x = =round(line_width * 0.6 / 0.8, 2) diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg index 054309c705..1274f43eea 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg @@ -38,11 +38,11 @@ retract_at_layer_change = False retraction_count_max = 12 retraction_extra_prime_amount = 0.5 retraction_hop = 0.5 +retraction_hop_enabled = False retraction_hop_only_when_collides = False retraction_min_travel = 0.8 retraction_prime_speed = 15 skin_line_width = =round(line_width * 0.78 / 0.8, 2) -skin_overlap = 15 speed_print = 30 speed_topbottom = =math.ceil(speed_print * 23 / 30) speed_travel = 300 @@ -56,6 +56,7 @@ switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 20 switch_extruder_retraction_speeds = 45 top_bottom_thickness = 1.2 +travel_avoid_distance = 0.5 travel_compensate_overlapping_walls_0_enabled = False wall_0_wipe_dist = =line_width * 2 wall_line_width_x = =round(line_width * 0.6 / 0.8, 2) diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg index 5bc96c8f08..b244b3b2da 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -weight = 0 +weight = 1 type = quality quality_type = high material = generic_pva_ultimaker3_BB_0.4 diff --git a/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg index ee35746983..2bca653fb7 100644 --- a/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg @@ -1,6 +1,6 @@ [general] version = 2 -name = Draft Quality +name = Fast definition = ultimaker3 [metadata] diff --git a/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg index 274533485e..f8d869b65c 100644 --- a/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg @@ -1,6 +1,6 @@ [general] version = 2 -name = Fast Quality +name = Normal definition = ultimaker3 [metadata] diff --git a/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg index d9c8d00eee..1f095a71e4 100755 --- a/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg @@ -1,6 +1,6 @@ [general] version = 2 -name = Superdraft Quality +name = Sprint definition = ultimaker3 [metadata] diff --git a/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg index 35a62bd63e..324e007653 100755 --- a/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg @@ -1,6 +1,6 @@ [general] version = 2 -name = Verydraft Quality +name = Extra Fast definition = ultimaker3 [metadata] diff --git a/resources/variants/ultimaker2_extended_0.25.inst.cfg b/resources/variants/ultimaker2_extended_0.25.inst.cfg new file mode 100644 index 0000000000..1a53ebc362 --- /dev/null +++ b/resources/variants/ultimaker2_extended_0.25.inst.cfg @@ -0,0 +1,13 @@ +[general] +name = 0.25 mm +version = 2 +definition = ultimaker2_extended + +[metadata] +author = Ultimaker +type = variant +setting_version = 1 + +[values] +machine_nozzle_size = 0.25 +machine_nozzle_tip_outer_diameter = 0.8 diff --git a/resources/variants/ultimaker2_extended_0.4.inst.cfg b/resources/variants/ultimaker2_extended_0.4.inst.cfg new file mode 100644 index 0000000000..e7caaa0772 --- /dev/null +++ b/resources/variants/ultimaker2_extended_0.4.inst.cfg @@ -0,0 +1,13 @@ +[general] +name = 0.4 mm +version = 2 +definition = ultimaker2_extended + +[metadata] +author = Ultimaker +type = variant +setting_version = 1 + +[values] +machine_nozzle_size = 0.4 +machine_nozzle_tip_outer_diameter = 1.05 diff --git a/resources/variants/ultimaker2_extended_0.6.inst.cfg b/resources/variants/ultimaker2_extended_0.6.inst.cfg new file mode 100644 index 0000000000..888dce45e8 --- /dev/null +++ b/resources/variants/ultimaker2_extended_0.6.inst.cfg @@ -0,0 +1,13 @@ +[general] +name = 0.6 mm +version = 2 +definition = ultimaker2_extended + +[metadata] +author = Ultimaker +type = variant +setting_version = 1 + +[values] +machine_nozzle_size = 0.6 +machine_nozzle_tip_outer_diameter = 1.25 diff --git a/resources/variants/ultimaker2_extended_0.8.inst.cfg b/resources/variants/ultimaker2_extended_0.8.inst.cfg new file mode 100644 index 0000000000..3f2e9dc55f --- /dev/null +++ b/resources/variants/ultimaker2_extended_0.8.inst.cfg @@ -0,0 +1,13 @@ +[general] +name = 0.8 mm +version = 2 +definition = ultimaker2_extended + +[metadata] +author = Ultimaker +type = variant +setting_version = 1 + +[values] +machine_nozzle_size = 0.8 +machine_nozzle_tip_outer_diameter = 1.35 diff --git a/resources/variants/ultimaker3_aa0.8.inst.cfg b/resources/variants/ultimaker3_aa0.8.inst.cfg index e0486289a1..e94177abc3 100644 --- a/resources/variants/ultimaker3_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_aa0.8.inst.cfg @@ -60,7 +60,6 @@ support_z_distance = =layer_height * 2 switch_extruder_prime_speed = 20 switch_extruder_retraction_amount = 16.5 top_bottom_thickness = 1.4 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =wall_line_width wall_thickness = 2 diff --git a/resources/variants/ultimaker3_bb0.8.inst.cfg b/resources/variants/ultimaker3_bb0.8.inst.cfg index 4ba2ca8422..aa2042b271 100644 --- a/resources/variants/ultimaker3_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_bb0.8.inst.cfg @@ -81,7 +81,6 @@ support_z_distance = 0 switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 12 top_bottom_thickness = 1 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =wall_line_width wall_thickness = 1 diff --git a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg index 0fd110c76c..47b0359df7 100644 --- a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg @@ -60,7 +60,6 @@ support_z_distance = =layer_height * 2 switch_extruder_prime_speed = 20 switch_extruder_retraction_amount = 16.5 top_bottom_thickness = 1.4 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =wall_line_width wall_thickness = 2 diff --git a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg index 2e6292ed08..c982d207b0 100644 --- a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg @@ -81,7 +81,6 @@ support_z_distance = 0 switch_extruder_prime_speed = 15 switch_extruder_retraction_amount = 12 top_bottom_thickness = 1 -travel_avoid_distance = 3 wall_0_inset = 0 wall_line_width_x = =wall_line_width wall_thickness = 1 diff --git a/tests/Settings/TestExtruderStack.py b/tests/Settings/TestExtruderStack.py index 4e55411d9d..4cafde5127 100644 --- a/tests/Settings/TestExtruderStack.py +++ b/tests/Settings/TestExtruderStack.py @@ -250,7 +250,8 @@ def test_getPropertyFallThrough(extruder_stack): container_indices = cura.Settings.CuraContainerStack._ContainerIndexes #Cache. for type_id, type_name in container_indices.IndexTypeMap.items(): container = unittest.mock.MagicMock() - container.getProperty = lambda key, property, type_id = type_id: type_id if (key == "layer_height" and property == "value") else None #Returns the container type ID as layer height, in order to identify it. + # Return type_id when asking for value and -1 when asking for limit_to_extruder + container.getProperty = lambda key, property, type_id = type_id: type_id if (key == "layer_height" and property == "value") else (None if property != "limit_to_extruder" else "-1") #Returns the container type ID as layer height, in order to identify it. container.hasProperty = lambda key, property: key == "layer_height" container.getMetaDataEntry = unittest.mock.MagicMock(return_value = type_name) mock_layer_heights[type_id] = container diff --git a/tests/Settings/TestGlobalStack.py b/tests/Settings/TestGlobalStack.py index 1eb3c43746..6dab02b220 100755 --- a/tests/Settings/TestGlobalStack.py +++ b/tests/Settings/TestGlobalStack.py @@ -69,11 +69,13 @@ def test_addExtruder(global_stack): assert len(global_stack.extruders) == 0 first_extruder = unittest.mock.MagicMock() + first_extruder.getMetaDataEntry = lambda key: 0 if key == "position" else None with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): global_stack.addExtruder(first_extruder) assert len(global_stack.extruders) == 1 assert global_stack.extruders[0] == first_extruder second_extruder = unittest.mock.MagicMock() + second_extruder.getMetaDataEntry = lambda key: 1 if key == "position" else None with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): global_stack.addExtruder(second_extruder) assert len(global_stack.extruders) == 2 @@ -350,7 +352,7 @@ def test_getPropertyResolveInInstance(global_stack): instance_containers = {} for container_type in container_indices.IndexTypeMap: instance_containers[container_type] = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature. - instance_containers[container_type].getProperty = lambda key, property: (7.5 if property == "resolve" else (InstanceState.User if property == "state" else 5)) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value. + instance_containers[container_type].getProperty = lambda key, property: (7.5 if property == "resolve" else (InstanceState.User if property == "state" else (5 if property != "limit_to_extruder" else "-1"))) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value. instance_containers[container_type].getMetaDataEntry = unittest.mock.MagicMock(return_value = container_indices.IndexTypeMap[container_type]) #Make queries for the type return the desired type. instance_containers[container_indices.Definition].getProperty = lambda key, property: 10 if (key == "material_bed_temperature" and property == "value") else None #Definition only has value. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking. @@ -374,7 +376,7 @@ def test_getPropertyResolveInInstance(global_stack): # definitions. def test_getPropertyInstancesBeforeResolve(global_stack): value = unittest.mock.MagicMock() #Sets just the value. - value.getProperty = lambda key, property: (10 if property == "value" else InstanceState.User) if key == "material_bed_temperature" else None + value.getProperty = lambda key, property: (10 if property == "value" else (InstanceState.User if property != "limit_to_extruder" else "-1")) if key == "material_bed_temperature" else None value.getMetaDataEntry = unittest.mock.MagicMock(return_value = "quality") resolve = unittest.mock.MagicMock() #Sets just the resolve. resolve.getProperty = lambda key, property: 7.5 if (key == "material_bed_temperature" and property == "resolve") else None