Merge branch 'master' into feature_extruder_per_feature

This commit is contained in:
Ghostkeeper 2017-05-22 16:05:57 +02:00
commit 2a6a968540
No known key found for this signature in database
GPG Key ID: C5F96EE2BC0F7E75
55 changed files with 713 additions and 226 deletions

View File

@ -871,7 +871,7 @@ class BuildVolume(SceneNode):
else:
extruder_index = self._global_container_stack.getProperty(extruder_setting_key, "value")
if extruder_index == "-1": # If extruder index is -1 use global instead
if str(extruder_index) == "-1": # If extruder index is -1 use global instead
stack = self._global_container_stack
else:
extruder_stack_id = ExtruderManager.getInstance().extruderIds[str(extruder_index)]

View File

@ -2,6 +2,9 @@ import sys
import platform
import traceback
import webbrowser
import faulthandler
import tempfile
import os
import urllib
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QCoreApplication
@ -91,6 +94,17 @@ def show(exception_type, value, tb):
crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}"
crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True)
os.close(tmp_file_fd)
with open(tmp_file_path, "w") as f:
faulthandler.dump_traceback(f, all_threads=True)
with open(tmp_file_path, "r") as f:
data = f.read()
msg = "-------------------------\n"
msg += data
crash_info += "\n\n" + msg
textarea.setText(crash_info)
buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog)

View File

