Skip to content

Commit 8248c16

Browse files
added QuickExt callback for Seq blocks, fixed non-promoted pargroup callbacks
1 parent ea4af66 commit 8248c16

File tree

8 files changed

+117
-46
lines changed

8 files changed

+117
-46
lines changed
26.8 KB
Binary file not shown.
24 Bytes
Binary file not shown.
272 Bytes
Binary file not shown.
File renamed without changes.

scripts/QuickExt/ExtQuickExt.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ class ExtQuickExt:
1818
def __init__(self, ownerComp):
1919
# The component to which this extension is attached
2020
self.ownerComp = ownerComp
21-
self.dialog = op('popDialog')
21+
self.dialog = self.ownerComp.op('popDialog')
2222
self.ConfigComp = None
23-
self.extType = 'empty'
24-
23+
self.extTemplate = self.ownerComp.op('extTemplate')
2524

2625
def CreateExtension(self, _target):
2726
if not _target:
@@ -59,15 +58,13 @@ def OnSelect(self, info):
5958
xPos = edgeX - 500 - (extIndex - 1) * 200
6059
yPos = edgeY
6160

62-
masterExt = self.ownerComp.op(self.extType.lower() +
63-
'ExtensionText')
61+
masterExt = self.extTemplate
6462
masterUtils = self.ownerComp.op('extUtils')
6563
extDat = self.ConfigComp.copy(masterExt, name=extModuleName)
6664
extUtils = self.ConfigComp.copy(masterUtils, includeDocked=True)
6765
extUtils.dock = extDat
6866

69-
extensionText = self.ownerComp.op(self.extType.lower() +
70-
'ExtensionText').text
67+
extensionText = masterExt.text
7168
extensionText = extensionText.replace('DefaultExt',
7269
extModuleName)
7370
extDat.par.file.mode = ParMode.CONSTANT
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# me - this DAT
2+
# par - the Par object that has changed
3+
# val - the current value
4+
# prev - the previous value
5+
#
6+
# Make sure the corresponding toggle is enabled in the Parameter Execute DAT.
7+
8+
def onValueChange(par, prev):
9+
# use par.eval() to get current value
10+
return
11+
12+
# Called at end of frame with complete list of individual parameter changes.
13+
# The changes are a list of named tuples, where each tuple is (Par, previous value)
14+
def onValuesChanged(changes):
15+
mod.extUtils.CustomParHelper.OnSeqValuesChanged(changes)
16+
return
17+
18+
def onPulse(par):
19+
return
20+
21+
def onExpressionChange(par, val, prev):
22+
return
23+
24+
def onExportChange(par, val, prev):
25+
return
26+
27+
def onEnableChange(par, val, prev):
28+
return
29+
30+
def onModeChange(par, val, prev):
31+
return
32+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'''Info Header Start
2+
Name : extTemplate
3+
Author : Dan@DAN-4090
4+
Saveorigin : FunctionStore_tools_2023.148.toe
5+
Saveversion : 2023.11600
6+
Info Header End'''
7+
from extUtils import CustomParHelper
8+
9+
class DefaultExt:
10+
def __init__(self, ownerComp):
11+
self.ownerComp = ownerComp
12+
CustomParHelper.Init(self, ownerComp, enable_properties=True, enable_callbacks=True)
13+
14+
15+
16+

