diff --git a/.gitignore b/.gitignore index cc21d3092c..dc951a52b7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,11 @@ resources/firmware *~ *.qm .idea + +# Eclipse+PyDev .project .pydevproject +.settings # Debian packaging -debian/ +debian* diff --git a/cura/ContainerSettingsModel.py b/cura/ContainerSettingsModel.py index 23d20cd6e2..2ff1a5f401 100644 --- a/cura/ContainerSettingsModel.py +++ b/cura/ContainerSettingsModel.py @@ -5,6 +5,7 @@ from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.InstanceContainer import InstanceContainer +from UM.Settings.SettingFunction import SettingFunction class ContainerSettingsModel(ListModel): LabelRole = Qt.UserRole + 1 @@ -20,33 +21,12 @@ class ContainerSettingsModel(ListModel): self.addRoleName(self.ValuesRole, "values") self._container_ids = [] - self._container = None + self._containers = [] - self._global_container_stack = None - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) - self._update() - - def _onGlobalContainerChanged(self): - if self._global_container_stack: - self._global_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged) - self._global_container_stack.propertyChanged.disconnect(self._onGlobalPropertyChanged) - - self._global_container_stack = Application.getInstance().getGlobalContainerStack() - - if self._global_container_stack: - Preferences.getInstance().setValue("cura/active_machine", self._global_container_stack.getId()) - self._global_container_stack.containersChanged.connect(self._onInstanceContainersChanged) - self._global_container_stack.propertyChanged.connect(self._onGlobalPropertyChanged) - - self._update() - - def _onGlobalPropertyChanged(self, key, property_name): + def _onPropertyChanged(self, key, property_name): if property_name == "value": self._update() - def _onInstanceContainersChanged(self, container): - self._update() - def _update(self): self.clear() @@ -54,24 +34,17 @@ class ContainerSettingsModel(ListModel): return keys = [] - containers = [] - for container_id in self._container_ids: - container = ContainerRegistry.getInstance().findContainers(id = container_id) - if not container: - return + for container in self._containers: + keys = keys + list(container.getAllKeys()) - keys = keys + list(container[0].getAllKeys()) - containers.append(container[0]) - - keys = list(set(keys)) + keys = list(set(keys)) # remove duplicate keys keys.sort() for key in keys: definition = None category = None values = [] - for container in containers: - + for container in self._containers: instance = container.getInstance(key) if instance: definition = instance.definition @@ -81,7 +54,11 @@ class ContainerSettingsModel(ListModel): while category.type != "category": category = category.parent - values.append(container.getProperty(key, "value")) + value = container.getProperty(key, "value") + if type(value) == SettingFunction: + values.append("=\u0192") + else: + values.append(container.getProperty(key, "value")) else: values.append("") @@ -93,9 +70,21 @@ class ContainerSettingsModel(ListModel): "category": category.label }) - ## Set the id of the container which has the settings this model should list. + ## Set the ids of the containers which have the settings this model should list. + # Also makes sure the model updates when the containers have property changes def setContainers(self, container_ids): + for container in self._containers: + container.propertyChanged.disconnect(self._onPropertyChanged) + self._container_ids = container_ids + self._containers = [] + + for container_id in self._container_ids: + containers = ContainerRegistry.getInstance().findContainers(id = container_id) + if containers: + containers[0].propertyChanged.connect(self._onPropertyChanged) + self._containers.append(containers[0]) + self._update() containersChanged = pyqtSignal() diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 9abfabc7b2..15c41f9c56 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -93,8 +93,11 @@ class CuraApplication(QtApplication): self._open_file_queue = [] # Files to open when plug-ins are loaded. # Need to do this before ContainerRegistry tries to load the machines - SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) - SettingDefinition.addSettingType("extruder", str, ast.literal_eval, UM.Settings.Validator) + SettingDefinition.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Any, default = True) + SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Any, default = True) + SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Any, default = True) + SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Any, default = True) + SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator) super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) @@ -291,6 +294,7 @@ class CuraApplication(QtApplication): # \sa PluginRegistery def _loadPlugins(self): self._plugin_registry.addType("profile_reader", self._addProfileReader) + self._plugin_registry.addType("profile_writer", self._addProfileWriter) self._plugin_registry.addPluginLocation(os.path.join(QtApplication.getInstallPrefix(), "lib", "cura")) if not hasattr(sys, "frozen"): self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "plugins")) @@ -785,3 +789,6 @@ class CuraApplication(QtApplication): def _addProfileReader(self, profile_reader): # TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles. pass + + def _addProfileWriter(self, profile_writer): + pass diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c8a07a4000..72b6086e26 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -36,7 +36,7 @@ class ExtruderManager(QObject): if not UM.Application.getInstance().getGlobalContainerStack(): return None #No active machine, so no active extruder. try: - return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)] + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)].getId() except KeyError: #Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. return None @@ -58,11 +58,22 @@ class ExtruderManager(QObject): cls.__instance = ExtruderManager() return cls.__instance + ## Changes the active extruder by index. + # + # \param index The index of the new active extruder. @pyqtSlot(int) def setActiveExtruderIndex(self, index): self._active_extruder_index = index self.activeExtruderChanged.emit() + def getActiveExtruderStack(self): + try: + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)] + except AttributeError: + return None + except KeyError: + return None + ## Adds all extruders of a specific machine definition to the extruder # manager. # @@ -87,7 +98,7 @@ class ExtruderManager(QObject): #Gets the extruder trains that we just created as well as any that still existed. extruder_trains = container_registry.findContainerStacks(type = "extruder_train", machine = machine_definition.getId()) for extruder_train in extruder_trains: - self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() + self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train if extruder_trains: self.extrudersChanged.emit(machine_definition) @@ -188,21 +199,17 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) ## Generates extruders for a specific machine. - def getMachineExtruders(self, machine_definition): - container_registry = UM.Settings.ContainerRegistry.getInstance() - machine_id = machine_definition.getId() - if not machine_id in self._extruder_trains: + # + # \param machine_id The machine to get the extruders of. + def getMachineExtruders(self, machine_id): + if machine_id not in self._extruder_trains: UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id) return - for _,extruder_train_id in self._extruder_trains[machine_id].items(): - extruder_train = container_registry.findContainerStacks(id = extruder_train_id) - if extruder_train: - yield extruder_train[0] - else: - UM.Logger.log("w", "Machine %s refers to an extruder train with ID %s, which doesn't exist.", machine_id, extruder_train_id) + for name in self._extruder_trains[machine_id]: + yield self._extruder_trains[machine_id][name] ## Adds the extruders of the currently active machine. def _addCurrentMachineExtruders(self): global_stack = UM.Application.getInstance().getGlobalContainerStack() if global_stack and global_stack.getBottom(): - self.addMachineExtruders(global_stack.getBottom()) \ No newline at end of file + self.addMachineExtruders(global_stack.getBottom()) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 60bd60abab..960c05bd5e 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty import cura.ExtruderManager import UM.Qt.ListModel @@ -12,18 +12,25 @@ import UM.Qt.ListModel # intended for drop-down lists of the current machine's extruders in place of # settings. class ExtrudersModel(UM.Qt.ListModel.ListModel): + # The ID of the container stack for the extruder. + IdRole = Qt.UserRole + 1 + ## Human-readable name of the extruder. - NameRole = Qt.UserRole + 1 + NameRole = Qt.UserRole + 2 ## Colour of the material loaded in the extruder. - ColourRole = Qt.UserRole + 2 + ColourRole = Qt.UserRole + 3 ## Index of the extruder, which is also the value of the setting itself. # # An index of 0 indicates the first extruder, an index of 1 the second # one, and so on. This is the value that will be saved in instance # containers. - IndexRole = Qt.UserRole + 3 + IndexRole = Qt.UserRole + 4 + + ## Colour to display if there is no material or the material has no known + # colour. + defaultColour = "#FFFF00" ## Initialises the extruders model, defining the roles and listening for # changes in the data. @@ -32,16 +39,30 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def __init__(self, parent = None): super().__init__(parent) + self.addRoleName(self.IdRole, "id") self.addRoleName(self.NameRole, "name") self.addRoleName(self.ColourRole, "colour") self.addRoleName(self.IndexRole, "index") + self._add_global = False + #Listen to changes. manager = cura.ExtruderManager.ExtruderManager.getInstance() manager.extrudersChanged.connect(self._updateExtruders) #When the list of extruders changes in general. UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes. self._updateExtruders() + def setAddGlobal(self, add): + if add != self._add_global: + self._add_global = add + self._updateExtruders() + self.addGlobalChanged.emit() + + addGlobalChanged = pyqtSignal() + @pyqtProperty(bool, fset = setAddGlobal, notify = addGlobalChanged) + def addGlobal(self): + return self._add_global + ## Update the list of extruders. # # This should be called whenever the list of extruders changes. @@ -51,13 +72,32 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): global_container_stack = UM.Application.getInstance().getGlobalContainerStack() if not global_container_stack: return #There is no machine to get the extruders of. - for index, extruder in enumerate(manager.getMachineExtruders(global_container_stack.getBottom())): - material = extruder.findContainer({ "type": "material" }) - colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" - item = { #Construct an item with only the relevant information. - "name": extruder.getName(), + + if self._add_global: + material = global_container_stack.findContainer({ "type": "material" }) + colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour + item = { + "id": global_container_stack.getId(), + "name": "Global", "colour": colour, - "index": index + "index": -1 } self.appendItem(item) - self.sort(lambda item: item["index"]) \ No newline at end of file + + for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()): + material = extruder.findContainer({ "type": "material" }) + colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour + position = extruder.getBottom().getMetaDataEntry("position", default = "0") #Position in the definition. + try: + position = int(position) + except ValueError: #Not a proper int. + position = -1 + item = { #Construct an item with only the relevant information. + "id": extruder.getId(), + "name": extruder.getName(), + "colour": colour, + "index": position + } + self.appendItem(item) + + self.sort(lambda item: item["index"]) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e719c05743..0e7230fb79 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -4,7 +4,6 @@ import re from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from UM.Application import Application from UM.Preferences import Preferences -from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState @@ -14,6 +13,7 @@ from . import ExtruderManager from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") + class MachineManagerModel(QObject): def __init__(self, parent = None): super().__init__(parent) @@ -41,7 +41,6 @@ class MachineManagerModel(QObject): self.setActiveMachine(active_machine_id) pass - globalContainerChanged = pyqtSignal() activeMaterialChanged = pyqtSignal() activeVariantChanged = pyqtSignal() @@ -114,8 +113,8 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) variant_instance_container = self._updateVariantContainer(definition) - material_instance_container = self._updateMaterialContainer(definition) - quality_instance_container = self._updateQualityContainer(definition) + material_instance_container = self._updateMaterialContainer(definition, variant_instance_container) + quality_instance_container = self._updateQualityContainer(definition, material_instance_container) current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container.addMetaDataEntry("machine", name) @@ -266,41 +265,21 @@ class MachineManagerModel(QObject): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if not containers or not self._global_container_stack: return True - return containers[0].getMetaDataEntry("read_only", False) == "True" + return containers[0].isReadOnly() @pyqtSlot(result = str) - def convertUserContainerToQuality(self): - if not self._global_container_stack: + def newQualityContainerFromQualityAndUser(self): + new_container_id = self.duplicateContainer(self.activeQualityId) + if new_container_id == "": return + self.setActiveQuality(new_container_id) + self.updateQualityContainerFromUserContainer() - new_quality_container = InstanceContainer("") - name = self._createUniqueName("quality", "", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) - user_settings = self._global_container_stack.getTop() - - ## Copy all values - new_quality_container.deserialize(user_settings.serialize()) - - ## If the currently active machine does not have quality profiles of its own, - # make the new quality profile available for all machines that don't have - # unique quality profiles (including the current machine) - if not self.filterQualityByMachine: - new_quality_container.setDefinition(UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = "fdmprinter")[0]) - - ## Change type / id / name - new_quality_container.setMetaDataEntry("type", "quality") - new_quality_container.setMetaDataEntry("read_only", False) - new_quality_container.setName(name) - new_quality_container._id = name - - UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container) - self.clearUserSettings() # As all users settings are now transfered to the new quality profile, remove them. - self.setActiveQuality(name) - return name @pyqtSlot(str, result=str) def duplicateContainer(self, container_id): if not self._global_container_stack: - return + return "" containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) @@ -310,7 +289,7 @@ class MachineManagerModel(QObject): ## Copy all values new_container.deserialize(containers[0].serialize()) - new_container.setMetaDataEntry("read_only", False) + new_container.setReadOnly(False) new_container.setName(new_name) new_container._id = new_name UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) @@ -318,15 +297,36 @@ class MachineManagerModel(QObject): return "" - @pyqtSlot(str, str) def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) - containers[0].setName(new_name) - self.activeQualityChanged.emit() + new_name = self._createUniqueName("quality", containers[0].getName(), new_name, + catalog.i18nc("@label", "Custom profile")) + if containers[0].getName() == new_name: + # Nothing to do. + return + + # As we also want the id of the container to be changed (so that profile name is the name of the file + # on disk. We need to create a new instance and remove it (so the old file of the container is removed) + # If we don't do that, we might get duplicates & other weird issues. + new_container = InstanceContainer("") + new_container.deserialize(containers[0].serialize()) + + # Actually set the name + new_container.setName(new_name) + new_container._id = new_name # Todo: Fix proper id change function for this. + + # Add the "new" container. + UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) + + # Ensure that the renamed profile is saved -before- we remove the old profile. + Application.getInstance().saveSettings() + + # Actually set & remove new / old quality. + self.setActiveQuality(new_name) + self.removeQualityContainer(containers[0].getId()) @pyqtSlot(str) def removeQualityContainer(self, container_id): @@ -348,7 +348,7 @@ class MachineManagerModel(QObject): @pyqtSlot() - def updateUserContainerToQuality(self): + def updateQualityContainerFromUserContainer(self): if not self._global_container_stack: return user_settings = self._global_container_stack.getTop() diff --git a/cura/ProfileWriter.py b/cura/ProfileWriter.py new file mode 100644 index 0000000000..6c719205ec --- /dev/null +++ b/cura/ProfileWriter.py @@ -0,0 +1,25 @@ +# Copyright (c) 2015 Ultimaker B.V. +# Uranium is released under the terms of the AGPLv3 or higher. + +from UM.PluginObject import PluginObject + +## Base class for profile writer plugins. +# +# This class defines a write() function to write profiles to files with. +class ProfileWriter(PluginObject): + ## Initialises the profile writer. + # + # This currently doesn't do anything since the writer is basically static. + def __init__(self): + super().__init__() + + ## Writes a profile to the specified file path. + # + # The profile writer may write its own file format to the specified file. + # + # \param path \type{string} The file to output to. + # \param profile \type{Profile} The profile to write to the file. + # \return \code True \endcode if the writing was successful, or \code + # False \endcode if it wasn't. + def write(self, path, node): + raise NotImplementedError("Profile writer plugin was not correctly implemented. No write was specified.") diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index f9878e436c..7417e47bf2 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -1,30 +1,40 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from UM.Scene.SceneNodeDecorator import SceneNodeDecorator +import copy + +from UM.Scene.SceneNodeDecorator import SceneNodeDecorator +from UM.Signal import Signal, signalemitter from UM.Settings.ContainerStack import ContainerStack from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerRegistry import ContainerRegistry +import UM.Logger from UM.Application import Application -import copy + ## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding # the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by # this stack still resolve. +@signalemitter class SettingOverrideDecorator(SceneNodeDecorator): + ## Event indicating that the user selected a different extruder. + activeExtruderChanged = Signal() + def __init__(self): super().__init__() self._stack = ContainerStack(stack_id = id(self)) self._stack.setDirty(False) # This stack does not need to be saved. self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) + self._extruder_stack = None #Stack upon which our stack is based. self._stack.propertyChanged.connect(self._onSettingChanged) ContainerRegistry.getInstance().addContainer(self._stack) - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) - self._onGlobalContainerStackChanged() + Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack) + self.activeExtruderChanged.connect(self._updateNextStack) + self._updateNextStack() def __deepcopy__(self, memo): ## Create a fresh decorator object @@ -35,13 +45,34 @@ class SettingOverrideDecorator(SceneNodeDecorator): deep_copy._stack.replaceContainer(0, deep_copy._instance) return deep_copy + ## Gets the currently active extruder to print this object with. + # + # \return An extruder's container stack. + def getActiveExtruder(self): + return self._extruder_stack + def _onSettingChanged(self, instance, property): if property == "value": # Only reslice if the value has changed. Application.getInstance().getBackend().forceSlice() - def _onGlobalContainerStackChanged(self): - ## Ensure that the next stack is always the global stack. - self._stack.setNextStack(Application.getInstance().getGlobalContainerStack()) + ## Makes sure that the stack upon which the container stack is placed is + # kept up to date. + def _updateNextStack(self): + if self._extruder_stack: + extruder_stack = ContainerRegistry.getInstance().findContainerStacks(id = self._extruder_stack) + if extruder_stack: + self._stack.setNextStack(extruder_stack) + else: + UM.Logger.log("e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack) + else: + self._stack.setNextStack(Application.getInstance().getGlobalContainerStack()) + + ## Changes the extruder with which to print this node. + # + # \param extruder_stack_id The new extruder stack to print with. + def setActiveExtruder(self, extruder_stack_id): + self._extruder_stack = extruder_stack_id + self.activeExtruderChanged.emit() def getStack(self): return self._stack \ No newline at end of file diff --git a/cura_app.py b/cura_app.py index dc748435f9..3bcce18fb5 100755 --- a/cura_app.py +++ b/cura_app.py @@ -36,7 +36,6 @@ import Arcus #@UnusedImport import cura.CuraApplication if sys.platform == "win32" and hasattr(sys, "frozen"): - import os dirpath = os.path.expanduser("~/AppData/Local/cura/") os.makedirs(dirpath, exist_ok = True) sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w") diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index 0d4975aca4..38753fd804 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -5,12 +5,20 @@ package cura.proto; message ObjectList { repeated Object objects = 1; - repeated Setting settings = 2; + repeated Setting settings = 2; // meshgroup settings (for one-at-a-time printing) } message Slice { - repeated ObjectList object_lists = 1; + repeated ObjectList object_lists = 1; // The meshgroups to be printed one after another + SettingList global_settings = 2; // The global settings used for the whole print job + repeated Extruder extruders = 3; // The settings sent to each extruder object +} + +message Extruder +{ + int32 id = 1; + SettingList settings = 2; } message Object @@ -29,10 +37,10 @@ message Progress message Layer { int32 id = 1; - float height = 2; - float thickness = 3; + float height = 2; // Z position + float thickness = 3; // height of a single layer - repeated Polygon polygons = 4; + repeated Polygon polygons = 4; // layer data } message Polygon { @@ -48,19 +56,19 @@ message Polygon { MoveCombingType = 8; MoveRetractionType = 9; } - Type type = 1; - bytes points = 2; - float line_width = 3; + Type type = 1; // Type of move + bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used) + float line_width = 3; // The width of the line being laid down } message GCodeLayer { bytes data = 2; } -message ObjectPrintTime { +message ObjectPrintTime { // The print time for the whole print and material estimates for the first extruder int64 id = 1; - float time = 2; - float material_amount = 3; + float time = 2; // Total time estimate + float material_amount = 3; // material used in the first extruder } message SettingList { @@ -68,13 +76,13 @@ message SettingList { } message Setting { - string name = 1; + string name = 1; // Internal key to signify a setting - bytes value = 2; + bytes value = 2; // The value of the setting } message GCodePrefix { - bytes data = 2; + bytes data = 2; // Header string to be prenpended before the rest of the gcode sent from the engine } message SlicingFinished { diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 9607ba407b..80f2614e87 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -12,6 +12,8 @@ from UM.PluginRegistry import PluginRegistry from UM.Resources import Resources from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then. +from cura.ExtruderManager import ExtruderManager + from cura.OneAtATimeIterator import OneAtATimeIterator from . import ProcessSlicedLayersJob from . import ProcessGCodeJob @@ -59,6 +61,10 @@ class CuraEngineBackend(Backend): Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) self._onGlobalStackChanged() + self._active_extruder_stack = None + ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) + self._onActiveExtruderChanged() + #When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired. #This timer will group them up, and only slice for the last setting changed signal. #TODO: Properly group propertyChanged signals by whether they are triggered by the same user interaction. @@ -145,8 +151,7 @@ class CuraEngineBackend(Backend): self.slicingStarted.emit() slice_message = self._socket.createMessage("cura.proto.Slice") - settings_message = self._socket.createMessage("cura.proto.SettingList") - self._start_slice_job = StartSliceJob.StartSliceJob(slice_message, settings_message) + self._start_slice_job = StartSliceJob.StartSliceJob(slice_message) self._start_slice_job.start() self._start_slice_job.finished.connect(self._onStartSliceCompleted) @@ -205,7 +210,6 @@ class CuraEngineBackend(Backend): return # Preparation completed, send it to the backend. - self._socket.sendMessage(job.getSettingsMessage()) self._socket.sendMessage(job.getSliceMessage()) ## Listener for when the scene has changed. @@ -369,4 +373,16 @@ class CuraEngineBackend(Backend): if self._global_container_stack: self._global_container_stack.propertyChanged.connect(self._onSettingChanged) #Note: Only starts slicing when the value changed. self._global_container_stack.containersChanged.connect(self._onChanged) + self._onActiveExtruderChanged() self._onChanged() + + def _onActiveExtruderChanged(self): + if self._active_extruder_stack: + self._active_extruder_stack.propertyChanged.disconnect(self._onSettingChanged) + self._active_extruder_stack.containersChanged.disconnect(self._onChanged) + + self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack() + if self._active_extruder_stack: + self._active_extruder_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed. + self._active_extruder_stack.containersChanged.connect(self._onChanged) + self._onChanged() \ No newline at end of file diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index dee6f2b64c..3d2eb0ed4a 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -15,6 +15,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Settings.Validator import ValidatorState from cura.OneAtATimeIterator import OneAtATimeIterator +from cura.ExtruderManager import ExtruderManager class StartJobResult(IntEnum): Finished = 1 @@ -37,17 +38,13 @@ class GcodeStartEndFormatter(Formatter): ## Job class that builds up the message of scene data to send to CuraEngine. class StartSliceJob(Job): - def __init__(self, slice_message, settings_message): + def __init__(self, slice_message): super().__init__() self._scene = Application.getInstance().getController().getScene() self._slice_message = slice_message - self._settings_message = settings_message self._is_cancelled = False - def getSettingsMessage(self): - return self._settings_message - def getSliceMessage(self): return self._slice_message @@ -131,6 +128,9 @@ class StartSliceJob(Job): self._buildGlobalSettingsMessage(stack) + for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getBottom().getId()): + self._buildExtruderMessage(extruder_stack) + for group in object_groups: group_message = self._slice_message.addRepeatedMessage("object_lists") if group[0].getParent().callDecoration("isGroup"): @@ -170,6 +170,15 @@ class StartSliceJob(Job): Logger.logException("w", "Unable to do token replacement on start/end gcode") return str(value).encode("utf-8") + def _buildExtruderMessage(self, stack): + message = self._slice_message.addRepeatedMessage("extruders") + message.id = int(stack.getMetaDataEntry("position")) + for key in stack.getAllKeys(): + setting = message.getMessage("settings").addRepeatedMessage("settings") + setting.name = key + setting.value = str(stack.getProperty(key, "value")).encode("utf-8") + Job.yieldThread() + ## Sends all global settings to the engine. # # The settings are taken from the global stack. This does not include any @@ -185,7 +194,7 @@ class StartSliceJob(Job): settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode for key, value in settings.items(): #Add all submessages for each individual setting. - setting_message = self._settings_message.addRepeatedMessage("settings") + setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings") setting_message.name = key if key == "machine_start_gcode" or key == "machine_end_gcode": #If it's a g-code message, use special formatting. setting_message.value = self._expandGcodeTokens(key, value, settings) @@ -193,21 +202,10 @@ class StartSliceJob(Job): setting_message.value = str(value).encode("utf-8") def _handlePerObjectSettings(self, node, message): - profile = node.callDecoration("getProfile") - if profile: - for key, value in profile.getAllSettingValues().items(): + stack = node.callDecoration("getStack") + if stack: + for key in stack.getAllKeys(): setting = message.addRepeatedMessage("settings") setting.name = key - setting.value = str(value).encode() - - Job.yieldThread() - - object_settings = node.callDecoration("getAllSettingValues") - if not object_settings: - return - for key, value in object_settings.items(): - setting = message.addRepeatedMessage("settings") - setting.name = key - setting.value = str(value).encode() - - Job.yieldThread() + setting.value = str(stack.getProperty(key, "value")).encode("utf-8") + Job.yieldThread() \ No newline at end of file diff --git a/plugins/CuraProfileReader/CuraProfileReader.py b/plugins/CuraProfileReader/CuraProfileReader.py index 1d27649498..b9c1f208ea 100644 --- a/plugins/CuraProfileReader/CuraProfileReader.py +++ b/plugins/CuraProfileReader/CuraProfileReader.py @@ -1,11 +1,12 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. +import os.path + from UM.Application import Application #To get the machine manager to create the new profile in. from UM.Logger import Logger -from UM.Settings.Profile import Profile -from UM.Settings.ProfileReader import ProfileReader - +from UM.Settings.InstanceContainer import InstanceContainer #The new profile to make. +from cura.ProfileReader import ProfileReader ## A plugin that reads profile data from Cura profile files. # @@ -25,17 +26,17 @@ class CuraProfileReader(ProfileReader): # returned. def read(self, file_name): # Create an empty profile. - profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) - serialised = "" + profile = InstanceContainer(os.path.basename(os.path.splitext(file_name)[0])) + profile.addMetaDataEntry("type", "quality") try: with open(file_name) as f: # Open file for reading. - serialised = f.read() + serialized = f.read() except IOError as e: Logger.log("e", "Unable to open file %s for reading: %s", file_name, str(e)) return None try: - profile.unserialise(serialised) + profile.deserialize(serialized) except Exception as e: # Parsing error. This is not a (valid) Cura profile then. Logger.log("e", "Error while trying to parse profile: %s", str(e)) return None diff --git a/plugins/CuraProfileReader/__init__.py b/plugins/CuraProfileReader/__init__.py index bfaa16ed5e..c4206ab763 100644 --- a/plugins/CuraProfileReader/__init__.py +++ b/plugins/CuraProfileReader/__init__.py @@ -13,7 +13,7 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Provides support for importing Cura profiles."), - "api": 2 + "api": 3 }, "profile_reader": [ { diff --git a/plugins/CuraProfileWriter/CuraProfileWriter.py b/plugins/CuraProfileWriter/CuraProfileWriter.py index 82df446b8a..86b4f7dc89 100644 --- a/plugins/CuraProfileWriter/CuraProfileWriter.py +++ b/plugins/CuraProfileWriter/CuraProfileWriter.py @@ -4,7 +4,7 @@ from UM.Logger import Logger from UM.SaveFile import SaveFile -from UM.Settings.ProfileWriter import ProfileWriter +from cura.ProfileWriter import ProfileWriter ## Writes profiles to Cura's own profile format with config files. @@ -16,10 +16,10 @@ class CuraProfileWriter(ProfileWriter): # \return \code True \endcode if the writing was successful, or \code # False \endcode if it wasn't. def write(self, path, profile): - serialised = profile.serialise() + serialized = profile.serialize() try: with SaveFile(path, "wt", -1, "utf-8") as f: # Open the specified file. - f.write(serialised) + f.write(serialized) except Exception as e: Logger.log("e", "Failed to write profile to %s: %s", path, str(e)) return False diff --git a/plugins/CuraProfileWriter/__init__.py b/plugins/CuraProfileWriter/__init__.py index 43890de469..30528b8167 100644 --- a/plugins/CuraProfileWriter/__init__.py +++ b/plugins/CuraProfileWriter/__init__.py @@ -13,7 +13,7 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Provides support for exporting Cura profiles."), - "api": 2 + "api": 3 }, "profile_writer": [ { diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 667f842469..502e903416 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Ultimaker B.V. +// Copyright (c) 2016 Ultimaker B.V. // Uranium is released under the terms of the AGPLv3 or higher. import QtQuick 2.2 @@ -26,6 +26,99 @@ Item { spacing: UM.Theme.getSize("default_margin").height; + Row + { + ComboBox + { + id: extruderSelector + + model: Cura.ExtrudersModel + { + id: extruders_model + } + visible: extruders_model.rowCount() > 1 + textRole: "name" + width: items.width + height: UM.Theme.getSize("section").height + MouseArea + { + anchors.fill: parent + acceptedButtons: Qt.NoButton + onWheel: wheel.accepted = true; + } + + style: ComboBoxStyle + { + background: Rectangle + { + color: + { + if(extruderSelector.hovered || base.activeFocus) + { + return UM.Theme.getColor("setting_control_highlight"); + } + else + { + return extruders_model.getItem(extruderSelector.currentIndex).colour; + } + } + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("setting_control_border") + } + label: Item + { + Label + { + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_lining").width + anchors.right: downArrow.left + anchors.rightMargin: UM.Theme.getSize("default_lining").width + anchors.verticalCenter: parent.verticalCenter + + text: extruderSelector.currentText + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("setting_control_disabled_text") + + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + UM.RecolorImage + { + id: downArrow + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2 + 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") + } + } + } + + onActivated: UM.ActiveTool.setProperty("SelectedActiveExtruder", extruders_model.getItem(index).id); + onModelChanged: updateCurrentIndex(); + + function updateCurrentIndex() + { + for(var i = 0; i < extruders_model.rowCount(); ++i) + { + if(extruders_model.getItem(i).id == UM.ActiveTool.properties.getValue("SelectedActiveExtruder")) + { + extruderSelector.currentIndex = i; + return; + } + } + extruderSelector.currentIndex = -1; + } + } + } + Repeater { id: contents @@ -190,11 +283,11 @@ Item { { if(text != "") { - listview.model.filter = {"global_only": false, "label": "*" + text} + listview.model.filter = {"settable_per_mesh": true, "label": "*" + text} } else { - listview.model.filter = {"global_only": false} + listview.model.filter = {"settable_per_mesh": true} } } } @@ -219,7 +312,7 @@ Item { containerId: Cura.MachineManager.activeDefinitionId filter: { - "global_only": false + "settable_per_mesh": true } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} } diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index 6ae44c2671..395dbdc594 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -1,11 +1,11 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2016 Ultimaker B.V. # Uranium is released under the terms of the AGPLv3 or higher. from UM.Tool import Tool from UM.Scene.Selection import Selection from UM.Application import Application from UM.Preferences import Preferences - +from cura.SettingOverrideDecorator import SettingOverrideDecorator ## This tool allows the user to add & change settings per node in the scene. # The settings per object are kept in a ContainerStack, which is linked to a node by decorator. @@ -14,7 +14,7 @@ class PerObjectSettingsTool(Tool): super().__init__() self._model = None - self.setExposedProperties("SelectedObjectId", "ContainerID") + self.setExposedProperties("SelectedObjectId", "ContainerID", "SelectedActiveExtruder") Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged) Selection.selectionChanged.connect(self.propertyChanged) @@ -42,6 +42,24 @@ class PerObjectSettingsTool(Tool): except AttributeError: return "" + ## Gets the active extruder of the currently selected object. + # + # \return The active extruder of the currently selected object. + def getSelectedActiveExtruder(self): + selected_object = Selection.getSelectedObject(0) + selected_object.callDecoration("getActiveExtruder") + + ## Changes the active extruder of the currently selected object. + # + # \param extruder_stack_id The ID of the extruder to print the currently + # selected object with. + def setSelectedActiveExtruder(self, extruder_stack_id): + selected_object = Selection.getSelectedObject(0) + stack = selected_object.callDecoration("getStack") #Don't try to get the active extruder since it may be None anyway. + if not stack: + selected_object.addDecorator(SettingOverrideDecorator()) + selected_object.callDecoration("setActiveExtruder", extruder_stack_id) + def _onPreferenceChanged(self, preference): if preference == "cura/active_mode": enabled = Preferences.getInstance().getValue(preference)==1 diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index 69797385a1..940b0bb3ed 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -24,7 +24,11 @@ "description": "The extruder train used for printing. This is used in multi-extrusion.", "type": "extruder", "default_value": 0, - "minimum_value": "0" + "minimum_value": "0", + "settable_per_mesh": true, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_nozzle_offset_x": { @@ -33,7 +37,10 @@ "type": "float", "unit": "mm", "default_value": 0, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_nozzle_offset_y": { @@ -42,7 +49,10 @@ "type": "float", "unit": "mm", "default_value": 0, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_start_code": { @@ -50,7 +60,10 @@ "description": "Start g-code to execute whenever turning the extruder on.", "type": "str", "default_value": "", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_start_pos_abs": { @@ -58,7 +71,10 @@ "description": "Make the extruder starting position absolute rather than relative to the last-known location of the head.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_start_pos_x": { @@ -67,7 +83,10 @@ "type": "float", "unit": "mm", "default_value": 0, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_start_pos_y": { @@ -76,7 +95,10 @@ "type": "float", "unit": "mm", "default_value": 0, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_end_code": { @@ -84,7 +106,10 @@ "description": "End g-code to execute whenever turning the extruder off.", "type": "str", "default_value": "", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_end_pos_abs": { @@ -92,7 +117,10 @@ "description": "Make the extruder ending position absolute rather than relative to the last-known location of the head.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_end_pos_x": { @@ -101,7 +129,10 @@ "type": "float", "unit": "mm", "default_value": 0, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_extruder_end_pos_y": { @@ -110,7 +141,10 @@ "type": "float", "unit": "mm", "default_value": 0, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false } } } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8be258c79e..1f7ed7c78a 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -32,151 +32,189 @@ "description": "Whether to show the different variants of this machine, which are described in separate json files.", "default_value": false, "type": "bool", - "label": "Show machine variants" + "label": "Show machine variants", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_start_gcode": { "description": "Gcode commands to be executed at the very start - separated by \\n.", "default_value": "G28 ;Home\nG1 Z15.0 F6000 ;Move the platform down 15mm\n;Prime the extruder\nG92 E0\nG1 F200 E3\nG92 E0", "label": "Start GCode", - "global_only": true, - "type": "str" + "type": "str", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_end_gcode": { "description": "Gcode commands to be executed at the very end - separated by \\n.", "default_value": "M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84", "label": "End GCode", - "global_only": true, - "type": "str" + "type": "str", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "material_bed_temp_wait": { "description": "Whether to insert a command to wait until the bed temperature is reached at the start.", "label": "Wait for bed heatup", "default_value": true, - "global_only": true, - "type": "bool" + "type": "bool", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "material_print_temp_prepend": { "description": "Whether to include nozzle temperature commands at the start of the gcode. When the start_gcode already contains nozzle temperature commands Cura frontend will automatically disable this setting.", "default_value": true, - "global_only": true, "type": "bool", - "label": "Wait for material heatup" + "label": "Wait for material heatup", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_width": { "description": "The width (X-direction) of the printable area.", "default_value": 100, - "global_only": true, "type": "float", - "label": "Machine width" + "label": "Machine width", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_depth": { "description": "The depth (Y-direction) of the printable area.", "default_value": 100, - "global_only": true, "type": "float", - "label": "Machine depth" + "label": "Machine depth", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_height": { "description": "The height (Z-direction) of the printable area.", "default_value": 100, - "global_only": true, "type": "float", - "label": "Machine height" + "label": "Machine height", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_heated_bed": { "description": "Whether the machine has a heated bed present.", "default_value": false, - "global_only": true, "label": "Has heated bed", - "type": "bool" + "type": "bool", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_center_is_zero": { "description": "Whether the X/Y coordinates of the zero position of the printer is at the center of the printable area.", "default_value": false, - "global_only": true, "type": "bool", - "label": "Is center origin" + "label": "Is center origin", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_extruder_count": { "description": "Number of extruder trains. An extruder train is the combination of a feeder, bowden tube, and nozzle.", "default_value": 1, - "global_only": true, "type": "int", - "label": "Number extruders" + "label": "Number extruders", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_nozzle_tip_outer_diameter": { "description": "The outer diameter of the tip of the nozzle.", "label": "Outer nozzle diameter", "default_value": 1, - "global_only": true, - "type": "float" + "type": "float", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false, + "settable_globally": false }, "machine_nozzle_head_distance": { "description": "The height difference between the tip of the nozzle and the lowest part of the print head.", "default_value": 3, - "global_only": true, "type": "float", - "label": "Nozzle length" + "label": "Nozzle length", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_nozzle_expansion_angle": { "description": "The angle between the horizontal plane and the conical part right above the tip of the nozzle.", "default_value": 45, - "global_only": true, "type": "int", - "label": "Nozzle angle" + "label": "Nozzle angle", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_heat_zone_length": { "description": "The distance from the tip of the nozzle in which heat from the nozzle is transfered to the filament.", "default_value": 16, - "global_only": true, "type": "float", - "label": "Heat zone length" + "label": "Heat zone length", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": false }, "machine_nozzle_heat_up_speed": { "description": "The speed (°C/s) by which the nozzle heats up averaged over the window of normal printing temperatures and the standby temperature.", "default_value": 2.0, - "global_only": true, "type": "float", - "label": "Heat up speed" + "label": "Heat up speed", + "settable_per_mesh": false, + "settable_per_extruder": true }, "machine_nozzle_cool_down_speed": { "description": "The speed (°C/s) by which the nozzle cools down averaged over the window of normal printing temperatures and the standby temperature.", "default_value": 2.0, - "global_only": true, "type": "float", - "label": "Cool down speed" + "label": "Cool down speed", + "settable_per_mesh": false, + "settable_per_extruder": true }, "machine_gcode_flavor": { "description": "The type of gcode to be generated.", "default_value": "RepRap", - "global_only": true, "type": "str", - "label": "Gcode flavour" + "label": "Gcode flavour", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_disallowed_areas": { "description": "A list of polygons with areas the print head is not allowed to enter.", "type": "polygons", "default_value": [], - "global_only": true, - "label": "Disallowed areas" + "label": "Disallowed areas", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_head_polygon": { @@ -201,8 +239,10 @@ 1 ] ], - "global_only": true, - "label": "Machine head polygon" + "label": "Machine head polygon", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_head_with_fans_polygon": { @@ -227,16 +267,20 @@ -10 ] ], - "global_only": true, - "label": "Machine head & Fan polygon" + "label": "Machine head & Fan polygon", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "gantry_height": { "description": "The height difference between the tip of the nozzle and the gantry system (X and Y axes).", "default_value": 99999999999, - "global_only": true, "label": "Gantry height", - "type": "float" + "type": "float", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "machine_nozzle_size": { @@ -246,14 +290,19 @@ "type": "float", "default_value": 0.4, "minimum_value": "0.001", - "maximum_value_warning": "10" + "maximum_value_warning": "10", + "settable_per_mesh": false, + "settable_per_extruder": true }, "machine_use_extruder_offset_to_offset_coords": { "label": "Offset With Extruder", "description": "Apply the extruder offset to the coordinate system.", "type": "bool", - "default_value": true + "default_value": true, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false } } }, @@ -275,7 +324,8 @@ "minimum_value": "0.001", "minimum_value_warning": "0.04", "maximum_value_warning": "0.8 * machine_nozzle_size", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "layer_height_0": { @@ -287,7 +337,8 @@ "minimum_value": "0.001", "minimum_value_warning": "0.04", "maximum_value_warning": "0.8 * machine_nozzle_size", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "line_width": { @@ -300,6 +351,7 @@ "default_value": 0.4, "type": "float", "value": "machine_nozzle_size", + "settable_per_mesh": true, "children": { "wall_line_width": @@ -313,6 +365,7 @@ "value":"line_width", "default_value": 0.4, "type": "float", + "settable_per_mesh": true, "children": { "wall_line_width_0": @@ -325,7 +378,8 @@ "maximum_value_warning": "5", "default_value": 0.4, "value":"wall_line_width", - "type": "float" + "type": "float", + "settable_per_mesh": true }, "wall_line_width_x": { @@ -337,7 +391,8 @@ "maximum_value_warning": "5", "default_value": 0.4, "value":"wall_line_width", - "type": "float" + "type": "float", + "settable_per_mesh": true } } }, @@ -351,7 +406,8 @@ "maximum_value_warning": "5", "default_value": 0.4, "type": "float", - "value": "line_width" + "value": "line_width", + "settable_per_mesh": true }, "infill_line_width": { @@ -363,7 +419,8 @@ "maximum_value_warning": "5", "default_value": 0.4, "type": "float", - "value": "line_width" + "value": "line_width", + "settable_per_mesh": true }, "skirt_line_width": { @@ -375,8 +432,9 @@ "maximum_value_warning": "5", "default_value": 0.4, "type": "float", - "global_only": true, - "value": "line_width" + "value": "line_width", + "settable_per_mesh": false, + "settable_per_extruder": true }, "support_line_width": { @@ -389,8 +447,9 @@ "default_value": 0.4, "type": "float", "enabled": "support_enable", - "global_only": true, - "value": "line_width" + "value": "line_width", + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_roof_line_width": { @@ -402,8 +461,9 @@ "maximum_value_warning": "machine_nozzle_size * 2", "type": "float", "enabled": "support_roof_enable", - "global_only": true, - "value": "line_width" + "value": "line_width", + "settable_per_mesh": false, + "settable_per_extruder": false }, "prime_tower_line_width": { @@ -417,7 +477,8 @@ "minimum_value": "0.0001", "minimum_value_warning": "0.2", "maximum_value_warning": "5", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } } @@ -441,6 +502,7 @@ "minimum_value_warning": "line_width", "maximum_value_warning": "5 * line_width", "type": "float", + "settable_per_mesh": true, "children": { "wall_line_count": @@ -450,7 +512,8 @@ "default_value": 2, "minimum_value": "0", "type": "int", - "value": "1 if magic_spiralize else max(1, round((wall_thickness - wall_line_width_0) / wall_line_width_x) + 1)" + "value": "1 if magic_spiralize else max(1, round((wall_thickness - wall_line_width_0) / wall_line_width_x) + 1)", + "settable_per_mesh": true } } }, @@ -463,6 +526,7 @@ "minimum_value": "0", "minimum_value_warning": "0.6", "type": "float", + "settable_per_mesh": true, "children": { "top_thickness": @@ -475,6 +539,7 @@ "maximum_value_warning": "100", "type": "float", "value": "top_bottom_thickness", + "settable_per_mesh": true, "children": { "top_layers": @@ -485,7 +550,8 @@ "minimum_value": "0", "maximum_value_warning": "100", "type": "int", - "value": "0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / layer_height, 4))" + "value": "0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / layer_height, 4))", + "settable_per_mesh": true } } }, @@ -498,6 +564,7 @@ "minimum_value": "0", "type": "float", "value": "top_bottom_thickness", + "settable_per_mesh": true, "children": { "bottom_layers": @@ -507,7 +574,8 @@ "minimum_value": "0", "default_value": 6, "type": "int", - "value": "999999 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / layer_height, 4))" + "value": "999999 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / layer_height, 4))", + "settable_per_mesh": true } } } @@ -524,7 +592,8 @@ "concentric": "Concentric", "zigzag": "Zig Zag" }, - "default_value": "lines" + "default_value": "lines", + "settable_per_mesh": true }, "wall_0_inset": { @@ -535,14 +604,16 @@ "default_value": 0.0, "value": "(machine_nozzle_size - wall_line_width_0) / 2 if wall_line_width_0 < machine_nozzle_size else 0", "minimum_value_warning": "0", - "maximum_value_warning": "machine_nozzle_size" + "maximum_value_warning": "machine_nozzle_size", + "settable_per_mesh": true }, "alternate_extra_perimeter": { "label": "Alternate Extra Wall", "description": "Prints an extra wall at every other layer. This way infill gets caught between these extra walls, resulting in stronger prints.", "type": "bool", - "default_value": false + "default_value": false, + "settable_per_mesh": true }, "travel_compensate_overlapping_walls_enabled": { @@ -550,6 +621,7 @@ "description": "Compensate the flow for parts of a wall being printed where there is already a wall in place.", "type": "bool", "default_value": true, + "settable_per_mesh": true, "children": { "travel_compensate_overlapping_walls_0_enabled": { @@ -557,14 +629,16 @@ "description": "Compensate the flow for parts of an outer wall being printed where there is already a wall in place.", "type": "bool", "default_value": true, - "value": "travel_compensate_overlapping_walls_enabled" + "value": "travel_compensate_overlapping_walls_enabled", + "settable_per_mesh": true }, "travel_compensate_overlapping_walls_x_enabled": { "label": "Compensate Inner Wall Overlaps", "description": "Compensate the flow for parts of an inner wall being printed where there is already a wall in place.", "type": "bool", "default_value": true, - "value": "travel_compensate_overlapping_walls_enabled" + "value": "travel_compensate_overlapping_walls_enabled", + "settable_per_mesh": true } } }, @@ -576,7 +650,8 @@ "type": "float", "minimum_value_warning": "-10", "maximum_value_warning": "10", - "default_value": 0 + "default_value": 0, + "settable_per_mesh": true }, "z_seam_type": { @@ -589,14 +664,16 @@ "shortest": "Shortest", "random": "Random" }, - "default_value": "shortest" + "default_value": "shortest", + "settable_per_mesh": true }, "skin_no_small_gaps_heuristic": { "label": "Ignore Small Z Gaps", "description": "When the model has small vertical gaps, about 5% extra computation time can be spent on generating top and bottom skin in these narrow spaces. In such case, disable the setting.", "type": "bool", - "default_value": true + "default_value": true, + "settable_per_mesh": true } } }, @@ -617,6 +694,7 @@ "default_value": 20, "minimum_value": "0", "maximum_value_warning": "100", + "settable_per_mesh": true, "children": { "infill_line_distance": @@ -627,7 +705,8 @@ "type": "float", "default_value": 2, "minimum_value": "0", - "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else 1))" + "value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == \"grid\" else (3 if infill_pattern == \"triangles\" else 1))", + "settable_per_mesh": true } } }, @@ -645,7 +724,8 @@ "zigzag": "Zig Zag" }, "default_value": "grid", - "value": "'lines' if infill_sparse_density > 25 else 'grid'" + "value": "'lines' if infill_sparse_density > 25 else 'grid'", + "settable_per_mesh": true }, "infill_overlap": { @@ -658,6 +738,7 @@ "minimum_value_warning": "-50", "maximum_value_warning": "100", "enabled": "infill_pattern != 'concentric'", + "settable_per_mesh": true, "children": { "infill_overlap_mm": @@ -670,7 +751,8 @@ "minimum_value_warning": "-0.5 * machine_nozzle_size", "maximum_value_warning": "machine_nozzle_size", "value": "infill_line_width * infill_overlap / 100 if infill_sparse_density < 95 and infill_pattern != 'concentric' else 0", - "enabled": "infill_pattern != 'concentric'" + "enabled": "infill_pattern != 'concentric'", + "settable_per_mesh": true } } }, @@ -684,6 +766,7 @@ "maximum_value_warning": "100", "value": "5 if top_bottom_pattern != 'concentric' else 0", "enabled": "top_bottom_pattern != 'concentric'", + "settable_per_mesh": true, "children": { "skin_overlap_mm": { "label": "Skin Overlap", @@ -694,7 +777,8 @@ "minimum_value_warning": "-0.5 * machine_nozzle_size", "maximum_value_warning": "machine_nozzle_size", "value": "skin_line_width * skin_overlap / 100 if top_bottom_pattern != 'concentric' else 0", - "enabled": "top_bottom_pattern != 'concentric'" + "enabled": "top_bottom_pattern != 'concentric'", + "settable_per_mesh": true } } }, @@ -707,7 +791,8 @@ "default_value": 0.04, "value": "wall_line_width_0 / 4 if wall_line_count == 1 else wall_line_width_x / 4", "minimum_value_warning": "0", - "maximum_value_warning": "machine_nozzle_size" + "maximum_value_warning": "machine_nozzle_size", + "settable_per_mesh": true }, "infill_sparse_thickness": { @@ -719,14 +804,16 @@ "minimum_value": "0.0001", "maximum_value_warning": "0.32", "maximum_value": "layer_height * 8", - "value": "layer_height" + "value": "layer_height", + "settable_per_mesh": true }, "infill_before_walls": { "label": "Infill Before Walls", "description": "Print the infill before printing the walls. Printing the walls first may lead to more accurate walls, but overhangs print worse. Printing the infill first leads to sturdier walls, but the infill pattern might sometimes show through the surface.", "type": "bool", - "default_value": true + "default_value": true, + "settable_per_mesh": true } } }, @@ -745,7 +832,8 @@ "type": "bool", "default_value": false, "enabled": "False", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "material_print_temperature": { @@ -756,7 +844,9 @@ "default_value": 210, "minimum_value": "0", "maximum_value_warning": "260", - "enabled": "not (material_flow_dependent_temperature)" + "enabled": "not (material_flow_dependent_temperature)", + "settable_per_mesh": false, + "settable_per_extruder": true }, "material_flow_temp_graph": { @@ -767,7 +857,8 @@ "default_value": "[[3.5,200],[7.0,240]]", "enabled": "False", "comments": "old enabled function: material_flow_dependent_temperature", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "material_extrusion_cool_down_speed": { "label": "Extrusion Cool Down Speed Modifier", @@ -777,9 +868,10 @@ "default_value": 0.5, "minimum_value": "0", "maximum_value_warning": "10.0", - "global_only": "True", "enabled": "False", - "comments": "old enabled function: material_flow_dependent_temperature or machine_extruder_count > 1" + "comments": "old enabled function: material_flow_dependent_temperature or machine_extruder_count > 1", + "settable_per_mesh": false, + "settable_per_extruder": true }, "material_bed_temperature": { "label": "Bed Temperature", @@ -790,7 +882,9 @@ "minimum_value": "0", "maximum_value_warning": "260", "enabled": "machine_heated_bed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "material_diameter": { "label": "Diameter", @@ -801,7 +895,8 @@ "minimum_value": "0.0001", "minimum_value_warning": "0.4", "maximum_value_warning": "3.5", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "material_flow": { "label": "Flow", @@ -811,13 +906,15 @@ "type": "float", "minimum_value": "5", "minimum_value_warning": "50", - "maximum_value_warning": "150" + "maximum_value_warning": "150", + "settable_per_mesh": true }, "retraction_enable": { "label": "Enable Retraction", "description": "Retract the filament when the nozzle is moving over a non-printed area. ", "type": "bool", - "default_value": true + "default_value": true, + "settable_per_mesh": true }, "retraction_amount": { "label": "Retraction Distance", @@ -827,7 +924,8 @@ "default_value": 6.5, "minimum_value_warning": "-0.0001", "maximum_value_warning": "10.0", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true }, "retraction_speed": { "label": "Retraction Speed", @@ -839,6 +937,7 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", + "settable_per_mesh": true, "children": { "retraction_retract_speed": { "label": "Retraction Retract Speed", @@ -850,7 +949,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", - "value": "retraction_speed" + "value": "retraction_speed", + "settable_per_mesh": true }, "retraction_prime_speed": { "label": "Retraction Prime Speed", @@ -862,7 +962,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", - "value": "retraction_speed" + "value": "retraction_speed", + "settable_per_mesh": true } } }, @@ -874,7 +975,8 @@ "default_value": 0, "minimum_value_warning": "-0.0001", "maximum_value_warning": "5.0", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true }, "retraction_min_travel": { "label": "Retraction Minimum Travel", @@ -885,7 +987,8 @@ "value": "line_width * 2", "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true }, "retraction_count_max": { "label": "Maximum Retraction Count", @@ -894,7 +997,8 @@ "minimum_value": "0", "maximum_value_warning": "100", "type": "int", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true }, "retraction_extrusion_window": { "label": "Minimum Extrusion Distance Window", @@ -905,7 +1009,8 @@ "minimum_value": "0", "maximum_value_warning": "retraction_amount * 2", "value": "retraction_amount", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true }, "retraction_hop": { "label": "Z Hop when Retracting", @@ -915,7 +1020,8 @@ "default_value": 0, "minimum_value_warning": "-0.0001", "maximum_value_warning": "10", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true }, "material_standby_temperature": { @@ -926,7 +1032,8 @@ "default_value": 150, "minimum_value": "0", "maximum_value_warning": "260", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "switch_extruder_retraction_amount": { @@ -939,7 +1046,8 @@ "value": "machine_heat_zone_length", "minimum_value_warning": "0", "maximum_value_warning": "100", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "switch_extruder_retraction_speeds": { @@ -951,7 +1059,8 @@ "default_value": 20, "minimum_value": "0.1", "maximum_value_warning": "300", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, "children": { "switch_extruder_retraction_speed": @@ -965,7 +1074,8 @@ "value": "switch_extruder_retraction_speeds", "minimum_value": "0.1", "maximum_value_warning": "300", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "switch_extruder_prime_speed": { @@ -978,7 +1088,8 @@ "value": "switch_extruder_retraction_speeds", "minimum_value": "0.1", "maximum_value_warning": "300", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -991,7 +1102,9 @@ "default_value": 1, "minimum_value_warning": "-0.0001", "maximum_value_warning": "10", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1013,6 +1126,7 @@ "maximum_value_warning": "150", "maximum_value": "299792458000", "default_value": 60, + "settable_per_mesh": true, "children": { "speed_infill": @@ -1025,7 +1139,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 60, - "value": "speed_print" + "value": "speed_print", + "settable_per_mesh": true }, "speed_wall": { @@ -1038,19 +1153,21 @@ "maximum_value_warning": "150", "default_value": 30, "value": "speed_print / 2", + "settable_per_mesh": true, "children": { "speed_wall_0": { "label": "Outer Wall Speed", - "description": "The speed at which the outermost walls are printed. Printing the outer wall at a lower speed improves the final skin quality. However, having a large difference between the inner wall speed and the outer wall speed will effect quality in a negative way.", + "description": "The speed at which the outermost walls are printed. Printing the outer wall at a lower speed improves the final skin quality. However, having a large difference between the inner wall speed and the outer wall speed will affect quality in a negative way.", "unit": "mm/s", "type": "float", "minimum_value": "0.1", "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 30, - "value": "speed_wall" + "value": "speed_wall", + "settable_per_mesh": true }, "speed_wall_x": { @@ -1062,7 +1179,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 60, - "value": "speed_wall * 2" + "value": "speed_wall * 2", + "settable_per_mesh": true } } }, @@ -1076,7 +1194,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 30, - "value": "speed_print / 2" + "value": "speed_print / 2", + "settable_per_mesh": true }, "speed_support": { @@ -1090,6 +1209,8 @@ "default_value": 60, "value": "speed_print", "enabled": "support_roof_enable", + "settable_per_mesh": false, + "settable_per_extruder": false, "children": { "speed_support_infill": @@ -1104,7 +1225,8 @@ "maximum_value_warning": "150", "value": "speed_support", "enabled": "support_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "speed_support_roof": { @@ -1118,7 +1240,8 @@ "maximum_value_warning": "150", "enabled": "support_roof_enable and support_enable", "value": "speed_support / 1.5", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false } } }, @@ -1133,7 +1256,8 @@ "value": "speed_print", "minimum_value": "0.1", "maximum_value_warning": "150", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1148,7 +1272,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "300", "value": "speed_print if magic_spiralize else 120", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "speed_layer_0": { "label": "Initial Layer Speed", @@ -1158,7 +1283,8 @@ "default_value": 30, "minimum_value": "0.1", "maximum_value": "299792458000", - "maximum_value_warning": "300" + "maximum_value_warning": "300", + "settable_per_mesh": true }, "skirt_speed": { "label": "Skirt Speed", @@ -1170,7 +1296,8 @@ "maximum_value": "299792458000", "maximum_value_warning": "300", "value": "speed_layer_0", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "speed_slowdown_layers": { @@ -1181,7 +1308,8 @@ "minimum_value": "0", "maximum_value": "299792458000", "maximum_value_warning": "300", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false } } }, @@ -1205,7 +1333,7 @@ "noskin": "No Skin" }, "default_value": "all", - "global_only": true + "settable_per_mesh": true }, "travel_avoid_other_parts": { @@ -1214,7 +1342,8 @@ "type": "bool", "default_value": true, "enabled": "retraction_combing != \"off\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "travel_avoid_distance": { @@ -1227,7 +1356,8 @@ "minimum_value": "0", "maximum_value_warning": "machine_nozzle_tip_outer_diameter * 5", "enabled": "retraction_combing != \"off\" and travel_avoid_other_parts", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1245,7 +1375,8 @@ "description": "Enables the cooling fans while printing. The fans improve print quality on layers with short layer times and bridging / overhangs.", "type": "bool", "default_value": true, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "cool_fan_speed": { @@ -1258,7 +1389,8 @@ "default_value": 100, "value": "100.0 if cool_fan_enabled else 0.0", "enabled": "cool_fan_enabled", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, "children": { "cool_fan_speed_min": @@ -1272,7 +1404,8 @@ "value": "cool_fan_speed", "default_value": 100, "enabled": "cool_fan_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "cool_fan_speed_max": { @@ -1284,8 +1417,9 @@ "maximum_value": "100", "default_value": 100, "enabled": "cool_fan_enabled", - "global_only": "True", - "value": "cool_fan_speed" + "value": "cool_fan_speed", + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1298,7 +1432,8 @@ "default_value": 10, "minimum_value": "cool_min_layer_time", "maximum_value_warning": "600", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "cool_fan_full_at_height": { @@ -1310,7 +1445,8 @@ "value": "layer_height_0", "minimum_value": "0", "maximum_value_warning": "10.0", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, "children": { "cool_fan_full_layer": @@ -1322,7 +1458,8 @@ "minimum_value": "0", "maximum_value_warning": "100", "value": "max(0, int(round((cool_fan_full_at_height - layer_height_0) / layer_height, 0)))", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1335,7 +1472,8 @@ "default_value": 5, "minimum_value": "0", "maximum_value_warning": "600", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "cool_min_speed": { @@ -1346,7 +1484,8 @@ "default_value": 10, "minimum_value": "0", "maximum_value_warning": "100", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "cool_lift_head": { @@ -1354,7 +1493,8 @@ "description": "When the minimum speed is hit because of minimum layer time, lift the head away from the print and wait the extra time until the minimum layer time is reached.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1371,7 +1511,8 @@ "label": "Enable Support", "description": "Enable support structures. These structures support parts of the model with severe overhangs.", "type": "bool", - "default_value": false + "default_value": false, + "settable_per_mesh": true }, "support_type": { @@ -1384,7 +1525,9 @@ "everywhere": "Everywhere" }, "default_value": "everywhere", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_angle": { @@ -1395,7 +1538,8 @@ "minimum_value": "0", "maximum_value": "90", "default_value": 50, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_pattern": { @@ -1412,7 +1556,8 @@ }, "default_value": "zigzag", "enabled": "support_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_connect_zigzags": { @@ -1421,7 +1566,8 @@ "type": "bool", "default_value": true, "enabled": "support_enable and (support_pattern == \"zigzag\")", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_infill_rate": { @@ -1433,7 +1579,8 @@ "maximum_value_warning": "100", "default_value": 15, "enabled": "support_enable", - "global_only": true, + "settable_per_mesh": false, + "settable_per_extruder": false, "children": { "support_line_distance": { @@ -1445,7 +1592,8 @@ "default_value": 2.66, "enabled": "support_enable", "value": "(support_line_width * 100) / support_infill_rate * (2 if support_pattern == \"grid\" else (3 if support_pattern == \"triangles\" else 1))", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false } } }, @@ -1459,7 +1607,7 @@ "maximum_value_warning": "10", "default_value": 0.15, "enabled": "support_enable", - + "settable_per_mesh": true, "children": { "support_top_distance": @@ -1472,7 +1620,8 @@ "default_value": 0.15, "type": "float", "enabled": "support_enable", - "value": "support_z_distance" + "value": "support_z_distance", + "settable_per_mesh": true }, "support_bottom_distance": { @@ -1484,7 +1633,8 @@ "default_value": 0.1, "value": "0.1 if support_type == 'everywhere' else 0", "type": "float", - "enabled": "support_enable and support_type == 'everywhere'" + "enabled": "support_enable and support_type == 'everywhere'", + "settable_per_mesh": true } } }, @@ -1497,7 +1647,8 @@ "minimum_value": "0", "maximum_value_warning": "10", "default_value": 0.7, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_xy_overrides_z": { "label": "Support Distance Priority", @@ -1508,7 +1659,8 @@ "z_overrides_xy": "Z overrides X/Y" }, "default_value": "z_overrides_xy", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_xy_distance_overhang": { "label": "Minimum Support X/Y Distance", @@ -1519,7 +1671,8 @@ "maximum_value_warning": "10", "default_value": 0.2, "value": "machine_nozzle_size / 2", - "enabled": "support_enable and 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": { @@ -1530,7 +1683,8 @@ "default_value": 0.3, "minimum_value": "0", "maximum_value_warning": "1.0", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_join_distance": { @@ -1541,7 +1695,8 @@ "default_value": 2.0, "minimum_value_warning": "0", "maximum_value_warning": "10", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_offset": { @@ -1552,7 +1707,8 @@ "default_value": 0.2, "minimum_value_warning": "-0.5", "maximum_value_warning": "5.0", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_area_smoothing": { @@ -1563,7 +1719,8 @@ "default_value": 0.6, "minimum_value": "0", "maximum_value_warning": "1.0", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_roof_enable": { @@ -1571,7 +1728,8 @@ "description": "Generate a dense top skin at the top of the support on which the model is printed.", "type": "bool", "default_value": false, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_roof_height": { @@ -1582,7 +1740,8 @@ "default_value": 1, "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "support_roof_enable" + "enabled": "support_roof_enable", + "settable_per_mesh": true }, "support_roof_density": { @@ -1594,7 +1753,8 @@ "minimum_value": "0", "maximum_value_warning": "100", "enabled":"support_roof_enable", - "global_only": true, + "settable_per_mesh": false, + "settable_per_extruder": false, "children": { "support_roof_line_distance": @@ -1607,7 +1767,8 @@ "minimum_value": "0", "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))", "enabled": "support_roof_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false } } }, @@ -1626,7 +1787,8 @@ }, "default_value": "concentric", "enabled": "support_roof_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_use_towers": { @@ -1634,7 +1796,8 @@ "description": "Use specialized towers to support tiny overhang areas. These towers have a larger diameter than the region they support. Near the overhang the towers' diameter decreases, forming a roof.", "type": "bool", "default_value": true, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_tower_diameter": { @@ -1645,7 +1808,8 @@ "default_value": 3.0, "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "support_enable and support_use_towers" + "enabled": "support_enable and support_use_towers", + "settable_per_mesh": true }, "support_minimal_diameter": { @@ -1657,7 +1821,8 @@ "minimum_value": "0", "maximum_value_warning": "10", "maximum_value": "support_tower_diameter", - "enabled": "support_enable and support_use_towers" + "enabled": "support_enable and support_use_towers", + "settable_per_mesh": true }, "support_tower_roof_angle": { @@ -1668,7 +1833,8 @@ "minimum_value": "0", "maximum_value": "90", "default_value": 65, - "enabled": "support_enable and support_use_towers" + "enabled": "support_enable and support_use_towers", + "settable_per_mesh": true } } }, @@ -1692,7 +1858,8 @@ "raft": "Raft" }, "default_value": "brim", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "skirt_line_count": { @@ -1703,7 +1870,8 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "adhesion_type == \"skirt\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "skirt_gap": { @@ -1715,7 +1883,8 @@ "minimum_value_warning": "0", "maximum_value_warning": "100", "enabled": "adhesion_type == \"skirt\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "skirt_minimal_length": { @@ -1728,7 +1897,8 @@ "minimum_value_warning": "25", "maximum_value_warning": "2500", "enabled": "adhesion_type == \"skirt\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "brim_width": { @@ -1740,7 +1910,8 @@ "minimum_value": "0.0", "maximum_value_warning": "100.0", "enabled": "adhesion_type == \"brim\"", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, "children": { "brim_line_count": @@ -1753,7 +1924,8 @@ "maximum_value_warning": "300", "value": "math.ceil(brim_width / skirt_line_width)", "enabled": "adhesion_type == \"brim\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1766,8 +1938,7 @@ "default_value": 5, "minimum_value_warning": "0", "maximum_value_warning": "10", - "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "enabled": "adhesion_type == \"raft\"" }, "raft_airgap": { @@ -1779,7 +1950,8 @@ "minimum_value": "0", "maximum_value_warning": "1.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "layer_0_z_overlap": { "label": "Initial Layer Z Overlap", @@ -1791,7 +1963,8 @@ "minimum_value": "0", "maximum_value_warning": "layer_height", "enabled": "adhesion_type == 'raft'", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_surface_layers": { @@ -1802,7 +1975,8 @@ "minimum_value": "0", "maximum_value_warning": "20", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_surface_thickness": { @@ -1814,7 +1988,8 @@ "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_surface_line_width": { @@ -1826,7 +2001,8 @@ "minimum_value": "0.0001", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_surface_line_spacing": { @@ -1839,7 +2015,8 @@ "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", "value": "raft_surface_line_width", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_interface_thickness": { @@ -1851,7 +2028,8 @@ "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_interface_line_width": { @@ -1864,7 +2042,8 @@ "minimum_value": "0.0001", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_interface_line_spacing": { @@ -1876,7 +2055,8 @@ "minimum_value": "0", "maximum_value_warning": "15.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_base_thickness": { @@ -1888,7 +2068,8 @@ "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_base_line_width": { @@ -1901,7 +2082,8 @@ "value": "line_width * 2", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_base_line_spacing": { @@ -1913,7 +2095,8 @@ "minimum_value": "0.0001", "maximum_value_warning": "100", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_speed": { @@ -1927,7 +2110,8 @@ "maximum_value_warning": "200", "enabled": "adhesion_type == \"raft\"", "value": "speed_print / 60 * 30", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, "children": { "raft_surface_speed": @@ -1942,7 +2126,8 @@ "maximum_value_warning": "100", "enabled": "adhesion_type == \"raft\"", "value": "raft_speed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_interface_speed": { @@ -1956,7 +2141,8 @@ "maximum_value_warning": "150", "enabled": "adhesion_type == \"raft\"", "value": "0.5 * raft_speed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_base_speed": { @@ -1970,7 +2156,8 @@ "maximum_value_warning": "200", "enabled": "adhesion_type == \"raft\"", "value": "0.5 * raft_speed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -1983,7 +2170,8 @@ "minimum_value": "0", "maximum_value": "100", "default_value": 0, - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, "enabled": "adhesion_type == \"raft\"", "children": { @@ -1996,9 +2184,10 @@ "minimum_value": "0", "maximum_value": "100", "default_value": 0, - "global_only": "True", "value": "raft_fan_speed", - "enabled": "adhesion_type == \"raft\"" + "enabled": "adhesion_type == \"raft\"", + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_interface_fan_speed": { @@ -2009,9 +2198,10 @@ "minimum_value": "0", "maximum_value": "100", "default_value": 0, - "global_only": "True", "value": "raft_fan_speed", - "enabled": "adhesion_type == \"raft\"" + "enabled": "adhesion_type == \"raft\"", + "settable_per_mesh": false, + "settable_per_extruder": true }, "raft_base_fan_speed": { @@ -2022,9 +2212,10 @@ "minimum_value": "0", "maximum_value": "100", "default_value": 0, - "global_only": "True", "value": "raft_fan_speed", - "enabled": "adhesion_type == \"raft\"" + "enabled": "adhesion_type == \"raft\"", + "settable_per_mesh": false, + "settable_per_extruder": true } } } @@ -2043,28 +2234,32 @@ "label": "Union Overlapping Volumes", "description": "Ignore the internal geometry arising from overlapping volumes and print the volumes as one. This may cause internal cavities to disappear.", "type": "bool", - "default_value": true + "default_value": true, + "settable_per_mesh": true }, "meshfix_union_all_remove_holes": { "label": "Remove All Holes", "description": "Remove the holes in each layer and keep only the outside shape. This will ignore any invisible internal geometry. However, it also ignores layer holes which can be viewed from above or below.", "type": "bool", - "default_value": false + "default_value": false, + "settable_per_mesh": true }, "meshfix_extensive_stitching": { "label": "Extensive Stitching", "description": "Extensive stitching tries to stitch up open holes in the mesh by closing the hole with touching polygons. This option can introduce a lot of processing time.", "type": "bool", - "default_value": false + "default_value": false, + "settable_per_mesh": true }, "meshfix_keep_open_polygons": { "label": "Keep Disconnected Faces", "description": "Normally Cura tries to stitch up small holes in the mesh and remove parts of a layer with big holes. Enabling this option keeps those parts which cannot be stitched. This option should be used as a last resort option when everything else fails to produce proper GCode.", "type": "bool", - "default_value": false + "default_value": false, + "settable_per_mesh": true } } }, @@ -2087,7 +2282,9 @@ "one_at_a_time": "One at a Time" }, "default_value": "all_at_once", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "magic_mesh_surface_mode": { @@ -2100,7 +2297,8 @@ "surface": "Surface", "both": "Both" }, - "default_value": "normal" + "default_value": "normal", + "settable_per_mesh": true }, "magic_spiralize": { @@ -2108,7 +2306,7 @@ "description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid object into a single walled print with a solid bottom. This feature used to be called Joris in older versions.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": true } } }, @@ -2128,7 +2326,8 @@ "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_extruder_nr": { @@ -2139,7 +2338,8 @@ "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", "enabled": "support_enable", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": false, "children": { "support_infill_extruder_nr": { @@ -2150,7 +2350,8 @@ "value": "support_extruder_nr", "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_extruder_nr_layer_0": { @@ -2161,7 +2362,8 @@ "value": "support_extruder_nr", "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "support_roof_extruder_nr": { @@ -2172,7 +2374,8 @@ "value": "support_extruder_nr", "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false } } }, @@ -2182,7 +2385,8 @@ "description": "Print a tower next to the print which serves to prime the material after each nozzle switch.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "prime_tower_size": { @@ -2195,7 +2399,8 @@ "value": "15 if prime_tower_enable else 0", "minimum_value": "0", "maximum_value_warning": "20", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "prime_tower_position_x": { @@ -2207,7 +2412,8 @@ "default_value": 200, "minimum_value_warning": "-1000", "maximum_value_warning": "1000", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "prime_tower_position_y": { @@ -2219,7 +2425,8 @@ "default_value": 200, "minimum_value_warning": "-1000", "maximum_value_warning": "1000", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "prime_tower_flow": { @@ -2232,7 +2439,8 @@ "minimum_value": "0.0001", "minimum_value_warning": "50", "maximum_value_warning": "150", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true }, "prime_tower_wipe_enabled": { @@ -2241,7 +2449,8 @@ "type": "bool", "enabled": "prime_tower_enable", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "multiple_mesh_overlap": { @@ -2251,7 +2460,8 @@ "unit": "mm", "default_value": 0.15, "minimum_value": "0", - "maximum_value_warning": "1.0" + "maximum_value_warning": "1.0", + "settable_per_mesh": true }, "ooze_shield_enabled": { @@ -2259,7 +2469,8 @@ "description": "Enable exterior ooze shield. This will create a shell around the object which is likely to wipe a second nozzle if it's at the same height as the first nozzle.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "ooze_shield_angle": { @@ -2271,7 +2482,8 @@ "default_value": 60, "minimum_value": "0", "maximum_value": "90", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false }, "ooze_shield_dist": { @@ -2283,7 +2495,8 @@ "default_value": 2, "minimum_value": "0", "maximum_value_warning": "30", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false } } }, @@ -2301,7 +2514,8 @@ "description": "This will create a wall around the object, which traps (hot) air and shields against exterior airflow. Especially useful for materials which warp easily.", "type": "bool", "default_value": false, - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "draft_shield_dist": { @@ -2313,7 +2527,8 @@ "maximum_value_warning": "100", "default_value": 10, "enabled": "draft_shield_enabled", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "draft_shield_height_limitation": { @@ -2327,7 +2542,8 @@ }, "default_value": "full", "enabled": "draft_shield_enabled", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "draft_shield_height": { @@ -2340,7 +2556,8 @@ "default_value": 0, "value": "9999 if draft_shield_height_limitation == 'full' and draft_shield_enabled else 0.0", "enabled": "draft_shield_height_limitation == \"limited\"", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false }, "conical_overhang_enabled": { "label": "Make Overhang Printable", @@ -2364,7 +2581,8 @@ "description": "Coasting replaces the last part of an extrusion path with a travel path. The oozed material is used to print the last piece of the extrusion path in order to reduce stringing.", "type": "bool", "default_value": false, - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "coasting_volume": { @@ -2376,7 +2594,8 @@ "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "coasting_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "coasting_min_volume": { @@ -2388,7 +2607,8 @@ "minimum_value": "0", "maximum_value_warning": "10.0", "enabled": "coasting_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "coasting_speed": { @@ -2400,7 +2620,8 @@ "minimum_value": "0.0001", "maximum_value_warning": "100", "enabled": "coasting_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true }, "skin_outline_count": { @@ -2409,7 +2630,8 @@ "default_value": 0, "minimum_value": "0", "maximum_value_warning": "10", - "type": "int" + "type": "int", + "settable_per_mesh": true }, "skin_alternate_rotation": { @@ -2417,7 +2639,8 @@ "description": "Alternate the direction in which the top/bottom layers are printed. Normally they are printed diagonally only. This setting adds the X-only and Y-only directions.", "type": "bool", "default_value": false, - "enabled": "top_bottom_pattern != \"concentric\"" + "enabled": "top_bottom_pattern != \"concentric\"", + "settable_per_mesh": true }, "support_conical_enabled": { @@ -2425,7 +2648,8 @@ "description": "Experimental feature: Make support areas smaller at the bottom than at the overhang.", "type": "bool", "default_value": false, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true }, "support_conical_angle": { @@ -2438,7 +2662,8 @@ "maximum_value_warning": "45", "maximum_value": "90", "default_value": 30, - "enabled": "support_conical_enabled and support_enable" + "enabled": "support_conical_enabled and support_enable", + "settable_per_mesh": true }, "support_conical_min_width": { @@ -2450,14 +2675,16 @@ "minimum_value_warning": "machine_nozzle_size * 3", "maximum_value_warning": "100.0", "type": "float", - "enabled": "support_conical_enabled and support_enable" + "enabled": "support_conical_enabled and support_enable", + "settable_per_mesh": true }, "magic_fuzzy_skin_enabled": { "label": "Fuzzy Skin", "description": "Randomly jitter while printing the outer wall, so that the surface has a rough and fuzzy look.", "type": "bool", - "default_value": false + "default_value": false, + "settable_per_mesh": true }, "magic_fuzzy_skin_thickness": { @@ -2468,7 +2695,8 @@ "default_value": 0.3, "minimum_value": "0.001", "maximum_value_warning": "wall_line_width_0", - "enabled": "magic_fuzzy_skin_enabled" + "enabled": "magic_fuzzy_skin_enabled", + "settable_per_mesh": true }, "magic_fuzzy_skin_point_density": { @@ -2482,6 +2710,7 @@ "maximum_value_warning": "10", "maximum_value": "2 / magic_fuzzy_skin_thickness", "enabled": "magic_fuzzy_skin_enabled", + "settable_per_mesh": true, "children": { "magic_fuzzy_skin_point_dist": @@ -2495,7 +2724,8 @@ "minimum_value_warning": "0.1", "maximum_value_warning": "10", "value": "10000 if magic_fuzzy_skin_point_density == 0 else 1 / magic_fuzzy_skin_point_density", - "enabled": "magic_fuzzy_skin_enabled" + "enabled": "magic_fuzzy_skin_enabled", + "settable_per_mesh": true } } }, @@ -2505,7 +2735,9 @@ "description": "Print only the outside surface with a sparse webbed structure, printing 'in thin air'. This is realized by horizontally printing the contours of the model at given Z intervals which are connected via upward and diagonally downward lines.", "type": "bool", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_height": { @@ -2517,7 +2749,9 @@ "minimum_value": "0.0001", "maximum_value_warning": "20", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_roof_inset": { @@ -2531,7 +2765,9 @@ "maximum_value_warning": "20", "enabled": "wireframe_enabled", "value": "wireframe_height", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_printspeed": { @@ -2544,7 +2780,9 @@ "maximum_value": "299792458000", "maximum_value_warning": "50", "enabled": "wireframe_enabled", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false, "children": { "wireframe_printspeed_bottom": @@ -2558,8 +2796,10 @@ "maximum_value": "299792458000", "maximum_value_warning": "50", "enabled": "wireframe_enabled", - "global_only": "True", - "value": "wireframe_printspeed" + "value": "wireframe_printspeed", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_printspeed_up": { @@ -2572,8 +2812,10 @@ "maximum_value": "299792458000", "maximum_value_warning": "50", "enabled": "wireframe_enabled", - "global_only": "True", - "value": "wireframe_printspeed" + "value": "wireframe_printspeed", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_printspeed_down": { @@ -2586,8 +2828,10 @@ "maximum_value": "299792458000", "maximum_value_warning": "50", "enabled": "wireframe_enabled", - "global_only": "True", - "value": "wireframe_printspeed" + "value": "wireframe_printspeed", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_printspeed_flat": { @@ -2601,7 +2845,9 @@ "maximum_value_warning": "100", "value": "wireframe_printspeed", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false } } }, @@ -2615,7 +2861,9 @@ "maximum_value_warning": "100", "type": "float", "enabled": "wireframe_enabled", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false, "children": { "wireframe_flow_connection": @@ -2628,8 +2876,10 @@ "maximum_value_warning": "100", "type": "float", "enabled": "wireframe_enabled", - "global_only": "True", - "value": "wireframe_flow" + "value": "wireframe_flow", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_flow_flat": { @@ -2641,8 +2891,10 @@ "maximum_value_warning": "100", "type": "float", "enabled": "wireframe_enabled", - "global_only": "True", - "value": "wireframe_flow" + "value": "wireframe_flow", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false } } }, @@ -2656,7 +2908,9 @@ "minimum_value": "0", "maximum_value_warning": "1", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_bottom_delay": { @@ -2668,7 +2922,9 @@ "minimum_value": "0", "maximum_value_warning": "1", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_flat_delay": { @@ -2680,7 +2936,9 @@ "minimum_value": "0", "maximum_value_warning": "0.5", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_up_half_speed": { @@ -2692,7 +2950,9 @@ "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_top_jump": { @@ -2704,7 +2964,9 @@ "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_fall_down": { @@ -2716,7 +2978,9 @@ "minimum_value": "0", "maximum_value_warning": "wireframe_height", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_drag_along": { @@ -2728,7 +2992,9 @@ "minimum_value": "0", "maximum_value_warning": "wireframe_height", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_strategy": { @@ -2743,7 +3009,9 @@ }, "default_value": "compensate", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_straight_before_down": { @@ -2755,7 +3023,9 @@ "minimum_value": "0", "maximum_value": "100", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_roof_fall_down": { @@ -2767,7 +3037,9 @@ "minimum_value_warning": "0", "maximum_value_warning": "wireframe_roof_inset", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_roof_drag_along": { @@ -2779,7 +3051,9 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_roof_outer_delay": { @@ -2791,7 +3065,9 @@ "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false }, "wireframe_nozzle_clearance": { @@ -2803,7 +3079,9 @@ "minimum_value_warning": "0", "maximum_value_warning": "10.0", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false } } } diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index e09b6b5424..7e03bd7102 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -111,23 +111,23 @@ Item { id: updateProfileAction; enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) - text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile"); - onTriggered: Cura.MachineManager.updateUserContainerToQuality() + text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings"); + onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer() } Action { id: resetProfileAction; enabled: Cura.MachineManager.hasUserSettings - text: catalog.i18nc("@action:inmenu menubar:profile","&Reload Current Profile"); + text: catalog.i18nc("@action:inmenu menubar:profile","&Discard current settings"); onTriggered: Cura.MachineManager.clearUserSettings(); } Action { id: addProfileAction; - enabled: Cura.MachineManager.isGlobalStackValid - text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile..."); + enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings + text: catalog.i18nc("@action:inmenu menubar:profile","&Create profile from current settings..."); } Action diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 46ebc25369..c3dc95b454 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -258,13 +258,13 @@ UM.MainWindow { //Insert a separator between readonly and custom profiles if(separatorIndex < 0 && index > 0) { - if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) { + if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) { profileMenu.insertSeparator(index); separatorIndex = index; } } //Because of the separator, custom profiles move one index lower - profileMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item); + profileMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item); } onObjectRemoved: { @@ -297,11 +297,11 @@ UM.MainWindow MenuSeparator { id: profileMenuSeparator } - MenuItem { action: Cura.Actions.updateProfile; } - MenuItem { action: Cura.Actions.resetProfile; } - MenuItem { action: Cura.Actions.addProfile; } + MenuItem { action: Cura.Actions.addProfile } + MenuItem { action: Cura.Actions.updateProfile } + MenuItem { action: Cura.Actions.resetProfile } MenuSeparator { } - MenuItem { action: Cura.Actions.manageProfiles; } + MenuItem { action: Cura.Actions.manageProfiles } } Menu @@ -533,13 +533,6 @@ UM.MainWindow } width: UM.Theme.getSize("sidebar").width; - - addMachineAction: Cura.Actions.addMachine; - configureMachinesAction: Cura.Actions.configureMachines; - addProfileAction: Cura.Actions.addProfile; - updateProfileAction: Cura.Actions.updateProfile; - resetProfileAction: Cura.Actions.resetProfile; - manageProfilesAction: Cura.Actions.manageProfiles; } } } @@ -589,7 +582,7 @@ UM.MainWindow target: Cura.Actions.addProfile onTriggered: { - Cura.MachineManager.convertUserContainerToQuality(); + Cura.MachineManager.newQualityContainerFromQualityAndUser(); preferences.setPage(5); preferences.show(); diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 97dd2c5d77..670bf79956 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -13,7 +13,7 @@ UM.ManagementPage id: base; title: catalog.i18nc("@title:tab", "Profiles"); - addText: catalog.i18nc("@label", "Duplicate") + addText: base.currentItem && (base.currentItem.id == Cura.MachineManager.activeQualityId) ? catalog.i18nc("@label", "Create") : catalog.i18nc("@label", "Duplicate") model: UM.InstanceContainersModel { @@ -36,6 +36,21 @@ UM.ManagementPage } } + section.property: "readOnly" + section.delegate: Rectangle + { + width: objectListContainer.viewport.width; + height: childrenRect.height; + + Label + { + anchors.left: parent.left; + anchors.leftMargin: UM.Theme.getSize("default_lining").width; + text: section == "true" ? catalog.i18nc("@label", "Protected profiles") : catalog.i18nc("@label", "Custom profiles") + font.bold: true + } + } + activeId: Cura.MachineManager.activeQualityId activeIndex: { for(var i = 0; i < model.rowCount(); i++) { @@ -49,9 +64,8 @@ UM.ManagementPage onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) onAddObject: { var selectedContainer; - if (objectList.currentIndex == 0) { - // Current settings - selectedContainer = Cura.MachineManager.convertUserContainerToQuality(); + if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) { + selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser(); } else { selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); } @@ -66,8 +80,8 @@ UM.ManagementPage activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false; addEnabled: currentItem != null; - removeEnabled: currentItem != null ? !currentItem.metadata.read_only : false; - renameEnabled: currentItem != null ? !currentItem.metadata.read_only : false; + removeEnabled: currentItem != null ? !currentItem.readOnly : false; + renameEnabled: currentItem != null ? !currentItem.readOnly : false; scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) @@ -102,17 +116,15 @@ UM.ManagementPage Button { text: { - var profileName = Cura.MachineManager.activeQualityName; - profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName; - return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName)); + return catalog.i18nc("@action:button", "Update profile with current settings"); } enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) - onClicked: Cura.MachineManager.updateUserContainerToQuality() + onClicked: Cura.MachineManager.updateQualityContainerFromUserContainer() } Button { - text: catalog.i18nc("@action:button", "Discard changes"); + text: catalog.i18nc("@action:button", "Discard current settings"); enabled: Cura.MachineManager.hasUserSettings onClicked: Cura.MachineManager.clearUserSettings(); } @@ -128,7 +140,7 @@ UM.ManagementPage Label { id: defaultsMessage - visible: !currentItem.hasSettings + visible: !currentItem.metadata.has_settings text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.") wrapMode: Text.WordWrap width: parent.width @@ -155,7 +167,7 @@ UM.ManagementPage model: Cura.ContainerSettingsModel{ containers: (currentItem.id == Cura.MachineManager.activeQualityId) ? [base.currentItem.id, Cura.MachineManager.activeUserProfileId] : [base.currentItem.id] } delegate: Row { property variant setting: model - spacing: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").width/2 Label { text: model.label elide: Text.ElideMiddle @@ -165,7 +177,8 @@ UM.ManagementPage model: setting.values.length Label { text: setting.values[index].toString() - width: scrollView.width / 100 * 10 + width: scrollView.width / 100 * 15 + elide: Text.ElideRight font.strikeout: index < setting.values.length - 1 && setting.values[index + 1] != "" opacity: font.strikeout ? 0.5 : 1 } @@ -174,6 +187,21 @@ UM.ManagementPage text: model.unit } } + header: Row { + visible: currentItem.id == Cura.MachineManager.activeQualityId + spacing: UM.Theme.getSize("default_margin").width + Label { + text: catalog.i18nc("@action:label", "Profile:") + width: scrollView.width / 100 * 55 + horizontalAlignment: Text.AlignRight + font.bold: true + } + Label { + text: catalog.i18nc("@action:label", "Current:") + visible: currentItem.id == Cura.MachineManager.activeQualityId + font.bold: true + } + } section.property: "category" section.criteria: ViewSection.FullString section.delegate: Label { @@ -268,7 +296,7 @@ UM.ManagementPage folder: base.model.getDefaultPath() onAccepted: { - var result = base.model.exportProfile(base.currentItem.id, fileUrl) + var result = base.model.exportProfile(base.currentItem.id, fileUrl, selectedNameFilter) if(result && result.status == "error") { messageDialog.icon = StandardIcon.Critical diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml deleted file mode 100644 index 48d52c539a..0000000000 --- a/resources/qml/ProfileSetup.qml +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2015 Ultimaker B.V. -// Cura is released under the terms of the AGPLv3 or higher. - -import QtQuick 2.2 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Layouts 1.1 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Item{ - id: base; - UM.I18nCatalog { id: catalog; name:"cura"} - property int totalHeightProfileSetup: childrenRect.height - property Action manageProfilesAction - property Action addProfileAction - property Action updateProfileAction - property Action resetProfileAction - - signal showTooltip(Item item, point location, string text) - signal hideTooltip() - - Rectangle{ - id: globalProfileRow - anchors.top: base.top - height: UM.Theme.getSize("sidebar_setup").height - width: base.width - - Label{ - id: globalProfileLabel - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width; - anchors.verticalCenter: parent.verticalCenter - text: catalog.i18nc("@label","Profile:"); - width: parent.width/100*45 - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton { - property int rightMargin: customisedSettings.visible ? customisedSettings.width + UM.Theme.getSize("default_margin").width / 2 : 0 - - id: globalProfileSelection - text: Cura.MachineManager.activeQualityName - width: parent.width/100*55 - height: UM.Theme.getSize("setting_control").height - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - anchors.verticalCenter: parent.verticalCenter - tooltip: Cura.MachineManager.activeQualityName - style: UM.Theme.styles.sidebar_header_button - - menu: Menu - { - id: profileSelectionMenu - Instantiator - { - id: profileSelectionInstantiator - model: UM.InstanceContainersModel - { - filter: - { - var result = { "type": "quality" }; - if(Cura.MachineManager.filterQualityByMachine) - { - result.definition = Cura.MachineManager.activeDefinitionId; - if(Cura.MachineManager.hasMaterials) - { - result.material = Cura.MachineManager.activeMaterialId; - } - } - else - { - result.definition = "fdmprinter" - } - return result - } - } - property int separatorIndex: -1 - - Loader { - property QtObject model_data: model - property int model_index: index - sourceComponent: menuItemDelegate - } - onObjectAdded: - { - //Insert a separator between readonly and custom profiles - if(separatorIndex < 0 && index > 0) { - if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) { - profileSelectionMenu.insertSeparator(index); - separatorIndex = index; - } - } - //Because of the separator, custom profiles move one index lower - profileSelectionMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item); - } - onObjectRemoved: - { - //When adding a profile, the menu is rebuild by removing all items. - //If a separator was added, we need to remove that too. - if(separatorIndex >= 0) - { - profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex]) - separatorIndex = -1; - } - profileSelectionMenu.removeItem(object.item); - } - } - ExclusiveGroup { id: profileSelectionMenuGroup; } - - Component - { - id: menuItemDelegate - MenuItem - { - id: item - text: model_data ? model_data.name : "" - checkable: true - checked: Cura.MachineManager.activeQualityId == model_data.id - exclusiveGroup: profileSelectionMenuGroup; - onTriggered: Cura.MachineManager.setActiveQuality(model_data.id) - } - } - - MenuSeparator { } - MenuItem { - action: base.updateProfileAction; - } - MenuItem { - action: base.resetProfileAction; - } - MenuItem { - action: base.addProfileAction; - } - MenuSeparator { } - MenuItem { - action: base.manageProfilesAction; - } - } - } - UM.SimpleButton { - id: customisedSettings - - visible: Cura.MachineManager.hasUserSettings - height: parent.height * 0.6 - width: parent.height * 0.6 - - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - - color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); - iconSource: UM.Theme.getIcon("star"); - - onClicked: base.manageProfilesAction.trigger() - onEntered: - { - var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.") - base.showTooltip(globalProfileRow, Qt.point(0, globalProfileRow.height / 2), content) - } - onExited: base.hideTooltip() - } - } -} diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index f4c35f876e..6e23158a1c 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -56,9 +56,9 @@ Button { anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - visible: hiddenValuesCount > 0 - height: parent.height / 2; - width: height; + visible: false //hiddenValuesCount > 0 + height: parent.height / 2 + width: height onClicked: { base.showAllHiddenInheritedSettings() diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 0cb1c169df..4fd84759fd 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -174,7 +174,7 @@ Item { break; } } - return state && base.showInheritButton && has_setting_function + return state && base.showInheritButton && has_setting_function && typeof(propertyProvider.getPropertyValue("value", base.stackLevels[0])) != "object" } height: parent.height; @@ -182,22 +182,37 @@ Item { onClicked: { focus = true; - // Get the deepest entry of this setting that we can find. TODO: This is a bit naive, in some cases - // there might be multiple profiles saying something about the same setting. There is no strategy - // how to handle this as of yet. - var last_entry = propertyProvider.stackLevels.slice(-1)[0] - // Put that entry into the "top" instance container. - // This ensures that the value in any of the deeper containers need not be removed, which is - // needed for the reset button (which deletes the top value) to correctly go back to profile - // defaults. - if(last_entry == 4 && base.stackLevel == 0) + + // Get the most shallow function value (eg not a number) that we can find. + var last_entry = propertyProvider.stackLevels[propertyProvider.stackLevels.length] + for (var i = 1; i < base.stackLevels.length; i++) + { + var has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object"; + if(has_setting_function) + { + last_entry = propertyProvider.stackLevels[i] + break; + } + } + + if(last_entry == 4 && base.stackLevel == 0 && base.stackLevels.length == 2) { // Special case of the inherit reset. If only the definition (4th container) and the first // entry (user container) are set, we can simply remove the container. propertyProvider.removeFromContainer(0) } + else if(last_entry - 1 == base.stackLevel) + { + // Another special case. The setting that is overriden is only 1 instance container deeper, + // so we can remove it. + propertyProvider.removeFromContainer(0) + } else { + // Put that entry into the "top" instance container. + // This ensures that the value in any of the deeper containers need not be removed, which is + // needed for the reset button (which deletes the top value) to correctly go back to profile + // defaults. propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) propertyProvider.setPropertyValue("state", "InstanceState.Calculated") } diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index a6bb60f865..4be2326b0a 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -31,6 +31,15 @@ ScrollView containerId: Cura.MachineManager.activeDefinitionId exclude: ["machine_settings"] visibilityHandler: UM.SettingPreferenceVisibilityHandler { } + + filter: + { + if(ExtruderManager.activeExtruderStackId) + { + return { "settable_per_extruder": true } + } + return { } + } } delegate: Loader @@ -82,7 +91,7 @@ ScrollView id: provider containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId - key: model.key + key: model.key ? model.key : "" watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 } diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 4109fd1586..b7ff0743de 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -12,13 +12,6 @@ Rectangle { id: base; - property Action addMachineAction; - property Action configureMachinesAction; - property Action addProfileAction; - property Action updateProfileAction; - property Action resetProfileAction; - property Action manageProfilesAction; - property Action configureSettingsAction; property int currentModeIndex; color: UM.Theme.getColor("sidebar"); @@ -52,20 +45,8 @@ Rectangle width: parent.width height: totalHeightHeader - addMachineAction: base.addMachineAction; - configureMachinesAction: base.configureMachinesAction; - } - - ProfileSetup { - id: profileItem - addProfileAction: base.addProfileAction - updateProfileAction: base.updateProfileAction - resetProfileAction: base.resetProfileAction - manageProfilesAction: base.manageProfilesAction - anchors.top: header.bottom + anchors.top: parent.top anchors.topMargin: UM.Theme.getSize("default_margin").height - width: parent.width - height: totalHeightProfileSetup onShowTooltip: base.showTooltip(item, location, text) onHideTooltip: base.hideTooltip() @@ -76,7 +57,7 @@ Rectangle width: parent.width height: UM.Theme.getSize("sidebar_lining").height color: UM.Theme.getColor("sidebar_lining") - anchors.top: profileItem.bottom + anchors.top: header.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height } diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 75f5393d57..282068ee2c 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -8,54 +8,54 @@ import QtQuick.Controls.Styles 1.1 import UM 1.2 as UM import Cura 1.0 as Cura -Item +Column { id: base; - // Machine Setup - property Action addMachineAction; - property Action configureMachinesAction; - UM.I18nCatalog { id: catalog; name:"cura"} + property int totalHeightHeader: childrenRect.height property int currentExtruderIndex; - Rectangle { - id: sidebarTabRow - width: base.width - height: 0 - anchors.top: parent.top - color: UM.Theme.getColor("sidebar_header_bar") - } + spacing: UM.Theme.getSize("default_margin").height - Rectangle { + signal showTooltip(Item item, point location, string text) + signal hideTooltip() + + Row + { id: machineSelectionRow - width: base.width height: UM.Theme.getSize("sidebar_setup").height - anchors.top: sidebarTabRow.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - anchors.horizontalCenter: parent.horizontalCenter - Label{ + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + } + + Label + { id: machineSelectionLabel - //: Machine selection label - text: catalog.i18nc("@label:listbox","Printer:"); - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@label:listbox", "Printer:"); anchors.verticalCenter: parent.verticalCenter font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); + + width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width } - ToolButton { + ToolButton + { id: machineSelection text: Cura.MachineManager.activeMachineName; - width: parent.width/100*55 + height: UM.Theme.getSize("setting_control").height tooltip: Cura.MachineManager.activeMachineName; - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter style: UM.Theme.styles.sidebar_header_button + width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width + menu: Menu { id: machineSelectionMenu @@ -81,102 +81,114 @@ Item MenuSeparator { } - MenuItem { action: base.addMachineAction; } - MenuItem { action: base.configureMachinesAction; } + MenuItem { action: Cura.Actions.addMachine; } + MenuItem { action: Cura.Actions.configureMachines; } } } } - Rectangle { - id: extruderSelection - width: parent.width/100*55 + ListView + { + id: extrudersList + property var index: 0 + visible: machineExtruderCount.properties.value > 1 - height: visible ? UM.Theme.getSize("sidebar_header_mode_toggle").height : 0 - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - anchors.top: machineSelectionRow.bottom - anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 - Component{ - id: wizardDelegate - Button { - height: extruderSelection.height - anchors.left: parent.left - anchors.leftMargin: model.index * (extruderSelection.width / machineExtruderCount.properties.value) - anchors.verticalCenter: parent.verticalCenter - width: parent.width / machineExtruderCount.properties.value - text: model.name - exclusiveGroup: extruderMenuGroup; - checkable: true; - checked: base.currentExtruderIndex == index - onClicked: - { - base.currentExtruderIndex = index - ExtruderManager.setActiveExtruderIndex(index) - } + height: UM.Theme.getSize("sidebar_header_mode_toggle").height - style: ButtonStyle { - background: Rectangle { - border.width: UM.Theme.getSize("default_lining").width - border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") : - control.pressed ? UM.Theme.getColor("toggle_active_border") : - control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border") - color: control.checked ? UM.Theme.getColor("toggle_checked") : - control.pressed ? UM.Theme.getColor("toggle_active") : - control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked") - Behavior on color { ColorAnimation { duration: 50; } } - Label { - anchors.centerIn: parent - color: control.checked ? UM.Theme.getColor("toggle_checked_text") : - control.pressed ? UM.Theme.getColor("toggle_active_text") : - control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text") - font: UM.Theme.getFont("default") - text: control.text; - } - } - label: Item { } - } - } - } - ExclusiveGroup { id: extruderMenuGroup; } - ListView + boundsBehavior: Flickable.StopAtBounds + + anchors { - id: extrudersList - property var index: 0 - model: Cura.ExtrudersModel {} - delegate: wizardDelegate - anchors.top: parent.top - anchors.left: parent.left - width: parent.width + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + } + + ExclusiveGroup { id: extruderMenuGroup; } + + orientation: ListView.Horizontal + + model: Cura.ExtrudersModel { id: extrudersModel; addGlobal: true } + + delegate: Button + { + height: ListView.view.height + width: ListView.view.width / extrudersModel.rowCount() + + text: model.name + exclusiveGroup: extruderMenuGroup; + checkable: true; + checked: base.currentExtruderIndex == index + + onClicked: + { + focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values. + base.currentExtruderIndex = index; + ExtruderManager.setActiveExtruderIndex(index); + } + + style: ButtonStyle + { + background: Rectangle + { + border.width: UM.Theme.getSize("default_lining").width + border.color: control.checked ? UM.Theme.getColor("toggle_checked_border") : + control.pressed ? UM.Theme.getColor("toggle_active_border") : + control.hovered ? UM.Theme.getColor("toggle_hovered_border") : UM.Theme.getColor("toggle_unchecked_border") + color: control.checked ? UM.Theme.getColor("toggle_checked") : + control.pressed ? UM.Theme.getColor("toggle_active") : + control.hovered ? UM.Theme.getColor("toggle_hovered") : UM.Theme.getColor("toggle_unchecked") + Behavior on color { ColorAnimation { duration: 50; } } + + Label + { + anchors.centerIn: parent + color: control.checked ? UM.Theme.getColor("toggle_checked_text") : + control.pressed ? UM.Theme.getColor("toggle_active_text") : + control.hovered ? UM.Theme.getColor("toggle_hovered_text") : UM.Theme.getColor("toggle_unchecked_text") + + font: UM.Theme.getFont("default") + text: control.text; + } + } + label: Item { } + } } } - Rectangle { + Row + { id: variantRow - anchors.top: extruderSelection.visible ? extruderSelection.bottom : machineSelectionRow.bottom - anchors.topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 - width: base.width - height: visible ? UM.Theme.getSize("sidebar_setup").height : 0 + + height: UM.Theme.getSize("sidebar_setup").height visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials - Label{ + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + } + + Label + { id: variantLabel text: (Cura.MachineManager.hasVariants && Cura.MachineManager.hasMaterials) ? catalog.i18nc("@label","Nozzle & Material:"): Cura.MachineManager.hasVariants ? catalog.i18nc("@label","Nozzle:") : catalog.i18nc("@label","Material:"); - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.verticalCenter: parent.verticalCenter - width: parent.width/100*45 + width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } Rectangle { - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter - width: parent.width/100*55 + width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width height: UM.Theme.getSize("setting_control").height ToolButton { @@ -213,13 +225,6 @@ Item onTriggered: { Cura.MachineManager.setActiveVariant(model.id); - /*if (typeof(model) !== "undefined" && !model.active) { - //Selecting a variant was canceled; undo menu selection - variantSelectionInstantiator.model.setProperty(index, "active", false); - var activeMachineVariantName = UM.MachineManager.activeMachineVariant; - var activeMachineVariantIndex = variantSelectionInstantiator.model.find("name", activeMachineVariantName); - variantSelectionInstantiator.model.setProperty(activeMachineVariantIndex, "active", true); - }*/ } } onObjectAdded: variantsSelectionMenu.insertItem(index, object) @@ -276,13 +281,6 @@ Item onTriggered: { Cura.MachineManager.setActiveMaterial(model.id); - /*if (typeof(model) !== "undefined" && !model.active) { - //Selecting a material was canceled; undo menu selection - materialSelectionInstantiator.model.setProperty(index, "active", false); - var activeMaterialName = Cura.MachineManager.activeMaterialName - var activeMaterialIndex = materialSelectionInstantiator.model.find("name", activeMaterialName); - materialSelectionInstantiator.model.setProperty(activeMaterialIndex, "active", true); - }*/ } } onObjectAdded: materialSelectionMenu.insertItem(index, object) @@ -295,6 +293,147 @@ Item } } + Row + { + id: globalProfileRow + height: UM.Theme.getSize("sidebar_setup").height + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + } + + + Label + { + id: globalProfileLabel + text: catalog.i18nc("@label","Profile:"); + width: parent.width * 0.45 - UM.Theme.getSize("default_margin").width + font: UM.Theme.getFont("default"); + color: UM.Theme.getColor("text"); + } + + ToolButton + { + id: globalProfileSelection + text: Cura.MachineManager.activeQualityName + width: parent.width * 0.55 + UM.Theme.getSize("default_margin").width + height: UM.Theme.getSize("setting_control").height + tooltip: Cura.MachineManager.activeQualityName + style: UM.Theme.styles.sidebar_header_button + + menu: Menu + { + id: profileSelectionMenu + Instantiator + { + id: profileSelectionInstantiator + model: UM.InstanceContainersModel + { + filter: + { + var result = { "type": "quality" }; + if(Cura.MachineManager.filterQualityByMachine) + { + result.definition = Cura.MachineManager.activeDefinitionId; + if(Cura.MachineManager.hasMaterials) + { + result.material = Cura.MachineManager.activeMaterialId; + } + } + else + { + result.definition = "fdmprinter" + } + return result + } + } + property int separatorIndex: -1 + + Loader { + property QtObject model_data: model + property int model_index: index + sourceComponent: menuItemDelegate + } + onObjectAdded: + { + //Insert a separator between readonly and custom profiles + if(separatorIndex < 0 && index > 0) + { + if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) + { + profileSelectionMenu.insertSeparator(index); + separatorIndex = index; + } + } + //Because of the separator, custom profiles move one index lower + profileSelectionMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item); + } + onObjectRemoved: + { + //When adding a profile, the menu is rebuilt by removing all items. + //If a separator was added, we need to remove that too. + if(separatorIndex >= 0) + { + profileSelectionMenu.removeItem(profileSelectionMenu.items[separatorIndex]) + separatorIndex = -1; + } + profileSelectionMenu.removeItem(object.item); + } + } + ExclusiveGroup { id: profileSelectionMenuGroup; } + + Component + { + id: menuItemDelegate + MenuItem + { + id: item + text: model_data ? model_data.name : "" + checkable: true + checked: model_data != null ? Cura.MachineManager.activeQualityId == model_data.id : false + exclusiveGroup: profileSelectionMenuGroup; + onTriggered: Cura.MachineManager.setActiveQuality(model_data.id) + } + } + + MenuSeparator { } + MenuItem { action: Cura.Actions.addProfile } + MenuItem { action: Cura.Actions.updateProfile } + MenuItem { action: Cura.Actions.resetProfile } + MenuSeparator { } + MenuItem { action: Cura.Actions.manageProfiles } + } + + UM.SimpleButton + { + id: customisedSettings + + visible: Cura.MachineManager.hasUserSettings + height: parent.height * 0.6 + width: parent.height * 0.6 + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("default_margin").width + + color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); + iconSource: UM.Theme.getIcon("star"); + + onClicked: Cura.Actions.manageProfiles.trigger() + onEntered: + { + var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.") + base.showTooltip(globalProfileRow, Qt.point(0, globalProfileRow.height / 2), content) + } + onExited: base.hideTooltip() + } + } + } + UM.SettingPropertyProvider { id: machineExtruderCount @@ -304,4 +443,6 @@ Item watchedProperties: [ "value" ] storeIndex: 0 } + + UM.I18nCatalog { id: catalog; name:"cura" } } diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 86df9dab92..b4498c6c8b 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -5,7 +5,7 @@ definition = fdmprinter [metadata] type = quality -read_only = True +weight = -3 [values] layer_height = 0.06 diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index 6cebc46dd5..d34a7c6461 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -5,7 +5,7 @@ definition = fdmprinter [metadata] type = quality -read_only = True +weight = -1 [values] infill_sparse_density = 10 diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg index b12603f921..417c7c700f 100644 --- a/resources/quality/normal.inst.cfg +++ b/resources/quality/normal.inst.cfg @@ -5,6 +5,6 @@ definition = fdmprinter [metadata] type = quality -read_only = True +weight = -2 [values] diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg index 07d3fae601..11b926378d 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_abs_ultimaker2_extended_plus_0.25_mm weight = -2 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg index 139c8cb976..bdeeb935f4 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_abs_ultimaker2_extended_plus_0.4_mm weight = -1 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg index 8d021f4d91..d658ee5bb5 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_abs_ultimaker2_extended_plus_0.4_mm weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg index 3f89bdeee6..ff024ccc69 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_abs_ultimaker2_extended_plus_0.4_mm weight = -2 -read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg index ea67bcc0b2..c2f4daa86f 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_abs_ultimaker2_extended_plus_0.6_mm weight = -2 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg index 8857db6cc1..362e844214 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_abs_ultimaker2_extended_plus_0.8_mm weight = -2 -read_only = True [values] layer_height = 0.2 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg index d34ea88798..f4d9264d3e 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_cpe_ultimaker2_extended_plus_0.25_mm weight = -2 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg index 5f402d50aa..f514f22294 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_cpe_ultimaker2_extended_plus_0.4_mm weight = -1 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg index 2b35097f66..0c68be2f5f 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_cpe_ultimaker2_extended_plus_0.4_mm weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg index 41e9fab6d3..26ea8ce9bc 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_cpe_ultimaker2_extended_plus_0.4_mm weight = -2 -read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg index 675c949364..d6d10dbe1a 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_cpe_ultimaker2_extended_plus_0.6_mm weight = -2 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg index b631baea42..53d5e0bc8c 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_cpe_ultimaker2_extended_plus_0.8_mm weight = -2 -read_only = True [values] layer_height = 0.2 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg index 142ee42b71..5e54b3194a 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_pla_ultimaker2_extended_plus_0.25_mm weight = -2 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg index 8fd8fedf4c..893256bb33 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_pla_ultimaker2_extended_plus_0.4_mm weight = -1 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg index 3fc5cb39a0..844e2b3eac 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_pla_ultimaker2_extended_plus_0.4_mm weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg index 94816b233c..47d511446a 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus type = quality material = generic_pla_ultimaker2_extended_plus_0.4_mm weight = -2 -read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg index 2de9b6a482..a2b15b6f16 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus material = generic_pla_ultimaker2_extended_plus_0.6_mm type = quality weight = -2 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg index f3a1a14f73..08b5bec667 100644 --- a/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_extended_plus material = generic_pla_ultimaker2_extended_plus_0.8_mm type = quality weight = -2 -read_only = True [values] layer_height = 0.2 diff --git a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg index 7a1da403ff..9a44582610 100644 --- a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.25_mm weight = -2 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg index 48fa105f80..0df882e418 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.4_mm weight = -1 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg index 8024ebe8d9..a8abdb081f 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.4_mm weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg index 5205a4d057..c29b017bbe 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_pla_ultimaker2_plus_0.4_mm weight = -2 -read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg index db3e208c8d..5a0a840ae7 100644 --- a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus material = generic_pla_ultimaker2_plus_0.6_mm type = quality weight = -2 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg index 4a52e0ff2c..bd90b8c059 100644 --- a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus material = generic_pla_ultimaker2_plus_0.8_mm type = quality weight = -2 -read_only = True [values] layer_height = 0.2 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg index 0b7a371ff1..05a9bce71c 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_abs_ultimaker2_plus_0.25_mm weight = -2 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg index 71f93ffe6f..cd0a25981a 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_abs_ultimaker2_plus_0.4_mm weight = -1 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg index 3ceb8ce198..4b1ece31ef 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_abs_ultimaker2_plus_0.4_mm weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg index 762ad08eca..f1b01fd408 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_abs_ultimaker2_plus_0.4_mm weight = -2 -read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg index ea88fe3616..89e73dda38 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_abs_ultimaker2_plus_0.6_mm weight = -2 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg index d5b9557ebb..2171fd3837 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_abs_ultimaker2_plus_0.8_mm weight = -2 -read_only = True [values] layer_height = 0.2 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg index eaab2ff2b6..6a300ba27d 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_cpe_ultimaker2_plus_0.25_mm weight = -2 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg index 25e96fd948..e76c5205f5 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_cpe_ultimaker2_plus_0.4_mm weight = -1 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg index 6680d78195..60f171dc17 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_cpe_ultimaker2_plus_0.4_mm weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg index acaedff20a..04116dbe21 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_cpe_ultimaker2_plus_0.4_mm weight = -2 -read_only = True [values] layer_height = 0.1 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg index f19032a95e..35e666e6d9 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_cpe_ultimaker2_plus_0.6_mm weight = -2 -read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg index 45372fdf39..c36d1714a0 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg @@ -7,7 +7,6 @@ definition = ultimaker2_plus type = quality material = generic_cpe_ultimaker2_plus_0.8_mm weight = -2 -read_only = True [values] layer_height = 0.2