@ -138,13 +138,14 @@ class CuraApplication(QtApplication):
# From which stack the setting would inherit if not defined per object (handled in the engine)
# AND for settings which are not settable_per_mesh:
# which extruder is the only extruder this setting is obtained from
SettingDefinition.addSupportedProperty("limit_to_extruder", DefinitionPropertyType.Function, default = "-1")
SettingDefinition.addSupportedProperty("limit_to_extruder", DefinitionPropertyType.Function, default = "-1", depends_on = "value")
# For settings which are not settable_per_mesh and not settable_per_extruder:
# A function which determines the glabel/meshgroup value by looking at the values of the setting in all (used) extruders
SettingDefinition.addSupportedProperty("resolve", DefinitionPropertyType.Function, default = None, depends_on = "value")
SettingDefinition.addSettingType("extruder", None, str, Validator)
SettingDefinition.addSettingType("optional_extruder", None, str, None)
SettingDefinition.addSettingType("[int]", None, str, None)
@ -178,7 +179,8 @@ class CuraApplication(QtApplication):
("machine_stack", ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"),
("extruder_train", ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"),
("preferences", Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"),
("user", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer")
("user", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer"),
("definition_changes", InstanceContainer.Version * 1000000 + self.SettingVersion): (self.ResourceTypes.DefinitionChangesContainer, "application/x-uranium-instancecontainer"),
}
)
@ -488,7 +490,7 @@ class CuraApplication(QtApplication):
self._plugin_registry.loadPlugins()
if self.getBackend() == None:
if self.getBackend() is None:
raise RuntimeError("Could not load the backend plugin!")
self._plugins_loaded = True
@ -625,7 +627,9 @@ class CuraApplication(QtApplication):
camera.lookAt(Vector(0, 0, 0))
controller.getScene().setActiveCamera("3d")
self.getController().getTool("CameraTool").setOrigin(Vector(0, 100, 0))
camera_tool = self.getController().getTool("CameraTool")
camera_tool.setOrigin(Vector(0, 100, 0))
camera_tool.setZoomRange(0.1, 200000)
self._camera_animation = CameraAnimation.CameraAnimation()
self._camera_animation.setCameraTool(self.getController().getTool("CameraTool"))

View File

@ -700,7 +700,7 @@ class ContainerManager(QObject):
self._container_registry.addContainer(duplicated_container)
return self._getMaterialContainerIdForActiveMachine(new_id)
## Create a new material by cloning Generic PLA and setting the GUID to something unqiue
## Create a new material by cloning Generic PLA for the current material diameter and setting the GUID to something unqiue
#
# \return \type{str} the id of the newly created container.
@pyqtSlot(result = str)
@ -708,14 +708,25 @@ class ContainerManager(QObject):
# Ensure all settings are saved.
Application.getInstance().saveSettings()
containers = self._container_registry.findInstanceContainers(id="generic_pla")
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return ""
approximate_diameter = round(global_stack.getProperty("material_diameter", "value"))
containers = self._container_registry.findInstanceContainers(id = "generic_pla*", approximate_diameter = approximate_diameter)
if not containers:
Logger.log("d", "Unable to create a new material by cloning generic_pla, because it doesn't exist.")
Logger.log("d", "Unable to create a new material by cloning Generic PLA, because it cannot be found for the material diameter for this machine.")
return ""
base_file = containers[0].getMetaDataEntry("base_file")
containers = self._container_registry.findInstanceContainers(id = base_file)
if not containers:
Logger.log("d", "Unable to create a new material by cloning Generic PLA, because the base file for Generic PLA for this machine can not be found.")
return ""
# Create a new ID & container to hold the data.
new_id = self._container_registry.uniqueName("custom_material")
container_type = type(containers[0]) # Could be either a XMLMaterialProfile or a InstanceContainer
container_type = type(containers[0]) # Always XMLMaterialProfile, since we specifically clone the base_file
duplicated_container = container_type(new_id)
# Instead of duplicating we load the data from the basefile again.

View File

@ -15,7 +15,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.Interfaces import DefinitionContainerInterface
from typing import Optional, List, TYPE_CHECKING, Union
if TYPE_CHECKING:
@ -74,11 +74,12 @@ class ExtruderManager(QObject):
except KeyError:
return 0
@pyqtProperty("QVariantMap", notify=extrudersChanged)
@pyqtProperty("QVariantMap", notify = extrudersChanged)
def extruderIds(self):
map = {}
for position in self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()]:
map[position] = self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][position].getId()
global_stack_id = Application.getInstance().getGlobalContainerStack().getId()
for position in self._extruder_trains[global_stack_id]:
map[position] = self._extruder_trains[global_stack_id][position].getId()
return map
@pyqtSlot(str, result = str)
@ -150,14 +151,14 @@ class ExtruderManager(QObject):
selected_nodes.append(node)
# Then, figure out which nodes are used by those selected nodes.
global_stack = Application.getInstance().getGlobalContainerStack()
current_extruder_trains = self._extruder_trains.get(global_stack.getId())
for node in selected_nodes:
extruder = node.callDecoration("getActiveExtruder")
if extruder:
object_extruders.add(extruder)
else:
global_stack = Application.getInstance().getGlobalContainerStack()
if global_stack.getId() in self._extruder_trains:
object_extruders.add(self._extruder_trains[global_stack.getId()]["0"].getId())
elif current_extruder_trains:
object_extruders.add(current_extruder_trains["0"].getId())
self._selected_object_extruders = list(object_extruders)
@ -202,7 +203,7 @@ class ExtruderManager(QObject):
# \param machine_definition The machine definition to add the extruders for.
# \param machine_id The machine_id to add the extruders for.
@deprecated("Use CuraStackBuilder", "2.6")
def addMachineExtruders(self, machine_definition: DefinitionContainer, machine_id: str) -> None:
def addMachineExtruders(self, machine_definition: DefinitionContainerInterface, machine_id: str) -> None:
changed = False
machine_definition_id = machine_definition.getId()
if machine_id not in self._extruder_trains:
@ -236,6 +237,13 @@ class ExtruderManager(QObject):
if machine_id not in self._extruder_trains:
self._extruder_trains[machine_id] = {}
changed = True
# do not register if an extruder has already been registered at the position on this machine
if any(item.getId() == extruder_train.getId() for item in self._extruder_trains[machine_id].values()):
Logger.log("w", "Extruder [%s] has already been registered on machine [%s], not doing anything",
extruder_train.getId(), machine_id)
return
if extruder_train:
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
changed = True
@ -255,7 +263,7 @@ class ExtruderManager(QObject):
# \param position The position of this extruder train in the extruder slots of the machine.
# \param machine_id The id of the "global" stack this extruder is linked to.
@deprecated("Use CuraStackBuilder::createExtruderStack", "2.6")
def createExtruderTrain(self, extruder_definition: DefinitionContainer, machine_definition: DefinitionContainer,
def createExtruderTrain(self, extruder_definition: DefinitionContainerInterface, machine_definition: DefinitionContainerInterface,
position, machine_id: str) -> None:
# Cache some things.
container_registry = ContainerRegistry.getInstance()
@ -462,6 +470,8 @@ class ExtruderManager(QObject):
for extruder in self.getMachineExtruders(machine_id):
ContainerRegistry.getInstance().removeContainer(extruder.userChanges.getId())
ContainerRegistry.getInstance().removeContainer(extruder.getId())
if machine_id in self._extruder_trains:
del self._extruder_trains[machine_id]
## Returns extruders for a specific machine.
#
@ -515,7 +525,7 @@ class ExtruderManager(QObject):
#
# This is exposed to SettingFunction so it can be used in value functions.
#
# \param key The key of the setting to retieve values for.
# \param key The key of the setting to retrieve values for.
#
# \return A list of values for all extruders. If an extruder does not have a value, it will not be in the list.
# If no extruder has the value, the list will contain the global value.

View File

@ -1,22 +1,21 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from typing import Any
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
from typing import Any, TYPE_CHECKING, Optional
from UM.Decorators import override
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
from UM.Settings.ContainerStack import ContainerStack, InvalidContainerStackError
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.Interfaces import ContainerInterface
from . import Exceptions
from .CuraContainerStack import CuraContainerStack
from .ExtruderManager import ExtruderManager
if TYPE_CHECKING:
from cura.Settings.GlobalStack import GlobalStack
## Represents an Extruder and its related containers.
#
#
@ -38,6 +37,10 @@ class ExtruderStack(CuraContainerStack):
# For backward compatibility: Register the extruder with the Extruder Manager
ExtruderManager.getInstance().registerExtruder(self, stack.id)
@override(ContainerStack)
def getNextStack(self) -> Optional["GlobalStack"]:
return super().getNextStack()
@classmethod
def getLoadingPriority(cls) -> int:
return 3
@ -59,6 +62,13 @@ class ExtruderStack(CuraContainerStack):
if not super().getProperty(key, "settable_per_extruder"):
return self.getNextStack().getProperty(key, property_name)
limit_to_extruder = super().getProperty(key, "limit_to_extruder")
if (limit_to_extruder is not None and limit_to_extruder != "-1") and self.getMetaDataEntry("position") != str(limit_to_extruder):
if str(limit_to_extruder) in self.getNextStack().extruders:
result = self.getNextStack().extruders[str(limit_to_extruder)].getProperty(key, property_name)
if result is not None:
return result
return super().getProperty(key, property_name)
@override(CuraContainerStack)

View File

@ -1,12 +1,15 @@
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer
from typing import Iterable
import UM.Qt.ListModel
from UM.Application import Application
import UM.FlameProfiler
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders.
from cura.Settings.MachineManager import MachineManager #To listen to changes on the extruders of the currently active machine.
## Model that holds extruders.
#
@ -66,16 +69,13 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
self._add_global = False
self._simple_names = False
self._active_extruder_stack = None
self._active_machine_extruders = [] # type: Iterable[ExtruderStack]
self._use_optional_extruder = False
#Listen to changes.
Application.getInstance().globalContainerStackChanged.connect(self._updateExtruders)
manager = ExtruderManager.getInstance()
self._updateExtruders()
manager.activeExtruderChanged.connect(self._onActiveExtruderChanged)
self._onActiveExtruderChanged()
Application.getInstance().globalContainerStackChanged.connect(self._extrudersChanged) #When the machine is swapped we must update the active machine extruders.
ExtruderManager.getInstance().extrudersChanged.connect(self._extrudersChanged) #When the extruders change we must link to the stack-changed signal of the new extruder.
self._extrudersChanged() #Also calls _updateExtruders.
def setAddGlobal(self, add):
if add != self._add_global:
@ -89,6 +89,18 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
def addGlobal(self):
return self._add_global
useOptionalExtruderChanged = pyqtSignal()
def setUseOptionalExtruder(self, use_optional_extruder):
if use_optional_extruder != self._use_optional_extruder:
self._use_optional_extruder = use_optional_extruder
self.useOptionalExtruderChanged.emit()
self._updateExtruders()
@pyqtProperty(bool, fset = setUseOptionalExtruder, notify = useOptionalExtruderChanged)
def useOptionalExtruder(self):
return self._use_optional_extruder
## Set the simpleNames property.
def setSimpleNames(self, simple_names):
if simple_names != self._simple_names:
@ -104,17 +116,31 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
def simpleNames(self):
return self._simple_names
def _onActiveExtruderChanged(self):
manager = ExtruderManager.getInstance()
active_extruder_stack = manager.getActiveExtruderStack()
if self._active_extruder_stack != active_extruder_stack:
if self._active_extruder_stack:
self._active_extruder_stack.containersChanged.disconnect(self._onExtruderStackContainersChanged)
## Links to the stack-changed signal of the new extruders when an extruder
# is swapped out or added in the current machine.
#
# \param machine_id The machine for which the extruders changed. This is
# filled by the ExtruderManager.extrudersChanged signal when coming from
# that signal. Application.globalContainerStackChanged doesn't fill this
# signal; it's assumed to be the current printer in that case.
def _extrudersChanged(self, machine_id = None):
if machine_id is not None:
if Application.getInstance().getGlobalContainerStack() is None:
return #No machine, don't need to update the current machine's extruders.
if machine_id != Application.getInstance().getGlobalContainerStack().getId():
return #Not the current machine.
#Unlink from old extruders.
for extruder in self._active_machine_extruders:
extruder.containersChanged.disconnect(self._onExtruderStackContainersChanged)
if active_extruder_stack:
# Update the model when the material container is changed
active_extruder_stack.containersChanged.connect(self._onExtruderStackContainersChanged)
self._active_extruder_stack = active_extruder_stack
#Link to new extruders.
self._active_machine_extruders = []
extruder_manager = ExtruderManager.getInstance()
for extruder in extruder_manager.getExtruderStacks():
extruder.containersChanged.connect(self._onExtruderStackContainersChanged)
self._active_machine_extruders.append(extruder)
self._updateExtruders() #Since the new extruders may have different properties, update our own model.
def _onExtruderStackContainersChanged(self, container):
# Update when there is an empty container or material change
@ -184,5 +210,16 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
if changed:
items.sort(key = lambda i: i["index"])
# We need optional extruder to be last, so add it after we do sorting.
# This way we can simply intrepret the -1 of the index as the last item (which it now always is)
if self._use_optional_extruder:
item = {
"id": "zomg",
"name": "Not overridden",
"color": "#ffffff",
"index": -1,
"definition": ""
}
items.append(item)
self.setItems(items)
self.modelChanged.emit()

View File

@ -1,7 +1,7 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from typing import Any
from typing import Any, Dict
from PyQt5.QtCore import pyqtProperty
@ -24,7 +24,7 @@ class GlobalStack(CuraContainerStack):
self.addMetaDataEntry("type", "machine") # For backward compatibility
self._extruders = []
self._extruders = {}
# This property is used to track which settings we are calculating the "resolve" for
# and if so, to bypass the resolve to prevent an infinite recursion that would occur
@ -34,8 +34,8 @@ class GlobalStack(CuraContainerStack):
## Get the list of extruders of this stack.
#
# \return The extruders registered with this stack.
@pyqtProperty("QVariantList")
def extruders(self) -> list:
@pyqtProperty("QVariantMap")
def extruders(self) -> Dict[str, "ExtruderStack"]:
return self._extruders
@classmethod
@ -52,8 +52,17 @@ class GlobalStack(CuraContainerStack):
extruder_count = self.getProperty("machine_extruder_count", "value")
if extruder_count and len(self._extruders) + 1 > extruder_count:
Logger.log("w", "Adding extruder {meta} to {id} but its extruder count is {count}".format(id = self.id, count = extruder_count, meta = str(extruder.getMetaData())))
return
self._extruders.append(extruder)
position = extruder.getMetaDataEntry("position")
if position is None:
Logger.log("w", "No position defined for extruder {extruder}, cannot add it to stack {stack}", extruder = extruder.id, stack = self.id)
return
if any(item.getId() == extruder.id for item in self._extruders.values()):
Logger.log("w", "Extruder [%s] has already been added to this stack [%s]", extruder.id, self._id)
return
self._extruders[position] = extruder
## Overridden from ContainerStack
#
@ -71,6 +80,7 @@ class GlobalStack(CuraContainerStack):
if not self.definition.findDefinitions(key = key):
return None
# Handle the "resolve" property.
if self._shouldResolve(key, property_name):
self._resolving_settings.add(key)
resolve = super().getProperty(key, "resolve")
@ -78,6 +88,16 @@ class GlobalStack(CuraContainerStack):
if resolve is not None:
return resolve
# Handle the "limit_to_extruder" property.
limit_to_extruder = super().getProperty(key, "limit_to_extruder")
if limit_to_extruder is not None and limit_to_extruder != "-1" and limit_to_extruder in self._extruders:
if super().getProperty(key, "settable_per_extruder"):
result = self._extruders[str(limit_to_extruder)].getProperty(key, property_name)
if result is not None:
return result
else:
Logger.log("e", "Setting {setting} has limit_to_extruder but is not settable per extruder!", setting = key)
return super().getProperty(key, property_name)
## Overridden from ContainerStack

View File

@ -220,6 +220,7 @@ class MachineManager(QObject):
if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index)
self._auto_materials_changed = {} #Processed all of them now.
def _autoUpdateHotends(self):
extruder_manager = ExtruderManager.getInstance()
@ -236,6 +237,7 @@ class MachineManager(QObject):
if old_index is not None:
extruder_manager.setActiveExtruderIndex(old_index)
self._auto_hotends_changed = {} #Processed all of them now.
def _onGlobalContainerChanged(self):
if self._global_container_stack:
@ -703,7 +705,7 @@ class MachineManager(QObject):
# Depending on from/to material+current variant, a quality profile is chosen and set.
@pyqtSlot(str)
def setActiveMaterial(self, material_id: str):
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
with postponeSignals(*self._getContainerChangedSignals()):
containers = ContainerRegistry.getInstance().findInstanceContainers(id = material_id)
if not containers or not self._active_container_stack:
return
@ -768,7 +770,7 @@ class MachineManager(QObject):
@pyqtSlot(str)
def setActiveVariant(self, variant_id: str):
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
with postponeSignals(*self._getContainerChangedSignals()):
containers = ContainerRegistry.getInstance().findInstanceContainers(id = variant_id)
if not containers or not self._active_container_stack:
return
@ -1061,19 +1063,19 @@ class MachineManager(QObject):
# If the machine that is being removed is the currently active machine, set another machine as the active machine.
activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id)
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
# activate a new machine before removing a machine because this is safer
if activate_new_machine:
machine_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
other_machine_stacks = [s for s in machine_stacks if s.getId() != machine_id]
if other_machine_stacks:
Application.getInstance().setGlobalContainerStack(other_machine_stacks[0])
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id)
for container in containers:
ContainerRegistry.getInstance().removeContainer(container.getId())
ContainerRegistry.getInstance().removeContainer(machine_id)
if activate_new_machine:
stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
if stacks:
Application.getInstance().setGlobalContainerStack(stacks[0])
@pyqtProperty(bool, notify = globalContainerChanged)
def hasMaterials(self) -> bool:
if self._global_container_stack:

