From 4de0a208d15faa6474e733878b50ed3ce8803f1a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 19 May 2016 14:48:34 +0200 Subject: [PATCH 001/304] Fix version number and remove beta tag in Changelog Fixes CURA-1575 --- plugins/ChangeLogPlugin/ChangeLog.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 8dc6a61dd8..6cf0b5a488 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,6 +1,5 @@ -[2.1.0] +[2.1.1] -*2.1 Beta release Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings. *Select Multiple Objects From f8c8de86bc47ccf69ae520a58a22e6f8aae07499 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 23 May 2016 11:35:01 +0200 Subject: [PATCH 002/304] Fix showing changelog when the first item in the changelog doesn't start with an "*" CURA-1583 --- plugins/ChangeLogPlugin/ChangeLog.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.py b/plugins/ChangeLogPlugin/ChangeLog.py index 7c8c81f2c6..d004104f91 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.py +++ b/plugins/ChangeLogPlugin/ChangeLog.py @@ -48,7 +48,8 @@ class ChangeLog(Extension, QObject,): result += "

" + str(version) + "


" result += "" for change in logs[version]: - result += "" + str(change) + "
" + if str(change) != "": + result += "" + str(change) + "
" for line in logs[version][change]: result += str(line) + "
" result += "
" @@ -60,20 +61,21 @@ class ChangeLog(Extension, QObject,): self._change_logs = collections.OrderedDict() with open(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.txt"), "r",-1, "utf-8") as f: open_version = None - open_header = None + open_header = "" # Initialise to an empty header in case there is no "*" in the first line of the changelog for line in f: line = line.replace("\n","") if "[" in line and "]" in line: line = line.replace("[","") line = line.replace("]","") open_version = Version(line) - self._change_logs[Version(line)] = collections.OrderedDict() + self._change_logs[open_version] = collections.OrderedDict() elif line.startswith("*"): open_header = line.replace("*","") self._change_logs[open_version][open_header] = [] - else: - if line != "": - self._change_logs[open_version][open_header].append(line) + elif line != "": + if open_header not in self._change_logs[open_version]: + self._change_logs[open_version][open_header] = [] + self._change_logs[open_version][open_header].append(line) def _onEngineCreated(self): if not self._version: @@ -105,4 +107,3 @@ class ChangeLog(Extension, QObject,): self._changelog_context = QQmlContext(Application.getInstance()._engine.rootContext()) self._changelog_context.setContextProperty("manager", self) self._changelog_window = component.create(self._changelog_context) - #print(self._changelog_window) From 740f3775fa5c2703a6ff43c347aee6d5e23bec6c Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 13 May 2016 13:05:58 +0200 Subject: [PATCH 003/304] Reset stored layer data as soon as a new slice operation starts This prevents layer view showing a combination of stale and fresh data Fixes CURA-1370 (and CURA-1519) --- plugins/CuraEngineBackend/CuraEngineBackend.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index e3f9a4542e..d3d3469fbc 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -119,6 +119,7 @@ class CuraEngineBackend(Backend): ## Perform a slice of the scene. def slice(self): + self._stored_layer_data = [] if not self._enabled: return From 19695a93b55caae708b30bd39bb15a5de899aef9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 30 May 2016 14:27:04 +0200 Subject: [PATCH 004/304] Move extruder trains to metadata Uranium doesn't know about extruder trains so it can't load that. Cura doesn't have access to anything outside of metadata or settings. So I'm putting it into metadata. Contributes to issues CURA-1278 and CURA-351. --- resources/definitions/fdmprinter.def.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index f8400d6d62..ab16f49a8d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -11,11 +11,11 @@ "file_formats": "text/x-gcode;application/x-stl-ascii;application/x-stl-binary;application/x-wavefront-obj;application/x3g", "visible": false, "preferred_material": "pla", - "preferred_quality": "normal" - }, - "machine_extruder_trains": - { - "0": "fdmextruder" + "preferred_quality": "normal", + "machine_extruder_trains": + { + "0": "fdmextruder" + } }, "settings": { From 79892daa5e493c85ae8d8da95e30bdcffbf9ce65 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Mon, 30 May 2016 15:26:21 +0200 Subject: [PATCH 005/304] Bump API version of plugins that do not need extra porting Contributes to CURA-1615 --- plugins/3MFReader/__init__.py | 2 +- plugins/ChangeLogPlugin/__init__.py | 4 ++-- plugins/ImageReader/__init__.py | 2 +- plugins/RemovableDriveOutputDevice/__init__.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/3MFReader/__init__.py b/plugins/3MFReader/__init__.py index 610165f7a0..42b1794160 100644 --- a/plugins/3MFReader/__init__.py +++ b/plugins/3MFReader/__init__.py @@ -13,7 +13,7 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."), - "api": 2 + "api": 3 }, "mesh_reader": [ { diff --git a/plugins/ChangeLogPlugin/__init__.py b/plugins/ChangeLogPlugin/__init__.py index 88ac4e08a6..8466bfaa1b 100644 --- a/plugins/ChangeLogPlugin/__init__.py +++ b/plugins/ChangeLogPlugin/__init__.py @@ -13,9 +13,9 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Shows changes since latest checked version."), - "api": 2 + "api": 3 } } def register(app): - return {"extension": ChangeLog.ChangeLog()} \ No newline at end of file + return {"extension": ChangeLog.ChangeLog()} diff --git a/plugins/ImageReader/__init__.py b/plugins/ImageReader/__init__.py index 69fc1ddcc3..7ebdc31e57 100644 --- a/plugins/ImageReader/__init__.py +++ b/plugins/ImageReader/__init__.py @@ -13,7 +13,7 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": i18n_catalog.i18nc("@info:whatsthis", "Enables ability to generate printable geometry from 2D image files."), - "api": 2 + "api": 3 }, "mesh_reader": [ { diff --git a/plugins/RemovableDriveOutputDevice/__init__.py b/plugins/RemovableDriveOutputDevice/__init__.py index 635bdde008..16adcbfd7c 100644 --- a/plugins/RemovableDriveOutputDevice/__init__.py +++ b/plugins/RemovableDriveOutputDevice/__init__.py @@ -13,7 +13,7 @@ def getMetaData(): "author": "Ultimaker B.V.", "description": catalog.i18nc("@info:whatsthis", "Provides removable drive hotplugging and writing support."), "version": "1.0", - "api": 2 + "api": 3 } } From bdc8fdf508fdcbe13836de26d350f5f5cba0d909 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Mon, 30 May 2016 15:27:13 +0200 Subject: [PATCH 006/304] Turn CuraApplication::_onExit into public api as saveSettings Since we need it for the autosave plugin Contributes to CURA-1615 --- cura/CuraApplication.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index f0610a3538..eccb3e4525 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -116,6 +116,7 @@ class CuraApplication(QtApplication): self._center_after_select = False self._camera_animation = None self._cura_actions = None + self._started = False self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity) self.getController().toolOperationStopped.connect(self._onToolOperationStopped) @@ -189,7 +190,7 @@ class CuraApplication(QtApplication): JobQueue.getInstance().jobFinished.connect(self._onJobFinished) - self.applicationShuttingDown.connect(self._onExit) + self.applicationShuttingDown.connect(self.saveSettings) self._recent_files = [] files = Preferences.getInstance().getValue("cura/recent_files").split(";") @@ -199,8 +200,13 @@ class CuraApplication(QtApplication): self._recent_files.append(QUrl.fromLocalFile(f)) - ## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently. - def _onExit(self): + ## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently. + # + # Note that the AutoSave plugin also calls this method. + def saveSettings(self): + if not self._started: # Do not do saving during application start + return + for instance in ContainerRegistry.getInstance().findInstanceContainers(): if not instance.isDirty(): continue @@ -332,6 +338,8 @@ class CuraApplication(QtApplication): for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading. self._openFile(file_name) + self._started = True + self.exec_() ## Handle Qt events From 581b9ce11ff25d787c5dd0babd3b05cca1bde318 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Mon, 30 May 2016 15:28:14 +0200 Subject: [PATCH 007/304] Update AutoSave plugin to work with the new settings API Contributes to CURA-1615 --- plugins/AutoSave/AutoSave.py | 31 ++++++++++++------------------- plugins/AutoSave/__init__.py | 2 +- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/plugins/AutoSave/AutoSave.py b/plugins/AutoSave/AutoSave.py index e621ccdc4b..2aa49e3da1 100644 --- a/plugins/AutoSave/AutoSave.py +++ b/plugins/AutoSave/AutoSave.py @@ -15,15 +15,9 @@ class AutoSave(Extension): Preferences.getInstance().preferenceChanged.connect(self._triggerTimer) - machine_manager = Application.getInstance().getMachineManager() - - self._profile = None - machine_manager.activeProfileChanged.connect(self._onActiveProfileChanged) - machine_manager.profileNameChanged.connect(self._triggerTimer) - machine_manager.profilesChanged.connect(self._triggerTimer) - machine_manager.machineInstanceNameChanged.connect(self._triggerTimer) - machine_manager.machineInstancesChanged.connect(self._triggerTimer) - self._onActiveProfileChanged() + self._global_stack = None + Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + self._onGlobalStackChanged() Preferences.getInstance().addPreference("cura/autosave_delay", 1000 * 10) @@ -38,24 +32,23 @@ class AutoSave(Extension): if not self._saving: self._change_timer.start() - def _onActiveProfileChanged(self): - if self._profile: - self._profile.settingValueChanged.disconnect(self._triggerTimer) + def _onGlobalStackChanged(self): + if self._global_stack: + self._global_stack.propertyChanged.disconnect(self._triggerTimer) + self._global_stack.containersChanged.disconnect(self._triggerTimer) - self._profile = Application.getInstance().getMachineManager().getWorkingProfile() + self._global_stack = Application.getInstance().getGlobalContainerStack() - if self._profile: - self._profile.settingValueChanged.connect(self._triggerTimer) + if self._global_stack: + self._global_stack.propertyChanged.connect(self._triggerTimer) + self._global_stack.containersChanged.connect(self._triggerTimer) def _onTimeout(self): self._saving = True # To prevent the save process from triggering another autosave. Logger.log("d", "Autosaving preferences, instances and profiles") - machine_manager = Application.getInstance().getMachineManager() + Application.getInstance().saveSettings() - machine_manager.saveVisibility() - machine_manager.saveMachineInstances() - machine_manager.saveProfiles() Preferences.getInstance().writeToFile(Resources.getStoragePath(Resources.Preferences, Application.getInstance().getApplicationName() + ".cfg")) self._saving = False diff --git a/plugins/AutoSave/__init__.py b/plugins/AutoSave/__init__.py index 0caa02a748..7e70ebe0a2 100644 --- a/plugins/AutoSave/__init__.py +++ b/plugins/AutoSave/__init__.py @@ -13,7 +13,7 @@ def getMetaData(): "author": "Ultimaker", "version": "1.0", "description": catalog.i18nc("@info:whatsthis", "Automatically saves Preferences, Machines and Profiles after changes."), - "api": 2 + "api": 3 }, } From 7e33b76fe2b744db682b5a0bf4277906178647fb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 30 May 2016 16:18:54 +0200 Subject: [PATCH 008/304] Increment version number Contributes to issue CURA-1583. --- plugins/ChangeLogPlugin/ChangeLog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 6cf0b5a488..48e96ce4b6 100644 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -1,4 +1,4 @@ -[2.1.1] +[2.1.2] Cura has been completely reengineered from the ground up for an even more seamless integration between hardware, software and materials. Together with its intuitive new user interface, it’s now also ready for any future developments. For the beginner Cura makes 3D printing incredibly easy, and for more advanced users, there are over 140 new customisable settings. From d616a72bb12897807176a67e35c2642adb2df8cc Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Mon, 30 May 2016 16:25:20 +0200 Subject: [PATCH 009/304] Display affects/affected by in the tooltip again Contributes to CURA-1278 --- resources/qml/Settings/SettingItem.qml | 32 +++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 013dcd1680..c1666a8157 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -50,7 +50,37 @@ Item { interval: 500; repeat: false; - onTriggered: base.showTooltip(definition.description); + onTriggered: + { + var affects = settingDefinitionsModel.getRequiredBy(definition.key, "value") + var affected_by = settingDefinitionsModel.getRequires(definition.key, "value") + + var affected_by_list = "" + for(var i in affected_by) + { + affected_by_list += "
  • %1
  • \n".arg(affected_by[i].label) + } + + var affects_list = "" + for(var i in affects) + { + affects_list += "
  • %1
  • \n".arg(affects[i].label) + } + + var tooltip = "%1
    \n

    %2

    ".arg(definition.label).arg(definition.description) + + if(affects_list != "") + { + tooltip += "
    %1
    \n
      \n%2
    ".arg(catalog.i18nc("@label", "Affects")).arg(affects_list) + } + + if(affected_by_list != "") + { + tooltip += "
    %1
    \n
      \n%2
    ".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list) + } + + base.showTooltip(tooltip); + } } Label From b1419d802861952f8f1d2dab8cb9df751f15d5d4 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 30 May 2016 16:45:36 +0200 Subject: [PATCH 010/304] Fix activating (quality)profiles on the profiles page CURA-1278 --- resources/qml/Preferences/ProfilesPage.qml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 6e5d39cb49..10acc8beef 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -6,6 +6,7 @@ import QtQuick.Controls 1.1 import QtQuick.Dialogs 1.2 import UM 1.2 as UM +import Cura 1.0 as Cura UM.ManagementPage { @@ -16,6 +17,7 @@ UM.ManagementPage model: UM.InstanceContainersModel { filter: { "type": "quality" } } + onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) onAddObject: { var selectedProfile; if (objectList.currentIndex == 0) { @@ -33,6 +35,7 @@ UM.ManagementPage onRemoveObject: confirmDialog.open(); onRenameObject: { renameDialog.removeWhenRejected = false; renameDialog.open(); renameDialog.selectText(); } + activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false; addEnabled: currentItem != null; removeEnabled: currentItem != null ? !currentItem.readOnly : false; renameEnabled: currentItem != null ? !currentItem.readOnly : false; @@ -69,7 +72,7 @@ UM.ManagementPage Row { - visible: base.currentItem.id == -1 || base.currentItem.active + visible: base.currentItem.id == -1 || currentItem.id == Cura.MachineManager.activeQualityId Button { text: { From 932eefeb0e60cb0486f4927e7923b3e126d77a0e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 30 May 2016 16:31:00 +0200 Subject: [PATCH 011/304] Correct data type for extruder number setting This caused a crash. Stupid mistake. --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ab16f49a8d..6dca68a6c9 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -110,7 +110,7 @@ "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": "bool", + "type": "int", "label": "Number extruders" }, "machine_nozzle_tip_outer_diameter": From d7eda39cb0e23351033e284656332bdd91afd563 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 30 May 2016 17:05:06 +0200 Subject: [PATCH 012/304] Basic extruder manager model implementation This implementation is currently not used, and also still leaves its container stacks empty. But still... Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManagerModel.py | 102 +++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 cura/ExtruderManagerModel.py diff --git a/cura/ExtruderManagerModel.py b/cura/ExtruderManagerModel.py new file mode 100644 index 0000000000..7f0baa7aa8 --- /dev/null +++ b/cura/ExtruderManagerModel.py @@ -0,0 +1,102 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal +import re + +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. + + +## Class that handles the current extruder stack. +# +# This finds the extruders that are available for the currently active machine +# 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 ExtruderManagerModel(QObject): + ## Registers listeners and such to listen to changes to the extruders. + # + # \param parent Parent QObject of this model. + def __init__(self, parent = None): + super().__init__(parent) + + self._extruderDefinitions = [] #Extruder definitions for the current machine. + self._nozzles = {} #Nozzle instances for each extruder. + self._extruderTrains = [] #Container stacks for each of the extruder trains. + + Application.getInstance().getGlobalContainerStack().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. + # + # This looks at the global container stack to see which machine is active. + # Then it loads the extruder definitions for that machine and the variants + # of those definitions. Then it puts the new extruder definitions in the + # appropriate place in the container stacks. + def _reloadExtruders(self): + self._extruderDefinitions = [] + self._nozzles = {} + self._extruderTrains = [] + global_container_stack = Application.getInstance().getGlobalContainerStack() + if not global_container_stack: #No machine has been added yet. + return #Then leave them empty! + + #Fill the list of extruder trains. + machine = global_container_stack.getBottom() + extruder_train_ids = machine.getMetaData("machine_extruder_trains") + for extruder_train_id in extruder_train_ids: + extruders = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. + if not extruders: #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) + continue + self._extruderDefinitions += extruders + + #Fill the nozzles for each of the extruder trains. + for extruder in self._extruderDefinitions: + self._nozzles[extruder.id] = [] + all_nozzles = ContainerRegistry.getInstance().findInstanceContainers(type="nozzle") + for nozzle in all_nozzles: + extruders = nozzle.getMetaDataEntry("definitions").split(",").strip() + for extruder_id in extruders: + self._nozzles[extruder_id] = nozzle + + #Create the extruder train container stacks. + for extruder in self._extruderDefinitions: + self._extruderTrains.append(self._createContainerStack(extruder)) + + ## Creates a container stack for the specified extruder. + # + # This fills in the specified extruder as base definition, then a nozzle + # that fits in that extruder train, then a material that fits through that + # nozzle, then a quality profile that can be used with that material, and + # finally an empty user profile. + # + # \param extruder The extruder to create the container stack for. + # \return A container stack with the specified extruder as base. + def _createContainerStack(self, extruder): + container_stack = ContainerStack(self._uniqueName(extruder)) + #TODO: Fill the container stack. + return container_stack + + ## Finds a unique name for an extruder stack. + # + # \param extruder Extruder to design a name for. + # \return A name for an extruder stack that is unique and reasonably + # human-readable. + def _uniqueName(self, extruder): + container_registry = ContainerRegistry.getInstance() + + name = extruder.getName().strip() + num_check = re.compile("(.*?)\s*#\d$").match(name) + if(num_check): #There is a number in the name. + name = num_check.group(1) #Filter out the number. + if name == "": #Wait, that deleted everything! + name = "Extruder" + unique_name = name + + i = 1 + while(container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name)): #A container already has this name. + i += 1 #Try next numbering. + unique_name = "%s #%d" % (name, i) #Fill name like this: "Extruder #2". + return unique_name \ No newline at end of file From 5289d5b4ac29e66e759edb6478b7b731456b2b3e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 31 May 2016 11:02:22 +0200 Subject: [PATCH 013/304] Codestyle CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 8c9b63ac1b..8c39919b13 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -18,12 +18,6 @@ Item { width: childrenRect.width; height: childrenRect.height; - - function updateContainerID() - { - console.log("containerid",UM.ActiveTool.properties.getValue("ContainerID")) - } - Column { id: items @@ -58,7 +52,7 @@ Item { //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, - //causing nasty issues when selecting 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" source: From 72d7bd57697696540a88287c98c529cec3c6488d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 31 May 2016 11:06:26 +0200 Subject: [PATCH 014/304] Added hide button to per object settings CURA-1278 --- .../PerObjectSettingsPanel.qml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 8c39919b13..c68cd88dea 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -75,7 +75,32 @@ Item { return "../../resources/qml/Settings/SettingUnknown.qml" } } + Button + { + width: UM.Theme.getSize("setting").height; + height: UM.Theme.getSize("setting").height; + onClicked: addedSettingsModel.setVisible(model.key, false); + + style: ButtonStyle + { + background: Rectangle + { + color: control.hovered ? control.parent.style.controlHighlightColor : control.parent.style.controlColor; + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width/2 + height: parent.height/2 + sourceSize.width: width + sourceSize.height: width + color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button") + source: UM.Theme.getIcon("cross1") + } + } + } + } UM.SettingPropertyProvider { id: provider From 152f36256284bcb1e22e8b83024f681e85a43767 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 31 May 2016 11:12:22 +0200 Subject: [PATCH 015/304] Hide button is now in correct location CURA-1278 --- .../PerObjectSettingsPanel.qml | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index c68cd88dea..e5149ccb79 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -41,40 +41,44 @@ Item { } } - delegate: Loader + delegate: Row { - width: UM.Theme.getSize("setting").width; - height: UM.Theme.getSize("setting").height; - - property var definition: model - property var settingDefinitionsModel: addedSettingsModel - property var propertyProvider: provider - - //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 - //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, - //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. - asynchronous: model.type != "enum" - - source: + Loader { - switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job! + width: UM.Theme.getSize("setting").width; + height: UM.Theme.getSize("setting").height; + + property var definition: model + property var settingDefinitionsModel: addedSettingsModel + property var propertyProvider: provider + + //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 + //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, + //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. + asynchronous: model.type != "enum" + + source: { - case "int": - return "../../resources/qml/Settings/SettingTextField.qml" - case "float": - return "../../resources/qml/Settings/SettingTextField.qml" - case "enum": - return "../../resources/qml/Settings/SettingComboBox.qml" - case "bool": - return "../../resources/qml/Settings/SettingCheckBox.qml" - case "str": - return "../../resources/qml/Settings/SettingTextField.qml" - case "category": - return "../../resources/qml/Settings/SettingCategory.qml" - default: - return "../../resources/qml/Settings/SettingUnknown.qml" + switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job! + { + case "int": + return "../../resources/qml/Settings/SettingTextField.qml" + case "float": + return "../../resources/qml/Settings/SettingTextField.qml" + case "enum": + return "../../resources/qml/Settings/SettingComboBox.qml" + case "bool": + return "../../resources/qml/Settings/SettingCheckBox.qml" + case "str": + return "../../resources/qml/Settings/SettingTextField.qml" + case "category": + return "../../resources/qml/Settings/SettingCategory.qml" + default: + return "../../resources/qml/Settings/SettingUnknown.qml" + } } } + Button { width: UM.Theme.getSize("setting").height; @@ -111,8 +115,8 @@ Item { storeIndex: 0 } } - } + Button { id: customise_settings_button; From 29ed8c2f5be2f87c7b44cf441f14f1baa190f396 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 31 May 2016 11:33:02 +0200 Subject: [PATCH 016/304] Increased width of per-object settings panel CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- resources/themes/cura/theme.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index e5149ccb79..f873ec9a79 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -46,7 +46,7 @@ Item { Loader { width: UM.Theme.getSize("setting").width; - height: UM.Theme.getSize("setting").height; + height: UM.Theme.getSize("section").height; property var definition: model property var settingDefinitionsModel: addedSettingsModel diff --git a/resources/themes/cura/theme.json b/resources/themes/cura/theme.json index 67df41ef7c..acd60e2646 100644 --- a/resources/themes/cura/theme.json +++ b/resources/themes/cura/theme.json @@ -176,7 +176,7 @@ "section_icon": [1.6, 1.6], "section_icon_column": [2.8, 0.0], - "setting": [19.0, 1.8], + "setting": [25.0, 1.8], "setting_control": [10.0, 2.0], "setting_control_depth_margin": [1.4, 0.0], "setting_preferences_button_margin": [3.3, 0.0], From 3638890138d1fed247bfd01bb5abbb55fa650003 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 31 May 2016 15:26:38 +0200 Subject: [PATCH 017/304] Renaming a printer in the Manage Printers dialog is now reflected in the sidebar again Contributes to CURA-1632 --- cura/MachineManagerModel.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 7b42483fca..deef72529b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -263,6 +263,7 @@ class MachineManagerModel(QObject): if containers: new_name = self._uniqueMachineName(new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) + self.globalContainerChanged.emit() @pyqtSlot(str) def removeMachine(self, machine_id): From 21e8dd151ef26801ce006f326ff664eb1cb2a616 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 31 May 2016 15:48:08 +0200 Subject: [PATCH 018/304] Prevent removing the last printer, disable Activate button for current active printer Fixes CURA-1631 --- resources/qml/MachinesPage.qml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/resources/qml/MachinesPage.qml b/resources/qml/MachinesPage.qml index 8c7a2c521d..00ebcfc0af 100644 --- a/resources/qml/MachinesPage.qml +++ b/resources/qml/MachinesPage.qml @@ -12,11 +12,9 @@ UM.ManagementPage id: base; title: catalog.i18nc("@title:tab", "Printers"); - property int numInstances: model.rowCount(); model: UM.ContainerStacksModel { filter: {"type": "machine"} - onDataChanged: numInstances = model.rowCount() } onAddObject: Printer.requestAddPrinter() @@ -24,9 +22,9 @@ UM.ManagementPage onRenameObject: renameDialog.open(); onActivateObject: Cura.MachineManager.setActiveMachine(base.currentItem.id) - removeEnabled: base.currentItem != null && numInstances > 1 - renameEnabled: base.currentItem != null && numInstances > 0 - activateEnabled: base.currentItem != null + removeEnabled: base.currentItem != null && model.rowCount() > 1 + renameEnabled: base.currentItem != null + activateEnabled: base.currentItem != null && base.currentItem.id != Cura.MachineManager.activeMachineId Flow { From 23cb386b7c99f4070900a32ebfe0c9406f57e950 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Tue, 31 May 2016 17:41:36 +0200 Subject: [PATCH 019/304] Set default version to 2.1.2 While discussing on #718 I noticed that the splash screen still shows "master" when built from [2.1]. This sets the version to 2.1.2. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc9f37c76e..6a23ffe94f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ include(GNUInstallDirs) set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository") -set(CURA_VERSION "master" CACHE STRING "Version name of Cura") +set(CURA_VERSION "2.1.2" CACHE STRING "Version name of Cura") configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY) # Macro needed to list all sub-directory of a directory. From 4dffc414fb0ee775ef6d5fc21e2a8cc85ee98858 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 17:59:03 +0200 Subject: [PATCH 020/304] Make convex hull decorator respond properly to property change events Fixes CURA-1460 --- cura/ConvexHullDecorator.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index 8fb26858a5..6639d12dc7 100644 --- a/cura/ConvexHullDecorator.py +++ b/cura/ConvexHullDecorator.py @@ -27,7 +27,9 @@ class ConvexHullDecorator(SceneNodeDecorator): # Keep track of the previous parent so we can clear its convex hull when the object is reparented self._parent_node = None - self._profile = None + self._global_stack = None + Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + self._onGlobalStackChanged() #Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged) #Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveMachineInstanceChanged) #self._onActiveProfileChanged() @@ -95,28 +97,30 @@ class ConvexHullDecorator(SceneNodeDecorator): def setConvexHullNode(self, node): self._convex_hull_node = node - def _onActiveProfileChanged(self): - if self._profile: - self._profile.settingValueChanged.disconnect(self._onSettingValueChanged) + def _onSettingValueChanged(self, key, property_name): + if key == "print_sequence" and property_name == "value": + self._onChanged() - self._profile = Application.getInstance().getMachineManager().getWorkingProfile() - - if self._profile: - self._profile.settingValueChanged.connect(self._onSettingValueChanged) - - def _onActiveMachineInstanceChanged(self): + def _onChanged(self): if self._convex_hull_job: self._convex_hull_job.cancel() self.setConvexHull(None) - def _onSettingValueChanged(self, setting): - if setting == "print_sequence": - if self._convex_hull_job: - self._convex_hull_job.cancel() - self.setConvexHull(None) - def _onParentChanged(self, node): # Force updating the convex hull of the parent group if the object is in a group if self._parent_node and self._parent_node.callDecoration("isGroup"): self._parent_node.callDecoration("setConvexHull", None) self._parent_node = self.getNode().getParent() + + def _onGlobalStackChanged(self): + if self._global_stack: + self._global_stack.propertyChanged.disconnect(self._onSettingValueChanged) + self._global_stack.containersChanged.disconnect(self._onChanged) + + self._global_stack = Application.getInstance().getGlobalContainerStack() + + if self._global_stack: + self._global_stack.propertyChanged.connect(self._onSettingValueChanged) + self._global_stack.containersChanged.connect(self._onChanged) + + self._onChanged() From f21e48adbbebb11630b90ac339d34f1a5e8bda9c Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 18:00:26 +0200 Subject: [PATCH 021/304] Register all QML files in Cura's QML directory as part of the Cura module Jaime asked for it. --- cura/CuraApplication.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index eccb3e4525..d7e5768116 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -42,7 +42,7 @@ from . import MachineManagerModel from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtGui import QColor, QIcon -from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType +from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType import platform import sys @@ -365,6 +365,15 @@ class CuraApplication(QtApplication): qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") + qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") + + for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): + type_name = os.path.splitext(os.path.basename(path))[0] + if type_name in ("Cura", "Actions"): + continue + + qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name) + def onSelectionChanged(self): if Selection.hasSelection(): if not self.getController().getActiveTool(): From 3b51c3d339a07effb593339b9fa7202e3f36c358 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 18:06:20 +0200 Subject: [PATCH 022/304] Remove qmldir from qml resources and use proper Cura namespace for everything Since we now properly expose all the qml files in the Cura namespace we should also use it from there. --- resources/qml/Cura.qml | 124 ++++++++++----------- resources/qml/Settings/SettingCategory.qml | 5 +- resources/qml/Settings/SettingView.qml | 4 +- resources/qml/qmldir | 3 - 4 files changed, 64 insertions(+), 72 deletions(-) delete mode 100644 resources/qml/qmldir diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index a7f4a43c22..a043567c0f 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -10,8 +10,6 @@ import QtQuick.Dialogs 1.1 import UM 1.2 as UM import Cura 1.0 as Cura -import "." - UM.MainWindow { id: base @@ -56,7 +54,7 @@ UM.MainWindow title: catalog.i18nc("@title:menu menubar:toplevel","&File"); MenuItem { - action: Actions.open; + action: Cura.Actions.open; } Menu @@ -118,11 +116,11 @@ UM.MainWindow } } - MenuItem { action: Actions.reloadAll; } + MenuItem { action: Cura.Actions.reloadAll; } MenuSeparator { } - MenuItem { action: Actions.quit; } + MenuItem { action: Cura.Actions.quit; } } Menu @@ -130,17 +128,17 @@ UM.MainWindow //: Edit menu title: catalog.i18nc("@title:menu menubar:toplevel","&Edit"); - MenuItem { action: Actions.undo; } - MenuItem { action: Actions.redo; } + MenuItem { action: Cura.Actions.undo; } + MenuItem { action: Cura.Actions.redo; } MenuSeparator { } - MenuItem { action: Actions.deleteSelection; } - MenuItem { action: Actions.deleteAll; } - MenuItem { action: Actions.resetAllTranslation; } - MenuItem { action: Actions.resetAll; } + MenuItem { action: Cura.Actions.deleteSelection; } + MenuItem { action: Cura.Actions.deleteAll; } + MenuItem { action: Cura.Actions.resetAllTranslation; } + MenuItem { action: Cura.Actions.resetAll; } MenuSeparator { } - MenuItem { action: Actions.groupObjects;} - MenuItem { action: Actions.mergeObjects;} - MenuItem { action: Actions.unGroupObjects;} + MenuItem { action: Cura.Actions.groupObjects;} + MenuItem { action: Cura.Actions.mergeObjects;} + MenuItem { action: Cura.Actions.unGroupObjects;} } Menu @@ -216,8 +214,8 @@ UM.MainWindow MenuSeparator { visible: Cura.MachineManager.hasVariants; } - MenuItem { action: Actions.addMachine; } - MenuItem { action: Actions.configureMachines; } + MenuItem { action: Cura.Actions.addMachine; } + MenuItem { action: Cura.Actions.configureMachines; } } Menu @@ -290,11 +288,11 @@ UM.MainWindow MenuSeparator { id: profileMenuSeparator } - MenuItem { action: Actions.updateProfile; } - MenuItem { action: Actions.resetProfile; } - MenuItem { action: Actions.addProfile; } + MenuItem { action: Cura.Actions.updateProfile; } + MenuItem { action: Cura.Actions.resetProfile; } + MenuItem { action: Cura.Actions.addProfile; } MenuSeparator { } - MenuItem { action: Actions.manageProfiles; } + MenuItem { action: Cura.Actions.manageProfiles; } } Menu @@ -337,7 +335,7 @@ UM.MainWindow //: Settings menu title: catalog.i18nc("@title:menu menubar:toplevel","&Settings"); - MenuItem { action: Actions.preferences; } + MenuItem { action: Cura.Actions.preferences; } } Menu @@ -345,11 +343,11 @@ UM.MainWindow //: Help menu title: catalog.i18nc("@title:menu menubar:toplevel","&Help"); - MenuItem { action: Actions.showEngineLog; } - MenuItem { action: Actions.documentation; } - MenuItem { action: Actions.reportBug; } + MenuItem { action: Cura.Actions.showEngineLog; } + MenuItem { action: Cura.Actions.documentation; } + MenuItem { action: Cura.Actions.reportBug; } MenuSeparator { } - MenuItem { action: Actions.about; } + MenuItem { action: Cura.Actions.about; } } } @@ -439,7 +437,7 @@ UM.MainWindow left: parent.left; //leftMargin: UM.Theme.getSize("loadfile_margin").width } - action: Actions.open; + action: Cura.Actions.open; } Image @@ -527,12 +525,12 @@ UM.MainWindow width: UM.Theme.getSize("sidebar").width; - addMachineAction: Actions.addMachine; - configureMachinesAction: Actions.configureMachines; - addProfileAction: Actions.addProfile; - updateProfileAction: Actions.updateProfile; - resetProfileAction: Actions.resetProfile; - manageProfilesAction: Actions.manageProfiles; + addMachineAction: Cura.Actions.addMachine; + configureMachinesAction: Cura.Actions.configureMachines; + addProfileAction: Cura.Actions.addProfile; + updateProfileAction: Cura.Actions.updateProfile; + resetProfileAction: Cura.Actions.resetProfile; + manageProfilesAction: Cura.Actions.manageProfiles; } } } @@ -573,13 +571,13 @@ UM.MainWindow Connections { - target: Actions.preferences + target: Cura.Actions.preferences onTriggered: preferences.visible = true } Connections { - target: Actions.addProfile + target: Cura.Actions.addProfile onTriggered: { UM.MachineManager.createProfile(); @@ -593,7 +591,7 @@ UM.MainWindow Connections { - target: Actions.configureMachines + target: Cura.Actions.configureMachines onTriggered: { preferences.visible = true; @@ -603,7 +601,7 @@ UM.MainWindow Connections { - target: Actions.manageProfiles + target: Cura.Actions.manageProfiles onTriggered: { preferences.visible = true; @@ -613,7 +611,7 @@ UM.MainWindow Connections { - target: Actions.configureSettingVisibility + target: Cura.Actions.configureSettingVisibility onTriggered: { preferences.visible = true; @@ -636,22 +634,22 @@ UM.MainWindow id: objectContextMenu; property variant objectId: -1; - MenuItem { action: Actions.centerObject; } - MenuItem { action: Actions.deleteObject; } - MenuItem { action: Actions.multiplyObject; } + MenuItem { action: Cura.Actions.centerObject; } + MenuItem { action: Cura.Actions.deleteObject; } + MenuItem { action: Cura.Actions.multiplyObject; } MenuSeparator { } - MenuItem { action: Actions.deleteAll; } - MenuItem { action: Actions.reloadAll; } - MenuItem { action: Actions.resetAllTranslation; } - MenuItem { action: Actions.resetAll; } + MenuItem { action: Cura.Actions.deleteAll; } + MenuItem { action: Cura.Actions.reloadAll; } + MenuItem { action: Cura.Actions.resetAllTranslation; } + MenuItem { action: Cura.Actions.resetAll; } MenuSeparator { } - MenuItem { action: Actions.groupObjects; } - MenuItem { action: Actions.mergeObjects; } - MenuItem { action: Actions.unGroupObjects; } + MenuItem { action: Cura.Actions.groupObjects; } + MenuItem { action: Cura.Actions.mergeObjects; } + MenuItem { action: Cura.Actions.unGroupObjects; } Connections { - target: Actions.deleteObject + target: Cura.Actions.deleteObject onTriggered: { if(objectContextMenu.objectId != 0) @@ -664,7 +662,7 @@ UM.MainWindow Connections { - target: Actions.multiplyObject + target: Cura.Actions.multiplyObject onTriggered: { if(objectContextMenu.objectId != 0) @@ -677,7 +675,7 @@ UM.MainWindow Connections { - target: Actions.centerObject + target: Cura.Actions.centerObject onTriggered: { if(objectContextMenu.objectId != 0) @@ -692,14 +690,14 @@ UM.MainWindow Menu { id: contextMenu; - MenuItem { action: Actions.deleteAll; } - MenuItem { action: Actions.reloadAll; } - MenuItem { action: Actions.resetAllTranslation; } - MenuItem { action: Actions.resetAll; } + MenuItem { action: Cura.Actions.deleteAll; } + MenuItem { action: Cura.Actions.reloadAll; } + MenuItem { action: Cura.Actions.resetAllTranslation; } + MenuItem { action: Cura.Actions.resetAll; } MenuSeparator { } - MenuItem { action: Actions.groupObjects; } - MenuItem { action: Actions.mergeObjects; } - MenuItem { action: Actions.unGroupObjects; } + MenuItem { action: Cura.Actions.groupObjects; } + MenuItem { action: Cura.Actions.mergeObjects; } + MenuItem { action: Cura.Actions.unGroupObjects; } } Connections @@ -720,13 +718,13 @@ UM.MainWindow Connections { - target: Actions.quit + target: Cura.Actions.quit onTriggered: base.visible = false; } Connections { - target: Actions.toggleFullScreen + target: Cura.Actions.toggleFullScreen onTriggered: base.toggleFullscreen(); } @@ -756,7 +754,7 @@ UM.MainWindow Connections { - target: Actions.open + target: Cura.Actions.open onTriggered: openDialog.open() } @@ -767,7 +765,7 @@ UM.MainWindow Connections { - target: Actions.showEngineLog + target: Cura.Actions.showEngineLog onTriggered: engineLog.visible = true; } @@ -778,7 +776,7 @@ UM.MainWindow Connections { - target: Actions.addMachine + target: Cura.Actions.addMachine onTriggered: addMachineDialog.visible = true; } @@ -789,7 +787,7 @@ UM.MainWindow Connections { - target: Actions.about + target: Cura.Actions.about onTriggered: aboutDialog.visible = true; } diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index f4e3dbe5ae..f4c35f876e 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -7,8 +7,7 @@ import QtQuick.Controls.Styles 1.1 import QtQuick.Layouts 1.1 import UM 1.1 as UM - -import ".." +import Cura 1.0 as Cura Button { id: base; @@ -45,7 +44,7 @@ Button { iconSource: UM.Theme.getIcon("settings"); onClicked: { - Actions.configureSettingVisibility.trigger(definition) + Cura.Actions.configureSettingVisibility.trigger(definition) } } diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 560e7b0803..48380e9a95 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -9,8 +9,6 @@ import QtQuick.Layouts 1.1 import UM 1.2 as UM import Cura 1.0 as Cura -import ".." - ScrollView { id: base; @@ -134,7 +132,7 @@ ScrollView //: Settings context menu action text: catalog.i18nc("@action:menu", "Configure setting visiblity..."); - onTriggered: Actions.configureSettingVisibility.trigger(contextMenu); + onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu); } } } diff --git a/resources/qml/qmldir b/resources/qml/qmldir deleted file mode 100644 index 096561aca5..0000000000 --- a/resources/qml/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module Cura - -singleton Actions 1.0 Actions.qml From 3953da7a509886f002e305b8f62587504af5a37d Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 31 May 2016 18:13:47 +0200 Subject: [PATCH 023/304] JSON fix: support roof speed was visible when roof enabled but support not (CURA-1498) --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6dca68a6c9..ce7c17c41c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1116,7 +1116,7 @@ "minimum_value": "0.1", "maximum_value": "299792458000", "maximum_value_warning": "150", - "enabled": "support_roof_enable", + "enabled": "support_roof_enable and support_enable", "value": "speed_support / 1.5", "global_only": true } From 38c9d9e4a12e65ccead5f784feaf9abfd7dab2b0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 10:47:04 +0200 Subject: [PATCH 024/304] Fix highlighting the currently active (printer|quality|material) on their management pages CURA-1278 --- resources/qml/MachinesPage.qml | 10 ++++++++++ resources/qml/Preferences/MaterialsPage.qml | 10 ++++++++++ resources/qml/Preferences/ProfilesPage.qml | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/resources/qml/MachinesPage.qml b/resources/qml/MachinesPage.qml index 00ebcfc0af..faef019deb 100644 --- a/resources/qml/MachinesPage.qml +++ b/resources/qml/MachinesPage.qml @@ -17,6 +17,16 @@ UM.ManagementPage filter: {"type": "machine"} } + activeId: Cura.MachineManager.activeMachineId + activeIndex: { + for(var i = 0; i < model.rowCount(); i++) { + if (model.getItem(i).id == Cura.MachineManager.activeMachineId) { + return i; + } + } + return -1; + } + onAddObject: Printer.requestAddPrinter() onRemoveObject: confirmDialog.open(); onRenameObject: renameDialog.open(); diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 03ede39a5c..0b606ced77 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -15,6 +15,16 @@ UM.ManagementPage title: catalog.i18nc("@title:tab", "Materials"); model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } + + activeId: Cura.MachineManager.activeMaterialId + activeIndex: { + for(var i = 0; i < model.rowCount(); i++) { + if (model.getItem(i).id == Cura.MachineManager.activeMaterialId) { + return i; + } + } + return -1; + } /* onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); } onRemoveObject: confirmDialog.open(); diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 10acc8beef..9561bba521 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -17,6 +17,16 @@ UM.ManagementPage model: UM.InstanceContainersModel { filter: { "type": "quality" } } + activeId: Cura.MachineManager.activeQualityId + activeIndex: { + for(var i = 0; i < model.rowCount(); i++) { + if (model.getItem(i).id == Cura.MachineManager.activeQualityId) { + return i; + } + } + return -1; + } + onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) onAddObject: { var selectedProfile; From 2a288cd7a2107f43239143623fe4184264eb3b9b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 11:51:42 +0200 Subject: [PATCH 025/304] Fix typo causing a minor error when opening MaterialsPage.qml CURA-339 --- resources/qml/Preferences/MaterialsPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index 0b606ced77..ed35a32fdf 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -195,7 +195,7 @@ UM.ManagementPage onCurrentItemChanged: { - if(!currentItem == null) + if(currentItem == null) { return } From a08e71774d2386d57e52aaa8e353bda0a8202d77 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 31 May 2016 10:59:32 +0200 Subject: [PATCH 026/304] Make ExtruderManagerModel no longer a PyQt model It is still a model according to the MVC paradigm but not according to Qt. To be consistent with the rest, don't call it a model any more. Contributes to issues CURA-1278 and CURA-351. --- cura/{ExtruderManagerModel.py => ExtruderManager.py} | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) rename cura/{ExtruderManagerModel.py => ExtruderManager.py} (95%) diff --git a/cura/ExtruderManagerModel.py b/cura/ExtruderManager.py similarity index 95% rename from cura/ExtruderManagerModel.py rename to cura/ExtruderManager.py index 7f0baa7aa8..c99ac4be00 100644 --- a/cura/ExtruderManagerModel.py +++ b/cura/ExtruderManager.py @@ -1,7 +1,6 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal import re from UM.Application import Application #To get the global container stack to find the current machine. @@ -15,13 +14,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers # This finds the extruders that are available for the currently active machine # 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 ExtruderManagerModel(QObject): +class ExtruderManager: ## Registers listeners and such to listen to changes to the extruders. - # - # \param parent Parent QObject of this model. - def __init__(self, parent = None): - super().__init__(parent) - + def __init__(self): self._extruderDefinitions = [] #Extruder definitions for the current machine. self._nozzles = {} #Nozzle instances for each extruder. self._extruderTrains = [] #Container stacks for each of the extruder trains. From 6164112bf2d8f78c30b6fe39cda29b5223686da4 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 1 Jun 2016 13:35:09 +0200 Subject: [PATCH 027/304] Setting textfield now updates correctly, even when mouse is hovering another text field. CURA-1278 --- resources/qml/Settings/SettingTextField.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index 9972f83aa1..2a1fb96330 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -16,8 +16,6 @@ SettingItem anchors.fill: parent - property alias hovered: mouseArea.containsMouse; - border.width: UM.Theme.getSize("default_lining").width border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") @@ -74,7 +72,7 @@ SettingItem { id: mouseArea anchors.fill: parent; - hoverEnabled: true; + //hoverEnabled: true; cursorShape: Qt.IBeamCursor } From 48eb8de9a10b870aa3d0f26386a67c9d8f5e47c1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 13:35:30 +0200 Subject: [PATCH 028/304] Add basic extruder implementation This implementation can load an extruder from a definition container, but doesn't expose anything (yet). It is intended to function in much the same way as a definition model, so it must expose its relevant properties to QML. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 cura/Extruder.py diff --git a/cura/Extruder.py b/cura/Extruder.py new file mode 100644 index 0000000000..f9f957dfe3 --- /dev/null +++ b/cura/Extruder.py @@ -0,0 +1,85 @@ +# Copyright (c) 2016 Ultimaker B.V. +# Cura is released under the terms of the AGPLv3 or higher. + +import re #To parse container registry names to increment the duplicates-resolving number. + +import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. +import UM.Settings.ContainerStack #To create a container stack for this extruder. + +class Extruder: + ## Creates a new extruder from the specified definition container. + # + # \param definition The definition container defining this extruder. + def __init__(self, definition): + self._definition = definition + + container_registry = UM.Settings.ContainerRegistry.getInstance() + + #Find the nozzles that fit on this extruder. + self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId()) + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId() + ",*") + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId()) + + #Create a container stack for this extruder. + self._container_stack = UM.Settings.ContainerStack(self._uniqueName(self._definition.getId())) + self._container_stack.addMetaDataEntry("type", "extruder_train") + self._container_stack.addContainer(self._definition) + + #Find the nozzle to use for this extruder. + self._nozzle = container_registry.getEmptyInstanceContainer() + if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid. + self._nozzle = self._nozzles[0] + preferred_nozzle_id = self._definition.getMetaDataEntry("preferred_nozzle") + if preferred_nozzle_id: + for nozzle in self._nozzles: + if nozzle.getId() == preferred_nozzle_id: + self._nozzle = nozzle + break + self._container_stack.addContainer(self._nozzle) + + #Find a material to use for this nozzle. + self._material = container_registry.getEmptyInstanceContainer() + all_materials = container_registry.findInstanceContainers(type = "material") + if len(all_materials) >= 1: + self._material = all_materials[0] + preferred_material_id = self._definition.getMetaDataEntry("preferred_material") + if preferred_material_id: + preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower()) + if len(preferred_material) >= 1: + self._material = preferred_material[0] + self._container_stack.addContainer(self._material) + + #Find a quality to use for this extruder. + self._quality = container_registry.getEmptyInstanceContainer() + all_qualities = container_registry.findInstanceContainers(type = "quality") + if len(all_qualities) >= 1: + self._quality = all_qualities[0] + preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality") + if preferred_quality_id: + preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower()) + if len(preferred_quality) >= 1: + self._quality = preferred_quality[0] + self._container_stack.addContainer(self._quality) + + ## Finds a unique name for an extruder stack. + # + # \param extruder An extruder definition to design a name for. + # \return A name for an extruder stack that is unique and reasonably + # human-readable. + def _uniqueName(self, extruder): + container_registry = UM.Settings.ContainerRegistry.getInstance() + + name = extruder.getName().strip() + num_check = re.compile("(.*?)\s*#\d$").match(name) + if num_check: #There is a number in the name. + name = num_check.group(1) #Filter out the number. + if name == "": #Wait, that deleted everything! + name = "Extruder" + unique_name = name + + i = 1 + while container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name): #A container already has this name. + i += 1 #Try next numbering. + unique_name = "%s #%d" % (name, i) #Fill name like this: "Extruder #2". + return unique_name \ No newline at end of file From 377fed206c0d581c74b72d534fe8bf988ca3b5ef Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 13:41:25 +0200 Subject: [PATCH 029/304] Remove extruder creation logic from manager This logic is now in cura/Extruder.py. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 68 ++++++----------------------------------- 1 file changed, 9 insertions(+), 59 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c99ac4be00..924c6a1e21 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -3,6 +3,7 @@ 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. @@ -26,72 +27,21 @@ class ExtruderManager: ## (Re)loads all extruders of the currently active machine. # # This looks at the global container stack to see which machine is active. - # Then it loads the extruder definitions for that machine and the variants - # of those definitions. Then it puts the new extruder definitions in the - # appropriate place in the container stacks. + # Then it loads the extruders for that machine and loads each of them in a + # list of extruders. def _reloadExtruders(self): - self._extruderDefinitions = [] - self._nozzles = {} - self._extruderTrains = [] + self._extruders = [] global_container_stack = Application.getInstance().getGlobalContainerStack() if not global_container_stack: #No machine has been added yet. return #Then leave them empty! - #Fill the list of extruder trains. + #Get the extruder definitions belonging to the current machine. machine = global_container_stack.getBottom() extruder_train_ids = machine.getMetaData("machine_extruder_trains") for extruder_train_id in extruder_train_ids: - extruders = ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) #Should be only 1 definition if IDs are unique, but add the whole list anyway. - if not extruders: #Empty list or error. + extruder_definitions = 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) continue - self._extruderDefinitions += extruders - - #Fill the nozzles for each of the extruder trains. - for extruder in self._extruderDefinitions: - self._nozzles[extruder.id] = [] - all_nozzles = ContainerRegistry.getInstance().findInstanceContainers(type="nozzle") - for nozzle in all_nozzles: - extruders = nozzle.getMetaDataEntry("definitions").split(",").strip() - for extruder_id in extruders: - self._nozzles[extruder_id] = nozzle - - #Create the extruder train container stacks. - for extruder in self._extruderDefinitions: - self._extruderTrains.append(self._createContainerStack(extruder)) - - ## Creates a container stack for the specified extruder. - # - # This fills in the specified extruder as base definition, then a nozzle - # that fits in that extruder train, then a material that fits through that - # nozzle, then a quality profile that can be used with that material, and - # finally an empty user profile. - # - # \param extruder The extruder to create the container stack for. - # \return A container stack with the specified extruder as base. - def _createContainerStack(self, extruder): - container_stack = ContainerStack(self._uniqueName(extruder)) - #TODO: Fill the container stack. - return container_stack - - ## Finds a unique name for an extruder stack. - # - # \param extruder Extruder to design a name for. - # \return A name for an extruder stack that is unique and reasonably - # human-readable. - def _uniqueName(self, extruder): - container_registry = ContainerRegistry.getInstance() - - name = extruder.getName().strip() - num_check = re.compile("(.*?)\s*#\d$").match(name) - if(num_check): #There is a number in the name. - name = num_check.group(1) #Filter out the number. - if name == "": #Wait, that deleted everything! - name = "Extruder" - unique_name = name - - i = 1 - while(container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name)): #A container already has this name. - i += 1 #Try next numbering. - unique_name = "%s #%d" % (name, i) #Fill name like this: "Extruder #2". - return unique_name \ No newline at end of file + for extruder_definition in extruder_definitions: + self._extruders.append(Extruder(extruder_definition)) \ No newline at end of file From 60a71fcc332da5f7b20939e7458609b7c2be845c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 14:54:30 +0200 Subject: [PATCH 030/304] Only list extruders in extruder manager Let the extruders themselves take care of which profiles are attached to each. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 924c6a1e21..d0dea31206 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -18,9 +18,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers class ExtruderManager: ## Registers listeners and such to listen to changes to the extruders. def __init__(self): - self._extruderDefinitions = [] #Extruder definitions for the current machine. - self._nozzles = {} #Nozzle instances for each extruder. - self._extruderTrains = [] #Container stacks for each of the extruder trains. + self._extruders = [] #Extruders for the current machine. Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. From d1566ef637a5c244c0e7a20611f4998a0fd104f3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 14:55:15 +0200 Subject: [PATCH 031/304] Also reload extruders at init Not a reload really, just a load. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index d0dea31206..4d95a9008d 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -21,6 +21,7 @@ class ExtruderManager: self._extruders = [] #Extruders for the current machine. Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. + self._reloadExtruders() ## (Re)loads all extruders of the currently active machine. # From 91fc90a42323ef64258555c36b3e805881713e22 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:05:14 +0200 Subject: [PATCH 032/304] Link extruder stack to global container stack Each extruder stack is linked to the same global container stack. 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 f9f957dfe3..8fa1b71ab1 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -3,6 +3,7 @@ import re #To parse container registry names to increment the duplicates-resolving number. +import UM.Application #To link the stack to the global container stack. import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. import UM.Settings.ContainerStack #To create a container stack for this extruder. @@ -62,6 +63,8 @@ class Extruder: self._quality = preferred_quality[0] self._container_stack.addContainer(self._quality) + self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + ## Finds a unique name for an extruder stack. # # \param extruder An extruder definition to design a name for. From 0e108f0c04b8be53f51ee7ef18ad23946b3d7e5c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:12:20 +0200 Subject: [PATCH 033/304] Document filtering nozzles by extruder better Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 8fa1b71ab1..5f74bd036f 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -17,7 +17,7 @@ class Extruder: container_registry = UM.Settings.ContainerRegistry.getInstance() #Find the nozzles that fit on this extruder. - self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") + self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId()) self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId() + ",*") self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId()) From faf647dca05bb39f988637d56f7e2fbdaf5ad769 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:14:03 +0200 Subject: [PATCH 034/304] Git ignore resources/firmware It is also compiled and will only be included by including the cura-binary-data repository. However it is also useful to have this in your testing environment. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 72ba4bf565..f60e268711 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ docs/html *.log resources/i18n/en resources/i18n/x-test +resources/firmware # Editors and IDEs. *kdev* From 49e5b1938a8a367d4d47ca04dc877e065982a940 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 1 Jun 2016 15:45:54 +0200 Subject: [PATCH 035/304] Reduce number of top layer to increase processing speed --- plugins/LayerView/LayerView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/LayerView/LayerView.py b/plugins/LayerView/LayerView.py index 9f65a8e783..27bb7f022c 100644 --- a/plugins/LayerView/LayerView.py +++ b/plugins/LayerView/LayerView.py @@ -44,7 +44,7 @@ class LayerView(View): self._top_layers_job = None self._activity = False - self._solid_layers = 5 + self._solid_layers = 1 self._top_layer_timer = QTimer() self._top_layer_timer.setInterval(50) From ffa6a0376d44d7189cdaea9ff7fafd2d5eefaf49 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 21:44:56 +0200 Subject: [PATCH 036/304] Fix typo Contributes to CURA-1540, CURA-1278 --- resources/qml/Cura.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index a043567c0f..32e1e79029 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -303,7 +303,7 @@ UM.MainWindow Instantiator { - id: extenions + id: extensions model: UM.ExtensionModel { } Menu @@ -318,7 +318,7 @@ UM.MainWindow MenuItem { text: model.text - onTriggered: extenions.model.subMenuTriggered(name, model.text) + onTriggered: extensions.model.subMenuTriggered(name, model.text) } onObjectAdded: sub_menu.insertItem(index, object) onObjectRemoved: sub_menu.removeItem(object) From c6dd9d2c8c8028b3798080ad0192bfd165707226 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 22:21:12 +0200 Subject: [PATCH 037/304] Fix codestyle and change faux-"hovered" property mechanism hovered_ex was a bool property that was set in onEntered and onExited, and has been replaced with an alias to the mouseArea.containsMouse that necessitated the clutch. CURA-790 --- resources/qml/SidebarSimple.qml | 39 +++++++++++++++----------------- resources/themes/cura/styles.qml | 20 ++++++++-------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c828b5d3db..c95cb54b1f 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -28,13 +28,13 @@ Item id: infillCellLeft anchors.top: parent.top anchors.left: parent.left - width: base.width/100* 35 - UM.Theme.getSize("default_margin").width + width: base.width / 100 * 35 - UM.Theme.getSize("default_margin").width height: childrenRect.height Label{ id: infillLabel //: Infill selection label - text: catalog.i18nc("@label","Infill:"); + text: catalog.i18nc("@label", "Infill:"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); anchors.top: parent.top @@ -85,7 +85,7 @@ Item { return UM.Theme.getColor("setting_control_selected") } - else if(mousearea.containsMouse) + else if(infillMouseArea.containsMouse) { return UM.Theme.getColor("setting_control_border_highlight") } @@ -106,7 +106,7 @@ Item } MouseArea { - id: mousearea + id: infillMouseArea anchors.fill: parent hoverEnabled: true onClicked: { @@ -187,28 +187,29 @@ Item anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: brimCheckBox.verticalCenter - width: parent.width/100*35 - 3 * UM.Theme.getSize("default_margin").width + width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width //: Bed adhesion label - text: catalog.i18nc("@label:listbox","Bed Adhesion:"); + text: catalog.i18nc("@label:listbox", "Bed Adhesion:"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } CheckBox{ id: brimCheckBox - property bool hovered_ex: false + property alias _hovered: brimMouseArea.containsMouse anchors.top: parent.top anchors.left: adhesionHelperLabel.right anchors.leftMargin: UM.Theme.getSize("default_margin").width //: Setting enable skirt adhesion checkbox - text: catalog.i18nc("@option:check","Print Brim"); + text: catalog.i18nc("@option:check", "Print Brim"); style: UM.Theme.styles.checkbox; checked: platformAdhesionType.properties.value == "brim" MouseArea { + id: brimMouseArea anchors.fill: parent hoverEnabled: true onClicked: @@ -217,13 +218,11 @@ Item } onEntered: { - parent.hovered_ex = true base.showTooltip(brimCheckBox, Qt.point(-brimCheckBox.x, 0), catalog.i18nc("@label", "Enable printing a brim. This will add a single-layer-thick flat area around your object which is easy to cut off afterwards.")); } onExited: { - parent.hovered_ex = false base.hideTooltip(); } } @@ -234,9 +233,9 @@ Item anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: supportCheckBox.verticalCenter - width: parent.width/100*35 - 3 * UM.Theme.getSize("default_margin").width + width: parent.width / 100 * 35 - 3 * UM.Theme.getSize("default_margin").width //: Support label - text: catalog.i18nc("@label:listbox","Support:"); + text: catalog.i18nc("@label:listbox", "Support:"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); } @@ -244,7 +243,7 @@ Item CheckBox{ id: supportCheckBox visible: machineExtruderCount.properties.value <= 1 - property bool hovered_ex: false + property alias _hovered: supportMouseArea.containsMouse anchors.top: brimCheckBox.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height @@ -252,11 +251,12 @@ Item anchors.leftMargin: UM.Theme.getSize("default_margin").width //: Setting enable support checkbox - text: catalog.i18nc("@option:check","Print Support Structure"); + text: catalog.i18nc("@option:check", "Print Support Structure"); style: UM.Theme.styles.checkbox; checked: supportEnabled.properties.value == "True" MouseArea { + id: supportMouseArea anchors.fill: parent hoverEnabled: true onClicked: @@ -265,13 +265,11 @@ Item } onEntered: { - parent.hovered_ex = true base.showTooltip(supportCheckBox, Qt.point(-supportCheckBox.x, 0), catalog.i18nc("@label", "Enable printing support structures. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air.")); } onExited: { - parent.hovered_ex = false base.hideTooltip(); } } @@ -286,10 +284,10 @@ Item anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.left: supportHelperLabel.right anchors.leftMargin: UM.Theme.getSize("default_margin").width - width: parent.width/100*45 + width: parent.width / 100 * 45 style: UM.Theme.styles.combobox - property bool hovered_ex: false + property alias _hovered: supportExtruderMouseArea.containsMouse currentIndex: supportEnabled.properties.value == "True" ? parseFloat(supportExtruderNr.properties.value) + 1 : 0 onActivated: { @@ -301,18 +299,17 @@ Item } } MouseArea { + id: supportExtruderMouseArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.NoButton onEntered: { - parent.hovered_ex = true base.showTooltip(supportExtruderCombobox, Qt.point(-supportExtruderCombobox.x, 0), catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air.")); } onExited: { - parent.hovered_ex = false base.hideTooltip(); } } @@ -358,7 +355,7 @@ Item anchors.rightMargin: UM.Theme.getSize("default_margin").width wrapMode: Text.WordWrap //: Tips label - text: catalog.i18nc("@label","Need help improving your prints? Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting"); + text: catalog.i18nc("@label", "Need help improving your prints? Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting"); font: UM.Theme.getFont("default"); color: UM.Theme.getColor("text"); linkColor: UM.Theme.getColor("text_link") diff --git a/resources/themes/cura/styles.qml b/resources/themes/cura/styles.qml index b2c2329169..1428c3d40a 100644 --- a/resources/themes/cura/styles.qml +++ b/resources/themes/cura/styles.qml @@ -283,14 +283,14 @@ QtObject { property Component combobox: Component { ComboBoxStyle { background: Rectangle { - implicitHeight: UM.Theme.getSize("setting_control").height; - implicitWidth: UM.Theme.getSize("setting_control").width; + implicitHeight: Theme.getSize("setting_control").height; + implicitWidth: Theme.getSize("setting_control").width; - color: (control.hovered || control.hovered_ex) ? Theme.getColor("setting_control_highlight") : Theme.getColor("setting_control"); + color: (control.hovered || control._hovered) ? Theme.getColor("setting_control_highlight") : Theme.getColor("setting_control"); Behavior on color { ColorAnimation { duration: 50; } } border.width: Theme.getSize("default_lining").width; - border.color: (control.hovered || control.hovered_ex) ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border"); + border.color: (control.hovered || control._hovered) ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border"); } label: Item { Label { @@ -301,7 +301,7 @@ QtObject { anchors.verticalCenter: parent.verticalCenter; text: control.currentText; - font: UM.Theme.getFont("default"); + font: Theme.getFont("default"); color: !enabled ? Theme.getColor("setting_control_disabled_text") : Theme.getColor("setting_control_text"); elide: Text.ElideRight; @@ -314,9 +314,9 @@ QtObject { anchors.rightMargin: 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 + source: Theme.getIcon("arrow_bottom") + width: Theme.getSize("standard_arrow").width + height: Theme.getSize("standard_arrow").height sourceSize.width: width + 5 sourceSize.height: width + 5 @@ -333,13 +333,13 @@ QtObject { implicitWidth: Theme.getSize("checkbox").width; implicitHeight: Theme.getSize("checkbox").height; - color: (control.hovered || control.hovered_ex) ? Theme.getColor("checkbox_hover") : Theme.getColor("checkbox"); + color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_hover") : Theme.getColor("checkbox"); Behavior on color { ColorAnimation { duration: 50; } } radius: control.exclusiveGroup ? Theme.getSize("checkbox").width / 2 : 0 border.width: Theme.getSize("default_lining").width; - border.color: (control.hovered || control.hovered_ex) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border"); + border.color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border"); UM.RecolorImage { anchors.verticalCenter: parent.verticalCenter From 7d65475bf99d88b6ed8d66154b733147b4112669 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Jun 2016 23:59:09 +0200 Subject: [PATCH 038/304] Fix mouseover highlight of checkbox settings CURA-1278 --- resources/qml/Settings/SettingCheckBox.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingCheckBox.qml b/resources/qml/Settings/SettingCheckBox.qml index 6f0314160e..1d66e509d0 100644 --- a/resources/qml/Settings/SettingCheckBox.qml +++ b/resources/qml/Settings/SettingCheckBox.qml @@ -16,6 +16,7 @@ SettingItem { id: control anchors.fill: parent + hoverEnabled: true property bool checked: { From 907de8b586192f51909a7233b85ffeea80e7b51b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 00:01:08 +0200 Subject: [PATCH 039/304] Improve performance of advanced sidebar Prevent a delegate being loaded when the item is "filtered out" by the model. CURA-1278 --- resources/qml/Settings/SettingView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 48380e9a95..9dabbaee98 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -50,6 +50,7 @@ ScrollView //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. asynchronous: model.type != "enum" + active: model.type != undefined source: { From ed3d01ed7b53d6a83e3ce274fe35455214382504 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 06:38:57 +0200 Subject: [PATCH 040/304] Add icon to Machine category to squelch some warnings CURA-1278 --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ce7c17c41c..48952c2c99 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -24,6 +24,7 @@ "label": "Machine", "type": "category", "description": "Machine specific settings", + "icon": "category_machine", "children": { "machine_show_variants": From d5aa75f2cf7beba2f6f2ba5243dc7d7cc8d18c46 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 01:47:44 +0200 Subject: [PATCH 041/304] Remove obsolete file --- .../Settings/SettingsConfigurationPage.qml | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 resources/qml/Settings/SettingsConfigurationPage.qml diff --git a/resources/qml/Settings/SettingsConfigurationPage.qml b/resources/qml/Settings/SettingsConfigurationPage.qml deleted file mode 100644 index a2889d410a..0000000000 --- a/resources/qml/Settings/SettingsConfigurationPage.qml +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2015 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.Layouts 1.1 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQml 2.2 - -import UM 1.1 as UM - -import "../Preferences" - -PreferencesPage -{ - //: Machine configuration page title. - title: catalog.i18nc("@title:tab","Machine"); - id: base - - contents: ColumnLayout - { - z: base.z - anchors.fill: parent; - UM.I18nCatalog { id: catalog; name:"uranium"} - RowLayout - { - //: Active machine combo box label - Label { text: catalog.i18nc("@label:listbox","Active Machine:"); } - ComboBox - { - id: machineCombo; - Layout.fillWidth: true; - model: UM.Models.machinesModel; - textRole: "name"; - onActivated: - { - if(index != -1) - UM.Models.machinesModel.setActive(index); - } - - Connections - { - id: machineChange - target: UM.Application - onMachineChanged: machineCombo.currentIndex = machineCombo.find(UM.Application.machineName); - } - - Component.onCompleted: machineCombo.currentIndex = machineCombo.find(UM.Application.machineName); - } - //: Remove active machine button - Button { text: catalog.i18nc("@action:button","Remove"); onClicked: confirmRemoveDialog.open(); } - } - ScrollView - { - id: settingsScrollView - Layout.fillWidth: true; - Layout.fillHeight: true; - - ListView - { - id: settingsListView - delegate: settingDelegate - model: UM.Models.settingsModel - x: 0 - - section.property: "category" - section.delegate: Label { text: section } - } - } - } - - Component - { - id: settingDelegate - CheckBox - { - z:0 - id: settingCheckBox - text: model.name; - x: depth * 25 - checked: model.visibility - onClicked: ListView.view.model.setVisibility(model.key, checked) - //enabled: !model.disabled - - onHoveredChanged: - { - if(hovered) - { - var xPos = parent.x + settingCheckBox.width; - var yPos = parent.y; - toolTip.show(model.description, 1000, 200, undefined, undefined) //tooltip-text, hover-delay in msec, animation-length in msec, position X, position Y (both y en x == undefined: gives the tooltip a standard placement in the right corner) - } else - { - toolTip.hide(0, 0)//hover-delay in msec, animation-length in msec - } - } - } - } - - PreferencesToolTip - { - id: toolTip; - } - - MessageDialog - { - id: confirmRemoveDialog; - - icon: StandardIcon.Question; - //: Remove machine confirmation dialog title - title: catalog.i18nc("@title:window","Confirm Machine Deletion"); - //: Remove machine confirmation dialog text - text: catalog.i18nc("@label","Are you sure you wish to remove the machine?"); - standardButtons: StandardButton.Yes | StandardButton.No; - - onYes: UM.Models.machinesModel.removeMachine(machineCombo.currentIndex); - } -} From 803dcdcec703c69896dafc5263476c00c1ee9643 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 31 May 2016 01:48:21 +0200 Subject: [PATCH 042/304] Stop the Item's hover timer when showing a different tooltip --- resources/qml/Settings/SettingItem.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index c1666a8157..4c14ee4039 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -136,7 +136,7 @@ Item { propertyProvider.removeFromContainer(0) } - onEntered: base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) + onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) } onExited: base.showTooltip(definition.description); } @@ -163,7 +163,7 @@ Item { iconSource: UM.Theme.getIcon("notice"); - onEntered: base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) + onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) } onExited: base.showTooltip(definition.description); } From e0fab7aa11532b9243a42d8b7c1f9eb0093c9591 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:03:24 +0200 Subject: [PATCH 043/304] Add some logging and documentation to XmlMaterialProfile Contributes to CURA-339 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index d73beec193..9cfca1c535 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -45,6 +45,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): self.addMetaDataEntry("material", material.text) self.addMetaDataEntry("color_name", color.text) + continue + self.addMetaDataEntry(tag_name, entry.text) property_values = {} @@ -78,6 +80,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): if key in self.__material_property_setting_map: self.setProperty(self.__material_property_setting_map[key], "value", entry.text, self._definition) global_setting_values[self.__material_property_setting_map[key]] = entry.text + else: + Logger.log("d", "Unsupported material setting %s", key) machines = data.iterfind("./um:settings/um:machine", self.__namespaces) for machine in machines: @@ -87,6 +91,8 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): key = entry.get("key") if key in self.__material_property_setting_map: machine_setting_values[self.__material_property_setting_map[key]] = entry.text + else: + Logger.log("d", "Unsupported material setting %s", key) identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces) for identifier in identifiers: @@ -116,12 +122,15 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): UM.Settings.ContainerRegistry.getInstance().addContainer(new_material) + + # Map XML file setting names to internal names __material_property_setting_map = { "print temperature": "material_print_temperature", "heated bed temperature": "material_bed_temperature", "standby temperature": "material_standby_temperature", } + # Map XML file product names to internal ids __product_id_map = { "Ultimaker2": "ultimaker2", "Ultimaker2+": "ultimaker2_plus", From f491405eb19f6504969a4f031aa630c5ba8b2526 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:04:06 +0200 Subject: [PATCH 044/304] Use a copy of the metadata for Xml materials Contributes to CURA-339 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 9cfca1c535..bdffc3d60f 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -106,16 +106,18 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): Logger.log("w", "No definition found for machine ID %s", machine_id) continue + definition = definitions[0] + new_material = XmlMaterialProfile(self.id + "_" + machine_id) new_material.setName(self.getName()) - new_material.setMetaData(self.getMetaData()) - new_material.setDefinition(definitions[0]) + new_material.setMetaData(copy.deepcopy(self.getMetaData())) + new_material.setDefinition(definition) for key, value in global_setting_values.items(): - new_material.setProperty(key, "value", value, definitions[0]) + new_material.setProperty(key, "value", value, definition) for key, value in machine_setting_values.items(): - new_material.setProperty(key, "value", value, definitions[0]) + new_material.setProperty(key, "value", value, definition) new_material._dirty = False From 90ac1c1380cb904ee07b33317954fdf65aa0d2d2 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:04:43 +0200 Subject: [PATCH 045/304] Add support for hotend-specfic overrides to XmlMaterialProfile Contributes to CURA-339 --- .../XmlMaterialProfile/XmlMaterialProfile.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index bdffc3d60f..c97dbe85ed 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -123,6 +123,44 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): UM.Settings.ContainerRegistry.getInstance().addContainer(new_material) + hotends = machine.iterfind("./um:hotend", self.__namespaces) + for hotend in hotends: + hotend_id = hotend.get("id") + if hotend_id is None: + continue + + variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = hotend_id) + if not variant_containers: + # It is not really properly defined what "ID" is so also search for variants by name. + variant_containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(definition = definition.id, name = hotend_id) + + if not variant_containers: + Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id) + continue + + new_hotend_material = XmlMaterialProfile(self.id + "_" + machine_id + "_" + hotend_id.replace(" ", "_")) + new_hotend_material.setName(self.getName()) + new_hotend_material.setMetaData(copy.deepcopy(self.getMetaData())) + new_hotend_material.setDefinition(definition) + + new_hotend_material.addMetaDataEntry("variant", variant_containers[0].id) + + for key, value in global_setting_values.items(): + new_hotend_material.setProperty(key, "value", value, definition) + + for key, value in machine_setting_values.items(): + new_hotend_material.setProperty(key, "value", value, definition) + + settings = hotend.iterfind("./um:setting", self.__namespaces) + for entry in settings: + key = entry.get("key") + if key in self.__material_property_setting_map: + new_hotend_material.setProperty(self.__material_property_setting_map[key], "value", entry.text, definition) + else: + Logger.log("d", "Unsupported material setting %s", key) + + new_hotend_material._dirty = False + UM.Settings.ContainerRegistry.getInstance().addContainer(new_hotend_material) # Map XML file setting names to internal names From eaea940aa2a9a4cbccdc23459088fb12064bdaf0 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:05:11 +0200 Subject: [PATCH 046/304] Add support for some additional properties to XmlMaterialProfile Contributes to CURA-339 --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index c97dbe85ed..89c7d76e9f 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -168,6 +168,9 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer): "print temperature": "material_print_temperature", "heated bed temperature": "material_bed_temperature", "standby temperature": "material_standby_temperature", + "print cooling": "cool_fan_speed", + "retraction amount": "retraction_amount", + "retraction speed": "retraction_speed", } # Map XML file product names to internal ids From 123af4e3e46e0f5ca0c5e6e801a27008b0dd956a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:07:04 +0200 Subject: [PATCH 047/304] Use metadata to determine what materials/qualities to use when adding a machine Contributes to CURA-1612 --- cura/MachineManagerModel.py | 97 ++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index deef72529b..83b8e87859 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -1,11 +1,13 @@ +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 -import re class MachineManagerModel(QObject): def __init__(self, parent = None): @@ -74,43 +76,48 @@ class MachineManagerModel(QObject): empty_container = UM.Settings.ContainerRegistry.getInstance().getEmptyInstanceContainer() - variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) - if variants: - new_global_stack.addMetaDataEntry("has_variants", True) - - preferred_variant_id = definitions[0].getMetaDataEntry("preferred_variant") variant_instance_container = empty_container - if preferred_variant_id: - preferred_variant_id = preferred_variant_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id) - if container: - variant_instance_container = container[0] + if definition.getMetaDataEntry("has_variants"): + variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", empty_container) - if variants and variant_instance_container == empty_container: - variant_instance_container = variants[0] + if variant_instance_container == empty_container: + variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) + if variants: + variant_instance_container = variants[0] - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) - if materials: - new_global_stack.addMetaDataEntry("has_materials", True) + if variant_instance_container == empty_container: + Logger.log("w", "Machine %s defines it has variants but no variants found", definition.id) - preferred_material_id = definitions[0].getMetaDataEntry("preferred_material") material_instance_container = empty_container - if preferred_material_id: - preferred_material_id = preferred_material_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_material_id) - if container: - material_instance_container = container[0] + if definition.getMetaDataEntry("has_materials"): + material_instance_container = self._getPreferredContainer(definition, "preferred_material", empty_container) - if materials and material_instance_container == empty_container: - material_instance_container = materials[0] + if material_instance_container == empty_container: + materials = None + if definition.getMetaDataEntry("has_machine_materials"): + if variant_instance_container != empty_container: + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id, variant = variant_instance_container.id) + else: + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) + else: + materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = "fdmprinter") - preferred_quality_id = definitions[0].getMetaDataEntry("preferred_quality") - quality_instance_container = empty_container - if preferred_quality_id: - preferred_quality_id = preferred_quality_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_quality_id) - if container: - quality_instance_container = container[0] + if materials: + material_instance_container = materials[0] + + quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", empty_container) + + if quality_instance_container == empty_container: + if definition.getMetaDataEntry("has_machine_quality"): + if material_instance_container: + qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id, material = material_instance_container.id) + else: + qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id) + else: + qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = "fdmprinter") + + if qualities: + quality_instance_container = qualities[0] current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container.addMetaDataEntry("machine", name) @@ -277,16 +284,40 @@ class MachineManagerModel(QObject): @pyqtProperty(bool, notify = globalContainerChanged) def hasMaterials(self): if self._global_container_stack: - return self._global_container_stack.getMetaDataEntry("has_materials", False) + return bool(self._global_container_stack.getMetaDataEntry("has_materials", False)) return False @pyqtProperty(bool, notify = globalContainerChanged) def hasVariants(self): if self._global_container_stack: - return self._global_container_stack.getMetaDataEntry("has_variants", False) + return bool(self._global_container_stack.getMetaDataEntry("has_variants", False)) return False + @pyqtProperty(bool, notify = globalContainerChanged) + def filterMaterialsByMachine(self): + if self._global_container_stack: + return bool(self._global_container_stack.getMetaDataEntry("has_machine_materials", False)) + + return False + + @pyqtProperty(bool, notify = globalContainerChanged) + def filterQualityByMachine(self): + if self._global_container_stack: + return bool(self._global_container_stack.getMetaDataEntry("has_machine_quality", False)) + + return False + + def _getPreferredContainer(self, definition, property_name, default_container): + preferred_id = definition.getMetaDataEntry(property_name) + if preferred_id: + preferred_variant_id = preferred_variant_id.lower() + container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id) + if container: + return container[0] + + return default_container + def createMachineManagerModel(engine, script_engine): return MachineManagerModel() From ceb21ce89b6f7e8cbc89fcc17a4546f57f72f3ed Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:07:51 +0200 Subject: [PATCH 048/304] Filter material/quality by machine only when we should filter Contributes to CURA-1612 --- resources/qml/ProfileSetup.qml | 18 +++++++++++++++++- resources/qml/SidebarHeader.qml | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index 95aed3685c..3175a4e2b3 100644 --- a/resources/qml/ProfileSetup.qml +++ b/resources/qml/ProfileSetup.qml @@ -59,7 +59,23 @@ Item{ id: profileSelectionInstantiator model: UM.InstanceContainersModel { - filter: {"type": "quality"} + 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 diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 282fa8af25..4b48584174 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -266,7 +266,23 @@ Item id: materialSelectionInstantiator model: UM.InstanceContainersModel { - filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } + filter: + { + var result = { "type": "material" } + if(Cura.MachineManager.filterMaterialsByMachine) + { +// result.definition = Cura.MachineManager.activeDefinitionId + if(Cura.MachineManager.hasVariants) + { + result.variant = Cura.MachineManager.activeVariantId + } + } + else + { + result.definition = "fdmprinter" + } + return result + } } MenuItem { From 2b91e3639ed6e28985ee3b3f82345f0be2c57808 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:08:21 +0200 Subject: [PATCH 049/304] Add basic ABS and CPE material profiles Contributes to CURA-1612 --- .../materials/generic_abs.xml.fdm_material | 34 +++++++++++++++++++ .../materials/generic_cpe.xml.fdm_material | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 resources/materials/generic_abs.xml.fdm_material create mode 100644 resources/materials/generic_cpe.xml.fdm_material diff --git a/resources/materials/generic_abs.xml.fdm_material b/resources/materials/generic_abs.xml.fdm_material new file mode 100644 index 0000000000..654b06d221 --- /dev/null +++ b/resources/materials/generic_abs.xml.fdm_material @@ -0,0 +1,34 @@ + + + + + + Generic + ABS + Generic + + 506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9 + 0 + #FF0000 + + + 1.07 + 2.85 + + + 250 + 80 + + + + + + + + + + + + diff --git a/resources/materials/generic_cpe.xml.fdm_material b/resources/materials/generic_cpe.xml.fdm_material new file mode 100644 index 0000000000..bbe6e328d2 --- /dev/null +++ b/resources/materials/generic_cpe.xml.fdm_material @@ -0,0 +1,34 @@ + + + + + + Generic + CPE + Generic + + 506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9 + 0 + #0000FF + + + 0.94 + 2.85 + + + 250 + 70 + + + + + + + + + + + + From 6847365e097420c12e2824923ef85bbd70972933 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:08:56 +0200 Subject: [PATCH 050/304] Indicate the UM2+ should use machine specific materials and qualities Contributes to CURA-1612 --- resources/definitions/ultimaker.def.json | 5 +---- resources/definitions/ultimaker2_plus.def.json | 8 ++++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/definitions/ultimaker.def.json b/resources/definitions/ultimaker.def.json index 60e4dbbf40..b33f820198 100644 --- a/resources/definitions/ultimaker.def.json +++ b/resources/definitions/ultimaker.def.json @@ -6,9 +6,6 @@ "inherits": "fdmprinter", "metadata": { "author": "Ultimaker", - "manufacturer": "Ultimaker", - "preferred_profile": "Normal Quality", - "preferred_nozzle": "0.4 mm", - "preferred_material": "PLA" + "manufacturer": "Ultimaker" } } diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json index 9f68c2a16b..75501fb158 100644 --- a/resources/definitions/ultimaker2_plus.def.json +++ b/resources/definitions/ultimaker2_plus.def.json @@ -12,8 +12,12 @@ "platform": "ultimaker2_platform.obj", "platform_texture": "Ultimaker2Plusbackplate.png", "preferred_variant": "ultimaker2_plus_0.4", - "preferred_material": "pla", - "preferred_quality": "high" + "preferred_material": "generic_pla_ultimaker2_plus_0.4mm", + "preferred_quality": "pla_0.4_normal", + "has_variants": true, + "has_materials": true, + "has_machine_materials": true, + "has_machine_quality": true }, "overrides": { From 48c8e7a1897961cd504edd510931e19cd4fc3478 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:09:14 +0200 Subject: [PATCH 051/304] Update generic PLA profile Contributes to CURA-1612 --- .../materials/generic_pla.xml.fdm_material | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/resources/materials/generic_pla.xml.fdm_material b/resources/materials/generic_pla.xml.fdm_material index a4fe02c195..40432d5849 100644 --- a/resources/materials/generic_pla.xml.fdm_material +++ b/resources/materials/generic_pla.xml.fdm_material @@ -11,7 +11,7 @@ Generic PLA profile. Serves as an example file, data in this file is not correct 506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9 0 - #FFFFFF + #00FF00 1.3 @@ -20,28 +20,15 @@ Generic PLA profile. Serves as an example file, data in this file is not correct 210 60 - 175 - 150 - - - - - - - - - 150 - - 80 - - - 100 - + + + + From 5ce9bc64f4ec9145d53d481a3f0f1f8638f79032 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:09:38 +0200 Subject: [PATCH 052/304] Remove non-xml material profiles Contributes to CURA-1612 --- resources/materials/abs.inst.cfg | 12 ------------ resources/materials/cpe.inst.cfg | 11 ----------- resources/materials/pla.inst.cfg | 10 ---------- 3 files changed, 33 deletions(-) delete mode 100644 resources/materials/abs.inst.cfg delete mode 100644 resources/materials/cpe.inst.cfg delete mode 100644 resources/materials/pla.inst.cfg diff --git a/resources/materials/abs.inst.cfg b/resources/materials/abs.inst.cfg deleted file mode 100644 index 0d64e81437..0000000000 --- a/resources/materials/abs.inst.cfg +++ /dev/null @@ -1,12 +0,0 @@ -[general] -version = 2 -name = ABS -definition = fdmprinter - -[metadata] -type = material - -[values] -material_print_temperature = 250 -material_bed_temperature = 80 -material_flow = 107 diff --git a/resources/materials/cpe.inst.cfg b/resources/materials/cpe.inst.cfg deleted file mode 100644 index ca30cba046..0000000000 --- a/resources/materials/cpe.inst.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[general] -version = 2 -name = CPE -definition = fdmprinter - -[metadata] -type = material - -[values] -material_print_temperature = 250 -material_bed_temperature = 70 \ No newline at end of file diff --git a/resources/materials/pla.inst.cfg b/resources/materials/pla.inst.cfg deleted file mode 100644 index dfa9c62469..0000000000 --- a/resources/materials/pla.inst.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[general] -version = 2 -name = PLA -definition = fdmprinter - -[metadata] -type = material - -[values] -material_bed_temperature = 60 From 7f7b56ff08988058ea1ba28b4496f5c2310fef0a Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 08:10:32 +0200 Subject: [PATCH 053/304] Add additional quality profiles Low quality and machine-specific qualities for UM2+ Contributes to CURA-1612 --- resources/quality/low.inst.cfg | 10 +++++++++ .../ultimaker2_plus/pla_0.25_normal.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.4_fast.inst.cfg | 20 ++++++++++++++++++ .../ultimaker2_plus/pla_0.4_high.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.4_normal.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.4_ulti.inst.cfg | 21 +++++++++++++++++++ .../ultimaker2_plus/pla_0.6_normal.inst.cfg | 18 ++++++++++++++++ .../ultimaker2_plus/pla_0.8_normal.inst.cfg | 18 ++++++++++++++++ 8 files changed, 141 insertions(+) create mode 100644 resources/quality/low.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg new file mode 100644 index 0000000000..d684bd81b9 --- /dev/null +++ b/resources/quality/low.inst.cfg @@ -0,0 +1,10 @@ +[general] +version = 2 +name = Low Quality +definition = fdmprinter + +[metadata] +type = quality + +[values] +layer_height = 0.15 diff --git a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg new file mode 100644 index 0000000000..9a44582610 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.25_mm +weight = -2 + +[values] +layer_height = 0.06 +wall_thickness = 0.88 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 30 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg new file mode 100644 index 0000000000..be1e1ce992 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -0,0 +1,20 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.4_mm +weight = -1 + +[values] +layer_height = 0.15 +wall_thickness = 0.7 +top_bottom_thickness = 0.75 +infill_sparse_density = 18 +speed_print = 60 +speed_travel = 150 +speed_layer_0 = 30 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg new file mode 100644 index 0000000000..b058d17fbd --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.4_mm +weight = -3 + +[values] +layer_height = 0.06 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg new file mode 100644 index 0000000000..78ee8cf566 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_plus_0.4_mm +weight = -2 + +[values] +layer_height = 0.1 +wall_thickness = 1.05 +top_bottom_thickness = 0.8 +infill_sparse_density = 20 +speed_print = 50 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg new file mode 100644 index 0000000000..db091d8e8d --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 1 +name = Ulti Quality +machine_type = ultimaker2plus +machine_variant = 0.4 mm +material = PLA +weight = -4 + +[settings] +line_width = 0.35 +layer_height = 0.04 +layer_height_0 = 0.26 +wall_thickness = 1.4 +top_bottom_thickness = 1.12 +infill_sparse_density = 25 +speed_print = 30 +speed_infill = 50 +speed_wall_x = 40 +speed_topbottom = 20 +speed_layer_0 = 25 +cool_min_layer_time_fan_speed_max = 15 diff --git a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg new file mode 100644 index 0000000000..f8f966e25a --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +material = generic_pla_ultimaker2_plus_0.6_mm +type = quality +weight = -2 + +[values] +layer_height = 0.15 +wall_thickness = 1.59 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 55 +cool_min_layer_time = 5 +cool_min_speed = 10 diff --git a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg new file mode 100644 index 0000000000..ec53d15867 --- /dev/null +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -0,0 +1,18 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +material = generic_pla_ultimaker2_plus_0.8_mm +type = quality +weight = -2 + +[values] +layer_height = 0.2 +wall_thickness = 2.1 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 5 +cool_min_speed = 10 From 72bc68f38ac8209170d1d60693fe8fab7c2f74a1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 15:16:39 +0200 Subject: [PATCH 054/304] Use self._definition instead of local definition parameter This is supposedly more defensive coding. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 5f74bd036f..b8783026f1 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -17,10 +17,10 @@ class Extruder: container_registry = UM.Settings.ContainerRegistry.getInstance() #Find the nozzles that fit on this extruder. - self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + definition.getId()) - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId() + ",*") - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = definition.getId()) + self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId()) + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId() + ",*") + self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. self._container_stack = UM.Settings.ContainerStack(self._uniqueName(self._definition.getId())) From 7993775feb6887874dd5947160760101955883d7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 16:33:24 +0200 Subject: [PATCH 055/304] Make profiles only load if the extruder says it has them For instance, only load materials if has_materials is True. Contributes to issues CURA-351 and CURA-1278. --- cura/Extruder.py | 60 ++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index b8783026f1..d0c5478270 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -29,39 +29,45 @@ class Extruder: #Find the nozzle to use for this extruder. self._nozzle = container_registry.getEmptyInstanceContainer() - if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid. - self._nozzle = self._nozzles[0] - preferred_nozzle_id = self._definition.getMetaDataEntry("preferred_nozzle") - if preferred_nozzle_id: - for nozzle in self._nozzles: - if nozzle.getId() == preferred_nozzle_id: - self._nozzle = nozzle - break - self._container_stack.addContainer(self._nozzle) + if self._definition.getMetaDataEntry("has_nozzles", default = "False") == "True": + if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid. + self._nozzle = self._nozzles[0] + preferred_nozzle_id = self._definition.getMetaDataEntry("preferred_nozzle") + if preferred_nozzle_id: + for nozzle in self._nozzles: + if nozzle.getId() == preferred_nozzle_id: + self._nozzle = nozzle + break + self._container_stack.addContainer(self._nozzle) #Find a material to use for this nozzle. self._material = container_registry.getEmptyInstanceContainer() - all_materials = container_registry.findInstanceContainers(type = "material") - if len(all_materials) >= 1: - self._material = all_materials[0] - preferred_material_id = self._definition.getMetaDataEntry("preferred_material") - if preferred_material_id: - preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower()) - if len(preferred_material) >= 1: - self._material = preferred_material[0] - self._container_stack.addContainer(self._material) + if self._definition.getMetaDataEntry("has_materials", default = "False") == "True": + if self._definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True": + all_materials = container_registry.findInstanceContainers(type = "material", nozzle = self._nozzle.getId()) + else: + all_materials = container_registry.findInstanceContainers(type = "material") + if len(all_materials) >= 1: + self._material = all_materials[0] + preferred_material_id = self._definition.getMetaDataEntry("preferred_material") + if preferred_material_id: + preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower()) + if len(preferred_material) >= 1: + self._material = preferred_material[0] + self._container_stack.addContainer(self._material) #Find a quality to use for this extruder. self._quality = container_registry.getEmptyInstanceContainer() - all_qualities = container_registry.findInstanceContainers(type = "quality") - if len(all_qualities) >= 1: - self._quality = all_qualities[0] - preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality") - if preferred_quality_id: - preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower()) - if len(preferred_quality) >= 1: - self._quality = preferred_quality[0] - self._container_stack.addContainer(self._quality) + if self._definition.getMetaDataEntry("has_machine_quality"): + all_qualities = container_registry.findInstanceContainers(type = "quality") + if len(all_qualities) >= 1: + self._quality = all_qualities[0] + preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality") + if preferred_quality_id: + preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower()) + if len(preferred_quality) >= 1: + self._quality = preferred_quality[0] + self._container_stack.addContainer(self._quality) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) From 9772d95984e4d52261de5dd6df18488abe363521 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 1 Jun 2016 16:47:52 +0200 Subject: [PATCH 056/304] Add user profile to extruder stack This profile is empty to start with. The user can fill it. Contributes to issues CURA-351 and CURA-1278. --- cura/Extruder.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index d0c5478270..c51f3106a2 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -23,7 +23,8 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - self._container_stack = UM.Settings.ContainerStack(self._uniqueName(self._definition.getId())) + name = self._uniqueName(self._definition.getId()) + self._container_stack = UM.Settings.ContainerStack(name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -69,6 +70,11 @@ class Extruder: self._quality = preferred_quality[0] self._container_stack.addContainer(self._quality) + #Add an empty user profile. + self._user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + self._user_profile.addMetaDataEntry("type", "user") + self._container_stack.addContainer(self._user_profile) + self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) ## Finds a unique name for an extruder stack. From 1603bb3075d0bd90d3f11cef1587709d8fa0a46f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 10:55:03 +0200 Subject: [PATCH 057/304] Give access to nozzle, material and quality profiles You can now swap them out in the extruder model. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index c51f3106a2..5be05c713c 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -4,8 +4,10 @@ import re #To parse container registry names to increment the duplicates-resolving number. import UM.Application #To link the stack to the global container stack. +import UM.Logger import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. import UM.Settings.ContainerStack #To create a container stack for this extruder. +import UM.Signal #To notify people of changing extruder stacks. class Extruder: ## Creates a new extruder from the specified definition container. @@ -77,6 +79,73 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + nozzle_changed = UM.Signal.Signal() + material_changed = UM.Signal.Signal() + quality_changed = UM.Signal.Signal() + + ## Gets the currently active material on this extruder. + # + # \return The currently active material on this extruder. + @property + def material(self): + return self._material + + ## Changes the currently active material in this extruder. + # + # \param value The new material to extrude through this extruder. + @material.setter + def material(self, value): + try: + position = self._container_stack.index(self._material) + except ValueError: #Material is not in the list. + UM.Logger.log("e", "I've lost my old material, so I can't find where to insert the new material.") + return + self._container_stack.replaceContainer(position, value) + self._material = value + self.material_changed.emit() + + ## Gets the currently active nozzle on this extruder. + # + # \return The currently active nozzle on this extruder. + @property + def nozzle(self): + return self._nozzle + + ## Changes the currently active nozzle on this extruder. + # + # \param value The new nozzle to use with this extruder. + @nozzle.setter + def nozzle(self, value): + try: + position = self._container_stack.index(self._nozzle) + except ValueError: #Nozzle is not in the list. + UM.Logger.log("e", "I've lost my old nozzle, so I can't find where to insert the new nozzle.") + return + self._container_stack.replaceContainer(position, value) + self._nozzle = value + self.nozzle_changed.emit() + + ## Gets the currently active quality on this extruder. + # + # \return The currently active quality on this extruder. + @property + def quality(self): + return self._quality + + ## Changes the currently active quality to use with this extruder. + # + # \param value The new quality to use with this extruder. + @quality.setter + def quality(self, value): + try: + position = self._container_stack.index(self._quality) + except ValueError: #Quality is not in the list. + UM.Logger.log("e", "I've lost my old quality, so I can't find where to insert the new quality.") + return + self._container_stack.replaceContainer(position, value) + self._quality = value + self.quality_changed.emit() + ## Finds a unique name for an extruder stack. # # \param extruder An extruder definition to design a name for. From e03f65c47158474d48e1d5643433baf4e3828524 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 11:12:37 +0200 Subject: [PATCH 058/304] Remove stray debug print CURA-1278 --- resources/qml/SidebarSimple.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml index c95cb54b1f..80870ac29f 100644 --- a/resources/qml/SidebarSimple.qml +++ b/resources/qml/SidebarSimple.qml @@ -371,8 +371,6 @@ Item key: "infill_sparse_density" watchedProperties: [ "value" ] storeIndex: 0 - - onPropertiesChanged: console.log(properties.value) } UM.SettingPropertyProvider From c369202957e4e5c10fe7b1a889a5e704ffbab337 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:08:22 +0200 Subject: [PATCH 059/304] Fix unknown variable Was probably a copy-paste mistake here. Fixed it for him. Contributes to issue CURA-1278. --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 83b8e87859..c3b57ca8d0 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -312,8 +312,8 @@ class MachineManagerModel(QObject): def _getPreferredContainer(self, definition, property_name, default_container): preferred_id = definition.getMetaDataEntry(property_name) if preferred_id: - preferred_variant_id = preferred_variant_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_variant_id) + preferred_id = preferred_id.lower() + container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_id) if container: return container[0] From 73f12ffd99e0b4c7fba37dd845f36928d2d884e4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:15:52 +0200 Subject: [PATCH 060/304] Incorporate switching of global extruder stack When the global extruder stack switches, we need to re-connect the reloading of extruders to the new containersChanged signal of the new global container stack. This now also bootstraps the listening for the first time, when the global container stack changes from None to the first stack. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 4d95a9008d..71b636ad6f 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -19,9 +19,17 @@ class ExtruderManager: ## Registers listeners and such to listen to changes to the extruders. def __init__(self): self._extruders = [] #Extruders for the current machine. + self._global_container_stack = None - Application.getInstance().getGlobalContainerStack().containersChanged.connect(self._reloadExtruders) #When the current machine changes, we need to reload all extruders belonging to the new machine. - self._reloadExtruders() + Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. + + ## When the global container stack changes, this reconnects to the new + # signal for containers changing. + 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.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. # @@ -30,12 +38,11 @@ class ExtruderManager: # list of extruders. def _reloadExtruders(self): self._extruders = [] - global_container_stack = Application.getInstance().getGlobalContainerStack() - if not global_container_stack: #No machine has been added yet. + if not self._global_container_stack: #No machine has been added yet. return #Then leave them empty! #Get the extruder definitions belonging to the current machine. - machine = global_container_stack.getBottom() + 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. From 95e633f16cf1746b97405d63ae86e63959ac241f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 11:17:39 +0200 Subject: [PATCH 061/304] Load extruder manager on start-up This will consequently also load all extruder stacks of the current machine whenever the current machine changes. 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 d7e5768116..49fcbbf405 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -30,6 +30,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog +from . import ExtruderManager from . import PlatformPhysics from . import BuildVolume from . import CameraAnimation @@ -326,6 +327,8 @@ 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() From 5873f1d4d09206261f27bb12c6527a7fa9aeb123 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 11:22:39 +0200 Subject: [PATCH 062/304] Limit layer processing to 99% to indicate more stuff needs to happen Fixes CURA-1644 --- plugins/CuraEngineBackend/ProcessSlicedLayersJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index d3053f9175..77a42f6b3e 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -96,7 +96,7 @@ class ProcessSlicedLayersJob(Job): Job.yieldThread() Job.yieldThread() current_layer += 1 - progress = (current_layer / layer_count) * 100 + progress = (current_layer / layer_count) * 99 # TODO: Rebuild the layer data mesh once the layer has been processed. # This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh. From 070e791b94dcc9197e7a865d4e055b0dd26b1635 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 11:23:18 +0200 Subject: [PATCH 063/304] Add a preference to change LayerView top layers between 1 and 5 Fixes CURA-1643 --- plugins/LayerView/LayerView.py | 16 +++++++++++++++- resources/qml/ViewPage.qml | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/plugins/LayerView/LayerView.py b/plugins/LayerView/LayerView.py index 27bb7f022c..b5f152e825 100644 --- a/plugins/LayerView/LayerView.py +++ b/plugins/LayerView/LayerView.py @@ -12,6 +12,7 @@ from UM.Math.Color import Color from UM.Mesh.MeshData import MeshData from UM.Job import Job from UM.Message import Message +from UM.Preferences import Preferences from UM.View.RenderBatch import RenderBatch from UM.View.GL.OpenGL import OpenGL @@ -44,7 +45,10 @@ class LayerView(View): self._top_layers_job = None self._activity = False - self._solid_layers = 1 + Preferences.getInstance().addPreference("view/top_layer_count", 1) + Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) + + self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count")) self._top_layer_timer = QTimer() self._top_layer_timer.setInterval(50) @@ -212,6 +216,16 @@ class LayerView(View): self._top_layers_job = None + def _onPreferencesChanged(self, preference): + if preference != "view/top_layer_count": + return + + self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count")) + + self._current_layer_mesh = None + self._current_layer_jumps = None + self._top_layer_timer.start() + class _CreateTopLayersJob(Job): def __init__(self, scene, layer_number, solid_layers): super().__init__() diff --git a/resources/qml/ViewPage.qml b/resources/qml/ViewPage.qml index ee0c74904a..3860f8f304 100644 --- a/resources/qml/ViewPage.qml +++ b/resources/qml/ViewPage.qml @@ -19,6 +19,7 @@ UM.PreferencesPage { UM.Preferences.resetPreference("view/show_overhang"); UM.Preferences.resetPreference("view/center_on_select"); + UM.Preferences.resetPreference("view/top_layer_count"); } Column @@ -57,12 +58,38 @@ UM.PreferencesPage } } + UM.TooltipArea { + width: childrenRect.width; + height: childrenRect.height; + text: catalog.i18nc("@info:tooltip","Displays") + + CheckBox + { + id: topLayerCheckbox + text: catalog.i18nc("@action:button","Display five top layers in layer view."); + checked: UM.Preferences.getValue("view/top_layer_count") == 5 + onClicked: + { + if(UM.Preferences.getValue("view/top_layer_count") == 5) + { + UM.Preferences.setValue("view/top_layer_count", 1) + } + else + { + UM.Preferences.setValue("view/top_layer_count", 5) + } + } + } + } + Connections { target: UM.Preferences onPreferenceChanged: { overhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang")) centerCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select")) + topLayerCheckbox = UM.Preferences.getValue("view/top_layer_count") == 5 + } } } From 02b8fa90437d5aac8875ce52145344affa8d7dec Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 12:46:01 +0200 Subject: [PATCH 064/304] Add missing tooltip CURA-1643 --- resources/qml/ViewPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/ViewPage.qml b/resources/qml/ViewPage.qml index 3860f8f304..1763325e18 100644 --- a/resources/qml/ViewPage.qml +++ b/resources/qml/ViewPage.qml @@ -61,7 +61,7 @@ UM.PreferencesPage UM.TooltipArea { width: childrenRect.width; height: childrenRect.height; - text: catalog.i18nc("@info:tooltip","Displays") + text: catalog.i18nc("@info:tooltip","Display 5 top layers in layer view or only the top-most layer. Rendering 5 layers takes longer, but may show more information.") CheckBox { From 14a8b8a1a40ea3e889fb2a1715f4637eb3e10fa1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 13:30:26 +0200 Subject: [PATCH 065/304] Fix showing formatted tooltip when exiting reset-value-icon CURA-1278 --- resources/qml/Settings/SettingItem.qml | 65 ++++++++++++++------------ 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 4c14ee4039..aa4ef5be85 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -22,6 +22,38 @@ Item { signal showTooltip(string text); signal hideTooltip(); + property string tooltipText: + { + var affects = settingDefinitionsModel.getRequiredBy(definition.key, "value") + var affected_by = settingDefinitionsModel.getRequires(definition.key, "value") + + var affected_by_list = "" + for(var i in affected_by) + { + affected_by_list += "
  • %1
  • \n".arg(affected_by[i].label) + } + + var affects_list = "" + for(var i in affects) + { + affects_list += "
  • %1
  • \n".arg(affects[i].label) + } + + var tooltip = "%1\n

    %2

    ".arg(definition.label).arg(definition.description) + + if(affects_list != "") + { + tooltip += "
    %1\n
      \n%2
    ".arg(catalog.i18nc("@label", "Affects")).arg(affects_list) + } + + if(affected_by_list != "") + { + tooltip += "
    %1\n
      \n%2
    ".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list) + } + + return tooltip + } + MouseArea { id: mouse; @@ -52,34 +84,7 @@ Item { onTriggered: { - var affects = settingDefinitionsModel.getRequiredBy(definition.key, "value") - var affected_by = settingDefinitionsModel.getRequires(definition.key, "value") - - var affected_by_list = "" - for(var i in affected_by) - { - affected_by_list += "
  • %1
  • \n".arg(affected_by[i].label) - } - - var affects_list = "" - for(var i in affects) - { - affects_list += "
  • %1
  • \n".arg(affects[i].label) - } - - var tooltip = "%1
    \n

    %2

    ".arg(definition.label).arg(definition.description) - - if(affects_list != "") - { - tooltip += "
    %1
    \n
      \n%2
    ".arg(catalog.i18nc("@label", "Affects")).arg(affects_list) - } - - if(affected_by_list != "") - { - tooltip += "
    %1
    \n
      \n%2
    ".arg(catalog.i18nc("@label", "Affected By")).arg(affected_by_list) - } - - base.showTooltip(tooltip); + base.showTooltip(base.tooltipText); } } @@ -137,7 +142,7 @@ Item { } onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) } - onExited: base.showTooltip(definition.description); + onExited: base.showTooltip(base.tooltipText); } UM.SimpleButton @@ -164,7 +169,7 @@ Item { iconSource: UM.Theme.getIcon("notice"); onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) } - onExited: base.showTooltip(definition.description); + onExited: base.showTooltip(base.tooltipText); } } From 1af6e63b35f8483bac5674ae7315bed1dcf867e2 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 13:41:46 +0200 Subject: [PATCH 066/304] 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 067/304] 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 068/304] 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 069/304] 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 070/304] 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 071/304] 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 072/304] 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 073/304] 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 074/304] 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 075/304] 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 076/304] 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 077/304] 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 078/304] 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 079/304] 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 080/304] 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 081/304] 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 6257fe41d531d46476c207689b2a1375bf5fb192 Mon Sep 17 00:00:00 2001 From: Aldo Hoeben Date: Thu, 2 Jun 2016 14:50:02 +0200 Subject: [PATCH 082/304] Remove unsanctioned PLA profile --- .../ultimaker2+/pla_0.4_ulti.curaprofile | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile diff --git a/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile deleted file mode 100644 index 5cb807de01..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile +++ /dev/null @@ -1,23 +0,0 @@ -[general] -version = 1 -name = Ulti Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -4 - -[settings] -line_width = 0.35 -layer_height = 0.04 -layer_height_0 = 0.26 -wall_thickness = 1.4 -top_bottom_thickness = 1.12 -infill_sparse_density = 25 -retraction_amount = 5.5 -retraction_extrusion_window = 6 -speed_print = 30 -speed_infill = 50 -speed_wall_x = 40 -speed_topbottom = 20 -speed_layer_0 = 25 -cool_min_layer_time_fan_speed_max = 15 From 64e4cd0041127f1c31eb28d356dd98f8a348264d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 15:52:25 +0200 Subject: [PATCH 083/304] 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 084/304] 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 085/304] 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 086/304] 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 087/304] 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 088/304] 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 089/304] 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 090/304] 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 091/304] 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 092/304] 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. From bb18bf6a30914e7127d7e40a4dbf3baa5baf1d3e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 16:38:06 +0200 Subject: [PATCH 093/304] Fix creating a jobname after loading a file Moves jobname creation out of qml and into python. CURA-1619 --- cura/CuraApplication.py | 15 ------- cura/PrintInformation.py | 56 ++++++++++++++++++++++-- resources/qml/Cura.qml | 4 +- resources/qml/JobSpecs.qml | 85 ++++++++++-------------------------- resources/qml/SaveButton.qml | 2 +- 5 files changed, 79 insertions(+), 83 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 49fcbbf405..3e3ab28010 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -436,21 +436,6 @@ class CuraApplication(QtApplication): self._platform_activity = True if count > 0 else False self.activityChanged.emit() - @pyqtSlot(str) - def setJobName(self, name): - # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its - # extension. This cuts the extension off if necessary. - name = os.path.splitext(name)[0] - if self._job_name != name: - self._job_name = name - self.jobNameChanged.emit() - - jobNameChanged = pyqtSignal() - - @pyqtProperty(str, notify = jobNameChanged) - def jobName(self): - return self._job_name - # Remove all selected objects from the scene. @pyqtSlot() def deleteSelection(self): diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 2663cab5a0..dd15d7a264 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -1,14 +1,17 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty +from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot from UM.Application import Application from UM.Qt.Duration import Duration +from UM.Preferences import Preferences import math +import os.path +import unicodedata -## A class for processing and calculating minimum, current and maximum print time. +## A class for processing and calculating minimum, current and maximum print time as well as managing the job name # # This class contains all the logic relating to calculation and slicing for the # time/quality slider concept. It is a rather tricky combination of event handling @@ -22,6 +25,8 @@ import math # - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass". # - When the high quality pass is done, we update the maximum print time. # +# This class also mangles the current machine name and the filename of the first loaded mesh into a job name. +# This job name is requested by the JobSpecs qml file. class PrintInformation(QObject): class SlicePass: CurrentSettings = 1 @@ -45,14 +50,17 @@ class PrintInformation(QObject): if self._backend: self._backend.printDurationMessage.connect(self._onPrintDurationMessage) + self._job_name = "" + Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + currentPrintTimeChanged = pyqtSignal() - + @pyqtProperty(Duration, notify = currentPrintTimeChanged) def currentPrintTime(self): return self._current_print_time materialAmountChanged = pyqtSignal() - + @pyqtProperty(float, notify = materialAmountChanged) def materialAmount(self): return self._material_amount @@ -66,3 +74,43 @@ class PrintInformation(QObject): r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2) self.materialAmountChanged.emit() + + @pyqtSlot(str) + def setJobName(self, name): + # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its + # extension. This cuts the extension off if necessary. + name = os.path.splitext(name)[0] + if self._job_name != name: + self._job_name = name + self.jobNameChanged.emit() + + jobNameChanged = pyqtSignal() + + @pyqtProperty(str, notify = jobNameChanged) + def jobName(self): + return self._job_name + + @pyqtSlot(str, result = str) + def createJobName(self, base_name): + base_name = self._stripAccents(base_name) + if Preferences.getInstance().getValue("cura/jobname_prefix"): + return self._abbr_machine + "_" + base_name + else: + return base_name + + def _onGlobalStackChanged(self): + global_stack_name = Application.getInstance().getGlobalContainerStack().getName() + split_name = global_stack_name.split(" ") + abbr_machine = "" + for word in split_name: + if(word.lower() == "ultimaker"): + abbr_machine += "UM" + elif word.isdigit(): + abbr_machine += word + else: + abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0] + + self._abbr_machine = abbr_machine + + def _stripAccents(self, str): + return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn') \ No newline at end of file diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 32e1e79029..cf99b39864 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -93,7 +93,7 @@ UM.MainWindow text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File"); enabled: UM.Selection.hasSelection; iconName: "document-save-as"; - onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName, { "filter_by_machine": false }); + onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false }); } Menu { @@ -109,7 +109,7 @@ UM.MainWindow MenuItem { text: model.description; - onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, Printer.jobName, { "filter_by_machine": false }); + onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, PrintInformation.jobName, { "filter_by_machine": false }); } onObjectAdded: saveAllMenu.insertItem(index, object) onObjectRemoved: saveAllMenu.removeItem(object) diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index 9551e3bcf5..e73bf145de 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -10,62 +10,25 @@ import UM 1.1 as UM import Cura 1.0 as Cura Rectangle { - id: base; + id: base - property bool activity: Printer.getPlatformActivity; + property bool activity: Printer.getPlatformActivity property string fileBaseName property variant activeMachineName: Cura.MachineManager.activeMachineName onActiveMachineNameChanged: { - base.createFileName() + printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName); } UM.I18nCatalog { id: catalog; name:"cura"} - property variant printDuration: PrintInformation.currentPrintTime; - property real printMaterialAmount: PrintInformation.materialAmount; + property variant printDuration: PrintInformation.currentPrintTime + property real printMaterialAmount: PrintInformation.materialAmount height: childrenRect.height color: "transparent" - function createFileName() - { - var splitMachineName = Cura.MachineManager.activeMachineName.split(" ") - var abbrMachine = ""; - if ((UM.Preferences.getValue("cura/jobname_prefix"))) - { - for (var i = 0; i < splitMachineName.length; i++) - { - if (splitMachineName[i].search(/ultimaker/i) != -1) - { - abbrMachine += "UM"; - } - else - { - if (splitMachineName[i].charAt(0).search(/[0-9]/g) == -1) - { - abbrMachine += splitMachineName[i].charAt(0); - } - } - } - var regExpAdditives = /[0-9\+]/g; - var resultAdditives = splitMachineName[i].match(regExpAdditives); - if (resultAdditives != null) - { - for (var j = 0; j < resultAdditives.length; j++) - { - abbrMachine += resultAdditives[j]; - } - } - printJobTextfield.text = abbrMachine + "_" + base.fileBaseName; - } - else - { - printJobTextfield.text = base.fileBaseName; - } - } - Connections { target: backgroundItem @@ -78,20 +41,20 @@ Rectangle { onActivityChanged: { if (activity == true && base.fileBaseName == ''){ //this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows) - base.fileBaseName = Printer.jobName //it gets the fileBaseName from CuraApplication.py because this saves the filebase when the file is opened using the terminal (or something alike) - base.createFileName() + base.fileBaseName = PrintInformation.jobName; //get the fileBaseName from PrintInformation.py because this saves the filebase when the file is opened using the terminal (or something alike) + printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName); } if (activity == true && base.fileBaseName != ''){ //this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal - base.createFileName() + printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName); } if (activity == false){ //When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file) - printJobTextfield.text = '' + printJobTextfield.text = ''; } } - Rectangle + Rectangle { id: jobNameRow anchors.top: parent.top @@ -112,22 +75,22 @@ Rectangle { width: UM.Theme.getSize("save_button_specs_icons").width height: UM.Theme.getSize("save_button_specs_icons").height - onClicked: + onClicked: { - printJobTextfield.selectAll() - printJobTextfield.focus = true + printJobTextfield.selectAll(); + printJobTextfield.focus = true; } style: ButtonStyle { background: Rectangle { color: "transparent" - UM.RecolorImage + UM.RecolorImage { - width: UM.Theme.getSize("save_button_specs_icons").width - height: UM.Theme.getSize("save_button_specs_icons").height - sourceSize.width: width - sourceSize.height: width + width: UM.Theme.getSize("save_button_specs_icons").width; + height: UM.Theme.getSize("save_button_specs_icons").height; + sourceSize.width: width; + sourceSize.height: width; color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text"); source: UM.Theme.getIcon("pencil"); } @@ -147,15 +110,15 @@ Rectangle { text: '' horizontalAlignment: TextInput.AlignRight onTextChanged: { - Printer.setJobName(text) + PrintInformation.setJobName(text); } onEditingFinished: { if (printJobTextfield.text != ''){ - printJobTextfield.focus = false + printJobTextfield.focus = false; } } validator: RegExpValidator { - regExp: /^[^\\ \/ \.]*$/ + regExp: /^[^\\ \/ \*\?\|\[\]]*$/ } style: TextFieldStyle{ textColor: UM.Theme.getColor("setting_control_text"); @@ -200,7 +163,7 @@ Rectangle { sourceSize.width: width sourceSize.height: width color: UM.Theme.getColor("text_subtext") - source: UM.Theme.getIcon("print_time"); + source: UM.Theme.getIcon("print_time") } Label{ id: timeSpec @@ -221,7 +184,7 @@ Rectangle { sourceSize.width: width sourceSize.height: width color: UM.Theme.getColor("text_subtext") - source: UM.Theme.getIcon("category_material"); + source: UM.Theme.getIcon("category_material") } Label{ id: lengthSpec @@ -229,7 +192,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter font: UM.Theme.getFont("small") color: UM.Theme.getColor("text_subtext") - text: base.printMaterialAmount <= 0 ? catalog.i18nc("@label", "0.0 m") : catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount) + text: catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount > 0 ? base.printMaterialAmount : 0) } } } diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml index 1307e8f820..8b95de15ee 100644 --- a/resources/qml/SaveButton.qml +++ b/resources/qml/SaveButton.qml @@ -98,7 +98,7 @@ Rectangle { text: UM.OutputDeviceManager.activeDeviceShortDescription onClicked: { - UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, Printer.jobName, { "filter_by_machine": true }) + UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, { "filter_by_machine": true }) } style: ButtonStyle { From 4cd224aeb2ea6f5fbf7523fc16e1c8bbf4ec1927 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 17:19:47 +0200 Subject: [PATCH 094/304] Add empty variant, material and quality containers Since we need these for making container switching work. Contributes to CURA-1612 --- cura/CuraApplication.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 39c3ed924f..dc5eb70394 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -142,6 +142,23 @@ class CuraApplication(QtApplication): ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack) + # Add empty variant, material and quality containers. + # Since they are empty, they should never be serialized and instead just programmatically created. + # We need them to simplify the switching between materials. + empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer() + empty_variant_container = copy.deepcopy(empty_container) + empty_variant_container._id = "empty_variant" + empty_variant_container.addMetaDataEntry("type", "variant") + ContainerRegistry.getInstance().addContainer(empty_variant_container) + empty_material_container = copy.deepcopy(empty_container) + empty_material_container._id = "empty_material" + empty_material_container.addMetaDataEntry("type", "material") + ContainerRegistry.getInstance().addContainer(empty_material_container) + empty_quality_container = copy.deepcopy(empty_container) + empty_quality_container._id = "empty_quality" + empty_quality_container.addMetaDataEntry("type", "quality") + ContainerRegistry.getInstance().addContainer(empty_quality_container) + ContainerRegistry.getInstance().load() Preferences.getInstance().addPreference("cura/active_mode", "simple") From e36397fa29bd5999655502d599b1904512eaa202 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 2 Jun 2016 17:21:18 +0200 Subject: [PATCH 095/304] Use the new empty type-specific containers when adding a new machine Contributes to CURA-1612 --- cura/MachineManagerModel.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c3b57ca8d0..77dfa39d3b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -22,6 +22,10 @@ class MachineManagerModel(QObject): self.globalContainerChanged.connect(self.activeVariantChanged) self.globalContainerChanged.connect(self.activeQualityChanged) + self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_variant")[0] + self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_material")[0] + self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = "empty_quality")[0] + Preferences.getInstance().addPreference("cura/active_machine", "") active_machine_id = Preferences.getInstance().getValue("cura/active_machine") @@ -74,28 +78,26 @@ class MachineManagerModel(QObject): new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) - empty_container = UM.Settings.ContainerRegistry.getInstance().getEmptyInstanceContainer() - - variant_instance_container = empty_container + variant_instance_container = self._empty_variant_container if definition.getMetaDataEntry("has_variants"): - variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", empty_container) + variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", self._empty_variant_container) - if variant_instance_container == empty_container: + if variant_instance_container == self._empty_variant_container: variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) if variants: variant_instance_container = variants[0] - if variant_instance_container == empty_container: + if variant_instance_container == self._empty_variant_container: Logger.log("w", "Machine %s defines it has variants but no variants found", definition.id) - material_instance_container = empty_container + material_instance_container = self._empty_material_container if definition.getMetaDataEntry("has_materials"): - material_instance_container = self._getPreferredContainer(definition, "preferred_material", empty_container) + material_instance_container = self._getPreferredContainer(definition, "preferred_material", self._empty_material_container) - if material_instance_container == empty_container: + if material_instance_container == self._empty_material_container: materials = None if definition.getMetaDataEntry("has_machine_materials"): - if variant_instance_container != empty_container: + if variant_instance_container != self._empty_material_container: materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id, variant = variant_instance_container.id) else: materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) @@ -105,9 +107,11 @@ class MachineManagerModel(QObject): if materials: material_instance_container = materials[0] - quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", empty_container) + if material_instance_container == self._empty_materials_container: + Logger.log("w", "Machine %s defines it has materials but no matererials found", definition.id) - if quality_instance_container == empty_container: + quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", self._empty_quality_container) + if quality_instance_container == self._empty_quality_container: if definition.getMetaDataEntry("has_machine_quality"): if material_instance_container: qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id, material = material_instance_container.id) From 95a0c69662ec6ac7bd68bd2bd16055831297c7ae Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 17:25:34 +0200 Subject: [PATCH 096/304] Bit of code refactoring to prevent duplication CURA-1288 --- plugins/CuraEngineBackend/StartSliceJob.py | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 0851261877..dee6f2b64c 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -51,6 +51,20 @@ class StartSliceJob(Job): def getSliceMessage(self): return self._slice_message + ## Check if a stack has any errors. + ## returns true if it has errors, false otherwise. + def _checkStackForErrors(self, stack): + if stack is None: + return False + + for key in stack.getAllKeys(): + validation_state = stack.getProperty(key, "validationState") + if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): + Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state) + return True + Job.yieldThread() + return False + ## Runs the job that initiates the slicing. def run(self): stack = Application.getInstance().getGlobalContainerStack() @@ -59,30 +73,18 @@ class StartSliceJob(Job): return # 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): - Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state) - self.setResult(StartJobResult.SettingError) - return - - Job.yieldThread() + if self._checkStackForErrors(stack): + self.setResult(StartJobResult.SettingError) + return # 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() + if self._checkStackForErrors(node.callDecoration("getStack")): + self.setResult(StartJobResult.SettingError) + return with self._scene.getSceneLock(): # Remove old layer data. From 11cb9af97f819b362a719ff66ba8e6c7f8ac0464 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 2 Jun 2016 17:32:26 +0200 Subject: [PATCH 097/304] fixed typo --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 77dfa39d3b..4bd42c9c9d 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -107,7 +107,7 @@ class MachineManagerModel(QObject): if materials: material_instance_container = materials[0] - if material_instance_container == self._empty_materials_container: + if material_instance_container == self._empty_material_container: Logger.log("w", "Machine %s defines it has materials but no matererials found", definition.id) quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", self._empty_quality_container) From 0dec0aafcfbff6091d1e3a92908d9699b5ff11b7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Jun 2016 17:44:06 +0200 Subject: [PATCH 098/304] Fix exception when loading an object CURA-1619 --- cura/CuraApplication.py | 6 ++++-- cura/PrintInformation.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 39c3ed924f..3c4d776df8 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -706,16 +706,18 @@ class CuraApplication(QtApplication): def _onActiveMachineChanged(self): pass + fileLoaded = pyqtSignal() + def _onFileLoaded(self, job): node = job.getResult() if node != None: - self.setJobName(os.path.basename(job.getFileName())) + self.fileLoaded.emit(job.getFileName()) node.setSelectable(True) node.setName(os.path.basename(job.getFileName())) op = AddSceneNodeOperation(node, self.getController().getScene().getRoot()) op.push() - self.getController().getScene().sceneChanged.emit(node) #F orce scene change. + self.getController().getScene().sceneChanged.emit(node) #Force scene change. def _onJobFinished(self, job): if type(job) is not ReadMeshJob or not job.getResult(): diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index dd15d7a264..22bc562502 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -52,6 +52,7 @@ class PrintInformation(QObject): self._job_name = "" Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() From ad35c9f070a6321f5328c92390fd7baef93fe566 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 10:06:08 +0200 Subject: [PATCH 099/304] Added reload profile (simply clears user instance container) CURA-1278 --- cura/MachineManagerModel.py | 22 ++++++++++++++++++++++ resources/qml/Actions.qml | 5 +++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 4bd42c9c9d..d34e392720 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -41,9 +41,15 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() + globalPropertyChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. + + def _onGlobalPropertyChanged(self, key, property_name): + self.globalPropertyChanged.emit() + 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() self.globalContainerChanged.emit() @@ -51,6 +57,7 @@ class MachineManagerModel(QObject): 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) def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") @@ -160,6 +167,21 @@ class MachineManagerModel(QObject): return unique_name + @pyqtSlot() + def clearUserSettings(self): + if not self._global_container_stack: + return + user_settings = self._global_container_stack.getTop() + user_settings.clear() + + @pyqtProperty(bool, notify = globalPropertyChanged) + def hasUserSettings(self): + if not self._global_container_stack: + return + + user_settings = self._global_container_stack.getTop().findInstances(**{}) + return len(user_settings) != 0 + @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): if self._global_container_stack: diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index f3bce7b993..6dd851c3d5 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -6,6 +6,7 @@ pragma Singleton import QtQuick 2.2 import QtQuick.Controls 1.1 import UM 1.1 as UM +import Cura 1.0 as Cura Item { @@ -117,9 +118,9 @@ Item Action { id: resetProfileAction; - enabled: UM.ActiveProfile.valid && UM.ActiveProfile.hasCustomisedValues + enabled: Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:inmenu menubar:profile","&Reload Current Profile"); - onTriggered: UM.ActiveProfile.discardChanges(); + onTriggered: Cura.MachineManager.clearUserSettings(); } Action From 171adde6be95a11d751c892f565a732da42152b5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 10:15:01 +0200 Subject: [PATCH 100/304] Fixed broken signal when file was loaded --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 41dec309d9..d22fed73ce 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -723,7 +723,7 @@ class CuraApplication(QtApplication): def _onActiveMachineChanged(self): pass - fileLoaded = pyqtSignal() + fileLoaded = pyqtSignal(str) def _onFileLoaded(self, job): node = job.getResult() From 113da81db527773f32746bd84fd29e6103e8f7d3 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 10:29:19 +0200 Subject: [PATCH 101/304] Added isValidGlobalStack property to MachineManager CURA-1585 --- cura/MachineManagerModel.py | 16 ++++++++++++++++ resources/qml/Actions.qml | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index d34e392720..e9b8ba7d55 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -7,6 +7,7 @@ from UM.Preferences import Preferences from UM.Logger import Logger import UM.Settings +from UM.Settings.Validator import ValidatorState class MachineManagerModel(QObject): @@ -167,6 +168,17 @@ class MachineManagerModel(QObject): return unique_name + ## Convenience function to check if a stack has errors. + def _checkStackForErrors(self, stack): + if stack is None: + return False + + for key in stack.getAllKeys(): + validation_state = stack.getProperty(key, "validationState") + if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): + return True + return False + @pyqtSlot() def clearUserSettings(self): if not self._global_container_stack: @@ -182,6 +194,10 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 + @pyqtProperty(bool, notify = globalPropertyChanged) + def isGlobalStackValid(self): + return not self._checkStackForErrors(self._global_container_stack) + @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): if self._global_container_stack: diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 6dd851c3d5..4769b53b05 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -110,7 +110,7 @@ Item Action { id: updateProfileAction; - enabled: UM.ActiveProfile.valid && !UM.ActiveProfile.readOnly && UM.ActiveProfile.hasCustomisedValues + enabled: Cura.MachineManager.isGlobalStackValid && !UM.ActiveProfile.readOnly && Cura.MachineManager.hasUserSettings text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile"); onTriggered: UM.ActiveProfile.updateProfile(); } @@ -126,7 +126,7 @@ Item Action { id: addProfileAction; - enabled: UM.ActiveProfile.valid + enabled: Cura.MachineManager.isGlobalStackValid text: catalog.i18nc("@action:inmenu menubar:profile","&Create New Profile..."); } From 4fc565711d3675fef2c860c38531c8013fe9f39d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 11:19:33 +0200 Subject: [PATCH 102/304] Added read-only property to profiles CURA-1585 --- cura/MachineManagerModel.py | 9 +++++++++ resources/qml/Actions.qml | 2 +- resources/quality/high.inst.cfg | 1 + resources/quality/low.inst.cfg | 1 + resources/quality/normal.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.25_normal.inst.cfg | 1 + resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg | 1 + resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.4_normal.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.6_normal.inst.cfg | 1 + .../quality/ultimaker2_plus/pla_0.8_normal.inst.cfg | 1 + 11 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e9b8ba7d55..5a43f8cbf1 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -246,6 +246,15 @@ class MachineManagerModel(QObject): return quality.getId() return "" + ## Check if a container is read_only + @pyqtSlot(str, result = bool) + def isReadOnly(self, container_id): + 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" + + @pyqtSlot(str) def setActiveMaterial(self, material_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=material_id) diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 4769b53b05..2e89ce043a 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -110,7 +110,7 @@ Item Action { id: updateProfileAction; - enabled: Cura.MachineManager.isGlobalStackValid && !UM.ActiveProfile.readOnly && Cura.MachineManager.hasUserSettings + enabled: Cura.MachineManager.isGlobalStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) text: catalog.i18nc("@action:inmenu menubar:profile","&Update Current Profile"); onTriggered: UM.ActiveProfile.updateProfile(); } diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 0329e9ffe1..546d11326b 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index d684bd81b9..11a0094aca 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +read_only = True [values] layer_height = 0.15 diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg index 6d317cdf7a..b12603f921 100644 --- a/resources/quality/normal.inst.cfg +++ b/resources/quality/normal.inst.cfg @@ -5,5 +5,6 @@ definition = fdmprinter [metadata] type = quality +read_only = True [values] 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 9a44582610..7a1da403ff 100644 --- a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -7,6 +7,7 @@ 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 be1e1ce992..54f180379d 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -7,6 +7,7 @@ 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 b058d17fbd..926bcdcae7 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -7,6 +7,7 @@ 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 78ee8cf566..f65544307e 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -7,6 +7,7 @@ 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 f8f966e25a..906613dc23 100644 --- a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -7,6 +7,7 @@ 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 ec53d15867..5cad44ec9c 100644 --- a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -7,6 +7,7 @@ definition = ultimaker2_plus material = generic_pla_ultimaker2_plus_0.8_mm type = quality weight = -2 +read_only = True [values] layer_height = 0.2 From d29cc37d6bcbca9306a8ecffc73566a90af28ff1 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 11:58:59 +0200 Subject: [PATCH 103/304] Adds way to convert user settings into quality settings CURA-1585 --- cura/MachineManagerModel.py | 32 +++++++++++++++++++++++++++----- resources/qml/Cura.qml | 2 +- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 5a43f8cbf1..130b492ff4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -8,6 +8,7 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState +from UM.Settings.InstanceContainer import InstanceContainer class MachineManagerModel(QObject): @@ -80,7 +81,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._uniqueMachineName(name, definition.getName()) + name = self._createUniqueStackName(name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -150,7 +151,7 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique - def _uniqueMachineName(self, name, fallback_name): + def _createUniqueStackName(self, name, fallback_name): name = name.strip() num_check = re.compile("(.*?)\s*#\d$").match(name) if(num_check): @@ -160,10 +161,10 @@ class MachineManagerModel(QObject): unique_name = name i = 1 - #Check both the id and the name, because they may not be the same and it is better if they are both unique + # Check both the id and the name, because they may not be the same and it is better if they are both unique while UM.Settings.ContainerRegistry.getInstance().findContainers(None, id = unique_name) or \ UM.Settings.ContainerRegistry.getInstance().findContainers(None, name = unique_name): - i = i + 1 + i += 1 unique_name = "%s #%d" % (name, i) return unique_name @@ -254,6 +255,27 @@ class MachineManagerModel(QObject): return True return containers[0].getMetaDataEntry("read_only", False) == "True" + @pyqtSlot() + def convertUserContainerToQuality(self): + if not self._global_container_stack: + return + + name = self._createUniqueStackName("Custom profile", "") + user_settings = self._global_container_stack.getTop() + new_quality_container = InstanceContainer("") + + ## Copy all values + new_quality_container.deserialize(user_settings.serialize()) + + ## Change type / id / name + new_quality_container.setMetaDataEntry("type","quality") + 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 noq a quality, remove them. + self.setActiveQuality(name) + @pyqtSlot(str) def setActiveMaterial(self, material_id): @@ -319,7 +341,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._uniqueMachineName(new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueStackName(new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index cf99b39864..2b7a4ccea7 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -580,7 +580,7 @@ UM.MainWindow target: Cura.Actions.addProfile onTriggered: { - UM.MachineManager.createProfile(); + Cura.MachineManager.convertUserContainerToQuality(); preferences.setPage(5); preferences.show(); From 0dece95f0f0b9c25026f0c00dcf5a03f53e250ed Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:03:56 +0200 Subject: [PATCH 104/304] Updating non-readonly profiles is now possible again CURA-1585 --- cura/MachineManagerModel.py | 10 ++++++++++ resources/qml/Actions.qml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 130b492ff4..b9d6a9d37c 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -276,6 +276,16 @@ class MachineManagerModel(QObject): self.clearUserSettings() # As all users settings are noq a quality, remove them. self.setActiveQuality(name) + @pyqtSlot() + def updateUserContainerToQuality(self): + if not self._global_container_stack: + return + user_settings = self._global_container_stack.getTop() + quality = self._global_container_stack.findContainer({"type": "quality"}) + for key in user_settings.getAllKeys(): + quality.setProperty(key, "value", user_settings.getProperty(key, "value")) + self.clearUserSettings() # As all users settings are noq a quality, remove them. + @pyqtSlot(str) def setActiveMaterial(self, material_id): diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 2e89ce043a..e09b6b5424 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -112,7 +112,7 @@ 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: UM.ActiveProfile.updateProfile(); + onTriggered: Cura.MachineManager.updateUserContainerToQuality() } Action From 7b87143e65f4b14c0a9859e415db185b7ef0b39e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:07:35 +0200 Subject: [PATCH 105/304] Only value property events are now used This speeds the num events up a bit, but it's still a tad to slow CURA-1585 --- cura/MachineManagerModel.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index b9d6a9d37c..c03c8074f5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -43,10 +43,11 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - globalPropertyChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. + globalValueChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. def _onGlobalPropertyChanged(self, key, property_name): - self.globalPropertyChanged.emit() + if property_name == "value": + self.globalValueChanged.emit() def _onGlobalContainerChanged(self): if self._global_container_stack: @@ -187,7 +188,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop() user_settings.clear() - @pyqtProperty(bool, notify = globalPropertyChanged) + @pyqtProperty(bool, notify = globalValueChanged) def hasUserSettings(self): if not self._global_container_stack: return @@ -195,7 +196,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 - @pyqtProperty(bool, notify = globalPropertyChanged) + @pyqtProperty(bool, notify = globalValueChanged) def isGlobalStackValid(self): return not self._checkStackForErrors(self._global_container_stack) From 5faf2f024fb9118df7c146b40905fb14be3389cc Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:14:49 +0200 Subject: [PATCH 106/304] Added signal for validation state This improves the runtime speed somewhat CURA-1585 --- cura/MachineManagerModel.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c03c8074f5..3496252bb5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -43,11 +43,14 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - globalValueChanged = pyqtSignal() # Emitted whenever a property inside global container is changed. + globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. + globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed. def _onGlobalPropertyChanged(self, key, property_name): if property_name == "value": self.globalValueChanged.emit() + if property_name == "validationState": + self.globalValidationChanged.emit() def _onGlobalContainerChanged(self): if self._global_container_stack: @@ -196,7 +199,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 - @pyqtProperty(bool, notify = globalValueChanged) + @pyqtProperty(bool, notify = globalValidationChanged) def isGlobalStackValid(self): return not self._checkStackForErrors(self._global_container_stack) From 2b91b81f2d85eb3d5b3e1bfe1165c91a990c01e8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:24:23 +0200 Subject: [PATCH 107/304] Added documentation CURA-1585 --- cura/MachineManagerModel.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3496252bb5..ef0de37774 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -174,6 +174,7 @@ class MachineManagerModel(QObject): return unique_name ## Convenience function to check if a stack has errors. + # TODO; This is a rather expensive check, which we run way to often. def _checkStackForErrors(self, stack): if stack is None: return False @@ -184,6 +185,7 @@ class MachineManagerModel(QObject): return True return False + ## Remove all instances from the top instanceContainer (effectively removing all user-changed settings) @pyqtSlot() def clearUserSettings(self): if not self._global_container_stack: @@ -191,6 +193,7 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop() user_settings.clear() + ## Check if the global_container has instances in the user container @pyqtProperty(bool, notify = globalValueChanged) def hasUserSettings(self): if not self._global_container_stack: @@ -199,6 +202,8 @@ class MachineManagerModel(QObject): user_settings = self._global_container_stack.getTop().findInstances(**{}) return len(user_settings) != 0 + ## Check if the global profile does not contain error states + # TODO; Way to expensive step. We should probably cache this. @pyqtProperty(bool, notify = globalValidationChanged) def isGlobalStackValid(self): return not self._checkStackForErrors(self._global_container_stack) From b6b154e153e92dab90a59ab10e1d062453662e2e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 13:34:06 +0200 Subject: [PATCH 108/304] Fixed slowdown caused by validation check CURA-1585 --- cura/MachineManagerModel.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index ef0de37774..d9d62ecc1d 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -17,6 +17,7 @@ class MachineManagerModel(QObject): self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) + self._global_stack_valid = None self._onGlobalContainerChanged() ## When the global container is changed, active material probably needs to be updated. @@ -32,6 +33,8 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") + + if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) @@ -50,7 +53,16 @@ class MachineManagerModel(QObject): if property_name == "value": self.globalValueChanged.emit() if property_name == "validationState": - self.globalValidationChanged.emit() + if self._global_stack_valid: + changed_validation_state = self._global_container_stack.getProperty(key, property_name) + if changed_validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError): + self._global_stack_valid = False + self.globalValidationChanged.emit() + else: + new_validation_state = self._checkStackForErrors(self._global_container_stack) + if new_validation_state: + self._global_stack_valid = True + self.globalValidationChanged.emit() def _onGlobalContainerChanged(self): if self._global_container_stack: @@ -64,6 +76,7 @@ class MachineManagerModel(QObject): 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._global_stack_valid = self._checkStackForErrors(self._global_container_stack) def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") @@ -174,7 +187,6 @@ class MachineManagerModel(QObject): return unique_name ## Convenience function to check if a stack has errors. - # TODO; This is a rather expensive check, which we run way to often. def _checkStackForErrors(self, stack): if stack is None: return False @@ -203,10 +215,11 @@ class MachineManagerModel(QObject): return len(user_settings) != 0 ## Check if the global profile does not contain error states - # TODO; Way to expensive step. We should probably cache this. + # Note that the _global_stack_valid is cached due to performance issues + # Calling _checkStackForErrors on every change is simply too expensive @pyqtProperty(bool, notify = globalValidationChanged) def isGlobalStackValid(self): - return not self._checkStackForErrors(self._global_container_stack) + return self._global_stack_valid @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): From ea73f00aacc9dc024f544b385dec7f285dd5c18a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 14:39:36 +0200 Subject: [PATCH 109/304] Fixed case where validation state was set incorrectly CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index d9d62ecc1d..f89920e407 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -76,7 +76,7 @@ class MachineManagerModel(QObject): 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._global_stack_valid = self._checkStackForErrors(self._global_container_stack) + self._global_stack_valid = not self._checkStackForErrors(self._global_container_stack) def _onInstanceContainersChanged(self, container): container_type = container.getMetaDataEntry("type") From cd8df448127449136323cebc45b5c61d43aa8f94 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 14:40:28 +0200 Subject: [PATCH 110/304] Changed multiple properties in profile page to new API CURA-1285 --- resources/qml/Preferences/ProfilesPage.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 9561bba521..982f612943 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -90,15 +90,15 @@ UM.ManagementPage profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName; return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName)); } - enabled: UM.ActiveProfile.hasCustomisedValues && !UM.ActiveProfile.readOnly + enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) onClicked: UM.ActiveProfile.updateProfile() } Button { text: catalog.i18nc("@action:button", "Discard changes"); - enabled: UM.ActiveProfile.hasCustomisedValues - onClicked: UM.ActiveProfile.discardChanges() + enabled: Cura.MachineManager.hasUserSettings + onClicked: Cura.MachineManager.clearUserSettings(); } } @@ -114,7 +114,7 @@ UM.ManagementPage } Label { text: base.currentItem == null ? "" : - base.currentItem.id == -1 ? UM.MachineManager.activeProfile : + base.currentItem.id == -1 ? Cura.MachineManager.activeQualityName: base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") } From 80f24b6c5420b80d0d90823fd3352cfc588995fd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 14:56:42 +0200 Subject: [PATCH 111/304] Removed ulti quality, as that got in 2.1 by mistake As it got in there by mistake, it has no place here either! --- .../ultimaker2_plus/pla_0.4_ulti.inst.cfg | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg diff --git a/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg deleted file mode 100644 index db091d8e8d..0000000000 --- a/resources/quality/ultimaker2_plus/pla_0.4_ulti.inst.cfg +++ /dev/null @@ -1,21 +0,0 @@ -[general] -version = 1 -name = Ulti Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -4 - -[settings] -line_width = 0.35 -layer_height = 0.04 -layer_height_0 = 0.26 -wall_thickness = 1.4 -top_bottom_thickness = 1.12 -infill_sparse_density = 25 -speed_print = 30 -speed_infill = 50 -speed_wall_x = 40 -speed_topbottom = 20 -speed_layer_0 = 25 -cool_min_layer_time_fan_speed_max = 15 From 01999f7ddd6b101ab128141ef7c17525823f64f5 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 15:00:09 +0200 Subject: [PATCH 112/304] Custom profiles can now be renamed --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 982f612943..fb133a08ec 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -170,7 +170,7 @@ UM.ManagementPage id: renameDialog; object: base.currentItem != null ? base.currentItem.name : ""; property bool removeWhenRejected: false; - onAccepted: base.model.renameProfile(base.currentItem.name, newName.trim()); + onAccepted: base.model.rename(base.currentItem.id, newName.trim()); onRejected: { if(removeWhenRejected) { base.model.removeProfile(base.currentItem.name) From d1d60e27cc2719431aece5cea292bfcc8d17be48 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 15:25:08 +0200 Subject: [PATCH 113/304] Added function to duplicate container CURA-1427 --- cura/MachineManagerModel.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index f89920e407..355fc188d3 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -277,8 +277,9 @@ class MachineManagerModel(QObject): return True return containers[0].getMetaDataEntry("read_only", False) == "True" - @pyqtSlot() + @pyqtSlot(result = str) def convertUserContainerToQuality(self): + print("convertUserContainerToQuality") if not self._global_container_stack: return @@ -297,6 +298,23 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container) self.clearUserSettings() # As all users settings are noq a quality, remove them. self.setActiveQuality(name) + return name + + @pyqtSlot(str, result=str) + def duplicateContainer(self, container_id): + print("convertUserContainerToQuality") + if not self._global_container_stack: + return + container_to_duplicate = self._global_container_stack.findContainer({"id": container_id}) + if container_to_duplicate: + new_name = self._createUniqueStackName(container_to_duplicate.getName(), "") + new_container = InstanceContainer("") + new_container.setName(new_name) + new_container._id = new_name + UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) + return new_name + + return "" @pyqtSlot() def updateUserContainerToQuality(self): From fdbd6d7c5f3114760a8d11dd4bdc6264041b203c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 15:29:41 +0200 Subject: [PATCH 114/304] Updating profile now also works in profile page CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index fb133a08ec..594b15e066 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -29,14 +29,14 @@ UM.ManagementPage onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) onAddObject: { - var selectedProfile; + var selectedContainer; if (objectList.currentIndex == 0) { // Current settings - selectedProfile = UM.MachineManager.createProfile(); + selectedContainer = Cura.MachineManager.convertUserContainerToQuality(); } else { - selectedProfile = UM.MachineManager.duplicateProfile(currentItem.name); + selectedContainer = Cura.MachineManager.duplicateContainer(currentItem.id); } - base.selectProfile(selectedProfile); + base.selectContainer(selectedContainer); renameDialog.removeWhenRejected = true; renameDialog.open(); @@ -50,11 +50,11 @@ UM.ManagementPage removeEnabled: currentItem != null ? !currentItem.readOnly : false; renameEnabled: currentItem != null ? !currentItem.readOnly : false; - scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(UM.MachineManager.activeMachineInstance) + scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) - signal selectProfile(string name) - onSelectProfile: { - objectList.currentIndex = objectList.model.find("name", name); + signal selectContainer(string id) + onSelectContainer: { + objectList.currentIndex = objectList.model.find("id", id); } Item { @@ -86,12 +86,12 @@ UM.ManagementPage Button { text: { - var profileName = UM.MachineManager.activeProfile; + var profileName = Cura.MachineManager.activeQualityName; profileName = (profileName.length > 20) ? profileName.substring(0, 20) + '...' : profileName; return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName)); } enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) - onClicked: UM.ActiveProfile.updateProfile() + onClicked: Cura.MachineManager.updateUserContainerToQuality() } Button From 490a8724e589365f0136b11f2851a906f9c9d8dd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 3 Jun 2016 16:29:46 +0200 Subject: [PATCH 115/304] Fixed duplication of profiles CURA-1427 --- cura/MachineManagerModel.py | 13 ++++++++----- resources/qml/Preferences/ProfilesPage.qml | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 355fc188d3..609d2a77f8 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -279,7 +279,6 @@ class MachineManagerModel(QObject): @pyqtSlot(result = str) def convertUserContainerToQuality(self): - print("convertUserContainerToQuality") if not self._global_container_stack: return @@ -302,13 +301,17 @@ class MachineManagerModel(QObject): @pyqtSlot(str, result=str) def duplicateContainer(self, container_id): - print("convertUserContainerToQuality") if not self._global_container_stack: return - container_to_duplicate = self._global_container_stack.findContainer({"id": container_id}) - if container_to_duplicate: - new_name = self._createUniqueStackName(container_to_duplicate.getName(), "") + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) + if containers: + new_name = self._createUniqueStackName(containers[0].getName(), "") + new_container = InstanceContainer("") + + ## Copy all values + new_container.deserialize(containers[0].serialize()) + new_container.setName(new_name) new_container._id = new_name UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 594b15e066..8182eb1bb6 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -34,7 +34,7 @@ UM.ManagementPage // Current settings selectedContainer = Cura.MachineManager.convertUserContainerToQuality(); } else { - selectedContainer = Cura.MachineManager.duplicateContainer(currentItem.id); + selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); } base.selectContainer(selectedContainer); From c62ab6e937460e7fe81ca0765fbb3393f9e6e69d Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Sat, 4 Jun 2016 13:55:35 +0200 Subject: [PATCH 116/304] Adding a field of the build type to the spashscreen. For example, if the community distributes Cura in a different way, they can set CURA_BUILDTYPE via 'cmake -DCURA_BUILDTYPE=' and whenever Cura is launched " (PPA)" will be appended. Of course, this could be done by appending " (PPA)" to CURA_VERSION, but in case of my Ubuntu/Debian packaging it will only need one modification in debian/changelog to change the version. During build (debian/rules) this version will be read from debian/changelog. Changing the version number across different files, is a waste of time. Finally, we can use that field in the future to indicate debug or other other special builds. --- CMakeLists.txt | 1 + cura/CuraApplication.py | 5 +++-- cura/CuraSplashScreen.py | 3 +++ cura/CuraVersion.py.in | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc9f37c76e..98dca222b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ include(GNUInstallDirs) set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository") set(CURA_VERSION "master" CACHE STRING "Version name of Cura") +set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY) # Macro needed to list all sub-directory of a directory. diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index eccb3e4525..ac95529a5d 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -61,9 +61,10 @@ if platform.system() == "Linux": # Needed for platform.linux_distribution, which ctypes.CDLL(find_library('GL'), ctypes.RTLD_GLOBAL) try: - from cura.CuraVersion import CuraVersion + from cura.CuraVersion import CuraVersion, CuraBuildType except ImportError: CuraVersion = "master" # [CodeStyle: Reflecting imported value] + CuraBuildType = "" class CuraApplication(QtApplication): @@ -89,7 +90,7 @@ class CuraApplication(QtApplication): # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) - super().__init__(name = "cura", version = CuraVersion) + super().__init__(name = "cura", version = CuraVersion, build_type = CuraBuildType) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) diff --git a/cura/CuraSplashScreen.py b/cura/CuraSplashScreen.py index d27c9c0240..8f677986df 100644 --- a/cura/CuraSplashScreen.py +++ b/cura/CuraSplashScreen.py @@ -21,6 +21,9 @@ class CuraSplashScreen(QSplashScreen): painter.setPen(QColor(0, 0, 0, 255)) version = Application.getInstance().getVersion().split("-") + buildtype = Application.getInstance().getBuildType() + if buildtype: + version += " (%s)" %(buildtype) painter.setFont(QFont("Proxima Nova Rg", 20 )) painter.drawText(0, 0, 330 * self._scale, 230 * self._scale, Qt.AlignHCenter | Qt.AlignBottom, version[0]) diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in index bb69319ee6..5ad819b1fc 100644 --- a/cura/CuraVersion.py.in +++ b/cura/CuraVersion.py.in @@ -2,3 +2,4 @@ # Cura is released under the terms of the AGPLv3 or higher. CuraVersion = "@CURA_VERSION@" +CuraBuildType = "@CURA_BUILDTYPE@" \ No newline at end of file From b33ce573c1522e8b1864882e2429709de80ab4a0 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 19:22:42 +0200 Subject: [PATCH 117/304] Also filter materials and profiles preference pages by machine etc. when desired Contriubtes to CURA-1612 --- resources/qml/Preferences/MaterialsPage.qml | 28 +++++++++++++++------ resources/qml/Preferences/ProfilesPage.qml | 21 +++++++++++++++- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/resources/qml/Preferences/MaterialsPage.qml b/resources/qml/Preferences/MaterialsPage.qml index ed35a32fdf..af0f0c1bd2 100644 --- a/resources/qml/Preferences/MaterialsPage.qml +++ b/resources/qml/Preferences/MaterialsPage.qml @@ -14,7 +14,26 @@ UM.ManagementPage title: catalog.i18nc("@title:tab", "Materials"); - model: UM.InstanceContainersModel { filter: { "type": "material", "definition": Cura.MachineManager.activeDefinitionId } } + model: UM.InstanceContainersModel + { + filter: + { + var result = { "type": "material" } + if(Cura.MachineManager.filterMaterialsByMachine) + { + result.definition = Cura.MachineManager.activeDefinitionId + if(Cura.MachineManager.hasVariants) + { + result.variant = Cura.MachineManager.activeVariantId + } + } + else + { + result.definition = "fdmprinter" + } + return result + } + } activeId: Cura.MachineManager.activeMaterialId activeIndex: { @@ -25,12 +44,7 @@ UM.ManagementPage } return -1; } -/* - onAddObject: { var selectedMaterial = UM.MaterialManager.createProfile(); base.selectMaterial(selectedMaterial); } - onRemoveObject: confirmDialog.open(); - onRenameObject: { renameDialog.open(); renameDialog.selectText(); } -*/ -// activateEnabled: false + addEnabled: false removeEnabled: false renameEnabled: false diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 8182eb1bb6..b7261afcec 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -15,7 +15,26 @@ UM.ManagementPage title: catalog.i18nc("@title:tab", "Profiles"); addText: catalog.i18nc("@label", "Duplicate") - model: UM.InstanceContainersModel { filter: { "type": "quality" } } + 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 + } + } activeId: Cura.MachineManager.activeQualityId activeIndex: { From 6a3b321e5a597e92b1257fd838569bdd1a6b190b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 19:23:46 +0200 Subject: [PATCH 118/304] Re-enable commented code --- resources/qml/SidebarHeader.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 4b48584174..bb7aeebae7 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -271,7 +271,7 @@ Item var result = { "type": "material" } if(Cura.MachineManager.filterMaterialsByMachine) { -// result.definition = Cura.MachineManager.activeDefinitionId + result.definition = Cura.MachineManager.activeDefinitionId if(Cura.MachineManager.hasVariants) { result.variant = Cura.MachineManager.activeVariantId From 8f21ec39807f3aeec50954f74f0bc4147194728d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 20:51:53 +0200 Subject: [PATCH 119/304] Add PLA profiles for UM2Extended+ Contributes to CURA-1612 --- .../um2ep_pla_0.25_normal.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.4_fast.inst.cfg | 21 +++++++++++++++++++ .../um2ep_pla_0.4_high.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.4_normal.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.6_normal.inst.cfg | 19 +++++++++++++++++ .../um2ep_pla_0.8_normal.inst.cfg | 19 +++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg 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 new file mode 100644 index 0000000000..142ee42b71 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg @@ -0,0 +1,19 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_extended_plus_0.25_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 0.88 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 30 +cool_min_layer_time = 5 +cool_min_speed = 10 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 new file mode 100644 index 0000000000..8fd8fedf4c --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_extended_plus_0.4_mm +weight = -1 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 0.7 +top_bottom_thickness = 0.75 +infill_sparse_density = 18 +speed_print = 60 +speed_travel = 150 +speed_layer_0 = 30 +cool_min_layer_time = 5 +cool_min_speed = 10 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 new file mode 100644 index 0000000000..3fc5cb39a0 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg @@ -0,0 +1,19 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_extended_plus_0.4_mm +weight = -3 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 50 +cool_min_layer_time = 5 +cool_min_speed = 10 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 new file mode 100644 index 0000000000..94816b233c --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg @@ -0,0 +1,19 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_pla_ultimaker2_extended_plus_0.4_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.1 +wall_thickness = 1.05 +top_bottom_thickness = 0.8 +infill_sparse_density = 20 +speed_print = 50 +cool_min_layer_time = 5 +cool_min_speed = 10 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 new file mode 100644 index 0000000000..2de9b6a482 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg @@ -0,0 +1,19 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_extended_plus + +[metadata] +material = generic_pla_ultimaker2_extended_plus_0.6_mm +type = quality +weight = -2 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 1.59 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 55 +cool_min_layer_time = 5 +cool_min_speed = 10 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 new file mode 100644 index 0000000000..f3a1a14f73 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg @@ -0,0 +1,19 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_extended_plus + +[metadata] +material = generic_pla_ultimaker2_extended_plus_0.8_mm +type = quality +weight = -2 +read_only = True + +[values] +layer_height = 0.2 +wall_thickness = 2.1 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 5 +cool_min_speed = 10 From 3a3314aad1e6c14d0eb8c2af7efb2e53edee525e Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:16:39 +0200 Subject: [PATCH 120/304] Remove all old profiles Contributes to CURA-1612 --- resources/instances/high_quality.inst.cfg | 9 -------- resources/instances/normal_quality.inst.cfg | 9 -------- resources/profiles/general/High+Quality.cfg | 10 --------- resources/profiles/general/Low+Quality.cfg | 15 ------------- resources/profiles/general/Normal+Quality.cfg | 8 ------- resources/profiles/general/Ulti+Quality.cfg | 9 -------- resources/profiles/materials/abs.cfg | 9 -------- resources/profiles/materials/cpe.cfg | 8 ------- resources/profiles/materials/pla.cfg | 7 ------ .../ultimaker2+/abs_0.25_normal.curaprofile | 20 ----------------- .../ultimaker2+/abs_0.4_fast.curaprofile | 21 ------------------ .../ultimaker2+/abs_0.4_high.curaprofile | 19 ---------------- .../ultimaker2+/abs_0.4_normal.curaprofile | 18 --------------- .../ultimaker2+/abs_0.6_normal.curaprofile | 20 ----------------- .../ultimaker2+/abs_0.8_normal.curaprofile | 19 ---------------- .../ultimaker2+/cpe_0.25_normal.curaprofile | 19 ---------------- .../ultimaker2+/cpe_0.4_fast.curaprofile | 22 ------------------- .../ultimaker2+/cpe_0.4_high.curaprofile | 18 --------------- .../ultimaker2+/cpe_0.4_normal.curaprofile | 19 ---------------- .../ultimaker2+/cpe_0.6_normal.curaprofile | 18 --------------- .../ultimaker2+/cpe_0.8_normal.curaprofile | 18 --------------- .../ultimaker2+/pla_0.25_normal.curaprofile | 16 -------------- .../ultimaker2+/pla_0.4_fast.curaprofile | 18 --------------- .../ultimaker2+/pla_0.4_high.curaprofile | 16 -------------- .../ultimaker2+/pla_0.4_normal.curaprofile | 16 -------------- .../ultimaker2+/pla_0.4_ulti.curaprofile | 21 ------------------ .../ultimaker2+/pla_0.6_normal.curaprofile | 16 -------------- .../ultimaker2+/pla_0.8_normal.curaprofile | 16 -------------- 28 files changed, 434 deletions(-) delete mode 100644 resources/instances/high_quality.inst.cfg delete mode 100644 resources/instances/normal_quality.inst.cfg delete mode 100644 resources/profiles/general/High+Quality.cfg delete mode 100644 resources/profiles/general/Low+Quality.cfg delete mode 100644 resources/profiles/general/Normal+Quality.cfg delete mode 100644 resources/profiles/general/Ulti+Quality.cfg delete mode 100644 resources/profiles/materials/abs.cfg delete mode 100644 resources/profiles/materials/cpe.cfg delete mode 100644 resources/profiles/materials/pla.cfg delete mode 100644 resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.4_high.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_high.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile delete mode 100644 resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile diff --git a/resources/instances/high_quality.inst.cfg b/resources/instances/high_quality.inst.cfg deleted file mode 100644 index 2e860cf380..0000000000 --- a/resources/instances/high_quality.inst.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[general] -version = 2 -name = high -definition = fdmprinter - -[metadata] -type = quality - -[values] diff --git a/resources/instances/normal_quality.inst.cfg b/resources/instances/normal_quality.inst.cfg deleted file mode 100644 index 6bb23d841c..0000000000 --- a/resources/instances/normal_quality.inst.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[general] -version = 2 -name = normal -definition = fdmprinter - -[metadata] -type = quality - -[values] diff --git a/resources/profiles/general/High+Quality.cfg b/resources/profiles/general/High+Quality.cfg deleted file mode 100644 index a006c7a995..0000000000 --- a/resources/profiles/general/High+Quality.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[general] -version = 1 -name = High Quality -weight = -3 - -[settings] -layer_height = 0.06 -speed_topbottom = 15 -speed_infill = 80 - diff --git a/resources/profiles/general/Low+Quality.cfg b/resources/profiles/general/Low+Quality.cfg deleted file mode 100644 index f7f4e5d6b7..0000000000 --- a/resources/profiles/general/Low+Quality.cfg +++ /dev/null @@ -1,15 +0,0 @@ -[general] -version = 1 -name = Low Quality -weight = -1 - -[settings] -infill_sparse_density = 10 -layer_height = 0.15 -cool_min_layer_time = 3 -speed_wall_0 = 40 -speed_wall_x = 80 -speed_infill = 100 -wall_thickness = 1 -speed_topbottom = 30 - diff --git a/resources/profiles/general/Normal+Quality.cfg b/resources/profiles/general/Normal+Quality.cfg deleted file mode 100644 index 575c3343e2..0000000000 --- a/resources/profiles/general/Normal+Quality.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 1 -name = Normal Quality -weight = -2 - -[settings] -speed_topbottom = 15 -speed_infill = 80 \ No newline at end of file diff --git a/resources/profiles/general/Ulti+Quality.cfg b/resources/profiles/general/Ulti+Quality.cfg deleted file mode 100644 index 1fa9b6085c..0000000000 --- a/resources/profiles/general/Ulti+Quality.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[general] -version = 1 -name = Ulti Quality -weight = -4 - -[settings] -layer_height = 0.04 -speed_topbottom = 15 -speed_infill = 80 \ No newline at end of file diff --git a/resources/profiles/materials/abs.cfg b/resources/profiles/materials/abs.cfg deleted file mode 100644 index 67abc32810..0000000000 --- a/resources/profiles/materials/abs.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[general] -version = 1 -type = material -name = ABS - -[settings] -material_print_temperature = 250 -material_bed_temperature = 80 -material_flow = 107 diff --git a/resources/profiles/materials/cpe.cfg b/resources/profiles/materials/cpe.cfg deleted file mode 100644 index 0621260745..0000000000 --- a/resources/profiles/materials/cpe.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[general] -version = 1 -type = material -name = CPE - -[settings] -material_print_temperature = 250 -material_bed_temperature = 70 \ No newline at end of file diff --git a/resources/profiles/materials/pla.cfg b/resources/profiles/materials/pla.cfg deleted file mode 100644 index b5af61b9b6..0000000000 --- a/resources/profiles/materials/pla.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[general] -version = 1 -type = material -name = PLA - -[settings] -material_bed_temperature = 60 \ No newline at end of file diff --git a/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile deleted file mode 100644 index 9f45e9d01a..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.25_normal.curaprofile +++ /dev/null @@ -1,20 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.25 mm -material = ABS -weight = -2 - -[settings] -layer_height = 0.06 -wall_thickness = 0.88 -top_bottom_thickness = 0.72 -infill_sparse_density = 22 -speed_print = 30 -cool_min_layer_time = 3 -cool_fan_speed_min = 20 -cool_min_speed = 10 -cool_min_layer_time_fan_speed_max = 15 - - diff --git a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile deleted file mode 100644 index 50018372b5..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile +++ /dev/null @@ -1,21 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = ABS -weight = -1 - -[settings] -layer_height = 0.15 -wall_thickness = 0.7 -top_bottom_thickness = 0.75 -infill_sparse_density = 18 -speed_print = 55 -speed_travel = 150 -speed_layer_0 = 30 -cool_min_layer_time = 3 -cool_fan_speed_min = 20 -cool_min_speed = 10 -cool_min_layer_time_fan_speed_max = 15 - diff --git a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile deleted file mode 100644 index 341c9cc34f..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = ABS -weight = -3 - -[settings] -layer_height = 0.06 -wall_thickness = 1.05 -top_bottom_thickness = 0.72 -infill_sparse_density = 22 -speed_print = 45 -cool_min_layer_time = 3 -cool_fan_speed_min = 20 -cool_min_speed = 10 -cool_min_layer_time_fan_speed_max = 15 - diff --git a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile deleted file mode 100644 index d8fce8a4dd..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = ABS -weight = -2 - -[settings] -layer_height = 0.1 -wall_thickness = 1.05 -top_bottom_thickness = 0.8 -infill_sparse_density = 20 -speed_print = 45 -cool_min_layer_time = 3 -cool_fan_speed_min = 20 -cool_min_speed = 10 -cool_min_layer_time_fan_speed_max = 15 diff --git a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile deleted file mode 100644 index 5512450471..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile +++ /dev/null @@ -1,20 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.6 mm -material = ABS -weight = -2 - -[settings] -layer_height = 0.15 -wall_thickness = 1.59 -top_bottom_thickness = 1.2 -infill_sparse_density = 20 -speed_print = 40 -cool_min_layer_time = 3 -cool_fan_speed_min = 50 -cool_min_speed = 20 -cool_min_layer_time_fan_speed_max = 20 - - diff --git a/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile deleted file mode 100644 index e5f27c51a2..0000000000 --- a/resources/profiles/ultimaker2+/abs_0.8_normal.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.8 mm -material = ABS -weight = -2 - -[settings] -layer_height = 0.2 -wall_thickness = 2.1 -top_bottom_thickness = 1.2 -infill_sparse_density = 20 -speed_print = 40 -cool_min_layer_time = 3 -cool_fan_speed_min = 50 -cool_min_speed = 15 -cool_min_layer_time_fan_speed_max = 25 - diff --git a/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile deleted file mode 100644 index c4c09932d8..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.25_normal.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.25 mm -material = CPE -weight = -2 - -[settings] -layer_height = 0.06 -wall_thickness = 0.88 -top_bottom_thickness = 0.72 -infill_sparse_density = 22 -speed_print = 30 -cool_min_layer_time = 2 -cool_fan_speed_min = 20 -cool_min_speed = 15 -cool_min_layer_time_fan_speed_max = 15 - diff --git a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile deleted file mode 100644 index f9050e5ce5..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile +++ /dev/null @@ -1,22 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = CPE -weight = -1 - -[settings] -layer_height = 0.15 -wall_thickness = 0.7 -top_bottom_thickness = 0.75 -infill_sparse_density = 18 -speed_print = 45 -speed_travel = 150 -speed_layer_0 = 30 -cool_min_layer_time = 3 -cool_fan_speed_min = 80 -cool_min_speed = 10 -cool_min_layer_time_fan_speed_max = 15 - - diff --git a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile deleted file mode 100644 index 377ab5b257..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = CPE -weight = -3 - -[settings] -layer_height = 0.06 -wall_thickness = 1.05 -top_bottom_thickness = 0.72 -infill_sparse_density = 22 -speed_print = 45 -cool_min_layer_time = 2 -cool_fan_speed_min = 80 -cool_min_speed = 15 -cool_min_layer_time_fan_speed_max = 15 diff --git a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile deleted file mode 100644 index e8142405ff..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile +++ /dev/null @@ -1,19 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = CPE -weight = -2 - -[settings] -layer_height = 0.1 -wall_thickness = 1.05 -top_bottom_thickness = 0.8 -infill_sparse_density = 20 -speed_print = 45 -cool_min_layer_time = 3 -cool_fan_speed_min = 80 -cool_min_speed = 10 -cool_min_layer_time_fan_speed_max = 15 - diff --git a/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile deleted file mode 100644 index 034fa17e1b..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.6_normal.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.6 mm -material = CPE -weight = -2 - -[settings] -layer_height = 0.15 -wall_thickness = 1.59 -top_bottom_thickness = 1.2 -infill_sparse_density = 20 -speed_print = 40 -cool_min_layer_time = 5 -cool_fan_speed_min = 80 -cool_min_speed = 8 -cool_min_layer_time_fan_speed_max = 20 diff --git a/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile deleted file mode 100644 index 523a5d3243..0000000000 --- a/resources/profiles/ultimaker2+/cpe_0.8_normal.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.8 mm -material = CPE -weight = -2 - -[settings] -layer_height = 0.2 -wall_thickness = 2.1 -top_bottom_thickness = 1.2 -infill_sparse_density = 20 -speed_print = 40 -cool_min_layer_time = 3 -cool_fan_speed_min = 80 -cool_min_speed = 8 -cool_min_layer_time_fan_speed_max = 25 diff --git a/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile deleted file mode 100644 index 63c1fc9fdd..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.25_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.25 mm -material = PLA -weight = -2 - -[settings] -layer_height = 0.06 -wall_thickness = 0.88 -top_bottom_thickness = 0.72 -infill_sparse_density = 22 -speed_print = 30 -cool_min_layer_time = 5 -cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile deleted file mode 100644 index 06e401c139..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile +++ /dev/null @@ -1,18 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -1 - -[settings] -layer_height = 0.15 -wall_thickness = 0.7 -top_bottom_thickness = 0.75 -infill_sparse_density = 18 -speed_print = 60 -speed_travel = 150 -speed_layer_0 = 30 -cool_min_layer_time = 5 -cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile deleted file mode 100644 index 5e2f762354..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = High Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -3 - -[settings] -layer_height = 0.06 -wall_thickness = 1.05 -top_bottom_thickness = 0.72 -infill_sparse_density = 22 -speed_print = 50 -cool_min_layer_time = 5 -cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile deleted file mode 100644 index 689a3251b2..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -2 - -[settings] -layer_height = 0.1 -wall_thickness = 1.05 -top_bottom_thickness = 0.8 -infill_sparse_density = 20 -speed_print = 50 -cool_min_layer_time = 5 -cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile deleted file mode 100644 index db091d8e8d..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.4_ulti.curaprofile +++ /dev/null @@ -1,21 +0,0 @@ -[general] -version = 1 -name = Ulti Quality -machine_type = ultimaker2plus -machine_variant = 0.4 mm -material = PLA -weight = -4 - -[settings] -line_width = 0.35 -layer_height = 0.04 -layer_height_0 = 0.26 -wall_thickness = 1.4 -top_bottom_thickness = 1.12 -infill_sparse_density = 25 -speed_print = 30 -speed_infill = 50 -speed_wall_x = 40 -speed_topbottom = 20 -speed_layer_0 = 25 -cool_min_layer_time_fan_speed_max = 15 diff --git a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile deleted file mode 100644 index 188ed42a95..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = Normal Quality -machine_type = ultimaker2plus -machine_variant = 0.6 mm -material = PLA -weight = -2 - -[settings] -layer_height = 0.15 -wall_thickness = 1.59 -top_bottom_thickness = 1.2 -infill_sparse_density = 20 -speed_print = 55 -cool_min_layer_time = 5 -cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile deleted file mode 100644 index 92cb4a6054..0000000000 --- a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile +++ /dev/null @@ -1,16 +0,0 @@ -[general] -version = 1 -name = Fast Print -machine_type = ultimaker2plus -machine_variant = 0.8 mm -material = PLA -weight = -2 - -[settings] -layer_height = 0.2 -wall_thickness = 2.1 -top_bottom_thickness = 1.2 -infill_sparse_density = 20 -speed_print = 40 -cool_min_layer_time = 5 -cool_min_speed = 10 From 3413334c6d0b8409307c5d234fbaf65f79c9eb66 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:17:27 +0200 Subject: [PATCH 121/304] Update active material/quality when changing one of the lower levels Contributes to CURA-1612 --- cura/MachineManagerModel.py | 119 ++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 609d2a77f8..24020f50a4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -104,50 +104,9 @@ class MachineManagerModel(QObject): new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) - variant_instance_container = self._empty_variant_container - if definition.getMetaDataEntry("has_variants"): - variant_instance_container = self._getPreferredContainer(definition, "preferred_variant", self._empty_variant_container) - - if variant_instance_container == self._empty_variant_container: - variants = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) - if variants: - variant_instance_container = variants[0] - - if variant_instance_container == self._empty_variant_container: - Logger.log("w", "Machine %s defines it has variants but no variants found", definition.id) - - material_instance_container = self._empty_material_container - if definition.getMetaDataEntry("has_materials"): - material_instance_container = self._getPreferredContainer(definition, "preferred_material", self._empty_material_container) - - if material_instance_container == self._empty_material_container: - materials = None - if definition.getMetaDataEntry("has_machine_materials"): - if variant_instance_container != self._empty_material_container: - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id, variant = variant_instance_container.id) - else: - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition.id) - else: - materials = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = "fdmprinter") - - if materials: - material_instance_container = materials[0] - - if material_instance_container == self._empty_material_container: - Logger.log("w", "Machine %s defines it has materials but no matererials found", definition.id) - - quality_instance_container = self._getPreferredContainer(definition, "preferred_quality", self._empty_quality_container) - if quality_instance_container == self._empty_quality_container: - if definition.getMetaDataEntry("has_machine_quality"): - if material_instance_container: - qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id, material = material_instance_container.id) - else: - qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition.id) - else: - qualities = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = "fdmprinter") - - if qualities: - quality_instance_container = qualities[0] + variant_instance_container = self._updateVariantContainer(definition) + material_instance_container = self._updateMaterialContainer(definition) + quality_instance_container = self._updateQualityContainer(definition) current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings") current_settings_instance_container.addMetaDataEntry("machine", name) @@ -341,6 +300,8 @@ class MachineManagerModel(QObject): material_index = self._global_container_stack.getContainerIndex(old_material) self._global_container_stack.replaceContainer(material_index, containers[0]) + self.setActiveQuality(self._updateQualityContainer(self._global_container_stack.getBottom(), containers[0]).id) + @pyqtSlot(str) def setActiveVariant(self, variant_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=variant_id) @@ -352,6 +313,8 @@ class MachineManagerModel(QObject): variant_index = self._global_container_stack.getContainerIndex(old_variant) self._global_container_stack.replaceContainer(variant_index, containers[0]) + self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0]).id) + @pyqtSlot(str) def setActiveQuality(self, quality_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id) @@ -435,15 +398,67 @@ class MachineManagerModel(QObject): return False - def _getPreferredContainer(self, definition, property_name, default_container): - preferred_id = definition.getMetaDataEntry(property_name) - if preferred_id: - preferred_id = preferred_id.lower() - container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = preferred_id) - if container: - return container[0] + def _updateVariantContainer(self, definition): + if not definition.getMetaDataEntry("has_variants"): + return self._empty_variant_container - return default_container + containers = [] + preferred_variant = definition.getMetaDataEntry("preferred_variant") + if preferred_variant: + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id, id = preferred_variant) + + if not containers: + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = definition.id) + + if containers: + return containers[0] + + return self._empty_variant_container + + def _updateMaterialContainer(self, definition, variant_container): + if not definition.getMetaDataEntry("has_materials"): + return self._empty_material_container + + search_criteria = { "type": "material" } + + if definition.getMetaDataEntry("has_machine_materials"): + search_criteria["definition"] = definition.id + + if definition.getMetaDataEntry("has_variants") and variant_container: + search_criteria["variant"] = variant_container.id + else: + search_criteria["definition"] = "fdmprinter" + + preferred_material = definition.getMetaDataEntry("preferred_material") + if preferred_material: + search_criteria["id"] = preferred_material + + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) + if containers: + return containers[0] + + return self._empty_material_container + + def _updateQualityContainer(self, definition, material_container): + search_criteria = { "type": "quality" } + + if definition.getMetaDataEntry("has_machine_quality"): + search_criteria["definition"] = definition.id + + if definition.getMetaDataEntry("has_materials") and material_container: + search_criteria["material"] = material_container.id + else: + search_criteria["definition"] = "fdmprinter" + + preferred_quality = definition.getMetaDataEntry("preferred_quality") + if preferred_quality: + search_criteria["id"] = preferred_quality + + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria) + if containers: + return containers[0] + + return self._empty_quality_container def createMachineManagerModel(engine, script_engine): return MachineManagerModel() From 65a563027de5b8dad9c5b4edba766a2ee33c7ba8 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:19:05 +0200 Subject: [PATCH 122/304] Specify preferred material/quality as wildcards This way it becomes a lot simpler to match them Contributes to CURA-1612 --- resources/definitions/ultimaker2_plus.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json index 75501fb158..b29f904095 100644 --- a/resources/definitions/ultimaker2_plus.def.json +++ b/resources/definitions/ultimaker2_plus.def.json @@ -12,8 +12,8 @@ "platform": "ultimaker2_platform.obj", "platform_texture": "Ultimaker2Plusbackplate.png", "preferred_variant": "ultimaker2_plus_0.4", - "preferred_material": "generic_pla_ultimaker2_plus_0.4mm", - "preferred_quality": "pla_0.4_normal", + "preferred_material": "*pla*", + "preferred_quality": "*normal*", "has_variants": true, "has_materials": true, "has_machine_materials": true, From e0ebe960acc9e0d8d9eea9448d3df82909c8ff03 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:19:29 +0200 Subject: [PATCH 123/304] Update standard quality profiles Contributes to CURA-1612 --- resources/quality/high.inst.cfg | 2 ++ resources/quality/low.inst.cfg | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 546d11326b..86df9dab92 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -9,3 +9,5 @@ read_only = True [values] layer_height = 0.06 +speed_topbottom = 15 +speed_infill = 80 diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index 11a0094aca..6cebc46dd5 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -8,4 +8,11 @@ type = quality read_only = True [values] +infill_sparse_density = 10 layer_height = 0.15 +cool_min_layer_time = 3 +speed_wall_0 = 40 +speed_wall_x = 80 +speed_infill = 100 +wall_thickness = 1 +speed_topbottom = 30 From 312097c523fe81ea51913698517b9c319ba792b5 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:21:24 +0200 Subject: [PATCH 124/304] Specify UMO as having materials Contributes to CURA-1612 --- resources/definitions/ultimaker_original.def.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/definitions/ultimaker_original.def.json b/resources/definitions/ultimaker_original.def.json index 1dbdb95d8c..55668946a0 100644 --- a/resources/definitions/ultimaker_original.def.json +++ b/resources/definitions/ultimaker_original.def.json @@ -11,6 +11,9 @@ "file_formats": "text/x-gcode", "icon": "icon_ultimaker.png", "platform": "ultimaker_platform.stl", + "has_materials": true, + "preferred_material": "*pla*", + "preferred_quality": "*normal*", "pages": [ "SelectUpgradedParts", "UpgradeFirmware", From 2d77ddada41915cc410f731230e229e8d518a434 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:21:57 +0200 Subject: [PATCH 125/304] Add ABS/CPE quality profiles for UM2(E)+ Contributes to CURA-1612 --- .../um2ep_abs_0.25_normal.inst.cfg | 23 +++++++++++++++++ .../um2ep_abs_0.4_fast.inst.cfg | 24 ++++++++++++++++++ .../um2ep_abs_0.4_high.inst.cfg | 22 ++++++++++++++++ .../um2ep_abs_0.4_normal.inst.cfg | 21 ++++++++++++++++ .../um2ep_abs_0.6_normal.inst.cfg | 23 +++++++++++++++++ .../um2ep_abs_0.8_normal.inst.cfg | 22 ++++++++++++++++ .../um2ep_cpe_0.25_normal.inst.cfg | 22 ++++++++++++++++ .../um2ep_cpe_0.4_fast.inst.cfg | 25 +++++++++++++++++++ .../um2ep_cpe_0.4_high.inst.cfg | 21 ++++++++++++++++ .../um2ep_cpe_0.4_normal.inst.cfg | 22 ++++++++++++++++ .../um2ep_cpe_0.6_normal.inst.cfg | 21 ++++++++++++++++ .../um2ep_cpe_0.8_normal.inst.cfg | 21 ++++++++++++++++ .../um2p_abs_0.25_normal.inst.cfg | 23 +++++++++++++++++ .../um2p_abs_0.4_fast.inst.cfg | 24 ++++++++++++++++++ .../um2p_abs_0.4_high.inst.cfg | 22 ++++++++++++++++ .../um2p_abs_0.4_normal.inst.cfg | 21 ++++++++++++++++ .../um2p_abs_0.6_normal.inst.cfg | 23 +++++++++++++++++ .../um2p_abs_0.8_normal.inst.cfg | 22 ++++++++++++++++ .../um2p_cpe_0.25_normal.inst.cfg | 22 ++++++++++++++++ .../um2p_cpe_0.4_fast.inst.cfg | 25 +++++++++++++++++++ .../um2p_cpe_0.4_high.inst.cfg | 21 ++++++++++++++++ .../um2p_cpe_0.4_normal.inst.cfg | 22 ++++++++++++++++ .../um2p_cpe_0.6_normal.inst.cfg | 21 ++++++++++++++++ .../um2p_cpe_0.8_normal.inst.cfg | 21 ++++++++++++++++ 24 files changed, 534 insertions(+) create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg create mode 100644 resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg 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 new file mode 100644 index 0000000000..07d3fae601 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_extended_plus_0.25_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 0.88 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 30 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 + + 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 new file mode 100644 index 0000000000..f554c7f058 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg @@ -0,0 +1,24 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_extended_plus_0.4_mm +weight = -1 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 0.7 +top_bottom_thickness = 0.75 +infill_sparse_density = 18 +speed_print = 55 +speed_travel = 150 +speed_layer_0 = 30 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 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 new file mode 100644 index 0000000000..c1a8136cf5 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_extended_plus_0.4_mm +weight = -3 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 45 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 + 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 new file mode 100644 index 0000000000..eabc9827a1 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_extended_plus_0.4_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.1 +wall_thickness = 1.05 +top_bottom_thickness = 0.8 +infill_sparse_density = 20 +speed_print = 45 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 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 new file mode 100644 index 0000000000..64e0ec72fb --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_extended_plus_0.6_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 1.59 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 3 +cool_fan_speed_min = 50 +cool_min_speed = 20 +cool_min_layer_time_fan_speed_max = 20 + + 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 new file mode 100644 index 0000000000..8857db6cc1 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_extended_plus_0.8_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.2 +wall_thickness = 2.1 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 3 +cool_fan_speed_min = 50 +cool_min_speed = 15 +cool_min_layer_time_fan_speed_max = 25 + 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 new file mode 100644 index 0000000000..d34ea88798 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_extended_plus_0.25_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 0.88 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 30 +cool_min_layer_time = 2 +cool_fan_speed_min = 20 +cool_min_speed = 15 +cool_min_layer_time_fan_speed_max = 15 + 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 new file mode 100644 index 0000000000..ae9b437010 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg @@ -0,0 +1,25 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_extended_plus_0.4_mm +weight = -1 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 0.7 +top_bottom_thickness = 0.75 +infill_sparse_density = 18 +speed_print = 45 +speed_travel = 150 +speed_layer_0 = 30 +cool_min_layer_time = 3 +cool_fan_speed_min = 80 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 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 new file mode 100644 index 0000000000..e3fa254a74 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_extended_plus_0.4_mm +weight = -3 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 45 +cool_min_layer_time = 2 +cool_fan_speed_min = 80 +cool_min_speed = 15 +cool_min_layer_time_fan_speed_max = 15 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 new file mode 100644 index 0000000000..48e767e1cb --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_extended_plus_0.4_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.1 +wall_thickness = 1.05 +top_bottom_thickness = 0.8 +infill_sparse_density = 20 +speed_print = 45 +cool_min_layer_time = 3 +cool_fan_speed_min = 80 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 + 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 new file mode 100644 index 0000000000..675c949364 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_extended_plus_0.6_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 1.59 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 5 +cool_fan_speed_min = 80 +cool_min_speed = 8 +cool_min_layer_time_fan_speed_max = 20 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 new file mode 100644 index 0000000000..b631baea42 --- /dev/null +++ b/resources/quality/ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_extended_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_extended_plus_0.8_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.2 +wall_thickness = 2.1 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 3 +cool_fan_speed_min = 80 +cool_min_speed = 8 +cool_min_layer_time_fan_speed_max = 25 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 new file mode 100644 index 0000000000..0b7a371ff1 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_plus_0.25_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 0.88 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 30 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 + + 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 new file mode 100644 index 0000000000..e9593b10a7 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg @@ -0,0 +1,24 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_plus_0.4_mm +weight = -1 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 0.7 +top_bottom_thickness = 0.75 +infill_sparse_density = 18 +speed_print = 55 +speed_travel = 150 +speed_layer_0 = 30 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 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 new file mode 100644 index 0000000000..2bd3b4fa1a --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_plus_0.4_mm +weight = -3 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 45 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 + 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 new file mode 100644 index 0000000000..34bb28d20a --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_plus_0.4_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.1 +wall_thickness = 1.05 +top_bottom_thickness = 0.8 +infill_sparse_density = 20 +speed_print = 45 +cool_min_layer_time = 3 +cool_fan_speed_min = 20 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 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 new file mode 100644 index 0000000000..2c4656a4d9 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg @@ -0,0 +1,23 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_plus_0.6_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 1.59 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 3 +cool_fan_speed_min = 50 +cool_min_speed = 20 +cool_min_layer_time_fan_speed_max = 20 + + 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 new file mode 100644 index 0000000000..d5b9557ebb --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_abs_ultimaker2_plus_0.8_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.2 +wall_thickness = 2.1 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 3 +cool_fan_speed_min = 50 +cool_min_speed = 15 +cool_min_layer_time_fan_speed_max = 25 + 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 new file mode 100644 index 0000000000..eaab2ff2b6 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_plus_0.25_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 0.88 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 30 +cool_min_layer_time = 2 +cool_fan_speed_min = 20 +cool_min_speed = 15 +cool_min_layer_time_fan_speed_max = 15 + 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 new file mode 100644 index 0000000000..e20f5ec96b --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg @@ -0,0 +1,25 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_plus_0.4_mm +weight = -1 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 0.7 +top_bottom_thickness = 0.75 +infill_sparse_density = 18 +speed_print = 45 +speed_travel = 150 +speed_layer_0 = 30 +cool_min_layer_time = 3 +cool_fan_speed_min = 80 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 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 new file mode 100644 index 0000000000..9b64b5580c --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = High Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_plus_0.4_mm +weight = -3 +read_only = True + +[values] +layer_height = 0.06 +wall_thickness = 1.05 +top_bottom_thickness = 0.72 +infill_sparse_density = 22 +speed_print = 45 +cool_min_layer_time = 2 +cool_fan_speed_min = 80 +cool_min_speed = 15 +cool_min_layer_time_fan_speed_max = 15 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 new file mode 100644 index 0000000000..6ec06e1fb9 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg @@ -0,0 +1,22 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_plus_0.4_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.1 +wall_thickness = 1.05 +top_bottom_thickness = 0.8 +infill_sparse_density = 20 +speed_print = 45 +cool_min_layer_time = 3 +cool_fan_speed_min = 80 +cool_min_speed = 10 +cool_min_layer_time_fan_speed_max = 15 + 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 new file mode 100644 index 0000000000..f19032a95e --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Normal Quality +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_plus_0.6_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.15 +wall_thickness = 1.59 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 5 +cool_fan_speed_min = 80 +cool_min_speed = 8 +cool_min_layer_time_fan_speed_max = 20 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 new file mode 100644 index 0000000000..45372fdf39 --- /dev/null +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg @@ -0,0 +1,21 @@ +[general] +version = 2 +name = Fast Print +definition = ultimaker2_plus + +[metadata] +type = quality +material = generic_cpe_ultimaker2_plus_0.8_mm +weight = -2 +read_only = True + +[values] +layer_height = 0.2 +wall_thickness = 2.1 +top_bottom_thickness = 1.2 +infill_sparse_density = 20 +speed_print = 40 +cool_min_layer_time = 3 +cool_fan_speed_min = 80 +cool_min_speed = 8 +cool_min_layer_time_fan_speed_max = 25 From 0a9382aa114d1315c8b701f4448278ac61f309af Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Sat, 4 Jun 2016 21:22:21 +0200 Subject: [PATCH 126/304] Fix exclusiveGroup for machine selection in the menu Contributes to CURA-1278 --- resources/qml/Cura.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 2b7a4ccea7..851e7c984f 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -178,7 +178,7 @@ UM.MainWindow text: model.name; checkable: true; checked: Cura.MachineManager.activeMachineId == model.id - exclusiveGroup: machineSelectionMenuGroup; + exclusiveGroup: machineMenuGroup; onTriggered: Cura.MachineManager.setActiveMachine(model.id); } onObjectAdded: machineMenu.insertItem(index, object) From 2f3352bfa0cc38675230f05a0b2cece1d5759b5a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 10:45:47 +0200 Subject: [PATCH 127/304] Added default values when adding variant & materials CURA-1612 --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 24020f50a4..3e4c7a0411 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -415,7 +415,7 @@ class MachineManagerModel(QObject): return self._empty_variant_container - def _updateMaterialContainer(self, definition, variant_container): + def _updateMaterialContainer(self, definition, variant_container = None): if not definition.getMetaDataEntry("has_materials"): return self._empty_material_container @@ -439,7 +439,7 @@ class MachineManagerModel(QObject): return self._empty_material_container - def _updateQualityContainer(self, definition, material_container): + def _updateQualityContainer(self, definition, material_container = None): search_criteria = { "type": "quality" } if definition.getMetaDataEntry("has_machine_quality"): From d6acb78bd4c310b5ded6180e6cc17394872672a6 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Sun, 5 Jun 2016 09:59:57 +0100 Subject: [PATCH 128/304] Fixing a typo Had that change locally here, but for a reason I forgot to commit that fix. Oops.. --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index ac95529a5d..8668a746fb 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -90,7 +90,7 @@ class CuraApplication(QtApplication): # Need to do this before ContainerRegistry tries to load the machines SettingDefinition.addSupportedProperty("global_only", DefinitionPropertyType.Function, default = False) - super().__init__(name = "cura", version = CuraVersion, build_type = CuraBuildType) + super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) From c79b7bdd7ad2ed7df481f718c87346a489ba5da9 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 11:34:29 +0200 Subject: [PATCH 129/304] Machine manager now creates ExtruderTrainStacks CURA-340 --- cura/CuraApplication.py | 12 +++++++++--- cura/MachineManagerModel.py | 27 ++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index df72a4208d..729264767e 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -269,9 +269,15 @@ class CuraApplication(QtApplication): continue file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" - path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) - with SaveFile(path, "wt", -1, "utf-8") as f: - f.write(data) + stack_type = stack.getMetaDataEntry("type", None) + path = None + if not stack_type: + path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) + elif stack_type == "extruder": + path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name) + if path: + with SaveFile(path, "wt", -1, "utf-8") as f: + f.write(data) @pyqtSlot(result = QUrl) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3e4c7a0411..c69ddbc3c2 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -33,8 +33,6 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") - - if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) @@ -46,9 +44,15 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() + activeExtrudersChanged = pyqtSignal() + globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed. + @pyqtProperty("QVariantMap", notify = activeExtrudersChanged) + def activeExtruders(self): + return {} + def _onGlobalPropertyChanged(self, key, property_name): if property_name == "value": self.globalValueChanged.emit() @@ -115,7 +119,7 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_instance_container) # If a definition is found, its a list. Should only have one item. - new_global_stack.addContainer(definitions[0]) + new_global_stack.addContainer(definition) if variant_instance_container: new_global_stack.addContainer(variant_instance_container) if material_instance_container: @@ -124,6 +128,23 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) + ## Check if the machine has extruder trains + extruder_trains = definition.getMetaDataEntry("machine_extruder_trains", {}) + for extruder in extruder_trains: + extruder_train_stack = UM.Settings.ContainerStack(name + "_extruder_" + extruder) + extruder_train_stack.addMetaDataEntry("type", "extruder") + extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_trains[extruder]) + if extruder_definitions: + extruder_train_stack.addContainer(extruder_definitions[0]) + current_settings_container_extruder = UM.Settings.InstanceContainer(extruder_train_stack.getName() + "_current_settings") + current_settings_container_extruder.addMetaDataEntry("machine", name) + current_settings_container_extruder.addMetaDataEntry("type", "user") + extruder_train_stack.addContainer(current_settings_container_extruder) + extruder_train_stack.setNextStack(new_global_stack) + UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) + else: + Logger.log("W", "Unable to find definition for extruder") + Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique From 1e44abb9bea42cb1374127be7df46127d954d3cd Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:01:46 +0200 Subject: [PATCH 130/304] Added activeExtruder stack to machineManager model CURA-340 --- cura/MachineManagerModel.py | 26 ++++++++++++++++++++++---- resources/qml/SidebarHeader.qml | 6 +++++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c69ddbc3c2..1134e36a38 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -33,6 +33,8 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") + self._active_extruder_index = 0 + if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) @@ -44,14 +46,28 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - activeExtrudersChanged = pyqtSignal() + activeExtruderChanged = pyqtSignal() globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed. - @pyqtProperty("QVariantMap", notify = activeExtrudersChanged) - def activeExtruders(self): - return {} + @pyqtProperty(str, notify=activeExtruderChanged) + def activeExtruderStackId(self): + return self.extrudersIds[str(self._active_extruder_index)] + + @pyqtSlot(int) + def setActiveExtruderIndex(self, index): + self._active_extruder_index = index + self.activeExtruderChanged.emit() + + @pyqtProperty("QVariantMap", notify = globalContainerChanged) + def extrudersIds(self): + ## Find all extruders that reference the new stack + extruders = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(**{"machine": self._global_container_stack.getId()}) + result = {} + for extruder in extruders: + result[extruder.getMetaDataEntry("position")] = extruder.getId() + return result def _onGlobalPropertyChanged(self, key, property_name): if property_name == "value": @@ -133,6 +149,8 @@ class MachineManagerModel(QObject): for extruder in extruder_trains: extruder_train_stack = UM.Settings.ContainerStack(name + "_extruder_" + extruder) extruder_train_stack.addMetaDataEntry("type", "extruder") + extruder_train_stack.addMetaDataEntry("machine", name) # What global stack is this extruder linked with? + extruder_train_stack.addMetaDataEntry("position", extruder) # What is the position of the extruder (as defined by machine definition) extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_trains[extruder]) if extruder_definitions: extruder_train_stack.addContainer(extruder_definitions[0]) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index bb7aeebae7..61ccbb998d 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -108,7 +108,11 @@ Item exclusiveGroup: extruderMenuGroup; checkable: true; checked: base.currentExtruderIndex == index - onClicked: base.currentExtruderIndex = index + onClicked: + { + base.currentExtruderIndex = index + Cura.MachineManager.setActiveExtruderIndex(index) + } style: ButtonStyle { background: Rectangle { From 783134031bd43b6125fe3c5bd8236a99e2e00121 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:17:35 +0200 Subject: [PATCH 131/304] Settings can now be set by extruder CURA-340 --- cura/MachineManagerModel.py | 1 + resources/qml/Settings/SettingView.qml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 1134e36a38..1423744263 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -157,6 +157,7 @@ class MachineManagerModel(QObject): current_settings_container_extruder = UM.Settings.InstanceContainer(extruder_train_stack.getName() + "_current_settings") current_settings_container_extruder.addMetaDataEntry("machine", name) current_settings_container_extruder.addMetaDataEntry("type", "user") + current_settings_container_extruder.setDefinition(definition) extruder_train_stack.addContainer(current_settings_container_extruder) extruder_train_stack.setNextStack(new_global_stack) UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 1555149d22..7430932b65 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -79,7 +79,7 @@ ScrollView { id: provider - containerStackId: Cura.MachineManager.activeMachineId + containerStackId: Cura.MachineManager.activeExtruderStackId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 From d13b5adda6549064ec9eca0e0f19aa35f73cef79 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 12:22:23 +0200 Subject: [PATCH 132/304] Codestyle & comments CURA-1619 --- cura/PrintInformation.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 22bc562502..47d3989b55 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -51,7 +51,7 @@ class PrintInformation(QObject): self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) currentPrintTimeChanged = pyqtSignal() @@ -99,12 +99,14 @@ class PrintInformation(QObject): else: return base_name - def _onGlobalStackChanged(self): + ## Created an acronymn-like abbreviated machine name from the currently active machine name + # Called each time the global stack is switched + def _setAbbreviatedMachineName(self): global_stack_name = Application.getInstance().getGlobalContainerStack().getName() split_name = global_stack_name.split(" ") abbr_machine = "" for word in split_name: - if(word.lower() == "ultimaker"): + if word.lower() == "ultimaker": abbr_machine += "UM" elif word.isdigit(): abbr_machine += word @@ -113,5 +115,6 @@ class PrintInformation(QObject): self._abbr_machine = abbr_machine + ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, str): return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn') \ No newline at end of file From b63c3086940dfa208ceabb3742d830c1f125b1df Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:45:02 +0200 Subject: [PATCH 133/304] Changed order of loading containers so extruder stacks don't fail anymore CURA-340 --- cura/CuraApplication.py | 4 ++-- cura/MachineManagerModel.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 22ae244286..1198f4523d 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -132,15 +132,15 @@ class CuraApplication(QtApplication): Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality") Resources.addStorageType(self.ResourceTypes.VariantInstanceContainer, "variants") Resources.addStorageType(self.ResourceTypes.MaterialInstanceContainer, "materials") - Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders") Resources.addStorageType(self.ResourceTypes.UserInstanceContainer, "user") + Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders") Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances") ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.VariantInstanceContainer) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MaterialInstanceContainer) - ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.UserInstanceContainer) + ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.ExtruderStack) ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.MachineStack) # Add empty variant, material and quality containers. diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 1423744263..50098dfa1b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -158,6 +158,7 @@ class MachineManagerModel(QObject): current_settings_container_extruder.addMetaDataEntry("machine", name) current_settings_container_extruder.addMetaDataEntry("type", "user") current_settings_container_extruder.setDefinition(definition) + UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_container_extruder) extruder_train_stack.addContainer(current_settings_container_extruder) extruder_train_stack.setNextStack(new_global_stack) UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) From cb742cf7ce749c5f4111f07ab43f4e3160e0ce9d Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Sun, 5 Jun 2016 12:53:41 +0200 Subject: [PATCH 134/304] Fixed saving of machines again --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1198f4523d..a067ae659b 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -271,7 +271,7 @@ class CuraApplication(QtApplication): file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" stack_type = stack.getMetaDataEntry("type", None) path = None - if not stack_type: + if stack_type == "machine": path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) elif stack_type == "extruder": path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name) From ead91db06291dcfa08c2b9ece9275d0a65ba1b95 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 13:54:55 +0200 Subject: [PATCH 135/304] Fix activating another container stack when the currently active stack is removed CURA-1632 --- cura/MachineManagerModel.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 50098dfa1b..a0af119636 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -405,11 +405,13 @@ class MachineManagerModel(QObject): @pyqtSlot(str) def removeMachine(self, machine_id): # If the machine that is being removed is the currently active machine, set another machine as the active machine - if self._global_container_stack and self._global_container_stack.getId() == machine_id: - containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks() - if containers: - Application.getInstance().setGlobalContainerStack(containers[0]) + activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id) UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id) + if activate_new_machine: + stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "machine") + if stacks: + Application.getInstance().setGlobalContainerStack(stacks[0]) + @pyqtProperty(bool, notify = globalContainerChanged) def hasMaterials(self): From c21475abd78a103bfc394e098cd92194a461dd8a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 14:05:56 +0200 Subject: [PATCH 136/304] Prevent multiple machines having the same custom name Caused by container vs containerstack confusion Fixes CURA-1606 and CURA-1649 --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index a0af119636..75b273e1f5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -179,8 +179,8 @@ class MachineManagerModel(QObject): i = 1 # Check both the id and the name, because they may not be the same and it is better if they are both unique - while UM.Settings.ContainerRegistry.getInstance().findContainers(None, id = unique_name) or \ - UM.Settings.ContainerRegistry.getInstance().findContainers(None, name = unique_name): + while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ + UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): i += 1 unique_name = "%s #%d" % (name, i) From 9aa8ca329221f8e8b8b0ec78830eaa34dc97d287 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 5 Jun 2016 16:03:31 +0200 Subject: [PATCH 137/304] Fix uninitialised variable CURA-1619 --- cura/PrintInformation.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index 47d3989b55..f1eb93de0e 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -51,6 +51,8 @@ class PrintInformation(QObject): self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._job_name = "" + self._abbr_machine = "" + Application.getInstance().globalContainerStackChanged.connect(self._setAbbreviatedMachineName) Application.getInstance().fileLoaded.connect(self.setJobName) From d810c7ddbb9d9594ec622b2be9ac372cba4225dc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:00:38 +0200 Subject: [PATCH 138/304] Properly reload extruders at the start The extruder manager was too late to catch the initial global stack switch and machine switch. Now it just always reloads the extruders at the beginning. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 4 +++- cura/ExtrudersModel.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index bfce380a70..46cdeabc91 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -27,6 +27,7 @@ class ExtruderManager: 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. + self._reconnectExtruderReload() ## Gets an instance of this extruder manager. # @@ -51,6 +52,7 @@ class ExtruderManager: self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. 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. + self._reloadExtruders() ## (Re)loads all extruders of the currently active machine. # @@ -66,7 +68,7 @@ class ExtruderManager: #Get the extruder definitions belonging to the current machine. machine = self._global_container_stack.getBottom() extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains") - for extruder_train_id in extruder_train_ids: + for _,extruder_train_id in extruder_train_ids.items(): 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. UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index eb63bc4257..60514e8708 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -53,4 +53,5 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "index": index } self.appendItem(item) + print("Appending extruder " + extruder.name + " to presenter.") self.sort(lambda item: item["index"]) \ No newline at end of file From 9b2acf03174410b09bc6f0e35c3975a5cf507723 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:12:22 +0200 Subject: [PATCH 139/304] Remove print statement Contributes to issues CURA-1278 and CURA-351. --- cura/ExtrudersModel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 60514e8708..eb63bc4257 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -53,5 +53,4 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "index": index } self.appendItem(item) - print("Appending extruder " + extruder.name + " to presenter.") self.sort(lambda item: item["index"]) \ No newline at end of file From b4782e9b122ff4b5eaff134d2e4c7cef25540abb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:13:30 +0200 Subject: [PATCH 140/304] Pass definition to _uniqueName instead of name This function expects the entire definition. Contributes to issueS CURA-1278 and CURA-351. --- cura/Extruder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index 4bbe24183d..f27cd061bd 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -25,7 +25,7 @@ class Extruder: self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) #Create a container stack for this extruder. - self._name = self._uniqueName(self._definition.getId()) + self._name = self._uniqueName(self._definition) self._container_stack = UM.Settings.ContainerStack(self._name) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) From c50d0a97dab3b23042bdd90da889450864f1556e Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:18:09 +0200 Subject: [PATCH 141/304] Load extruder combobox synchronously Asynchronously causes Qt 5.4 to give a segfault. Contributes to issues CURA-351 and CURA-1278. --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- resources/qml/Settings/SettingView.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index d707fe9810..8ab05e90c1 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -56,7 +56,7 @@ Item { //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. - asynchronous: model.type != "enum" + asynchronous: model.type != "enum" && model.type != "extruder" onLoaded: { settingLoader.item.showRevertButton = false diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 7430932b65..1ffc2f939f 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -49,7 +49,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 different options. So disable asynchronous loading of enum type completely. - asynchronous: model.type != "enum" + asynchronous: model.type != "enum" && model.type != "extruder" active: model.type != undefined source: From a948c7bcc67fafbc3e32c593a127eac51cd5b6b2 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 2 Jun 2016 17:29:26 +0200 Subject: [PATCH 142/304] Set colours of extruder selection to material colour Ubuntu Unity doesn't seem to listen to these colours at all though. Contributes to issues CURA-1278 and CURA-351. --- resources/qml/Settings/SettingExtruder.qml | 60 +++++++++++----------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index 86ab728fc1..0160dab7fa 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -16,17 +16,18 @@ SettingItem { id: control - model: Cura.ExtrudersModel { + model: Cura.ExtrudersModel + { id: extruders_model } - textRole: "name"; + textRole: "name" anchors.fill: parent MouseArea { - anchors.fill: parent; - acceptedButtons: Qt.NoButton; + anchors.fill: parent + acceptedButtons: Qt.NoButton onWheel: wheel.accepted = true; } @@ -38,44 +39,44 @@ SettingItem { if (!enabled) { - return UM.Theme.getColor("setting_control_disabled") + return UM.Theme.getColor("setting_control_disabled"); } if(control.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_control_highlight") + return UM.Theme.getColor("setting_control_highlight"); } else { - return UM.Theme.getColor("setting_control") + return extruders_model.getItem(index).colour; } } - 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"); + 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.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; + 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"); + text: control.currentText + font: UM.Theme.getFont("default") + color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : extruders_model.getItem(index).colour - elide: Text.ElideRight; - verticalAlignment: Text.AlignVCenter; + 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; + 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 @@ -83,29 +84,30 @@ SettingItem sourceSize.width: width + 5 sourceSize.height: width + 5 - color: UM.Theme.getColor("setting_control_text"); - + color: UM.Theme.getColor("setting_control_text") } } } - onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index) + onActivated: provider.setPropertyValue("value", extruders_model.getItem(index).index); onModelChanged: updateCurrentIndex(); Connections { target: provider - onPropertiesChanged: control.updateCurrentIndex() + onPropertiesChanged: control.updateCurrentIndex(); } - function updateCurrentIndex() { - for(var i = 0; i < extruders_model.rowCount(); ++i) { - if(extruders_model.getItem(i).index == provider.properties.value) { + 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; } } From e03c3b95c527347c92939257b44d8d450b41c929 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Mon, 6 Jun 2016 06:36:30 +0100 Subject: [PATCH 143/304] Splashscreen: Another (and last) correction Now all the needed changes should be done. --- cura/CuraSplashScreen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraSplashScreen.py b/cura/CuraSplashScreen.py index 8f677986df..f2810d359b 100644 --- a/cura/CuraSplashScreen.py +++ b/cura/CuraSplashScreen.py @@ -23,7 +23,7 @@ class CuraSplashScreen(QSplashScreen): version = Application.getInstance().getVersion().split("-") buildtype = Application.getInstance().getBuildType() if buildtype: - version += " (%s)" %(buildtype) + version[0] += " (%s)" %(buildtype) painter.setFont(QFont("Proxima Nova Rg", 20 )) painter.drawText(0, 0, 330 * self._scale, 230 * self._scale, Qt.AlignHCenter | Qt.AlignBottom, version[0]) From 1171bf112c79f3f3586fb0d030d9dea20db9b961 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Mon, 6 Jun 2016 06:43:07 +0100 Subject: [PATCH 144/304] Ignoring Eclipse+PyDev project files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 72ba4bf565..925de00391 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ resources/i18n/x-test *~ *.qm .idea +.project +.pydevproject From b88f2847ef58cf27b4aab96398ef160a483b9c63 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 08:39:38 +0200 Subject: [PATCH 145/304] Fix saving machine instances to the cura profile CURA-340, see https://github.com/Ultimaker/Cura/commit/c79b7bdd7ad2ed7df481f718c87346a489ba5da9 --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1198f4523d..4f02d2dab5 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -271,7 +271,7 @@ class CuraApplication(QtApplication): file_name = urllib.parse.quote_plus(stack.getId()) + ".stack.cfg" stack_type = stack.getMetaDataEntry("type", None) path = None - if not stack_type: + if not stack_type or stack_type == "machine": path = Resources.getStoragePath(self.ResourceTypes.MachineStack, file_name) elif stack_type == "extruder": path = Resources.getStoragePath(self.ResourceTypes.ExtruderStack, file_name) From a3e5c065727270d5175c6f76d557115ebb17d97b Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Mon, 6 Jun 2016 06:40:34 +0100 Subject: [PATCH 146/304] Adding debian to gitignore Got a link here my packaging files. As Cura does not come with packaging files itself, we can add this ignore here. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 76f470544f..cc21d3092c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ resources/firmware .idea .project .pydevproject + +# Debian packaging +debian/ From c7340c3b21fbf10c36d6ddf9ec96c95e75703eeb Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Jun 2016 10:18:19 +0200 Subject: [PATCH 147/304] Temporary removed multi extruder stack so slicing works again --- 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 7430932b65..1555149d22 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -79,7 +79,7 @@ ScrollView { id: provider - containerStackId: Cura.MachineManager.activeExtruderStackId + containerStackId: Cura.MachineManager.activeMachineId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 From 22857bf3e1599367ac82e0b30e1334658005e7b0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 12:14:10 +0200 Subject: [PATCH 148/304] Disable export profile button when no profile is selected CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index b7261afcec..3f7c696d9d 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -168,9 +168,10 @@ UM.ManagementPage Button { - text: catalog.i18nc("@action:button", "Export"); - iconName: "document-export"; - onClicked: exportDialog.open(); + text: catalog.i18nc("@action:button", "Export") + iconName: "document-export" + onClicked: exportDialog.open() + enabled: currentItem != null } } From 3752a6bbef2f534efc92d7666dc5397f7d0f62f8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 13:02:20 +0200 Subject: [PATCH 149/304] Show rename profile dialog after creating a profile from the profiles dropdown CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 3f7c696d9d..0b57405b56 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -71,6 +71,9 @@ UM.ManagementPage scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) + signal showProfileNameDialog() + onShowProfileNameDialog: { renameDialog.removeWhenRejected = true; renameDialog.open(); renameDialog.selectText(); } + signal selectContainer(string id) onSelectContainer: { objectList.currentIndex = objectList.model.find("id", id); From a139809b75d956773f4a3164f7623a3acdd5ebd0 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 13:39:11 +0200 Subject: [PATCH 150/304] Fix showing profiles created using the dropdown menu in the dropdown and on the profiles manager CURA-1585 --- cura/MachineManagerModel.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 75b273e1f5..3a584a2797 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -289,6 +289,12 @@ class MachineManagerModel(QObject): ## 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.setName(name) From a2db4740b9654fde55f0f811cb33797dc9e63320 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 15:09:21 +0200 Subject: [PATCH 151/304] Fix removing custom (quality) profiles CURA-1585 --- cura/MachineManagerModel.py | 22 +++++++++++++++++++++- resources/qml/Preferences/ProfilesPage.qml | 8 ++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3a584a2797..6e1a6185e7 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -301,7 +301,7 @@ class MachineManagerModel(QObject): new_quality_container._id = name UM.Settings.ContainerRegistry.getInstance().addContainer(new_quality_container) - self.clearUserSettings() # As all users settings are noq a quality, remove them. + self.clearUserSettings() # As all users settings are now transfered to the new quality profile, remove them. self.setActiveQuality(name) return name @@ -325,6 +325,26 @@ class MachineManagerModel(QObject): return "" + + @pyqtSlot(str) + def removeQualityContainer(self, container_id): + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id) + if not containers or not self._global_container_stack: + return + + # If the container that is being removed is the currently active container, set another machine as the active container + activate_new_container = container_id == self.activeQualityId + + UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id) + + if activate_new_container: + old_container = self._global_container_stack.findInstanceContainers({"type": "quality"}) + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = container_type) + if containers and old_container: + container_index = self._global_container_stack.getContainerIndex(old_container) + self._global_container_stack.replaceContainer(container_index, containers[0]) + + @pyqtSlot() def updateUserContainerToQuality(self): if not self._global_container_stack: diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 0b57405b56..f5d3169508 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -66,8 +66,8 @@ UM.ManagementPage activateEnabled: currentItem != null ? currentItem.id != Cura.MachineManager.activeQualityId : false; addEnabled: currentItem != null; - removeEnabled: currentItem != null ? !currentItem.readOnly : false; - renameEnabled: currentItem != null ? !currentItem.readOnly : false; + removeEnabled: currentItem != null ? !currentItem.metadata.read_only : false; + renameEnabled: currentItem != null ? !currentItem.metadata.read_only : false; scrollviewCaption: catalog.i18nc("@label %1 is printer name","Printer: %1").arg(Cura.MachineManager.activeMachineName) @@ -137,7 +137,7 @@ UM.ManagementPage Label { text: base.currentItem == null ? "" : base.currentItem.id == -1 ? Cura.MachineManager.activeQualityName: - base.currentItem.readOnly ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") + base.currentItem.metadata.read_only ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") } Column { @@ -186,7 +186,7 @@ UM.ManagementPage { id: confirmDialog; object: base.currentItem != null ? base.currentItem.name : ""; - onYes: base.model.removeProfile(base.currentItem.name); + onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id); } UM.RenameDialog { From 2660b2a68f892dad154fdcbd034d90a402515ec7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 09:37:25 +0200 Subject: [PATCH 152/304] Give default empty machine_extruder_ids Works also if the machine has no machine_extruder_ids metadata. Contributes to issues CURA-1278 and CURA-351. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 46cdeabc91..7222a1c0f8 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -67,7 +67,7 @@ class ExtruderManager: #Get the extruder definitions belonging to the current machine. machine = self._global_container_stack.getBottom() - extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains") + extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains", { }) for _,extruder_train_id in extruder_train_ids.items(): 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. From 357997c984793edcb06881c29047854154c30823 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 09:40:20 +0200 Subject: [PATCH 153/304] Add user profile to container registry This will allow it to be saved when restarting Cura and such. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index f27cd061bd..1e701f9eaa 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -76,6 +76,7 @@ class Extruder: self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") self._user_profile.addMetaDataEntry("type", "user") self._container_stack.addContainer(self._user_profile) + container_registry.addContainer(self._user_profile) self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) From bfc880b61a42026e78b4afbca2e3937b00d8dbd6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 10:20:59 +0200 Subject: [PATCH 154/304] Add extruder container stack to registry Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/Extruder.py b/cura/Extruder.py index 1e701f9eaa..bfda6db27a 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -27,6 +27,7 @@ class Extruder: #Create a container stack for this extruder. self._name = self._uniqueName(self._definition) self._container_stack = UM.Settings.ContainerStack(self._name) + container_registry.addContainer(self._container_stack) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) From 79c37d667e50d3dd730ade079dfb245a3c614079 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 10:22:47 +0200 Subject: [PATCH 155/304] Add extruder stack only when it's completely built Probably better for concurrency reasons, though that is not a problem yet at this moment. Contributes to issues CURA-1278 and CURA-351. --- cura/Extruder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/Extruder.py b/cura/Extruder.py index bfda6db27a..6418f008c4 100644 --- a/cura/Extruder.py +++ b/cura/Extruder.py @@ -27,7 +27,6 @@ class Extruder: #Create a container stack for this extruder. self._name = self._uniqueName(self._definition) self._container_stack = UM.Settings.ContainerStack(self._name) - container_registry.addContainer(self._container_stack) self._container_stack.addMetaDataEntry("type", "extruder_train") self._container_stack.addContainer(self._definition) @@ -81,6 +80,8 @@ class Extruder: self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + container_registry.addContainer(self._container_stack) + definition_changed = UM.Signal() material_changed = UM.Signal() name_changed = UM.Signal() From 927d33145f227d04fbfce393213e0878bae87cd5 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 13:41:49 +0200 Subject: [PATCH 156/304] Move creating extruder manager logic to ExtruderManager This logic was both in Extruder.py and in MachineManagerModel.py due to a planning mishap. Contributes to issues CURA-1278 and CURA-340. --- cura/CuraApplication.py | 3 + cura/Extruder.py | 211 ------------------------- cura/ExtruderManager.py | 139 ++++++++++++---- cura/MachineManagerModel.py | 31 ---- resources/qml/Settings/SettingView.qml | 2 +- resources/qml/SidebarHeader.qml | 2 +- 6 files changed, 109 insertions(+), 279 deletions(-) delete mode 100644 cura/Extruder.py diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 4f02d2dab5..126d8b2864 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 ExtruderManager from . import ExtrudersModel from . import PlatformPhysics from . import BuildVolume @@ -352,6 +353,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) + qmlRegisterSingletonType(ExtruderManager.ExtruderManager, "Cura", 1, 0, "ExtruderManager", + ExtruderManager.createExtruderManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) diff --git a/cura/Extruder.py b/cura/Extruder.py deleted file mode 100644 index 6418f008c4..0000000000 --- a/cura/Extruder.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright (c) 2016 Ultimaker B.V. -# Cura is released under the terms of the AGPLv3 or higher. - -import re #To parse container registry names to increment the duplicates-resolving number. - -import UM.Application #To link the stack to the global container stack. -import UM.Logger -import UM.Settings.ContainerRegistry #To search for nozzles, materials, etc. -import UM.Settings.ContainerStack #To create a container stack for this extruder. -import UM.Signal #To notify people of changing extruder stacks. - -class Extruder: - ## Creates a new extruder from the specified definition container. - # - # \param definition The definition container defining this extruder. - def __init__(self, definition): - self._definition = definition - - container_registry = UM.Settings.ContainerRegistry.getInstance() - - #Find the nozzles that fit on this extruder. - self._nozzles = container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId() + ",*") #Extruder needs to be delimited by either a comma or the end of string. - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = "*," + self._definition.getId()) - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId() + ",*") - self._nozzles += container_registry.findInstanceContainers(type = "nozzle", definitions = self._definition.getId()) - - #Create a container stack for this extruder. - self._name = self._uniqueName(self._definition) - self._container_stack = UM.Settings.ContainerStack(self._name) - self._container_stack.addMetaDataEntry("type", "extruder_train") - self._container_stack.addContainer(self._definition) - - #Find the nozzle to use for this extruder. - self._nozzle = container_registry.getEmptyInstanceContainer() - if self._definition.getMetaDataEntry("has_nozzles", default = "False") == "True": - if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid. - self._nozzle = self._nozzles[0] - preferred_nozzle_id = self._definition.getMetaDataEntry("preferred_nozzle") - if preferred_nozzle_id: - for nozzle in self._nozzles: - if nozzle.getId() == preferred_nozzle_id: - self._nozzle = nozzle - break - self._container_stack.addContainer(self._nozzle) - - #Find a material to use for this nozzle. - self._material = container_registry.getEmptyInstanceContainer() - if self._definition.getMetaDataEntry("has_materials", default = "False") == "True": - if self._definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True": - all_materials = container_registry.findInstanceContainers(type = "material", nozzle = self._nozzle.getId()) - else: - all_materials = container_registry.findInstanceContainers(type = "material") - if len(all_materials) >= 1: - self._material = all_materials[0] - preferred_material_id = self._definition.getMetaDataEntry("preferred_material") - if preferred_material_id: - preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower()) - if len(preferred_material) >= 1: - self._material = preferred_material[0] - self._container_stack.addContainer(self._material) - - #Find a quality to use for this extruder. - self._quality = container_registry.getEmptyInstanceContainer() - if self._definition.getMetaDataEntry("has_machine_quality"): - all_qualities = container_registry.findInstanceContainers(type = "quality") - if len(all_qualities) >= 1: - self._quality = all_qualities[0] - preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality") - if preferred_quality_id: - preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower()) - if len(preferred_quality) >= 1: - self._quality = preferred_quality[0] - self._container_stack.addContainer(self._quality) - - #Add an empty user profile. - self._user_profile = UM.Settings.InstanceContainer(self._name + "_current_settings") - self._user_profile.addMetaDataEntry("type", "user") - self._container_stack.addContainer(self._user_profile) - container_registry.addContainer(self._user_profile) - - self._container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) - - container_registry.addContainer(self._container_stack) - - 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. - @property - def material(self): - return self._material - - ## Changes the currently active material in this extruder. - # - # \param value The new material to extrude through this extruder. - @material.setter - def material(self, value): - try: - position = self._container_stack.index(self._material) - except ValueError: #Material is not in the list. - UM.Logger.log("e", "I've lost my old material, so I can't find where to insert the new material.") - return - self._container_stack.replaceContainer(position, value) - 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. - # - # \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. - # - # \return The currently active nozzle on this extruder. - @property - def nozzle(self): - return self._nozzle - - ## Changes the currently active nozzle on this extruder. - # - # \param value The new nozzle to use with this extruder. - @nozzle.setter - def nozzle(self, value): - try: - position = self._container_stack.index(self._nozzle) - except ValueError: #Nozzle is not in the list. - UM.Logger.log("e", "I've lost my old nozzle, so I can't find where to insert the new nozzle.") - return - self._container_stack.replaceContainer(position, value) - self._nozzle = value - self.nozzle_changed.emit() - - ## Gets the currently active quality on this extruder. - # - # \return The currently active quality on this extruder. - @property - def quality(self): - return self._quality - - ## Changes the currently active quality to use with this extruder. - # - # \param value The new quality to use with this extruder. - @quality.setter - def quality(self, value): - try: - position = self._container_stack.index(self._quality) - except ValueError: #Quality is not in the list. - UM.Logger.log("e", "I've lost my old quality, so I can't find where to insert the new quality.") - return - self._container_stack.replaceContainer(position, value) - self._quality = value - self.quality_changed.emit() - - ## Finds a unique name for an extruder stack. - # - # \param extruder An extruder definition to design a name for. - # \return A name for an extruder stack that is unique and reasonably - # human-readable. - def _uniqueName(self, extruder): - container_registry = UM.Settings.ContainerRegistry.getInstance() - - name = extruder.getName().strip() - num_check = re.compile("(.*?)\s*#\d$").match(name) - if num_check: #There is a number in the name. - name = num_check.group(1) #Filter out the number. - if name == "": #Wait, that deleted everything! - name = "Extruder" - unique_name = name - - i = 1 - while container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name): #A container already has this name. - i += 1 #Try next numbering. - unique_name = "%s #%d" % (name, i) #Fill name like this: "Extruder #2". - return unique_name \ No newline at end of file diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 7222a1c0f8..4f23a01808 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,7 +1,8 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from cura.Extruder import Extruder #The individual extruders managed by this manager. +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject + 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. @@ -13,21 +14,24 @@ import UM.Signal #To notify other components of changes in the extruders. # This finds the extruders that are available for the currently active machine # 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: +class ExtruderManager(QObject): ## 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. - self._global_container_stack = None - self._next_item = 0 #For when you use this class as iterator. + ## Notify when the user switches the currently active extruder. + activeExtruderChanged = pyqtSignal() - UM.Application.getInstance().globalContainerStackChanged.connect(self._reconnectExtruderReload) #When the current machine changes, we need to reload all extruders belonging to the new machine. - self._reconnectExtruderReload() + ## Registers listeners and such to listen to changes to the extruders. + def __init__(self, parent = None): + super().__init__(parent) + self._extruder_trains = { } #Extruders for the current machine. + self._next_item = 0 #For when you use this class as iterator. + self._active_extruder_index = 0 + + self._repopulate() ## Gets an instance of this extruder manager. # @@ -45,34 +49,99 @@ class ExtruderManager: 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): - if self._global_container_stack: - self._global_container_stack.containersChanged.disconnect(self._reloadExtruders) #Disconnect from the old global container stack. - 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. - self._reloadExtruders() + @pyqtProperty(str, notify = activeExtruderChanged) + def activeExtruderStackId(self): + if UM.Application.getInstance().getGlobalContainerStack(): + try: + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] + except KeyError: + pass - ## (Re)loads all extruders of the currently active machine. - # - # 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, *args): - self._extruders = [] - if not self._global_container_stack: #No machine has been added yet. + @pyqtSlot(int) + def setActiveExtruderIndex(self, index): + self._active_extruder_index = index + self.activeExtruderChanged.emit() + + ## (Re)populates the collections of extruders by machine. + def _repopulate(self): + self._extruder_trains = { } + if not UM.Application.getInstance().getGlobalContainerStack(): #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. - machine = self._global_container_stack.getBottom() - extruder_train_ids = machine.getMetaDataEntry("machine_extruder_trains", { }) - for _,extruder_train_id in extruder_train_ids.items(): - 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. - UM.Logger.log("w", "Machine definition %s refers to an extruder train \"%s\", but no such extruder was found.", machine.getId(), extruder_train_id) + extruder_trains = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "extruder_train") + for extruder_train in extruder_trains: + machine_id = extruder_train.getMetaDataEntry("machine") + if not machine_id: continue - for extruder_definition in extruder_definitions: - self._extruders.append(Extruder(extruder_definition)) - self.extrudersChanged.emit() \ No newline at end of file + if machine_id not in self._extruder_trains: + self._extruder_trains[machine_id] = { } + self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() + self.extrudersChanged.emit() + + def createExtruderTrain(self, definition, extruder_id): + container_registry = UM.Settings.ContainerRegistry.getInstance() + + #Create a container stack for this extruder. + name = self._uniqueName(extruder_id) + container_stack = UM.Settings.ContainerStack(name) + container_stack.addMetaDataEntry("type", "extruder_train") + container_stack.addContainer(definition) + + """ + Yes, I'm committing this code which needs to be transformed to work later. + #Find the nozzle to use for this extruder. + nozzle = container_registry.getEmptyInstanceContainer() + if definition.getMetaDataEntry("has_nozzles", default = "False") == "True": + if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid. + self._nozzle = self._nozzles[0] + preferred_nozzle_id = definition.getMetaDataEntry("preferred_nozzle") + if preferred_nozzle_id: + for nozzle in self._nozzles: + if nozzle.getId() == preferred_nozzle_id: + self._nozzle = nozzle + break + self._container_stack.addContainer(self._nozzle) + + #Find a material to use for this nozzle. + self._material = container_registry.getEmptyInstanceContainer() + if self._definition.getMetaDataEntry("has_materials", default = "False") == "True": + if self._definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True": + all_materials = container_registry.findInstanceContainers(type = "material", nozzle = self._nozzle.getId()) + else: + all_materials = container_registry.findInstanceContainers(type = "material") + if len(all_materials) >= 1: + self._material = all_materials[0] + preferred_material_id = self._definition.getMetaDataEntry("preferred_material") + if preferred_material_id: + preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower()) + if len(preferred_material) >= 1: + self._material = preferred_material[0] + self._container_stack.addContainer(self._material) + + #Find a quality to use for this extruder. + self._quality = container_registry.getEmptyInstanceContainer() + if self._definition.getMetaDataEntry("has_machine_quality"): + all_qualities = container_registry.findInstanceContainers(type = "quality") + if len(all_qualities) >= 1: + self._quality = all_qualities[0] + preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality") + if preferred_quality_id: + preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower()) + if len(preferred_quality) >= 1: + self._quality = preferred_quality[0] + self._container_stack.addContainer(self._quality) + """ + + #Add an empty user profile. + user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + user_profile.addMetaDataEntry("type", "user") + container_stack.addContainer(user_profile) + container_registry.addContainer(user_profile) + + container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) + + container_registry.addContainer(container_stack) + +def createExtruderManager(engine, script_engine): + return ExtruderManager() \ No newline at end of file diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3a584a2797..3515d613bd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -46,20 +46,9 @@ class MachineManagerModel(QObject): activeVariantChanged = pyqtSignal() activeQualityChanged = pyqtSignal() - activeExtruderChanged = pyqtSignal() - globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed. globalValidationChanged = pyqtSignal() # Emitted whenever a validation inside global container is changed. - @pyqtProperty(str, notify=activeExtruderChanged) - def activeExtruderStackId(self): - return self.extrudersIds[str(self._active_extruder_index)] - - @pyqtSlot(int) - def setActiveExtruderIndex(self, index): - self._active_extruder_index = index - self.activeExtruderChanged.emit() - @pyqtProperty("QVariantMap", notify = globalContainerChanged) def extrudersIds(self): ## Find all extruders that reference the new stack @@ -145,26 +134,6 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(current_settings_instance_container) ## Check if the machine has extruder trains - extruder_trains = definition.getMetaDataEntry("machine_extruder_trains", {}) - for extruder in extruder_trains: - extruder_train_stack = UM.Settings.ContainerStack(name + "_extruder_" + extruder) - extruder_train_stack.addMetaDataEntry("type", "extruder") - extruder_train_stack.addMetaDataEntry("machine", name) # What global stack is this extruder linked with? - extruder_train_stack.addMetaDataEntry("position", extruder) # What is the position of the extruder (as defined by machine definition) - extruder_definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=extruder_trains[extruder]) - if extruder_definitions: - extruder_train_stack.addContainer(extruder_definitions[0]) - current_settings_container_extruder = UM.Settings.InstanceContainer(extruder_train_stack.getName() + "_current_settings") - current_settings_container_extruder.addMetaDataEntry("machine", name) - current_settings_container_extruder.addMetaDataEntry("type", "user") - current_settings_container_extruder.setDefinition(definition) - UM.Settings.ContainerRegistry.getInstance().addContainer(current_settings_container_extruder) - extruder_train_stack.addContainer(current_settings_container_extruder) - extruder_train_stack.setNextStack(new_global_stack) - UM.Settings.ContainerRegistry.getInstance().addContainer(extruder_train_stack) - else: - Logger.log("W", "Unable to find definition for extruder") - Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 0eb13d668c..2e62280865 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -79,7 +79,7 @@ ScrollView { id: provider - containerStackId: Cura.MachineManager.activeMachineId + containerStackId: Cura.ExtruderManager.activeExtruderStackId ? Cura.ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 61ccbb998d..b38f65772d 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -111,7 +111,7 @@ Item onClicked: { base.currentExtruderIndex = index - Cura.MachineManager.setActiveExtruderIndex(index) + Cura.ExtruderManager.setActiveExtruderIndex(index) } style: ButtonStyle { From d1be5b6c029d5764436226b53461b1ef600cda46 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:17:00 +0200 Subject: [PATCH 157/304] Create extruder train for each train in a machine We had the functionality, but this function was not yet called! Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 5 +++-- cura/MachineManagerModel.py | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 4f23a01808..ccf8a3ad40 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -79,14 +79,14 @@ class ExtruderManager(QObject): self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() self.extrudersChanged.emit() - def createExtruderTrain(self, definition, extruder_id): + def createExtruderTrain(self, extruder_definition, machine_definition, extruder_id): container_registry = UM.Settings.ContainerRegistry.getInstance() #Create a container stack for this extruder. name = self._uniqueName(extruder_id) container_stack = UM.Settings.ContainerStack(name) container_stack.addMetaDataEntry("type", "extruder_train") - container_stack.addContainer(definition) + container_stack.addContainer(extruder_definition) """ Yes, I'm committing this code which needs to be transformed to work later. @@ -136,6 +136,7 @@ class ExtruderManager(QObject): #Add an empty user profile. user_profile = UM.Settings.InstanceContainer(name + "_current_settings") user_profile.addMetaDataEntry("type", "user") + user_profile.setDefinition(machine_definition) container_stack.addContainer(user_profile) container_registry.addContainer(user_profile) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 3515d613bd..5e811e603d 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,7 +9,7 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer - +from . import ExtruderManager class MachineManagerModel(QObject): def __init__(self, parent = None): @@ -133,7 +133,15 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - ## Check if the machine has extruder trains + for position, extruder_train_id in definitions.getMetaDataEntry("machine_extruder_trains", default = {}).items(): + extruder_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) + if extruder_definition: + extruder_definition = extruder_definition[0] + else: + Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", definition.getName(), extruder_train_id) + continue + ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) + Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique From 70e6c8093ed56db8bcb50b40a140d7ffe5e4d0da Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:19:18 +0200 Subject: [PATCH 158/304] Explicitly return None if no global container stack That's what it does. This is more clear than doing 'pass' or something. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index ccf8a3ad40..ff29165df5 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -51,11 +51,12 @@ class ExtruderManager(QObject): @pyqtProperty(str, notify = activeExtruderChanged) def activeExtruderStackId(self): - if UM.Application.getInstance().getGlobalContainerStack(): - try: - return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] - except KeyError: - pass + if not UM.Application.getInstance().getGlobalContainerStack(): + return None #Whatta ya gonna do? + try: + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] + except KeyError: + return None @pyqtSlot(int) def setActiveExtruderIndex(self, index): From 7950dfaa072bf9208b5c25551e46bac7bb29e011 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:31:02 +0200 Subject: [PATCH 159/304] Document activeExtruderStackId Contributes to issues CURA-340, CURA-351 and CURA-1278. --- cura/ExtruderManager.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index ff29165df5..369eb33d51 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -49,13 +49,19 @@ class ExtruderManager(QObject): def __iter__(self): return iter(self._extruders) + ## Gets the unique identifier of the currently active extruder stack. + # + # The currently active extruder stack is the stack that is currently being + # edited. + # + # \return The unique ID of the currently active extruder stack. @pyqtProperty(str, notify = activeExtruderChanged) def activeExtruderStackId(self): if not UM.Application.getInstance().getGlobalContainerStack(): - return None #Whatta ya gonna do? + return None #No active machine, so no active extruder. try: return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)] - except KeyError: + 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 @pyqtSlot(int) From 77c918a0a7c92a98e499fb0dba22a4e193fac16f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:32:20 +0200 Subject: [PATCH 160/304] Remove superfluous singleton pattern The qmlRegisterSingletonType function already makes sure it is a singleton. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 369eb33d51..9785c51c2c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -15,9 +15,6 @@ import UM.Signal #To notify other components of changes in the extruders. # 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(QObject): - ## The singleton instance of this manager. - __instance = None - ## Signal to notify other components when the list of extruders changes. extrudersChanged = UM.Signal() @@ -33,16 +30,6 @@ class ExtruderManager(QObject): self._repopulate() - ## 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 - ## Creates an iterator over the extruders in this manager. # # \return An iterator over the extruders in this manager. From 64c92caa58b410ab39c9306747d004568ad5ed5f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 14:48:55 +0200 Subject: [PATCH 161/304] Update documentation of ExtruderManager class Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 9785c51c2c..11cd6d70cc 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -9,11 +9,9 @@ import UM.Settings.ContainerRegistry #Finding containers by ID. import UM.Signal #To notify other components of changes in the extruders. -## Class that handles the current extruder stack. +## Manages all existing extruder stacks. # -# This finds the extruders that are available for the currently active machine -# 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. +# This keeps a list of extruder stacks for each machine. class ExtruderManager(QObject): ## Signal to notify other components when the list of extruders changes. extrudersChanged = UM.Signal() From 84a91662417dfb38323d878f5cfc4b15cfed1b28 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 6 Jun 2016 15:06:36 +0200 Subject: [PATCH 162/304] Make extrudersChanged into a pyqtSignal This way we can listen for it on the cute side. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 11cd6d70cc..b35243df05 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -1,12 +1,11 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt. 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. ## Manages all existing extruder stacks. @@ -14,7 +13,7 @@ import UM.Signal #To notify other components of changes in the extruders. # This keeps a list of extruder stacks for each machine. class ExtruderManager(QObject): ## Signal to notify other components when the list of extruders changes. - extrudersChanged = UM.Signal() + extrudersChanged = pyqtSignal() ## Notify when the user switches the currently active extruder. activeExtruderChanged = pyqtSignal() From 0b57728d9d7042fff3b5d694732b09a697564779 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 15:55:14 +0200 Subject: [PATCH 163/304] Fix creating a unique name for profiles CURA-1585 --- cura/MachineManagerModel.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6e1a6185e7..4deea99afc 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,7 +9,8 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer - +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") class MachineManagerModel(QObject): def __init__(self, parent = None): @@ -118,7 +119,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueStackName(name, definition.getName()) + name = self._createUniqueName("machine", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -168,7 +169,7 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) # Create a name that is not empty and unique - def _createUniqueStackName(self, name, fallback_name): + def _createUniqueName(self, object_type, name, fallback_name): name = name.strip() num_check = re.compile("(.*?)\s*#\d$").match(name) if(num_check): @@ -179,10 +180,16 @@ class MachineManagerModel(QObject): i = 1 # Check both the id and the name, because they may not be the same and it is better if they are both unique - while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ - UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): - i += 1 - unique_name = "%s #%d" % (name, i) + if object_type == "machine": + while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ + UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): + i += 1 + unique_name = "%s #%d" % (name, i) + else: + while UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = unique_name, type = object_type) or \ + UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = unique_name, type = object_type): + i += 1 + unique_name = "%s #%d" % (name, i) return unique_name @@ -282,7 +289,7 @@ class MachineManagerModel(QObject): if not self._global_container_stack: return - name = self._createUniqueStackName("Custom profile", "") + name = self._createUniqueName("quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) user_settings = self._global_container_stack.getTop() new_quality_container = InstanceContainer("") @@ -311,7 +318,7 @@ class MachineManagerModel(QObject): return containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: - new_name = self._createUniqueStackName(containers[0].getName(), "") + new_name = self._createUniqueName("quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -424,7 +431,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueStackName(new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName("machine", new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From df71269f8244ed4c3e15b32a20af241df4463384 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 15:56:45 +0200 Subject: [PATCH 164/304] Mark custom profiles as not read-only CURA-1585 --- cura/MachineManagerModel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 4deea99afc..ad7669b43a 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -303,7 +303,8 @@ class MachineManagerModel(QObject): 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("type", "quality") + new_quality_container.setMetaDataEntry("read_only", False) new_quality_container.setName(name) new_quality_container._id = name From 03914674c7f105be37a3a7dc222a9659c3d741f4 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Mon, 6 Jun 2016 16:03:16 +0200 Subject: [PATCH 165/304] Cache all of the settings list items instead of recreating them all the time. Fixes CURA-1630 Settings disappear after selecting all options of Experimental Modes --- resources/qml/Settings/SettingView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 0eb13d668c..ba7b5e32a9 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -24,6 +24,7 @@ ScrollView { id: contents spacing: UM.Theme.getSize("default_lining").height; + cacheBuffer: 1000000; // A huge to cache to effectively cache everything. model: UM.SettingDefinitionsModel { id: definitionsModel; From a2def606c68b1d91fbe15c0dca8ff4fdd3968424 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 17:10:56 +0200 Subject: [PATCH 166/304] Fix Profile (application-)menu and add separators to profiles dropdown CURA-1585 --- resources/qml/Cura.qml | 43 ++++++++++++++++++++-------------- resources/qml/ProfileSetup.qml | 18 ++++---------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 851e7c984f..46ebc25369 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -226,7 +226,26 @@ UM.MainWindow Instantiator { id: profileMenuInstantiator -// model: UM.ProfilesModel {} + 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 { @@ -239,13 +258,13 @@ UM.MainWindow { //Insert a separator between readonly and custom profiles if(separatorIndex < 0 && index > 0) { - if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) { + if(model.getItem(index-1).metadata.read_only != model.getItem(index).metadata.read_only) { profileMenu.insertSeparator(index); separatorIndex = index; } } //Because of the separator, custom profiles move one index lower - profileMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item); + profileMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item); } onObjectRemoved: { @@ -269,20 +288,10 @@ UM.MainWindow { id: item text: model_data ? model_data.name : "" - checkable: true; - checked: model_data ? model_data.active : false; - exclusiveGroup: profileMenuGroup; - onTriggered: - { - UM.MachineManager.setActiveProfile(model_data.name); - if (!model_data.active) { - //Selecting a profile was canceled; undo menu selection - profileMenuInstantiator.model.setProperty(model_index, "active", false); - var activeProfileName = UM.MachineManager.activeProfile; - var activeProfileIndex = profileMenuInstantiator.model.find("name", activeProfileName); - profileMenuInstantiator.model.setProperty(activeProfileIndex, "active", true); - } - } + checkable: true + checked: Cura.MachineManager.activeQualityId == model_data.id + exclusiveGroup: profileMenuGroup + onTriggered: Cura.MachineManager.setActiveQuality(model_data.id) } } diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index 3175a4e2b3..c6291c8c85 100644 --- a/resources/qml/ProfileSetup.qml +++ b/resources/qml/ProfileSetup.qml @@ -88,13 +88,13 @@ Item{ { //Insert a separator between readonly and custom profiles if(separatorIndex < 0 && index > 0) { - if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) { + 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).readOnly) ? index : index + 1, object.item); + profileSelectionMenu.insertItem((model.getItem(index).metadata.read_only) ? index : index + 1, object.item); } onObjectRemoved: { @@ -117,20 +117,10 @@ Item{ { id: item text: model_data ? model_data.name : "" - checkable: true; + checkable: true checked: Cura.MachineManager.activeQualityId == model_data.id exclusiveGroup: profileSelectionMenuGroup; - onTriggered: - { - Cura.MachineManager.setActiveQuality(model_data.id); - /*if (!model_data.active) { - //Selecting a profile was canceled; undo menu selection - profileSelectionInstantiator.model.setProperty(model_index, "active", false); - var activeProfileName = UM.MachineManager.activeProfile; - var activeProfileIndex = profileSelectionInstantiator.model.find("name", activeProfileName); - profileSelectionInstantiator.model.setProperty(activeProfileIndex, "active", true); - }*/ - } + onTriggered: Cura.MachineManager.setActiveQuality(model_data.id) } } From 5235f74adfc68420587a3e0d570a3ff3bc66ec5a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 17:47:33 +0200 Subject: [PATCH 167/304] Prevent unique names like "profile #10 #2" CURA-1606, CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e57294d871..6d6ff10a4b 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -149,7 +149,7 @@ class MachineManagerModel(QObject): # Create a name that is not empty and unique def _createUniqueName(self, object_type, name, fallback_name): name = name.strip() - num_check = re.compile("(.*?)\s*#\d$").match(name) + num_check = re.compile("(.*?)\s*#\d+$").match(name) if(num_check): name = num_check.group(1) if name == "": From efe3f5e4ee08c3dea2104dc35b29c0b7bc408d4a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 17:53:34 +0200 Subject: [PATCH 168/304] Remove dependency on QtQml.Models CURA-1278 --- resources/qml/GeneralPage.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/GeneralPage.qml b/resources/qml/GeneralPage.qml index dcd5c66d73..0ae783916b 100644 --- a/resources/qml/GeneralPage.qml +++ b/resources/qml/GeneralPage.qml @@ -5,7 +5,6 @@ import QtQuick 2.1 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.1 -import QtQml.Models 2.2 import UM 1.1 as UM @@ -207,10 +206,11 @@ UM.PreferencesPage } } - DelegateModel + ListView { id: plugins model: UM.PluginsModel { } + visible: false } } } From 35706734e696ca0c360c4f607b81be21ea6736d3 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Mon, 6 Jun 2016 23:13:25 +0200 Subject: [PATCH 169/304] Show settings on Profile page CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index f5d3169508..52ab10cfd6 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -144,7 +144,7 @@ UM.ManagementPage Repeater { model: base.currentItem ? base.currentItem.settings : null Label { - text: modelData.name.toString(); + text: modelData.label elide: Text.ElideMiddle; } } From 05643eca11e8c4cd58645d519db67ad90a4bf4e7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 08:11:53 +0200 Subject: [PATCH 170/304] Fix renaming profiles from the Profiles page CURA-1585 --- cura/MachineManagerModel.py | 9 +++++++++ resources/qml/Preferences/ProfilesPage.qml | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6d6ff10a4b..6e0e0a6127 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -312,6 +312,15 @@ 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("machine", new_name, catalog.i18nc("@label", "Custom profile")) + containers[0].setName(new_name) + UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) + + @pyqtSlot(str) def removeQualityContainer(self, container_id): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 52ab10cfd6..c031ed9f20 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -184,19 +184,19 @@ UM.ManagementPage UM.ConfirmRemoveDialog { - id: confirmDialog; - object: base.currentItem != null ? base.currentItem.name : ""; - onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id); + id: confirmDialog + object: base.currentItem != null ? base.currentItem.name : "" + onYes: Cura.MachineManager.removeQualityContainer(base.currentItem.id) } UM.RenameDialog { id: renameDialog; - object: base.currentItem != null ? base.currentItem.name : ""; - property bool removeWhenRejected: false; - onAccepted: base.model.rename(base.currentItem.id, newName.trim()); + object: base.currentItem != null ? base.currentItem.name : "" + property bool removeWhenRejected: false + onAccepted: Cura.MachineManager.renameQualityContainer(base.currentItem.id, newName) onRejected: { if(removeWhenRejected) { - base.model.removeProfile(base.currentItem.name) + Cura.MachineManager.removeQualityContainer(base.currentItem.id) } } } From 0a84867132f899288be59a72ba17b810e81fce87 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 09:33:29 +0200 Subject: [PATCH 171/304] Fixed multiple typos / missing things in extrudermanager --- cura/ExtruderManager.py | 28 ++++++++++++++++++++++++++++ cura/MachineManagerModel.py | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b35243df05..aae90afdc5 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -6,6 +6,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For commun 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 re ## Manages all existing extruder stacks. @@ -48,6 +49,13 @@ class ExtruderManager(QObject): 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 + __instance = None + @classmethod + def getInstance(cls): + if not cls.__instance: + cls.__instance = ExtruderManager() + return cls.__instance + @pyqtSlot(int) def setActiveExtruderIndex(self, index): self._active_extruder_index = index @@ -135,5 +143,25 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) + + def _uniqueName(self, extruder): + container_registry = UM.Settings.ContainerRegistry.getInstance() + + name = extruder.strip() + num_check = re.compile("(.*?)\s*#\d$").match(name) + if num_check: # There is a number in the name. + name = num_check.group(1) # Filter out the number. + if name == "": # Wait, that deleted everything! + name = "Extruder" + unique_name = name + + i = 1 + while container_registry.findContainers(id=unique_name) or container_registry.findContainers( + name=unique_name): # A container already has this name. + i += 1 # Try next numbering. + unique_name = "%s #%d" % (name, i) # Fill name like this: "Extruder #2". + return unique_name + + def createExtruderManager(engine, script_engine): return ExtruderManager() \ No newline at end of file diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6d6ff10a4b..e2c097daf5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -135,14 +135,14 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - for position, extruder_train_id in definitions.getMetaDataEntry("machine_extruder_trains", default = {}).items(): + for position, extruder_train_id in definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): extruder_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) if extruder_definition: extruder_definition = extruder_definition[0] else: Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", definition.getName(), extruder_train_id) continue - ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) + ExtruderManager.ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) Application.getInstance().setGlobalContainerStack(new_global_stack) From a6870b555b644f2fa91ea313f010551d4f64b61a Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Tue, 7 Jun 2016 10:34:08 +0200 Subject: [PATCH 172/304] Fix up my comment, make it clearer. Fixes CURA-1630 Settings disappear after selecting all options of Experimental Modes --- 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 ed66661a8e..7191bff3ef 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -24,7 +24,7 @@ ScrollView { id: contents spacing: UM.Theme.getSize("default_lining").height; - cacheBuffer: 1000000; // A huge to cache to effectively cache everything. + cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item. model: UM.SettingDefinitionsModel { id: definitionsModel; From ce388c4b231aaedc8377668b6c27cdc9d7ed96d8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 11:18:09 +0200 Subject: [PATCH 173/304] Show settings in profile as a sorted list with section headers CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 103 ++++++++++----------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index c031ed9f20..28248b23f4 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -91,70 +91,63 @@ UM.ManagementPage elide: Text.ElideRight } - ScrollView { + Row { + id: currentSettingsActions + visible: base.currentItem.id == -1 || currentItem.id == Cura.MachineManager.activeQualityId + anchors.left: parent.left anchors.top: profileName.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height + + 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)); + } + enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) + onClicked: Cura.MachineManager.updateUserContainerToQuality() + } + + Button + { + text: catalog.i18nc("@action:button", "Discard changes"); + enabled: Cura.MachineManager.hasUserSettings + onClicked: Cura.MachineManager.clearUserSettings(); + } + } + + ScrollView { + id: scrollView + + anchors.left: parent.left + anchors.top: currentSettingsActions.visible ? currentSettingsActions.bottom : profileName.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.right: parent.right anchors.bottom: parent.bottom - Column - { - spacing: UM.Theme.getSize("default_margin").height - - Row - { - visible: base.currentItem.id == -1 || currentItem.id == Cura.MachineManager.activeQualityId - 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)); - } - enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) - onClicked: Cura.MachineManager.updateUserContainerToQuality() + ListView { + model: base.currentItem ? base.currentItem.settings: null + delegate: Row { + spacing: UM.Theme.getSize("default_margin").width + Label { + text: model.label + elide: Text.ElideMiddle + width: scrollView.width / 100 * 40 } - - Button - { - text: catalog.i18nc("@action:button", "Discard changes"); - enabled: Cura.MachineManager.hasUserSettings - onClicked: Cura.MachineManager.clearUserSettings(); + Label { + text: model.value.toString() + } + Label { + text: model.unit } } - - Grid - { - id: containerGrid - columns: 2 - spacing: UM.Theme.getSize("default_margin").width - - Label { - text: base.currentItem == null ? "" : - base.currentItem.id == -1 ? catalog.i18nc("@label", "Based on") : catalog.i18nc("@label", "Profile type") - } - Label { - text: base.currentItem == null ? "" : - base.currentItem.id == -1 ? Cura.MachineManager.activeQualityName: - base.currentItem.metadata.read_only ? catalog.i18nc("@label", "Protected profile") : catalog.i18nc("@label", "Custom profile") - } - - Column { - Repeater { - model: base.currentItem ? base.currentItem.settings : null - Label { - text: modelData.label - elide: Text.ElideMiddle; - } - } - } - Column { - Repeater { - model: base.currentItem ? base.currentItem.settings : null - Label { text: modelData.value.toString(); } - } - } + section.property: "category" + section.criteria: ViewSection.FullString + section.delegate: Label { + text: section + font.bold: true } } } From 889844e34bfd5733aa23e58a392ca9f2f031cfd3 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 7 Jun 2016 11:39:23 +0200 Subject: [PATCH 174/304] profiles: speed changes (extra overrides) (CURA-1662) --- resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile | 2 ++ resources/profiles/ultimaker2+/abs_0.4_high.curaprofile | 1 + resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile | 1 + resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile | 1 + resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile | 1 + resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile | 1 + resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile | 1 + resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile | 2 ++ resources/profiles/ultimaker2+/pla_0.4_high.curaprofile | 1 + resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile | 1 + resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile | 3 +++ resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile | 1 + 12 files changed, 16 insertions(+) diff --git a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile index 50018372b5..96e99f8a3d 100644 --- a/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile +++ b/resources/profiles/ultimaker2+/abs_0.4_fast.curaprofile @@ -12,6 +12,8 @@ wall_thickness = 0.7 top_bottom_thickness = 0.75 infill_sparse_density = 18 speed_print = 55 +speed_wall = 40 +speed_topbottom = 30 speed_travel = 150 speed_layer_0 = 30 cool_min_layer_time = 3 diff --git a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile index 341c9cc34f..66a72e17bf 100644 --- a/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile +++ b/resources/profiles/ultimaker2+/abs_0.4_high.curaprofile @@ -12,6 +12,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.72 infill_sparse_density = 22 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 3 cool_fan_speed_min = 20 cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile index d8fce8a4dd..c6baaf448e 100644 --- a/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile +++ b/resources/profiles/ultimaker2+/abs_0.4_normal.curaprofile @@ -12,6 +12,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.8 infill_sparse_density = 20 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 3 cool_fan_speed_min = 20 cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile index 5512450471..9699b4e0c9 100644 --- a/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile +++ b/resources/profiles/ultimaker2+/abs_0.6_normal.curaprofile @@ -12,6 +12,7 @@ wall_thickness = 1.59 top_bottom_thickness = 1.2 infill_sparse_density = 20 speed_print = 40 +speed_infill = 55 cool_min_layer_time = 3 cool_fan_speed_min = 50 cool_min_speed = 20 diff --git a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile index f9050e5ce5..550b8f46e3 100644 --- a/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile +++ b/resources/profiles/ultimaker2+/cpe_0.4_fast.curaprofile @@ -12,6 +12,7 @@ wall_thickness = 0.7 top_bottom_thickness = 0.75 infill_sparse_density = 18 speed_print = 45 +speed_wall = 40 speed_travel = 150 speed_layer_0 = 30 cool_min_layer_time = 3 diff --git a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile index 377ab5b257..88db3c4bec 100644 --- a/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile +++ b/resources/profiles/ultimaker2+/cpe_0.4_high.curaprofile @@ -12,6 +12,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.72 infill_sparse_density = 22 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 2 cool_fan_speed_min = 80 cool_min_speed = 15 diff --git a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile index e8142405ff..91a82753ac 100644 --- a/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile +++ b/resources/profiles/ultimaker2+/cpe_0.4_normal.curaprofile @@ -12,6 +12,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.8 infill_sparse_density = 20 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 3 cool_fan_speed_min = 80 cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile index 06e401c139..c03c8ce621 100644 --- a/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile +++ b/resources/profiles/ultimaker2+/pla_0.4_fast.curaprofile @@ -12,6 +12,8 @@ wall_thickness = 0.7 top_bottom_thickness = 0.75 infill_sparse_density = 18 speed_print = 60 +speed_wall = 50 +speed_topbottom = 30 speed_travel = 150 speed_layer_0 = 30 cool_min_layer_time = 5 diff --git a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile index 5e2f762354..7cba49b71e 100644 --- a/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile +++ b/resources/profiles/ultimaker2+/pla_0.4_high.curaprofile @@ -12,5 +12,6 @@ wall_thickness = 1.05 top_bottom_thickness = 0.72 infill_sparse_density = 22 speed_print = 50 +speed_topbottom = 20 cool_min_layer_time = 5 cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile index 689a3251b2..4989b0e780 100644 --- a/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile +++ b/resources/profiles/ultimaker2+/pla_0.4_normal.curaprofile @@ -12,5 +12,6 @@ wall_thickness = 1.05 top_bottom_thickness = 0.8 infill_sparse_density = 20 speed_print = 50 +speed_topbottom = 20 cool_min_layer_time = 5 cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile index 188ed42a95..767a3d5ef5 100644 --- a/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile +++ b/resources/profiles/ultimaker2+/pla_0.6_normal.curaprofile @@ -12,5 +12,8 @@ wall_thickness = 1.59 top_bottom_thickness = 1.2 infill_sparse_density = 20 speed_print = 55 +speed_wall = 40 +speed_wall_0 = 25 +speed_topbottom = 20 cool_min_layer_time = 5 cool_min_speed = 10 diff --git a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile b/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile index 92cb4a6054..a8d50c78df 100644 --- a/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile +++ b/resources/profiles/ultimaker2+/pla_0.8_normal.curaprofile @@ -12,5 +12,6 @@ wall_thickness = 2.1 top_bottom_thickness = 1.2 infill_sparse_density = 20 speed_print = 40 +speed_wall_0 = 25 cool_min_layer_time = 5 cool_min_speed = 10 From 890303da146a77d6be6be51bb1eda1104930f556 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:33:10 +0200 Subject: [PATCH 175/304] Add function to add all extruder trains of a machine This function only adds extruder trains if they have not been added already. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 41 +++++++++++++++++++++++++++++++++---- cura/MachineManagerModel.py | 9 +------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index aae90afdc5..8c467ede00 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -61,6 +61,38 @@ class ExtruderManager(QObject): self._active_extruder_index = index self.activeExtruderChanged.emit() + ## Adds all extruders of a specific machine definition to the extruder + # manager. + # + # \param machine_definition The machine to add the extruders for. + def addMachineExtruders(self, machine_definition): + machine_id = machine_definition.getId() + if not self._extruder_trains[machine_id]: + self._extruder_trains[machine_id] = { } + + container_registry = UM.Settings.ContainerRegistry.getInstance() + if not container_registry: #Then we shouldn't have any machine definition either. In any case, there are no extruder trains then so bye bye. + return + + #Add the extruder trains that don't exist yet. + for position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): + extruder_definition = container_registry.findDefinitionContainers(id = extruder_definition_id) + if extruder_definition: + extruder_definition = extruder_definition[0] + else: + Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) + continue + name = self._uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. + if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. + self.createExtruderTrain(extruder_definition, machine_definition, name, position) + + #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() + if extruder_trains: + self.extrudersChanged.emit() + ## (Re)populates the collections of extruders by machine. def _repopulate(self): self._extruder_trains = { } @@ -78,13 +110,14 @@ class ExtruderManager(QObject): self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() self.extrudersChanged.emit() - def createExtruderTrain(self, extruder_definition, machine_definition, extruder_id): + def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): container_registry = UM.Settings.ContainerRegistry.getInstance() #Create a container stack for this extruder. - name = self._uniqueName(extruder_id) - container_stack = UM.Settings.ContainerStack(name) + container_stack = UM.Settings.ContainerStack(extruder_train_id) container_stack.addMetaDataEntry("type", "extruder_train") + container_stack.addMetaDataEntry("machine", machine_definition.getId()) + container_stack.addMetaDataEntry("position", position) container_stack.addContainer(extruder_definition) """ @@ -133,7 +166,7 @@ class ExtruderManager(QObject): """ #Add an empty user profile. - user_profile = UM.Settings.InstanceContainer(name + "_current_settings") + user_profile = UM.Settings.InstanceContainer(extruder_train_id + "_current_settings") user_profile.addMetaDataEntry("type", "user") user_profile.setDefinition(machine_definition) container_stack.addContainer(user_profile) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 576cf1acc0..86e74e8302 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -135,14 +135,7 @@ class MachineManagerModel(QObject): new_global_stack.addContainer(quality_instance_container) new_global_stack.addContainer(current_settings_instance_container) - for position, extruder_train_id in definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): - extruder_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = extruder_train_id) - if extruder_definition: - extruder_definition = extruder_definition[0] - else: - Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", definition.getName(), extruder_train_id) - continue - ExtruderManager.ExtruderManager.getInstance().createExtruderTrain(extruder_definition, definition, extruder_train_id) + ExtruderManager.ExtruderManager.getInstance().addMachineExtruders(definition) Application.getInstance().setGlobalContainerStack(new_global_stack) From 9fe543596316fb11c5478b750465f958228983a9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:34:00 +0200 Subject: [PATCH 176/304] Rename parameter in _uniqueName Original means the original name. That's better. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 8c467ede00..15fbbe2a1c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -177,10 +177,10 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) - def _uniqueName(self, extruder): + def _uniqueName(self, original): container_registry = UM.Settings.ContainerRegistry.getInstance() - name = extruder.strip() + name = original.strip() num_check = re.compile("(.*?)\s*#\d$").match(name) if num_check: # There is a number in the name. name = num_check.group(1) # Filter out the number. From dff94b4559e558aeadea7a8694393557b838c3f5 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:54:16 +0200 Subject: [PATCH 177/304] Make ExtruderManager a QML context item There were two singletons of this manager: One created by QML and managed by QML, and one created by us and managed by our own singleton pattern. That won't work! So we now manage just our own singleton type, and make it a context item for QML so it can use the manager too. Contributes to issues CURA-340 and CURA-1278. --- cura/CuraApplication.py | 7 +++++-- cura/ExtruderManager.py | 6 +----- resources/qml/Settings/SettingView.qml | 2 +- resources/qml/SidebarHeader.qml | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 126d8b2864..7edb0bf8bd 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -353,8 +353,6 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) - qmlRegisterSingletonType(ExtruderManager.ExtruderManager, "Cura", 1, 0, "ExtruderManager", - ExtruderManager.createExtruderManager) self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml")) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) @@ -386,6 +384,9 @@ class CuraApplication(QtApplication): def getPrintInformation(self): return self._print_information + ## Registers objects for the QML engine to use. + # + # \param engine The QML engine. def registerObjects(self, engine): engine.rootContext().setContextProperty("Printer", self) self._print_information = PrintInformation.PrintInformation() @@ -399,6 +400,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") + engine.rootContext().setContextProperty("ExtruderManager", ExtruderManager.ExtruderManager.getInstance()) + for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles): type_name = os.path.splitext(os.path.basename(path))[0] if type_name in ("Cura", "Actions"): diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 15fbbe2a1c..4f8c58be07 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -76,7 +76,7 @@ class ExtruderManager(QObject): #Add the extruder trains that don't exist yet. for position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): - extruder_definition = container_registry.findDefinitionContainers(id = extruder_definition_id) + extruder_definition = container_registry.findDefinitionContainers(machine = machine_definition.getId()) if extruder_definition: extruder_definition = extruder_definition[0] else: @@ -194,7 +194,3 @@ class ExtruderManager(QObject): i += 1 # Try next numbering. unique_name = "%s #%d" % (name, i) # Fill name like this: "Extruder #2". return unique_name - - -def createExtruderManager(engine, script_engine): - return ExtruderManager() \ No newline at end of file diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 7191bff3ef..6261496c84 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -80,7 +80,7 @@ ScrollView { id: provider - containerStackId: Cura.ExtruderManager.activeExtruderStackId ? Cura.ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId + containerStackId: ExtruderManager.activeExtruderStackId ? ExtruderManager.activeExtruderStackId : Cura.MachineManager.activeMachineId key: model.key watchedProperties: [ "value", "enabled", "state", "validationState" ] storeIndex: 0 diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index b38f65772d..237746ac0d 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -111,7 +111,7 @@ Item onClicked: { base.currentExtruderIndex = index - Cura.ExtruderManager.setActiveExtruderIndex(index) + ExtruderManager.setActiveExtruderIndex(index) } style: ButtonStyle { From 66bf0831f310e7f56090843d31db0ba057218903 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 11:55:07 +0200 Subject: [PATCH 178/304] Document _uniqueName This function should really just be moved to ContainerRegistry... I'll do that later. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 4f8c58be07..f8bcd75151 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -176,7 +176,14 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) - + ## Creates a new unique name for a container that doesn't exist yet. + # + # It tries if the original name you provide exists, and if it doesn't + # it'll add a " #1" or " #2" after the name to make it unique. + # + # \param original The original name that may not be unique. + # \return A unique name that looks a lot like the original but may have + # a number behind it to make it unique. def _uniqueName(self, original): container_registry = UM.Settings.ContainerRegistry.getInstance() @@ -189,8 +196,7 @@ class ExtruderManager(QObject): unique_name = name i = 1 - while container_registry.findContainers(id=unique_name) or container_registry.findContainers( - name=unique_name): # A container already has this name. + while container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name): # A container already has this name. i += 1 # Try next numbering. unique_name = "%s #%d" % (name, i) # Fill name like this: "Extruder #2". return unique_name From 4fb66afe069ba9f6b7dff397448d6f659232cb79 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 11:58:44 +0200 Subject: [PATCH 179/304] Mark duplicated profiles as non-read-only CURA-1585 --- cura/MachineManagerModel.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 576cf1acc0..e179eb2ebd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -304,6 +304,7 @@ class MachineManagerModel(QObject): ## Copy all values new_container.deserialize(containers[0].serialize()) + new_container.setMetaDataEntry("read_only", False) new_container.setName(new_name) new_container._id = new_name UM.Settings.ContainerRegistry.getInstance().addContainer(new_container) From b14b05d6fb5615b5c8fc30f228d430b4017a4fcc Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 7 Jun 2016 12:12:14 +0200 Subject: [PATCH 180/304] JSON: upped the retraction_count_max further up to 90 (CURA-1662) --- resources/machines/fdmprinter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/machines/fdmprinter.json b/resources/machines/fdmprinter.json index 2b172d1720..a523627b7d 100644 --- a/resources/machines/fdmprinter.json +++ b/resources/machines/fdmprinter.json @@ -760,7 +760,7 @@ "retraction_count_max": { "label": "Maximum Retraction Count", "description": "This setting limits the number of retractions occurring within the minimum extrusion distance window. Further retractions within this window will be ignored. This avoids retracting repeatedly on the same piece of filament, as that can flatten the filament and cause grinding issues.", - "default": 45, + "default": 90, "min_value": "0", "max_value_warning": "100", "type": "int", From 68837a089ad46ca990969188169bcd0b69de6e06 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 12:50:57 +0200 Subject: [PATCH 181/304] Moved some properties to bindings due to bug in qt 5.5.1 CURA-1494 --- 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 f476349c42..e4edc267ef 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -22,6 +22,10 @@ Item { property var showInheritButton: true property var doDepthIdentation: true + // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise) + property var state: propertyProvider.properties.state + property var stackLevel: propertyProvider.stackLevel + signal contextMenuRequested() signal showTooltip(string text); signal hideTooltip(); @@ -128,7 +132,7 @@ Item { { id: revertButton; - visible: propertyProvider.stackLevel == 0 && base.showRevertButton + visible: base.stackLevel == 0 && base.showRevertButton height: parent.height; width: height; @@ -155,14 +159,14 @@ Item { id: inheritButton; //visible: has_profile_value && base.has_inherit_function && base.is_enabled - visible: propertyProvider.properties.state == "InstanceState.User" && propertyProvider.stackLevel > 0 && base.showInheritButton + visible: base.state == "InstanceState.User" && base.stackLevel > 0 && base.showInheritButton height: parent.height; width: height; onClicked: { focus = true; - propertyProvider.removeFromContainer(propertyProvider.stackLevel) + propertyProvider.removeFromContainer(base.stackLevel) } backgroundColor: UM.Theme.getColor("setting_control"); From ca1b199c7e4d57e4ef071b64add53ad2d895be3d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Tue, 7 Jun 2016 13:17:35 +0200 Subject: [PATCH 182/304] Fix PerObjectSettings to use the right objects when instantiating setting items Contributes to CURA-1592 --- .../PerObjectSettingsPanel.qml | 62 ++++++++++++++++--- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 8ab05e90c1..c89485517e 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -64,24 +64,26 @@ Item { settingLoader.item.doDepthIdentation = false } - source: + sourceComponent: { - switch(model.type) // TODO: This needs to be fixed properly. Got frustrated with it not working, so this is the patch job! + switch(model.type) { case "int": - return "../../resources/qml/Settings/SettingTextField.qml" + return settingTextField case "float": - return "../../resources/qml/Settings/SettingTextField.qml" + return settingTextField case "enum": - return "../../resources/qml/Settings/SettingComboBox.qml" + return settingComboBox + case "extruder": + return settingExtruder case "bool": - return "../../resources/qml/Settings/SettingCheckBox.qml" + return settingCheckBox case "str": - return "../../resources/qml/Settings/SettingTextField.qml" + return settingTextField case "category": - return "../../resources/qml/Settings/SettingCategory.qml" + return settingCategory default: - return "../../resources/qml/Settings/SettingUnknown.qml" + return settingUnknown } } } @@ -257,4 +259,46 @@ Item { } SystemPalette { id: palette; } + + Component + { + id: settingTextField; + + Cura.SettingTextField { } + } + + Component + { + id: settingComboBox; + + Cura.SettingComboBox { } + } + + Component + { + id: settingExtruder; + + Cura.SettingExtruder { } + } + + Component + { + id: settingCheckBox; + + Cura.SettingCheckBox { } + } + + Component + { + id: settingCategory; + + Cura.SettingCategory { } + } + + Component + { + id: settingUnknown; + + Cura.SettingUnknown { } + } } From 227c0f9f8c9d71d264f1959c18b2fdf550f05a5b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 12:01:12 +0200 Subject: [PATCH 183/304] Move _uniqueName to ContainerRegistry It's not specific to any type of container and we might re-use this anyway. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index f8bcd75151..31943be747 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -26,8 +26,6 @@ class ExtruderManager(QObject): self._next_item = 0 #For when you use this class as iterator. self._active_extruder_index = 0 - self._repopulate() - ## Creates an iterator over the extruders in this manager. # # \return An iterator over the extruders in this manager. @@ -82,7 +80,7 @@ class ExtruderManager(QObject): else: Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) continue - name = self._uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. + name = container_registry.uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. self.createExtruderTrain(extruder_definition, machine_definition, name, position) @@ -175,28 +173,3 @@ class ExtruderManager(QObject): container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) container_registry.addContainer(container_stack) - - ## Creates a new unique name for a container that doesn't exist yet. - # - # It tries if the original name you provide exists, and if it doesn't - # it'll add a " #1" or " #2" after the name to make it unique. - # - # \param original The original name that may not be unique. - # \return A unique name that looks a lot like the original but may have - # a number behind it to make it unique. - def _uniqueName(self, original): - container_registry = UM.Settings.ContainerRegistry.getInstance() - - name = original.strip() - num_check = re.compile("(.*?)\s*#\d$").match(name) - if num_check: # There is a number in the name. - name = num_check.group(1) # Filter out the number. - if name == "": # Wait, that deleted everything! - name = "Extruder" - unique_name = name - - i = 1 - while container_registry.findContainers(id = unique_name) or container_registry.findContainers(name = unique_name): # A container already has this name. - i += 1 # Try next numbering. - unique_name = "%s #%d" % (name, i) # Fill name like this: "Extruder #2". - return unique_name From c5b07debdcf5583de189c13beeb6bcf333eae252 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:22:47 +0200 Subject: [PATCH 184/304] Remove iterability from ExtruderManager This is no longer used. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 31943be747..a1f901ce54 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -23,15 +23,8 @@ class ExtruderManager(QObject): def __init__(self, parent = None): super().__init__(parent) self._extruder_trains = { } #Extruders for the current machine. - self._next_item = 0 #For when you use this class as iterator. self._active_extruder_index = 0 - ## 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) - ## Gets the unique identifier of the currently active extruder stack. # # The currently active extruder stack is the stack that is currently being From 253061cfa492adeb628e9f7fa4929c43df0fafd6 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:24:03 +0200 Subject: [PATCH 185/304] Remove unused import The _uniqueName function was using this but it was moved to ContainerRegistry. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index a1f901ce54..d157cbb08e 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -6,7 +6,6 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For commun 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 re ## Manages all existing extruder stacks. From b991743053edf2778a2395dc9ede7007b99386eb Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 13:30:13 +0200 Subject: [PATCH 186/304] Fix ExtruderManager.py --- cura/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index d157cbb08e..b2c3b47e8e 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -4,7 +4,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt. import UM.Application #To get the global container stack to find the current machine. -import UM.Logger +from UM.Logger import Logger import UM.Settings.ContainerRegistry #Finding containers by ID. @@ -57,7 +57,7 @@ class ExtruderManager(QObject): # \param machine_definition The machine to add the extruders for. def addMachineExtruders(self, machine_definition): machine_id = machine_definition.getId() - if not self._extruder_trains[machine_id]: + if machine_id not in self._extruder_trains: self._extruder_trains[machine_id] = { } container_registry = UM.Settings.ContainerRegistry.getInstance() From 4695862b491dc0edd2560b89f689b170f385e391 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 13:33:19 +0200 Subject: [PATCH 187/304] Added deepcopy function to settingOverrideDecorator CURA-1636 --- cura/SettingOverrideDecorator.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index e212d93dac..04e77b0d3f 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -7,7 +7,7 @@ from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerRegistry import ContainerRegistry 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. @@ -25,6 +25,15 @@ class SettingOverrideDecorator(SceneNodeDecorator): Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() + def __deepcopy__(self, memo): + ## Create a fresh decorator object + deep_copy = SettingOverrideDecorator() + ## Copy the stack + deep_copy._stack = copy.deepcopy(self._stack, memo) + ## Ensure that the id is unique. + deep_copy._stack._id = id(deep_copy) + return deep_copy + def _onSettingChanged(self, instance, property): if property == "value": # Only reslice if the value has changed. Application.getInstance().getBackend().forceSlice() From 08d116590d2aac424be9f222b171a9ada751eabf Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:32:36 +0200 Subject: [PATCH 188/304] Revert "Fix ExtruderManager.py" That is not a fix. That is a patch. This reverts commit b991743053edf2778a2395dc9ede7007b99386eb. --- cura/ExtruderManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b2c3b47e8e..d157cbb08e 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -4,7 +4,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt. import UM.Application #To get the global container stack to find the current machine. -from UM.Logger import Logger +import UM.Logger import UM.Settings.ContainerRegistry #Finding containers by ID. @@ -57,7 +57,7 @@ class ExtruderManager(QObject): # \param machine_definition The machine to add the extruders for. def addMachineExtruders(self, machine_definition): machine_id = machine_definition.getId() - if machine_id not in self._extruder_trains: + if not self._extruder_trains[machine_id]: self._extruder_trains[machine_id] = { } container_registry = UM.Settings.ContainerRegistry.getInstance() From 8feed746bf82d7fccaf5c6966685aba49c96b8ac Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:40:49 +0200 Subject: [PATCH 189/304] Re-apply part of b991743053edf2778a2395dc9ede7007b99386eb that worked This was indeed a mistake. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index d157cbb08e..9fbfc8eb84 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -57,7 +57,7 @@ class ExtruderManager(QObject): # \param machine_definition The machine to add the extruders for. def addMachineExtruders(self, machine_definition): machine_id = machine_definition.getId() - if not self._extruder_trains[machine_id]: + if machine_id not in self._extruder_trains: self._extruder_trains[machine_id] = { } container_registry = UM.Settings.ContainerRegistry.getInstance() From a9376cffd1b19c43ecc068e8c579b6ab96d1e3d0 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:41:28 +0200 Subject: [PATCH 190/304] Fix logging Specify the fully qualified name. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 9fbfc8eb84..9ec17c1abd 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -70,7 +70,7 @@ class ExtruderManager(QObject): if extruder_definition: extruder_definition = extruder_definition[0] else: - Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) + UM.Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) continue name = container_registry.uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. From 499a0557bd55492871a0160f7cd6f9b61fe1d0cb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 13:59:58 +0200 Subject: [PATCH 191/304] Fix checking if an extruder train already exists Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 9ec17c1abd..df31cbacdf 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -65,15 +65,12 @@ class ExtruderManager(QObject): return #Add the extruder trains that don't exist yet. - for position, extruder_definition_id in machine_definition.getMetaDataEntry("machine_extruder_trains", default = {}).items(): - extruder_definition = container_registry.findDefinitionContainers(machine = machine_definition.getId()) - if extruder_definition: - extruder_definition = extruder_definition[0] - else: - UM.Logger.log("w", "Machine %s references an extruder with ID %s, which doesn't exist.", machine_definition.getName(), extruder_definition_id) - continue - name = container_registry.uniqueName(extruder_definition_id) #Make a name based on the ID of the definition. - if not container_registry.findContainerStacks(id = name): #Doesn't exist yet. + for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()): + position = extruder_definition.getMetaDataEntry("position", None) + if not position: + UM.Logger.Log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) + if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet. + name = container_registry.uniqueName(extruder_definition.getId()) #Make a name based on the ID of the definition. self.createExtruderTrain(extruder_definition, machine_definition, name, position) #Gets the extruder trains that we just created as well as any that still existed. From d2405a24d26f0c23b1be3349438232142234e842 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 14:56:29 +0200 Subject: [PATCH 192/304] Perobject stacks are no longer saved CURA-1278 --- cura/SettingOverrideDecorator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 04e77b0d3f..10a14007f3 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -15,6 +15,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): 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) From 5761307b336c5dcdea2c8d162a78d04f4ac39863 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 15:45:51 +0200 Subject: [PATCH 193/304] Updated deepcopy to correctly copy the instance container CURA-1636 --- cura/SettingOverrideDecorator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 10a14007f3..f9878e436c 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -29,10 +29,10 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __deepcopy__(self, memo): ## Create a fresh decorator object deep_copy = SettingOverrideDecorator() - ## Copy the stack - deep_copy._stack = copy.deepcopy(self._stack, memo) - ## Ensure that the id is unique. - deep_copy._stack._id = id(deep_copy) + ## Copy the instance + deep_copy._instance = copy.deepcopy(self._instance, memo) + ## Set the copied instance as the first (and only) instance container of the stack. + deep_copy._stack.replaceContainer(0, deep_copy._instance) return deep_copy def _onSettingChanged(self, instance, property): From 9a14a3e8b755bb9f85015670d0fb85bf2c90f50f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 7 Jun 2016 15:46:37 +0200 Subject: [PATCH 194/304] Per object settings no longer watches "state" property CURA-1278 --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index c89485517e..9565b0e345 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -120,7 +120,7 @@ Item { containerStackId: UM.ActiveTool.properties.getValue("ContainerID") key: model.key - watchedProperties: [ "value", "enabled", "state", "validationState" ] + watchedProperties: [ "value", "enabled", "validationState" ] storeIndex: 0 } } From b2782ced0a088274b2f483cc7502fc53abc70ab2 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 15:56:59 +0200 Subject: [PATCH 195/304] Fix "renaming" profiles/machines to their current name without adding an increment CURA-1585 --- cura/MachineManagerModel.py | 66 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c764296a68..7d8403afdd 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -9,6 +9,7 @@ from UM.Logger import Logger import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer +from UM.Settings.ContainerStack import ContainerStack from . import ExtruderManager from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -109,7 +110,7 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueName("machine", name, definition.getName()) + name = self._createUniqueName(containers[0], "machine", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) new_global_stack.addMetaDataEntry("type", "machine") @@ -139,31 +140,42 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) - # Create a name that is not empty and unique - def _createUniqueName(self, object_type, name, fallback_name): - name = name.strip() - num_check = re.compile("(.*?)\s*#\d+$").match(name) - if(num_check): - name = num_check.group(1) - if name == "": - name = fallback_name - unique_name = name - i = 1 + ## Create a name that is not empty and unique + # \param container \type{} container to create a unique name for + # \param container_type \type{string} Type of the container (machine, quality, ...) + # \param new_name \type{string} Name base name, which may not be unique + # \param fallback_name \type{string} Name to use when (stripped) new_name is empty + # \return \type{string} Name that is unique for the specified type and name/id + def _createUniqueName(self, container, object_type, new_name, fallback_name): + new_name = new_name.strip() + num_check = re.compile("(.*?)\s*#\d+$").match(new_name) + if num_check: + new_name = num_check.group(1) + if new_name == "": + new_name = fallback_name - # Check both the id and the name, because they may not be the same and it is better if they are both unique - if object_type == "machine": - while UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = unique_name, type = "machine") or \ - UM.Settings.ContainerRegistry.getInstance().findContainerStacks(name = unique_name, type = "machine"): - i += 1 - unique_name = "%s #%d" % (name, i) - else: - while UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = unique_name, type = object_type) or \ - UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(name = unique_name, type = object_type): - i += 1 - unique_name = "%s #%d" % (name, i) + unique_name = new_name + i = 1 + while self._containerWithIdOrNameExists(unique_name, object_type, container): + i += 1 + unique_name = "%s #%d" % (new_name, i) return unique_name + ## Check if a container with of a certain type and a certain name or id exists + # Both the id and the name are checked, because they may not be the same and it is better if they are both unique + def _containerWithIdOrNameExists(self, id_or_name, container_type, exclude_container = None): + container_class = ContainerStack if container_type == "machine" else InstanceContainer + + containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = id_or_name, type = container_type) + if containers and containers[0] != exclude_container: + return True + containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = id_or_name, type = container_type) + if containers and containers[0] != exclude_container: + return True + + return False + ## Convenience function to check if a stack has errors. def _checkStackForErrors(self, stack): if stack is None: @@ -260,9 +272,9 @@ class MachineManagerModel(QObject): if not self._global_container_stack: return - name = self._createUniqueName("quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) - user_settings = self._global_container_stack.getTop() new_quality_container = InstanceContainer("") + name = self._createUniqueName(new_quality_container, "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()) @@ -290,7 +302,7 @@ class MachineManagerModel(QObject): 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")) + new_name = self._createUniqueName(containers[0], "quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -310,7 +322,7 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName("machine", new_name, catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName(containers[0], "quality", new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) @@ -413,7 +425,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueName("machine", new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName(containers[0], "machine", new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From 44d9fefd5d622bc5a3edaeb553173627fb9705f4 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Tue, 7 Jun 2016 16:11:44 +0200 Subject: [PATCH 196/304] Profile export from the Profiles window. Contributed to CURA-1667 Profile import/export --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 28248b23f4..ed9c20f65f 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -237,7 +237,7 @@ UM.ManagementPage folder: base.model.getDefaultPath() onAccepted: { - var result = base.model.exportProfile(base.currentItem.id, base.currentItem.name, fileUrl, selectedNameFilter) + var result = base.model.exportProfile(base.currentItem.id, fileUrl) if(result && result.status == "error") { messageDialog.icon = StandardIcon.Critical From cca432742b124f3103cad5fd8b52cf077a67050b Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 17:01:08 +0200 Subject: [PATCH 197/304] Fix creating a name for a new MachineManagerModel CURA-1585 --- cura/MachineManagerModel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 7d8403afdd..c0ac74abe4 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -110,9 +110,10 @@ class MachineManagerModel(QObject): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] - name = self._createUniqueName(containers[0], "machine", name, definition.getName()) - new_global_stack = UM.Settings.ContainerStack(name) + name = self._createUniqueName(new_global_stack, "machine", name, definition.getName()) + new_global_stack._id = name + new_global_stack.setName(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) From e33eb52e936dab1cffa98e6568a41ca0dea3782a Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 17:32:28 +0200 Subject: [PATCH 198/304] Hide Support Extruder in advanced mode when support is disabled CURA-1663 --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ec27abd9f5..79bdf4399a 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2139,6 +2139,7 @@ "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", + "enabled": "support_enable", "global_only": "True", "children": { "support_infill_extruder_nr": From 4d0bb217af1d7f35c75576e44b1b4e0d61967fb9 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 18:13:19 +0200 Subject: [PATCH 199/304] Fix crash when enabling setting visibility for adhesion_extruder_nr or support_extruder_nr The fix is likely not what was intended by the author of the offending code (and does not seem to be functional), but at least it fixes the hard crash outlined in CURA-1666 --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index eb63bc4257..7e00611742 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -46,7 +46,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def _updateExtruders(self): self.clear() manager = cura.ExtruderManager.ExtruderManager.getInstance() - for index, extruder in enumerate(manager): + for index, extruder in enumerate(manager._extruder_trains): item = { #Construct an item with only the relevant information. "name": extruder.name, "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), From 406baf49af7183fcc13e5f2279f3f3507e0d3474 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 7 Jun 2016 18:25:03 +0200 Subject: [PATCH 200/304] JSON feat: replaced global_only with four properties settable_per_[mesh|extruder|meshgroup] and settable_globally (CURA-1558) --- resources/definitions/fdmprinter.def.json | 1264 +++++++++++++++++---- 1 file changed, 1016 insertions(+), 248 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ec27abd9f5..f80d5d0d8f 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -32,151 +32,209 @@ "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_globally": true }, "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, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_globally": true }, "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, + "settable_globally": true }, "machine_head_polygon": { @@ -201,8 +259,11 @@ 1 ] ], - "global_only": true, - "label": "Machine head polygon" + "label": "Machine head polygon", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": true }, "machine_head_with_fans_polygon": { @@ -227,16 +288,22 @@ -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, + "settable_globally": true }, "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, + "settable_globally": true }, "machine_nozzle_size": { @@ -246,14 +313,22 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_globally": true } } }, @@ -275,7 +350,11 @@ "minimum_value": "0.001", "minimum_value_warning": "0.04", "maximum_value_warning": "0.8 * machine_nozzle_size", - "global_only": "True" + "default_value": true, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "layer_height_0": { @@ -287,7 +366,11 @@ "minimum_value": "0.001", "minimum_value_warning": "0.04", "maximum_value_warning": "0.8 * machine_nozzle_size", - "global_only": "True" + "default_value": true, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "line_width": { @@ -313,6 +396,11 @@ "value":"line_width", "default_value": 0.4, "type": "float", + "default_value": true, + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "wall_line_width_0": @@ -325,7 +413,11 @@ "maximum_value_warning": "5", "default_value": 0.4, "value":"wall_line_width", - "type": "float" + "type": "float", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "wall_line_width_x": { @@ -337,7 +429,11 @@ "maximum_value_warning": "5", "default_value": 0.4, "value":"wall_line_width", - "type": "float" + "type": "float", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -351,7 +447,11 @@ "maximum_value_warning": "5", "default_value": 0.4, "type": "float", - "value": "line_width" + "value": "line_width", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "infill_line_width": { @@ -363,7 +463,11 @@ "maximum_value_warning": "5", "default_value": 0.4, "type": "float", - "value": "line_width" + "value": "line_width", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "skirt_line_width": { @@ -375,8 +479,11 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_line_width": { @@ -389,8 +496,11 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_roof_line_width": { @@ -402,8 +512,11 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "prime_tower_line_width": { @@ -417,7 +530,10 @@ "minimum_value": "0.0001", "minimum_value_warning": "0.2", "maximum_value_warning": "5", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } } @@ -441,6 +557,10 @@ "minimum_value_warning": "line_width", "maximum_value_warning": "5 * line_width", "type": "float", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "wall_line_count": @@ -450,7 +570,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -464,6 +588,10 @@ "maximum_value": "5", "minimum_value_warning": "0.6", "type": "float", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "top_thickness": @@ -476,6 +604,10 @@ "maximum_value_warning": "100", "type": "float", "value": "top_bottom_thickness", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "top_layers": @@ -486,7 +618,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -499,6 +635,10 @@ "minimum_value": "0", "type": "float", "value": "top_bottom_thickness", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "bottom_layers": @@ -508,7 +648,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } } @@ -525,7 +669,11 @@ "concentric": "Concentric", "zigzag": "Zig Zag" }, - "default_value": "lines" + "default_value": "lines", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "wall_0_inset": { @@ -536,14 +684,22 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "travel_compensate_overlapping_walls_enabled": { @@ -551,6 +707,10 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "travel_compensate_overlapping_walls_0_enabled": { @@ -558,14 +718,22 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -577,7 +745,11 @@ "type": "float", "minimum_value_warning": "-10", "maximum_value_warning": "10", - "default_value": 0 + "default_value": 0, + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "z_seam_type": { @@ -590,14 +762,22 @@ "shortest": "Shortest", "random": "Random" }, - "default_value": "shortest" + "default_value": "shortest", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -618,6 +798,10 @@ "default_value": 20, "minimum_value": "0", "maximum_value_warning": "100", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "infill_line_distance": @@ -628,7 +812,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -646,7 +834,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "infill_overlap": { @@ -659,6 +851,10 @@ "minimum_value_warning": "-50", "maximum_value_warning": "100", "enabled": "infill_pattern != 'concentric'", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "infill_overlap_mm": @@ -671,7 +867,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -685,6 +885,10 @@ "maximum_value_warning": "100", "value": "5 if top_bottom_pattern != 'concentric' else 0", "enabled": "top_bottom_pattern != 'concentric'", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "skin_overlap_mm": { "label": "Skin Overlap", @@ -695,7 +899,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -708,7 +916,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "infill_sparse_thickness": { @@ -720,14 +932,22 @@ "minimum_value": "0.0001", "maximum_value_warning": "0.32", "maximum_value": "layer_height * 8", - "value": "layer_height" + "value": "layer_height", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -746,7 +966,10 @@ "type": "bool", "default_value": false, "enabled": "False", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "material_print_temperature": { @@ -757,7 +980,11 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "material_flow_temp_graph": { @@ -768,7 +995,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "material_extrusion_cool_down_speed": { "label": "Extrusion Cool Down Speed Modifier", @@ -778,9 +1008,12 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "material_bed_temperature": { "label": "Bed Temperature", @@ -791,7 +1024,10 @@ "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, + "settable_globally": true }, "material_diameter": { "label": "Diameter", @@ -802,7 +1038,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "material_flow": { "label": "Flow", @@ -812,13 +1051,21 @@ "type": "float", "minimum_value": "5", "minimum_value_warning": "50", - "maximum_value_warning": "150" + "maximum_value_warning": "150", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_amount": { "label": "Retraction Distance", @@ -828,7 +1075,11 @@ "default_value": 6.5, "minimum_value_warning": "-0.0001", "maximum_value_warning": "10.0", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_speed": { "label": "Retraction Speed", @@ -840,6 +1091,10 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "retraction_retract_speed": { "label": "Retraction Retract Speed", @@ -851,7 +1106,11 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", - "value": "retraction_speed" + "value": "retraction_speed", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_prime_speed": { "label": "Retraction Prime Speed", @@ -863,7 +1122,11 @@ "maximum_value": "299792458000", "maximum_value_warning": "100", "enabled": "retraction_enable", - "value": "retraction_speed" + "value": "retraction_speed", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -875,7 +1138,11 @@ "default_value": 0, "minimum_value_warning": "-0.0001", "maximum_value_warning": "5.0", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_min_travel": { "label": "Retraction Minimum Travel", @@ -886,7 +1153,11 @@ "value": "line_width * 2", "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_count_max": { "label": "Maximum Retraction Count", @@ -895,7 +1166,11 @@ "minimum_value": "0", "maximum_value_warning": "100", "type": "int", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_extrusion_window": { "label": "Minimum Extrusion Distance Window", @@ -906,7 +1181,11 @@ "minimum_value": "0", "maximum_value_warning": "retraction_amount * 2", "value": "retraction_amount", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "retraction_hop": { "label": "Z Hop when Retracting", @@ -916,7 +1195,11 @@ "default_value": 0, "minimum_value_warning": "-0.0001", "maximum_value_warning": "10", - "enabled": "retraction_enable" + "enabled": "retraction_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "material_standby_temperature": { @@ -927,7 +1210,10 @@ "default_value": 150, "minimum_value": "0", "maximum_value_warning": "260", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "switch_extruder_retraction_amount": { @@ -940,7 +1226,10 @@ "value": "machine_heat_zone_length", "minimum_value_warning": "0", "maximum_value_warning": "100", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "switch_extruder_retraction_speeds": { @@ -952,7 +1241,10 @@ "default_value": 20, "minimum_value": "0.1", "maximum_value_warning": "300", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "switch_extruder_retraction_speed": @@ -966,7 +1258,10 @@ "value": "switch_extruder_retraction_speeds", "minimum_value": "0.1", "maximum_value_warning": "300", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "switch_extruder_prime_speed": { @@ -979,7 +1274,10 @@ "value": "switch_extruder_retraction_speeds", "minimum_value": "0.1", "maximum_value_warning": "300", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -992,7 +1290,11 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1014,6 +1316,10 @@ "maximum_value_warning": "150", "maximum_value": "299792458000", "default_value": 60, + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "speed_infill": @@ -1026,7 +1332,11 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 60, - "value": "speed_print" + "value": "speed_print", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "speed_wall": { @@ -1039,6 +1349,10 @@ "maximum_value_warning": "150", "default_value": 30, "value": "speed_print / 2", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "speed_wall_0": @@ -1051,7 +1365,11 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 30, - "value": "speed_wall" + "value": "speed_wall", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "speed_wall_x": { @@ -1063,7 +1381,11 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 60, - "value": "speed_wall * 2" + "value": "speed_wall * 2", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1077,7 +1399,11 @@ "maximum_value": "299792458000", "maximum_value_warning": "150", "default_value": 30, - "value": "speed_print / 2" + "value": "speed_print / 2", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "speed_support": { @@ -1091,6 +1417,10 @@ "default_value": 60, "value": "speed_print", "enabled": "support_roof_enable", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "speed_support_infill": @@ -1105,7 +1435,10 @@ "maximum_value_warning": "150", "value": "speed_support", "enabled": "support_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "speed_support_roof": { @@ -1119,7 +1452,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1134,7 +1470,10 @@ "value": "speed_print", "minimum_value": "0.1", "maximum_value_warning": "150", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1149,7 +1488,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "speed_layer_0": { "label": "Initial Layer Speed", @@ -1159,7 +1501,11 @@ "default_value": 30, "minimum_value": "0.1", "maximum_value": "299792458000", - "maximum_value_warning": "300" + "maximum_value_warning": "300", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "skirt_speed": { "label": "Skirt Speed", @@ -1171,7 +1517,10 @@ "maximum_value": "299792458000", "maximum_value_warning": "300", "value": "speed_layer_0", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "speed_slowdown_layers": { @@ -1182,7 +1531,10 @@ "minimum_value": "0", "maximum_value": "299792458000", "maximum_value_warning": "300", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1206,7 +1558,10 @@ "noskin": "No Skin" }, "default_value": "all", - "global_only": true + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "travel_avoid_other_parts": { @@ -1215,7 +1570,10 @@ "type": "bool", "default_value": true, "enabled": "retraction_combing != \"off\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "travel_avoid_distance": { @@ -1228,7 +1586,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1246,7 +1607,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "cool_fan_speed": { @@ -1259,7 +1623,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "cool_fan_speed_min": @@ -1273,7 +1640,10 @@ "value": "cool_fan_speed", "default_value": 100, "enabled": "cool_fan_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "cool_fan_speed_max": { @@ -1285,8 +1655,11 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1299,7 +1672,10 @@ "default_value": 10, "minimum_value": "cool_min_layer_time", "maximum_value_warning": "600", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "cool_fan_full_at_height": { @@ -1311,7 +1687,10 @@ "value": "layer_height_0", "minimum_value": "0", "maximum_value_warning": "10.0", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "cool_fan_full_layer": @@ -1323,7 +1702,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1336,7 +1718,10 @@ "default_value": 5, "minimum_value": "0", "maximum_value_warning": "600", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "cool_min_speed": { @@ -1347,7 +1732,10 @@ "default_value": 10, "minimum_value": "0", "maximum_value_warning": "100", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "cool_lift_head": { @@ -1355,7 +1743,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1372,7 +1763,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_type": { @@ -1385,7 +1780,11 @@ "everywhere": "Everywhere" }, "default_value": "everywhere", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_angle": { @@ -1396,7 +1795,11 @@ "minimum_value": "0", "maximum_value": "90", "default_value": 50, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_pattern": { @@ -1413,7 +1816,10 @@ }, "default_value": "zigzag", "enabled": "support_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_connect_zigzags": { @@ -1422,7 +1828,10 @@ "type": "bool", "default_value": true, "enabled": "support_enable and (support_pattern == \"zigzag\")", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_infill_rate": { @@ -1434,7 +1843,10 @@ "maximum_value_warning": "100", "default_value": 15, "enabled": "support_enable", - "global_only": true, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "support_line_distance": { @@ -1446,7 +1858,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1460,7 +1875,10 @@ "maximum_value_warning": "10", "default_value": 0.15, "enabled": "support_enable", - + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "support_top_distance": @@ -1473,7 +1891,11 @@ "default_value": 0.15, "type": "float", "enabled": "support_enable", - "value": "support_z_distance" + "value": "support_z_distance", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_bottom_distance": { @@ -1485,7 +1907,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1498,7 +1924,11 @@ "minimum_value": "0", "maximum_value_warning": "10", "default_value": 0.7, - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_xy_overrides_z": { "label": "Support Distance Priority", @@ -1509,7 +1939,11 @@ "z_overrides_xy": "Z overrides X/Y" }, "default_value": "z_overrides_xy", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_xy_distance_overhang": { "label": "Minimum Support X/Y Distance", @@ -1520,7 +1954,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_bottom_stair_step_height": { @@ -1531,7 +1969,11 @@ "default_value": 0.3, "minimum_value": "0", "maximum_value_warning": "1.0", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_join_distance": { @@ -1542,7 +1984,11 @@ "default_value": 2.0, "minimum_value_warning": "0", "maximum_value_warning": "10", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_offset": { @@ -1553,7 +1999,11 @@ "default_value": 0.2, "minimum_value_warning": "-0.5", "maximum_value_warning": "5.0", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_area_smoothing": { @@ -1564,7 +2014,11 @@ "default_value": 0.6, "minimum_value": "0", "maximum_value_warning": "1.0", - "enabled": "support_enable" + "enabled": "support_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_roof_enable": { @@ -1572,7 +2026,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_roof_height": { @@ -1583,7 +2041,11 @@ "default_value": 1, "minimum_value": "0", "maximum_value_warning": "10", - "enabled": "support_roof_enable" + "enabled": "support_roof_enable", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_roof_density": { @@ -1595,7 +2057,10 @@ "minimum_value": "0", "maximum_value_warning": "100", "enabled":"support_roof_enable", - "global_only": true, + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "support_roof_line_distance": @@ -1608,7 +2073,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1627,7 +2095,10 @@ }, "default_value": "concentric", "enabled": "support_roof_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_use_towers": { @@ -1635,7 +2106,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_tower_diameter": { @@ -1646,7 +2121,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_minimal_diameter": { @@ -1658,7 +2137,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_tower_roof_angle": { @@ -1669,7 +2152,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1693,7 +2180,10 @@ "raft": "Raft" }, "default_value": "brim", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "skirt_line_count": { @@ -1704,7 +2194,10 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "adhesion_type == \"skirt\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "skirt_gap": { @@ -1716,7 +2209,10 @@ "minimum_value_warning": "0", "maximum_value_warning": "100", "enabled": "adhesion_type == \"skirt\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "skirt_minimal_length": { @@ -1729,7 +2225,10 @@ "minimum_value_warning": "25", "maximum_value_warning": "2500", "enabled": "adhesion_type == \"skirt\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "brim_width": { @@ -1741,7 +2240,10 @@ "minimum_value": "0.0", "maximum_value_warning": "100.0", "enabled": "adhesion_type == \"brim\"", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "brim_line_count": @@ -1754,7 +2256,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1767,8 +2272,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": { @@ -1780,7 +2284,10 @@ "minimum_value": "0", "maximum_value_warning": "1.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "layer_0_z_overlap": { "label": "Initial Layer Z Overlap", @@ -1792,7 +2299,10 @@ "minimum_value": "0", "maximum_value_warning": "layer_height", "enabled": "adhesion_type == 'raft'", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_surface_layers": { @@ -1803,7 +2313,10 @@ "minimum_value": "0", "maximum_value_warning": "20", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_surface_thickness": { @@ -1815,7 +2328,10 @@ "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_surface_line_width": { @@ -1827,7 +2343,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_surface_line_spacing": { @@ -1840,7 +2359,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_interface_thickness": { @@ -1852,7 +2374,10 @@ "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_interface_line_width": { @@ -1865,7 +2390,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_interface_line_spacing": { @@ -1877,7 +2405,10 @@ "minimum_value": "0", "maximum_value_warning": "15.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_base_thickness": { @@ -1889,7 +2420,10 @@ "minimum_value": "0", "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_base_line_width": { @@ -1902,7 +2436,10 @@ "value": "line_width", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_base_line_spacing": { @@ -1914,7 +2451,10 @@ "minimum_value": "0.0001", "maximum_value_warning": "100", "enabled": "adhesion_type == \"raft\"", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_speed": { @@ -1928,7 +2468,10 @@ "maximum_value_warning": "200", "enabled": "adhesion_type == \"raft\"", "value": "speed_print / 60 * 30", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "raft_surface_speed": @@ -1943,7 +2486,10 @@ "maximum_value_warning": "100", "enabled": "adhesion_type == \"raft\"", "value": "raft_speed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_interface_speed": { @@ -1957,7 +2503,10 @@ "maximum_value_warning": "150", "enabled": "adhesion_type == \"raft\"", "value": "0.5 * raft_speed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_base_speed": { @@ -1971,7 +2520,10 @@ "maximum_value_warning": "200", "enabled": "adhesion_type == \"raft\"", "value": "0.5 * raft_speed", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -1984,7 +2536,10 @@ "minimum_value": "0", "maximum_value": "100", "default_value": 0, - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "enabled": "adhesion_type == \"raft\"", "children": { @@ -1997,9 +2552,12 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_interface_fan_speed": { @@ -2010,9 +2568,12 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "raft_base_fan_speed": { @@ -2023,9 +2584,12 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true } } } @@ -2044,28 +2608,44 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -2088,7 +2668,10 @@ "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, + "settable_globally": true }, "magic_mesh_surface_mode": { @@ -2101,7 +2684,11 @@ "surface": "Surface", "both": "Both" }, - "default_value": "normal" + "default_value": "normal", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "magic_spiralize": { @@ -2109,7 +2696,10 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -2129,7 +2719,10 @@ "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_extruder_nr": { @@ -2139,7 +2732,10 @@ "default_value": 0, "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "support_infill_extruder_nr": { @@ -2150,7 +2746,10 @@ "value": "support_extruder_nr", "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_extruder_nr_layer_0": { @@ -2161,7 +2760,10 @@ "value": "support_extruder_nr", "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_roof_extruder_nr": { @@ -2172,7 +2774,10 @@ "value": "support_extruder_nr", "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -2182,7 +2787,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "prime_tower_size": { @@ -2195,7 +2803,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "prime_tower_position_x": { @@ -2207,7 +2818,10 @@ "default_value": 200, "minimum_value_warning": "-1000", "maximum_value_warning": "1000", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "prime_tower_position_y": { @@ -2219,7 +2833,10 @@ "default_value": 200, "minimum_value_warning": "-1000", "maximum_value_warning": "1000", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "prime_tower_flow": { @@ -2232,7 +2849,10 @@ "minimum_value": "0.0001", "minimum_value_warning": "50", "maximum_value_warning": "150", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "prime_tower_wipe_enabled": { @@ -2241,7 +2861,10 @@ "type": "bool", "enabled": "prime_tower_enable", "default_value": false, - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "multiple_mesh_overlap": { @@ -2251,7 +2874,11 @@ "unit": "mm", "default_value": 0.15, "minimum_value": "0", - "maximum_value_warning": "1.0" + "maximum_value_warning": "1.0", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "ooze_shield_enabled": { @@ -2259,7 +2886,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "ooze_shield_angle": { @@ -2271,7 +2901,10 @@ "default_value": 60, "minimum_value": "0", "maximum_value": "90", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "ooze_shield_dist": { @@ -2283,7 +2916,10 @@ "default_value": 2, "minimum_value": "0", "maximum_value_warning": "30", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -2301,7 +2937,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "draft_shield_dist": { @@ -2313,7 +2952,10 @@ "maximum_value_warning": "100", "default_value": 10, "enabled": "draft_shield_enabled", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "draft_shield_height_limitation": { @@ -2327,7 +2969,10 @@ }, "default_value": "full", "enabled": "draft_shield_enabled", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": true, + "settable_globally": true }, "draft_shield_height": { @@ -2340,7 +2985,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "conical_overhang_enabled": { "label": "Make Overhang Printable", @@ -2364,7 +3012,10 @@ "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, + "settable_per_meshgroup": true, + "settable_globally": true }, "coasting_volume": { @@ -2376,7 +3027,10 @@ "minimum_value": "0", "maximum_value_warning": "2.0", "enabled": "coasting_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "coasting_min_volume": { @@ -2388,7 +3042,10 @@ "minimum_value": "0", "maximum_value_warning": "10.0", "enabled": "coasting_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "coasting_speed": { @@ -2400,7 +3057,10 @@ "minimum_value": "0.0001", "maximum_value_warning": "100", "enabled": "coasting_enable", - "global_only": true + "settable_per_mesh": false, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "skin_outline_count": { @@ -2409,7 +3069,11 @@ "default_value": 0, "minimum_value": "0", "maximum_value_warning": "10", - "type": "int" + "type": "int", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "skin_alternate_rotation": { @@ -2417,7 +3081,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_conical_enabled": { @@ -2425,7 +3093,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_conical_angle": { @@ -2438,7 +3110,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "support_conical_min_width": { @@ -2450,14 +3126,22 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": 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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "magic_fuzzy_skin_thickness": { @@ -2468,7 +3152,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true }, "magic_fuzzy_skin_point_density": { @@ -2482,6 +3170,10 @@ "maximum_value_warning": "10", "maximum_value": "2 / magic_fuzzy_skin_thickness", "enabled": "magic_fuzzy_skin_enabled", + "settable_per_mesh": true, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true, "children": { "magic_fuzzy_skin_point_dist": @@ -2495,7 +3187,11 @@ "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, + "settable_per_extruder": true, + "settable_per_meshgroup": true, + "settable_globally": true } } }, @@ -2505,7 +3201,10 @@ "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, + "settable_globally": true }, "wireframe_height": { @@ -2517,7 +3216,10 @@ "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, + "settable_globally": true }, "wireframe_roof_inset": { @@ -2531,7 +3233,10 @@ "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, + "settable_globally": true }, "wireframe_printspeed": { @@ -2544,7 +3249,10 @@ "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, + "settable_globally": true, "children": { "wireframe_printspeed_bottom": @@ -2558,8 +3266,11 @@ "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, + "settable_globally": true }, "wireframe_printspeed_up": { @@ -2572,8 +3283,11 @@ "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, + "settable_globally": true }, "wireframe_printspeed_down": { @@ -2586,8 +3300,11 @@ "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, + "settable_globally": true }, "wireframe_printspeed_flat": { @@ -2601,7 +3318,10 @@ "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, + "settable_globally": true } } }, @@ -2615,7 +3335,10 @@ "maximum_value_warning": "100", "type": "float", "enabled": "wireframe_enabled", - "global_only": "True", + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": true, "children": { "wireframe_flow_connection": @@ -2628,8 +3351,11 @@ "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, + "settable_globally": true }, "wireframe_flow_flat": { @@ -2641,8 +3367,11 @@ "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, + "settable_globally": true } } }, @@ -2656,7 +3385,10 @@ "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, + "settable_globally": true }, "wireframe_bottom_delay": { @@ -2668,7 +3400,10 @@ "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, + "settable_globally": true }, "wireframe_flat_delay": { @@ -2680,7 +3415,10 @@ "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, + "settable_globally": true }, "wireframe_up_half_speed": { @@ -2692,7 +3430,10 @@ "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, + "settable_globally": true }, "wireframe_top_jump": { @@ -2704,7 +3445,10 @@ "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, + "settable_globally": true }, "wireframe_fall_down": { @@ -2716,7 +3460,10 @@ "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, + "settable_globally": true }, "wireframe_drag_along": { @@ -2728,7 +3475,10 @@ "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, + "settable_globally": true }, "wireframe_strategy": { @@ -2743,7 +3493,10 @@ }, "default_value": "compensate", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": true }, "wireframe_straight_before_down": { @@ -2755,7 +3508,10 @@ "minimum_value": "0", "maximum_value": "100", "enabled": "wireframe_enabled", - "global_only": "True" + "settable_per_mesh": false, + "settable_per_extruder": false, + "settable_per_meshgroup": false, + "settable_globally": true }, "wireframe_roof_fall_down": { @@ -2767,7 +3523,10 @@ "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, + "settable_globally": true }, "wireframe_roof_drag_along": { @@ -2779,7 +3538,10 @@ "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, + "settable_globally": true }, "wireframe_roof_outer_delay": { @@ -2791,7 +3553,10 @@ "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, + "settable_globally": true }, "wireframe_nozzle_clearance": { @@ -2803,7 +3568,10 @@ "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, + "settable_globally": true } } } From fc0a3c83472e77b0fa0ff7484361c4a92a665ca2 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Tue, 7 Jun 2016 18:30:30 +0200 Subject: [PATCH 201/304] JSON feat: replaced global_only with four properties settable_per_[mesh|extruder|meshgroup] and settable_globally for fdmextruder settings (CURA-1558) --- resources/definitions/fdmextruder.def.json | 56 +++++++++++++++++----- 1 file changed, 45 insertions(+), 11 deletions(-) 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 } } } From 21b1891c0ee72afa44a6d606fe40ff5a11bc8776 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 18:55:27 +0200 Subject: [PATCH 202/304] Make unique name generation more robust and simpler CURA-1585 --- cura/MachineManagerModel.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index c0ac74abe4..202ca3611c 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -106,14 +106,12 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(containers[0]) @pyqtSlot(str, str) - def addMachine(self,name, definition_id): + def addMachine(self, name, definition_id): definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) if definitions: definition = definitions[0] + name = self._createUniqueName("machine", "", name, definition.getName()) new_global_stack = UM.Settings.ContainerStack(name) - name = self._createUniqueName(new_global_stack, "machine", name, definition.getName()) - new_global_stack._id = name - new_global_stack.setName(name) new_global_stack.addMetaDataEntry("type", "machine") UM.Settings.ContainerRegistry.getInstance().addContainer(new_global_stack) @@ -142,12 +140,12 @@ class MachineManagerModel(QObject): Application.getInstance().setGlobalContainerStack(new_global_stack) ## Create a name that is not empty and unique - # \param container \type{} container to create a unique name for # \param container_type \type{string} Type of the container (machine, quality, ...) - # \param new_name \type{string} Name base name, which may not be unique + # \param current_name \type{} Current name of the container, which may be an acceptable option + # \param new_name \type{string} Base name, which may not be unique # \param fallback_name \type{string} Name to use when (stripped) new_name is empty # \return \type{string} Name that is unique for the specified type and name/id - def _createUniqueName(self, container, object_type, new_name, fallback_name): + def _createUniqueName(self, container_type, current_name, new_name, fallback_name): new_name = new_name.strip() num_check = re.compile("(.*?)\s*#\d+$").match(new_name) if num_check: @@ -157,7 +155,8 @@ class MachineManagerModel(QObject): unique_name = new_name i = 1 - while self._containerWithIdOrNameExists(unique_name, object_type, container): + # In case we are renaming, the current name of the container is also a valid end-result + while self._containerExists(container_type, unique_name) and unique_name != current_name: i += 1 unique_name = "%s #%d" % (new_name, i) @@ -165,17 +164,13 @@ class MachineManagerModel(QObject): ## Check if a container with of a certain type and a certain name or id exists # Both the id and the name are checked, because they may not be the same and it is better if they are both unique - def _containerWithIdOrNameExists(self, id_or_name, container_type, exclude_container = None): + # \param container_type \type{string} Type of the container (machine, quality, ...) + # \param container_name \type{string} Name to check + def _containerExists(self, container_type, container_name): container_class = ContainerStack if container_type == "machine" else InstanceContainer - containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = id_or_name, type = container_type) - if containers and containers[0] != exclude_container: - return True - containers = UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = id_or_name, type = container_type) - if containers and containers[0] != exclude_container: - return True - - return False + return UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, id = container_name, type = container_type) or \ + UM.Settings.ContainerRegistry.getInstance().findContainers(container_class, name = container_name, type = container_type) ## Convenience function to check if a stack has errors. def _checkStackForErrors(self, stack): @@ -274,7 +269,7 @@ class MachineManagerModel(QObject): return new_quality_container = InstanceContainer("") - name = self._createUniqueName(new_quality_container, "quality", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) + name = self._createUniqueName("quality", "", self.activeQualityName, catalog.i18nc("@label", "Custom profile")) user_settings = self._global_container_stack.getTop() ## Copy all values @@ -303,7 +298,7 @@ class MachineManagerModel(QObject): return containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id=container_id) if containers: - new_name = self._createUniqueName(containers[0], "quality", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName("quality", "", containers[0].getName(), catalog.i18nc("@label", "Custom profile")) new_container = InstanceContainer("") @@ -323,7 +318,7 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - new_name = self._createUniqueName(containers[0], "quality", new_name, catalog.i18nc("@label", "Custom profile")) + new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) @@ -426,7 +421,7 @@ class MachineManagerModel(QObject): def renameMachine(self, machine_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id) if containers: - new_name = self._createUniqueName(containers[0], "machine", new_name, containers[0].getBottom().getName()) + new_name = self._createUniqueName("machine", containers[0].getName(), new_name, containers[0].getBottom().getName()) containers[0].setName(new_name) self.globalContainerChanged.emit() From f7480baca2c7f1648571fbf8bb9d1e9a892cddc1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 19:25:12 +0200 Subject: [PATCH 203/304] Fix selecting another quality when the currently active quality is removed CURA-1585 --- cura/MachineManagerModel.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 202ca3611c..5f3ca0b7af 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -335,11 +335,11 @@ class MachineManagerModel(QObject): UM.Settings.ContainerRegistry.getInstance().removeContainer(container_id) if activate_new_container: - old_container = self._global_container_stack.findInstanceContainers({"type": "quality"}) - containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = container_type) - if containers and old_container: - container_index = self._global_container_stack.getContainerIndex(old_container) - self._global_container_stack.replaceContainer(container_index, containers[0]) + definition_id = "fdmprinter" if not self.filterQualityByMachine else self.activeDefinitionId + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "quality", definition = definition_id) + if containers: + self.setActiveQuality(containers[0].getId()) + self.activeQualityChanged.emit() @pyqtSlot() From b452af5dbf5997c92e47ea09a4366d7f876c538d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 7 Jun 2016 19:31:35 +0200 Subject: [PATCH 204/304] Update Profile dropdown when renaming a quality profile CURA-1585 --- cura/MachineManagerModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 5f3ca0b7af..02d8db8290 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -320,7 +320,7 @@ class MachineManagerModel(QObject): if containers: new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) containers[0].setName(new_name) - UM.Settings.ContainerRegistry.getInstance().containerChanged.emit(containers[0]) + self.activeQualityChanged.emit() @pyqtSlot(str) From ec2657947345c7b76f59bbec4ab0898b658c26cc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 14:59:32 +0200 Subject: [PATCH 205/304] Remove unused _repopulate function It is replaced by the addMachineExtruders function. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index df31cbacdf..23a72b2c3b 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -80,23 +80,6 @@ class ExtruderManager(QObject): if extruder_trains: self.extrudersChanged.emit() - ## (Re)populates the collections of extruders by machine. - def _repopulate(self): - self._extruder_trains = { } - if not UM.Application.getInstance().getGlobalContainerStack(): #No machine has been added yet. - self.extrudersChanged.emit() #Yes, we just cleared the _extruders list! - return #Then leave them empty! - - extruder_trains = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "extruder_train") - for extruder_train in extruder_trains: - machine_id = extruder_train.getMetaDataEntry("machine") - if not machine_id: - continue - if machine_id not in self._extruder_trains: - self._extruder_trains[machine_id] = { } - self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() - self.extrudersChanged.emit() - def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): container_registry = UM.Settings.ContainerRegistry.getInstance() From f461ed0f5f62f2cbf556c32037298bb5c7052514 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 15:26:51 +0200 Subject: [PATCH 206/304] Document singleton Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 23a72b2c3b..b40bb0f664 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -39,7 +39,18 @@ class ExtruderManager(QObject): 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 + ## The instance of the singleton pattern. + # + # It's None if the extruder manager hasn't been created yet. __instance = None + + ## Gets an instance of the extruder manager, or creates one if no instance + # exists yet. + # + # This is an implementation of singleton. If an extruder manager already + # exists, it is re-used. + # + # \return The extruder manager. @classmethod def getInstance(cls): if not cls.__instance: From 98a0f90dae4764bfb77ca6feaf92412e7716aaf3 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 16:56:55 +0200 Subject: [PATCH 207/304] Remove unused variable _active_extruder_index This index is managed by ExtruderManager. Contributes to issues CURA-340 and CURA-1278. --- cura/MachineManagerModel.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 02d8db8290..e7034412f5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -36,8 +36,6 @@ class MachineManagerModel(QObject): active_machine_id = Preferences.getInstance().getValue("cura/active_machine") - self._active_extruder_index = 0 - if active_machine_id != "": # An active machine was saved, so restore it. self.setActiveMachine(active_machine_id) From 8b1c36393261608ade3257386d613cb72d5e32cd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 7 Jun 2016 17:37:25 +0200 Subject: [PATCH 208/304] Load current machine's extruders upon creation, start and switch of machines This requires some trickery of initialising the extruder manager before the machine manager is initialised, so that it properly listens to global container stack changes. Contributes to issues CURA-340 and CURA-1278. --- cura/CuraApplication.py | 1 + cura/ExtruderManager.py | 29 ++++++++++++++++++++++++----- cura/ExtrudersModel.py | 11 ++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7edb0bf8bd..37ba6cf7ad 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -351,6 +351,7 @@ class CuraApplication(QtApplication): self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface...")) + ExtruderManager.ExtruderManager.getInstance() #Initialise extruder so as to listen to global container stack changes before the first global container stack is set. qmlRegisterSingletonType(MachineManagerModel.MachineManagerModel, "Cura", 1, 0, "MachineManager", MachineManagerModel.createMachineManagerModel) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b40bb0f664..c71dd27414 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.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 pyqtSignal, pyqtProperty, pyqtSlot, QObject #For communicating data and events to Qt. +from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject, QVariant #For communicating data and events to Qt. import UM.Application #To get the global container stack to find the current machine. import UM.Logger @@ -13,7 +13,7 @@ import UM.Settings.ContainerRegistry #Finding containers by ID. # This keeps a list of extruder stacks for each machine. class ExtruderManager(QObject): ## Signal to notify other components when the list of extruders changes. - extrudersChanged = pyqtSignal() + extrudersChanged = pyqtSignal(QVariant) ## Notify when the user switches the currently active extruder. activeExtruderChanged = pyqtSignal() @@ -21,8 +21,9 @@ class ExtruderManager(QObject): ## Registers listeners and such to listen to changes to the extruders. def __init__(self, parent = None): super().__init__(parent) - self._extruder_trains = { } #Extruders for the current machine. + self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs. self._active_extruder_index = 0 + UM.Application.getInstance().globalContainerStackChanged.connect(self._addCurrentMachineExtruders) ## Gets the unique identifier of the currently active extruder stack. # @@ -79,7 +80,7 @@ class ExtruderManager(QObject): for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition.getId()): position = extruder_definition.getMetaDataEntry("position", None) if not position: - UM.Logger.Log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) + UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet. name = container_registry.uniqueName(extruder_definition.getId()) #Make a name based on the ID of the definition. self.createExtruderTrain(extruder_definition, machine_definition, name, position) @@ -89,7 +90,7 @@ class ExtruderManager(QObject): for extruder_train in extruder_trains: self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train.getId() if extruder_trains: - self.extrudersChanged.emit() + self.extrudersChanged.emit(machine_definition) def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): container_registry = UM.Settings.ContainerRegistry.getInstance() @@ -156,3 +157,21 @@ class ExtruderManager(QObject): container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) 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: + 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]: + extruder_train = container_registry.findContainerStacks(id = extruder_train_id) + if extruder_train: + yield extruder_train[0] + + ## 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 diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 7e00611742..691a5c7690 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -9,7 +9,8 @@ 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. +# intended for drop-down lists of the current machine's extruders in place of +# settings. class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 1 @@ -37,7 +38,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) #When the list of extruders changes in general. + UM.Application.globalContainerStackChanged.connect(self._updateExtruders) #When the current machine changes. self._updateExtruders() ## Update the list of extruders. @@ -46,7 +48,10 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def _updateExtruders(self): self.clear() manager = cura.ExtruderManager.ExtruderManager.getInstance() - for index, extruder in enumerate(manager._extruder_trains): + 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 manager.getMachineExtruders(global_container_stack.getBottom()): item = { #Construct an item with only the relevant information. "name": extruder.name, "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), From 2e2437d1632250aa1588b9b24faebbdcb38b50f9 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Wed, 8 Jun 2016 10:50:40 +0200 Subject: [PATCH 209/304] feat: use settable_per_[mesh|extruder|meshgroup|globally] instead of global_only (CURA-1560) --- cura/CuraApplication.py | 5 ++++- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 7edb0bf8bd..646e257ff3 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -91,7 +91,10 @@ 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.addSupportedProperty("settable_per_mesh", DefinitionPropertyType.Function, default = True) + SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Function, default = True) + SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Function, default = True) + SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Function, default = True) SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator) super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index c89485517e..bc721782ae 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -190,11 +190,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 +219,7 @@ Item { containerId: Cura.MachineManager.activeDefinitionId filter: { - "global_only": false + "settable_per_mesh": true } visibilityHandler: UM.SettingPreferenceVisibilityHandler {} } From 1a8fe6aa1fb7dd22034f02d61338d1e8d1faab04 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 10:55:48 +0200 Subject: [PATCH 210/304] Fix customised settings indicator CURA-1585 --- resources/qml/ProfileSetup.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index c6291c8c85..48d52c539a 100644 --- a/resources/qml/ProfileSetup.qml +++ b/resources/qml/ProfileSetup.qml @@ -143,7 +143,7 @@ Item{ UM.SimpleButton { id: customisedSettings - visible: UM.ActiveProfile.hasCustomisedValues + visible: Cura.MachineManager.hasUserSettings height: parent.height * 0.6 width: parent.height * 0.6 From 77431b01a3ddb88952c6d2283e420386cb92d19e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jun 2016 11:02:04 +0200 Subject: [PATCH 211/304] Inherit button now has the same behaviour as 2.1 again CURA-1278 --- resources/qml/Settings/SettingItem.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index e4edc267ef..eb8fabec28 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -24,7 +24,7 @@ Item { // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise) property var state: propertyProvider.properties.state - property var stackLevel: propertyProvider.stackLevel + property var stackLevel: propertyProvider.stackLevels[0] signal contextMenuRequested() signal showTooltip(string text); @@ -166,7 +166,15 @@ Item { onClicked: { focus = true; - propertyProvider.removeFromContainer(base.stackLevel) + // 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. + propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) } backgroundColor: UM.Theme.getColor("setting_control"); From af484b03d80a5379c5eebd38b1a26f3e89a66cfd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 10:45:32 +0200 Subject: [PATCH 212/304] Fix typo in variable name --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- resources/qml/Settings/SettingItem.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 9565b0e345..667f842469 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -61,7 +61,7 @@ Item { onLoaded: { settingLoader.item.showRevertButton = false settingLoader.item.showInheritButton = false - settingLoader.item.doDepthIdentation = false + settingLoader.item.doDepthIndentation = false } sourceComponent: diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index eb8fabec28..4fa615134b 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -20,7 +20,7 @@ Item { property var showRevertButton: true property var showInheritButton: true - property var doDepthIdentation: true + property var doDepthIndentation: true // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise) property var state: propertyProvider.properties.state @@ -101,7 +101,7 @@ Item { id: label; anchors.left: parent.left; - anchors.leftMargin: doDepthIdentation ? (UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width) : 0 + anchors.leftMargin: doDepthIndentation ? (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 From 4aa495f9efa8dba6120c129f193186502c6d802b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 10:56:51 +0200 Subject: [PATCH 213/304] Fix getting name and colour from extruder There used to be an extruder object from which we could ask these properties. But now we have a container stack in its place, so we need to get the properties in a slightly different way. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtrudersModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 691a5c7690..cd85181787 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -53,8 +53,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): return #There is no machine to get the extruders of. for index, extruder in manager.getMachineExtruders(global_container_stack.getBottom()): item = { #Construct an item with only the relevant information. - "name": extruder.name, - "colour": extruder.material.getMetaDataEntry("color_code", default = "#FFFF00"), + "name": extruder.getName(), + "colour": extruder.findContainer(type = "material").getMetaDataEntry("color_code", default = "#FFFF00"), "index": index } self.appendItem(item) From 675a8c140e1bf22ed9c396298ff150d66f9d7e69 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:00:50 +0200 Subject: [PATCH 214/304] Give default colour if there is no material Otherwise it would try to call getMetaDataEntry on None. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtrudersModel.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index cd85181787..a915a21506 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -52,9 +52,11 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): if not global_container_stack: return #There is no machine to get the extruders of. for index, extruder in 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(), - "colour": extruder.findContainer(type = "material").getMetaDataEntry("color_code", default = "#FFFF00"), + "colour": colour, "index": index } self.appendItem(item) From 91797c3944c24e41b16883bb55f48d4294c046c1 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:09:08 +0200 Subject: [PATCH 215/304] Log error if the machine refers to invalid extruder train ID This helped mostly for debugging but it should be a genuine warning. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c71dd27414..3be0694440 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -169,6 +169,8 @@ class ExtruderManager(QObject): 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) ## Adds the extruders of the currently active machine. def _addCurrentMachineExtruders(self): From 21545af5c8eb425faee88caf1ca703ea8ea9ef1a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:10:41 +0200 Subject: [PATCH 216/304] Get only values from extruder trains dictionary Instead of getting the keys, which are labeled '0' and '1', we'd like to get the values, which are the extruder train IDs themselves. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 3be0694440..8219066eca 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -165,7 +165,7 @@ class ExtruderManager(QObject): if not machine_id 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]: + 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] From 8c7b3a05b654e2eea12cf6a2a6525e6e97950bfc Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:22:03 +0200 Subject: [PATCH 217/304] Enumerate again over the machine's extruders We needed to get the index, after all. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index a915a21506..a95f9f8a99 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -51,7 +51,7 @@ 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 manager.getMachineExtruders(global_container_stack.getBottom()): + 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. From 8b75a230a0adad455787278683863bd70c63df41 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 11:24:41 +0200 Subject: [PATCH 218/304] Fix findContainer call without kwargs It has no kwargs. This needs to be provided as dictionary. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index a95f9f8a99..60bd60abab 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -52,7 +52,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): 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") + 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(), From 56b00ad4250b276c69eceee517d90c9c3c8dfde4 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Wed, 8 Jun 2016 11:54:25 +0200 Subject: [PATCH 219/304] JSON cleanup: removed settable_per_x when they were obvious and default (CURA-1560) removed:settable_globally: true settable_per_meshgroup: true settable_per_extruder: true when settable_per_mesh was also true --- cura/CuraApplication.py | 8 +- resources/definitions/fdmprinter.def.json | 886 +++++----------------- 2 files changed, 203 insertions(+), 691 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 646e257ff3..da2b38ade7 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -91,10 +91,10 @@ 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("settable_per_mesh", DefinitionPropertyType.Function, default = True) - SettingDefinition.addSupportedProperty("settable_per_extruder", DefinitionPropertyType.Function, default = True) - SettingDefinition.addSupportedProperty("settable_per_meshgroup", DefinitionPropertyType.Function, default = True) - SettingDefinition.addSupportedProperty("settable_globally", DefinitionPropertyType.Function, default = True) + 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) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index f80d5d0d8f..504a0eac83 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -35,8 +35,7 @@ "label": "Show machine variants", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_start_gcode": { @@ -46,8 +45,7 @@ "type": "str", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_end_gcode": { @@ -57,8 +55,7 @@ "type": "str", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "material_bed_temp_wait": { @@ -68,8 +65,7 @@ "type": "bool", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "material_print_temp_prepend": { @@ -79,8 +75,7 @@ "label": "Wait for material heatup", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_width": { @@ -90,8 +85,7 @@ "label": "Machine width", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_depth": { @@ -101,8 +95,7 @@ "label": "Machine depth", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_height": { @@ -112,8 +105,7 @@ "label": "Machine height", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_heated_bed": { @@ -123,8 +115,7 @@ "type": "bool", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_center_is_zero": { @@ -134,8 +125,7 @@ "label": "Is center origin", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_extruder_count": { @@ -145,8 +135,7 @@ "label": "Number extruders", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_nozzle_tip_outer_diameter": { @@ -167,8 +156,7 @@ "label": "Nozzle length", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_nozzle_expansion_angle": { @@ -178,8 +166,7 @@ "label": "Nozzle angle", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_heat_zone_length": { @@ -189,8 +176,7 @@ "label": "Heat zone length", "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_nozzle_heat_up_speed": { @@ -199,9 +185,7 @@ "type": "float", "label": "Heat up speed", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "machine_nozzle_cool_down_speed": { @@ -210,9 +194,7 @@ "type": "float", "label": "Cool down speed", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "machine_gcode_flavor": { @@ -222,8 +204,7 @@ "label": "Gcode flavour", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_disallowed_areas": { @@ -233,8 +214,7 @@ "label": "Disallowed areas", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_head_polygon": { @@ -262,8 +242,7 @@ "label": "Machine head polygon", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_head_with_fans_polygon": { @@ -291,8 +270,7 @@ "label": "Machine head & Fan polygon", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "gantry_height": { @@ -302,8 +280,7 @@ "type": "float", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "machine_nozzle_size": { @@ -315,9 +292,7 @@ "minimum_value": "0.001", "maximum_value_warning": "10", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "machine_use_extruder_offset_to_offset_coords": { @@ -327,8 +302,7 @@ "default_value": true, "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false } } }, @@ -352,9 +326,7 @@ "maximum_value_warning": "0.8 * machine_nozzle_size", "default_value": true, "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "layer_height_0": { @@ -368,9 +340,7 @@ "maximum_value_warning": "0.8 * machine_nozzle_size", "default_value": true, "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "line_width": { @@ -398,9 +368,6 @@ "type": "float", "default_value": true, "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "wall_line_width_0": @@ -414,10 +381,7 @@ "default_value": 0.4, "value":"wall_line_width", "type": "float", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "wall_line_width_x": { @@ -430,10 +394,7 @@ "default_value": 0.4, "value":"wall_line_width", "type": "float", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -448,10 +409,7 @@ "default_value": 0.4, "type": "float", "value": "line_width", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "infill_line_width": { @@ -464,10 +422,7 @@ "default_value": 0.4, "type": "float", "value": "line_width", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "skirt_line_width": { @@ -481,9 +436,7 @@ "type": "float", "value": "line_width", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "support_line_width": { @@ -498,9 +451,7 @@ "enabled": "support_enable", "value": "line_width", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_roof_line_width": { @@ -514,9 +465,7 @@ "enabled": "support_roof_enable", "value": "line_width", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "prime_tower_line_width": { @@ -531,9 +480,7 @@ "minimum_value_warning": "0.2", "maximum_value_warning": "5", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } } @@ -558,9 +505,6 @@ "maximum_value_warning": "5 * line_width", "type": "float", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "wall_line_count": @@ -571,10 +515,7 @@ "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)", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -589,9 +530,6 @@ "minimum_value_warning": "0.6", "type": "float", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "top_thickness": @@ -605,9 +543,6 @@ "type": "float", "value": "top_bottom_thickness", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "top_layers": @@ -619,10 +554,7 @@ "maximum_value_warning": "100", "type": "int", "value": "0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / layer_height, 4))", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -636,9 +568,6 @@ "type": "float", "value": "top_bottom_thickness", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "bottom_layers": @@ -649,10 +578,7 @@ "default_value": 6, "type": "int", "value": "999999 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / layer_height, 4))", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } } @@ -670,10 +596,7 @@ "zigzag": "Zig Zag" }, "default_value": "lines", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "wall_0_inset": { @@ -685,10 +608,7 @@ "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", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "alternate_extra_perimeter": { @@ -696,10 +616,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "travel_compensate_overlapping_walls_enabled": { @@ -708,9 +625,6 @@ "type": "bool", "default_value": true, "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "travel_compensate_overlapping_walls_0_enabled": { @@ -719,10 +633,7 @@ "type": "bool", "default_value": true, "value": "travel_compensate_overlapping_walls_enabled", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "travel_compensate_overlapping_walls_x_enabled": { "label": "Compensate Inner Wall Overlaps", @@ -730,10 +641,7 @@ "type": "bool", "default_value": true, "value": "travel_compensate_overlapping_walls_enabled", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -746,10 +654,7 @@ "minimum_value_warning": "-10", "maximum_value_warning": "10", "default_value": 0, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "z_seam_type": { @@ -763,10 +668,7 @@ "random": "Random" }, "default_value": "shortest", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "skin_no_small_gaps_heuristic": { @@ -774,10 +676,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -799,9 +698,6 @@ "minimum_value": "0", "maximum_value_warning": "100", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "infill_line_distance": @@ -813,10 +709,7 @@ "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))", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -835,10 +728,7 @@ }, "default_value": "grid", "value": "'lines' if infill_sparse_density > 25 else 'grid'", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "infill_overlap": { @@ -852,9 +742,6 @@ "maximum_value_warning": "100", "enabled": "infill_pattern != 'concentric'", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "infill_overlap_mm": @@ -868,10 +755,7 @@ "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'", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -886,9 +770,6 @@ "value": "5 if top_bottom_pattern != 'concentric' else 0", "enabled": "top_bottom_pattern != 'concentric'", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "skin_overlap_mm": { "label": "Skin Overlap", @@ -900,10 +781,7 @@ "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'", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -917,10 +795,7 @@ "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", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "infill_sparse_thickness": { @@ -933,10 +808,7 @@ "maximum_value_warning": "0.32", "maximum_value": "layer_height * 8", "value": "layer_height", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "infill_before_walls": { @@ -944,10 +816,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -967,9 +836,7 @@ "default_value": false, "enabled": "False", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "material_print_temperature": { @@ -982,9 +849,7 @@ "maximum_value_warning": "260", "enabled": "not (material_flow_dependent_temperature)", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "material_flow_temp_graph": { @@ -996,9 +861,7 @@ "enabled": "False", "comments": "old enabled function: material_flow_dependent_temperature", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "material_extrusion_cool_down_speed": { "label": "Extrusion Cool Down Speed Modifier", @@ -1011,9 +874,7 @@ "enabled": "False", "comments": "old enabled function: material_flow_dependent_temperature or machine_extruder_count > 1", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "material_bed_temperature": { "label": "Bed Temperature", @@ -1026,8 +887,7 @@ "enabled": "machine_heated_bed", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "material_diameter": { "label": "Diameter", @@ -1039,9 +899,7 @@ "minimum_value_warning": "0.4", "maximum_value_warning": "3.5", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "material_flow": { "label": "Flow", @@ -1052,20 +910,14 @@ "minimum_value": "5", "minimum_value_warning": "50", "maximum_value_warning": "150", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_amount": { "label": "Retraction Distance", @@ -1076,10 +928,7 @@ "minimum_value_warning": "-0.0001", "maximum_value_warning": "10.0", "enabled": "retraction_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_speed": { "label": "Retraction Speed", @@ -1092,9 +941,6 @@ "maximum_value_warning": "100", "enabled": "retraction_enable", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "retraction_retract_speed": { "label": "Retraction Retract Speed", @@ -1107,10 +953,7 @@ "maximum_value_warning": "100", "enabled": "retraction_enable", "value": "retraction_speed", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_prime_speed": { "label": "Retraction Prime Speed", @@ -1123,10 +966,7 @@ "maximum_value_warning": "100", "enabled": "retraction_enable", "value": "retraction_speed", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -1139,10 +979,7 @@ "minimum_value_warning": "-0.0001", "maximum_value_warning": "5.0", "enabled": "retraction_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_min_travel": { "label": "Retraction Minimum Travel", @@ -1154,10 +991,7 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "retraction_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_count_max": { "label": "Maximum Retraction Count", @@ -1167,10 +1001,7 @@ "maximum_value_warning": "100", "type": "int", "enabled": "retraction_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_extrusion_window": { "label": "Minimum Extrusion Distance Window", @@ -1182,10 +1013,7 @@ "maximum_value_warning": "retraction_amount * 2", "value": "retraction_amount", "enabled": "retraction_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "retraction_hop": { "label": "Z Hop when Retracting", @@ -1196,10 +1024,7 @@ "minimum_value_warning": "-0.0001", "maximum_value_warning": "10", "enabled": "retraction_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "material_standby_temperature": { @@ -1211,9 +1036,7 @@ "minimum_value": "0", "maximum_value_warning": "260", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "switch_extruder_retraction_amount": { @@ -1227,9 +1050,7 @@ "minimum_value_warning": "0", "maximum_value_warning": "100", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "switch_extruder_retraction_speeds": { @@ -1243,8 +1064,6 @@ "maximum_value_warning": "300", "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "switch_extruder_retraction_speed": @@ -1259,9 +1078,7 @@ "minimum_value": "0.1", "maximum_value_warning": "300", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "switch_extruder_prime_speed": { @@ -1275,9 +1092,7 @@ "minimum_value": "0.1", "maximum_value_warning": "300", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1292,9 +1107,7 @@ "maximum_value_warning": "10", "enabled": "retraction_enable", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1317,9 +1130,6 @@ "maximum_value": "299792458000", "default_value": 60, "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "speed_infill": @@ -1333,10 +1143,7 @@ "maximum_value_warning": "150", "default_value": 60, "value": "speed_print", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "speed_wall": { @@ -1350,9 +1157,6 @@ "default_value": 30, "value": "speed_print / 2", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "speed_wall_0": @@ -1366,10 +1170,7 @@ "maximum_value_warning": "150", "default_value": 30, "value": "speed_wall", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "speed_wall_x": { @@ -1382,10 +1183,7 @@ "maximum_value_warning": "150", "default_value": 60, "value": "speed_wall * 2", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -1400,10 +1198,7 @@ "maximum_value_warning": "150", "default_value": 30, "value": "speed_print / 2", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "speed_support": { @@ -1419,8 +1214,6 @@ "enabled": "support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "speed_support_infill": @@ -1436,9 +1229,7 @@ "value": "speed_support", "enabled": "support_enable", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "speed_support_roof": { @@ -1453,9 +1244,7 @@ "enabled": "support_roof_enable and support_enable", "value": "speed_support / 1.5", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false } } }, @@ -1471,9 +1260,7 @@ "minimum_value": "0.1", "maximum_value_warning": "150", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1489,9 +1276,7 @@ "maximum_value_warning": "300", "value": "speed_print if magic_spiralize else 120", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "speed_layer_0": { "label": "Initial Layer Speed", @@ -1502,10 +1287,7 @@ "minimum_value": "0.1", "maximum_value": "299792458000", "maximum_value_warning": "300", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "skirt_speed": { "label": "Skirt Speed", @@ -1518,9 +1300,7 @@ "maximum_value_warning": "300", "value": "speed_layer_0", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "speed_slowdown_layers": { @@ -1532,9 +1312,7 @@ "maximum_value": "299792458000", "maximum_value_warning": "300", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false } } }, @@ -1558,10 +1336,7 @@ "noskin": "No Skin" }, "default_value": "all", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "travel_avoid_other_parts": { @@ -1571,9 +1346,7 @@ "default_value": true, "enabled": "retraction_combing != \"off\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "travel_avoid_distance": { @@ -1587,9 +1360,7 @@ "maximum_value_warning": "machine_nozzle_tip_outer_diameter * 5", "enabled": "retraction_combing != \"off\" and travel_avoid_other_parts", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1608,9 +1379,7 @@ "type": "bool", "default_value": true, "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "cool_fan_speed": { @@ -1625,8 +1394,6 @@ "enabled": "cool_fan_enabled", "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "cool_fan_speed_min": @@ -1641,9 +1408,7 @@ "default_value": 100, "enabled": "cool_fan_enabled", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "cool_fan_speed_max": { @@ -1657,9 +1422,7 @@ "enabled": "cool_fan_enabled", "value": "cool_fan_speed", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1673,9 +1436,7 @@ "minimum_value": "cool_min_layer_time", "maximum_value_warning": "600", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "cool_fan_full_at_height": { @@ -1689,8 +1450,6 @@ "maximum_value_warning": "10.0", "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "cool_fan_full_layer": @@ -1703,9 +1462,7 @@ "maximum_value_warning": "100", "value": "max(0, int(round((cool_fan_full_at_height - layer_height_0) / layer_height, 0)))", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1719,9 +1476,7 @@ "minimum_value": "0", "maximum_value_warning": "600", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "cool_min_speed": { @@ -1733,9 +1488,7 @@ "minimum_value": "0", "maximum_value_warning": "100", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "cool_lift_head": { @@ -1744,9 +1497,7 @@ "type": "bool", "default_value": false, "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -1764,10 +1515,7 @@ "description": "Enable support structures. These structures support parts of the model with severe overhangs.", "type": "bool", "default_value": false, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_type": { @@ -1782,9 +1530,7 @@ "default_value": "everywhere", "enabled": "support_enable", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_angle": { @@ -1796,10 +1542,7 @@ "maximum_value": "90", "default_value": 50, "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_pattern": { @@ -1817,9 +1560,7 @@ "default_value": "zigzag", "enabled": "support_enable", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_connect_zigzags": { @@ -1829,9 +1570,7 @@ "default_value": true, "enabled": "support_enable and (support_pattern == \"zigzag\")", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_infill_rate": { @@ -1845,8 +1584,6 @@ "enabled": "support_enable", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "support_line_distance": { @@ -1859,9 +1596,7 @@ "enabled": "support_enable", "value": "(support_line_width * 100) / support_infill_rate * (2 if support_pattern == \"grid\" else (3 if support_pattern == \"triangles\" else 1))", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false } } }, @@ -1876,9 +1611,6 @@ "default_value": 0.15, "enabled": "support_enable", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "support_top_distance": @@ -1892,10 +1624,7 @@ "type": "float", "enabled": "support_enable", "value": "support_z_distance", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_bottom_distance": { @@ -1908,10 +1637,7 @@ "value": "0.1 if support_type == 'everywhere' else 0", "type": "float", "enabled": "support_enable and support_type == 'everywhere'", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -1925,10 +1651,7 @@ "maximum_value_warning": "10", "default_value": 0.7, "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_xy_overrides_z": { "label": "Support Distance Priority", @@ -1940,10 +1663,7 @@ }, "default_value": "z_overrides_xy", "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_xy_distance_overhang": { "label": "Minimum Support X/Y Distance", @@ -1955,10 +1675,7 @@ "default_value": 0.2, "value": "machine_nozzle_size / 2", "enabled": "support_enable and support_xy_overrides_z=='z_overrides_xy'", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_bottom_stair_step_height": { @@ -1970,10 +1687,7 @@ "minimum_value": "0", "maximum_value_warning": "1.0", "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_join_distance": { @@ -1985,10 +1699,7 @@ "minimum_value_warning": "0", "maximum_value_warning": "10", "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_offset": { @@ -2000,10 +1711,7 @@ "minimum_value_warning": "-0.5", "maximum_value_warning": "5.0", "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_area_smoothing": { @@ -2015,10 +1723,7 @@ "minimum_value": "0", "maximum_value_warning": "1.0", "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_roof_enable": { @@ -2027,10 +1732,7 @@ "type": "bool", "default_value": false, "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_roof_height": { @@ -2042,10 +1744,7 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "support_roof_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_roof_density": { @@ -2059,8 +1758,6 @@ "enabled":"support_roof_enable", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "support_roof_line_distance": @@ -2074,9 +1771,7 @@ "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", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false } } }, @@ -2096,9 +1791,7 @@ "default_value": "concentric", "enabled": "support_roof_enable", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_use_towers": { @@ -2107,10 +1800,7 @@ "type": "bool", "default_value": true, "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_tower_diameter": { @@ -2122,10 +1812,7 @@ "minimum_value": "0", "maximum_value_warning": "10", "enabled": "support_enable and support_use_towers", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_minimal_diameter": { @@ -2138,10 +1825,7 @@ "maximum_value_warning": "10", "maximum_value": "support_tower_diameter", "enabled": "support_enable and support_use_towers", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_tower_roof_angle": { @@ -2153,10 +1837,7 @@ "maximum_value": "90", "default_value": 65, "enabled": "support_enable and support_use_towers", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -2181,9 +1862,7 @@ }, "default_value": "brim", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "skirt_line_count": { @@ -2195,9 +1874,7 @@ "maximum_value_warning": "10", "enabled": "adhesion_type == \"skirt\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "skirt_gap": { @@ -2210,9 +1887,7 @@ "maximum_value_warning": "100", "enabled": "adhesion_type == \"skirt\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "skirt_minimal_length": { @@ -2226,9 +1901,7 @@ "maximum_value_warning": "2500", "enabled": "adhesion_type == \"skirt\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "brim_width": { @@ -2242,8 +1915,6 @@ "enabled": "adhesion_type == \"brim\"", "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "brim_line_count": @@ -2257,9 +1928,7 @@ "value": "math.ceil(brim_width / skirt_line_width)", "enabled": "adhesion_type == \"brim\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -2285,9 +1954,7 @@ "maximum_value_warning": "1.0", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "layer_0_z_overlap": { "label": "Initial Layer Z Overlap", @@ -2300,9 +1967,7 @@ "maximum_value_warning": "layer_height", "enabled": "adhesion_type == 'raft'", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_surface_layers": { @@ -2314,9 +1979,7 @@ "maximum_value_warning": "20", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_surface_thickness": { @@ -2329,9 +1992,7 @@ "maximum_value_warning": "2.0", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_surface_line_width": { @@ -2344,9 +2005,7 @@ "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_surface_line_spacing": { @@ -2360,9 +2019,7 @@ "enabled": "adhesion_type == \"raft\"", "value": "raft_surface_line_width", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_interface_thickness": { @@ -2375,9 +2032,7 @@ "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_interface_line_width": { @@ -2391,9 +2046,7 @@ "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_interface_line_spacing": { @@ -2406,9 +2059,7 @@ "maximum_value_warning": "15.0", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_base_thickness": { @@ -2421,9 +2072,7 @@ "maximum_value_warning": "5.0", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_base_line_width": { @@ -2437,9 +2086,7 @@ "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_base_line_spacing": { @@ -2452,9 +2099,7 @@ "maximum_value_warning": "100", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_speed": { @@ -2470,8 +2115,6 @@ "value": "speed_print / 60 * 30", "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "raft_surface_speed": @@ -2487,9 +2130,7 @@ "enabled": "adhesion_type == \"raft\"", "value": "raft_speed", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_interface_speed": { @@ -2504,9 +2145,7 @@ "enabled": "adhesion_type == \"raft\"", "value": "0.5 * raft_speed", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_base_speed": { @@ -2521,9 +2160,7 @@ "enabled": "adhesion_type == \"raft\"", "value": "0.5 * raft_speed", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } }, @@ -2538,8 +2175,6 @@ "default_value": 0, "settable_per_mesh": false, "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "enabled": "adhesion_type == \"raft\"", "children": { @@ -2555,9 +2190,7 @@ "value": "raft_fan_speed", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_interface_fan_speed": { @@ -2571,9 +2204,7 @@ "value": "raft_fan_speed", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "raft_base_fan_speed": { @@ -2587,9 +2218,7 @@ "value": "raft_fan_speed", "enabled": "adhesion_type == \"raft\"", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true } } } @@ -2609,10 +2238,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "meshfix_union_all_remove_holes": { @@ -2620,10 +2246,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "meshfix_extensive_stitching": { @@ -2631,10 +2254,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "meshfix_keep_open_polygons": { @@ -2642,10 +2262,7 @@ "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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -2670,8 +2287,7 @@ "default_value": "all_at_once", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "magic_mesh_surface_mode": { @@ -2685,10 +2301,7 @@ "both": "Both" }, "default_value": "normal", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "magic_spiralize": { @@ -2696,10 +2309,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, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -2720,9 +2330,7 @@ "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_extruder_nr": { @@ -2734,8 +2342,6 @@ "maximum_value": "machine_extruder_count - 1", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "support_infill_extruder_nr": { @@ -2747,9 +2353,7 @@ "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_extruder_nr_layer_0": { @@ -2761,9 +2365,7 @@ "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "support_roof_extruder_nr": { @@ -2775,9 +2377,7 @@ "minimum_value": "0", "maximum_value": "machine_extruder_count - 1", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false } } }, @@ -2788,9 +2388,7 @@ "type": "bool", "default_value": false, "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "prime_tower_size": { @@ -2804,9 +2402,7 @@ "minimum_value": "0", "maximum_value_warning": "20", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "prime_tower_position_x": { @@ -2819,9 +2415,7 @@ "minimum_value_warning": "-1000", "maximum_value_warning": "1000", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "prime_tower_position_y": { @@ -2834,9 +2428,7 @@ "minimum_value_warning": "-1000", "maximum_value_warning": "1000", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "prime_tower_flow": { @@ -2850,9 +2442,7 @@ "minimum_value_warning": "50", "maximum_value_warning": "150", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "prime_tower_wipe_enabled": { @@ -2862,9 +2452,7 @@ "enabled": "prime_tower_enable", "default_value": false, "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "multiple_mesh_overlap": { @@ -2875,10 +2463,7 @@ "default_value": 0.15, "minimum_value": "0", "maximum_value_warning": "1.0", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "ooze_shield_enabled": { @@ -2887,9 +2472,7 @@ "type": "bool", "default_value": false, "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "ooze_shield_angle": { @@ -2902,9 +2485,7 @@ "minimum_value": "0", "maximum_value": "90", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "ooze_shield_dist": { @@ -2917,9 +2498,7 @@ "minimum_value": "0", "maximum_value_warning": "30", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false } } }, @@ -2938,9 +2517,7 @@ "type": "bool", "default_value": false, "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "draft_shield_dist": { @@ -2953,9 +2530,7 @@ "default_value": 10, "enabled": "draft_shield_enabled", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "draft_shield_height_limitation": { @@ -2970,9 +2545,7 @@ "default_value": "full", "enabled": "draft_shield_enabled", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "draft_shield_height": { @@ -2986,9 +2559,7 @@ "value": "9999 if draft_shield_height_limitation == 'full' and draft_shield_enabled else 0.0", "enabled": "draft_shield_height_limitation == \"limited\"", "settable_per_mesh": false, - "settable_per_extruder": false, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": false }, "conical_overhang_enabled": { "label": "Make Overhang Printable", @@ -3013,9 +2584,7 @@ "type": "bool", "default_value": false, "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "coasting_volume": { @@ -3028,9 +2597,7 @@ "maximum_value_warning": "2.0", "enabled": "coasting_enable", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "coasting_min_volume": { @@ -3043,9 +2610,7 @@ "maximum_value_warning": "10.0", "enabled": "coasting_enable", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "coasting_speed": { @@ -3058,9 +2623,7 @@ "maximum_value_warning": "100", "enabled": "coasting_enable", "settable_per_mesh": false, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_extruder": true }, "skin_outline_count": { @@ -3070,10 +2633,7 @@ "minimum_value": "0", "maximum_value_warning": "10", "type": "int", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "skin_alternate_rotation": { @@ -3082,10 +2642,7 @@ "type": "bool", "default_value": false, "enabled": "top_bottom_pattern != \"concentric\"", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_conical_enabled": { @@ -3094,10 +2651,7 @@ "type": "bool", "default_value": false, "enabled": "support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_conical_angle": { @@ -3111,10 +2665,7 @@ "maximum_value": "90", "default_value": 30, "enabled": "support_conical_enabled and support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "support_conical_min_width": { @@ -3127,10 +2678,7 @@ "maximum_value_warning": "100.0", "type": "float", "enabled": "support_conical_enabled and support_enable", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "magic_fuzzy_skin_enabled": { @@ -3138,10 +2686,7 @@ "description": "Randomly jitter while printing the outer wall, so that the surface has a rough and fuzzy look.", "type": "bool", "default_value": false, - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "magic_fuzzy_skin_thickness": { @@ -3153,10 +2698,7 @@ "minimum_value": "0.001", "maximum_value_warning": "wall_line_width_0", "enabled": "magic_fuzzy_skin_enabled", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true }, "magic_fuzzy_skin_point_density": { @@ -3171,9 +2713,6 @@ "maximum_value": "2 / magic_fuzzy_skin_thickness", "enabled": "magic_fuzzy_skin_enabled", "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true, "children": { "magic_fuzzy_skin_point_dist": @@ -3188,10 +2727,7 @@ "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", - "settable_per_mesh": true, - "settable_per_extruder": true, - "settable_per_meshgroup": true, - "settable_globally": true + "settable_per_mesh": true } } }, @@ -3203,8 +2739,7 @@ "default_value": false, "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_height": { @@ -3218,8 +2753,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_roof_inset": { @@ -3235,8 +2769,7 @@ "value": "wireframe_height", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_printspeed": { @@ -3252,7 +2785,6 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false, - "settable_globally": true, "children": { "wireframe_printspeed_bottom": @@ -3269,8 +2801,7 @@ "value": "wireframe_printspeed", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_printspeed_up": { @@ -3286,8 +2817,7 @@ "value": "wireframe_printspeed", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_printspeed_down": { @@ -3303,8 +2833,7 @@ "value": "wireframe_printspeed", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_printspeed_flat": { @@ -3320,8 +2849,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false } } }, @@ -3338,7 +2866,6 @@ "settable_per_mesh": false, "settable_per_extruder": false, "settable_per_meshgroup": false, - "settable_globally": true, "children": { "wireframe_flow_connection": @@ -3354,8 +2881,7 @@ "value": "wireframe_flow", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_flow_flat": { @@ -3370,8 +2896,7 @@ "value": "wireframe_flow", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false } } }, @@ -3387,8 +2912,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_bottom_delay": { @@ -3402,8 +2926,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_flat_delay": { @@ -3417,8 +2940,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_up_half_speed": { @@ -3432,8 +2954,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_top_jump": { @@ -3447,8 +2968,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_fall_down": { @@ -3462,8 +2982,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_drag_along": { @@ -3477,8 +2996,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_strategy": { @@ -3495,8 +3013,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_straight_before_down": { @@ -3510,8 +3027,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_roof_fall_down": { @@ -3525,8 +3041,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_roof_drag_along": { @@ -3540,8 +3055,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_roof_outer_delay": { @@ -3555,8 +3069,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false }, "wireframe_nozzle_clearance": { @@ -3570,8 +3083,7 @@ "enabled": "wireframe_enabled", "settable_per_mesh": false, "settable_per_extruder": false, - "settable_per_meshgroup": false, - "settable_globally": true + "settable_per_meshgroup": false } } } From b53926b9de53abc85b2bd8a6345a34563c1acc9f Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 8 Jun 2016 13:29:36 +0200 Subject: [PATCH 220/304] Exclude machine_settings from the settings visible in the sidebar Contrivbutes to CURA-1645 --- resources/qml/Settings/SettingView.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 6261496c84..a6bb60f865 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -29,7 +29,8 @@ ScrollView model: UM.SettingDefinitionsModel { id: definitionsModel; containerId: Cura.MachineManager.activeDefinitionId - visibilityHandler: UM.SettingPreferenceVisibilityHandler {} + exclude: ["machine_settings"] + visibilityHandler: UM.SettingPreferenceVisibilityHandler { } } delegate: Loader From 2cedc69ed19c309f9c348a6ca597ba5b1761d22b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 8 Jun 2016 13:46:30 +0200 Subject: [PATCH 221/304] Remove all special floating point handling code from SettingTextField Since we now always send setting values as string and the conversion from float to string already does the rounding, there is no need to also do it here. Contributes to CURA-1278 Contributes to CURA-389 --- resources/qml/Settings/SettingTextField.qml | 36 +-------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index 2a1fb96330..bf6fc34c93 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -90,21 +90,11 @@ SettingItem Keys.onReleased: { -// text = text.replace(",", ".") // User convenience. We use dots for decimal values -// if(parseFloat(text) != base.parentValue) -// { -// base.valueChanged(parseFloat(text)); -// } - propertyProvider.setPropertyValue("value", text) } onEditingFinished: { -// if(parseFloat(text) != base.parentValue) -// { -// base.valueChanged(parseFloat(text)); -// } propertyProvider.setPropertyValue("value", text) } @@ -121,33 +111,9 @@ SettingItem { target: input property: "text" - value: control.format(propertyProvider.properties.value) + value: propertyProvider.properties.value when: !input.activeFocus } } - - //Rounds a floating point number to 4 decimals. This prevents floating - //point rounding errors. - // - //input: The number to round. - //decimals: The number of decimals (digits after the radix) to round to. - //return: The rounded number. - function roundFloat(input, decimals) - { - //First convert to fixed-point notation to round the number to 4 decimals and not introduce new floating point errors. - //Then convert to a string (is implicit). The fixed-point notation will be something like "3.200". - //Then remove any trailing zeroes and the radix. - return input.toFixed(decimals).replace(/\.?0*$/, ""); //Match on periods, if any ( \.? ), followed by any number of zeros ( 0* ), then the end of string ( $ ). - } - - //Formats a value for display in the text field. - // - //This correctly handles formatting of float values. - // - //input: The string value to format. - //return: The formatted string. - function format(inputValue) { - return parseFloat(inputValue) ? roundFloat(parseFloat(inputValue), 4) : inputValue //If it's a float, round to four decimals. - } } } From e53a961ba72e5090467689d9e95722f7d393d24d Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Wed, 8 Jun 2016 13:49:27 +0200 Subject: [PATCH 222/304] JSON fix: topbottom thickness had max value for no apparent reason (CURA-1352) --- resources/definitions/fdmprinter.def.json | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index ec27abd9f5..2443e08b47 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -461,7 +461,6 @@ "unit": "mm", "default_value": 0.8, "minimum_value": "0", - "maximum_value": "5", "minimum_value_warning": "0.6", "type": "float", "children": From 163642f9ada9585f8582826b89c6f77c171b1a83 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 8 Jun 2016 14:05:16 +0200 Subject: [PATCH 223/304] Also remove the "current_settings" container when removing a machine Contributes to CURA-1628 --- cura/MachineManagerModel.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e7034412f5..2738bfd764 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -427,7 +427,13 @@ class MachineManagerModel(QObject): def removeMachine(self, machine_id): # If the machine that is being removed is the currently active machine, set another machine as the active machine activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id) + + current_settings_id = machine_id + "_current_settings" + containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = current_settings_id) + for container in containers: + UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId()) UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id) + if activate_new_machine: stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "machine") if stacks: From f6ece126c31f62e0984f6a5b31f35e827c3f2dc8 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 12:22:45 +0200 Subject: [PATCH 224/304] Don't re-create user profile if one is loaded from files The user profiles are also saved because they are added to the container registry. So if one exists for this extruder, don't create a new blank name, but use the pre-loaded one which contained the user settings the user had before he closed down Cura previously. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index 8219066eca..a5960be552 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -147,12 +147,15 @@ class ExtruderManager(QObject): self._container_stack.addContainer(self._quality) """ - #Add an empty user profile. - user_profile = UM.Settings.InstanceContainer(extruder_train_id + "_current_settings") - user_profile.addMetaDataEntry("type", "user") - user_profile.setDefinition(machine_definition) + user_profile = container_registry.findInstanceContainers(id = extruder_train_id + "_current_settings") + if user_profile: #There was already a user profile, loaded from settings. + user_profile = user_profile[0] + else: + user_profile = UM.Settings.InstanceContainer(extruder_train_id + "_current_settings") #Add an empty user profile. + user_profile.addMetaDataEntry("type", "user") + user_profile.setDefinition(machine_definition) + container_registry.addContainer(user_profile) container_stack.addContainer(user_profile) - container_registry.addContainer(user_profile) container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack()) From 32f90ad8676d69e536f5775fa912d35e5ec44586 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 13:19:46 +0200 Subject: [PATCH 225/304] Re-add per-extruder nozzles, materials, qualities Slightly more efficient and correct implementation.Contributes to issue CURA-340. --- cura/ExtruderManager.py | 77 +++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index a5960be552..e03bcfd3b3 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -93,7 +93,9 @@ class ExtruderManager(QObject): self.extrudersChanged.emit(machine_definition) def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): + #Cache some things. container_registry = UM.Settings.ContainerRegistry.getInstance() + machine_id = machine_definition.getId() #Create a container stack for this extruder. container_stack = UM.Settings.ContainerStack(extruder_train_id) @@ -102,50 +104,59 @@ class ExtruderManager(QObject): container_stack.addMetaDataEntry("position", position) container_stack.addContainer(extruder_definition) - """ - Yes, I'm committing this code which needs to be transformed to work later. #Find the nozzle to use for this extruder. nozzle = container_registry.getEmptyInstanceContainer() - if definition.getMetaDataEntry("has_nozzles", default = "False") == "True": - if len(self._nozzles) >= 1: #First add any extruder. Later, overwrite with preference if the preference is valid. - self._nozzle = self._nozzles[0] - preferred_nozzle_id = definition.getMetaDataEntry("preferred_nozzle") + if machine_definition.getMetaDataEntry("has_nozzles", default = "False") == "True": + #First add any nozzle. Later, overwrite with preference if the preference is valid. + nozzles = container_registry.findInstanceContainers(machine = machine_id, type = "nozzle") + if len(nozzles) >= 1: + nozzle = nozzles[0] + preferred_nozzle_id = machine_definition.getMetaDataEntry("preferred_nozzle") if preferred_nozzle_id: - for nozzle in self._nozzles: - if nozzle.getId() == preferred_nozzle_id: - self._nozzle = nozzle - break - self._container_stack.addContainer(self._nozzle) + preferred_nozzles = container_registry.findInstanceContainers(id = preferred_nozzle_id, type = "nozzle") + if len(preferred_nozzles) >= 1: + nozzle = preferred_nozzles[0] + else: + UM.Logger.log("w", "The preferred nozzle \"%s\" of machine %s doesn't exist or is not a nozzle profile.", preferred_nozzle_id, machine_id) + #And leave it at the default nozzle. + container_stack.addContainer(nozzle) #Find a material to use for this nozzle. - self._material = container_registry.getEmptyInstanceContainer() - if self._definition.getMetaDataEntry("has_materials", default = "False") == "True": - if self._definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True": - all_materials = container_registry.findInstanceContainers(type = "material", nozzle = self._nozzle.getId()) + material = container_registry.getEmptyInstanceContainer() + if machine_definition.getMetaDataEntry("has_materials", default = "False") == "True": + #First add any material. Later, overwrite with preference if the preference is valid. + if machine_definition.getMetaDataEntry("has_nozzle_materials", default = "False") == "True": + materials = container_registry.findInstanceContainers(type = "material", machine = machine_id, nozzle = nozzle.getId()) else: - all_materials = container_registry.findInstanceContainers(type = "material") - if len(all_materials) >= 1: - self._material = all_materials[0] - preferred_material_id = self._definition.getMetaDataEntry("preferred_material") + materials = container_registry.findInstanceContainers(type = "material", machine = machine_id) + if len(materials) >= 1: + material = materials[0] + preferred_material_id = machine_definition.getMetaDataEntry("preferred_material") if preferred_material_id: - preferred_material = container_registry.findInstanceContainers(type = "material", id = preferred_material_id.lower()) - if len(preferred_material) >= 1: - self._material = preferred_material[0] - self._container_stack.addContainer(self._material) + preferred_materials = container_registry.findInstanceContainers(id = preferred_material_id, type = "material") + if len(preferred_materials) >= 1: + material = preferred_materials[0] + else: + UM.Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id) + #And leave it at the default material. + container_stack.addContainer(material) #Find a quality to use for this extruder. - self._quality = container_registry.getEmptyInstanceContainer() - if self._definition.getMetaDataEntry("has_machine_quality"): - all_qualities = container_registry.findInstanceContainers(type = "quality") - if len(all_qualities) >= 1: - self._quality = all_qualities[0] - preferred_quality_id = self._definition.getMetaDataEntry("preferred_quality") + quality = container_registry.getEmptyInstanceContainer() + if machine_definition.getMetaDataEntry("has_machine_quality"): + #First add any quality. Later, overwrite with preference if the preference is valid. + qualities = container_registry.findInstanceContainers(type = "quality") + if len(qualities) >= 1: + quality = qualities[0] + preferred_quality_id = machine_definition.getMetaDataEntry("preferred_quality") if preferred_quality_id: - preferred_quality = container_registry.findInstanceContainers(type = "quality", id = preferred_quality_id.lower()) + preferred_quality = container_registry.findInstanceContainers(id = preferred_quality_id.lower(), type = "quality") if len(preferred_quality) >= 1: - self._quality = preferred_quality[0] - self._container_stack.addContainer(self._quality) - """ + quality = preferred_quality[0] + else: + UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality_id, machine_id) + #And leave it at the default quality. + container_stack.addContainer(quality) user_profile = container_registry.findInstanceContainers(id = extruder_train_id + "_current_settings") if user_profile: #There was already a user profile, loaded from settings. From fffe9b3a943afa39621f803c21273f5c6c57b101 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 13:56:42 +0200 Subject: [PATCH 226/304] Better naming for extruder slot The name of the extruder stack is now the same as the name for the extruder definition. The IDs are different though! Contributes to issues CURA-1278 and CURA-340. --- cura/ExtruderManager.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index e03bcfd3b3..b67a7f1542 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -82,8 +82,7 @@ class ExtruderManager(QObject): if not position: UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId()) if not container_registry.findContainerStacks(machine = machine_id, position = position): #Doesn't exist yet. - name = container_registry.uniqueName(extruder_definition.getId()) #Make a name based on the ID of the definition. - self.createExtruderTrain(extruder_definition, machine_definition, name, position) + self.createExtruderTrain(extruder_definition, machine_definition, position) #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()) @@ -92,13 +91,15 @@ class ExtruderManager(QObject): if extruder_trains: self.extrudersChanged.emit(machine_definition) - def createExtruderTrain(self, extruder_definition, machine_definition, extruder_train_id, position): + def createExtruderTrain(self, extruder_definition, machine_definition, position): #Cache some things. container_registry = UM.Settings.ContainerRegistry.getInstance() machine_id = machine_definition.getId() #Create a container stack for this extruder. - container_stack = UM.Settings.ContainerStack(extruder_train_id) + extruder_stack_id = container_registry.uniqueName(extruder_definition.getId()) + container_stack = UM.Settings.ContainerStack(extruder_stack_id) + container_stack.setName(extruder_definition.getName()) #Take over the display name to display the stack with. container_stack.addMetaDataEntry("type", "extruder_train") container_stack.addMetaDataEntry("machine", machine_definition.getId()) container_stack.addMetaDataEntry("position", position) @@ -158,11 +159,11 @@ class ExtruderManager(QObject): #And leave it at the default quality. container_stack.addContainer(quality) - user_profile = container_registry.findInstanceContainers(id = extruder_train_id + "_current_settings") + user_profile = container_registry.findInstanceContainers(id = extruder_stack_id + "_current_settings") if user_profile: #There was already a user profile, loaded from settings. user_profile = user_profile[0] else: - user_profile = UM.Settings.InstanceContainer(extruder_train_id + "_current_settings") #Add an empty user profile. + user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") #Add an empty user profile. user_profile.addMetaDataEntry("type", "user") user_profile.setDefinition(machine_definition) container_registry.addContainer(user_profile) From 0a34577fdb898cc24e4cea1305bc53b24669c8f4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 13:59:26 +0200 Subject: [PATCH 227/304] Add documentation for createExtruderTrain Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b67a7f1542..b4d05d7e6c 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -91,6 +91,20 @@ class ExtruderManager(QObject): if extruder_trains: self.extrudersChanged.emit(machine_definition) + ## Creates a container stack for an extruder train. + # + # The container stack has an extruder definition at the bottom, which is + # linked to a machine definition. Then it has a nozzle profile, a material + # profile, a quality profile and a user profile, in that order. + # + # The resulting container stack is added to the registry. + # + # \param extruder_definition The extruder to create the extruder train + # for. + # \param machine_definition The machine that the extruder train belongs + # to. + # \param position The position of this extruder train in the extruder + # slots of the machine. def createExtruderTrain(self, extruder_definition, machine_definition, position): #Cache some things. container_registry = UM.Settings.ContainerRegistry.getInstance() From 59c8a4e66d5c0b8f5a2cc1b5fbb2a3e9af9c4629 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 14:16:13 +0200 Subject: [PATCH 228/304] Fix validation of extruder-type settings Based on how ints are validated, since the data is the same. Contributes to issues CURA-1278 and CURA-340. --- cura/CuraApplication.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 37ba6cf7ad..8acd3eda2a 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -47,6 +47,7 @@ from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENU from PyQt5.QtGui import QColor, QIcon from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType +import ast #For literal eval of extruder setting types. import platform import sys import os.path @@ -92,7 +93,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) + SettingDefinition.addSettingType("extruder", str, ast.literal_eval, UM.Settings.Validator) super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) From 061cbfe46bc4c9f8e32290484402a2b62a51b419 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Wed, 8 Jun 2016 14:20:06 +0200 Subject: [PATCH 229/304] JSON fix: make base of raft with thicker lines than nozzle size (CURA-695) --- resources/definitions/fdmprinter.def.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index da99c36d51..29db032aa1 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1860,7 +1860,7 @@ "unit": "mm", "type": "float", "default_value": 1, - "value": "line_width", + "value": "line_width * 2", "minimum_value": "0.0001", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", @@ -1898,7 +1898,7 @@ "type": "float", "default_value": 1, "minimum_value": "0.0001", - "value": "line_width", + "value": "line_width * 2", "maximum_value_warning": "machine_nozzle_size * 2", "enabled": "adhesion_type == \"raft\"", "global_only": "True" From 3881ed8a61f40249b96c5e6f2103b73f588e95fb Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jun 2016 14:58:05 +0200 Subject: [PATCH 230/304] Fixed behaviour of inheritance button CURA-1278 --- resources/qml/Settings/SettingItem.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 4fa615134b..2f1a74dba6 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -24,7 +24,8 @@ Item { // Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise) property var state: propertyProvider.properties.state - property var stackLevel: propertyProvider.stackLevels[0] + property var stackLevels: propertyProvider.stackLevels + property var stackLevel: stackLevels[0] signal contextMenuRequested() signal showTooltip(string text); @@ -159,7 +160,7 @@ Item { id: inheritButton; //visible: has_profile_value && base.has_inherit_function && base.is_enabled - visible: base.state == "InstanceState.User" && base.stackLevel > 0 && base.showInheritButton + visible: base.state == "InstanceState.User" && base.showInheritButton height: parent.height; width: height; @@ -175,6 +176,7 @@ Item { // 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") } backgroundColor: UM.Theme.getColor("setting_control"); From cf15f9e2a11a593648bd4217408f6b64934858f6 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jun 2016 15:31:28 +0200 Subject: [PATCH 231/304] Added handling of special case when only user & definition were set CURA-1278 --- resources/qml/Settings/SettingItem.qml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 2f1a74dba6..9ed75bdecf 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -175,8 +175,17 @@ Item { // 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") + if(last_entry == 4 && base.stackLevel == 0) + { + // 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 + { + propertyProvider.setPropertyValue("value", propertyProvider.getPropertyValue("value", last_entry)) + propertyProvider.setPropertyValue("state", "InstanceState.Calculated") + } } backgroundColor: UM.Theme.getColor("setting_control"); From 8a7e549a27c6b6f9fe28c7d944097f093fdf1224 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Wed, 8 Jun 2016 15:40:15 +0200 Subject: [PATCH 232/304] Merge fix of 2.1 Max Retraction count 45 ==> 90 wasn't taken along --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 29db032aa1..8be258c79e 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -890,7 +890,7 @@ "retraction_count_max": { "label": "Maximum Retraction Count", "description": "This setting limits the number of retractions occurring within the minimum extrusion distance window. Further retractions within this window will be ignored. This avoids retracting repeatedly on the same piece of filament, as that can flatten the filament and cause grinding issues.", - "default_value": 45, + "default_value": 90, "minimum_value": "0", "maximum_value_warning": "100", "type": "int", From cc7369c59476aa49bb7c515dc6dca2d4ce75db83 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Wed, 8 Jun 2016 15:43:22 +0200 Subject: [PATCH 233/304] profiles fix: duplicated UM2+ profile changes from 2.1 to the UM2E+ profiles (CURA-1662) --- .../ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg | 2 ++ .../ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg | 1 + .../ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg | 1 + .../ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg | 1 + .../ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg | 1 + .../ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg | 1 + .../ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg | 1 + 7 files changed, 8 insertions(+) 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 f554c7f058..139c8cb976 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 @@ -15,6 +15,8 @@ wall_thickness = 0.7 top_bottom_thickness = 0.75 infill_sparse_density = 18 speed_print = 55 +speed_wall = 40 +speed_topbottom = 30 speed_travel = 150 speed_layer_0 = 30 cool_min_layer_time = 3 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 c1a8136cf5..8d021f4d91 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 @@ -15,6 +15,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.72 infill_sparse_density = 22 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 3 cool_fan_speed_min = 20 cool_min_speed = 10 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 eabc9827a1..3f89bdeee6 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 @@ -15,6 +15,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.8 infill_sparse_density = 20 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 3 cool_fan_speed_min = 20 cool_min_speed = 10 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 64e0ec72fb..ea67bcc0b2 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 @@ -15,6 +15,7 @@ wall_thickness = 1.59 top_bottom_thickness = 1.2 infill_sparse_density = 20 speed_print = 40 +speed_infill = 55 cool_min_layer_time = 3 cool_fan_speed_min = 50 cool_min_speed = 20 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 ae9b437010..5f402d50aa 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 @@ -15,6 +15,7 @@ wall_thickness = 0.7 top_bottom_thickness = 0.75 infill_sparse_density = 18 speed_print = 45 +speed_wall = 40 speed_travel = 150 speed_layer_0 = 30 cool_min_layer_time = 3 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 e3fa254a74..2b35097f66 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 @@ -15,6 +15,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.72 infill_sparse_density = 22 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 2 cool_fan_speed_min = 80 cool_min_speed = 15 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 48e767e1cb..41e9fab6d3 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 @@ -15,6 +15,7 @@ wall_thickness = 1.05 top_bottom_thickness = 0.8 infill_sparse_density = 20 speed_print = 45 +speed_wall = 30 cool_min_layer_time = 3 cool_fan_speed_min = 80 cool_min_speed = 10 From 860846880212c89f2b0aca718b23b15acba4a3e8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 16:32:39 +0200 Subject: [PATCH 234/304] Add a method to get the id of the current user profile CURA-1668 --- cura/MachineManagerModel.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 2738bfd764..e719c05743 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -105,7 +105,7 @@ class MachineManagerModel(QObject): @pyqtSlot(str, str) def addMachine(self, name, definition_id): - definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=definition_id) + definitions = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id = definition_id) if definitions: definition = definitions[0] name = self._createUniqueName("machine", "", name, definition.getName()) @@ -205,6 +205,13 @@ class MachineManagerModel(QObject): def isGlobalStackValid(self): return self._global_stack_valid + @pyqtProperty(str, notify = globalContainerChanged) + def activeUserProfileId(self): + if self._global_container_stack: + return self._global_container_stack.getTop().getId() + + return "" + @pyqtProperty(str, notify = globalContainerChanged) def activeMachineName(self): if self._global_container_stack: From 1131623278227f9e7ab4db9b5fd42ff54a27f961 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 8 Jun 2016 16:33:58 +0200 Subject: [PATCH 235/304] Disable the property editor when the value of the setting is not used Contributes to CURA-1278 --- resources/qml/Settings/SettingItem.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 9ed75bdecf..8160489b01 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -205,6 +205,8 @@ Item { { id: controlContainer; + enabled: provider.isValueUsed + anchors.right: parent.right; anchors.rightMargin: UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter; From 485ae53660d5c234084403ab7d13125470ca7bcf Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 16:35:10 +0200 Subject: [PATCH 236/304] Show quality profile and user profile settings side-by-side on Profiles manager Introduces ContainerSettingsModel, which can combine the settings of instances from multiple containers into one model. Towards CURA-1668 --- cura/ContainerSettingsModel.py | 104 +++++++++++++++++++++ cura/CuraApplication.py | 3 + resources/qml/Preferences/ProfilesPage.qml | 11 ++- 3 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 cura/ContainerSettingsModel.py diff --git a/cura/ContainerSettingsModel.py b/cura/ContainerSettingsModel.py new file mode 100644 index 0000000000..23d20cd6e2 --- /dev/null +++ b/cura/ContainerSettingsModel.py @@ -0,0 +1,104 @@ +from UM.Application import Application +from UM.Qt.ListModel import ListModel + +from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot, QUrl + +from UM.Settings.ContainerRegistry import ContainerRegistry +from UM.Settings.InstanceContainer import InstanceContainer + +class ContainerSettingsModel(ListModel): + LabelRole = Qt.UserRole + 1 + CategoryRole = Qt.UserRole + 2 + UnitRole = Qt.UserRole + 3 + ValuesRole = Qt.UserRole + 4 + + def __init__(self, parent = None): + super().__init__(parent) + self.addRoleName(self.LabelRole, "label") + self.addRoleName(self.CategoryRole, "category") + self.addRoleName(self.UnitRole, "unit") + self.addRoleName(self.ValuesRole, "values") + + self._container_ids = [] + self._container = None + + 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): + if property_name == "value": + self._update() + + def _onInstanceContainersChanged(self, container): + self._update() + + def _update(self): + self.clear() + + if len(self._container_ids) == 0: + return + + keys = [] + containers = [] + for container_id in self._container_ids: + container = ContainerRegistry.getInstance().findContainers(id = container_id) + if not container: + return + + keys = keys + list(container[0].getAllKeys()) + containers.append(container[0]) + + keys = list(set(keys)) + keys.sort() + + for key in keys: + definition = None + category = None + values = [] + for container in containers: + + instance = container.getInstance(key) + if instance: + definition = instance.definition + + # Traverse up to find the category + category = definition + while category.type != "category": + category = category.parent + + values.append(container.getProperty(key, "value")) + else: + values.append("") + + self.appendItem({ + "key": key, + "values": values, + "label": definition.label, + "unit": definition.unit, + "category": category.label + }) + + ## Set the id of the container which has the settings this model should list. + def setContainers(self, container_ids): + self._container_ids = container_ids + self._update() + + containersChanged = pyqtSignal() + @pyqtProperty("QVariantList", fset = setContainers, notify = containersChanged) + def containers(self): + return self.container_ids \ No newline at end of file diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 8acd3eda2a..9abfabc7b2 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -42,6 +42,7 @@ from . import MultiMaterialDecorator from . import ZOffsetDecorator from . import CuraSplashScreen from . import MachineManagerModel +from . import ContainerSettingsModel from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtGui import QColor, QIcon @@ -400,6 +401,8 @@ class CuraApplication(QtApplication): qmlRegisterType(ExtrudersModel.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") + qmlRegisterType(ContainerSettingsModel.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel") + qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions") engine.rootContext().setContextProperty("ExtruderManager", ExtruderManager.ExtruderManager.getInstance()) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index ed9c20f65f..ee7653f96e 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -128,16 +128,21 @@ UM.ManagementPage anchors.bottom: parent.bottom ListView { - model: base.currentItem ? base.currentItem.settings: null + model: Cura.ContainerSettingsModel{ containers: [base.currentItem.id, Cura.MachineManager.activeUserProfileId] } delegate: Row { + property variant setting: model spacing: UM.Theme.getSize("default_margin").width Label { text: model.label elide: Text.ElideMiddle width: scrollView.width / 100 * 40 } - Label { - text: model.value.toString() + Repeater { + model: setting.values.length + Label { + text: setting.values[index].toString() + width: scrollView.width / 100 * 10 + } } Label { text: model.unit From 7dbafa06d1ae2b53e77726dee45662d721470ccb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 16:00:52 +0200 Subject: [PATCH 237/304] Make SidebarHeader use ExtrudersModel This model is also used by the extruder selection drop-downs, and it's automatically filled already so that was double logic. Contributes to issues CURA-340 and CURA-1278. --- resources/qml/SidebarHeader.qml | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 237746ac0d..75f5393d57 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -104,7 +104,7 @@ Item anchors.leftMargin: model.index * (extruderSelection.width / machineExtruderCount.properties.value) anchors.verticalCenter: parent.verticalCenter width: parent.width / machineExtruderCount.properties.value - text: model.text + text: model.name exclusiveGroup: extruderMenuGroup; checkable: true; checked: base.currentExtruderIndex == index @@ -138,10 +138,11 @@ Item } } ExclusiveGroup { id: extruderMenuGroup; } - ListView{ + ListView + { id: extrudersList property var index: 0 - model: extrudersListModel + model: Cura.ExtrudersModel {} delegate: wizardDelegate anchors.top: parent.top anchors.left: parent.left @@ -149,28 +150,6 @@ Item } } - ListModel - { - id: extrudersListModel - Component.onCompleted: populateExtruderModel() - } - Connections - { - id: machineChange - target: Cura.MachineManager - onGlobalContainerChanged: populateExtruderModel() - } - - function populateExtruderModel() - { - extrudersListModel.clear(); - for(var extruder = 0; extruder < machineExtruderCount.properties.value ; extruder++) { - extrudersListModel.append({ - text: catalog.i18nc("@label", "Extruder %1").arg(extruder + 1) - }) - } - } - Rectangle { id: variantRow anchors.top: extruderSelection.visible ? extruderSelection.bottom : machineSelectionRow.bottom From 4d418a7c1a94ddfe11a3f3e6b252821b9e077d73 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 16:26:57 +0200 Subject: [PATCH 238/304] When switching active extruder, get the extruder train from definition id Not from extruder container stack ID. Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index b4d05d7e6c..c8a07a4000 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().getId()][str(self._active_extruder_index)] + return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getBottom().getId()][str(self._active_extruder_index)] 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 From da467b9b2806af69fb55f51f2b8a73b095c69cd6 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 16:45:20 +0200 Subject: [PATCH 239/304] Only shown the current settings column when the currently active quality profile is selected CURA-1668 --- resources/qml/Preferences/ProfilesPage.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index ee7653f96e..3307c1e2a5 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -93,7 +93,7 @@ UM.ManagementPage Row { id: currentSettingsActions - visible: base.currentItem.id == -1 || currentItem.id == Cura.MachineManager.activeQualityId + visible: currentItem.id == Cura.MachineManager.activeQualityId anchors.left: parent.left anchors.top: profileName.bottom @@ -128,7 +128,7 @@ UM.ManagementPage anchors.bottom: parent.bottom ListView { - model: Cura.ContainerSettingsModel{ containers: [base.currentItem.id, Cura.MachineManager.activeUserProfileId] } + 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 From 07b51d0ca8813f95a76e252651113bf398c68010 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 17:04:04 +0200 Subject: [PATCH 240/304] Strike out profile value if it is overridden by the current setting CURA-1668 --- resources/qml/Preferences/ProfilesPage.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 3307c1e2a5..14569464d6 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -142,6 +142,8 @@ UM.ManagementPage Label { text: setting.values[index].toString() width: scrollView.width / 100 * 10 + font.strikeout: index < setting.values.length - 1 && setting.values[index + 1] != "" + opacity: font.strikeout ? 0.5 : 1 } } Label { From fcd6f0959f0b15281074af4ab717eb8536e0660c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Wed, 8 Jun 2016 17:47:23 +0200 Subject: [PATCH 241/304] Inheritance button now only shows if there is a function in the container stack at some point CURA-1278 --- resources/qml/Settings/SettingItem.qml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 9ed75bdecf..1b80cb68f5 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -158,9 +158,24 @@ Item { { // This button shows when the setting has an inherited function, but is overriden by profile. id: inheritButton; - - //visible: has_profile_value && base.has_inherit_function && base.is_enabled - visible: base.state == "InstanceState.User" && base.showInheritButton + // Inherit button needs to be visible if; + // - User made changes that override any loaded settings + // - This setting item uses inherit button at all + // - The type of the value of any deeper container is an "object" (eg; is a function) + visible: + { + var state = base.state == "InstanceState.User"; + var has_setting_function = false; + for (var i = 1; i < base.stackLevels.length; i++) + { + has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object"; + if(has_setting_function) + { + break; + } + } + return state && base.showInheritButton && has_setting_function + } height: parent.height; width: height; From ca308c5b05f37d0205b5392e31de927eae0a5b31 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 17:50:54 +0200 Subject: [PATCH 242/304] Add notice if a profile has no settings, and if the current settings are "empty" CURA-1668, CURA-696 --- resources/qml/Preferences/ProfilesPage.qml | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 14569464d6..97dd2c5d77 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -118,11 +118,35 @@ UM.ManagementPage } } + Column { + id: profileNotices + anchors.top: currentSettingsActions.visible ? currentSettingsActions.bottom : currentSettingsActions.anchors.top + anchors.topMargin: UM.Theme.getSize("default_margin").height + anchors.left: parent.left + anchors.right: parent.right + spacing: UM.Theme.getSize("default_margin").height + + Label { + id: defaultsMessage + visible: !currentItem.hasSettings + text: catalog.i18nc("@action:label", "This profile has no settings and uses the defaults specified by the printer.") + wrapMode: Text.WordWrap + width: parent.width + } + Label { + id: noCurrentSettingsMessage + visible: currentItem.id == Cura.MachineManager.activeQualityId && !Cura.MachineManager.hasUserSettings + text: catalog.i18nc("@action:label", "Your current settings match the selected profile.") + wrapMode: Text.WordWrap + width: parent.width + } + } + ScrollView { id: scrollView anchors.left: parent.left - anchors.top: currentSettingsActions.visible ? currentSettingsActions.bottom : profileName.bottom + anchors.top: profileNotices.visible ? profileNotices.bottom : profileNotices.anchors.top anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.right: parent.right anchors.bottom: parent.bottom From e702fef44b185f51da79112aeedeffcb85cbf0cb Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Jun 2016 22:07:57 +0200 Subject: [PATCH 243/304] Add header to profile settings table --- resources/qml/Preferences/ProfilesPage.qml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 97dd2c5d77..3ca8d77461 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -155,7 +155,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 +165,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 +175,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 value") + width: scrollView.width / 100 * 55 + horizontalAlignment: Text.AlignRight + font.bold: true + } + Label { + text: catalog.i18nc("@action:label", "Current setting") + visible: currentItem.id == Cura.MachineManager.activeQualityId + font.bold: true + } + } section.property: "category" section.criteria: ViewSection.FullString section.delegate: Label { From b85a8ca404a59e09def6b0e901b7b6374a221308 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 07:54:13 +0200 Subject: [PATCH 244/304] Update ContainerSettingsModel when its containers have property changes CURA-1668 --- cura/ContainerSettingsModel.py | 52 ++++++++++++---------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/cura/ContainerSettingsModel.py b/cura/ContainerSettingsModel.py index 23d20cd6e2..1dea88cac3 100644 --- a/cura/ContainerSettingsModel.py +++ b/cura/ContainerSettingsModel.py @@ -22,31 +22,10 @@ class ContainerSettingsModel(ListModel): self._container_ids = [] self._container = None - 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 +33,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 @@ -93,9 +65,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() From a6dd9e74158e3fad24a2ef0d0740318b8fb0cbf4 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 08:14:06 +0200 Subject: [PATCH 245/304] Fix initialization of ContainerSettingsModel CURA-1668 --- cura/ContainerSettingsModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ContainerSettingsModel.py b/cura/ContainerSettingsModel.py index 1dea88cac3..83a1f3ccd4 100644 --- a/cura/ContainerSettingsModel.py +++ b/cura/ContainerSettingsModel.py @@ -20,7 +20,7 @@ class ContainerSettingsModel(ListModel): self.addRoleName(self.ValuesRole, "values") self._container_ids = [] - self._container = None + self._containers = [] def _onPropertyChanged(self, key, property_name): if property_name == "value": From ecfd7e599356a6f84ef8a3983fa25f9680f5c91c Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 08:21:18 +0200 Subject: [PATCH 246/304] Move InstanceContainersModel has_settings into metadata to clean up the model CURA-1668 --- resources/qml/Preferences/ProfilesPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 3ca8d77461..faf72bfc7a 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -128,7 +128,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 From a21498c37536fead27f63e91a9adfd94d504e9c1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 08:29:05 +0200 Subject: [PATCH 247/304] Add weights to generic quality profiles CURA-1278 --- resources/quality/high.inst.cfg | 1 + resources/quality/low.inst.cfg | 1 + resources/quality/normal.inst.cfg | 1 + 3 files changed, 3 insertions(+) diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 86df9dab92..b2413bba23 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +weight = -3 read_only = True [values] diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index 6cebc46dd5..43ac4ac02d 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +weight = -1 read_only = True [values] diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg index b12603f921..df9448097b 100644 --- a/resources/quality/normal.inst.cfg +++ b/resources/quality/normal.inst.cfg @@ -5,6 +5,7 @@ definition = fdmprinter [metadata] type = quality +weight = -2 read_only = True [values] From a070684ade3e89f6dbb18e2ba5d7692d07eafb4c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 09:59:06 +0200 Subject: [PATCH 248/304] Fixed minor issue for inheritance button It didn't always reset to correct value. CURA-1278 --- resources/qml/Settings/SettingItem.qml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 0cb1c169df..6095ab10d1 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -185,12 +185,22 @@ Item { // 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] + 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; + } + } // 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) + 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. From e4e307cd2a08f8024ebc4237857b41317be08578 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 10:25:01 +0200 Subject: [PATCH 249/304] Inheritance button now works if instance containers contain functions CURA-1686 --- resources/qml/Settings/SettingItem.qml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 6095ab10d1..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,11 +182,9 @@ 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[propertyProvider.stackLevels.length] + // 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"; @@ -196,18 +194,25 @@ Item { break; } } - // 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 && 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") } From 20f657af888692f4f8620c974d3781429d2f4c6c Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 10:40:28 +0200 Subject: [PATCH 250/304] Updated proto file Objects & global settings are now sent in one message. Also added support for extruder settings CURA-1681 --- plugins/CuraEngineBackend/Cura.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index 0d4975aca4..c51829aeff 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -11,6 +11,8 @@ message ObjectList message Slice { repeated ObjectList object_lists = 1; + SettingList global_settings = 2; + repeated SettingsList extruder_settings = 3; } message Object From 14b9294a3944196eef01401741807e279570969a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 8 Jun 2016 17:02:00 +0200 Subject: [PATCH 251/304] Document setActiveExtruderIndex Contributes to issues CURA-340 and CURA-1278. --- cura/ExtruderManager.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c8a07a4000..bd0c3956d3 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -58,6 +58,9 @@ 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 From 1149a96d70c2ff44167d6c607e95ee4636605ea4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 10:45:20 +0200 Subject: [PATCH 252/304] Fix spelling --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8be258c79e..2bb1f6acff 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1043,7 +1043,7 @@ "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", From ce9d8b6dd0ea1b6147913dd317a1b8ca6cb8ae97 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Thu, 9 Jun 2016 10:48:44 +0200 Subject: [PATCH 253/304] proto file typo fix (CURA-1681 CURA-1682) --- plugins/CuraEngineBackend/Cura.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index c51829aeff..c2b6a142b4 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -12,7 +12,7 @@ message Slice { repeated ObjectList object_lists = 1; SettingList global_settings = 2; - repeated SettingsList extruder_settings = 3; + repeated SettingList extruder_settings = 3; } message Object From 5da366583273b4a9fe1061d1ed1c3f104276f630 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 11:22:33 +0200 Subject: [PATCH 254/304] Fix duplicating the first item on the Profiles page CURA-1585 --- resources/qml/Preferences/ProfilesPage.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index faf72bfc7a..ac57dbba35 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -49,8 +49,7 @@ UM.ManagementPage onActivateObject: Cura.MachineManager.setActiveQuality(currentItem.id) onAddObject: { var selectedContainer; - if (objectList.currentIndex == 0) { - // Current settings + if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) { selectedContainer = Cura.MachineManager.convertUserContainerToQuality(); } else { selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); From 123c2f5c85148bb74b5e510f5d7cc06d2ba31cc9 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 11:33:15 +0200 Subject: [PATCH 255/304] Moved global settings into slice message (as per API changes) CURA-1681 --- plugins/CuraEngineBackend/CuraEngineBackend.py | 4 +--- plugins/CuraEngineBackend/StartSliceJob.py | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 9607ba407b..3e22f8f6fb 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -145,8 +145,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 +204,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. diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index dee6f2b64c..75bbd4073f 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -37,17 +37,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 @@ -185,7 +181,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) From 899e4cc175ff8b78ccea35be29e163805c53ea20 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 11:46:52 +0200 Subject: [PATCH 256/304] Fixed sending of per-object settings to engine CURA-1681 --- plugins/CuraEngineBackend/StartSliceJob.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 75bbd4073f..9a3dc3a263 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -189,21 +189,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 From 4bdd5713f19e2d8a7c2c656dec5d2ee24fe6b105 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 11:35:23 +0200 Subject: [PATCH 257/304] Fix extruder number attached to extruders It reads that from position in the extruder definition file. Contributes to issues CURA-1278 and CURA-340. --- cura/ExtrudersModel.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 60bd60abab..37487f838c 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -51,13 +51,18 @@ 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())): + for extruder in manager.getMachineExtruders(global_container_stack.getBottom()): material = extruder.findContainer({ "type": "material" }) colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" + 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. "name": extruder.getName(), "colour": colour, - "index": index + "index": position } self.appendItem(item) self.sort(lambda item: item["index"]) \ No newline at end of file From 6a520cad47c547b896db6dc02c4125e760faff6d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 11:48:21 +0200 Subject: [PATCH 258/304] Change focus upon extruder switch This applies a setting that is currently being typed by the user. Otherwise it would take the currently being typed value along to the next tab, since it can't update a setting value while it is in focus. Contributes to issues CURA-340 and CURA-1278. --- resources/qml/SidebarHeader.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 75f5393d57..60f5af2e73 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -110,8 +110,9 @@ Item checked: base.currentExtruderIndex == index onClicked: { - base.currentExtruderIndex = index - ExtruderManager.setActiveExtruderIndex(index) + extruderSelection.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 { From a01b554ee3320a148753417df8ebcaa933a097ce Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 11:56:41 +0200 Subject: [PATCH 259/304] Added extruder to proto message CURA-1681 --- plugins/CuraEngineBackend/Cura.proto | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index c2b6a142b4..aa42ed989a 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -12,7 +12,13 @@ message Slice { repeated ObjectList object_lists = 1; SettingList global_settings = 2; - repeated SettingList extruder_settings = 3; + repeated Extruder extruders = 3; +} + +message Extruder +{ + int32 id = 1; + SettingList settings = 2; } message Object From b6649eab3aef1dbd72058618dfd441d56c65f8a4 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Thu, 9 Jun 2016 12:08:10 +0200 Subject: [PATCH 260/304] dox: documented proto file (CURA-1681 CURA-1682) --- plugins/CuraEngineBackend/Cura.proto | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index aa42ed989a..38753fd804 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -5,14 +5,14 @@ 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; - SettingList global_settings = 2; - repeated Extruder extruders = 3; + 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 @@ -37,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 { @@ -56,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 { @@ -76,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 { From d93044a338cc2e9603c6a027c2c29d9813935a52 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 13:04:07 +0200 Subject: [PATCH 261/304] Added setting sending per extruder CURA-1681 --- cura/ExtruderManager.py | 13 ++++++------- cura/ExtrudersModel.py | 2 +- plugins/CuraEngineBackend/StartSliceJob.py | 13 +++++++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c8a07a4000..102f7d7fc0 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -187,19 +187,18 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) - ## Generates extruders for a specific machine. - def getMachineExtruders(self, machine_definition): + ## Gets extruders for a specific machine. + def getMachineExtruders(self, machine_definition_id): container_registry = UM.Settings.ContainerRegistry.getInstance() - machine_id = machine_definition.getId() - if not machine_id in self._extruder_trains: - UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id) + if not machine_definition_id in self._extruder_trains: + UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_definition_id) return - for _,extruder_train_id in self._extruder_trains[machine_id].items(): + for _,extruder_train_id in self._extruder_trains[machine_definition_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) + UM.Logger.log("w", "Machine %s refers to an extruder train with ID %s, which doesn't exist.", machine_definition_id, extruder_train_id) ## Adds the extruders of the currently active machine. def _addCurrentMachineExtruders(self): diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 60bd60abab..1efc86d9c5 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -51,7 +51,7 @@ 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())): + for index, extruder in enumerate(manager.getMachineExtruders(global_container_stack.getBottom().getId())): 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. diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 9a3dc3a263..259750d098 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 @@ -127,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"): @@ -166,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.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 From cd803bc36ecbf85ea1846c780dd054fb56362b11 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 13:16:23 +0200 Subject: [PATCH 262/304] Determine readonly state from location in filesystem instead of a metadata property CURA-1684 --- cura/MachineManagerModel.py | 6 +++--- resources/qml/Cura.qml | 4 ++-- resources/qml/Preferences/ProfilesPage.qml | 4 ++-- resources/qml/ProfileSetup.qml | 4 ++-- resources/quality/high.inst.cfg | 1 - resources/quality/low.inst.cfg | 1 - resources/quality/normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_abs_0.25_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_abs_0.4_fast.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_abs_0.4_high.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_abs_0.4_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_abs_0.6_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_abs_0.8_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_cpe_0.25_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_cpe_0.4_fast.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_cpe_0.4_high.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_cpe_0.4_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_cpe_0.6_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_cpe_0.8_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_pla_0.25_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_pla_0.4_fast.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_pla_0.4_high.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_pla_0.4_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_pla_0.6_normal.inst.cfg | 1 - .../ultimaker2_extended_plus/um2ep_pla_0.8_normal.inst.cfg | 1 - resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg | 1 - resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg | 1 - resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg | 1 - resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg | 1 - resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg | 1 - resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg | 1 - .../quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg | 1 - 43 files changed, 9 insertions(+), 48 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e719c05743..816dbc4600 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -266,7 +266,7 @@ 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): @@ -288,7 +288,7 @@ class MachineManagerModel(QObject): ## Change type / id / name new_quality_container.setMetaDataEntry("type", "quality") - new_quality_container.setMetaDataEntry("read_only", False) + new_quality_container.setReadOnly(False) new_quality_container.setName(name) new_quality_container._id = name @@ -310,7 +310,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) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 46ebc25369..74f5e8bdd8 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: { diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index ac57dbba35..a5992a3f8c 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -65,8 +65,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) diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml index 48d52c539a..a168d87ff1 100644 --- a/resources/qml/ProfileSetup.qml +++ b/resources/qml/ProfileSetup.qml @@ -88,13 +88,13 @@ Item{ { //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) { 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); + profileSelectionMenu.insertItem((model.getItem(index).readOnly) ? index : index + 1, object.item); } onObjectRemoved: { diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index b2413bba23..b4498c6c8b 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -6,7 +6,6 @@ definition = fdmprinter [metadata] type = quality weight = -3 -read_only = True [values] layer_height = 0.06 diff --git a/resources/quality/low.inst.cfg b/resources/quality/low.inst.cfg index 43ac4ac02d..d34a7c6461 100644 --- a/resources/quality/low.inst.cfg +++ b/resources/quality/low.inst.cfg @@ -6,7 +6,6 @@ definition = fdmprinter [metadata] type = quality weight = -1 -read_only = True [values] infill_sparse_density = 10 diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg index df9448097b..417c7c700f 100644 --- a/resources/quality/normal.inst.cfg +++ b/resources/quality/normal.inst.cfg @@ -6,6 +6,5 @@ definition = fdmprinter [metadata] type = quality weight = -2 -read_only = True [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 From 3df1bc4e62c302721d89974838104c948cea6a0e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 13:23:09 +0200 Subject: [PATCH 263/304] Fixed minor issue in buildExtruderMessage CURA-1681 --- plugins/CuraEngineBackend/StartSliceJob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 259750d098..3d2eb0ed4a 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -174,7 +174,7 @@ class StartSliceJob(Job): message = self._slice_message.addRepeatedMessage("extruders") message.id = int(stack.getMetaDataEntry("position")) for key in stack.getAllKeys(): - setting = message.addRepeatedMessage("settings") + setting = message.getMessage("settings").addRepeatedMessage("settings") setting.name = key setting.value = str(stack.getProperty(key, "value")).encode("utf-8") Job.yieldThread() From 8729dce531e4b2f8ba655ff03491e2339e4fc9ab Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 13:30:17 +0200 Subject: [PATCH 264/304] Store the actual extruder stack in ExtruderManager instead of just the ID Contributes to CURA-340 --- cura/ExtruderManager.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index c8a07a4000..5c695de1f1 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 @@ -87,7 +87,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) @@ -194,15 +194,11 @@ class ExtruderManager(QObject): if not machine_id 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()) From 8f4f67d552f2b6993137e9429c4ea53f2949bc78 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 13:41:33 +0200 Subject: [PATCH 265/304] Show "Protected profiles" / "Custom profiles" section on profiles page CURA-855 --- resources/qml/Preferences/ProfilesPage.qml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index a5992a3f8c..2030ced505 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -36,6 +36,22 @@ UM.ManagementPage } } + section.property: "readOnly" + section.delegate: Rectangle + { + width: objectListContainer.viewport.width; + height: childrenRect.height; + color: palette.light + + 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++) { From d57e2b2e225fbe851cc0e26d166078df6ae417c3 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 13:46:39 +0200 Subject: [PATCH 266/304] Add an ID role and addGlobal property to ExtrudersModel Contributes to CURA-340 --- cura/ExtrudersModel.py | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 37487f838c..3265667dc6 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,21 @@ 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 ## Initialises the extruders model, defining the roles and listening for # changes in the data. @@ -32,16 +35,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,6 +68,18 @@ 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. + + if self._add_global: + material = global_container_stack.findContainer({ "type": "material" }) + colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" + item = { + "id": global_container_stack.getId(), + "name": "Global", + "colour": colour, + "index": -1 + } + self.appendItem(item) + for extruder in manager.getMachineExtruders(global_container_stack.getBottom()): material = extruder.findContainer({ "type": "material" }) colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" @@ -60,9 +89,11 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): 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"]) \ No newline at end of file + + self.sort(lambda item: item["index"]) From c03588c6e576f3e164f5b28baf848b8072e2e78c Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Wed, 8 Jun 2016 14:40:10 +0200 Subject: [PATCH 267/304] Profile export now goes via the plugin system, and does the same filename checks as before. Contributed to CURA-1667 Profile import/export --- cura/CuraApplication.py | 4 ++++ plugins/CuraProfileReader/CuraProfileReader.py | 1 - plugins/CuraProfileReader/__init__.py | 2 +- plugins/CuraProfileWriter/CuraProfileWriter.py | 4 ++-- plugins/CuraProfileWriter/__init__.py | 2 +- resources/qml/Preferences/ProfilesPage.qml | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a2415478a4..12828971cd 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -294,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")) @@ -788,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/plugins/CuraProfileReader/CuraProfileReader.py b/plugins/CuraProfileReader/CuraProfileReader.py index 1d27649498..c9b4e60046 100644 --- a/plugins/CuraProfileReader/CuraProfileReader.py +++ b/plugins/CuraProfileReader/CuraProfileReader.py @@ -3,7 +3,6 @@ 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 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..c6c4244948 100644 --- a/plugins/CuraProfileWriter/CuraProfileWriter.py +++ b/plugins/CuraProfileWriter/CuraProfileWriter.py @@ -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/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 2030ced505..b382065a7e 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -299,7 +299,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 From 97d64a0749633606e57ed2d566bbadcc96d4dc00 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Wed, 8 Jun 2016 15:36:26 +0200 Subject: [PATCH 268/304] Move ProfileReader and ProfileWriter over to Cura itself. Contributes to CURA-1667 Profile import/export --- cura/ProfileWriter.py | 25 +++++++++++++++++++ .../CuraProfileReader/CuraProfileReader.py | 7 +++--- .../CuraProfileWriter/CuraProfileWriter.py | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 cura/ProfileWriter.py 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/plugins/CuraProfileReader/CuraProfileReader.py b/plugins/CuraProfileReader/CuraProfileReader.py index c9b4e60046..9ff2955b22 100644 --- a/plugins/CuraProfileReader/CuraProfileReader.py +++ b/plugins/CuraProfileReader/CuraProfileReader.py @@ -3,7 +3,7 @@ from UM.Application import Application #To get the machine manager to create the new profile in. from UM.Logger import Logger -from UM.Settings.ProfileReader import ProfileReader +from cura.ProfileReader import ProfileReader ## A plugin that reads profile data from Cura profile files. @@ -25,16 +25,15 @@ class CuraProfileReader(ProfileReader): def read(self, file_name): # Create an empty profile. profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) - serialised = "" 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/CuraProfileWriter/CuraProfileWriter.py b/plugins/CuraProfileWriter/CuraProfileWriter.py index c6c4244948..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. From b93137545f8db44383985ddf02c7b2a8500afd04 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 9 Jun 2016 14:14:09 +0200 Subject: [PATCH 269/304] Support for importing a profile. Contributes to CURA-1667 Profile import/export --- plugins/CuraProfileReader/CuraProfileReader.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/CuraProfileReader/CuraProfileReader.py b/plugins/CuraProfileReader/CuraProfileReader.py index 9ff2955b22..b9c1f208ea 100644 --- a/plugins/CuraProfileReader/CuraProfileReader.py +++ b/plugins/CuraProfileReader/CuraProfileReader.py @@ -1,11 +1,13 @@ # 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.InstanceContainer import InstanceContainer #The new profile to make. from cura.ProfileReader import ProfileReader - ## A plugin that reads profile data from Cura profile files. # # It reads a profile from a .curaprofile file, and returns it as a profile @@ -24,7 +26,8 @@ class CuraProfileReader(ProfileReader): # returned. def read(self, file_name): # Create an empty profile. - profile = Profile(machine_manager = Application.getInstance().getMachineManager(), read_only = False) + 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. serialized = f.read() From 725086b0dd10085ab9f25e5b1aa6814cb28ad6be Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 14:31:32 +0200 Subject: [PATCH 270/304] Remove ProfileSetup and move its contents to SidebaarHeader Contributes to CURA-340 --- resources/qml/ProfileSetup.qml | 166 -------------------------------- resources/qml/Sidebar.qml | 16 +-- resources/qml/SidebarHeader.qml | 153 +++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 180 deletions(-) delete mode 100644 resources/qml/ProfileSetup.qml diff --git a/resources/qml/ProfileSetup.qml b/resources/qml/ProfileSetup.qml deleted file mode 100644 index a168d87ff1..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).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 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/Sidebar.qml b/resources/qml/Sidebar.qml index 4109fd1586..29814ca42e 100644 --- a/resources/qml/Sidebar.qml +++ b/resources/qml/Sidebar.qml @@ -52,20 +52,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 +64,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 60f5af2e73..83daf00be0 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -296,6 +296,159 @@ 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).metadata.read_only) + { + 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 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: model_data != null ? Cura.MachineManager.activeQualityId == model_data.id : false + exclusiveGroup: profileSelectionMenuGroup; + onTriggered: Cura.MachineManager.setActiveQuality(model_data.id) + } + } + + MenuSeparator { } + MenuItem + { + action: Cura.Actions.updateProfile; + } + MenuItem + { + action: Cura.Actions.resetProfile; + } + MenuItem + { + action: Cura.Actions.addProfile; + } + 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 + + 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() + } + } + } + UM.SettingPropertyProvider { id: machineExtruderCount From 88d87e8e8558dcd840cd3d2e5f8768e8ed83c9c9 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 14:31:56 +0200 Subject: [PATCH 271/304] Cleanup sidebarheader and fix extruder selection Contributes to CURA-340 --- resources/qml/SidebarHeader.qml | 225 ++++++++++++++++---------------- 1 file changed, 113 insertions(+), 112 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 83daf00be0..f1c0bf7d8b 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,103 +81,116 @@ 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: - { - extruderSelection.focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values. - 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: + { + extruderSelection.focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values. + base.currentExtruderIndex = index; + ExtruderManager.setActiveExtruderIndex(index); + } + + Component.onCompleted: console.log(model.name); + + 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 { @@ -214,13 +227,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) @@ -277,13 +283,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) @@ -458,4 +457,6 @@ Item watchedProperties: [ "value" ] storeIndex: 0 } + + UM.I18nCatalog { id: catalog; name:"cura" } } From 4a43b50b7a99b4dce6d72826eca23e772ee7255b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 14:59:32 +0200 Subject: [PATCH 272/304] Remove unused action properties from Sidebar --- resources/qml/Cura.qml | 7 ------- resources/qml/Sidebar.qml | 7 ------- 2 files changed, 14 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 74f5e8bdd8..a1023d8ef2 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -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; } } } diff --git a/resources/qml/Sidebar.qml b/resources/qml/Sidebar.qml index 29814ca42e..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"); From 3a75e1fb795740398d668ba0c3bacbce2b0e456b Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 15:12:37 +0200 Subject: [PATCH 273/304] Fix setting the active extruder Contributes to CURA-340 --- resources/qml/SidebarHeader.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index f1c0bf7d8b..7d7161256a 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -123,7 +123,7 @@ Column onClicked: { - extruderSelection.focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values. + focus = true; //Changing focus applies the currently-being-typed values so it can change the displayed setting values. base.currentExtruderIndex = index; ExtruderManager.setActiveExtruderIndex(index); } From abf634c0b0ed7cac37be69ba4d44e08e3977f190 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 15:14:32 +0200 Subject: [PATCH 274/304] Filter visible settings based on if they can be set per extruder Contributes to CURA-340 --- resources/qml/Settings/SettingView.qml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index a6bb60f865..d1ddb12e34 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 From 98c9f202a293d7409b36865ca61d2ad096000e4c Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 15:32:41 +0200 Subject: [PATCH 275/304] Do not produce an error when a setting has been filtered out Contributes to CURA-340 --- 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 d1ddb12e34..4be2326b0a 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -91,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 } From 90ddff1c7ffe8e5c0b4624275d75b5ec9a49f8c7 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 9 Jun 2016 15:35:37 +0200 Subject: [PATCH 276/304] Remove obsolete debug statement Contributes to 1685 --- resources/qml/SidebarHeader.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 7d7161256a..db9b580907 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -128,8 +128,6 @@ Column ExtruderManager.setActiveExtruderIndex(index); } - Component.onCompleted: console.log(model.name); - style: ButtonStyle { background: Rectangle From 12a7b99cf7c7aa6a21c40e8279c3334886ab55ca Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Thu, 9 Jun 2016 15:43:18 +0200 Subject: [PATCH 277/304] fix: merge b3cfa62 went wrong, no slicing happened (CURA-1558) --- cura/CuraApplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 12828971cd..15c41f9c56 100644 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -97,7 +97,7 @@ class CuraApplication(QtApplication): 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", str, ast.literal_eval, UM.Settings.Validator) + SettingDefinition.addSettingType("extruder", int, str, UM.Settings.Validator) super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType) From bd76c3e30f68560fc8d1bc821e6f488a9978f61d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 15:46:22 +0200 Subject: [PATCH 278/304] Add drop-down in per-object settings to select extruder Actually selecting an extruder has no effect because there are dragons in that area and I need better armour with bonus damage against bugs before I venture in there. Contributes to issues CURA-340 and CURA-1278. --- cura/SettingOverrideDecorator.py | 38 ++++++-- .../PerObjectSettingsPanel.qml | 94 ++++++++++++++++++- .../PerObjectSettingsTool.py | 19 +++- 3 files changed, 142 insertions(+), 9 deletions(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index f9878e436c..06dbc2cb31 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -1,5 +1,9 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. + +from PyQt5.QtCore import pyqtSignal +import copy + from UM.Scene.SceneNodeDecorator import SceneNodeDecorator from UM.Settings.ContainerStack import ContainerStack @@ -7,24 +11,29 @@ from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerRegistry import ContainerRegistry 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. class SettingOverrideDecorator(SceneNodeDecorator): + ## Event indicating that the user selected a different extruder. + activeExtruderChanged = pyqtSignal() + 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 +44,30 @@ 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: + self._stack.setNextStack(ContainerRegistry.getInstance().findContainerStack(id = 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/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index d07db2e212..4610083674 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,98 @@ Item { spacing: UM.Theme.getSize("default_margin").height; + Row + { + ComboBox + { + id: extruderSelector + + model: Cura.ExtrudersModel + { + id: extruders_model + } + 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.properties.setValue("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 diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index 6ae44c2671..255277c3af 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -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. from UM.Tool import Tool @@ -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,21 @@ 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) + selected_object.callDecoration("setActiveExtruder", extruder_stack_id) + def _onPreferenceChanged(self, preference): if preference == "cura/active_mode": enabled = Preferences.getInstance().getValue(preference)==1 From 38c6c3cb0160b45c94d15e9b221dc338b2b0a3b5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 15:51:28 +0200 Subject: [PATCH 279/304] Minor fixes to SidebarHeader CURA-1689 --- resources/qml/SidebarHeader.qml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index f1c0bf7d8b..17fb473b74 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -128,8 +128,6 @@ Column ExtruderManager.setActiveExtruderIndex(index); } - Component.onCompleted: console.log(model.name); - style: ButtonStyle { background: Rectangle @@ -365,7 +363,7 @@ Column //Insert a separator between readonly and custom profiles if(separatorIndex < 0 && index > 0) { - if(model.getItem(index-1).readOnly != model.getItem(index).metadata.read_only) + if(model.getItem(index-1).readOnly != model.getItem(index).readOnly) { profileSelectionMenu.insertSeparator(index); separatorIndex = index; @@ -376,7 +374,7 @@ Column } onObjectRemoved: { - //When adding a profile, the menu is rebuild by removing all items. + //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) { From 0952dd0327b4fd90545208b628c4c3b5b5c1cdb4 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 16:01:08 +0200 Subject: [PATCH 280/304] Removed warnings about undefined properties CURA-1278 --- resources/qml/Preferences/ProfilesPage.qml | 1 - resources/qml/Settings/SettingCategory.qml | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index b382065a7e..cd37df3cc5 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -41,7 +41,6 @@ UM.ManagementPage { width: objectListContainer.viewport.width; height: childrenRect.height; - color: palette.light Label { 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() From 392d237b4746b013affc749b192ab48033dabc04 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 16:55:04 +0200 Subject: [PATCH 281/304] Fix filtering UM2+ profiles Profiles did not show before selecting a material CURA-1278 --- cura/MachineManagerModel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 816dbc4600..e9a07f58f7 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -114,8 +114,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) From e793ce1a2c289cca27c1d4b42b788118521c4855 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 16:57:40 +0200 Subject: [PATCH 282/304] Use ID instead of definition --- cura/ExtrudersModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 3265667dc6..2a4ae54310 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -80,7 +80,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): } self.appendItem(item) - for extruder in manager.getMachineExtruders(global_container_stack.getBottom()): + for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()): material = extruder.findContainer({ "type": "material" }) colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" position = extruder.getBottom().getMetaDataEntry("position", default = "0") #Position in the definition. From beb263025b5041ec00a222355d02bd6625d9f983 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 15:59:57 +0200 Subject: [PATCH 283/304] Make ExtruderSelector invisible if there is no choice in extruders It doesn't yet update well if you keep the panel open while switching machines. Contributes to issue CURA-340. --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 4610083674..03158266f5 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -36,6 +36,7 @@ Item { { id: extruders_model } + visible: extruders_model.rowCount() > 1 textRole: "name" width: items.width height: UM.Theme.getSize("section").height From 9d618282ed614b78ee263187af71f6ed25c3603f Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 16:30:54 +0200 Subject: [PATCH 284/304] Save default material colour statically So if you wish to change that colour, you only need to change it in one place. Contributes to issue CURA-340. --- cura/ExtrudersModel.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cura/ExtrudersModel.py b/cura/ExtrudersModel.py index 2a4ae54310..960c05bd5e 100644 --- a/cura/ExtrudersModel.py +++ b/cura/ExtrudersModel.py @@ -28,6 +28,10 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): # containers. 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. # @@ -71,7 +75,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): if self._add_global: material = global_container_stack.findContainer({ "type": "material" }) - colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" + colour = material.getMetaDataEntry("color_code", default = self.defaultColour) if material else self.defaultColour item = { "id": global_container_stack.getId(), "name": "Global", @@ -82,7 +86,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): for extruder in manager.getMachineExtruders(global_container_stack.getBottom().getId()): material = extruder.findContainer({ "type": "material" }) - colour = material.getMetaDataEntry("color_code", default = "#FFFF00") if material else "#FFFF00" + 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) From 9f3752276f701f5fb417f06d28aa94a6b3f34532 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 16:43:53 +0200 Subject: [PATCH 285/304] Fix check if machine's extruders are processed Luckily this did never occur anyway since the rest of the code was sound. Contributes to issue CURA-340. --- cura/ExtruderManager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/ExtruderManager.py b/cura/ExtruderManager.py index f5971ac141..edd6ab7d23 100644 --- a/cura/ExtruderManager.py +++ b/cura/ExtruderManager.py @@ -191,9 +191,10 @@ class ExtruderManager(QObject): container_registry.addContainer(container_stack) ## Generates extruders for a specific machine. + # + # \param machine_id The machine to get the extruders of. def getMachineExtruders(self, machine_id): - container_registry = UM.Settings.ContainerRegistry.getInstance() - if not machine_id in self._extruder_trains: + 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 name in self._extruder_trains[machine_id]: From 3206650f39cf6f7b034307d5f5afad79b632acb8 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 16:59:01 +0200 Subject: [PATCH 286/304] Fix signal, repair per-object settings This was the wrong type of signal, which gave an error. Contributes to issue CURA-340. --- cura/SettingOverrideDecorator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 06dbc2cb31..23730fee60 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -1,11 +1,10 @@ # Copyright (c) 2016 Ultimaker B.V. # Cura is released under the terms of the AGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal 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 @@ -15,9 +14,10 @@ from UM.Application import Application ## 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 = pyqtSignal() + activeExtruderChanged = Signal() def __init__(self): super().__init__() From 959305ddf72769d5154771996b7a6c78e2db492d Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Thu, 9 Jun 2016 17:26:43 +0200 Subject: [PATCH 287/304] JSOn fix: removed buggy default:true for numeric values (CURA-1558) --- resources/definitions/fdmprinter.def.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 52aab1d26c..bc4b8dbc40 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -324,7 +324,6 @@ "minimum_value": "0.001", "minimum_value_warning": "0.04", "maximum_value_warning": "0.8 * machine_nozzle_size", - "default_value": true, "settable_per_mesh": false, "settable_per_extruder": false }, @@ -338,7 +337,6 @@ "minimum_value": "0.001", "minimum_value_warning": "0.04", "maximum_value_warning": "0.8 * machine_nozzle_size", - "default_value": true, "settable_per_mesh": false, "settable_per_extruder": false }, @@ -366,7 +364,6 @@ "value":"line_width", "default_value": 0.4, "type": "float", - "default_value": true, "settable_per_mesh": true, "children": { From b0198aedb089afb64be4322424503ddf9138e3f1 Mon Sep 17 00:00:00 2001 From: Tim Kuipers Date: Thu, 9 Jun 2016 17:27:20 +0200 Subject: [PATCH 288/304] JSON fix: line_width didn't supply any settable_per info (CURA-1558) --- resources/definitions/fdmprinter.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index bc4b8dbc40..1f7ed7c78a 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -351,6 +351,7 @@ "default_value": 0.4, "type": "float", "value": "machine_nozzle_size", + "settable_per_mesh": true, "children": { "wall_line_width": From c6b17064601eb59837d9f109c2ffe5e2435c5b58 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 17:49:33 +0200 Subject: [PATCH 289/304] Fix customisedSettings button (profiles dropdown) layout and behavior CURA-1685 --- resources/qml/SidebarHeader.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index fdae096aee..1083496f36 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -430,12 +430,12 @@ Column anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("setting_preferences_button_margin").width + 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: base.manageProfilesAction.trigger() + 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.") From d34d398e9660060233024d338823567bd04a1444 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 18:40:42 +0200 Subject: [PATCH 290/304] Change the implementation of creating a profile from the current settings The newly created profile now combines the settings of the active quality profile and the current settings CURA-970, CURA-1585 --- cura/MachineManagerModel.py | 34 +++++----------------- resources/qml/Actions.qml | 2 +- resources/qml/Cura.qml | 2 +- resources/qml/Preferences/ProfilesPage.qml | 4 +-- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e9a07f58f7..6768a357a5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -269,38 +269,18 @@ class MachineManagerModel(QObject): 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.setReadOnly(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")) @@ -348,7 +328,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/resources/qml/Actions.qml b/resources/qml/Actions.qml index e09b6b5424..3ef40644d2 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -112,7 +112,7 @@ 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() + onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer() } Action diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index a1023d8ef2..547f05d056 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -582,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 cd37df3cc5..71afdd98ac 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -65,7 +65,7 @@ UM.ManagementPage onAddObject: { var selectedContainer; if (objectList.currentItem.id == Cura.MachineManager.activeQualityId) { - selectedContainer = Cura.MachineManager.convertUserContainerToQuality(); + selectedContainer = Cura.MachineManager.newQualityContainerFromQualityAndUser(); } else { selectedContainer = Cura.MachineManager.duplicateContainer(base.currentItem.id); } @@ -121,7 +121,7 @@ UM.ManagementPage return catalog.i18nc("@action:button", "Update \"%1\"".arg(profileName)); } enabled: Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId) - onClicked: Cura.MachineManager.updateUserContainerToQuality() + onClicked: Cura.MachineManager.updateQualityContainerFromUserContainer() } Button From c8070cff052083751f0a17bd0058e9f8888876c5 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Thu, 9 Jun 2016 18:43:54 +0200 Subject: [PATCH 291/304] Don't ignore the directory but the link, too. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index cc21d3092c..8bcc055115 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ resources/firmware .pydevproject # Debian packaging -debian/ +debian* From 330481d2d604913199c408deccf79f24c118a72f Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Thu, 9 Jun 2016 18:45:48 +0200 Subject: [PATCH 292/304] Ignore settings set on Eclipse --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8bcc055115..dc951a52b7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,11 @@ resources/firmware *~ *.qm .idea + +# Eclipse+PyDev .project .pydevproject +.settings # Debian packaging debian* From f5f711b7dc38270860d2c54e3403fc647aae716c Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 18:59:28 +0200 Subject: [PATCH 293/304] On extruder switch create OverrideDecorator if needed The SettingOverrideDecorator is only applied if the node has a per-object setting. Now it also creates a decorator also if you've ever switched the extruder, which was needed because the decorator contains the information which extruder to print with. Contributes to issue CURA-340. --- plugins/PerObjectSettingsTool/PerObjectSettingsTool.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py index 255277c3af..395dbdc594 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsTool.py @@ -5,7 +5,7 @@ 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. @@ -55,6 +55,9 @@ class PerObjectSettingsTool(Tool): # 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): From 9e86cd5c85312d54d120a0d769560ae833055443 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 19:03:41 +0200 Subject: [PATCH 294/304] Fix call to findContainerStack[s] Was a typo. Now it also checks if the stack ID is correct here. Not because it went wrong, but for defensive programming. Contributes to issue CURA-340. --- cura/SettingOverrideDecorator.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cura/SettingOverrideDecorator.py b/cura/SettingOverrideDecorator.py index 23730fee60..7417e47bf2 100644 --- a/cura/SettingOverrideDecorator.py +++ b/cura/SettingOverrideDecorator.py @@ -8,6 +8,7 @@ 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 @@ -58,7 +59,11 @@ class SettingOverrideDecorator(SceneNodeDecorator): # kept up to date. def _updateNextStack(self): if self._extruder_stack: - self._stack.setNextStack(ContainerRegistry.getInstance().findContainerStack(id = 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()) From 598ff1e398d662f2f4570417d1893f071f7bd31b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 9 Jun 2016 19:05:52 +0200 Subject: [PATCH 295/304] Fix changing active extruder from per-object drop-down Apparently this is the way you do it. Contributes to issue CURA-340. --- plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 03158266f5..502e903416 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -101,7 +101,7 @@ Item { } } - onActivated: UM.ActiveTool.properties.setValue("SelectedActiveExtruder", extruders_model.getItem(index).id); + onActivated: UM.ActiveTool.setProperty("SelectedActiveExtruder", extruders_model.getItem(index).id); onModelChanged: updateCurrentIndex(); function updateCurrentIndex() From af238d5a7656b243550c426405e2b356de877365 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 9 Jun 2016 19:17:31 +0200 Subject: [PATCH 296/304] Renaming profiles now also renames them on disk CURA-1683 --- cura/MachineManagerModel.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e9a07f58f7..7e588574d8 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -5,12 +5,17 @@ from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from UM.Application import Application from UM.Preferences import Preferences from UM.Logger import Logger +from UM.Resources import Resources + +import os +import urllib import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerStack import ContainerStack from . import ExtruderManager +import cura.CuraApplication from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -323,8 +328,19 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: + + # Remove old container form drive. + old_id = containers[0].getId() + file_name = urllib.parse.quote_plus(old_id) + ".inst.cfg" + path = Resources.getStoragePath(cura.CuraApplication.CuraApplication.ResourceTypes.QualityInstanceContainer, + file_name) + os.remove(path) + + ## Check if the new name is allowed. new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) + containers[0].setName(new_name) + containers[0]._id = new_name # Todo: Fix proper id change function for this. self.activeQualityChanged.emit() From 0d7a7d9299a945a5da32445897d758b11b5d6b81 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 19:18:46 +0200 Subject: [PATCH 297/304] Update wording to make storing/updating/discarding current settings more clear CURA-970 --- resources/qml/Actions.qml | 8 ++++---- resources/qml/Cura.qml | 8 ++++---- resources/qml/Preferences/ProfilesPage.qml | 8 +++----- resources/qml/SidebarHeader.qml | 20 ++++---------------- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 3ef40644d2..7e03bd7102 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -111,7 +111,7 @@ 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"); + text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings"); onTriggered: Cura.MachineManager.updateQualityContainerFromUserContainer() } @@ -119,15 +119,15 @@ Item { 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 547f05d056..c3dc95b454 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -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 diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 71afdd98ac..93fd8ae61f 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 { @@ -116,9 +116,7 @@ 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.updateQualityContainerFromUserContainer() @@ -126,7 +124,7 @@ UM.ManagementPage Button { - text: catalog.i18nc("@action:button", "Discard changes"); + text: catalog.i18nc("@action:button", "Discard current settings"); enabled: Cura.MachineManager.hasUserSettings onClicked: Cura.MachineManager.clearUserSettings(); } diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml index 1083496f36..282068ee2c 100644 --- a/resources/qml/SidebarHeader.qml +++ b/resources/qml/SidebarHeader.qml @@ -401,23 +401,11 @@ Column } MenuSeparator { } - 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 } } UM.SimpleButton From 7d2a7bd157a334fe96dd8e215a0faf2de3e391e1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 21:40:07 +0200 Subject: [PATCH 298/304] Abbreviate headers CURA-1668 --- resources/qml/Preferences/ProfilesPage.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 93fd8ae61f..670bf79956 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -191,13 +191,13 @@ UM.ManagementPage visible: currentItem.id == Cura.MachineManager.activeQualityId spacing: UM.Theme.getSize("default_margin").width Label { - text: catalog.i18nc("@action:label", "Profile value") + text: catalog.i18nc("@action:label", "Profile:") width: scrollView.width / 100 * 55 horizontalAlignment: Text.AlignRight font.bold: true } Label { - text: catalog.i18nc("@action:label", "Current setting") + text: catalog.i18nc("@action:label", "Current:") visible: currentItem.id == Cura.MachineManager.activeQualityId font.bold: true } From 2287c2daa698c0300074af37c65d9c8c96855391 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 9 Jun 2016 21:40:53 +0200 Subject: [PATCH 299/304] Show that a value is being calculated instead of showing "QVariant..." CURA-1668 --- cura/ContainerSettingsModel.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cura/ContainerSettingsModel.py b/cura/ContainerSettingsModel.py index 83a1f3ccd4..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 @@ -53,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("") From d8e8b0740ac2b1d776c13cd8078fe1b8e4f5a45d Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 10 Jun 2016 00:12:35 +0200 Subject: [PATCH 300/304] Temporarily revert "Renaming profiles now also renames them on disk" This reverts commit af238d5a7656b243550c426405e2b356de877365. --- cura/MachineManagerModel.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e3f0bd6241..6768a357a5 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -5,17 +5,12 @@ from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from UM.Application import Application from UM.Preferences import Preferences from UM.Logger import Logger -from UM.Resources import Resources - -import os -import urllib import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerStack import ContainerStack from . import ExtruderManager -import cura.CuraApplication from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -308,19 +303,8 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: - - # Remove old container form drive. - old_id = containers[0].getId() - file_name = urllib.parse.quote_plus(old_id) + ".inst.cfg" - path = Resources.getStoragePath(cura.CuraApplication.CuraApplication.ResourceTypes.QualityInstanceContainer, - file_name) - os.remove(path) - - ## Check if the new name is allowed. new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) - containers[0].setName(new_name) - containers[0]._id = new_name # Todo: Fix proper id change function for this. self.activeQualityChanged.emit() From 070a522abb772854d5d59214a30f18ff8f25b940 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jun 2016 09:17:12 +0200 Subject: [PATCH 301/304] Revert "Temporarily revert "Renaming profiles now also renames them on disk"" Starting work on it again, so unreverting the revert (i guess) This reverts commit d8e8b0740ac2b1d776c13cd8078fe1b8e4f5a45d. --- cura/MachineManagerModel.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 6768a357a5..e3f0bd6241 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -5,12 +5,17 @@ from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from UM.Application import Application from UM.Preferences import Preferences from UM.Logger import Logger +from UM.Resources import Resources + +import os +import urllib import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerStack import ContainerStack from . import ExtruderManager +import cura.CuraApplication from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -303,8 +308,19 @@ class MachineManagerModel(QObject): def renameQualityContainer(self, container_id, new_name): containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id, type = "quality") if containers: + + # Remove old container form drive. + old_id = containers[0].getId() + file_name = urllib.parse.quote_plus(old_id) + ".inst.cfg" + path = Resources.getStoragePath(cura.CuraApplication.CuraApplication.ResourceTypes.QualityInstanceContainer, + file_name) + os.remove(path) + + ## Check if the new name is allowed. new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) + containers[0].setName(new_name) + containers[0]._id = new_name # Todo: Fix proper id change function for this. self.activeQualityChanged.emit() From 962b4e84a963f8799691b829ff701b077307065e Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jun 2016 09:38:47 +0200 Subject: [PATCH 302/304] Fixed renaming of profiles. They are now correctly renamed (and saved under different name on disk as well) CURA-1683 --- cura/MachineManagerModel.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index e3f0bd6241..7cb80bbf20 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -6,6 +6,7 @@ from UM.Application import Application from UM.Preferences import Preferences from UM.Logger import Logger from UM.Resources import Resources +import copy import os import urllib @@ -303,26 +304,32 @@ 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")) - # Remove old container form drive. - old_id = containers[0].getId() - file_name = urllib.parse.quote_plus(old_id) + ".inst.cfg" - path = Resources.getStoragePath(cura.CuraApplication.CuraApplication.ResourceTypes.QualityInstanceContainer, - file_name) - os.remove(path) + # 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()) - ## Check if the new name is allowed. - new_name = self._createUniqueName("quality", containers[0].getName(), new_name, catalog.i18nc("@label", "Custom profile")) + # Actually set the name + new_container.setName(new_name) + new_container._id = new_name # Todo: Fix proper id change function for this. - containers[0].setName(new_name) - containers[0]._id = new_name # Todo: Fix proper id change function for this. - self.activeQualityChanged.emit() + # 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): From 0cf3fd36240849d30415057bb307ec70959abbf7 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 10 Jun 2016 09:41:51 +0200 Subject: [PATCH 303/304] Removed unused imports CURA-1278 --- cura/MachineManagerModel.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cura/MachineManagerModel.py b/cura/MachineManagerModel.py index 7cb80bbf20..443c19d302 100644 --- a/cura/MachineManagerModel.py +++ b/cura/MachineManagerModel.py @@ -4,22 +4,16 @@ 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 -from UM.Resources import Resources -import copy - -import os -import urllib import UM.Settings from UM.Settings.Validator import ValidatorState from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.ContainerStack import ContainerStack from . import ExtruderManager -import cura.CuraApplication from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") + class MachineManagerModel(QObject): def __init__(self, parent = None): super().__init__(parent) @@ -47,7 +41,6 @@ class MachineManagerModel(QObject): self.setActiveMachine(active_machine_id) pass - globalContainerChanged = pyqtSignal() activeMaterialChanged = pyqtSignal() activeVariantChanged = pyqtSignal() From b61b0a7ee2e11adf6bbf150a61bf48e226fd57c5 Mon Sep 17 00:00:00 2001 From: Thomas Karl Pietrowski Date: Fri, 10 Jun 2016 10:52:12 +0200 Subject: [PATCH 304/304] Removing unneeded import of os' --- cura_app.py | 1 - 1 file changed, 1 deletion(-) 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")