mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 02:16:01 +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.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# 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.Application import Application
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from UM.Logger import Logger
|
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.Message import Message
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
@ -56,8 +55,9 @@ class CuraEngineBackend(Backend):
|
|||||||
self._stored_layer_data = []
|
self._stored_layer_data = []
|
||||||
|
|
||||||
#Triggers for when to (re)start slicing:
|
#Triggers for when to (re)start slicing:
|
||||||
if Application.getInstance().getGlobalContainerStack():
|
self._global_container_stack = None
|
||||||
Application.getInstance().getGlobalContainerStack().propertyChanged.connect(self._onSettingChanged) #Note: Only starts slicing when the value changed.
|
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.
|
#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.
|
#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._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._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.backendQuit.connect(self._onBackendQuit)
|
||||||
self.backendConnected.connect(self._onBackendConnected)
|
self.backendConnected.connect(self._onBackendConnected)
|
||||||
@ -124,7 +124,7 @@ class CuraEngineBackend(Backend):
|
|||||||
def slice(self):
|
def slice(self):
|
||||||
self._stored_layer_data = []
|
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
|
return
|
||||||
|
|
||||||
if self._slicing: #We were already slicing. Stop the old job.
|
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.abort()
|
||||||
self._process_layers_job = None
|
self._process_layers_job = None
|
||||||
|
|
||||||
# #Don't slice if there is a setting with an error value.
|
if self._error_message:
|
||||||
# stack = Application.getInstance().getGlobalContainerStack()
|
self._error_message.hide()
|
||||||
# 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
|
|
||||||
|
|
||||||
self.processingProgress.emit(0.0)
|
self.processingProgress.emit(0.0)
|
||||||
self.backendStateChange.emit(BackendState.NOT_STARTED)
|
self.backendStateChange.emit(BackendState.NotStarted)
|
||||||
if self._message:
|
|
||||||
self._message.setProgress(-1)
|
|
||||||
else:
|
|
||||||
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
|
||||||
self._message.show()
|
|
||||||
|
|
||||||
self._scene.gcode_list = []
|
self._scene.gcode_list = []
|
||||||
self._slicing = True
|
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.
|
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))
|
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
|
## Event handler to call when the job to initiate the slicing process is
|
||||||
# completed.
|
# completed.
|
||||||
#
|
#
|
||||||
@ -209,15 +182,31 @@ class CuraEngineBackend(Backend):
|
|||||||
# Note that cancelled slice jobs can still call this method.
|
# Note that cancelled slice jobs can still call this method.
|
||||||
if self._start_slice_job is job:
|
if self._start_slice_job is job:
|
||||||
self._start_slice_job = None
|
self._start_slice_job = None
|
||||||
if job.isCancelled() or job.getError() or job.getResult() != True:
|
|
||||||
if self._message:
|
if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error:
|
||||||
self._message.hide()
|
|
||||||
self._message = None
|
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
# Preparation completed, send it to the backend.
|
if job.getResult() == StartSliceJob.StartJobResult.SettingError:
|
||||||
self._socket.sendMessage(job.getSettingsMessage())
|
if Application.getInstance().getPlatformActivity:
|
||||||
self._socket.sendMessage(job.getSliceMessage())
|
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.
|
## Listener for when the scene has changed.
|
||||||
#
|
#
|
||||||
@ -270,26 +259,18 @@ class CuraEngineBackend(Backend):
|
|||||||
#
|
#
|
||||||
# \param message The protobuf message containing the slicing progress.
|
# \param message The protobuf message containing the slicing progress.
|
||||||
def _onProgressMessage(self, message):
|
def _onProgressMessage(self, message):
|
||||||
if self._message:
|
|
||||||
self._message.setProgress(round(message.amount * 100))
|
|
||||||
|
|
||||||
self.processingProgress.emit(message.amount)
|
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.
|
## Called when the engine sends a message that slicing is finished.
|
||||||
#
|
#
|
||||||
# \param message The protobuf message signalling that slicing is finished.
|
# \param message The protobuf message signalling that slicing is finished.
|
||||||
def _onSlicingFinishedMessage(self, message):
|
def _onSlicingFinishedMessage(self, message):
|
||||||
self.backendStateChange.emit(BackendState.DONE)
|
self.backendStateChange.emit(BackendState.Done)
|
||||||
self.processingProgress.emit(1.0)
|
self.processingProgress.emit(1.0)
|
||||||
|
|
||||||
self._slicing = False
|
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()):
|
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 = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data)
|
||||||
self._process_layers_job.start()
|
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.
|
## Called when anything has changed to the stuff that needs to be sliced.
|
||||||
#
|
#
|
||||||
# This indicates that we should probably re-slice soon.
|
# This indicates that we should probably re-slice soon.
|
||||||
def _onChanged(self):
|
def _onChanged(self, *args, **kwargs):
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
|
||||||
## Called when the back-end connects to the front-end.
|
## 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())
|
Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait())
|
||||||
self._process = None
|
self._process = None
|
||||||
self._createSocket()
|
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
|
import numpy
|
||||||
from string import Formatter
|
from string import Formatter
|
||||||
import traceback
|
import traceback
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
@ -12,8 +13,15 @@ from UM.Logger import Logger
|
|||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
|
|
||||||
|
from UM.Settings.Validator import ValidatorState
|
||||||
|
|
||||||
from cura.OneAtATimeIterator import OneAtATimeIterator
|
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
|
## Formatter class that handles token expansion in start/end gcod
|
||||||
class GcodeStartEndFormatter(Formatter):
|
class GcodeStartEndFormatter(Formatter):
|
||||||
@ -48,9 +56,19 @@ class StartSliceJob(Job):
|
|||||||
def run(self):
|
def run(self):
|
||||||
stack = Application.getInstance().getGlobalContainerStack()
|
stack = Application.getInstance().getGlobalContainerStack()
|
||||||
if not stack:
|
if not stack:
|
||||||
self.setResult(False)
|
self.setResult(StartJobResult.Error)
|
||||||
return
|
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():
|
with self._scene.getSceneLock():
|
||||||
# Remove old layer data.
|
# Remove old layer data.
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||||
@ -91,6 +109,7 @@ class StartSliceJob(Job):
|
|||||||
object_groups.append(temp_list)
|
object_groups.append(temp_list)
|
||||||
|
|
||||||
if not object_groups:
|
if not object_groups:
|
||||||
|
self.setResult(StartJobResult.NothingToSlice)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._buildGlobalSettingsMessage(stack)
|
self._buildGlobalSettingsMessage(stack)
|
||||||
@ -116,7 +135,7 @@ class StartSliceJob(Job):
|
|||||||
|
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
self.setResult(True)
|
self.setResult(StartJobResult.Finished)
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self):
|
||||||
super().cancel()
|
super().cancel()
|
||||||
@ -131,7 +150,7 @@ class StartSliceJob(Job):
|
|||||||
fmt = GcodeStartEndFormatter()
|
fmt = GcodeStartEndFormatter()
|
||||||
return str(fmt.format(value, **settings)).encode("utf-8")
|
return str(fmt.format(value, **settings)).encode("utf-8")
|
||||||
except:
|
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")
|
return str(value).encode("utf-8")
|
||||||
|
|
||||||
## Sends all global settings to the engine.
|
## Sends all global settings to the engine.
|
||||||
|
@ -14,21 +14,33 @@ Rectangle {
|
|||||||
|
|
||||||
property real progress: UM.Backend.progress;
|
property real progress: UM.Backend.progress;
|
||||||
property int backendState: UM.Backend.state;
|
property int backendState: UM.Backend.state;
|
||||||
|
|
||||||
property bool activity: Printer.getPlatformActivity;
|
property bool activity: Printer.getPlatformActivity;
|
||||||
//Behavior on progress { NumberAnimation { duration: 250; } }
|
//Behavior on progress { NumberAnimation { duration: 250; } }
|
||||||
property int totalHeight: childrenRect.height + UM.Theme.getSize("default_margin").height
|
property int totalHeight: childrenRect.height + UM.Theme.getSize("default_margin").height
|
||||||
property string fileBaseName
|
property string fileBaseName
|
||||||
property string statusText: {
|
property string statusText:
|
||||||
if(base.backendState == 0) {
|
{
|
||||||
if(!activity) {
|
if(!activity)
|
||||||
return catalog.i18nc("@label:PrintjobStatus","Please load a 3d model");
|
{
|
||||||
} else {
|
return catalog.i18nc("@label:PrintjobStatus", "Please load a 3d model");
|
||||||
return catalog.i18nc("@label:PrintjobStatus","Preparing to slice...");
|
}
|
||||||
}
|
|
||||||
} else if(base.backendState == 1) {
|
if(base.backendState == 1)
|
||||||
return catalog.i18nc("@label:PrintjobStatus","Slicing...");
|
{
|
||||||
} else {
|
return catalog.i18nc("@label:PrintjobStatus", "Preparing to slice...");
|
||||||
return catalog.i18nc("@label:PrintjobStatus","Ready to ") + UM.OutputDeviceManager.activeDeviceShortDescription;
|
}
|
||||||
|
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
|
height: parent.height
|
||||||
color: UM.Theme.getColor("progressbar_control")
|
color: UM.Theme.getColor("progressbar_control")
|
||||||
radius: UM.Theme.getSize("progressbar_radius").width
|
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
|
id: saveToButton
|
||||||
|
|
||||||
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
|
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
|
height: UM.Theme.getSize("save_button_save_to_button").height
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
@ -127,7 +139,7 @@ Rectangle {
|
|||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
width: UM.Theme.getSize("save_button_save_to_button").height
|
width: UM.Theme.getSize("save_button_save_to_button").height
|
||||||
height: 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
|
visible: devicesModel.deviceCount > 1
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user