From 8aa135b964b1f94dce83c2344b1018b48503b8db Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 30 Oct 2022 00:15:48 +0200 Subject: [PATCH] Python implementation of PCell helper with callback --- .../pcell_declaration_helper.lym | 136 ++++++++++++++---- 1 file changed, 108 insertions(+), 28 deletions(-) diff --git a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym index 3632806fd..1df6dcb53 100644 --- a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym +++ b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym @@ -162,6 +162,51 @@ It is supposed to adjust parameters to render a consistent parameter set and to parameter range errors. This method is called for example inside the PCell user interface to compute the actual parameters when "Apply" is pressed. +@method callback_impl(name) + +@brief Provides a callback on a parameter change + +This method applies to user interface changes only. Whenever a parameter is changed +on the parameter page, this method is called with the name of the parameter. + +On some occasions, this method called to establish a configuration unspecifically. +In this case, the name is an empty string - indicating "all parameters may have changed". + +This method can change the state of this or any other parameter. For this, the +state objects are supplied instead of the parameter values. For example to enable +parameter "b" when a boolean parameter "a" is true, use the following code: + +@code +def callback_impl(self, name): + if name == "a" or name == "": + b.enabled = a.value +@/code + +The "enabled" attribute of the \\PCellParameterState object indicates whether the +parameter is enabled in the user interface. "a.value" delivers the value of the +(boolean type assumed) parameter "a". + +Note that the above code also checks for empty name to consider the case of a +global refresh. + +Further useful attributes of the parameters are: + +@ul + @li + @b enabled @/b: the parameter entry is grayed out if false + @/li + @li + @b readonly @/b: the parameter cannot be edited (less strict than enabled) + @/li + @li + @b visible @/b: the parameter entry is not visible if false + @/li + @li + @b icon @/b: Sets an icon in front of the parameter indicating an error or a + warning (use \\PCellParameterState#WarningIcon or \\PCellParameterState#ErrorIcon). + @/li +@/ul + @method can_create_from_shape_impl @brief Returns true if the PCell can be created from the given shape @@ -232,13 +277,16 @@ class _PCellDeclarationHelperParameterDescriptor(object): the descriptor acts as a value holder (self.value) """ - def __init__(self, param_index): + def __init__(self, param_index, param_name): self.param_index = param_index + self.param_name = param_name self.value = None def __get__(self, obj, type = None): if obj._param_values: return obj._param_values[self.param_index] + elif obj._param_states: + return obj._param_states.parameter(self.param_name) else: return self.value @@ -261,6 +309,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): # "private" attributes self._param_decls = [] self._param_values = None + self._param_states = None self._layer_param_index = [] self._layers = [] # public attributes @@ -290,7 +339,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): # create accessor methods for the parameters param_index = len(self._param_decls) - setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index)) + setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index, name)) if value_type == type(self).TypeLayer: setattr(type(self), name + "_layer", _PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index))) @@ -323,8 +372,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): implementation of display_text """ self._param_values = parameters - text = self.display_text_impl() - self._param_values = None + try: + text = self.display_text_impl() + finally: + self._param_values = None return text def get_parameters(self): @@ -341,7 +392,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self._param_values = None return v - def init_values(self, values = None, layers = None): + def init_values(self, values = None, layers = None, states = None): """ initializes the temporary parameter values "values" are the original values. If "None" is given, the @@ -349,7 +400,11 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): "layers" are the layer indexes corresponding to the layer parameters. """ - if not values: + self._param_values = None + self._param_states = None + if states: + self._param_states = states + elif not values: self._param_values = [] for pd in self._param_decls: self._param_values.append(pd.default) @@ -359,29 +414,48 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): def finish(self): """ - Needs to be called at the end of produce() after init_values was used + Needs to be called at the end of an implementation """ self._param_values = None + self._param_states = None self._layers = None + self._cell = None + self._layout = None + self._layer = None + self._shape = None def get_layers(self, parameters): """ - get the layer definitions + gets the layer definitions """ layers = [] for i in self._layer_param_index: layers.append(parameters[i]) return layers + def callback(self, layout, name, states): + """ + callback (change state on parameter change) + """ + self.init_values(states = states) + self.layout = layout + try: + self.callback_impl(name) + finally: + self.finish() + def coerce_parameters(self, layout, parameters): """ coerce parameters (make consistent) """ self.init_values(parameters) self.layout = layout - self.coerce_parameters_impl() - self.layout = None - return self.get_values() + try: + self.coerce_parameters_impl() + parameters = self.get_values() + finally: + self.finish() + return parameters def produce(self, layout, layers, parameters, cell): """ @@ -390,10 +464,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.init_values(parameters, layers) self.cell = cell self.layout = layout - self.produce_impl() - self.cell = None - self.layout = None - self.finish() + try: + self.produce_impl() + finally: + self.finish() def can_create_from_shape(self, layout, shape, layer): """ @@ -402,10 +476,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - ret = self.can_create_from_shape_impl() - self.layout = None - self.shape = None - self.layer = None + try: + ret = self.can_create_from_shape_impl() + finally: + self.finish() return ret def transformation_from_shape(self, layout, shape, layer): @@ -415,10 +489,10 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - t = self.transformation_from_shape_impl() - self.layout = None - self.shape = None - self.layer = None + try: + t = self.transformation_from_shape_impl() + finally: + self.finish() return t def parameters_from_shape(self, layout, shape, layer): @@ -430,11 +504,11 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): self.layout = layout self.shape = shape self.layer = layer - self.parameters_from_shape_impl() - param = self.get_values() - self.layout = None - self.shape = None - self.layer = None + try: + self.parameters_from_shape_impl() + param = self.get_values() + finally: + self.finish() return param def display_text_impl(self): @@ -449,6 +523,12 @@ class _PCellDeclarationHelper(pya.PCellDeclaration): """ pass + def callback_impl(self, name): + """ + default implementation + """ + pass + def produce_impl(self): """ default implementation