From 1af6e63b35f8483bac5674ae7315bed1dcf867e2 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 13:41:46 +0200 Subject: [PATCH 01/26] Removed unused model --- .../PerObjectSettingsModel.py | 75 ------------------- .../PerObjectSettingsTool.py | 1 - 2 files changed, 76 deletions(-) delete mode 100644 plugins/PerObjectSettingsTool/PerObjectSettingsModel.py diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsModel.py b/plugins/PerObjectSettingsTool/PerObjectSettingsModel.py deleted file mode 100644 index 74a1fbed9a..0000000000 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsModel.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2015 Ultimaker B.V. -# Uranium is released under the terms of the AGPLv3 or higher. - -from PyQt5.QtCore import Qt, pyqtSlot, QUrl - -from UM.Application import Application -from UM.Qt.ListModel import ListModel -from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator -from UM.Scene.SceneNode import SceneNode -#from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator -#from UM.Settings.ProfileOverrideDecorator import ProfileOverrideDecorator - -from . import SettingOverrideModel - -class PerObjectSettingsModel(ListModel): - IdRole = Qt.UserRole + 1 # ID of the node - - def __init__(self, parent = None): - super().__init__(parent) - self._scene = Application.getInstance().getController().getScene() - self._root = self._scene.getRoot() - self.addRoleName(self.IdRole,"id") - - self._updateModel() - - @pyqtSlot("quint64", str) - def setObjectProfile(self, object_id, profile_name): - self.setProperty(self.find("id", object_id), "profile", profile_name) - - profile = None - '''if profile_name != "global": - profile = Application.getInstance().getMachineManager().findProfile(profile_name) - - node = self._scene.findObject(object_id) - if profile: - if not node.getDecorator(ProfileOverrideDecorator): - node.addDecorator(ProfileOverrideDecorator()) - node.callDecoration("setProfile", profile) - else: - if node.getDecorator(ProfileOverrideDecorator): - node.removeDecorator(ProfileOverrideDecorator)''' - - @pyqtSlot("quint64", str) - def addOverride(self, object_id, key): - machine = Application.getInstance().getMachineManager().getActiveMachineInstance() - if not machine: - return - - node = self._scene.findObject(object_id) - #if not node.getDecorator(SettingOverrideDecorator): - # node.addDecorator(SettingOverrideDecorator()) - - node.callDecoration("addSetting", key) - - @pyqtSlot("quint64", str) - def removerOverride(self, object_id, key): - node = self._scene.findObject(object_id) - node.callDecoration("removeSetting", key) - - #if len(node.callDecoration("getAllSettings")) == 0: - # node.removeDecorator(SettingOverrideDecorator) - - def _updateModel(self): - self.clear() - - for node in BreadthFirstIterator(self._root): - if type(node) is not SceneNode or not node.isSelectable(): - continue - - node_stack = node.callDecoration("getStack") - - if not node_stack: - self.appendItem({ - "id": id(node) - }) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index c74800e83d..f702d0b939 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -6,7 +6,6 @@ from UM.Scene.Selection import Selection from UM.Application import Application from UM.Preferences import Preferences -from . import PerObjectSettingsModel class PerObjectSettingsTool(Tool): def __init__(self): From ca218d7a1fb6e46a4092ab072062458c56e44273 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 13:52:11 +0200 Subject: [PATCH 02/26] Removed too generic exception handling CURA-1278 --- .../PerObjectSettingsTool.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index f702d0b939..a06ecd297f 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -32,18 +32,14 @@ class PerObjectSettingsTool(Tool): return selected_object_id def getContainerID(self): + + selected_object = Selection.getSelectedObject(0) + if selected_object.getParent().callDecoration("isGroup"): + selected_object = selected_object.getParent() try: - selected_object = Selection.getSelectedObject(0) - if selected_object.getParent().callDecoration("isGroup"): - selected_object = selected_object.getParent() - try: - return selected_object.callDecoration("getStack").getId() - except: - print(":(") - return - except: - print(":((") - return + return selected_object.callDecoration("getStack").getId() + except AttributeError: + return "" def setContainerID(self, value): pass From b9f2d498b4ddfc0d02f36b8d109180abf90a42a7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:25:38 +0200 Subject: [PATCH 03/26] Fix typo in documentation --- resources/qml/Settings/SettingView.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 9dabbaee98..6a11136966 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -48,7 +48,7 @@ ScrollView //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, - //causing nasty issues when selecting differnt options. So disable asynchronous loading of enum type completely. + //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" active: model.type != undefined From 1f9805a73c0b7cdfba3b57405062703e0e6b9d97 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:43:02 +0200 Subject: [PATCH 04/26] Remove unused imports These are unused because the code was moved to Extruder.py Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 71b636ad6f..60d452ae73 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,12 +1,9 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -import re - from cura.Extruder import Extruder #The individual extruders managed by this manager. from UM.Application import Application #To get the global container stack to find the current machine. from UM.Logger import Logger -from UM.Settings.ContainerStack import ContainerStack #To create container stacks for each extruder. from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. From 06f7f90bb08c5a5dea6e216a670cf05d112125a9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:04:19 +0200 Subject: [PATCH 05/26] Make ExtruderManager into a singleton This way we don't need to load it in CuraApplication but we can just load it whenever it is first needed. ExtruderManager should be robust against initialising it at any point in Cura's runtime. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 2 -- cura/ExtruderManager.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 49fcbbf405..b8cef52d0c 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -327,8 +327,6 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) - self._extruder_manager = ExtruderManager.ExtruderManager() - self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self.initializeEngine() diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 60d452ae73..34dbfd7c0c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -13,6 +13,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers # and makes sure that whenever the machine is swapped, this list is kept up to # date. It also contains and updates the setting stacks for the extruders. class ExtruderManager: + ## The singleton instance of this manager. + __instance = None + ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. @@ -20,6 +23,16 @@ class ExtruderManager: Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + ## Gets an instance of this extruder manager. + # + # If an instance was already created, the old instance is returned. This + # implements the singleton pattern. + @classmethod + def getInstance(cls): + if not cls.__instance: + cls.__instance = ExtruderManager() + return cls.__instance + ## When the global container stack changes, this reconnects to the new # signal for containers changing. def _reconnectExtruderReload(self): From 8a8b0016ba314fbf7167710f24cf139beb0ce8ce Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:55:01 +0200 Subject: [PATCH 06/26] Add signal for when extruder list changes The ExtrudersModel will need to listen to this. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 34dbfd7c0c..3477a3175f 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -5,6 +5,7 @@ from cura.Extruder import Extruder #The individual extruders managed by this man from UM.Application import Application #To get the global container stack to find the current machine. from UM.Logger import Logger from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. +import UM.Signal #To notify other components of changes in the extruders. ## Class that handles the current extruder stack. @@ -16,6 +17,9 @@ class ExtruderManager: ## The singleton instance of this manager. __instance = None + ## Signal to notify other components when the list of extruders changes. + extrudersChanged = UM.Signal() + ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. @@ -49,6 +53,7 @@ class ExtruderManager: def _reloadExtruders(self): self._extruders = [] if not self._global_container_stack: #No machine has been added yet. + self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! return #Then leave them empty! #Get the extruder definitions belonging to the current machine. @@ -60,4 +65,5 @@ class ExtruderManager: Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue for extruder_definition in extruder_definitions: - self._extruders.append(Extruder(extruder_definition)) \ No newline at end of file + self._extruders.append(Extruder(extruder_definition)) + self.extrudersChanged.emit() \ No newline at end of file From 83693162369851aff7f287de64095066205edcd3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 12:56:55 +0200 Subject: [PATCH 07/26] Use modern import method This is more robust to cyclic dependencies, and also the intended way of importing these classes in Python in general. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3477a3175f..51faa0a5e2 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -2,9 +2,9 @@ # Cura is released under the terms of the AGPLv3 or higher. from cura.Extruder import Extruder #The individual extruders managed by this manager. -from UM.Application import Application #To get the global container stack to find the current machine. -from UM.Logger import Logger -from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID. +import UM.Application #To get the global container stack to find the current machine. +import UM.Logger +import UM.Settings.ContainerRegistry #Finding containers by ID. import UM.Signal #To notify other components of changes in the extruders. @@ -25,7 +25,7 @@ class ExtruderManager: self._extruders = [] #Extruders for the current machine. self._global_container_stack = None - Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. ## Gets an instance of this extruder manager. # @@ -42,7 +42,7 @@ class ExtruderManager: def _reconnectExtruderReload(self): if self._global_container_stack: self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. - self._global_container_stack = Application.getInstance().getGlobalContainerStack() + self._global_container_stack = UM.Application.getInstance().getGlobalContainerStack() self._global_container_stack.containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. ## (Re)loads all extruders of the currently active machine. @@ -60,9 +60,9 @@ class ExtruderManager: machine = self._global_container_stack.getBottom() extruder_train_ids = machine.getMetaData("machine_extruder_trains") for extruder_train_id in extruder_train_ids: - extruder_definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. + extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #Empty list or error. - Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) + UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) continue for extruder_definition in extruder_definitions: self._extruders.append(Extruder(extruder_definition)) From 8a8de959692e4ea65135166de3ad4c2bba84d585 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:11:02 +0200 Subject: [PATCH 08/26] Add iteration over extruder manager This iteration iterates over the extruders. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 51faa0a5e2..3c1e50d9bd 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -24,6 +24,7 @@ class ExtruderManager: def __init__(self): self._extruders = [] #Extruders for the current machine. self._global_container_stack = None + self._next_item = 0 #For when you use this class as iterator. UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. @@ -37,6 +38,12 @@ class ExtruderManager: cls.__instance = ExtruderManager() return cls.__instance + ## Creates an iterator over the extruders in this manager. + # + # \return An iterator over the extruders in this manager. + def __iter__(self): + return iter(self._extruders) + ## When the global container stack changes, this reconnects to the new # signal for containers changing. def _reconnectExtruderReload(self): From 25a6a992869e7f84511e838211f951e17df2ab61 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:15:33 +0200 Subject: [PATCH 09/26] Make name of extruder a property This stores the name for later use, for instance when displaying the extruder. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 5be05c713c..cff5f3e6d0 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -25,8 +25,8 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - name = self._uniqueName(self._definition.getId()) - self._container_stack = UM.Settings.ContainerStack(name) + self._name = self._uniqueName(self._definition.getId()) + self._container_stack = UM.Settings.ContainerStack(self._name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -73,15 +73,16 @@ class Extruder: self._container_stack.addContainer(self._quality) #Add an empty user profile. - self._user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") self._user_profile.addMetaDataEntry("type", "user") self._container_stack.addContainer(self._user_profile) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) - nozzle_changed = UM.Signal.Signal() - material_changed = UM.Signal.Signal() - quality_changed = UM.Signal.Signal() + material_changed = UM.Signal() + name_changed = UM.Signal() + nozzle_changed = UM.Signal() + quality_changed = UM.Signal() ## Gets the currently active material on this extruder. # @@ -104,6 +105,19 @@ class Extruder: self._material = value self.material_changed.emit() + ## Gets the name of this extruder. + # + # \return The name of this extruder. + @property + def name(self): + return self._name + + ## Changes the name of this extruder. + @name.setter + def name(self, value): + self._name = value + self.name_changed.emit() + ## Gets the currently active nozzle on this extruder. # # \return The currently active nozzle on this extruder. From df363a024a7a9e3c31ee9dfbc629da180e71b40d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:24:53 +0200 Subject: [PATCH 10/26] Expose definition container of extruders This contains important metadata which we'll need. It's also more consistent with the rest. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index cff5f3e6d0..9f2a8ab493 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -79,11 +79,33 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + definition_changed = UM.Signal() material_changed = UM.Signal() name_changed = UM.Signal() nozzle_changed = UM.Signal() quality_changed = UM.Signal() + ## Gets the definition container of this extruder. + # + # \return The definition container of this extruder. + @property + def definition(self): + return self._definition + + ## Changes the definition container of this extruder. + # + # \param value The new definition for this extruder. + @definition.setter + def definition(self, value): + try: + position = self._container_stack.index(self._definition) + except ValueError: #Definition is not in the list. Big trouble! + UM.Logger.log("e", "I've lost my old extruder definition, so I can't find where to insert the new definition.") + return + self._container_stack.replaceContainer(position, value) + self._definition = value + self.definition_changed.emit() + ## Gets the currently active material on this extruder. # # \return The currently active material on this extruder. From e16fedf2d8640146fa4059b28a1a0fea51b2e68e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:27:11 +0200 Subject: [PATCH 11/26] Changing name of extruder also changes name in container stack This name may be used to get a unique human-readable name. Just for consistency really. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index 9f2a8ab493..4bbe24183d 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -135,9 +135,12 @@ class Extruder: return self._name ## Changes the name of this extruder. + # + # \param value The new name for this extruder. @name.setter def name(self, value): self._name = value + self._container_stack.setName(value) #Also update in container stack, being defensive. self.name_changed.emit() ## Gets the currently active nozzle on this extruder. From c24f4be8ae3403223141d991d29fe4ca085c8d3f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 13:42:02 +0200 Subject: [PATCH 12/26] Add extruders model Hasn't been tested much because there is no display for this in the front-end yet. It needs a setting data type to go with in order to display it. This model is for the drop-down boxes to select an extruder to print, for instance, the support with. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 cura/ExtrudersModel.py diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py new file mode 100644 index 0000000000..08f349c1ff --- /dev/null +++ b/cura/ExtrudersModel.py @@ -0,0 +1,55 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from PyQt5.QtCore import Qt + +import cura.ExtruderManager +import UM.Qt.ListModel + +## Model that holds extruders. +# +# This model is designed for use by any list of extruders, but specifically +# intended for drop-down lists of extruders in place of settings. +class ExtrudersModel(UM.Qt.ListModel): + ## Human-readable name of the extruder. + NameRole = Qt.UserRole + 1 + + ## Colour of the material loaded in the extruder. + ColourRole = Qt.UserRole + 2 + + ## 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 + + ## Initialises the extruders model, defining the roles and listening for + # changes in the data. + # + # \param parent Parent QtObject of this list. + def __init__(self, parent = None): + super().__init__(parent) + + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.ColourRole, "colour") + self.addRoleName(self.IndexRole, "index") + + #Listen to changes. + manager = cura.ExtruderManager.ExtruderManager.getInstance() + manager.extrudersChanged.connect(self._updateExtruders()) + + ## Update the list of extruders. + # + # This should be called whenever the list of extruders changes. + def _updateExtruders(self): + self.clear() + manager = cura.ExtruderManager.ExtruderManager.getInstance() + for index, extruder in enumerate(manager): + item = { #Construct an item with only the relevant information. + "name": extruder.name, + "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), + "index": index + } + self.appendItem(item) + self.sort(lambda item: item["index"]) \ No newline at end of file From f18eeba793e148088f9d34fad2455fbb126fa374 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:02:44 +0200 Subject: [PATCH 13/26] Add extruder setting type This is a new data type. It behaves and saves just like an integer, but it's actually just an index of the extruder to use. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index b8cef52d0c..a5357b10d7 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -18,6 +18,7 @@ from UM.JobQueue import JobQueue from UM.SaveFile import SaveFile from UM.Scene.Selection import Selection from UM.Scene.GroupDecorator import GroupDecorator +import UM.Settings.Validator from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation @@ -89,6 +90,7 @@ class CuraApplication(QtApplication): # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) + SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator) super().__init__(name = "cura", version = CuraVersion) From 45d01bf37186c065f73eb16ce793cfb2c43cb619 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:03:33 +0200 Subject: [PATCH 14/26] Remove unused import This was no longer needed since ExtruderManager is now a singleton. It's no longer in CuraApplication. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a5357b10d7..3c3415aefe 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -31,7 +31,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog -from . import ExtruderManager from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation From c994cb6bef743e96edad69c9c740bf0048c163fe Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 14:19:39 +0200 Subject: [PATCH 15/26] Slicing no longer occurs when a perObject setting is in error state CURA-1288 --- plugins/CuraEngineBackend/StartSliceJob.py | 19 +++++++++++++++++-- .../PerObjectSettingsTool.py | 1 - 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index cf008e7b6f..0851261877 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -3,7 +3,6 @@ import numpy from string import Formatter -import traceback from enum import IntEnum from UM.Job import Job @@ -59,7 +58,7 @@ class StartSliceJob(Job): self.setResult(StartJobResult.Error) return - #Don't slice if there is a setting with an error value. + # Don't slice if there is a setting with an error value. for key in stack.getAllKeys(): validation_state = stack.getProperty(key, "validationState") if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): @@ -69,6 +68,22 @@ class StartSliceJob(Job): Job.yieldThread() + # Don't slice if there is a per object setting with an error value. + for node in DepthFirstIterator(self._scene.getRoot()): + if type(node) is not SceneNode or not node.isSelectable(): + continue + + node_stack = node.callDecoration("getStack") + if node_stack: + for key in node_stack.getAllKeys(): + validation_state = node_stack.getProperty(key, "validationState") + if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): + Logger.log("w", "Per object setting %s is not valid, but %s. Aborting slicing.", key, validation_state) + self.setResult(StartJobResult.SettingError) + return + + Job.yieldThread() + with self._scene.getSceneLock(): # Remove old layer data. for node in DepthFirstIterator(self._scene.getRoot()): diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index a06ecd297f..ee653ae339 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -32,7 +32,6 @@ class PerObjectSettingsTool(Tool): return selected_object_id def getContainerID(self): - selected_object = Selection.getSelectedObject(0) if selected_object.getParent().callDecoration("isGroup"): selected_object = selected_object.getParent() From 388a345140ace9f11af6b22451acfb3377a52f98 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 14:42:48 +0200 Subject: [PATCH 16/26] Changing a per-object setting now forces a re-slice CURA-1278 --- cura/SettingOverrideDecorator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 3e8815ec67..e212d93dac 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -18,11 +18,17 @@ class SettingOverrideDecorator(SceneNodeDecorator): self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) + self._stack.propertyChanged.connect(self._onSettingChanged) + ContainerRegistry.getInstance().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() + 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()) From 64e4cd0041127f1c31eb28d356dd98f8a348264d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 15:52:25 +0200 Subject: [PATCH 17/26] Added properties to make setting items more customisable CURA-1278 --- resources/qml/Settings/SettingItem.qml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index aa4ef5be85..f476349c42 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -18,6 +18,10 @@ Item { property alias contents: controlContainer.children; property alias hovered: mouse.containsMouse + property var showRevertButton: true + property var showInheritButton: true + property var doDepthIdentation: true + signal contextMenuRequested() signal showTooltip(string text); signal hideTooltip(); @@ -93,7 +97,7 @@ Item { id: label; anchors.left: parent.left; - anchors.leftMargin: (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) + anchors.leftMargin: doDepthIdentation ? (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) : 0 anchors.right: settingControls.left; anchors.verticalCenter: parent.verticalCenter @@ -124,7 +128,7 @@ Item { { id: revertButton; - visible: propertyProvider.stackLevel == 0 + visible: propertyProvider.stackLevel == 0 && base.showRevertButton height: parent.height; width: height; @@ -151,7 +155,7 @@ Item { id: inheritButton; //visible: has_profile_value && base.has_inherit_function && base.is_enabled - visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0 + visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0 && base.showInheritButton height: parent.height; width: height; From edd5eecc3dacf626ff5aadb0c343ced12e7e7a72 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 15:53:00 +0200 Subject: [PATCH 18/26] Per object settings no longer show depth identation, revert/inherit buttons CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index f873ec9a79..d707fe9810 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -45,6 +45,7 @@ Item { { Loader { + id: settingLoader width: UM.Theme.getSize("setting").width; height: UM.Theme.getSize("section").height; @@ -57,6 +58,12 @@ Item { //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" + onLoaded: { + settingLoader.item.showRevertButton = false + settingLoader.item.showInheritButton = false + settingLoader.item.doDepthIdentation = false + } + source: { switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job! From 2ed518c47edfb8853abf998876dfa6db5f08f39a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 16:02:47 +0200 Subject: [PATCH 19/26] Removed no longer used code CURA-1278 --- .../SettingOverrideModel.py | 138 ------------------ 1 file changed, 138 deletions(-) delete mode 100644 plugins/PerObjectSettingsTool/SettingOverrideModel.py diff --git a/plugins/PerObjectSettingsTool/SettingOverrideModel.py b/plugins/PerObjectSettingsTool/SettingOverrideModel.py deleted file mode 100644 index d4bebfdfee..0000000000 --- a/plugins/PerObjectSettingsTool/SettingOverrideModel.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) 2015 Ultimaker B.V. -# Uranium is released under the terms of the AGPLv3 or higher. - -from PyQt5.QtCore import Qt, pyqtSlot, QUrl - -from UM.Application import Application -from UM.Qt.ListModel import ListModel -#from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator - -class SettingOverrideModel(ListModel): - KeyRole = Qt.UserRole + 1 - LabelRole = Qt.UserRole + 2 - DescriptionRole = Qt.UserRole + 3 - ValueRole = Qt.UserRole + 4 - TypeRole = Qt.UserRole + 5 - UnitRole = Qt.UserRole + 6 - ValidRole = Qt.UserRole + 7 - OptionsRole = Qt.UserRole + 8 - WarningDescriptionRole = Qt.UserRole + 9 - ErrorDescriptionRole = Qt.UserRole + 10 - GlobalOnlyRole = Qt.UserRole + 11 - - def __init__(self, node, parent = None): - super().__init__(parent) - - self._ignore_setting_change = None - - self._node = node - self._node.decoratorsChanged.connect(self._onDecoratorsChanged) - self._onDecoratorsChanged(None) - - #self._activeProfile = Application.getInstance().getMachineManager().getWorkingProfile() #To be able to get notified when a setting changes. - #self._activeProfile.settingValueChanged.connect(self._onProfileSettingValueChanged) - #Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onProfileChanged) - - self.addRoleName(self.KeyRole, "key") - self.addRoleName(self.LabelRole, "label") - self.addRoleName(self.DescriptionRole, "description") - self.addRoleName(self.ValueRole,"value") - self.addRoleName(self.TypeRole, "type") - self.addRoleName(self.UnitRole, "unit") - self.addRoleName(self.ValidRole, "valid") - self.addRoleName(self.OptionsRole, "options") - self.addRoleName(self.WarningDescriptionRole, "warning_description") - self.addRoleName(self.ErrorDescriptionRole, "error_description") - self.addRoleName(self.GlobalOnlyRole, "global_only") - - @pyqtSlot(str, "QVariant") - def setSettingValue(self, key, value): - if not self._decorator: - return - - self._decorator.setSettingValue(key, value) - - def _onDecoratorsChanged(self, node): - return - '''if not self._node.getDecorator(SettingOverrideDecorator): - self.clear() - return - - self._decorator = self._node.getDecorator(SettingOverrideDecorator) - self._decorator.settingAdded.connect(self._onSettingsChanged) - self._decorator.settingRemoved.connect(self._onSettingsChanged) - self._decorator.settingValueChanged.connect(self._onSettingValueChanged) - self._onSettingsChanged()''' - - def _createOptionsModel(self, options): - if not options: - return None - - model = ListModel() - model.addRoleName(Qt.UserRole + 1, "value") - model.addRoleName(Qt.UserRole + 2, "name") - for value, name in options.items(): - model.appendItem({"value": str(value), "name": str(name)}) - return model - - ## Updates the active profile in this model if the active profile is - # changed. - # - # This links the settingValueChanged of the new profile to this model's - # _onSettingValueChanged function, so that it properly listens to those - # events again. - def _onProfileChanged(self): - if self._activeProfile: #Unlink from the old profile. - self._activeProfile.settingValueChanged.disconnect(self._onProfileSettingValueChanged) - old_profile = self._activeProfile - self._activeProfile = Application.getInstance().getMachineManager().getWorkingProfile() - self._activeProfile.settingValueChanged.connect(self._onProfileSettingValueChanged) #Re-link to the new profile. - for setting_name in old_profile.getChangedSettings().keys(): #Update all changed settings in the old and new profiles. - self._onProfileSettingValueChanged(setting_name) - for setting_name in self._activeProfile.getChangedSettings().keys(): - self._onProfileSettingValueChanged(setting_name) - - ## Updates the global_only property of a setting once a setting value - # changes. - # - # This method should only get called on settings that are dependent on the - # changed setting. - # - # \param setting_name The setting that needs to be updated. - def _onProfileSettingValueChanged(self, setting_name): - index = self.find("key", setting_name) - if index != -1: - self.setProperty(index, "global_only", Application.getInstance().getMachineManager().getActiveMachineInstance().getMachineDefinition().getSetting(setting_name).getGlobalOnly()) - - def _onSettingsChanged(self): - self.clear() - - items = [] - for key, setting in self._decorator.getAllSettings().items(): - value = self._decorator.getSettingValue(key) - items.append({ - "key": key, - "label": setting.getLabel(), - "description": setting.getDescription(), - "value": str(value), - "type": setting.getType(), - "unit": setting.getUnit(), - "valid": setting.validate(value), - "options": self._createOptionsModel(setting.getOptions()), - "warning_description": setting.getWarningDescription(), - "error_description": setting.getErrorDescription(), - "global_only": setting.getGlobalOnly() - }) - - items.sort(key = lambda i: i["key"]) - - for item in items: - self.appendItem(item) - - def _onSettingValueChanged(self, setting): - index = self.find("key", setting.getKey()) - value = self._decorator.getSettingValue(setting.getKey()) - if index != -1: - self.setProperty(index, "value", str(value)) - self.setProperty(index, "valid", setting.validate(value)) - self.setProperty(index, "global_only", setting.getGlobalOnly()) \ No newline at end of file From 1ae69b25fad24303e132830c8c576c77081d11d6 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 16:07:09 +0200 Subject: [PATCH 20/26] Added documentation --- .../PerObjectSettingVisibilityHandler.py | 3 ++- plugins/PerObjectSettingsTool/PerObjectSettingsTool.py | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py b/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py index 9ef2515bed..381d45b1c2 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingVisibilityHandler.py @@ -5,7 +5,8 @@ from UM.Logger import Logger from cura.SettingOverrideDecorator import SettingOverrideDecorator - +## The per object setting visibility handler ensures that only setting defintions that have a matching instance Container +# are returned as visible. class PerObjectSettingVisibilityHandler(QObject): def __init__(self, parent = None, *args, **kwargs): super().__init__(parent = parent, *args, **kwargs) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index ee653ae339..6ae44c2671 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -7,12 +7,14 @@ from UM.Application import Application from UM.Preferences import Preferences +## 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. class PerObjectSettingsTool(Tool): def __init__(self): super().__init__() self._model = None - self.setExposedProperties("SelectedObjectId","ContainerID") + self.setExposedProperties("SelectedObjectId", "ContainerID") Preferences.getInstance().preferenceChanged.connect(self._onPreferenceChanged) Selection.selectionChanged.connect(self.propertyChanged) @@ -40,9 +42,6 @@ class PerObjectSettingsTool(Tool): except AttributeError: return "" - def setContainerID(self, value): - pass - def _onPreferenceChanged(self, preference): if preference == "cura/active_mode": enabled = Preferences.getInstance().getValue(preference)==1 From 64ef5ab3a404aca828c9ecffb2ea9ab5707c994f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:58:11 +0200 Subject: [PATCH 21/26] Inherit from class, not module This is an import fail on my part, sorry. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 08f349c1ff..3eac9ce17b 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -10,7 +10,7 @@ import UM.Qt.ListModel # # This model is designed for use by any list of extruders, but specifically # intended for drop-down lists of extruders in place of settings. -class ExtrudersModel(UM.Qt.ListModel): +class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 1 From 05243a4fcab2ae763bcc4dc448beb7993166bd5b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 14:59:01 +0200 Subject: [PATCH 22/26] Connect to function, not result of function The result of the function was None, but I don't need None to be called whenever extruders changed. I need the function itself to be called. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 3eac9ce17b..eb63bc4257 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -37,7 +37,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): #Listen to changes. manager = cura.ExtruderManager.ExtruderManager.getInstance() - manager.extrudersChanged.connect(self._updateExtruders()) + manager.extrudersChanged.connect(self._updateExtruders) + self._updateExtruders() ## Update the list of extruders. # From 84fc7948ce7831dd26315dc58041b08f88a5230c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 15:00:40 +0200 Subject: [PATCH 23/26] Expose ExtrudersModel to QML It is required by the drop-down for extruder settings. Contributes to issues CURA-1278 and CURA-351. --- cura/CuraApplication.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 3c3415aefe..323d0b349a 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -31,6 +31,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog +from . import ExtrudersModel from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation @@ -367,6 +368,8 @@ class CuraApplication(QtApplication): qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") + qmlRegisterType(ExtrudersModel.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") + qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): From 7146c9ab7d537390dc5b254b396c6ba685772548 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 15:27:21 +0200 Subject: [PATCH 24/26] Make a drop-down box for selecting an extruder For use by settings such as infill_extruder_nr. Contributes to issues CURA-351 and CURA-1278. --- resources/qml/Settings/SettingExtruder.qml | 112 +++++++++++++++++++++ resources/qml/Settings/SettingView.qml | 2 + 2 files changed, 114 insertions(+) create mode 100644 resources/qml/Settings/SettingExtruder.qml diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml new file mode 100644 index 0000000000..86ab728fc1 --- /dev/null +++ b/resources/qml/Settings/SettingExtruder.qml @@ -0,0 +1,112 @@ +// Copyright (c) 2016 Ultimaker B.V. +// Uranium is released under the terms of the AGPLv3 or higher. + +import QtQuick 2.1 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +SettingItem +{ + id: base + + contents: ComboBox + { + id: control + + model: Cura.ExtrudersModel { + id: extruders_model + } + textRole: "name"; + + anchors.fill: parent + + MouseArea + { + anchors.fill: parent; + acceptedButtons: Qt.NoButton; + onWheel: wheel.accepted = true; + } + + style: ComboBoxStyle + { + background: Rectangle + { + color: + { + if (!enabled) + { + return UM.Theme.getColor("setting_control_disabled") + } + if(control.hovered || base.activeFocus) + { + return UM.Theme.getColor("setting_control_highlight") + } + else + { + return UM.Theme.getColor("setting_control") + } + } + border.width: UM.Theme.getSize("default_lining").width; + border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : control.hovered ? UM.Theme.getColor("setting_control_border_highlight") : 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: control.currentText; + font: UM.Theme.getFont("default"); + color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_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: provider.setPropertyValue("value", extruders_model.getItem(index).index) + onModelChanged: updateCurrentIndex(); + + Connections + { + target: provider + onPropertiesChanged: control.updateCurrentIndex() + } + + function updateCurrentIndex() { + for(var i = 0; i < extruders_model.rowCount(); ++i) { + if(extruders_model.getItem(i).index == provider.properties.value) { + currentIndex = i; + return; + } + } + + currentIndex = -1; + } + } +} diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 6a11136966..1555149d22 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -62,6 +62,8 @@ ScrollView return "SettingTextField.qml" case "enum": return "SettingComboBox.qml" + case "extruder": + return "SettingExtruder.qml" case "bool": return "SettingCheckBox.qml" case "str": From 1a30dd96b1acbb3f8e5af545bac49e6bd57ed837 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 15:30:39 +0200 Subject: [PATCH 25/26] Change setting type for extruder_nr settings This way it can determine the difference between an integer and an index in the extruder list. Contributes to issues CURA-1278. --- resources/definitions/fdmextruder.def.json | 2 +- resources/definitions/fdmprinter.def.json | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index f755d72c4a..69797385a1 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -22,7 +22,7 @@ { "label": "Extruder", "description": "The extruder train used for printing. This is used in multi-extrusion.", - "type": "int", + "type": "extruder", "default_value": 0, "minimum_value": "0" }, diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 48952c2c99..ec27abd9f5 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2125,7 +2125,7 @@ { "label": "Platform Adhesion Extruder", "description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.", - "type": "int", + "type": "extruder", "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", @@ -2135,7 +2135,7 @@ { "label": "Support Extruder", "description": "The extruder train to use for printing the support. This is used in multi-extrusion.", - "type": "int", + "type": "extruder", "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", @@ -2145,7 +2145,7 @@ { "label": "Support Infill Extruder", "description": "The extruder train to use for printing the infill of the support. This is used in multi-extrusion.", - "type": "int", + "type": "extruder", "default_value": 0, "value": "support_extruder_nr", "minimum_value": "0", @@ -2156,7 +2156,7 @@ { "label": "First Layer Support Extruder", "description": "The extruder train to use for printing the first layer of support infill. This is used in multi-extrusion.", - "type": "int", + "type": "extruder", "default_value": 0, "value": "support_extruder_nr", "minimum_value": "0", @@ -2167,7 +2167,7 @@ { "label": "Support Roof Extruder", "description": "The extruder train to use for printing the roof of the support. This is used in multi-extrusion.", - "type": "int", + "type": "extruder", "default_value": 0, "value": "support_extruder_nr", "minimum_value": "0", From 186eca160b507a6d417e4c9cb7759eea0a80b99f Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 12:01:19 +0200 Subject: [PATCH 26/26] Fix containersChanged signal handlers Fixes CURA-1642 --- cura/ConvexHullDecorator.py | 2 +- cura/ExtruderManager.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index 6639d12dc7..39cdc36232 100644 --- a/cura/ConvexHullDecorator.py +++ b/cura/ConvexHullDecorator.py @@ -101,7 +101,7 @@ class ConvexHullDecorator(SceneNodeDecorator): if key == "print_sequence" and property_name == "value": self._onChanged() - def _onChanged(self): + def _onChanged(self, *args): if self._convex_hull_job: self._convex_hull_job.cancel() self.setConvexHull(None) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3c1e50d9bd..bfce380a70 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -57,7 +57,7 @@ class ExtruderManager: # This looks at the global container stack to see which machine is active. # Then it loads the extruders for that machine and loads each of them in a # list of extruders. - def _reloadExtruders(self): + def _reloadExtruders(self, *args): self._extruders = [] if not self._global_container_stack: #No machine has been added yet. self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! @@ -65,7 +65,7 @@ class ExtruderManager: #Get the extruder definitions belonging to the current machine. machine = self._global_container_stack.getBottom() - extruder_train_ids = machine.getMetaData("machine_extruder_trains") + extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains") for extruder_train_id in extruder_train_ids: extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. if not extruder_definitions: #Empty list or error.