View File

@ -1,4 +1,4 @@
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
@ -35,7 +35,7 @@ class SettingInheritanceManager(QObject):
## Get the keys of all children settings with an override.
@pyqtSlot(str, result = "QStringList")
def getChildrenKeysWithOverride(self, key):
definitions = self._global_container_stack.getBottom().findDefinitions(key=key)
definitions = self._global_container_stack.definition.findDefinitions(key=key)
if not definitions:
Logger.log("w", "Could not find definition for key [%s]", key)
return []
@ -55,7 +55,7 @@ class SettingInheritanceManager(QObject):
Logger.log("w", "Unable to find extruder for current machine with index %s", extruder_index)
return []
definitions = self._global_container_stack.getBottom().findDefinitions(key=key)
definitions = self._global_container_stack.definition.findDefinitions(key=key)
if not definitions:
Logger.log("w", "Could not find definition for key [%s] (2)", key)
return []
@ -93,7 +93,7 @@ class SettingInheritanceManager(QObject):
def _onPropertyChanged(self, key, property_name):
if (property_name == "value" or property_name == "enabled") and self._global_container_stack:
definitions = self._global_container_stack.getBottom().findDefinitions(key = key)
definitions = self._global_container_stack.definition.findDefinitions(key = key)
if not definitions:
return
@ -198,6 +198,10 @@ class SettingInheritanceManager(QObject):
def _update(self):
self._settings_with_inheritance_warning = [] # Reset previous data.
# Make sure that the GlobalStack is not None. sometimes the globalContainerChanged signal gets here late.
if self._global_container_stack is None:
return
# Check all setting keys that we know of and see if they are overridden.
for setting_key in self._global_container_stack.getAllKeys():
override = self._settingIsOverwritingInheritance(setting_key)
@ -205,7 +209,7 @@ class SettingInheritanceManager(QObject):
self._settings_with_inheritance_warning.append(setting_key)
# Check all the categories if any of their children have their inheritance overwritten.
for category in self._global_container_stack.getBottom().findDefinitions(type = "category"):
for category in self._global_container_stack.definition.findDefinitions(type = "category"):
if self._recursiveCheck(category):
self._settings_with_inheritance_warning.append(category.key)

View File

@ -3,6 +3,7 @@ from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
## A decorator that stores the amount an object has been moved below the platform.
class ZOffsetDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
self._z_offset = 0
def setZOffset(self, offset):

View File

@ -312,31 +312,20 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
return WorkspaceReader.PreReadResult.accepted
## Overrides an ExtruderStack in the given GlobalStack and returns the new ExtruderStack.
def _overrideExtruderStack(self, global_stack, extruder_index, extruder_file_content):
extruder_stack = global_stack.extruders[extruder_index]
machine_extruder_count = len(global_stack.extruders)
def _overrideExtruderStack(self, global_stack, extruder_file_content):
# get extruder position first
extruder_config = configparser.ConfigParser()
extruder_config.read_string(extruder_file_content)
if not extruder_config.has_option("metadata", "position"):
msg = "Could not find 'metadata/position' in extruder stack file"
Logger.log("e", "Could not find 'metadata/position' in extruder stack file")
raise RuntimeError(msg)
extruder_position = extruder_config.get("metadata", "position")
old_extruder_stack_id = extruder_stack.getId()
# HACK: There are two cases:
# - the new ExtruderStack has the same ID as the one we are overriding
# - they don't have the same ID
# In the second case, directly overriding the existing ExtruderStack will leave the old stack file
# in the Cura directory, and this will cause a problem when we restart Cura. So, we always delete
# the existing file first.
self._container_registry._deleteFiles(extruder_stack)
extruder_stack = global_stack.extruders[extruder_position]
# override the given extruder stack
extruder_stack.deserialize(extruder_file_content)
# HACK: The deserialize() of ExtruderStack will add itself to the GlobalStack, which is redundant here.
# So we need to remove the new entries in the GlobalStack.
global_stack._extruders = global_stack._extruders[:machine_extruder_count]
# HACK: clean and fill the container query cache again
if old_extruder_stack_id in self._container_registry._id_container_cache:
del self._container_registry._id_container_cache[old_extruder_stack_id]
new_extruder_stack_id = extruder_stack.getId()
self._container_registry._id_container_cache[new_extruder_stack_id] = extruder_stack
# return the new ExtruderStack
return extruder_stack
@ -393,12 +382,23 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
global_stack_id_original = self._stripFileToId(global_stack_file)
global_stack_id_new = global_stack_id_original
global_stack_need_rename = False
extruder_stack_id_map = {} # new and old ExtruderStack IDs map
if self._resolve_strategies["machine"] == "new":
# We need a new id if the id already exists
if self._container_registry.findContainerStacks(id = global_stack_id_original):
global_stack_id_new = self.getNewId(global_stack_id_original)
global_stack_need_rename = True
for each_extruder_stack_file in extruder_stack_files:
old_container_id = self._stripFileToId(each_extruder_stack_file)
new_container_id = old_container_id
if self._container_registry.findContainerStacks(id = old_container_id):
# get a new name for this extruder
new_container_id = self.getNewId(old_container_id)
extruder_stack_id_map[old_container_id] = new_container_id
# TODO: For the moment we use pretty naive existence checking. If the ID is the same, we assume in quite a few
# TODO: cases that the container loaded is the same (most notable in materials & definitions).
# TODO: It might be possible that we need to add smarter checking in the future.
@ -454,13 +454,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
container_id = self._stripFileToId(instance_container_file)
serialized = archive.open(instance_container_file).read().decode("utf-8")
# HACK! we ignore the "metadata/type = quality" instance containers!
# HACK! we ignore "quality" and "variant" instance containers!
parser = configparser.ConfigParser()
parser.read_string(serialized)
if not parser.has_option("metadata", "type"):
Logger.log("w", "Cannot find metadata/type in %s, ignoring it", instance_container_file)
continue
if parser.get("metadata", "type") == "quality":
if parser.get("metadata", "type") in self._ignored_instance_container_types:
continue
instance_container = InstanceContainer(container_id)
@ -470,6 +470,12 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
container_type = instance_container.getMetaDataEntry("type")
Job.yieldThread()
#
# IMPORTANT:
# If an instance container (or maybe other type of container) exists, and user chooses "Create New",
# we need to rename this container and all references to it, and changing those references are VERY
# HARD.
#
if container_type in self._ignored_instance_container_types:
# Ignore certain instance container types
Logger.log("w", "Ignoring instance container [%s] with type [%s]", container_id, container_type)
@ -486,9 +492,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
instance_container.setDirty(True)
elif self._resolve_strategies["machine"] == "new":
# The machine is going to get a spiffy new name, so ensure that the id's of user settings match.
extruder_id = instance_container.getMetaDataEntry("extruder", None)
if extruder_id:
new_extruder_id = self.getNewId(extruder_id)
old_extruder_id = instance_container.getMetaDataEntry("extruder", None)
if old_extruder_id:
new_extruder_id = extruder_stack_id_map[old_extruder_id]
new_id = new_extruder_id + "_current_settings"
instance_container._id = new_id
instance_container.setName(new_id)
@ -521,17 +527,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
elif self._resolve_strategies[container_type] == "new":
# TODO: how should we handle the case "new" for quality_changes and definition_changes?
instance_container.setName(self._container_registry.uniqueName(instance_container.getName()))
new_changes_container_id = self.getNewId(instance_container.getId())
instance_container._id = new_changes_container_id
instance_container.setName(new_changes_container_id)
# TODO: we don't know the following is correct or not, need to verify
# AND REFACTOR!!!
if self._resolve_strategies["machine"] == "new":
# The machine is going to get a spiffy new name, so ensure that the id's of user settings match.
extruder_id = instance_container.getMetaDataEntry("extruder", None)
if extruder_id:
new_extruder_id = self.getNewId(extruder_id)
old_extruder_id = instance_container.getMetaDataEntry("extruder", None)
if old_extruder_id:
new_extruder_id = extruder_stack_id_map[old_extruder_id]
instance_container.setMetaDataEntry("extruder", new_extruder_id)
machine_id = instance_container.getMetaDataEntry("machine", None)
@ -631,13 +637,26 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if self._resolve_strategies["machine"] == "override":
# NOTE: This is the same code as those in the lower part
# deserialize new extruder stack over the current ones
stack = self._overrideExtruderStack(global_stack, index, extruder_file_content)
stack = self._overrideExtruderStack(global_stack, extruder_file_content)
elif self._resolve_strategies["machine"] == "new":
# create a new extruder stack from this one
new_id = self.getNewId(container_id)
new_id = extruder_stack_id_map[container_id]
stack = ExtruderStack(new_id)
stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
# HACK: the global stack can have a new name, so we need to make sure that this extruder stack
# references to the new name instead of the old one. Normally, this can be done after
# deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize()
# also does addExtruder() to its machine stack, so we have to make sure that it's pointing
# to the right machine BEFORE deserialization.
extruder_config = configparser.ConfigParser()
extruder_config.read_string(extruder_file_content)
extruder_config.set("metadata", "machine", global_stack_id_new)
tmp_string_io = io.StringIO()
extruder_config.write(tmp_string_io)
extruder_file_content = tmp_string_io.getvalue()
stack.deserialize(extruder_file_content)
# Ensure a unique ID and name
stack._id = new_id
@ -649,22 +668,31 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# No extruder stack with the same ID can be found
if self._resolve_strategies["machine"] == "override":
# deserialize new extruder stack over the current ones
stack = self._overrideExtruderStack(global_stack, index, extruder_file_content)
stack = self._overrideExtruderStack(global_stack, extruder_file_content)
elif self._resolve_strategies["machine"] == "new":
# container not found, create a new one
stack = ExtruderStack(container_id)
stack.deserialize(archive.open(extruder_stack_file).read().decode("utf-8"))
# HACK: the global stack can have a new name, so we need to make sure that this extruder stack
# references to the new name instead of the old one. Normally, this can be done after
# deserialize() by setting the metadata, but in the case of ExtruderStack, deserialize()
# also does addExtruder() to its machine stack, so we have to make sure that it's pointing
# to the right machine BEFORE deserialization.
extruder_config = configparser.ConfigParser()
extruder_config.read_string(extruder_file_content)
extruder_config.set("metadata", "machine", global_stack_id_new)
tmp_string_io = io.StringIO()
extruder_config.write(tmp_string_io)
extruder_file_content = tmp_string_io.getvalue()
stack.deserialize(extruder_file_content)
self._container_registry.addContainer(stack)
extruder_stacks_added.append(stack)
containers_added.append(stack)
else:
Logger.log("w", "Unknown resolve strategy: %s" % str(self._resolve_strategies["machine"]))
if global_stack_need_rename:
if stack.getMetaDataEntry("machine"):
stack.setMetaDataEntry("machine", global_stack_id_new)
extruder_stacks.append(stack)
except:
Logger.logException("w", "We failed to serialize the stack. Trying to clean up.")
@ -700,13 +728,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if self._resolve_strategies[changes_container_type] == "new":
# Quality changes needs to get a new ID, added to registry and to the right stacks
for each_changes_container in quality_and_definition_changes_instance_containers:
old_id = each_changes_container.getId()
each_changes_container.setName(self._container_registry.uniqueName(each_changes_container.getName()))
# We're not really supposed to change the ID in normal cases, but this is an exception.
each_changes_container._id = self.getNewId(each_changes_container.getId())
# The container was not added yet, as it didn't have an unique ID. It does now, so add it.
self._container_registry.addContainer(each_changes_container)
# NOTE: The renaming and giving new IDs are possibly redundant because they are done in the
# instance container loading part.
new_id = each_changes_container.getId()
# Find the old (current) changes container in the global stack
if changes_container_type == "quality_changes":
@ -723,7 +747,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# Replace the quality/definition changes container if it's in the GlobalStack
# NOTE: we can get an empty container here, but the IDs will not match,
# so this comparison is fine.
if old_container.getId() == old_id:
if self._id_mapping.get(old_container.getId()) == new_id:
if changes_container_type == "quality_changes":
global_stack.qualityChanges = each_changes_container
elif changes_container_type == "definition_changes":
@ -746,7 +770,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# NOTE: we can get an empty container here, but the IDs will not match,
# so this comparison is fine.
if changes_container.getId() == old_id:
if self._id_mapping.get(changes_container.getId()) == new_id:
if changes_container_type == "quality_changes":
each_extruder_stack.qualityChanges = each_changes_container
elif changes_container_type == "definition_changes":

