mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 06:05:52 +08:00
Merge branch 'master' into feature_accelerations_and_jerk_per_feature_settigns_rework
This commit is contained in:
commit
2932558a90
@ -1,13 +1,12 @@
|
||||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Backend.Backend import Backend
|
||||
from UM.Backend.Backend import Backend, BackendState
|
||||
from UM.Application import Application
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Preferences import Preferences
|
||||
from UM.Signal import Signal
|
||||
from UM.Logger import Logger
|
||||
from UM.Qt.Bindings.BackendProxy import BackendState #To determine the state of the slicing job.
|
||||
from UM.Message import Message
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Resources import Resources
|
||||
@ -56,8 +55,9 @@ class CuraEngineBackend(Backend):
|
||||
self._stored_layer_data = []
|
||||
|
||||
#Triggers for when to (re)start slicing:
|
||||
if Application.getInstance().getGlobalContainerStack():
|
||||
Application.getInstance().getGlobalContainerStack().propertyChanged.connect(self._onSettingChanged) #Note: Only starts slicing when the value changed.
|
||||
self._global_container_stack = None
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
self._onGlobalStackChanged()
|
||||
|
||||
#When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired.
|
||||
#This timer will group them up, and only slice for the last setting changed signal.
|
||||
@ -82,7 +82,7 @@ class CuraEngineBackend(Backend):
|
||||
self._always_restart = True #Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness.
|
||||
self._process_layers_job = None #The currently active job to process layers, or None if it is not processing layers.
|
||||
|
||||
self._message = None #Pop-up message that shows the slicing progress bar (or an error message).
|
||||
self._error_message = None #Pop-up message that shows errors.
|
||||
|
||||
self.backendQuit.connect(self._onBackendQuit)
|
||||
self.backendConnected.connect(self._onBackendConnected)
|
||||
@ -124,7 +124,7 @@ class CuraEngineBackend(Backend):
|
||||
def slice(self):
|
||||
self._stored_layer_data = []
|
||||
|
||||
if not self._enabled: #We shouldn't be slicing.
|
||||
if not self._enabled or not self._global_container_stack: #We shouldn't be slicing.
|
||||
return
|
||||
|
||||
if self._slicing: #We were already slicing. Stop the old job.
|
||||
@ -134,34 +134,11 @@ class CuraEngineBackend(Backend):
|
||||
self._process_layers_job.abort()
|
||||
self._process_layers_job = None
|
||||
|
||||
# #Don't slice if there is a setting with an error value.
|
||||
# stack = Application.getInstance().getGlobalContainerStack()
|
||||
# for key in stack.getAllKeys():
|
||||
# validation_state = stack.getProperty(key, "validationState")
|
||||
# #Only setting instances have a validation state, so settings which
|
||||
# #are not overwritten by any instance will have none. The property
|
||||
# #then, and only then, evaluates to None. We make the assumption that
|
||||
# #the definition defines the setting with a default value that is
|
||||
# #valid. Therefore we can allow both ValidatorState.Valid and None as
|
||||
# #allowable validation states.
|
||||
# #TODO: This assumption is wrong! If the definition defines an inheritance function that through inheritance evaluates to a disallowed value, a setting is still invalid even though it's default!
|
||||
# #TODO: Therefore we must also validate setting definitions.
|
||||
# if validation_state != None and validation_state != ValidatorState.Valid:
|
||||
# Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
|
||||
# if self._message: #Hide any old message before creating a new one.
|
||||
# self._message.hide()
|
||||
# self._message = None
|
||||
# self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
|
||||
# self._message.show()
|
||||
# return
|
||||
if self._error_message:
|
||||
self._error_message.hide()
|
||||
|
||||
self.processingProgress.emit(0.0)
|
||||
self.backendStateChange.emit(BackendState.NOT_STARTED)
|
||||
if self._message:
|
||||
self._message.setProgress(-1)
|
||||
else:
|
||||
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
||||
self._message.show()
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
|
||||
self._scene.gcode_list = []
|
||||
self._slicing = True
|
||||
@ -193,10 +170,6 @@ class CuraEngineBackend(Backend):
|
||||
except Exception as e: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||
Logger.log("d", "Exception occurred while trying to kill the engine %s", str(e))
|
||||
|
||||
if self._message:
|
||||
self._message.hide()
|
||||
self._message = None
|
||||
|
||||
## Event handler to call when the job to initiate the slicing process is
|
||||
# completed.
|
||||
#
|
||||
@ -209,15 +182,31 @@ class CuraEngineBackend(Backend):
|
||||
# Note that cancelled slice jobs can still call this method.
|
||||
if self._start_slice_job is job:
|
||||
self._start_slice_job = None
|
||||
if job.isCancelled() or job.getError() or job.getResult() != True:
|
||||
if self._message:
|
||||
self._message.hide()
|
||||
self._message = None
|
||||
|
||||
if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error:
|
||||
return
|
||||
else:
|
||||
# Preparation completed, send it to the backend.
|
||||
self._socket.sendMessage(job.getSettingsMessage())
|
||||
self._socket.sendMessage(job.getSliceMessage())
|
||||
|
||||
if job.getResult() == StartSliceJob.StartJobResult.SettingError:
|
||||
if Application.getInstance().getPlatformActivity:
|
||||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."), lifetime = 10)
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
else:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
return
|
||||
|
||||
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
|
||||
if Application.getInstance().getPlatformActivity:
|
||||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice. No suitable objects found."), lifetime = 10)
|
||||
self._error_message.show()
|
||||
self.backendStateChange.emit(BackendState.Error)
|
||||
else:
|
||||
self.backendStateChange.emit(BackendState.NotStarted)
|
||||
return
|
||||
|
||||
# Preparation completed, send it to the backend.
|
||||
self._socket.sendMessage(job.getSettingsMessage())
|
||||
self._socket.sendMessage(job.getSliceMessage())
|
||||
|
||||
## Listener for when the scene has changed.
|
||||
#
|
||||
@ -270,26 +259,18 @@ class CuraEngineBackend(Backend):
|
||||
#
|
||||
# \param message The protobuf message containing the slicing progress.
|
||||
def _onProgressMessage(self, message):
|
||||
if self._message:
|
||||
self._message.setProgress(round(message.amount * 100))
|
||||
|
||||
self.processingProgress.emit(message.amount)
|
||||
self.backendStateChange.emit(BackendState.PROCESSING)
|
||||
self.backendStateChange.emit(BackendState.Processing)
|
||||
|
||||
## Called when the engine sends a message that slicing is finished.
|
||||
#
|
||||
# \param message The protobuf message signalling that slicing is finished.
|
||||
def _onSlicingFinishedMessage(self, message):
|
||||
self.backendStateChange.emit(BackendState.DONE)
|
||||
self.backendStateChange.emit(BackendState.Done)
|
||||
self.processingProgress.emit(1.0)
|
||||
|
||||
self._slicing = False
|
||||
|
||||
if self._message:
|
||||
self._message.setProgress(100)
|
||||
self._message.hide()
|
||||
self._message = None
|
||||
|
||||
if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()):
|
||||
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data)
|
||||
self._process_layers_job.start()
|
||||
@ -326,7 +307,7 @@ class CuraEngineBackend(Backend):
|
||||
## Called when anything has changed to the stuff that needs to be sliced.
|
||||
#
|
||||
# This indicates that we should probably re-slice soon.
|
||||
def _onChanged(self):
|
||||
def _onChanged(self, *args, **kwargs):
|
||||
self._change_timer.start()
|
||||
|
||||
## Called when the back-end connects to the front-end.
|
||||
@ -376,3 +357,16 @@ class CuraEngineBackend(Backend):
|
||||
Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait())
|
||||
self._process = None
|
||||
self._createSocket()
|
||||
|
||||
## 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)
|
||||
|
||||
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)
|
||||
self._onChanged()
|
||||
|
@ -4,6 +4,7 @@
|
||||
import numpy
|
||||
from string import Formatter
|
||||
import traceback
|
||||
from enum import IntEnum
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Application import Application
|
||||
@ -12,8 +13,15 @@ from UM.Logger import Logger
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
|
||||
from UM.Settings.Validator import ValidatorState
|
||||
|
||||
from cura.OneAtATimeIterator import OneAtATimeIterator
|
||||
|
||||
class StartJobResult(IntEnum):
|
||||
Finished = 1
|
||||
Error = 2
|
||||
SettingError = 3
|
||||
NothingToSlice = 4
|
||||
|
||||
## Formatter class that handles token expansion in start/end gcod
|
||||
class GcodeStartEndFormatter(Formatter):
|
||||
@ -48,9 +56,19 @@ class StartSliceJob(Job):
|
||||
def run(self):
|
||||
stack = Application.getInstance().getGlobalContainerStack()
|
||||
if not stack:
|
||||
self.setResult(False)
|
||||
self.setResult(StartJobResult.Error)
|
||||
return
|
||||
|
||||
#Don't slice if there is a setting with an error value.
|
||||
for key in stack.getAllKeys():
|
||||
validation_state = stack.getProperty(key, "validationState")
|
||||
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
|
||||
Logger.log("w", "Setting %s is not valid, but %s. Aborting slicing.", key, validation_state)
|
||||
self.setResult(StartJobResult.SettingError)
|
||||
return
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
with self._scene.getSceneLock():
|
||||
# Remove old layer data.
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
@ -91,6 +109,7 @@ class StartSliceJob(Job):
|
||||
object_groups.append(temp_list)
|
||||
|
||||
if not object_groups:
|
||||
self.setResult(StartJobResult.NothingToSlice)
|
||||
return
|
||||
|
||||
self._buildGlobalSettingsMessage(stack)
|
||||
@ -116,7 +135,7 @@ class StartSliceJob(Job):
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
self.setResult(True)
|
||||
self.setResult(StartJobResult.Finished)
|
||||
|
||||
def cancel(self):
|
||||
super().cancel()
|
||||
@ -131,7 +150,7 @@ class StartSliceJob(Job):
|
||||
fmt = GcodeStartEndFormatter()
|
||||
return str(fmt.format(value, **settings)).encode("utf-8")
|
||||
except:
|
||||
Logger.log("w", "Unabled to do token replacement on start/end gcode %s", traceback.format_exc())
|
||||
Logger.logException("w", "Unable to do token replacement on start/end gcode")
|
||||
return str(value).encode("utf-8")
|
||||
|
||||
## Sends all global settings to the engine.
|
||||
|
@ -14,21 +14,33 @@ Rectangle {
|
||||
|
||||
property real progress: UM.Backend.progress;
|
||||
property int backendState: UM.Backend.state;
|
||||
|
||||
property bool activity: Printer.getPlatformActivity;
|
||||
//Behavior on progress { NumberAnimation { duration: 250; } }
|
||||
property int totalHeight: childrenRect.height + UM.Theme.getSize("default_margin").height
|
||||
property string fileBaseName
|
||||
property string statusText: {
|
||||
if(base.backendState == 0) {
|
||||
if(!activity) {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Please load a 3d model");
|
||||
} else {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Preparing to slice...");
|
||||
}
|
||||
} else if(base.backendState == 1) {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Slicing...");
|
||||
} else {
|
||||
return catalog.i18nc("@label:PrintjobStatus","Ready to ") + UM.OutputDeviceManager.activeDeviceShortDescription;
|
||||
property string statusText:
|
||||
{
|
||||
if(!activity)
|
||||
{
|
||||
return catalog.i18nc("@label:PrintjobStatus", "Please load a 3d model");
|
||||
}
|
||||
|
||||
if(base.backendState == 1)
|
||||
{
|
||||
return catalog.i18nc("@label:PrintjobStatus", "Preparing to slice...");
|
||||
}
|
||||
else if(base.backendState == 2)
|
||||
{
|
||||
return catalog.i18nc("@label:PrintjobStatus", "Slicing...");
|
||||
}
|
||||
else if(base.backendState == 3)
|
||||
{
|
||||
return catalog.i18nc("@label:PrintjobStatus %1 is target operation","Ready to %1").arg(UM.OutputDeviceManager.activeDeviceShortDescription);
|
||||
}
|
||||
else if(base.backendState == 4)
|
||||
{
|
||||
return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice")
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +72,7 @@ Rectangle {
|
||||
height: parent.height
|
||||
color: UM.Theme.getColor("progressbar_control")
|
||||
radius: UM.Theme.getSize("progressbar_radius").width
|
||||
visible: base.backendState == 1 ? true : false
|
||||
visible: base.backendState == 2 ? true : false
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +88,7 @@ Rectangle {
|
||||
id: saveToButton
|
||||
|
||||
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
|
||||
enabled: base.backendState == 2 && base.activity == true
|
||||
enabled: base.backendState == 3 && base.activity == true
|
||||
height: UM.Theme.getSize("save_button_save_to_button").height
|
||||
|
||||
anchors.top: parent.top
|
||||
@ -127,7 +139,7 @@ Rectangle {
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
width: UM.Theme.getSize("save_button_save_to_button").height
|
||||
height: UM.Theme.getSize("save_button_save_to_button").height
|
||||
enabled: base.backendState == 2 && base.activity == true
|
||||
enabled: base.backendState == 3 && base.activity == true
|
||||
visible: devicesModel.deviceCount > 1
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user