def _settingIsOverwritingInheritance(self, key: str, stack: ContainerStack = None) -> bool: """Check if a setting has an inheritance function that is overwritten""" has_setting_function = False if not stack: stack = self._active_container_stack if not stack: # No active container stack yet! return False if self._active_container_stack is None: return False all_keys = self._active_container_stack.getAllKeys() containers = [] # type: List[ContainerInterface] has_user_state = stack.getProperty(key, "state") == InstanceState.User """Check if the setting has a user state. If not, it is never overwritten.""" if not has_user_state: return False # If a setting is not enabled, don't label it as overwritten (It's never visible anyway). if not stack.getProperty(key, "enabled"): return False user_container = stack.getTop() """Also check if the top container is not a setting function (this happens if the inheritance is restored).""" if user_container and isinstance(user_container.getProperty(key, "value"), SettingFunction): return False ## Mash all containers for all the stacks together. while stack: containers.extend(stack.getContainers()) stack = stack.getNextStack() has_non_function_value = False for container in containers: try: value = container.getProperty(key, "value") except AttributeError: continue if value is not None: # If a setting doesn't use any keys, it won't change it's value, so treat it as if it's a fixed value has_setting_function = isinstance(value, SettingFunction) if has_setting_function: for setting_key in value.getUsedSettingKeys(): if setting_key in all_keys: break # We found an actual setting. So has_setting_function can remain true else: # All of the setting_keys turned out to not be setting keys at all! # This can happen due enum keys also being marked as settings. has_setting_function = False if has_setting_function is False: has_non_function_value = True continue if has_setting_function: break # There is a setting function somewhere, stop looking deeper. return has_setting_function and has_non_function_value
def _buildExtruderMessage(self, stack: ContainerStack) -> None: """Create extruder message from stack""" message = self._slice_message.addRepeatedMessage("extruders") message.id = int(stack.getMetaDataEntry("position")) if not self._all_extruders_settings: self._cacheAllExtruderSettings() if self._all_extruders_settings is None: return extruder_nr = stack.getProperty("extruder_nr", "value") settings = self._all_extruders_settings[str(extruder_nr)].copy() # Also send the material GUID. This is a setting in fdmprinter, but we have no interface for it. settings["material_guid"] = stack.material.getMetaDataEntry("GUID", "") # Replace the setting tokens in start and end g-code. extruder_nr = stack.getProperty("extruder_nr", "value") settings["machine_extruder_start_code"] = self._expandGcodeTokens(settings["machine_extruder_start_code"], extruder_nr) settings["machine_extruder_end_code"] = self._expandGcodeTokens(settings["machine_extruder_end_code"], extruder_nr) global_definition = cast(ContainerInterface, cast(ContainerStack, stack.getNextStack()).getBottom()) own_definition = cast(ContainerInterface, stack.getBottom()) for key, value in settings.items(): # Do not send settings that are not settable_per_extruder. # Since these can only be set in definition files, we only have to ask there. if not global_definition.getProperty(key, "settable_per_extruder") and \ not own_definition.getProperty(key, "settable_per_extruder"): continue setting = message.getMessage("settings").addRepeatedMessage("settings") setting.name = key setting.value = str(value).encode("utf-8") Job.yieldThread()
def _settingIsOverwritingInheritance(self, key: str, stack: ContainerStack = None) -> bool: has_setting_function = False if not stack: stack = self._active_container_stack if not stack: #No active container stack yet! return False containers = [] ## Check if the setting has a user state. If not, it is never overwritten. has_user_state = stack.getProperty(key, "state") == InstanceState.User if not has_user_state: return False ## If a setting is not enabled, don't label it as overwritten (It's never visible anyway). if not stack.getProperty(key, "enabled"): return False ## Also check if the top container is not a setting function (this happens if the inheritance is restored). if isinstance(stack.getTop().getProperty(key, "value"), SettingFunction): return False ## Mash all containers for all the stacks together. while stack: containers.extend(stack.getContainers()) stack = stack.getNextStack() has_non_function_value = False for container in containers: try: value = container.getProperty(key, "value") except AttributeError: continue if value is not None: # If a setting doesn't use any keys, it won't change it's value, so treat it as if it's a fixed value has_setting_function = isinstance(value, SettingFunction) if has_setting_function: for setting_key in value.getUsedSettingKeys(): if setting_key in self._active_container_stack.getAllKeys(): break # We found an actual setting. So has_setting_function can remain true else: # All of the setting_keys turned out to not be setting keys at all! # This can happen due enum keys also being marked as settings. has_setting_function = False if has_setting_function is False: has_non_function_value = True continue if has_setting_function: break # There is a setting function somewhere, stop looking deeper. return has_setting_function and has_non_function_value
class SettingOverrideDecorator(SceneNodeDecorator): ## Event indicating that the user selected a different extruder. activeExtruderChanged = Signal() def __init__(self): super().__init__() self._stack = ContainerStack(stack_id = id(self)) self._stack.setDirty(False) # This stack does not need to be saved. self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) if cura.Settings.ExtruderManager.getInstance().extruderCount > 1: self._extruder_stack = cura.Settings.ExtruderManager.getInstance().getExtruderStack(0).getId() else: self._extruder_stack = None self._stack.propertyChanged.connect(self._onSettingChanged) ContainerRegistry.getInstance().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack) self.activeExtruderChanged.connect(self._updateNextStack) self._updateNextStack() def __deepcopy__(self, memo): ## Create a fresh decorator object deep_copy = SettingOverrideDecorator() ## Copy the instance deep_copy._instance = copy.deepcopy(self._instance, memo) # Properly set the right extruder on the copy deep_copy.setActiveExtruder(self._extruder_stack) ## Set the copied instance as the first (and only) instance container of the stack. deep_copy._stack.replaceContainer(0, deep_copy._instance) return deep_copy ## Gets the currently active extruder to print this object with. # # \return An extruder's container stack. def getActiveExtruder(self): return self._extruder_stack ## Gets the currently active extruders position # # \return An extruder's position, or None if no position info is available. def getActiveExtruderPosition(self): containers = ContainerRegistry.getInstance().findContainers(id = self.getActiveExtruder()) if containers: container_stack = containers[0] return container_stack.getMetaDataEntry("position", default=None) def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function if property_name == "value": # Only reslice if the value has changed. Application.getInstance().getBackend().forceSlice() ## Makes sure that the stack upon which the container stack is placed is # kept up to date. def _updateNextStack(self): if self._extruder_stack: extruder_stack = ContainerRegistry.getInstance().findContainerStacks(id = self._extruder_stack) if extruder_stack: if self._stack.getNextStack(): old_extruder_stack_id = self._stack.getNextStack().getId() else: old_extruder_stack_id = "" self._stack.setNextStack(extruder_stack[0]) if self._stack.getNextStack().getId() != old_extruder_stack_id: #Only reslice if the extruder changed. Application.getInstance().getBackend().forceSlice() else: UM.Logger.log("e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack) else: self._stack.setNextStack(Application.getInstance().getGlobalContainerStack()) ## Changes the extruder with which to print this node. # # \param extruder_stack_id The new extruder stack to print with. def setActiveExtruder(self, extruder_stack_id): self._extruder_stack = extruder_stack_id self._updateNextStack() self.activeExtruderChanged.emit() def getStack(self): return self._stack
class SettingOverrideDecorator(SceneNodeDecorator): ## Event indicating that the user selected a different extruder. activeExtruderChanged = Signal() def __init__(self): super().__init__() self._stack = ContainerStack(stack_id=id(self)) self._stack.setDirty(False) # This stack does not need to be saved. self._instance = InstanceContainer( container_id="SettingOverrideInstanceContainer") self._stack.addContainer(self._instance) if ExtruderManager.getInstance().extruderCount > 1: self._extruder_stack = ExtruderManager.getInstance( ).getExtruderStack(0).getId() else: self._extruder_stack = None self._stack.propertyChanged.connect(self._onSettingChanged) ContainerRegistry.getInstance().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect( self._updateNextStack) self.activeExtruderChanged.connect(self._updateNextStack) self._updateNextStack() def __deepcopy__(self, memo): ## Create a fresh decorator object deep_copy = SettingOverrideDecorator() ## Copy the instance deep_copy._instance = copy.deepcopy(self._instance, memo) # Properly set the right extruder on the copy deep_copy.setActiveExtruder(self._extruder_stack) ## Set the copied instance as the first (and only) instance container of the stack. deep_copy._stack.replaceContainer(0, deep_copy._instance) return deep_copy ## Gets the currently active extruder to print this object with. # # \return An extruder's container stack. def getActiveExtruder(self): return self._extruder_stack ## Gets the signal that emits if the active extruder changed. # # This can then be accessed via a decorator. def getActiveExtruderChangedSignal(self): return self.activeExtruderChanged ## Gets the currently active extruders position # # \return An extruder's position, or None if no position info is available. def getActiveExtruderPosition(self): containers = ContainerRegistry.getInstance().findContainers( id=self.getActiveExtruder()) if containers: container_stack = containers[0] return container_stack.getMetaDataEntry("position", default=None) def _onSettingChanged( self, instance, property_name): # Reminder: 'property' is a built-in function if property_name == "value": # Only reslice if the value has changed. Application.getInstance().getBackend().forceSlice() ## Makes sure that the stack upon which the container stack is placed is # kept up to date. def _updateNextStack(self): if self._extruder_stack: extruder_stack = ContainerRegistry.getInstance( ).findContainerStacks(id=self._extruder_stack) if extruder_stack: if self._stack.getNextStack(): old_extruder_stack_id = self._stack.getNextStack().getId() else: old_extruder_stack_id = "" self._stack.setNextStack(extruder_stack[0]) if self._stack.getNextStack().getId( ) != old_extruder_stack_id: #Only reslice if the extruder changed. Application.getInstance().getBackend().forceSlice() else: UM.Logger.log( "e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack) else: self._stack.setNextStack( Application.getInstance().getGlobalContainerStack()) ## Changes the extruder with which to print this node. # # \param extruder_stack_id The new extruder stack to print with. def setActiveExtruder(self, extruder_stack_id): self._extruder_stack = extruder_stack_id self._updateNextStack() self.activeExtruderChanged.emit() def getStack(self): return self._stack