View File

@ -85,6 +85,7 @@ class GCodeWriter(MeshWriter):
for key in instance_container1.getAllKeys():
flat_container.setProperty(key, "value", instance_container1.getProperty(key, "value"))
return flat_container
@ -106,6 +107,9 @@ class GCodeWriter(MeshWriter):
return ""
flat_global_container = self._createFlattenedContainerInstance(stack.getTop(), container_with_profile)
# If the quality changes is not set, we need to set type manually
if flat_global_container.getMetaDataEntry("type", None) is None:
flat_global_container.addMetaDataEntry("type", "quality_changes")
# Ensure that quality_type is set. (Can happen if we have empty quality changes).
if flat_global_container.getMetaDataEntry("quality_type", None) is None:
@ -120,6 +124,9 @@ class GCodeWriter(MeshWriter):
Logger.log("w", "No extruder quality profile found, not writing quality for extruder %s to file!", extruder.getId())
continue
flat_extruder_quality = self._createFlattenedContainerInstance(extruder.getTop(), extruder_quality)
# If the quality changes is not set, we need to set type manually
if flat_extruder_quality.getMetaDataEntry("type", None) is None:
flat_extruder_quality.addMetaDataEntry("type", "quality_changes")
# Ensure that extruder is set. (Can happen if we have empty quality changes).
if flat_extruder_quality.getMetaDataEntry("extruder", None) is None:

View File

