123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- # Copyright (c) 2016 Ultimaker B.V.
- # Cura is released under the terms of the AGPLv3 or higher.
- from PyQt5.QtCore import pyqtProperty, pyqtSignal
- from UM.FlameProfiler import pyqtSlot
- from cura.MachineAction import MachineAction
- from UM.Application import Application
- from UM.Settings.InstanceContainer import InstanceContainer
- from UM.Settings.ContainerRegistry import ContainerRegistry
- from UM.Settings.DefinitionContainer import DefinitionContainer
- from UM.Logger import Logger
- from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
- from cura.Settings.ExtruderManager import ExtruderManager
- import UM.i18n
- catalog = UM.i18n.i18nCatalog("cura")
- ## This action allows for certain settings that are "machine only") to be modified.
- # It automatically detects machine definitions that it knows how to change and attaches itself to those.
- class MachineSettingsAction(MachineAction):
- def __init__(self, parent = None):
- super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
- self._qml_url = "MachineSettingsAction.qml"
- self._global_container_stack = None
- self._container_index = 0
- self._extruder_container_index = 0
- self._container_registry = ContainerRegistry.getInstance()
- self._container_registry.containerAdded.connect(self._onContainerAdded)
- Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
- ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
- self._backend = Application.getInstance().getBackend()
- def _reset(self):
- if not self._global_container_stack:
- return
- # Make sure there is a definition_changes container to store the machine settings
- definition_changes_container = self._global_container_stack.findContainer({"type": "definition_changes"})
- if not definition_changes_container:
- definition_changes_container = self._createDefinitionChangesContainer(self._global_container_stack, self._global_container_stack.getName() + "_settings")
- # Notify the UI in which container to store the machine settings data
- container_index = self._global_container_stack.getContainerIndex(definition_changes_container)
- if container_index != self._container_index:
- self._container_index = container_index
- self.containerIndexChanged.emit()
- # Disable autoslicing while the machineaction is showing
- self._backend.disableTimer()
- @pyqtSlot()
- def onFinishAction(self):
- # Restore autoslicing when the machineaction is dismissed
- if self._backend.determineAutoSlicing():
- self._backend.tickle()
- def _onActiveExtruderStackChanged(self):
- extruder_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
- if not self._global_container_stack or not extruder_container_stack:
- return
- # Make sure there is a definition_changes container to store the machine settings
- definition_changes_container = extruder_container_stack.findContainer({"type": "definition_changes"})
- if not definition_changes_container:
- definition_changes_container = self._createDefinitionChangesContainer(extruder_container_stack, extruder_container_stack.getId() + "_settings")
- # Notify the UI in which container to store the machine settings data
- container_index = extruder_container_stack.getContainerIndex(definition_changes_container)
- if container_index != self._extruder_container_index:
- self._extruder_container_index = container_index
- self.extruderContainerIndexChanged.emit()
- def _createDefinitionChangesContainer(self, container_stack, container_name, container_index = None):
- definition_changes_container = InstanceContainer(container_name)
- definition = container_stack.getBottom()
- definition_changes_container.setDefinition(definition)
- definition_changes_container.addMetaDataEntry("type", "definition_changes")
- self._container_registry.addContainer(definition_changes_container)
- # Insert definition_changes between the definition and the variant
- container_stack.insertContainer(-1, definition_changes_container)
- return definition_changes_container
- containerIndexChanged = pyqtSignal()
- @pyqtProperty(int, notify = containerIndexChanged)
- def containerIndex(self):
- return self._container_index
- extruderContainerIndexChanged = pyqtSignal()
- @pyqtProperty(int, notify = extruderContainerIndexChanged)
- def extruderContainerIndex(self):
- return self._extruder_container_index
- def _onContainerAdded(self, container):
- # Add this action as a supported action to all machine definitions
- if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
- Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
- def _onGlobalContainerChanged(self):
- self._global_container_stack = Application.getInstance().getGlobalContainerStack()
- # This additional emit is needed because we cannot connect a UM.Signal directly to a pyqtSignal
- self.globalContainerChanged.emit()
- globalContainerChanged = pyqtSignal()
- @pyqtProperty(int, notify = globalContainerChanged)
- def definedExtruderCount(self):
- if not self._global_container_stack:
- return 0
- return len(self._global_container_stack.getMetaDataEntry("machine_extruder_trains"))
- @pyqtSlot(int)
- def setMachineExtruderCount(self, extruder_count):
- machine_manager = Application.getInstance().getMachineManager()
- extruder_manager = ExtruderManager.getInstance()
- definition_changes_container = self._global_container_stack.findContainer({"type": "definition_changes"})
- if not self._global_container_stack or not definition_changes_container:
- return
- if extruder_count == self._global_container_stack.getProperty("machine_extruder_count", "value"):
- return
- extruder_material = None
- if extruder_count == 1 and machine_manager.hasMaterials:
- extruder_material = machine_manager.allActiveMaterialIds[machine_manager.activeStackId]
- definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count)
- self.forceUpdate()
- if extruder_count > 1:
- # multiextrusion; make sure one of these extruder stacks is active
- if extruder_manager.activeExtruderIndex == -1:
- extruder_manager.setActiveExtruderIndex(0)
- else:
- # single extrusion; make sure the machine stack is active
- if extruder_manager.activeExtruderIndex > -1:
- extruder_manager.setActiveExtruderIndex(-1);
- if extruder_material:
- # restore material on global stack
- # MachineManager._onGlobalContainerChanged removes the global material of multiextruder machines
- machine_manager.setActiveMaterial(extruder_material);
- @pyqtSlot()
- def forceUpdate(self):
- # Force rebuilding the build volume by reloading the global container stack.
- # This is a bit of a hack, but it seems quick enough.
- Application.getInstance().globalContainerStackChanged.emit()
- @pyqtSlot()
- def updateHasMaterialsMetadata(self):
- # Updates the has_materials metadata flag after switching gcode flavor
- if not self._global_container_stack:
- return
- definition = self._global_container_stack.getBottom()
- if definition.getProperty("machine_gcode_flavor", "value") == "UltiGCode" and not definition.getMetaDataEntry("has_materials", False):
- has_materials = self._global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
- material_container = self._global_container_stack.findContainer({"type": "material"})
- material_index = self._global_container_stack.getContainerIndex(material_container)
- if has_materials:
- if "has_materials" in self._global_container_stack.getMetaData():
- self._global_container_stack.setMetaDataEntry("has_materials", True)
- else:
- self._global_container_stack.addMetaDataEntry("has_materials", True)
- # Set the material container to a sane default
- if material_container.getId() == "empty_material":
- search_criteria = { "type": "material", "definition": "fdmprinter", "id": "*pla*" }
- containers = self._container_registry.findInstanceContainers(**search_criteria)
- if containers:
- self._global_container_stack.replaceContainer(material_index, containers[0])
- else:
- # The metadata entry is stored in an ini, and ini files are parsed as strings only.
- # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
- if "has_materials" in self._global_container_stack.getMetaData():
- self._global_container_stack.removeMetaDataEntry("has_materials")
- empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0]
- self._global_container_stack.replaceContainer(material_index, empty_material)
- Application.getInstance().globalContainerStackChanged.emit()
|