mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-15 12:15:58 +08:00
Merge branch 'master' of https://github.com/Ultimaker/Cura
This commit is contained in:
commit
184247ced6
@ -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)
|
||||
|
@ -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
|
||||
@ -30,7 +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
|
||||
from . import CameraAnimation
|
||||
@ -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)
|
||||
|
||||
@ -327,8 +329,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()
|
||||
@ -368,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):
|
||||
|
@ -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,38 @@ 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()
|
||||
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.
|
||||
#
|
||||
@ -104,6 +127,22 @@ 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.
|
||||
#
|
||||
# \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.
|
||||
|
@ -1,13 +1,11 @@
|
||||
# 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.
|
||||
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.
|
||||
|
||||
|
||||
## Class that handles the current extruder stack.
|
||||
@ -16,19 +14,42 @@ 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
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
#
|
||||
# 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.
|
||||
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 = 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.
|
||||
@ -36,18 +57,20 @@ 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!
|
||||
return #Then leave them empty!
|
||||
|
||||
#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 = 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))
|
||||
self._extruders.append(Extruder(extruder_definition))
|
||||
self.extrudersChanged.emit()
|
56
cura/ExtrudersModel.py
Normal file
56
cura/ExtrudersModel.py
Normal file
@ -0,0 +1,56 @@
|
||||
# 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.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)
|
||||
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"])
|
@ -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())
|
||||
|
@ -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()):
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
})
|
@ -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!
|
||||
|
@ -6,14 +6,15 @@ from UM.Scene.Selection import Selection
|
||||
from UM.Application import Application
|
||||
from UM.Preferences import Preferences
|
||||
|
||||
from . import PerObjectSettingsModel
|
||||
|
||||
## 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)
|
||||
@ -33,21 +34,13 @@ 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
|
||||
|
||||
def setContainerID(self, value):
|
||||
pass
|
||||
return selected_object.callDecoration("getStack").getId()
|
||||
except AttributeError:
|
||||
return ""
|
||||
|
||||
def _onPreferenceChanged(self, preference):
|
||||
if preference == "cura/active_mode":
|
||||
|
@ -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())
|
@ -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"
|
||||
},
|
||||
|
@ -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",
|
||||
|
112
resources/qml/Settings/SettingExtruder.qml
Normal file
112
resources/qml/Settings/SettingExtruder.qml
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
@ -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":
|
||||
|
Loading…
x
Reference in New Issue
Block a user