mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-13 01:37:51 -06:00
Merge pull request #3436 from Ultimaker/feature_enable_disable_extruder
CURA-4400 Feature enable disable extruder
This commit is contained in:
commit
8db4396ee7
22 changed files with 429 additions and 134 deletions
|
@ -111,6 +111,9 @@ class BuildVolume(SceneNode):
|
||||||
# but it does not update the disallowed areas after material change
|
# but it does not update the disallowed areas after material change
|
||||||
Application.getInstance().getMachineManager().activeStackChanged.connect(self._onStackChanged)
|
Application.getInstance().getMachineManager().activeStackChanged.connect(self._onStackChanged)
|
||||||
|
|
||||||
|
# Enable and disable extruder
|
||||||
|
Application.getInstance().getMachineManager().extruderChanged.connect(self.updateNodeBoundaryCheck)
|
||||||
|
|
||||||
# list of settings which were updated
|
# list of settings which were updated
|
||||||
self._changed_settings_since_last_rebuild = []
|
self._changed_settings_since_last_rebuild = []
|
||||||
|
|
||||||
|
@ -217,30 +220,26 @@ class BuildVolume(SceneNode):
|
||||||
group_nodes.append(node) # Keep list of affected group_nodes
|
group_nodes.append(node) # Keep list of affected group_nodes
|
||||||
|
|
||||||
if node.callDecoration("isSliceable") or node.callDecoration("isGroup"):
|
if node.callDecoration("isSliceable") or node.callDecoration("isGroup"):
|
||||||
node._outside_buildarea = False
|
if node.collidesWithBbox(build_volume_bounding_box):
|
||||||
bbox = node.getBoundingBox()
|
node.setOutsideBuildArea(True)
|
||||||
|
|
||||||
# Mark the node as outside the build volume if the bounding box test fails.
|
|
||||||
if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
|
||||||
node._outside_buildarea = True
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
convex_hull = node.callDecoration("getConvexHull")
|
if node.collidesWithArea(self.getDisallowedAreas()):
|
||||||
if convex_hull:
|
node.setOutsideBuildArea(True)
|
||||||
if not convex_hull.isValid():
|
continue
|
||||||
return
|
|
||||||
# Check for collisions between disallowed areas and the object
|
# Mark the node as outside build volume if the set extruder is disabled
|
||||||
for area in self.getDisallowedAreas():
|
extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||||
overlap = convex_hull.intersectsPolygon(area)
|
if not self._global_container_stack.extruders[extruder_position].isEnabled:
|
||||||
if overlap is None:
|
node.setOutsideBuildArea(True)
|
||||||
continue
|
continue
|
||||||
node._outside_buildarea = True
|
|
||||||
continue
|
node.setOutsideBuildArea(False)
|
||||||
|
|
||||||
# Group nodes should override the _outside_buildarea property of their children.
|
# Group nodes should override the _outside_buildarea property of their children.
|
||||||
for group_node in group_nodes:
|
for group_node in group_nodes:
|
||||||
for child_node in group_node.getAllChildren():
|
for child_node in group_node.getAllChildren():
|
||||||
child_node._outside_buildarea = group_node._outside_buildarea
|
child_node.setOutsideBuildArea(group_node.isOutsideBuildArea)
|
||||||
|
|
||||||
## Update the outsideBuildArea of a single node, given bounds or current build volume
|
## Update the outsideBuildArea of a single node, given bounds or current build volume
|
||||||
def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None):
|
def checkBoundsAndUpdate(self, node: CuraSceneNode, bounds: Optional[AxisAlignedBox] = None):
|
||||||
|
@ -260,24 +259,20 @@ class BuildVolume(SceneNode):
|
||||||
build_volume_bounding_box = bounds
|
build_volume_bounding_box = bounds
|
||||||
|
|
||||||
if node.callDecoration("isSliceable") or node.callDecoration("isGroup"):
|
if node.callDecoration("isSliceable") or node.callDecoration("isGroup"):
|
||||||
bbox = node.getBoundingBox()
|
if node.collidesWithBbox(build_volume_bounding_box):
|
||||||
|
node.setOutsideBuildArea(True)
|
||||||
# Mark the node as outside the build volume if the bounding box test fails.
|
return
|
||||||
if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
|
||||||
|
if node.collidesWithArea(self.getDisallowedAreas()):
|
||||||
|
node.setOutsideBuildArea(True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Mark the node as outside build volume if the set extruder is disabled
|
||||||
|
extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||||
|
if not self._global_container_stack.extruders[extruder_position].isEnabled:
|
||||||
node.setOutsideBuildArea(True)
|
node.setOutsideBuildArea(True)
|
||||||
return
|
return
|
||||||
|
|
||||||
convex_hull = self.callDecoration("getConvexHull")
|
|
||||||
if convex_hull:
|
|
||||||
if not convex_hull.isValid():
|
|
||||||
return
|
|
||||||
# Check for collisions between disallowed areas and the object
|
|
||||||
for area in self.getDisallowedAreas():
|
|
||||||
overlap = convex_hull.intersectsPolygon(area)
|
|
||||||
if overlap is None:
|
|
||||||
continue
|
|
||||||
node.setOutsideBuildArea(True)
|
|
||||||
return
|
|
||||||
node.setOutsideBuildArea(False)
|
node.setOutsideBuildArea(False)
|
||||||
|
|
||||||
## Recalculates the build volume & disallowed areas.
|
## Recalculates the build volume & disallowed areas.
|
||||||
|
|
|
@ -1605,6 +1605,8 @@ class CuraApplication(QtApplication):
|
||||||
fixed_nodes.append(node_)
|
fixed_nodes.append(node_)
|
||||||
arranger = Arrange.create(fixed_nodes = fixed_nodes)
|
arranger = Arrange.create(fixed_nodes = fixed_nodes)
|
||||||
min_offset = 8
|
min_offset = 8
|
||||||
|
default_extruder_position = self.getMachineManager().defaultExtruderPosition
|
||||||
|
default_extruder_id = self._global_container_stack.extruders[default_extruder_position].getId()
|
||||||
|
|
||||||
for original_node in nodes:
|
for original_node in nodes:
|
||||||
|
|
||||||
|
@ -1670,6 +1672,8 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
op = AddSceneNodeOperation(node, scene.getRoot())
|
op = AddSceneNodeOperation(node, scene.getRoot())
|
||||||
op.push()
|
op.push()
|
||||||
|
|
||||||
|
node.callDecoration("setActiveExtruder", default_extruder_id)
|
||||||
scene.sceneChanged.emit(node)
|
scene.sceneChanged.emit(node)
|
||||||
|
|
||||||
self.fileCompleted.emit(filename)
|
self.fileCompleted.emit(filename)
|
||||||
|
|
|
@ -39,6 +39,7 @@ class QualityProfilesDropDownMenuModel(ListModel):
|
||||||
|
|
||||||
self._application.globalContainerStackChanged.connect(self._update)
|
self._application.globalContainerStackChanged.connect(self._update)
|
||||||
self._machine_manager.activeQualityGroupChanged.connect(self._update)
|
self._machine_manager.activeQualityGroupChanged.connect(self._update)
|
||||||
|
self._machine_manager.extruderChanged.connect(self._update)
|
||||||
self._quality_manager.qualitiesUpdated.connect(self._update)
|
self._quality_manager.qualitiesUpdated.connect(self._update)
|
||||||
|
|
||||||
self._layer_height_unit = "" # This is cached
|
self._layer_height_unit = "" # This is cached
|
||||||
|
|
|
@ -159,9 +159,9 @@ class QualityManager(QObject):
|
||||||
# Updates the given quality groups' availabilities according to which extruders are being used/ enabled.
|
# Updates the given quality groups' availabilities according to which extruders are being used/ enabled.
|
||||||
def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list):
|
def _updateQualityGroupsAvailability(self, machine: "GlobalStack", quality_group_list):
|
||||||
used_extruders = set()
|
used_extruders = set()
|
||||||
# TODO: This will change after the Machine refactoring
|
|
||||||
for i in range(machine.getProperty("machine_extruder_count", "value")):
|
for i in range(machine.getProperty("machine_extruder_count", "value")):
|
||||||
used_extruders.add(str(i))
|
if machine.extruders[str(i)].isEnabled:
|
||||||
|
used_extruders.add(str(i))
|
||||||
|
|
||||||
# Update the "is_available" flag for each quality group.
|
# Update the "is_available" flag for each quality group.
|
||||||
for quality_group in quality_group_list:
|
for quality_group in quality_group_list:
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from copy import deepcopy
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from copy import deepcopy
|
|
||||||
from cura.Settings.ExtrudersModel import ExtrudersModel
|
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
|
||||||
|
|
||||||
|
|
||||||
## Scene nodes that are models are only seen when selecting the corresponding build plate
|
## Scene nodes that are models are only seen when selecting the corresponding build plate
|
||||||
|
@ -11,6 +15,8 @@ from cura.Settings.ExtrudersModel import ExtrudersModel
|
||||||
class CuraSceneNode(SceneNode):
|
class CuraSceneNode(SceneNode):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
if "no_setting_override" not in kwargs:
|
||||||
|
self.addDecorator(SettingOverrideDecorator()) # now we always have a getActiveExtruderPosition, unless explicitly disabled
|
||||||
self._outside_buildarea = False
|
self._outside_buildarea = False
|
||||||
|
|
||||||
def setOutsideBuildArea(self, new_value):
|
def setOutsideBuildArea(self, new_value):
|
||||||
|
@ -72,9 +78,34 @@ class CuraSceneNode(SceneNode):
|
||||||
1.0
|
1.0
|
||||||
]
|
]
|
||||||
|
|
||||||
|
## Return if the provided bbox collides with the bbox of this scene node
|
||||||
|
def collidesWithBbox(self, check_bbox):
|
||||||
|
bbox = self.getBoundingBox()
|
||||||
|
|
||||||
|
# Mark the node as outside the build volume if the bounding box test fails.
|
||||||
|
if check_bbox.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
## Return if any area collides with the convex hull of this scene node
|
||||||
|
def collidesWithArea(self, areas):
|
||||||
|
convex_hull = self.callDecoration("getConvexHull")
|
||||||
|
if convex_hull:
|
||||||
|
if not convex_hull.isValid():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check for collisions between disallowed areas and the object
|
||||||
|
for area in areas:
|
||||||
|
overlap = convex_hull.intersectsPolygon(area)
|
||||||
|
if overlap is None:
|
||||||
|
continue
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
## Taken from SceneNode, but replaced SceneNode with CuraSceneNode
|
## Taken from SceneNode, but replaced SceneNode with CuraSceneNode
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
copy = CuraSceneNode()
|
copy = CuraSceneNode(no_setting_override = True) # Setting override will be added later
|
||||||
copy.setTransformation(self.getLocalTransformation())
|
copy.setTransformation(self.getLocalTransformation())
|
||||||
copy.setMeshData(self._mesh_data)
|
copy.setMeshData(self._mesh_data)
|
||||||
copy.setVisible(deepcopy(self._visible, memo))
|
copy.setVisible(deepcopy(self._visible, memo))
|
||||||
|
|
|
@ -334,10 +334,13 @@ class ContainerManager(QObject):
|
||||||
|
|
||||||
# Go through global and extruder stacks and clear their topmost container (the user settings).
|
# Go through global and extruder stacks and clear their topmost container (the user settings).
|
||||||
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
|
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
|
||||||
container = stack.getTop()
|
container = stack.userChanges
|
||||||
container.clear()
|
container.clear()
|
||||||
send_emits_containers.append(container)
|
send_emits_containers.append(container)
|
||||||
|
|
||||||
|
# user changes are possibly added to make the current setup match the current enabled extruders
|
||||||
|
Application.getInstance().getMachineManager().correctExtruderSettings()
|
||||||
|
|
||||||
for container in send_emits_containers:
|
for container in send_emits_containers:
|
||||||
container.sendPostponedEmits()
|
container.sendPostponedEmits()
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,13 @@ class ExtruderManager(QObject):
|
||||||
result.append(extruder_stack.getProperty(setting_key, prop))
|
result.append(extruder_stack.getProperty(setting_key, prop))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def extruderValueWithDefault(self, value):
|
||||||
|
machine_manager = self._application.getMachineManager()
|
||||||
|
if value == "-1":
|
||||||
|
return machine_manager.defaultExtruderPosition
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
## Gets the extruder stacks that are actually being used at the moment.
|
## Gets the extruder stacks that are actually being used at the moment.
|
||||||
#
|
#
|
||||||
# An extruder stack is being used if it is the extruder to print any mesh
|
# An extruder stack is being used if it is the extruder to print any mesh
|
||||||
|
@ -252,7 +259,7 @@ class ExtruderManager(QObject):
|
||||||
#
|
#
|
||||||
# \return A list of extruder stacks.
|
# \return A list of extruder stacks.
|
||||||
def getUsedExtruderStacks(self) -> List["ContainerStack"]:
|
def getUsedExtruderStacks(self) -> List["ContainerStack"]:
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = self._application.getGlobalContainerStack()
|
||||||
container_registry = ContainerRegistry.getInstance()
|
container_registry = ContainerRegistry.getInstance()
|
||||||
|
|
||||||
used_extruder_stack_ids = set()
|
used_extruder_stack_ids = set()
|
||||||
|
@ -302,16 +309,19 @@ class ExtruderManager(QObject):
|
||||||
|
|
||||||
# Check support extruders
|
# Check support extruders
|
||||||
if support_enabled:
|
if support_enabled:
|
||||||
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_infill_extruder_nr", "value"))])
|
used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_infill_extruder_nr", "value")))])
|
||||||
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_extruder_nr_layer_0", "value"))])
|
used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_extruder_nr_layer_0", "value")))])
|
||||||
if support_bottom_enabled:
|
if support_bottom_enabled:
|
||||||
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_bottom_extruder_nr", "value"))])
|
used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_bottom_extruder_nr", "value")))])
|
||||||
if support_roof_enabled:
|
if support_roof_enabled:
|
||||||
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_roof_extruder_nr", "value"))])
|
used_extruder_stack_ids.add(self.extruderIds[self.extruderValueWithDefault(str(global_stack.getProperty("support_roof_extruder_nr", "value")))])
|
||||||
|
|
||||||
# The platform adhesion extruder. Not used if using none.
|
# The platform adhesion extruder. Not used if using none.
|
||||||
if global_stack.getProperty("adhesion_type", "value") != "none":
|
if global_stack.getProperty("adhesion_type", "value") != "none":
|
||||||
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("adhesion_extruder_nr", "value"))])
|
extruder_nr = str(global_stack.getProperty("adhesion_extruder_nr", "value"))
|
||||||
|
if extruder_nr == "-1":
|
||||||
|
extruder_nr = Application.getInstance().getMachineManager().defaultExtruderPosition
|
||||||
|
used_extruder_stack_ids.add(self.extruderIds[extruder_nr])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids]
|
return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids]
|
||||||
|
@ -485,6 +495,8 @@ class ExtruderManager(QObject):
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
|
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
|
||||||
|
if not extruder.isEnabled:
|
||||||
|
continue
|
||||||
# only include values from extruders that are "active" for the current machine instance
|
# only include values from extruders that are "active" for the current machine instance
|
||||||
if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value"):
|
if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value"):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
|
|
||||||
from typing import Any, TYPE_CHECKING, Optional
|
from typing import Any, TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtProperty
|
from PyQt5.QtCore import pyqtProperty, pyqtSignal
|
||||||
|
|
||||||
from UM.Decorators import override
|
from UM.Decorators import override
|
||||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
|
from UM.Settings.Interfaces import ContainerInterface, PropertyEvaluationContext
|
||||||
|
from UM.Util import parseBool
|
||||||
|
|
||||||
from . import Exceptions
|
from . import Exceptions
|
||||||
from .CuraContainerStack import CuraContainerStack, _ContainerIndexes
|
from .CuraContainerStack import CuraContainerStack, _ContainerIndexes
|
||||||
|
@ -30,6 +31,8 @@ class ExtruderStack(CuraContainerStack):
|
||||||
|
|
||||||
self.propertiesChanged.connect(self._onPropertiesChanged)
|
self.propertiesChanged.connect(self._onPropertiesChanged)
|
||||||
|
|
||||||
|
enabledChanged = pyqtSignal()
|
||||||
|
|
||||||
## Overridden from ContainerStack
|
## Overridden from ContainerStack
|
||||||
#
|
#
|
||||||
# This will set the next stack and ensure that we register this stack as an extruder.
|
# This will set the next stack and ensure that we register this stack as an extruder.
|
||||||
|
@ -46,6 +49,16 @@ class ExtruderStack(CuraContainerStack):
|
||||||
def getNextStack(self) -> Optional["GlobalStack"]:
|
def getNextStack(self) -> Optional["GlobalStack"]:
|
||||||
return super().getNextStack()
|
return super().getNextStack()
|
||||||
|
|
||||||
|
def setEnabled(self, enabled):
|
||||||
|
if "enabled" not in self._metadata:
|
||||||
|
self.addMetaDataEntry("enabled", "True")
|
||||||
|
self.setMetaDataEntry("enabled", str(enabled))
|
||||||
|
self.enabledChanged.emit()
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify = enabledChanged)
|
||||||
|
def isEnabled(self):
|
||||||
|
return parseBool(self.getMetaDataEntry("enabled", "True"))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getLoadingPriority(cls) -> int:
|
def getLoadingPriority(cls) -> int:
|
||||||
return 3
|
return 3
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, pyqtProperty, QTimer
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
@ -24,6 +24,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||||
|
|
||||||
## Human-readable name of the extruder.
|
## Human-readable name of the extruder.
|
||||||
NameRole = Qt.UserRole + 2
|
NameRole = Qt.UserRole + 2
|
||||||
|
## Is the extruder enabled?
|
||||||
|
EnabledRole = Qt.UserRole + 9
|
||||||
|
|
||||||
## Colour of the material loaded in the extruder.
|
## Colour of the material loaded in the extruder.
|
||||||
ColorRole = Qt.UserRole + 3
|
ColorRole = Qt.UserRole + 3
|
||||||
|
@ -43,6 +45,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||||
|
|
||||||
# The variant of the extruder.
|
# The variant of the extruder.
|
||||||
VariantRole = Qt.UserRole + 7
|
VariantRole = Qt.UserRole + 7
|
||||||
|
StackRole = Qt.UserRole + 8
|
||||||
|
|
||||||
## List of colours to display if there is no material or the material has no known
|
## List of colours to display if there is no material or the material has no known
|
||||||
# colour.
|
# colour.
|
||||||
|
@ -57,11 +60,13 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||||
|
|
||||||
self.addRoleName(self.IdRole, "id")
|
self.addRoleName(self.IdRole, "id")
|
||||||
self.addRoleName(self.NameRole, "name")
|
self.addRoleName(self.NameRole, "name")
|
||||||
|
self.addRoleName(self.EnabledRole, "enabled")
|
||||||
self.addRoleName(self.ColorRole, "color")
|
self.addRoleName(self.ColorRole, "color")
|
||||||
self.addRoleName(self.IndexRole, "index")
|
self.addRoleName(self.IndexRole, "index")
|
||||||
self.addRoleName(self.DefinitionRole, "definition")
|
self.addRoleName(self.DefinitionRole, "definition")
|
||||||
self.addRoleName(self.MaterialRole, "material")
|
self.addRoleName(self.MaterialRole, "material")
|
||||||
self.addRoleName(self.VariantRole, "variant")
|
self.addRoleName(self.VariantRole, "variant")
|
||||||
|
self.addRoleName(self.StackRole, "stack")
|
||||||
|
|
||||||
self._update_extruder_timer = QTimer()
|
self._update_extruder_timer = QTimer()
|
||||||
self._update_extruder_timer.setInterval(100)
|
self._update_extruder_timer.setInterval(100)
|
||||||
|
@ -183,11 +188,13 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||||
item = {
|
item = {
|
||||||
"id": extruder.getId(),
|
"id": extruder.getId(),
|
||||||
"name": extruder.getName(),
|
"name": extruder.getName(),
|
||||||
|
"enabled": extruder.isEnabled,
|
||||||
"color": color,
|
"color": color,
|
||||||
"index": position,
|
"index": position,
|
||||||
"definition": extruder.getBottom().getId(),
|
"definition": extruder.getBottom().getId(),
|
||||||
"material": extruder.material.getName() if extruder.material else "",
|
"material": extruder.material.getName() if extruder.material else "",
|
||||||
"variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core
|
"variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core
|
||||||
|
"stack": extruder,
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(item)
|
items.append(item)
|
||||||
|
|
|
@ -52,6 +52,8 @@ class MachineManager(QObject):
|
||||||
self._current_quality_group = None
|
self._current_quality_group = None
|
||||||
self._current_quality_changes_group = None
|
self._current_quality_changes_group = None
|
||||||
|
|
||||||
|
self._default_extruder_position = "0" # to be updated when extruders are switched on and off
|
||||||
|
|
||||||
self.machine_extruder_material_update_dict = collections.defaultdict(list)
|
self.machine_extruder_material_update_dict = collections.defaultdict(list)
|
||||||
|
|
||||||
self._error_check_timer = QTimer()
|
self._error_check_timer = QTimer()
|
||||||
|
@ -132,6 +134,7 @@ class MachineManager(QObject):
|
||||||
activeVariantChanged = pyqtSignal()
|
activeVariantChanged = pyqtSignal()
|
||||||
activeQualityChanged = pyqtSignal()
|
activeQualityChanged = pyqtSignal()
|
||||||
activeStackChanged = pyqtSignal() # Emitted whenever the active stack is changed (ie: when changing between extruders, changing a profile, but not when changing a value)
|
activeStackChanged = pyqtSignal() # Emitted whenever the active stack is changed (ie: when changing between extruders, changing a profile, but not when changing a value)
|
||||||
|
extruderChanged = pyqtSignal()
|
||||||
|
|
||||||
globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed.
|
globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed.
|
||||||
activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed.
|
activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed.
|
||||||
|
@ -189,7 +192,9 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
# Update the local global container stack reference
|
# Update the local global container stack reference
|
||||||
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
|
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
if self._global_container_stack:
|
||||||
|
self.updateDefaultExtruder()
|
||||||
|
self.updateNumberExtrudersEnabled()
|
||||||
self.globalContainerChanged.emit()
|
self.globalContainerChanged.emit()
|
||||||
|
|
||||||
# after switching the global stack we reconnect all the signals and set the variant and material references
|
# after switching the global stack we reconnect all the signals and set the variant and material references
|
||||||
|
@ -641,6 +646,8 @@ class MachineManager(QObject):
|
||||||
buildplate_compatible = True # It is compatible by default
|
buildplate_compatible = True # It is compatible by default
|
||||||
extruder_stacks = self._global_container_stack.extruders.values()
|
extruder_stacks = self._global_container_stack.extruders.values()
|
||||||
for stack in extruder_stacks:
|
for stack in extruder_stacks:
|
||||||
|
if not stack.isEnabled:
|
||||||
|
continue
|
||||||
material_container = stack.material
|
material_container = stack.material
|
||||||
if material_container == self._empty_material_container:
|
if material_container == self._empty_material_container:
|
||||||
continue
|
continue
|
||||||
|
@ -698,6 +705,43 @@ class MachineManager(QObject):
|
||||||
if containers:
|
if containers:
|
||||||
return containers[0].definition.getId()
|
return containers[0].definition.getId()
|
||||||
|
|
||||||
|
def getIncompatibleSettingsOnEnabledExtruders(self, container):
|
||||||
|
extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value")
|
||||||
|
result = []
|
||||||
|
for setting_instance in container.findInstances():
|
||||||
|
setting_key = setting_instance.definition.key
|
||||||
|
setting_enabled = self._global_container_stack.getProperty(setting_key, "enabled")
|
||||||
|
if not setting_enabled:
|
||||||
|
# A setting is not visible anymore
|
||||||
|
result.append(setting_key)
|
||||||
|
Logger.log("d", "Reset setting [%s] from [%s] because the setting is no longer enabled", setting_key, container)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
old_value = container.getProperty(setting_key, "value")
|
||||||
|
if int(old_value) >= extruder_count or not self._global_container_stack.extruders[str(old_value)].isEnabled:
|
||||||
|
result.append(setting_key)
|
||||||
|
Logger.log("d", "Reset setting [%s] in [%s] because its old value [%s] is no longer valid", setting_key, container, old_value)
|
||||||
|
return result
|
||||||
|
|
||||||
|
## Update extruder number to a valid value when the number of extruders are changed, or when an extruder is changed
|
||||||
|
def correctExtruderSettings(self):
|
||||||
|
for setting_key in self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.userChanges):
|
||||||
|
self._global_container_stack.userChanges.removeInstance(setting_key)
|
||||||
|
add_user_changes = self.getIncompatibleSettingsOnEnabledExtruders(self._global_container_stack.qualityChanges)
|
||||||
|
for setting_key in add_user_changes:
|
||||||
|
# Apply quality changes that are incompatible to user changes, so we do not change the quality changes itself.
|
||||||
|
self._global_container_stack.userChanges.setProperty(setting_key, "value", self._default_extruder_position)
|
||||||
|
if add_user_changes:
|
||||||
|
caution_message = Message(catalog.i18nc(
|
||||||
|
"@info:generic",
|
||||||
|
"Settings have been changed to match the current availability of extruders: [%s]" % ", ".join(add_user_changes)),
|
||||||
|
lifetime=0,
|
||||||
|
title = catalog.i18nc("@info:title", "Settings updated"))
|
||||||
|
caution_message.show()
|
||||||
|
|
||||||
## Set the amount of extruders on the active machine (global stack)
|
## Set the amount of extruders on the active machine (global stack)
|
||||||
# \param extruder_count int the number of extruders to set
|
# \param extruder_count int the number of extruders to set
|
||||||
def setActiveMachineExtruderCount(self, extruder_count):
|
def setActiveMachineExtruderCount(self, extruder_count):
|
||||||
|
@ -711,16 +755,11 @@ class MachineManager(QObject):
|
||||||
if extruder_count == previous_extruder_count:
|
if extruder_count == previous_extruder_count:
|
||||||
return
|
return
|
||||||
|
|
||||||
# reset all extruder number settings whose value is no longer valid
|
definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count)
|
||||||
for setting_instance in self._global_container_stack.userChanges.findInstances():
|
|
||||||
setting_key = setting_instance.definition.key
|
|
||||||
if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
old_value = int(self._global_container_stack.userChanges.getProperty(setting_key, "value"))
|
self.updateDefaultExtruder()
|
||||||
if old_value >= extruder_count:
|
self.updateNumberExtrudersEnabled()
|
||||||
self._global_container_stack.userChanges.removeInstance(setting_key)
|
self.correctExtruderSettings()
|
||||||
Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid ", setting_key, old_value)
|
|
||||||
|
|
||||||
# Check to see if any objects are set to print with an extruder that will no longer exist
|
# Check to see if any objects are set to print with an extruder that will no longer exist
|
||||||
root_node = Application.getInstance().getController().getScene().getRoot()
|
root_node = Application.getInstance().getController().getScene().getRoot()
|
||||||
|
@ -731,21 +770,19 @@ class MachineManager(QObject):
|
||||||
if extruder_nr is not None and int(extruder_nr) > extruder_count - 1:
|
if extruder_nr is not None and int(extruder_nr) > extruder_count - 1:
|
||||||
node.callDecoration("setActiveExtruder", extruder_manager.getExtruderStack(extruder_count - 1).getId())
|
node.callDecoration("setActiveExtruder", extruder_manager.getExtruderStack(extruder_count - 1).getId())
|
||||||
|
|
||||||
definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count)
|
|
||||||
|
|
||||||
# Make sure one of the extruder stacks is active
|
# Make sure one of the extruder stacks is active
|
||||||
extruder_manager.setActiveExtruderIndex(0)
|
extruder_manager.setActiveExtruderIndex(0)
|
||||||
|
|
||||||
# Move settable_per_extruder values out of the global container
|
# Move settable_per_extruder values out of the global container
|
||||||
# After CURA-4482 this should not be the case anymore, but we still want to support older project files.
|
# After CURA-4482 this should not be the case anymore, but we still want to support older project files.
|
||||||
global_user_container = self._global_container_stack.getTop()
|
global_user_container = self._global_container_stack.userChanges
|
||||||
|
|
||||||
# Make sure extruder_stacks exists
|
# Make sure extruder_stacks exists
|
||||||
extruder_stacks = []
|
extruder_stacks = []
|
||||||
|
|
||||||
if previous_extruder_count == 1:
|
if previous_extruder_count == 1:
|
||||||
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
|
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
|
||||||
global_user_container = self._global_container_stack.getTop()
|
global_user_container = self._global_container_stack.userChanges
|
||||||
|
|
||||||
for setting_instance in global_user_container.findInstances():
|
for setting_instance in global_user_container.findInstances():
|
||||||
setting_key = setting_instance.definition.key
|
setting_key = setting_instance.definition.key
|
||||||
|
@ -754,11 +791,12 @@ class MachineManager(QObject):
|
||||||
if settable_per_extruder:
|
if settable_per_extruder:
|
||||||
limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder"))
|
limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder"))
|
||||||
extruder_stack = extruder_stacks[max(0, limit_to_extruder)]
|
extruder_stack = extruder_stacks[max(0, limit_to_extruder)]
|
||||||
extruder_stack.getTop().setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value"))
|
extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value"))
|
||||||
global_user_container.removeInstance(setting_key)
|
global_user_container.removeInstance(setting_key)
|
||||||
|
|
||||||
# Signal that the global stack has changed
|
# Signal that the global stack has changed
|
||||||
Application.getInstance().globalContainerStackChanged.emit()
|
Application.getInstance().globalContainerStackChanged.emit()
|
||||||
|
self.forceUpdateAllSettings()
|
||||||
|
|
||||||
@pyqtSlot(int, result = QObject)
|
@pyqtSlot(int, result = QObject)
|
||||||
def getExtruder(self, position: int):
|
def getExtruder(self, position: int):
|
||||||
|
@ -767,6 +805,53 @@ class MachineManager(QObject):
|
||||||
extruder = self._global_container_stack.extruders.get(str(position))
|
extruder = self._global_container_stack.extruders.get(str(position))
|
||||||
return extruder
|
return extruder
|
||||||
|
|
||||||
|
def updateDefaultExtruder(self):
|
||||||
|
extruder_items = sorted(self._global_container_stack.extruders.items())
|
||||||
|
old_position = self._default_extruder_position
|
||||||
|
new_default_position = "0"
|
||||||
|
for position, extruder in extruder_items:
|
||||||
|
if extruder.isEnabled:
|
||||||
|
new_default_position = position
|
||||||
|
break
|
||||||
|
if new_default_position != old_position:
|
||||||
|
self._default_extruder_position = new_default_position
|
||||||
|
self.extruderChanged.emit()
|
||||||
|
|
||||||
|
def updateNumberExtrudersEnabled(self):
|
||||||
|
definition_changes_container = self._global_container_stack.definitionChanges
|
||||||
|
extruder_count = 0
|
||||||
|
for position, extruder in self._global_container_stack.extruders.items():
|
||||||
|
if extruder.isEnabled:
|
||||||
|
extruder_count += 1
|
||||||
|
definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count)
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify = extruderChanged)
|
||||||
|
def defaultExtruderPosition(self):
|
||||||
|
return self._default_extruder_position
|
||||||
|
|
||||||
|
## This will fire the propertiesChanged for all settings so they will be updated in the front-end
|
||||||
|
def forceUpdateAllSettings(self):
|
||||||
|
property_names = ["value", "resolve"]
|
||||||
|
for setting_key in self._global_container_stack.getAllKeys():
|
||||||
|
self._global_container_stack.propertiesChanged.emit(setting_key, property_names)
|
||||||
|
|
||||||
|
@pyqtSlot(int, bool)
|
||||||
|
def setExtruderEnabled(self, position: int, enabled) -> None:
|
||||||
|
extruder = self.getExtruder(position)
|
||||||
|
extruder.setEnabled(enabled)
|
||||||
|
self.updateDefaultExtruder()
|
||||||
|
self.updateNumberExtrudersEnabled()
|
||||||
|
self.correctExtruderSettings()
|
||||||
|
# ensure that the quality profile is compatible with current combination, or choose a compatible one if available
|
||||||
|
self._updateQualityWithMaterial()
|
||||||
|
self.extruderChanged.emit()
|
||||||
|
# update material compatibility color
|
||||||
|
self.activeQualityGroupChanged.emit()
|
||||||
|
# update items in SettingExtruder
|
||||||
|
ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId())
|
||||||
|
# Make sure the front end reflects changes
|
||||||
|
self.forceUpdateAllSettings()
|
||||||
|
|
||||||
def _onMachineNameChanged(self):
|
def _onMachineNameChanged(self):
|
||||||
self.globalContainerChanged.emit()
|
self.globalContainerChanged.emit()
|
||||||
|
|
||||||
|
@ -921,6 +1006,8 @@ class MachineManager(QObject):
|
||||||
# check material - variant compatibility
|
# check material - variant compatibility
|
||||||
if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)):
|
if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)):
|
||||||
for position, extruder in self._global_container_stack.extruders.items():
|
for position, extruder in self._global_container_stack.extruders.items():
|
||||||
|
if extruder.isEnabled and not extruder.material.getMetaDataEntry("compatible"):
|
||||||
|
return False
|
||||||
if not extruder.material.getMetaDataEntry("compatible"):
|
if not extruder.material.getMetaDataEntry("compatible"):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -62,7 +62,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
||||||
|
|
||||||
# use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh"
|
# use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh"
|
||||||
# has not been updated yet.
|
# has not been updated yet.
|
||||||
deep_copy._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings)
|
deep_copy._is_non_printing_mesh = self.evaluateIsNonPrintingMesh()
|
||||||
|
|
||||||
return deep_copy
|
return deep_copy
|
||||||
|
|
||||||
|
@ -90,10 +90,18 @@ class SettingOverrideDecorator(SceneNodeDecorator):
|
||||||
def isNonPrintingMesh(self):
|
def isNonPrintingMesh(self):
|
||||||
return self._is_non_printing_mesh
|
return self._is_non_printing_mesh
|
||||||
|
|
||||||
|
def evaluateIsNonPrintingMesh(self):
|
||||||
|
return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings)
|
||||||
|
|
||||||
def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function
|
def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function
|
||||||
# Trigger slice/need slicing if the value has changed.
|
object_has_instance_setting = False
|
||||||
if property_name == "value":
|
for container in self._stack.getContainers():
|
||||||
self._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings)
|
if container.hasProperty(instance, "value"):
|
||||||
|
object_has_instance_setting = True
|
||||||
|
break
|
||||||
|
if property_name == "value" and object_has_instance_setting:
|
||||||
|
# Trigger slice/need slicing if the value has changed.
|
||||||
|
self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh()
|
||||||
|
|
||||||
Application.getInstance().getBackend().needsSlicing()
|
Application.getInstance().getBackend().needsSlicing()
|
||||||
Application.getInstance().getBackend().tickle()
|
Application.getInstance().getBackend().tickle()
|
||||||
|
|
|
@ -94,6 +94,8 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self._onGlobalStackChanged()
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
||||||
|
# extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash
|
||||||
|
ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged)
|
||||||
|
|
||||||
# A flag indicating if an error check was scheduled
|
# A flag indicating if an error check was scheduled
|
||||||
# If so, we will stop the auto-slice timer and start upon the error check
|
# If so, we will stop the auto-slice timer and start upon the error check
|
||||||
|
@ -782,3 +784,9 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
def tickle(self):
|
def tickle(self):
|
||||||
if self._use_timer:
|
if self._use_timer:
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
|
||||||
|
def _extruderChanged(self):
|
||||||
|
for build_plate_number in range(Application.getInstance().getMultiBuildPlateModel().maxBuildPlate + 1):
|
||||||
|
if build_plate_number not in self._build_plates_to_be_sliced:
|
||||||
|
self._build_plates_to_be_sliced.append(build_plate_number)
|
||||||
|
self._invokeSlice()
|
||||||
|
|
|
@ -81,7 +81,8 @@ class ProcessSlicedLayersJob(Job):
|
||||||
|
|
||||||
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||||
|
|
||||||
new_node = CuraSceneNode()
|
# The no_setting_override is here because adding the SettingOverrideDecorator will trigger a reslice
|
||||||
|
new_node = CuraSceneNode(no_setting_override = True)
|
||||||
new_node.addDecorator(BuildPlateDecorator(self._build_plate_number))
|
new_node.addDecorator(BuildPlateDecorator(self._build_plate_number))
|
||||||
|
|
||||||
# Force garbage collection.
|
# Force garbage collection.
|
||||||
|
|
|
@ -129,8 +129,10 @@ class StartSliceJob(Job):
|
||||||
self.setResult(StartJobResult.MaterialIncompatible)
|
self.setResult(StartJobResult.MaterialIncompatible)
|
||||||
return
|
return
|
||||||
|
|
||||||
for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(stack.getId()):
|
for position, extruder_stack in stack.extruders.items():
|
||||||
material = extruder_stack.findContainer({"type": "material"})
|
material = extruder_stack.findContainer({"type": "material"})
|
||||||
|
if not extruder_stack.isEnabled:
|
||||||
|
continue
|
||||||
if material:
|
if material:
|
||||||
if material.getMetaDataEntry("compatible") == False:
|
if material.getMetaDataEntry("compatible") == False:
|
||||||
self.setResult(StartJobResult.MaterialIncompatible)
|
self.setResult(StartJobResult.MaterialIncompatible)
|
||||||
|
@ -189,11 +191,18 @@ class StartSliceJob(Job):
|
||||||
if per_object_stack:
|
if per_object_stack:
|
||||||
is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS)
|
is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS)
|
||||||
|
|
||||||
if node.callDecoration("getBuildPlateNumber") == self._build_plate_number:
|
# Find a reason not to add the node
|
||||||
if not getattr(node, "_outside_buildarea", False) or is_non_printing_mesh:
|
if node.callDecoration("getBuildPlateNumber") != self._build_plate_number:
|
||||||
temp_list.append(node)
|
continue
|
||||||
if not is_non_printing_mesh:
|
if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh:
|
||||||
has_printing_mesh = True
|
continue
|
||||||
|
node_position = node.callDecoration("getActiveExtruderPosition")
|
||||||
|
if not stack.extruders[str(node_position)].isEnabled:
|
||||||
|
continue
|
||||||
|
|
||||||
|
temp_list.append(node)
|
||||||
|
if not is_non_printing_mesh:
|
||||||
|
has_printing_mesh = True
|
||||||
|
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
|
@ -269,9 +278,15 @@ class StartSliceJob(Job):
|
||||||
# \return A dictionary of replacement tokens to the values they should be
|
# \return A dictionary of replacement tokens to the values they should be
|
||||||
# replaced with.
|
# replaced with.
|
||||||
def _buildReplacementTokens(self, stack) -> dict:
|
def _buildReplacementTokens(self, stack) -> dict:
|
||||||
|
default_extruder_position = int(Application.getInstance().getMachineManager().defaultExtruderPosition)
|
||||||
result = {}
|
result = {}
|
||||||
for key in stack.getAllKeys():
|
for key in stack.getAllKeys():
|
||||||
result[key] = stack.getProperty(key, "value")
|
setting_type = stack.getProperty(key, "type")
|
||||||
|
value = stack.getProperty(key, "value")
|
||||||
|
if setting_type == "extruder" and value == -1:
|
||||||
|
# replace with the default value
|
||||||
|
value = default_extruder_position
|
||||||
|
result[key] = value
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings.
|
result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings.
|
||||||
|
@ -377,11 +392,11 @@ class StartSliceJob(Job):
|
||||||
# limit_to_extruder property.
|
# limit_to_extruder property.
|
||||||
def _buildGlobalInheritsStackMessage(self, stack):
|
def _buildGlobalInheritsStackMessage(self, stack):
|
||||||
for key in stack.getAllKeys():
|
for key in stack.getAllKeys():
|
||||||
extruder = int(round(float(stack.getProperty(key, "limit_to_extruder"))))
|
extruder_position = int(round(float(stack.getProperty(key, "limit_to_extruder"))))
|
||||||
if extruder >= 0: #Set to a specific extruder.
|
if extruder_position >= 0: # Set to a specific extruder.
|
||||||
setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder")
|
setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder")
|
||||||
setting_extruder.name = key
|
setting_extruder.name = key
|
||||||
setting_extruder.extruder = extruder
|
setting_extruder.extruder = extruder_position
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
## Check if a node has per object settings and ensure that they are set correctly in the message
|
## Check if a node has per object settings and ensure that they are set correctly in the message
|
||||||
|
|
|
@ -78,17 +78,13 @@ class SolidView(View):
|
||||||
|
|
||||||
for node in DepthFirstIterator(scene.getRoot()):
|
for node in DepthFirstIterator(scene.getRoot()):
|
||||||
if not node.render(renderer):
|
if not node.render(renderer):
|
||||||
if node.getMeshData() and node.isVisible():
|
if node.getMeshData() and node.isVisible() and not node.callDecoration("getLayerData"):
|
||||||
uniforms = {}
|
uniforms = {}
|
||||||
shade_factor = 1.0
|
shade_factor = 1.0
|
||||||
|
|
||||||
per_mesh_stack = node.callDecoration("getStack")
|
per_mesh_stack = node.callDecoration("getStack")
|
||||||
|
|
||||||
# Get color to render this mesh in from ExtrudersModel
|
extruder_index = int(node.callDecoration("getActiveExtruderPosition"))
|
||||||
extruder_index = 0
|
|
||||||
extruder_id = node.callDecoration("getActiveExtruder")
|
|
||||||
if extruder_id:
|
|
||||||
extruder_index = max(0, self._extruders_model.find("id", extruder_id))
|
|
||||||
|
|
||||||
# Use the support extruder instead of the active extruder if this is a support_mesh
|
# Use the support extruder instead of the active extruder if this is a support_mesh
|
||||||
if per_mesh_stack:
|
if per_mesh_stack:
|
||||||
|
|
|
@ -211,6 +211,18 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
},
|
},
|
||||||
|
"extruders_enabled_count":
|
||||||
|
{
|
||||||
|
"label": "Number of Extruders that are enabled",
|
||||||
|
"description": "Number of extruder trains that are enabled; automatically set in software",
|
||||||
|
"default_value": "machine_extruder_count",
|
||||||
|
"minimum_value": "1",
|
||||||
|
"maximum_value": "16",
|
||||||
|
"type": "int",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
"machine_nozzle_tip_outer_diameter":
|
"machine_nozzle_tip_outer_diameter":
|
||||||
{
|
{
|
||||||
"label": "Outer nozzle diameter",
|
"label": "Outer nozzle diameter",
|
||||||
|
@ -887,7 +899,7 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1",
|
"enabled": "extruders_enabled_count > 1",
|
||||||
"children": {
|
"children": {
|
||||||
"wall_0_extruder_nr":
|
"wall_0_extruder_nr":
|
||||||
{
|
{
|
||||||
|
@ -900,7 +912,7 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1"
|
"enabled": "extruders_enabled_count > 1"
|
||||||
},
|
},
|
||||||
"wall_x_extruder_nr":
|
"wall_x_extruder_nr":
|
||||||
{
|
{
|
||||||
|
@ -913,7 +925,7 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1"
|
"enabled": "extruders_enabled_count > 1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -970,7 +982,7 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0"
|
"enabled": "extruders_enabled_count > 1 and max(extruderValues('roofing_layer_count')) > 0 and max(extruderValues('top_layers')) > 0"
|
||||||
},
|
},
|
||||||
"roofing_layer_count":
|
"roofing_layer_count":
|
||||||
{
|
{
|
||||||
|
@ -995,7 +1007,7 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1"
|
"enabled": "extruders_enabled_count > 1"
|
||||||
},
|
},
|
||||||
"top_bottom_thickness":
|
"top_bottom_thickness":
|
||||||
{
|
{
|
||||||
|
@ -1465,7 +1477,7 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1"
|
"enabled": "extruders_enabled_count > 1"
|
||||||
},
|
},
|
||||||
"infill_sparse_density":
|
"infill_sparse_density":
|
||||||
{
|
{
|
||||||
|
@ -1916,7 +1928,7 @@
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "10.0",
|
"maximum_value_warning": "10.0",
|
||||||
"maximum_value": "machine_nozzle_heat_up_speed",
|
"maximum_value": "machine_nozzle_heat_up_speed",
|
||||||
"enabled": "material_flow_dependent_temperature or (machine_extruder_count > 1 and material_final_print_temperature != material_print_temperature)",
|
"enabled": "material_flow_dependent_temperature or (extruders_enabled_count > 1 and material_final_print_temperature != material_print_temperature)",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
},
|
||||||
|
@ -2179,7 +2191,7 @@
|
||||||
"minimum_value": "-273.15",
|
"minimum_value": "-273.15",
|
||||||
"minimum_value_warning": "0",
|
"minimum_value_warning": "0",
|
||||||
"maximum_value_warning": "260",
|
"maximum_value_warning": "260",
|
||||||
"enabled": "machine_extruder_count > 1 and machine_nozzle_temp_enabled",
|
"enabled": "extruders_enabled_count > 1 and machine_nozzle_temp_enabled",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
},
|
||||||
|
@ -3281,7 +3293,7 @@
|
||||||
"description": "After the machine switched from one extruder to the other, the build plate is lowered to create clearance between the nozzle and the print. This prevents the nozzle from leaving oozed material on the outside of a print.",
|
"description": "After the machine switched from one extruder to the other, the build plate is lowered to create clearance between the nozzle and the print. This prevents the nozzle from leaving oozed material on the outside of a print.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"default_value": true,
|
"default_value": true,
|
||||||
"enabled": "retraction_hop_enabled and machine_extruder_count > 1",
|
"enabled": "retraction_hop_enabled and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
}
|
}
|
||||||
|
@ -3459,7 +3471,8 @@
|
||||||
"description": "The extruder train to use for printing the support. This is used in multi-extrusion.",
|
"description": "The extruder train to use for printing the support. This is used in multi-extrusion.",
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1",
|
"value": "-1",
|
||||||
|
"enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children": {
|
"children": {
|
||||||
|
@ -3470,7 +3483,7 @@
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"value": "support_extruder_nr",
|
"value": "support_extruder_nr",
|
||||||
"enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1",
|
"enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
|
@ -3481,7 +3494,7 @@
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"value": "support_extruder_nr",
|
"value": "support_extruder_nr",
|
||||||
"enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1",
|
"enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
|
@ -3492,7 +3505,7 @@
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"value": "support_extruder_nr",
|
"value": "support_extruder_nr",
|
||||||
"enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1",
|
"enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"children":
|
"children":
|
||||||
|
@ -3504,7 +3517,7 @@
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"value": "support_interface_extruder_nr",
|
"value": "support_interface_extruder_nr",
|
||||||
"enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1",
|
"enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
|
@ -3515,7 +3528,7 @@
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"value": "support_interface_extruder_nr",
|
"value": "support_interface_extruder_nr",
|
||||||
"enabled": "(support_enable or support_tree_enable) and machine_extruder_count > 1",
|
"enabled": "(support_enable or support_tree_enable) and extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
}
|
}
|
||||||
|
@ -4185,7 +4198,8 @@
|
||||||
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
|
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
|
||||||
"type": "extruder",
|
"type": "extruder",
|
||||||
"default_value": "0",
|
"default_value": "0",
|
||||||
"enabled": "machine_extruder_count > 1 and resolveOrValue('adhesion_type') != 'none'",
|
"value": "-1",
|
||||||
|
"enabled": "extruders_enabled_count > 1 and resolveOrValue('adhesion_type') != 'none'",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
|
@ -4756,7 +4770,7 @@
|
||||||
"label": "Enable Prime Tower",
|
"label": "Enable Prime Tower",
|
||||||
"description": "Print a tower next to the print which serves to prime the material after each nozzle switch.",
|
"description": "Print a tower next to the print which serves to prime the material after each nozzle switch.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"enabled": "machine_extruder_count > 1",
|
"enabled": "extruders_enabled_count > 1",
|
||||||
"default_value": false,
|
"default_value": false,
|
||||||
"resolve": "any(extruderValues('prime_tower_enable'))",
|
"resolve": "any(extruderValues('prime_tower_enable'))",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
|
@ -4904,7 +4918,7 @@
|
||||||
"description": "Enable exterior ooze shield. This will create a shell around the model which is likely to wipe a second nozzle if it's at the same height as the first nozzle.",
|
"description": "Enable exterior ooze shield. This will create a shell around the model which is likely to wipe a second nozzle if it's at the same height as the first nozzle.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"resolve": "any(extruderValues('ooze_shield_enabled'))",
|
"resolve": "any(extruderValues('ooze_shield_enabled'))",
|
||||||
"enabled": "machine_extruder_count > 1",
|
"enabled": "extruders_enabled_count > 1",
|
||||||
"default_value": false,
|
"default_value": false,
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
|
@ -4997,7 +5011,7 @@
|
||||||
"description": "Remove areas where multiple meshes are overlapping with each other. This may be used if merged dual material objects overlap with each other.",
|
"description": "Remove areas where multiple meshes are overlapping with each other. This may be used if merged dual material objects overlap with each other.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"default_value": true,
|
"default_value": true,
|
||||||
"value": "machine_extruder_count > 1",
|
"value": "extruders_enabled_count > 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true
|
"settable_per_meshgroup": true
|
||||||
|
@ -5044,7 +5058,7 @@
|
||||||
"one_at_a_time": "One at a Time"
|
"one_at_a_time": "One at a Time"
|
||||||
},
|
},
|
||||||
"default_value": "all_at_once",
|
"default_value": "all_at_once",
|
||||||
"enabled": "machine_extruder_count == 1",
|
"enabled": "extruders_enabled_count == 1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
|
|
|
@ -43,10 +43,10 @@
|
||||||
{
|
{
|
||||||
"default_value":
|
"default_value":
|
||||||
[
|
[
|
||||||
[ -29, 6.1 ],
|
[ -41.9, -45.8 ],
|
||||||
[ -29, -33.9 ],
|
[ -41.9, 33.9 ],
|
||||||
[ 71, 6.1 ],
|
[ 59.9, 33.9 ],
|
||||||
[ 71, -33.9 ]
|
[ 59.9, -45.8 ]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"machine_gcode_flavor": { "default_value": "Griffin" },
|
"machine_gcode_flavor": { "default_value": "Griffin" },
|
||||||
|
|
|
@ -194,14 +194,31 @@ UM.MainWindow
|
||||||
NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index }
|
NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index }
|
||||||
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index }
|
MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index }
|
||||||
|
|
||||||
MenuSeparator {
|
MenuSeparator
|
||||||
|
{
|
||||||
visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials
|
visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem {
|
MenuItem
|
||||||
|
{
|
||||||
text: catalog.i18nc("@action:inmenu", "Set as Active Extruder")
|
text: catalog.i18nc("@action:inmenu", "Set as Active Extruder")
|
||||||
onTriggered: Cura.ExtruderManager.setActiveExtruderIndex(model.index)
|
onTriggered: Cura.MachineManager.setExtruderIndex(model.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@action:inmenu", "Enable Extruder")
|
||||||
|
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true)
|
||||||
|
visible: !Cura.MachineManager.getExtruder(model.index).isEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
|
||||||
|
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
|
||||||
|
visible: Cura.MachineManager.getExtruder(model.index).isEnabled
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
onObjectAdded: settingsMenu.insertItem(index, object)
|
onObjectAdded: settingsMenu.insertItem(index, object)
|
||||||
onObjectRemoved: settingsMenu.removeItem(object)
|
onObjectRemoved: settingsMenu.removeItem(object)
|
||||||
|
|
|
@ -19,7 +19,7 @@ Button
|
||||||
iconSource: UM.Theme.getIcon("extruder_button")
|
iconSource: UM.Theme.getIcon("extruder_button")
|
||||||
|
|
||||||
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1
|
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1
|
||||||
enabled: UM.Selection.hasSelection
|
enabled: UM.Selection.hasSelection && extruder.stack.isEnabled
|
||||||
|
|
||||||
property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button");
|
property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button");
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,39 @@ SettingItem
|
||||||
id: control
|
id: control
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
model: Cura.ExtrudersModel { onModelChanged: control.color = getItem(control.currentIndex).color }
|
model: Cura.ExtrudersModel
|
||||||
|
{
|
||||||
|
onModelChanged: {
|
||||||
|
control.color = getItem(control.currentIndex).color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
textRole: "name"
|
textRole: "name"
|
||||||
|
|
||||||
|
// knowing the extruder position, try to find the item index in the model
|
||||||
|
function getIndexByPosition(position)
|
||||||
|
{
|
||||||
|
for (var item_index in model.items)
|
||||||
|
{
|
||||||
|
var item = model.getItem(item_index)
|
||||||
|
if (item.index == position)
|
||||||
|
{
|
||||||
|
return item_index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
onActivated:
|
onActivated:
|
||||||
{
|
{
|
||||||
forceActiveFocus();
|
if (model.getItem(index).enabled)
|
||||||
propertyProvider.setPropertyValue("value", model.getItem(index).index);
|
{
|
||||||
|
forceActiveFocus();
|
||||||
|
propertyProvider.setPropertyValue("value", model.getItem(index).index);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
currentIndex = propertyProvider.properties.value; // keep the old value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveFocusChanged:
|
onActiveFocusChanged:
|
||||||
|
@ -64,6 +89,23 @@ SettingItem
|
||||||
value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : ""
|
value: control.currentText != "" ? control.model.getItem(control.currentIndex).color : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binding
|
||||||
|
{
|
||||||
|
target: control
|
||||||
|
property: "currentIndex"
|
||||||
|
value:
|
||||||
|
{
|
||||||
|
if(propertyProvider.properties.value == -1)
|
||||||
|
{
|
||||||
|
return control.getIndexByPosition(Cura.MachineManager.defaultExtruderPosition);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
indicator: UM.RecolorImage
|
indicator: UM.RecolorImage
|
||||||
{
|
{
|
||||||
id: downArrow
|
id: downArrow
|
||||||
|
@ -173,7 +215,13 @@ SettingItem
|
||||||
{
|
{
|
||||||
text: model.name
|
text: model.name
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
color: UM.Theme.getColor("setting_control_text")
|
color: {
|
||||||
|
if (model.enabled) {
|
||||||
|
UM.Theme.getColor("setting_control_text")
|
||||||
|
} else {
|
||||||
|
UM.Theme.getColor("action_button_disabled_text");
|
||||||
|
}
|
||||||
|
}
|
||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
|
@ -91,10 +91,39 @@ Column
|
||||||
exclusiveGroup: extruderMenuGroup
|
exclusiveGroup: extruderMenuGroup
|
||||||
checked: base.currentExtruderIndex == index
|
checked: base.currentExtruderIndex == index
|
||||||
|
|
||||||
onClicked:
|
MouseArea
|
||||||
{
|
{
|
||||||
forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
|
anchors.fill: parent
|
||||||
Cura.ExtruderManager.setActiveExtruderIndex(index);
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: {
|
||||||
|
switch (mouse.button) {
|
||||||
|
case Qt.LeftButton:
|
||||||
|
forceActiveFocus(); // Changing focus applies the currently-being-typed values so it can change the displayed setting values.
|
||||||
|
Cura.ExtruderManager.setActiveExtruderIndex(index);
|
||||||
|
break;
|
||||||
|
case Qt.RightButton:
|
||||||
|
extruderMenu.popup();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu
|
||||||
|
{
|
||||||
|
id: extruderMenu
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: catalog.i18nc("@action:inmenu", "Enable Extruder")
|
||||||
|
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true)
|
||||||
|
visible: !Cura.MachineManager.getExtruder(model.index).isEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
|
||||||
|
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
|
||||||
|
visible: Cura.MachineManager.getExtruder(model.index).isEnabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
style: ButtonStyle
|
style: ButtonStyle
|
||||||
|
@ -114,6 +143,18 @@ Column
|
||||||
Behavior on color { ColorAnimation { duration: 50; } }
|
Behavior on color { ColorAnimation { duration: 50; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buttonColor(index) {
|
||||||
|
var extruder = Cura.MachineManager.getExtruder(index);
|
||||||
|
if (extruder.isEnabled) {
|
||||||
|
return (
|
||||||
|
control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") :
|
||||||
|
control.hovered ? UM.Theme.getColor("action_button_hovered_text") :
|
||||||
|
UM.Theme.getColor("action_button_text");
|
||||||
|
} else {
|
||||||
|
return UM.Theme.getColor("action_button_disabled_text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
id: extruderButtonFace
|
id: extruderButtonFace
|
||||||
|
@ -131,9 +172,7 @@ Column
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") :
|
color: buttonColor(index)
|
||||||
control.hovered ? UM.Theme.getColor("action_button_hovered_text") :
|
|
||||||
UM.Theme.getColor("action_button_text")
|
|
||||||
|
|
||||||
font: UM.Theme.getFont("large_nonbold")
|
font: UM.Theme.getFont("large_nonbold")
|
||||||
text: catalog.i18nc("@label", "Extruder")
|
text: catalog.i18nc("@label", "Extruder")
|
||||||
|
@ -176,9 +215,7 @@ Column
|
||||||
id: extruderNumberText
|
id: extruderNumberText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: index + 1;
|
text: index + 1;
|
||||||
color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") :
|
color: buttonColor(index)
|
||||||
control.hovered ? UM.Theme.getColor("action_button_hovered_text") :
|
|
||||||
UM.Theme.getColor("action_button_text")
|
|
||||||
font: UM.Theme.getFont("default_bold")
|
font: UM.Theme.getFont("default_bold")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ Item
|
||||||
property Action configureSettings;
|
property Action configureSettings;
|
||||||
property variant minimumPrintTime: PrintInformation.minimumPrintTime;
|
property variant minimumPrintTime: PrintInformation.minimumPrintTime;
|
||||||
property variant maximumPrintTime: PrintInformation.maximumPrintTime;
|
property variant maximumPrintTime: PrintInformation.maximumPrintTime;
|
||||||
property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || machineExtruderCount.properties.value == 1
|
property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1
|
||||||
|
|
||||||
Component.onCompleted: PrintInformation.enabled = true
|
Component.onCompleted: PrintInformation.enabled = true
|
||||||
Component.onDestruction: PrintInformation.enabled = false
|
Component.onDestruction: PrintInformation.enabled = false
|
||||||
|
@ -67,10 +67,8 @@ Item
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: Cura.MachineManager
|
target: Cura.QualityProfilesDropDownMenuModel
|
||||||
onActiveQualityChanged: qualityModel.update()
|
onItemsChanged: qualityModel.update()
|
||||||
onActiveMaterialChanged: qualityModel.update()
|
|
||||||
onActiveVariantChanged: qualityModel.update()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
@ -806,7 +804,7 @@ Item
|
||||||
ComboBox
|
ComboBox
|
||||||
{
|
{
|
||||||
id: supportExtruderCombobox
|
id: supportExtruderCombobox
|
||||||
visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)
|
visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)
|
||||||
model: extruderModel
|
model: extruderModel
|
||||||
|
|
||||||
property string color_override: "" // for manually setting values
|
property string color_override: "" // for manually setting values
|
||||||
|
@ -821,11 +819,11 @@ Item
|
||||||
textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started
|
textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started
|
||||||
|
|
||||||
anchors.top: enableSupportCheckBox.bottom
|
anchors.top: enableSupportCheckBox.bottom
|
||||||
anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0
|
anchors.topMargin: ((supportEnabled.properties.value === "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0
|
||||||
anchors.left: infillCellRight.left
|
anchors.left: infillCellRight.left
|
||||||
|
|
||||||
width: Math.round(UM.Theme.getSize("sidebar").width * .55)
|
width: Math.round(UM.Theme.getSize("sidebar").width * .55)
|
||||||
height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0
|
height: ((supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0
|
||||||
|
|
||||||
Behavior on height { NumberAnimation { duration: 100 } }
|
Behavior on height { NumberAnimation { duration: 100 } }
|
||||||
|
|
||||||
|
@ -1022,9 +1020,9 @@ Item
|
||||||
|
|
||||||
UM.SettingPropertyProvider
|
UM.SettingPropertyProvider
|
||||||
{
|
{
|
||||||
id: machineExtruderCount
|
id: extrudersEnabledCount
|
||||||
containerStackId: Cura.MachineManager.activeMachineId
|
containerStackId: Cura.MachineManager.activeMachineId
|
||||||
key: "machine_extruder_count"
|
key: "extruders_enabled_count"
|
||||||
watchedProperties: [ "value" ]
|
watchedProperties: [ "value" ]
|
||||||
storeIndex: 0
|
storeIndex: 0
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue