Ghostkeeper a7e1910711
Add E in the priority list
This way we're assured of the order in which these parameters occur, even though the firmware doesn't care about it. It's easier to read though.
2018-02-26 09:54:07 +01:00

164 lines
6.8 KiB
Python

# Copyright (c) 2015 Jaime van Kessel
# Copyright (c) 2017 Ultimaker B.V.
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
from UM.Logger import Logger
from UM.Signal import Signal, signalemitter
from UM.i18n import i18nCatalog
# Setting stuff import
from UM.Application import Application
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
import re
import json
import collections
i18n_catalog = i18nCatalog("cura")
## Base class for scripts. All scripts should inherit the script class.
@signalemitter
class Script:
def __init__(self):
super().__init__()
self._settings = None
self._stack = None
setting_data = self.getSettingData()
self._stack = ContainerStack(stack_id = str(id(self)))
self._stack.setDirty(False) # This stack does not need to be saved.
## Check if the definition of this script already exists. If not, add it to the registry.
if "key" in setting_data:
definitions = ContainerRegistry.getInstance().findDefinitionContainers(id = setting_data["key"])
if definitions:
# Definition was found
self._definition = definitions[0]
else:
self._definition = DefinitionContainer(setting_data["key"])
self._definition.deserialize(json.dumps(setting_data))
ContainerRegistry.getInstance().addContainer(self._definition)
self._stack.addContainer(self._definition)
self._instance = InstanceContainer(container_id="ScriptInstanceContainer")
self._instance.setDefinition(self._definition.getId())
self._instance.addMetaDataEntry("setting_version", self._definition.getMetaDataEntry("setting_version", default = 0))
self._stack.addContainer(self._instance)
self._stack.propertyChanged.connect(self._onPropertyChanged)
ContainerRegistry.getInstance().addContainer(self._stack)
settingsLoaded = Signal()
valueChanged = Signal() # Signal emitted whenever a value of a setting is changed
def _onPropertyChanged(self, key, property_name):
if property_name == "value":
self.valueChanged.emit()
# Property changed: trigger reslice
# To do this we use the global container stack propertyChanged.
# Reslicing is necessary for setting changes in this plugin, because the changes
# are applied only once per "fresh" gcode
global_container_stack = Application.getInstance().getGlobalContainerStack()
global_container_stack.propertyChanged.emit(key, property_name)
## Needs to return a dict that can be used to construct a settingcategory file.
# See the example script for an example.
# It follows the same style / guides as the Uranium settings.
# Scripts can either override getSettingData directly, or use getSettingDataString
# to return a string that will be parsed as json. The latter has the benefit over
# returning a dict in that the order of settings is maintained.
def getSettingData(self):
setting_data = self.getSettingDataString()
if type(setting_data) == str:
setting_data = json.loads(setting_data, object_pairs_hook = collections.OrderedDict)
return setting_data
def getSettingDataString(self):
raise NotImplementedError()
def getDefinitionId(self):
if self._stack:
return self._stack.getBottom().getId()
def getStackId(self):
if self._stack:
return self._stack.getId()
## Convenience function that retrieves value of a setting from the stack.
def getSettingValueByKey(self, key):
return self._stack.getProperty(key, "value")
## Convenience function that finds the value in a line of g-code.
# When requesting key = x from line "G1 X100" the value 100 is returned.
def getValue(self, line, key, default = None):
if not key in line or (';' in line and line.find(key) > line.find(';')):
return default
sub_part = line[line.find(key) + 1:]
m = re.search('^-?[0-9]+\.?[0-9]*', sub_part)
if m is None:
return default
try:
return float(m.group(0))
except:
return default
## Convenience function to produce a line of g-code.
#
# You can put in an original g-code line and it'll re-use all the values
# in that line.
# All other keyword parameters are put in the result in g-code's format.
# For instance, if you put ``G=1`` in the parameters, it will output
# ``G1``. If you put ``G=1, X=100`` in the parameters, it will output
# ``G1 X100``. The parameters G and M will always be put first. The
# parameters T and S will be put second (or first if there is no G or M).
# The rest of the parameters will be put in arbitrary order.
# \param line The original g-code line that must be modified. If not
# provided, an entirely new g-code line will be produced.
# \return A line of g-code with the desired parameters filled in.
def putValue(self, line = "", **kwargs):
#Strip the comment.
comment = ""
if ";" in line:
comment = line[line.find(";"):]
line = line[:line.find(";")] #Strip the comment.
#Parse the original g-code line.
for part in line.split(" "):
if part == "":
continue
parameter = part[0]
if parameter in kwargs:
continue #Skip this one. The user-provided parameter overwrites the one in the line.
value = part[1:]
kwargs[parameter] = value
#Write the new g-code line.
result = ""
priority_parameters = ["G", "M", "T", "S", "F", "X", "Y", "Z", "E"] #First some parameters that get priority. In order of priority!
for priority_key in priority_parameters:
if priority_key in kwargs:
if result != "":
result += " "
result += priority_key + str(kwargs[priority_key])
del kwargs[priority_key]
for key, value in kwargs.items():
if result != "":
result += " "
result += key + str(value)
#Put the comment back in.
if comment != "":
if result != "":
result += " "
result += ";" + comment
return result
## This is called when the script is executed.
# It gets a list of g-code strings and needs to return a (modified) list.
def execute(self, data):
raise NotImplementedError()