scijava-common icon indicating copy to clipboard operation
scijava-common copied to clipboard

Add #@callback and #@initialize directives

Open imagejan opened this issue 10 years ago • 3 comments

Adding simple callbacks for interdependent parameters should be possible from within scripts, e.g. in Python:

# @ImagePlus imp
# @int (label="Width", callback="widthChanged") width
# @int (label="Height", callback="heightChanged") height

def widthChanged():
  height = imp.getHeight() * width / imp.getWidth()

def heightChanged():
  width = imp.getWidth() * height / imp.getHeight()

The difficulty about this is that currently the script is parsed only after the parameters were harvested, so that the callback functions are not available at the time of parameter harvesting.

imagejan avatar Nov 03 '15 10:11 imagejan

The main difficulty is really that there is no language-agnostic mechanism for invoking a callback method. It would need to become part of the ScriptLanguage API contract. Well, maybe ScriptEngineFactory.getMethodCallSyntax could do the trick (or at least facilitate what is needed). More investigation needed there.

Once we have a way to say "invoke the function called foo of this ScriptModule" without hardcoding any knowledge of the script language in use, then we can update the ScriptInfo code to use ScriptItem objects (instead of DefaultMutableModuleItem like it is now), and implement the callback(Module) method of ScriptItem to lean on the new ScriptLanguage API.

But this is all a fair amount of work, which is why I didn't do it already. :smile:

ctrueden avatar Nov 03 '15 17:11 ctrueden

I figured out how we can do it! We can use a new directive:

#@ ImagePlus imp
#@ int (label="Width") width
#@ int (label="Height") height

#@callback("width")
height = imp.getHeight() * width / imp.getWidth()
----

#@callback("height")
width = imp.getWidth() * height / imp.getHeight()
----

I think some termination sequence like ---- or #@/callback is needed; open to suggestions on the most elegant syntax.

By doing things this way, we can strip out the code in between the callback and termination sequence, store it separately, and eval it every time the callback method of ScriptModule is invoked.

ctrueden avatar Sep 14 '17 19:09 ctrueden

After discussing with @ctrueden, we agreed on this syntax:

#@ int integer
#@ String string

#@callback("integer")
string = "" + integer
#@end

#@callback("string")
integer = Integer.parseInt(string)
#@end

imagejan avatar Sep 22 '17 13:09 imagejan