diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index e1386e8749..935ec94054 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -76,9 +76,28 @@ class CuraEngineBackend(QObject, Backend): self._scene = Application.getInstance().getController().getScene() self._scene.sceneChanged.connect(self._onSceneChanged) - # trigger auto-slicing on error check finished + # Triggers for auto-slicing. Auto-slicing is triggered as follows: + # - auto-slicing is started with a timer + # - whenever there is a value change, we start the timer + # - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the + # auto-slicing timer when that error check is finished + # If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer, + # and only wait for the error check to be finished to start the auto-slicing timer again. + # + self._global_container_stack = None + Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) + self._onGlobalStackChanged() + + self._active_extruder_stack = None + ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) + self._onActiveExtruderChanged() + Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished) + # A flag indicating if an error check was scheduled + # If so, we will stop the auto-slice timer and start upon the error check + self._is_error_check_scheduled = False + # Listeners for receiving messages from the back-end. self._message_handlers["cura.proto.Layer"] = self._onLayerMessage self._message_handlers["cura.proto.LayerOptimized"] = self._onOptimizedLayerMessage @@ -271,17 +290,16 @@ class CuraEngineBackend(QObject, Backend): return if job.getResult() == StartSliceJob.StartJobResult.SettingError: - global_container_stack = Application.getInstance().getGlobalContainerStack() if Application.getInstance().platformActivity: - extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId())) + extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) error_keys = [] for extruder in extruders: error_keys.extend(extruder.getErrorKeys()) if not extruders: - error_keys = global_container_stack.getErrorKeys() + error_keys = self._global_container_stack.getErrorKeys() error_labels = set() for key in error_keys: - for stack in [global_container_stack] + extruders: #Search all container stacks for the definition of this setting. Some are only in an extruder stack. + for stack in [self._global_container_stack] + extruders: #Search all container stacks for the definition of this setting. Some are only in an extruder stack. definitions = stack.getBottom().findDefinitions(key = key) if definitions: break #Found it! No need to continue search. @@ -420,7 +438,21 @@ class CuraEngineBackend(QObject, Backend): # With manually having to slice, we want to clear the old invalid layer data. self._clearLayerData() + ## A setting has changed, so check if we must reslice. + # \param instance The setting instance that has changed. + # \param property The property of the setting instance that has changed. + def _onSettingChanged(self, instance, property): + if property == "value": # Only reslice if the value has changed. + self.needsSlicing() + self._onChanged() + + elif property == "validationState": + if self._use_timer: + self._is_error_check_scheduled = True + self._change_timer.stop() + def _onStackErrorCheckFinished(self): + self._is_error_check_scheduled = False self.needsSlicing() self._onChanged() @@ -515,7 +547,12 @@ class CuraEngineBackend(QObject, Backend): def _onChanged(self, *args, **kwargs): self.needsSlicing() if self._use_timer: - self._change_timer.start() + # if the error check is scheduled, wait for the error check finish signal to trigger auto-slice, + # otherwise business as usual + if self._is_error_check_scheduled: + self._change_timer.stop() + else: + self._change_timer.start() ## Called when the back-end connects to the front-end. def _onBackendConnected(self): @@ -574,6 +611,44 @@ class CuraEngineBackend(QObject, Backend): if self._process: Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait()) self._process = None + ## Called when the global container stack changes + + def _onGlobalStackChanged(self): + if self._global_container_stack: + self._global_container_stack.propertyChanged.disconnect(self._onSettingChanged) + self._global_container_stack.containersChanged.disconnect(self._onChanged) + extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) + + if extruders: + for extruder in extruders: + extruder.propertyChanged.disconnect(self._onSettingChanged) + + self._global_container_stack = Application.getInstance().getGlobalContainerStack() + + if self._global_container_stack: + self._global_container_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed. + self._global_container_stack.containersChanged.connect(self._onChanged) + extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) + if extruders: + for extruder in extruders: + extruder.propertyChanged.connect(self._onSettingChanged) + self._onActiveExtruderChanged() + self._onChanged() + + def _onActiveExtruderChanged(self): + if self._global_container_stack: + # Connect all extruders of the active machine. This might cause a few connects that have already happend, + # but that shouldn't cause issues as only new / unique connections are added. + extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) + if extruders: + for extruder in extruders: + extruder.propertyChanged.connect(self._onSettingChanged) + if self._active_extruder_stack: + self._active_extruder_stack.containersChanged.disconnect(self._onChanged) + + self._active_extruder_stack = ExtruderManager.getInstance().getActiveExtruderStack() + if self._active_extruder_stack: + self._active_extruder_stack.containersChanged.connect(self._onChanged) def _onProcessLayersFinished(self, job): self._process_layers_job = None