scripts/QuickExt/template/extUtils.py

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,26 @@ class CustomParHelper:
1919
1. Import the CustomParHelper class:
2020
from utils import CustomParHelper
2121
22-
2. Initialize in your extension's __init__ method:
23-
CustomParHelper.Init(self, ownerComp, enable_properties=True, enable_callbacks=True)
22+
2. Initialize in your extension's __init__ method as follows:
23+
CustomParHelper.Init(self, ownerComp)
2424
25-
Full signature:
26-
CustomParHelper.Init(self, ownerComp, enable_properties=True, enable_callbacks=True, enable_parGroups=True, expose_public=False,
25+
Full signature and optional parameters:
26+
CustomParHelper.Init(self, ownerComp, enable_properties: bool = True, enable_callbacks: bool = True, enable_parGroups: bool = True, expose_public: bool = False,
2727
par_properties: list[str] = ['*'], par_callbacks: list[str] = ['*'],
2828
except_properties: list[str] = [], except_sequences: list[str] = [], except_callbacks: list[str] = [], except_pages: list[str] = [])
2929
30+
Additional options:
31+
- enable_parGroups: If True, creates properties and methods for parGroups (default: True)
32+
- expose_public: If True, uses capitalized property and method names (e.g., Par, Eval instead of par, eval)
33+
- par_properties: List of parameter names to include in property creation, by default all parameters are included
34+
- par_callbacks: List of parameter names to include in callback handling, by default all parameters are included
35+
- except_properties: List of parameter names to exclude from property creation
36+
- except_callbacks: List of parameter names to exclude from callback handling
37+
- except_pages: List of parameter pages to exclude from property and callback handling
38+
- except_sequences: List of sequence names to exclude from property and callback handling
39+
3040
> NOTE: this class should only be attached to one extension, otherwise it will cause conflicts
31-
41+
3242
3. Access custom parameters as properties (if enable_properties=True (default)):
3343
- self.par<ParamName>: Access the parameter object
3444
- self.eval<ParamName>: Get the evaluated value of the parameter
@@ -38,33 +48,24 @@ class CustomParHelper:
3848
3949
4. Implement callbacks (if enable_callbacks=True (default)):
4050
- For regular parameters:
41-
def on<ParamName>(self, _par, _val, _prev):
51+
def onPar<ParamName>(self, _par, _val, _prev):
4252
# _par and _prev can be omitted if not needed
4353
4454
- For pulse parameters:
45-
def on<PulseParamName>(self, _par):
55+
def onPar<PulseParamName>(self, _par):
4656
# _par can be omitted if not needed
4757
58+
- For sequence blocks:
59+
def onSeq<SeqName>N(self, idx):
60+
4861
- For sequence parameters:
49-
def on<SeqName>N<ParName>(self, _par, idx, _val, _prev):
62+
def onSeq<SeqName>N<ParName>(self, _par, idx, _val, _prev):
5063
# _par and _prev can be omitted if not needed
5164
5265
- For parameter groups if enable_parGroups=True (default):
5366
def onParGroup<GroupName>(self, _parGroup, _val):
5467
# _parGroup can be omitted if not needed
5568
56-
> NOTE: to expose public methods, eg. self.OnPar<ParamName> instead of self.onPar<ParamName>, set expose_public=True in the Init function
57-
58-
Additional options:
59-
- enable_parGroups: If True, creates properties and methods for parGroups (default: True)
60-
- expose_public: If True, uses capitalized property and method names (e.g., Par, Eval instead of par, eval)
61-
- par_properties: List of parameter names to include in property creation, by default all parameters are included
62-
- par_callbacks: List of parameter names to include in callback handling, by default all parameters are included
63-
- except_properties: List of parameter names to exclude from property creation
64-
- except_callbacks: List of parameter names to exclude from callback handling
65-
- except_pages: List of parameter pages to exclude from property and callback handling
66-
- except_sequences: List of sequence names to exclude from property and callback handling
67-
6869
> NOTE: This class only works with the docked helper ParExec DATs, which also perform filtering of parameters in a lot of cases.
6970
'''
7071

@@ -75,16 +76,16 @@ def onParGroup<GroupName>(self, _parGroup, _val):
7576
EXCEPT_SEQUENCES: list[str] = []
7677
PAR_PROPS: list[str] = ['*']
7778
PAR_CALLBACKS: list[str] = ['*']
78-
SEQUENCE_PATTERN = r'(\w+?)(\d+)(.+)'
79-
IS_EXPOSE_PUBLIC = False
80-
SELF = None
79+
SEQUENCE_PATTERN: str = r'(\w+?)(\d+)(.+)'
80+
IS_EXPOSE_PUBLIC: bool = False
81+
EXT_SELF = None
8182

8283
@staticmethod
8384
def Init(extension_self, ownerComp: COMP, enable_properties: bool = True, enable_callbacks: bool = True, enable_parGroups: bool = True, expose_public: bool = False,
8485
par_properties: list[str] = ['*'], par_callbacks: list[str] = ['*'],
8586
except_properties: list[str] = [], except_sequences: list[str] = [], except_callbacks: list[str] = [], except_pages: list[str] = []) -> None:
8687
"""Initialize the CustomParHelper."""
87-
CustomParHelper.SELF = extension_self
88+
CustomParHelper.EXT_SELF = extension_self
8889
CustomParHelper.IS_EXPOSE_PUBLIC = expose_public
8990
CustomParHelper.PAR_PROPS = par_properties
9091
CustomParHelper.PAR_CALLBACKS = par_callbacks
@@ -93,8 +94,8 @@ def Init(extension_self, ownerComp: COMP, enable_properties: bool = True, enable
9394
CustomParHelper.EXCEPT_CALLBACKS = except_callbacks
9495
CustomParHelper.EXCEPT_SEQUENCES = except_sequences
9596

96-
# me: textDAT = me
97-
for _docked in me.docked:
97+
me_me: textDAT = me # just to have autocomplete on this
98+
for _docked in me_me.docked:
9899
if 'extDatExec' in _docked.tags:
99100
_docked.par.active = enable_properties
100101

@@ -125,7 +126,7 @@ def CustomParsAsProperties(extension_self, ownerComp: COMP, enable_parGroups: bo
125126

126127

127128
@staticmethod
128-
def _create_propertyEval(extension_self, owner_comp: COMP, Parname: str, enable_parGroups: bool = True):
129+
def _create_propertyEval(extension_self, owner_comp: COMP, Parname: str, enable_parGroups: bool = True) -> None:
129130
"""Create a property for the evaluated value of a parameter."""
130131
def getter(instance):
131132
return getattr(owner_comp.par, Parname).eval()
@@ -134,13 +135,13 @@ def getter_group(instance):
134135

135136
property_name = f'{"Eval" if CustomParHelper.IS_EXPOSE_PUBLIC else "eval"}{Parname}'
136137
setattr(extension_self.__class__, property_name, property(getter))
137-
# this might be overkill
138+
138139
if enable_parGroups and CustomParHelper.__isParGroup(getattr(owner_comp.par, Parname)):
139140
setattr(extension_self.__class__, f'{"EvalGroup" if CustomParHelper.IS_EXPOSE_PUBLIC else "evalGroup"}{Parname[:-1]}', property(getter_group))
140141

141142

142143
@staticmethod
143-
def _create_propertyPar(extension_self, owner_comp: COMP, Parname: str, enable_parGroups: bool = True):
144+
def _create_propertyPar(extension_self, owner_comp: COMP, Parname: str, enable_parGroups: bool = True) -> None:
144145
"""Create a property for the parameter object."""
145146
def getter(instance):
146147
return getattr(owner_comp.par, Parname)
@@ -149,7 +150,7 @@ def getter_group(instance):
149150

150151
property_name = f'{"Par" if CustomParHelper.IS_EXPOSE_PUBLIC else "par"}{Parname}'
151152
setattr(extension_self.__class__, property_name, property(getter))
152-
# this might be overkill
153+
153154
if enable_parGroups and CustomParHelper.__isParGroup(getattr(owner_comp.par, Parname)):
154155
setattr(extension_self.__class__, f'{"ParGroup" if CustomParHelper.IS_EXPOSE_PUBLIC else "parGroup"}{Parname[:-1]}', property(getter_group))
155156

@@ -176,7 +177,7 @@ def OnValueChange(comp: COMP, par: Par, prev: Par) -> None:
176177
# exceptions are handled in the parExec itself
177178
# except for sequence parameters
178179

179-
comp = CustomParHelper.SELF # a bit hacky to be able to call non-exposed methods too
180+
comp = CustomParHelper.EXT_SELF # a bit hacky to be able to call non-exposed methods too
180181

181182
# check if we are a sequence parameter first
182183
match = re.match(CustomParHelper.SEQUENCE_PATTERN, par.name)
@@ -214,7 +215,7 @@ def OnPulse(comp: COMP, par: Par) -> None:
214215
# exceptions are handled in the parExec itself
215216
# except for sequence parameters
216217

217-
comp = CustomParHelper.SELF # a bit hacky to be able to call non-exposed methods too
218+
comp = CustomParHelper.EXT_SELF # a bit hacky to be able to call non-exposed methods too
218219

219220
# check if we are a sequence parameter first
220221
match = re.match(CustomParHelper.SEQUENCE_PATTERN, par.name)
@@ -242,19 +243,17 @@ def OnPulse(comp: COMP, par: Par) -> None:
242243

243244
@staticmethod
244245
def OnValuesChanged(changes: list[tuple[Par, Par]]) -> None:
245-
"""Handle value change events for custom parameters.
246-
Using this for ParGroup callbacks only"""
246+
"""Handle value change events for ParGroups."""
247247
# exceptions are handled in the parExec itself
248248
# except for sequence parameters
249249
parGroupsCalled = []
250250
for change in changes:
251251
_par = change[0]
252252
# _prev = change[1]
253253
# _comp = _par.owner
254-
_comp = CustomParHelper.SELF # a bit hacky to be able to call non-exposed methods too
254+
_comp = CustomParHelper.EXT_SELF # a bit hacky to be able to call non-exposed methods too
255255
# handle sequence exceptions
256256
# check if we are a sequence parameter first
257-
# TODO: should we check for sequence exceptions here?
258257
match = re.match(CustomParHelper.SEQUENCE_PATTERN, _par.name)
259258
if match:
260259
sequence_name, sequence_index, parameter_name = match.groups()
@@ -270,7 +269,7 @@ def OnValuesChanged(changes: list[tuple[Par, Par]]) -> None:
270269
match = re.match(r'(\w+)(.)', _par.name)
271270
if match:
272271
ParGroup, ParName = match.groups()
273-
_par = _comp.parGroup[ParGroup]
272+
_par = _comp.ownerComp.parGroup[ParGroup]
274273
method_name = f'{"OnParGroup" if CustomParHelper.IS_EXPOSE_PUBLIC else "onParGroup"}{ParGroup}'
275274
if hasattr(_comp, method_name):
276275
method = getattr(_comp, method_name)
@@ -280,10 +279,37 @@ def OnValuesChanged(changes: list[tuple[Par, Par]]) -> None:
280279
elif arg_count == 3:
281280
method(_par, _par.eval())
282281

283-
282+
@staticmethod
283+
def OnSeqValuesChanged(changes: list[tuple[Par, Par]]) -> None:
284+
"""Handle value change events for Sequence blocks."""
285+
seqsCalled = []
286+
for change in changes:
287+
_par = change[0]
288+
# _prev = change[1]
289+
# _comp = _par.owner
290+
_comp = CustomParHelper.EXT_SELF # a bit hacky to be able to call non-exposed methods too
291+
# handle sequence exceptions
292+
# check if we are a sequence parameter first
293+
match = re.match(CustomParHelper.SEQUENCE_PATTERN, _par.name)
294+
if match:
295+
sequence_name, sequence_index, parameter_name = match.groups()
296+
sequence_index = int(sequence_index)
297+
if sequence_name in CustomParHelper.EXCEPT_SEQUENCES:
298+
return
299+
if f'{sequence_name}{sequence_index}' not in seqsCalled:
300+
seqsCalled.append(f'{sequence_name}{sequence_index}')
301+
else:
302+
continue
303+
method_name = f'{"OnSeq" if CustomParHelper.IS_EXPOSE_PUBLIC else "onSeq"}{sequence_name}N'
304+
if hasattr(_comp, method_name):
305+
method = getattr(_comp, method_name)
306+
arg_count = method.__code__.co_argcount
307+
if arg_count == 2:
308+
method(sequence_index)
309+
284310
@staticmethod
285311
def __isParGroup(par: Par) -> bool:
286-
"""Check if a parameter is a ParGroup."""
312+
"""Check if a parameter is a ParGroup. Is there no better way?"""
287313
par_name = par.name[:-1]
288314
try:
289315
pg = par.owner.parGroup[par_name]

0 commit comments

Comments
 (0)