diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index be97fbc161..1a204c020b 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -365,7 +365,7 @@ class MaterialManager(QObject): nozzle_name = None if extruder_stack.variant.getId() != "empty_variant": nozzle_name = extruder_stack.variant.getName() - diameter = extruder_stack.approximateMaterialDiameter + diameter = extruder_stack.getApproximateMaterialDiameter() # Fetch the available materials (ContainerNode) for the current active machine and extruder setup. return self.getAvailableMaterials(machine.definition, nozzle_name, buildplate_name, diameter) @@ -478,12 +478,22 @@ class MaterialManager(QObject): buildplate_name = global_stack.getBuildplateName() machine_definition = global_stack.definition - if extruder_definition is None: - extruder_definition = global_stack.extruders[position].definition - if extruder_definition and parseBool(global_stack.getMetaDataEntry("has_materials", False)): - # At this point the extruder_definition is not None - material_diameter = extruder_definition.getProperty("material_diameter", "value") + # The extruder-compatible material diameter in the extruder definition may not be the correct value because + # the user can change it in the definition_changes container. + if extruder_definition is None: + extruder_stack_or_definition = global_stack.extruders[position] + is_extruder_stack = True + else: + extruder_stack_or_definition = extruder_definition + is_extruder_stack = False + + if extruder_stack_or_definition and parseBool(global_stack.getMetaDataEntry("has_materials", False)): + if is_extruder_stack: + material_diameter = extruder_stack_or_definition.getCompatibleMaterialDiameter() + else: + material_diameter = extruder_stack_or_definition.getProperty("material_diameter", "value") + if isinstance(material_diameter, SettingFunction): material_diameter = material_diameter(global_stack) approximate_material_diameter = str(round(material_diameter)) diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index be9f8be1ed..ef2e760330 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -64,9 +64,11 @@ class BaseMaterialsModel(ListModel): if self._extruder_stack is not None: self._extruder_stack.pyqtContainersChanged.disconnect(self._update) + self._extruder_stack.approximateMaterialDiameterChanged.disconnect(self._update) self._extruder_stack = global_stack.extruders.get(str(self._extruder_position)) if self._extruder_stack is not None: self._extruder_stack.pyqtContainersChanged.connect(self._update) + self._extruder_stack.approximateMaterialDiameterChanged.connect(self._update) # Force update the model when the extruder stack changes self._update() diff --git a/cura/Settings/CuraStackBuilder.py b/cura/Settings/CuraStackBuilder.py index 58109d3a8d..95aa364a2e 100644 --- a/cura/Settings/CuraStackBuilder.py +++ b/cura/Settings/CuraStackBuilder.py @@ -129,7 +129,7 @@ class CuraStackBuilder: # get material container for extruders material_container = application.empty_material_container - material_node = material_manager.getDefaultMaterial(global_stack, extruder_position, extruder_variant_name, + material_node = material_manager.getDefaultMaterial(global_stack, str(extruder_position), extruder_variant_name, extruder_definition = extruder_definition) if material_node and material_node.getContainer(): material_container = material_node.getContainer() diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index ca687e358b..d7faedb71c 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -65,16 +65,33 @@ class ExtruderStack(CuraContainerStack): def getLoadingPriority(cls) -> int: return 3 + compatibleMaterialDiameterChanged = pyqtSignal() + ## Return the filament diameter that the machine requires. # # If the machine has no requirement for the diameter, -1 is returned. # \return The filament diameter for the printer - @property - def materialDiameter(self) -> float: + def getCompatibleMaterialDiameter(self) -> float: context = PropertyEvaluationContext(self) context.context["evaluate_from_container_index"] = _ContainerIndexes.Variant - return self.getProperty("material_diameter", "value", context = context) + return float(self.getProperty("material_diameter", "value", context = context)) + + def setCompatibleMaterialDiameter(self, value: float) -> None: + old_approximate_diameter = self.getApproximateMaterialDiameter() + if self.getCompatibleMaterialDiameter() != value: + self.definitionChanges.setProperty("material_diameter", "value", value) + self.compatibleMaterialDiameterChanged.emit() + + # Emit approximate diameter changed signal if needed + if old_approximate_diameter != self.getApproximateMaterialDiameter(): + self.approximateMaterialDiameterChanged.emit() + + compatibleMaterialDiameter = pyqtProperty(float, fset = setCompatibleMaterialDiameter, + fget = getCompatibleMaterialDiameter, + notify = compatibleMaterialDiameterChanged) + + approximateMaterialDiameterChanged = pyqtSignal() ## Return the approximate filament diameter that the machine requires. # @@ -84,9 +101,11 @@ class ExtruderStack(CuraContainerStack): # If the machine has no requirement for the diameter, -1 is returned. # # \return The approximate filament diameter for the printer - @pyqtProperty(float) - def approximateMaterialDiameter(self) -> float: - return round(float(self.materialDiameter)) + def getApproximateMaterialDiameter(self) -> float: + return round(self.getCompatibleMaterialDiameter()) + + approximateMaterialDiameter = pyqtProperty(float, fget = getApproximateMaterialDiameter, + notify = approximateMaterialDiameterChanged) ## Overridden from ContainerStack # diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b935237742..f321ce94a6 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1279,11 +1279,7 @@ class MachineManager(QObject): if extruder.variant.getId() != empty_variant_container.getId(): current_nozzle_name = extruder.variant.getMetaDataEntry("name") - from UM.Settings.Interfaces import PropertyEvaluationContext - from cura.Settings.CuraContainerStack import _ContainerIndexes - context = PropertyEvaluationContext(extruder) - context.context["evaluate_from_container_index"] = _ContainerIndexes.DefinitionChanges - material_diameter = extruder.getProperty("material_diameter", "value", context) + material_diameter = extruder.getCompatibleMaterialDiameter() candidate_materials = self._material_manager.getAvailableMaterials( self._global_container_stack.definition, current_nozzle_name, @@ -1418,7 +1414,7 @@ class MachineManager(QObject): position = str(position) extruder_stack = self._global_container_stack.extruders[position] nozzle_name = extruder_stack.variant.getName() - material_diameter = extruder_stack.approximateMaterialDiameter + material_diameter = extruder_stack.getApproximateMaterialDiameter() material_node = self._material_manager.getMaterialNode(machine_definition_id, nozzle_name, buildplate_name, material_diameter, root_material_id) self.setMaterial(position, material_node) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 429d4ab7d4..e994e1a817 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -926,7 +926,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): build_plate_id = global_stack.variant.getId() # get material diameter of this extruder - machine_material_diameter = extruder_stack.materialDiameter + machine_material_diameter = extruder_stack.getCompatibleMaterialDiameter() material_node = material_manager.getMaterialNode(global_stack.definition.getId(), extruder_stack.variant.getName(), build_plate_id, diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index 6c95dc2c92..5109aa05cb 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -408,6 +408,10 @@ Cura.MachineAction manager.updateMaterialForDiameter(settingsTabs.currentIndex - 1); } } + function setValueFunction(value) + { + Cura.MachineManager.activeStack.compatibleMaterialDiameter = value + } property bool isExtruderSetting: true } @@ -564,6 +568,7 @@ Cura.MachineAction property bool _forceUpdateOnChange: (typeof(forceUpdateOnChange) === 'undefined') ? false : forceUpdateOnChange property string _label: (typeof(label) === 'undefined') ? "" : label property string _tooltip: (typeof(tooltip) === 'undefined') ? propertyProvider.properties.description : tooltip + property var _setValueFunction: (typeof(setValueFunction) === 'undefined') ? undefined : setValueFunction UM.SettingPropertyProvider { @@ -616,14 +621,32 @@ Cura.MachineAction { if (propertyProvider && text != propertyProvider.properties.value) { - propertyProvider.setPropertyValue("value", text); + // For some properties like the extruder-compatible material diameter, they need to + // trigger many updates, such as the available materials, the current material may + // need to be switched, etc. Although setting the diameter can be done directly via + // the provider, all the updates that need to be triggered then need to depend on + // the metadata update, a signal that can be fired way too often. The update functions + // can have if-checks to filter out the irrelevant updates, but still it incurs unnecessary + // overhead. + // The ExtruderStack class has a dedicated function for this call "setCompatibleMaterialDiameter()", + // and it triggers the diameter update signals only when it is needed. Here it is optionally + // choose to use setCompatibleMaterialDiameter() or other more specific functions that + // are available. + if (_setValueFunction !== undefined) + { + _setValueFunction(text) + } + else + { + propertyProvider.setPropertyValue("value", text) + } if(_forceUpdateOnChange) { - manager.forceUpdate(); + manager.forceUpdate() } if(_afterOnEditingFinished) { - _afterOnEditingFinished(); + _afterOnEditingFinished() } } }