@ -341,7 +341,6 @@ Cura.MachineAction
sourceComponent: numericTextFieldWithUnit
property var propertyProvider: gantryHeightProvider
property string unit: catalog.i18nc("@label", "mm")
property bool forceUpdateOnChange: false
}
Item { width: UM.Theme.getSize("default_margin").width; height: UM.Theme.getSize("default_margin").height }
@ -385,7 +384,6 @@ Cura.MachineAction
sourceComponent: numericTextFieldWithUnit
property var propertyProvider: materialDiameterProvider
property string unit: catalog.i18nc("@label", "mm")
property bool forceUpdateOnChange: false
}
Label
{
@ -399,7 +397,6 @@ Cura.MachineAction
sourceComponent: numericTextFieldWithUnit
property var propertyProvider: machineNozzleSizeProvider
property string unit: catalog.i18nc("@label", "mm")
property bool forceUpdateOnChange: false
}
}
}
@ -550,7 +547,6 @@ Cura.MachineAction
sourceComponent: numericTextFieldWithUnit
property var propertyProvider: extruderNozzleSizeProvider
property string unit: catalog.i18nc("@label", "mm")
property bool forceUpdateOnChange: false
}
Label
@ -564,6 +560,7 @@ Cura.MachineAction
property var propertyProvider: extruderOffsetXProvider
property string unit: catalog.i18nc("@label", "mm")
property bool forceUpdateOnChange: true
property bool allowNegative: true
}
Label
{
@ -576,6 +573,7 @@ Cura.MachineAction
property var propertyProvider: extruderOffsetYProvider
property string unit: catalog.i18nc("@label", "mm")
property bool forceUpdateOnChange: true
property bool allowNegative: true
}
}
@ -655,17 +653,21 @@ Cura.MachineAction
Item {
height: textField.height
width: textField.width
property bool _allowNegative: (typeof(allowNegative) === 'undefined') ? false : allowNegative
property bool _forceUpdateOnChange: (typeof(forceUpdateOnChange) === 'undefined') ? false: forceUpdateOnChange
TextField
{
id: textField
text: (propertyProvider.properties.value) ? propertyProvider.properties.value : ""
validator: RegExpValidator { regExp: /[0-9\.]{0,6}/ }
validator: RegExpValidator { regExp: _allowNegative ? /-?[0-9\.]{0,6}/ : /[0-9\.]{0,6}/ }
onEditingFinished:
{
if (propertyProvider && text != propertyProvider.properties.value)
{
propertyProvider.setPropertyValue("value", text);
if(forceUpdateOnChange)
if(_forceUpdateOnChange)
{
var extruderIndex = ExtruderManager.activeExtruderIndex;
manager.forceUpdate();

View File

@ -12,7 +12,6 @@ Cura.MachineAction
anchors.fill: parent;
property var selectedPrinter: null
property bool completeProperties: true
property var connectingToPrinter: null
Connections
{
@ -33,9 +32,8 @@ Cura.MachineAction
if(base.selectedPrinter && base.completeProperties)
{
var printerKey = base.selectedPrinter.getKey()
if(connectingToPrinter != printerKey) {
// prevent an infinite loop
connectingToPrinter = printerKey;
if(manager.getStoredKey() != printerKey)
{
manager.setKey(printerKey);
completed();
}

View File

@ -70,8 +70,8 @@ _printer_translations_profiles = {
# as a set for which profiles were built-in.
_profile_translations = {
"Low Quality": "low",
"Fine": "normal",
"Extra Fine": "high",
"Normal Quality": "normal",
"High Quality": "high",
"Ulti Quality": "high", #This one doesn't have an equivalent. Map it to high.
"abs_0.25_normal": "um2p_abs_0.25_normal",
"abs_0.4_fast": "um2p_abs_0.4_fast",

View File

@ -25,6 +25,7 @@ def getMetaData():
("quality_changes", 2000000): ("quality_changes", 2000001, upgrade.upgradeInstanceContainer),
("user", 2000000): ("user", 2000001, upgrade.upgradeInstanceContainer),
("quality", 2000000): ("quality", 2000001, upgrade.upgradeInstanceContainer),
("definition_changes", 2000000): ("definition_changes", 2000001, upgrade.upgradeInstanceContainer),
},
"sources": {
"quality_changes": {
@ -39,6 +40,10 @@ def getMetaData():
"get_version": upgrade.getCfgVersion,
"location": {"./user"}
},
"definition_changes": {
"get_version": upgrade.getCfgVersion,
"location": {"./machine_instances"}
}
}
}

View File

@ -14,9 +14,13 @@ from cura.CuraApplication import CuraApplication
import UM.Dictionary
from UM.Settings.InstanceContainer import InstanceContainer, InvalidInstanceError
from UM.Settings.ContainerRegistry import ContainerRegistry
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
## Handles serializing and deserializing material containers from an XML file
class XmlMaterialProfile(InstanceContainer):
Version = 1
def __init__(self, container_id, *args, **kwargs):
super().__init__(container_id, *args, **kwargs)
self._inherited_files = []
@ -386,11 +390,13 @@ class XmlMaterialProfile(InstanceContainer):
self._path = ""
def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]:
return "material"
return "materials"
def getVersionFromSerialized(self, serialized: str) -> Optional[int]:
version = None
data = ET.fromstring(serialized)
# get format version
version = None
metadata = data.iterfind("./um:metadata/*", self.__namespaces)
for entry in metadata:
tag_name = _tag_without_namespace(entry)
@ -402,14 +408,29 @@ class XmlMaterialProfile(InstanceContainer):
break
if version is None:
raise InvalidInstanceError("Missing version in metadata")
return version
# get setting version
if "version" in data.attrib:
setting_version = self.xmlVersionToSettingVersion(data.attrib["version"])
else:
setting_version = self.xmlVersionToSettingVersion("1.2")
if version is None:
raise InvalidInstanceError("Missing version in metadata")
return version * 1000000 + setting_version
## Overridden from InstanceContainer
def deserialize(self, serialized):
# update the serialized data first
from UM.Settings.Interfaces import ContainerInterface
serialized = ContainerInterface.deserialize(self, serialized)
try:
data = ET.fromstring(serialized)
except:
Logger.logException("e", "An exception occured while parsing the material profile")
return
# Reset previous metadata
self.clearData() # Ensure any previous data is gone.
@ -544,7 +565,7 @@ class XmlMaterialProfile(InstanceContainer):
variant_containers = ContainerRegistry.getInstance().findInstanceContainers(definition = definition.id, name = hotend_id)
if not variant_containers:
Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id)
#Logger.log("d", "No variants found with ID or name %s for machine %s", hotend_id, definition.id)
continue
hotend_compatibility = machine_compatibility

View File

@ -0,0 +1,62 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import xml.etree.ElementTree as ET
from UM.VersionUpgrade import VersionUpgrade
class XmlMaterialUpgrader(VersionUpgrade):
def getXmlVersion(self, serialized):
data = ET.fromstring(serialized)
# get format version
version = None
metadata = data.iterfind("./um:metadata/*")
for entry in metadata:
tag_name = entry.tag
if tag_name == "version":
try:
version = int(entry.text)
except Exception as e:
raise ValueError("Invalid version string '%s': %s" % (entry.text, e))
break
if version is None:
raise RuntimeError("Missing version in metadata")
# get setting version
if "version" in data.attrib:
setting_version = self._xmlVersionToSettingVersion(data.attrib["version"])
else:
setting_version = self._xmlVersionToSettingVersion("1.2")
if version is None:
raise RuntimeError("Missing version in metadata")
return version * 1000000 + setting_version
def _xmlVersionToSettingVersion(self, xml_version: str) -> int:
if xml_version == "1.3":
return 1
return 0 #Older than 1.3.
def upgradeMaterial(self, serialised, filename):
data = ET.fromstring(serialised)
# update version
metadata = data.iterfind("./um:metadata/*", {"um": "http://www.ultimaker.com/material"})
for entry in metadata:
if _tag_without_namespace(entry) == "version":
entry.text = "2"
break
data.attrib["version"] = "1.3"
# this makes sure that the XML header states encoding="utf-8"
new_serialised = ET.tostring(data, encoding="utf-8").decode("utf-8")
return [filename], [new_serialised]
def _tag_without_namespace(element):
return element.tag[element.tag.rfind("}") + 1:]

View File

@ -1,11 +1,16 @@
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from . import XmlMaterialProfile
from . import XmlMaterialUpgrader
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
upgrader = XmlMaterialUpgrader.XmlMaterialUpgrader()
def getMetaData():
return {
@ -19,15 +24,36 @@ def getMetaData():
"settings_container": {
"type": "material",
"mimetype": "application/x-ultimaker-material-profile"
},
"version_upgrade": {
("materials", 1000000): ("materials", 1000001, upgrader.upgradeMaterial),
},
"sources": {
"materials": {
"get_version": upgrader.getXmlVersion,
"location": {"./materials"}
},
}
}
def register(app):
# add Mime type
mime_type = MimeType(
name = "application/x-ultimaker-material-profile",
comment = "Ultimaker Material Profile",
suffixes = [ "xml.fdm_material" ]
)
MimeTypeDatabase.addMimeType(mime_type)
return { "settings_container": XmlMaterialProfile.XmlMaterialProfile("default_xml_material_profile") }
# add upgrade version
from cura.CuraApplication import CuraApplication
from UM.VersionUpgradeManager import VersionUpgradeManager
VersionUpgradeManager.getInstance().registerCurrentVersion(
("materials", XmlMaterialProfile.XmlMaterialProfile.Version * 1000000 + CuraApplication.SettingVersion),
(CuraApplication.ResourceTypes.MaterialInstanceContainer, "application/x-uranium-instancecontainer")
)
return {"version_upgrade": upgrader,
"settings_container": XmlMaterialProfile.XmlMaterialProfile("default_xml_material_profile"),
}

View File

@ -19,7 +19,7 @@
"variants_name": "Nozzle size",
"preferred_variant": "*0.8*",
"preferred_material": "*pla*",
"preferred_quality": "*high*",
"preferred_quality": "*normal*",
"machine_extruder_trains":
{
@ -29,7 +29,7 @@
"3": "cartesio_extruder_3"
},
"platform": "cartesio_platform.stl",
"platform_offset": [ -120, -1.5, 130],
"platform_offset": [ -220, -5, 150],
"first_start_actions": ["MachineSettingsAction"],
"supported_actions": ["MachineSettingsAction"]
},

View File

@ -778,7 +778,7 @@
"type": "float",
"enabled": "support_enable and support_roof_enable",
"limit_to_extruder": "support_roof_extruder_nr",
"value": "support_interface_line_width",
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_line_width')",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -794,7 +794,7 @@
"type": "float",
"enabled": "support_enable and support_bottom_enable",
"limit_to_extruder": "support_bottom_extruder_nr",
"value": "support_interface_line_width",
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_line_width')",
"settable_per_mesh": false,
"settable_per_extruder": true
}
@ -2072,7 +2072,7 @@
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150",
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "support_interface_enable and support_enable",
"limit_to_extruder": "support_interface_extruder_nr",
"value": "speed_support / 1.5",
"settable_per_mesh": false,
@ -2089,9 +2089,9 @@
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150",
"enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "support_roof_enable and support_enable",
"limit_to_extruder": "support_roof_extruder_nr",
"value": "speed_support_interface",
"value": "extruderValue(support_roof_extruder_nr, 'speed_support_interface')",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -2105,9 +2105,9 @@
"minimum_value": "0.1",
"maximum_value": "math.sqrt(machine_max_feedrate_x ** 2 + machine_max_feedrate_y ** 2)",
"maximum_value_warning": "150",
"enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "support_bottom_enable and support_enable",
"limit_to_extruder": "support_bottom_extruder_nr",
"value": "speed_support_interface",
"value": "extruderValue(support_bottom_extruder_nr, 'speed_support_interface')",
"settable_per_mesh": false,
"settable_per_extruder": true
}
@ -2399,7 +2399,7 @@
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "resolveOrValue('acceleration_enabled') and support_interface_enable and support_enable",
"limit_to_extruder": "support_interface_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -2412,11 +2412,11 @@
"unit": "mm/s²",
"type": "float",
"default_value": 3000,
"value": "acceleration_support_interface",
"value": "extruderValue(support_roof_extruder_nr, 'acceleration_support_interface')",
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "acceleration_enabled and support_roof_enable and support_enable",
"limit_to_extruder": "support_roof_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
@ -2428,11 +2428,11 @@
"unit": "mm/s²",
"type": "float",
"default_value": 3000,
"value": "acceleration_support_interface",
"value": "extruderValue(support_bottom_extruder_nr, 'acceleration_support_interface')",
"minimum_value": "0.1",
"minimum_value_warning": "100",
"maximum_value_warning": "10000",
"enabled": "resolveOrValue('acceleration_enabled') and extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "acceleration_enabled and support_bottom_enable and support_enable",
"limit_to_extruder": "support_bottom_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
@ -2669,7 +2669,7 @@
"value": "jerk_support",
"minimum_value": "0.1",
"maximum_value_warning": "50",
"enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "resolveOrValue('jerk_enabled') and support_interface_enable and support_enable",
"limit_to_extruder": "support_interface_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -2682,10 +2682,10 @@
"unit": "mm/s",
"type": "float",
"default_value": 20,
"value": "jerk_support_interface",
"value": "extruderValue(support_roof_extruder_nr, 'jerk_support_interface')",
"minimum_value": "0.1",
"maximum_value_warning": "50",
"enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "resolveOrValue('jerk_enabled') and support_roof_enable and support_enable",
"limit_to_extruder": "support_roof_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
@ -2697,10 +2697,10 @@
"unit": "mm/s",
"type": "float",
"default_value": 20,
"value": "jerk_support_interface",
"value": "extruderValue(support_roof_extruder_nr, 'jerk_support_interface')",
"minimum_value": "0.1",
"maximum_value_warning": "50",
"enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "resolveOrValue('jerk_enabled') and support_bottom_enable and support_enable",
"limit_to_extruder": "support_bottom_extruder_nr",
"settable_per_mesh": false,
"settable_per_extruder": true
@ -3285,7 +3285,7 @@
"default_value": 0.1,
"type": "float",
"enabled": "support_enable",
"value": "extruderValue(support_extruder_nr, 'support_z_distance')",
"value": "extruderValue(support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr, 'support_z_distance')",
"limit_to_extruder": "support_roof_extruder_nr if support_roof_enable else support_infill_extruder_nr",
"settable_per_mesh": true
},
@ -3297,7 +3297,7 @@
"minimum_value": "0",
"maximum_value_warning": "machine_nozzle_size",
"default_value": 0.1,
"value": "extruderValue(support_extruder_nr, 'support_z_distance') if resolveOrValue('support_type') == 'everywhere' else 0",
"value": "extruderValue(support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr, 'support_z_distance') if support_type == 'everywhere' else 0",
"limit_to_extruder": "support_bottom_extruder_nr if support_bottom_enable else support_infill_extruder_nr",
"type": "float",
"enabled": "support_enable and resolveOrValue('support_type') == 'everywhere'",
@ -3340,11 +3340,11 @@
"unit": "mm",
"type": "float",
"minimum_value": "0",
"maximum_value_warning": "extruderValue(support_infill_extruder_nr, 'support_xy_distance')",
"maximum_value_warning": "support_xy_distance",
"default_value": 0.2,
"value": "machine_nozzle_size / 2",
"limit_to_extruder": "support_infill_extruder_nr",
"enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_xy_overrides_z') == 'z_overrides_xy'",
"enabled": "support_enable and support_xy_overrides_z == 'z_overrides_xy'",
"settable_per_mesh": true
},
"support_bottom_stair_step_height":
@ -3416,7 +3416,7 @@
"description": "Generate a dense slab of material between the top of support and the model. This will create a skin between the model and support.",
"type": "bool",
"default_value": false,
"value": "support_interface_enable",
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_enable')",
"limit_to_extruder": "support_roof_extruder_nr",
"enabled": "support_enable",
"settable_per_mesh": true
@ -3427,7 +3427,7 @@
"description": "Generate a dense slab of material between the bottom of the support and the model. This will create a skin between the model and support.",
"type": "bool",
"default_value": false,
"value": "support_interface_enable",
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_enable')",
"limit_to_extruder": "support_bottom_extruder_nr",
"enabled": "support_enable",
"settable_per_mesh": true
@ -3442,10 +3442,10 @@
"type": "float",
"default_value": 1,
"minimum_value": "0",
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
"minimum_value_warning": "0.2 + layer_height",
"maximum_value_warning": "10",
"limit_to_extruder": "support_interface_extruder_nr",
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "support_interface_enable and support_enable",
"settable_per_mesh": true,
"children":
{
@ -3457,11 +3457,11 @@
"type": "float",
"default_value": 1,
"minimum_value": "0",
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
"minimum_value_warning": "0.2 + layer_height",
"maximum_value_warning": "10",
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_height')",
"limit_to_extruder": "support_roof_extruder_nr",
"enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "support_roof_enable and support_enable",
"settable_per_mesh": true
},
"support_bottom_height":
@ -3473,10 +3473,10 @@
"default_value": 1,
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_height')",
"minimum_value": "0",
"minimum_value_warning": "min(0.2 + resolveOrValue('layer_height'), extruderValue(support_bottom_extruder_nr, 'support_bottom_stair_step_height'))",
"minimum_value_warning": "min(0.2 + layer_height, support_bottom_stair_step_height)",
"maximum_value_warning": "10",
"limit_to_extruder": "support_bottom_extruder_nr",
"enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "support_bottom_enable and support_enable",
"settable_per_mesh": true
}
}
@ -3490,7 +3490,7 @@
"minimum_value": "0",
"maximum_value_warning": "support_interface_height",
"limit_to_extruder": "support_interface_extruder_nr",
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "support_interface_enable and support_enable",
"settable_per_mesh": true
},
"support_interface_density":
@ -3503,7 +3503,7 @@
"minimum_value": "0",
"maximum_value_warning": "100",
"limit_to_extruder": "support_interface_extruder_nr",
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "support_interface_enable and support_enable",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children":
@ -3518,7 +3518,8 @@
"minimum_value": "0",
"maximum_value": "100",
"limit_to_extruder": "support_roof_extruder_nr",
"enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "support_roof_enable and support_enable",
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_density')",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children":
@ -3534,7 +3535,7 @@
"minimum_value_warning": "support_roof_line_width - 0.0001",
"value": "0 if support_roof_density == 0 else (support_roof_line_width * 100) / support_roof_density * (2 if support_roof_pattern == 'grid' else (3 if support_roof_pattern == 'triangles' else 1))",
"limit_to_extruder": "support_roof_extruder_nr",
"enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "support_roof_enable and support_enable",
"settable_per_mesh": false,
"settable_per_extruder": true
}
@ -3550,7 +3551,8 @@
"minimum_value": "0",
"maximum_value": "100",
"limit_to_extruder": "support_bottom_extruder_nr",
"enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "support_bottom_enable and support_enable",
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_density')",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children":
@ -3566,7 +3568,7 @@
"minimum_value_warning": "support_bottom_line_width - 0.0001",
"value": "0 if support_bottom_density == 0 else (support_bottom_line_width * 100) / support_bottom_density * (2 if support_bottom_pattern == 'grid' else (3 if support_bottom_pattern == 'triangles' else 1))",
"limit_to_extruder": "support_bottom_extruder_nr",
"enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "support_bottom_enable and support_enable",
"settable_per_mesh": false,
"settable_per_extruder": true
}
@ -3590,7 +3592,7 @@
},
"default_value": "concentric",
"limit_to_extruder": "support_interface_extruder_nr",
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
"enabled": "support_interface_enable and support_enable",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children":
@ -3610,9 +3612,9 @@
"zigzag": "Zig Zag"
},
"default_value": "concentric",
"value": "support_interface_pattern",
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_pattern')",
"limit_to_extruder": "support_roof_extruder_nr",
"enabled": "extruderValue(support_roof_extruder_nr, 'support_roof_enable') and support_enable",
"enabled": "support_roof_enable and support_enable",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -3631,9 +3633,9 @@
"zigzag": "Zig Zag"
},
"default_value": "concentric",
"value": "support_interface_pattern",
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_pattern')",
"limit_to_extruder": "support_bottom_extruder_nr",
"enabled": "extruderValue(support_bottom_extruder_nr, 'support_bottom_enable') and support_enable",
"enabled": "support_bottom_enable and support_enable",
"settable_per_mesh": false,
"settable_per_extruder": true
}
@ -3660,7 +3662,7 @@
"minimum_value": "0",
"minimum_value_warning": "2 * machine_nozzle_size",
"maximum_value_warning": "20",
"enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_use_towers')",
"enabled": "support_enable and support_use_towers",
"settable_per_mesh": true
},
"support_minimal_diameter":
@ -3674,8 +3676,8 @@
"minimum_value": "0",
"minimum_value_warning": "2 * machine_nozzle_size",
"maximum_value_warning": "20",
"maximum_value": "extruderValue(support_infill_extruder_nr, 'support_tower_diameter')",
"enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_use_towers')",
"maximum_value": "support_tower_diameter",
"enabled": "support_enable and support_use_towers",
"settable_per_mesh": true
},
"support_tower_roof_angle":
@ -3688,7 +3690,7 @@
"maximum_value": "90",
"default_value": 65,
"limit_to_extruder": "support_infill_extruder_nr",
"enabled": "support_enable and extruderValue(support_infill_extruder_nr, 'support_use_towers')",
"enabled": "support_enable and support_use_towers",
"settable_per_mesh": true
}
}
@ -3914,7 +3916,7 @@
"value": "resolveOrValue('layer_height')",
"minimum_value": "0.001",
"minimum_value_warning": "0.04",
"maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'machine_nozzle_size')",
"maximum_value_warning": "0.75 * machine_nozzle_size",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -3929,8 +3931,8 @@
"default_value": 0.4,
"value": "line_width",
"minimum_value": "0.001",
"minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 0.1",
"maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 2",
"minimum_value_warning": "machine_nozzle_size * 0.1",
"maximum_value_warning": "machine_nozzle_size * 2",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -3944,8 +3946,8 @@
"type": "float",
"default_value": 0.4,
"minimum_value": "0",
"minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_surface_line_width')",
"maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_surface_line_width') * 3",
"minimum_value_warning": "raft_surface_line_width",
"maximum_value_warning": "raft_surface_line_width * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"value": "raft_surface_line_width",
"settable_per_mesh": false,
@ -3962,7 +3964,7 @@
"value": "resolveOrValue('layer_height') * 1.5",
"minimum_value": "0.001",
"minimum_value_warning": "0.04",
"maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'machine_nozzle_size')",
"maximum_value_warning": "0.75 * machine_nozzle_size",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -3977,8 +3979,8 @@
"default_value": 0.7,
"value": "line_width * 2",
"minimum_value": "0.001",
"minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 0.5",
"maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 3",
"minimum_value_warning": "machine_nozzle_size * 0.5",
"maximum_value_warning": "machine_nozzle_size * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -3993,7 +3995,7 @@
"default_value": 0.9,
"value": "raft_interface_line_width + 0.2",
"minimum_value": "0",
"minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_interface_line_width')",
"minimum_value_warning": "raft_interface_line_width",
"maximum_value_warning": "15.0",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
@ -4010,7 +4012,7 @@
"value": "resolveOrValue('layer_height_0') * 1.2",
"minimum_value": "0.001",
"minimum_value_warning": "0.04",
"maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'raft_base_line_width')",
"maximum_value_warning": "0.75 * raft_base_line_width",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -4024,9 +4026,9 @@
"type": "float",
"default_value": 0.8,
"minimum_value": "0.001",
"value": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 2",
"minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 0.5",
"maximum_value_warning": "extruderValue(adhesion_extruder_nr, 'machine_nozzle_size') * 3",
"value": "machine_nozzle_size * 2",
"minimum_value_warning": "machine_nozzle_size * 0.5",
"maximum_value_warning": "machine_nozzle_size * 3",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
"settable_per_extruder": true,
@ -4041,7 +4043,7 @@
"default_value": 1.6,
"value": "raft_base_line_width * 2",
"minimum_value": "0",
"minimum_value_warning": "extruderValue(adhesion_extruder_nr, 'raft_base_line_width')",
"minimum_value_warning": "raft_base_line_width",
"maximum_value_warning": "100",
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
"settable_per_mesh": false,
@ -4634,6 +4636,18 @@
"settable_per_mesh": true,
"enabled": "mold_enabled"
},
"mold_roof_height":
{
"label": "Mold Roof Height",
"description": "The height above horizontal parts in your model which to print mold.",
"unit": "mm",
"type": "float",
"minimum_value": "0",
"maximum_value_warning": "5",
"default_value": 0.5,
"settable_per_mesh": true,
"enabled": "mold_enabled"
},
"mold_angle":
{
"label": "Mold Angle",

View File

@ -17,7 +17,7 @@ SettingItem
id: control
anchors.fill: parent
model: Cura.ExtrudersModel { }
model: Cura.ExtrudersModel { onModelChanged: control.color = getItem(control.currentIndex).color }
textRole: "name"
@ -36,6 +36,17 @@ SettingItem
onWheel: wheel.accepted = true;
}
property string color: "#fff"
Binding
{
// We override the color property's value when the ExtruderModel changes. So we need to use an
// explicit binding here otherwise we do not handle value changes after the model changes.
target: control
property: "color"
value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : ""
}
style: ComboBoxStyle
{
background: Rectangle
@ -83,7 +94,7 @@ SettingItem
border.width: UM.Theme.getSize("default_lining").width
border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border")
color: control.currentText != "" ? control.model.getItem(control.currentIndex).color : ""
color: control.color
}
Label
{

View File

@ -0,0 +1,153 @@
// Copyright (c) 2016 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import UM 1.1 as UM
import Cura 1.0 as Cura
SettingItem
{
id: base
contents: ComboBox
{
id: control
anchors.fill: parent
model: Cura.ExtrudersModel
{
onModelChanged: control.color = getItem(control.currentIndex).color
useOptionalExtruder: true
}
textRole: "name"
onActivated:
{
forceActiveFocus();
propertyProvider.setPropertyValue("value", model.getItem(index).index);
}
Binding
{
target: control
property: "currentIndex"
value:
{
if(propertyProvider.properties.value == -1)
{
return control.model.items.length - 1
}
return propertyProvider.properties.value
}
// Sometimes when the value is already changed, the model is still being built.
// The when clause ensures that the current index is not updated when this happens.
when: control.model.items.length > 0
}
MouseArea
{
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: wheel.accepted = true;
}
property string color: "#fff"
Binding
{
// We override the color property's value when the ExtruderModel changes. So we need to use an
// explicit binding here otherwise we do not handle value changes after the model changes.
target: control
property: "color"
value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : ""
}
style: ComboBoxStyle
{
background: Rectangle
{
color:
{
if (!enabled)
{
return UM.Theme.getColor("setting_control_disabled");
}
if(control.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_control_highlight");
}
else
{
return UM.Theme.getColor("setting_control");
}
}
border.width: UM.Theme.getSize("default_lining").width
border.color:
{
if(!enabled)
{
return UM.Theme.getColor("setting_control_disabled_border");
}
if(control.hovered || base.activeFocus)
{
UM.Theme.getColor("setting_control_border_highlight")
}
return UM.Theme.getColor("setting_control_border")
}
}
label: Item
{
Rectangle
{
id: swatch
height: UM.Theme.getSize("setting_control").height / 2
width: height
anchors.verticalCenter: parent.verticalCenter
border.width: UM.Theme.getSize("default_lining").width
border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border")
color: control.color
}
Label
{
anchors
{
left: swatch.right;
right: arrow.left;
verticalCenter: parent.verticalCenter
margins: UM.Theme.getSize("default_lining").width
}
width: parent.width - swatch.width;
text: control.currentText
font: UM.Theme.getFont("default")
color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
UM.RecolorImage
{
id: arrow
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getIcon("arrow_bottom")
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
sourceSize.width: width + 5
sourceSize.height: width + 5
color: UM.Theme.getColor("setting_control_text")
}
}
}
}
}

View File

@ -195,7 +195,7 @@ Item
//Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989
//In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes,
//causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely.
asynchronous: model.type != "enum" && model.type != "extruder"
asynchronous: model.type != "enum" && model.type != "extruder" && model.type != "optional_extruder"
active: model.type != undefined
source:
@ -218,6 +218,8 @@ Item
return "SettingTextField.qml"
case "category":
return "SettingCategory.qml"
case "optional_extruder":
return "SettingOptionalExtruder.qml"
default:
return "SettingUnknown.qml"
}

View File

@ -45,6 +45,5 @@ speed_wall = =math.ceil(speed_print * 50 / 50)
speed_wall_0 = =math.ceil(speed_wall * 40 / 50)
support_bottom_distance = =support_z_distance
support_z_distance = =layer_height
travel_avoid_distance = 3
wall_0_inset = 0
wall_thickness = 1

View File

@ -45,5 +45,4 @@ speed_wall = =math.ceil(speed_print * 45 / 45)
speed_wall_0 = =math.ceil(speed_wall * 35 / 45)
support_bottom_distance = =support_z_distance
support_z_distance = =layer_height
travel_avoid_distance = 3
wall_0_inset = 0

View File

@ -47,5 +47,4 @@ speed_wall = =math.ceil(speed_print * 35 / 40)
speed_wall_0 = =math.ceil(speed_wall * 30 / 35)
support_bottom_distance = =support_z_distance
support_z_distance = =layer_height
travel_avoid_distance = 3
wall_0_inset = 0

View File

@ -46,5 +46,4 @@ speed_wall = =math.ceil(speed_print * 35 / 40)
speed_wall_0 = =math.ceil(speed_wall * 30 / 35)
support_bottom_distance = =support_z_distance
support_z_distance = =layer_height
travel_avoid_distance = 3
wall_0_inset = 0

View File

@ -59,7 +59,6 @@ support_interface_pattern = lines
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
wall_thickness = 1.2

View File

@ -58,7 +58,6 @@ support_interface_pattern = lines
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
wall_thickness = 1.2

View File

@ -59,7 +59,6 @@ support_interface_pattern = lines
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
wall_thickness = 1.2

View File

@ -56,7 +56,6 @@ support_interface_pattern = lines
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
wall_thickness = 1.2

View File

@ -44,7 +44,7 @@ retraction_count_max = 12
retraction_extra_prime_amount = 0.8
retraction_extrusion_window = 1
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_enabled = False
retraction_hop_only_when_collides = True
retraction_min_travel = 0.8
retraction_prime_speed = 15
@ -56,11 +56,12 @@ speed_travel = 300
speed_wall = =math.ceil(speed_print * 25 / 25)
speed_wall_0 = =math.ceil(speed_wall * 25 / 25)
support_angle = 50
skin_overlap = 5
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
top_bottom_thickness = 0.7
travel_avoid_distance = 3
travel_avoid_distance = 0.5
wall_0_inset = 0
wall_line_width_x = =line_width
wall_thickness = 0.76

View File

@ -45,10 +45,11 @@ retraction_count_max = 12
retraction_extra_prime_amount = 0.8
retraction_extrusion_window = 1
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_enabled = False
retraction_hop_only_when_collides = True
retraction_min_travel = 0.8
retraction_prime_speed = 15
skin_overlap = 5
speed_equalize_flow_enabled = True
speed_layer_0 = 18
speed_print = 25
@ -61,7 +62,7 @@ switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
top_bottom_thickness = 0.7
travel_avoid_distance = 3
travel_avoid_distance = 0.5
wall_0_inset = 0
wall_line_width_x = =line_width
wall_thickness = 0.76

View File

@ -42,10 +42,11 @@ retraction_count_max = 12
retraction_extra_prime_amount = 0.8
retraction_extrusion_window = 1
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_enabled = False
retraction_hop_only_when_collides = True
retraction_min_travel = 0.8
retraction_prime_speed = 15
skin_overlap = 5
speed_equalize_flow_enabled = True
speed_layer_0 = 18
speed_print = 25
@ -58,7 +59,7 @@ switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 35
top_bottom_thickness = 0.7
travel_avoid_distance = 3
travel_avoid_distance = 0.5
wall_0_inset = 0
wall_line_width_x = =line_width
wall_thickness = 0.76

View File

@ -38,11 +38,11 @@ retract_at_layer_change = False
retraction_count_max = 12
retraction_extra_prime_amount = 0.5
retraction_hop = 0.5
retraction_hop_enabled = False
retraction_hop_only_when_collides = False
retraction_min_travel = 0.8
retraction_prime_speed = 15
skin_line_width = =round(line_width * 0.78 / 0.8, 2)
skin_overlap = 15
speed_print = 30
speed_topbottom = =math.ceil(speed_print * 25 / 30)
speed_travel = 300
@ -56,6 +56,7 @@ switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 45
top_bottom_thickness = 1.2
travel_avoid_distance = 0.5
travel_compensate_overlapping_walls_0_enabled = False
wall_0_wipe_dist = =line_width * 2
wall_line_width_x = =round(line_width * 0.6 / 0.8, 2)

View File

@ -39,11 +39,11 @@ retract_at_layer_change = False
retraction_count_max = 12
retraction_extra_prime_amount = 0.5
retraction_hop = 0.5
retraction_hop_enabled = False
retraction_hop_only_when_collides = False
retraction_min_travel = 0.8
retraction_prime_speed = 15
skin_line_width = =round(line_width * 0.78 / 0.8, 2)
skin_overlap = 15
speed_print = 30
speed_topbottom = =math.ceil(speed_print * 20 / 30)
speed_travel = 300
@ -57,6 +57,7 @@ switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 45
top_bottom_thickness = 1.2
travel_avoid_distance = 0.5
travel_compensate_overlapping_walls_0_enabled = False
wall_0_wipe_dist = =line_width * 2
wall_line_width_x = =round(line_width * 0.6 / 0.8, 2)

View File

@ -38,11 +38,11 @@ retract_at_layer_change = False
retraction_count_max = 12
retraction_extra_prime_amount = 0.5
retraction_hop = 0.5
retraction_hop_enabled = False
retraction_hop_only_when_collides = False
retraction_min_travel = 0.8
retraction_prime_speed = 15
skin_line_width = =round(line_width * 0.78 / 0.8, 2)
skin_overlap = 15
speed_print = 30
speed_topbottom = =math.ceil(speed_print * 23 / 30)
speed_travel = 300
@ -56,6 +56,7 @@ switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 20
switch_extruder_retraction_speeds = 45
top_bottom_thickness = 1.2
travel_avoid_distance = 0.5
travel_compensate_overlapping_walls_0_enabled = False
wall_0_wipe_dist = =line_width * 2
wall_line_width_x = =round(line_width * 0.6 / 0.8, 2)

View File

@ -4,7 +4,7 @@ name = Extra Fine
definition = ultimaker3
[metadata]
weight = 0
weight = 1
type = quality
quality_type = high
material = generic_pva_ultimaker3_BB_0.4

View File

@ -1,6 +1,6 @@
[general]
version = 2
name = Draft Quality
name = Fast
definition = ultimaker3
[metadata]

View File

@ -1,6 +1,6 @@
[general]
version = 2
name = Fast Quality
name = Normal
definition = ultimaker3
[metadata]

View File

@ -1,6 +1,6 @@
[general]
version = 2
name = Superdraft Quality
name = Sprint
definition = ultimaker3
[metadata]

View File

@ -1,6 +1,6 @@
[general]
version = 2
name = Verydraft Quality
name = Extra Fast
definition = ultimaker3
[metadata]

View File

@ -0,0 +1,13 @@
[general]
name = 0.25 mm
version = 2
definition = ultimaker2_extended
[metadata]
author = Ultimaker
type = variant
setting_version = 1
[values]
machine_nozzle_size = 0.25
machine_nozzle_tip_outer_diameter = 0.8

View File

@ -0,0 +1,13 @@
[general]
name = 0.4 mm
version = 2
definition = ultimaker2_extended
[metadata]
author = Ultimaker
type = variant
setting_version = 1
[values]
machine_nozzle_size = 0.4
machine_nozzle_tip_outer_diameter = 1.05

View File

@ -0,0 +1,13 @@
[general]
name = 0.6 mm
version = 2
definition = ultimaker2_extended
[metadata]
author = Ultimaker
type = variant
setting_version = 1
[values]
machine_nozzle_size = 0.6
machine_nozzle_tip_outer_diameter = 1.25

View File

@ -0,0 +1,13 @@
[general]
name = 0.8 mm
version = 2
definition = ultimaker2_extended
[metadata]
author = Ultimaker
type = variant
setting_version = 1
[values]
machine_nozzle_size = 0.8
machine_nozzle_tip_outer_diameter = 1.35

View File

@ -60,7 +60,6 @@ support_z_distance = =layer_height * 2
switch_extruder_prime_speed = 20
switch_extruder_retraction_amount = 16.5
top_bottom_thickness = 1.4
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =wall_line_width
wall_thickness = 2

View File

@ -81,7 +81,6 @@ support_z_distance = 0
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 12
top_bottom_thickness = 1
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =wall_line_width
wall_thickness = 1

View File

@ -60,7 +60,6 @@ support_z_distance = =layer_height * 2
switch_extruder_prime_speed = 20
switch_extruder_retraction_amount = 16.5
top_bottom_thickness = 1.4
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =wall_line_width
wall_thickness = 2

View File

@ -81,7 +81,6 @@ support_z_distance = 0
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 12
top_bottom_thickness = 1
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =wall_line_width
wall_thickness = 1

View File

@ -250,7 +250,8 @@ def test_getPropertyFallThrough(extruder_stack):
container_indices = cura.Settings.CuraContainerStack._ContainerIndexes #Cache.
for type_id, type_name in container_indices.IndexTypeMap.items():
container = unittest.mock.MagicMock()
container.getProperty = lambda key, property, type_id = type_id: type_id if (key == "layer_height" and property == "value") else None #Returns the container type ID as layer height, in order to identify it.
# Return type_id when asking for value and -1 when asking for limit_to_extruder
container.getProperty = lambda key, property, type_id = type_id: type_id if (key == "layer_height" and property == "value") else (None if property != "limit_to_extruder" else "-1") #Returns the container type ID as layer height, in order to identify it.
container.hasProperty = lambda key, property: key == "layer_height"
container.getMetaDataEntry = unittest.mock.MagicMock(return_value = type_name)
mock_layer_heights[type_id] = container

View File

@ -69,11 +69,13 @@ def test_addExtruder(global_stack):
assert len(global_stack.extruders) == 0
first_extruder = unittest.mock.MagicMock()
first_extruder.getMetaDataEntry = lambda key: 0 if key == "position" else None
with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock):
global_stack.addExtruder(first_extruder)
assert len(global_stack.extruders) == 1
assert global_stack.extruders[0] == first_extruder
second_extruder = unittest.mock.MagicMock()
second_extruder.getMetaDataEntry = lambda key: 1 if key == "position" else None
with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock):
global_stack.addExtruder(second_extruder)
assert len(global_stack.extruders) == 2
@ -350,7 +352,7 @@ def test_getPropertyResolveInInstance(global_stack):
instance_containers = {}
for container_type in container_indices.IndexTypeMap:
instance_containers[container_type] = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature.
instance_containers[container_type].getProperty = lambda key, property: (7.5 if property == "resolve" else (InstanceState.User if property == "state" else 5)) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value.
instance_containers[container_type].getProperty = lambda key, property: (7.5 if property == "resolve" else (InstanceState.User if property == "state" else (5 if property != "limit_to_extruder" else "-1"))) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value.
instance_containers[container_type].getMetaDataEntry = unittest.mock.MagicMock(return_value = container_indices.IndexTypeMap[container_type]) #Make queries for the type return the desired type.
instance_containers[container_indices.Definition].getProperty = lambda key, property: 10 if (key == "material_bed_temperature" and property == "value") else None #Definition only has value.
with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
@ -374,7 +376,7 @@ def test_getPropertyResolveInInstance(global_stack):
# definitions.
def test_getPropertyInstancesBeforeResolve(global_stack):
value = unittest.mock.MagicMock() #Sets just the value.
value.getProperty = lambda key, property: (10 if property == "value" else InstanceState.User) if key == "material_bed_temperature" else None
value.getProperty = lambda key, property: (10 if property == "value" else (InstanceState.User if property != "limit_to_extruder" else "-1")) if key == "material_bed_temperature" else None
value.getMetaDataEntry = unittest.mock.MagicMock(return_value = "quality")
resolve = unittest.mock.MagicMock() #Sets just the resolve.
resolve.getProperty = lambda key, property: 7.5 if (key == "material_bed_temperature" and property == "resolve") else None