Smart Options
"Smart options" refers to the ability of options to be clever and interact with each other. For example, consider a module that provides different ionospheric models (e.g. Timba/doc/Courses/Workshop2007/ME2/iono_model.py). This declares the following set of options:
1 TDLCompileOption('iono_model',"Ionospheric model",[sine_tid_model,wedge_model]);
2 TDLCompileOption('TEC0',"Base TEC value",[0,5,10],more=float);
3 TDLCompileOptionSeparator();
4 TDLCompileMenu('Sine TID model options',
5 TDLOption('tid_x_ampl_0',"Relative TID-X amplitude at t=0",[0,0.01,0.02,0.05,0.1],more=float),
6 TDLOption('tid_x_ampl_1hr',"Relative TID-X amplitude at t=1hr",[0,0.002,0.01,0.02,0.05,0.1],more=float),
7 TDLOption('tid_x_size_km',"TID-X size, in km",[25,50,100,200,1000],more=int),
8 TDLOption('tid_x_speed_kmh',"TID-X speed, in km/h",[25,50,100,200,300,500],more=int),
9 None,
10 TDLOption('tid_y_ampl_0',"Relative TID-Y amplitude at t=0",[0,0.01,0.02,0.05,0.1],more=float),
11 TDLOption('tid_y_ampl_1hr',"Relative TID-Y amplitude at t=1hr",[0,0.002,0.01,0.02,0.05,0.1],more=float),
12 TDLOption('tid_y_size_km',"TID-Y size, in km",[25,50,100,200,1000],more=int),
13 TDLOption('tid_y_speed_kmh',"TID-Y speed, in km/h",[25,50,100,200,300,500],more=int),
14 );
15 TDLCompileMenu('Wedge model options',
16 TDLOption('wedge_min','Min delta-TEC over 100km',[0,0.001,0.1,1,2,5],more=float),
17 TDLOption('wedge_max','Max delta-TEC over 100km',[0,0.001,0.1,1,2,5],more=float),
18 TDLOption('wedge_time','Time to reach max delta-TEC, hours',[1,2,4,8],more=float)
19 );
This module provides two mutually exclusive models: sine-TID and wedge. The first compile-time option selects between the two models. Furthermore, each model provides its own set of options (here grouped in two sub-menus.) Things would be much less confusing for the user if the sub-menus were automatically enabled and disabled based on which model was selected. This is not hard to accomplish:
1 iono_model_option = TDLCompileOption('iono_model',"Ionospheric model",
2 [sine_tid_model,wedge_model]
3 );
4 TDLCompileOption('TEC0',"Base TEC value",[0,5,10],more=float);
5 TDLCompileOptionSeparator();
6 sine_options = TDLCompileMenu('Sine TID model options',
7 TDLOption('tid_x_ampl_0',"Relative TID-X amplitude at t=0",[0,0.01,0.02,0.05,0.1],more=float),
8 TDLOption('tid_x_ampl_1hr',"Relative TID-X amplitude at t=1hr",[0,0.002,0.01,0.02,0.05,0.1],more=float),
9 TDLOption('tid_x_size_km',"TID-X size, in km",[25,50,100,200,1000],more=int),
10 TDLOption('tid_x_speed_kmh',"TID-X speed, in km/h",[25,50,100,200,300,500],more=int),
11 None,
12 TDLOption('tid_y_ampl_0',"Relative TID-Y amplitude at t=0",[0,0.01,0.02,0.05,0.1],more=float),
13 TDLOption('tid_y_ampl_1hr',"Relative TID-Y amplitude at t=1hr",[0,0.002,0.01,0.02,0.05,0.1],more=float),
14 TDLOption('tid_y_size_km',"TID-Y size, in km",[25,50,100,200,1000],more=int),
15 TDLOption('tid_y_speed_kmh',"TID-Y speed, in km/h",[25,50,100,200,300,500],more=int),
16 );
17 wedge_options = TDLCompileMenu('Wedge model options',
18 TDLOption('wedge_min','Min delta-TEC over 100km',[0,0.001,0.1,1,2,5],more=float),
19 TDLOption('wedge_max','Max delta-TEC over 100km',[0,0.001,0.1,1,2,5],more=float),
20 TDLOption('wedge_time','Time to reach max delta-TEC, hours',[1,2,4,8],more=float)
21 );
22 # Define a callback to be called whenever the iono_model option changes
23 # This particular callback will show/hide the submenus based on the selected option
24 iono_model_option.when_changed(lambda model:\
(sine_options.show(model==sine_tid_model),
25 wedge_options.show(model==wedge_model)));
This code exploits the following features:
The return value of TDLxxxOption() is an "option" object. We have to retain the object if we want to manipulate the option later. Most of the time we just ignore it...
The when_changed() method of an option object registers a callback. Its argument must be a function taking a single argument. Whenever the value of the option is changed, the callback is invoked with the new value as its argument. (It is also invoked once initially, to set things up.)
The show(bool) method can be used to hide or show an option (or a whole option menu). An alternative method is enable(bool) -- this enables or disables (greys out) the option's menu item. Other methods may be implemented later as needed.
- Callbacks can be anything --- here we construct a lambda function on the fly. A more verbose equivalent of the code above would be:
1 def _show_model_options (model): 2 sine_options.show(model==sine_tid_model); 3 wedge_options.show(model==wedge_model); 4 iono_model_option.when_changed(_show_model_options);
Available callbacks
The following callback methods are available:
when_changed()
This is illustrated in the example above. option.when_changed(func) takes one argument, which should be a callable taking a single argument. Whenever the value of the option is changed, the callback is invoked with the new value as its argument. It is also invoked once from when_changed() itself, to set things up. If the option is read from a tdl.conf file after the callback is registered, the callback is also invoked.
Note that you can register multiple callbacks for a single option, by calling when_changed() repeatedly.
set_validator()
A validator callback can be registered to check if an option value is acceptable, as soon as it is entered by the user. This is only available for list-type options invoked with a more= argument, and for file/dir selectors (since for the other types of options, the possible values are known an restricted to begin with).
Here's an example validator:
1 def _channel_validator (value): 2 return 0 <= value and value <= 20; 3 opt = TDLRuntimeOption('channel_index',"Channel number",[0],more=int); 4 opt.set_validator(_channel_validator);
The validator function is called with a single argument, the new value to be tested. If the option was created with more=int or more=float, then the value passed in will already be an int or a float. If the option is a file or dir selector, then what is passed in is the full pathname.
The validator should return True if the value is acceptable, or False (or throw an exception) if not. The GUI will not let the user enter values that fail the validator.
Other methods of option objects
To achieve true interactivity, your callbacks must be able to manipulate the state of option objects. The following is a list of available option methods.
Methods common to all option types
value
opt.value is not really a method, but a data member. It contains the current value of the object.
show(show=True) & hide(hide=True)
show() and hide() show and hide the option in the GUI. They have a single boolean argument that defaults to True; setting it to False reverses the effect of the call.
enable(enable=True) & disable(disable=True)
enable() and disable() enable or disable (grey out) the option in the GUI. They have a single boolean argument that defaults to True; setting it to False reverses the effect of the call.
set_value(value,save=True)
set_value() changes the value of the option. At the moment minimal sanity checking is performed, specifically:
- boolean options are forced to a boolean value.
for list-type options without a custom value (i.e. created without a more= keyword), the value must be present in the original opton list. For list-type options with a custom value, if the value is not in the list, it will be set as the custom value. Note that the validator (if any) is not called in this case.
- for file or directory options, no checking is done.
If the optional save keyword is True, the new option setting will be saved to .tdl.conf.
set(n,save=True)
For list-type options, this selects option #n. For other options, this is equivalent to calling set_value().
set_name(name)
Changes the name of the option (i.e. the text displayed in the menu).
Methods specific to list-type options
set_custom_value(value,select=True,save=True)
This is only available for options with a custom value (i.e. created with a more= keyword). The function changes the custom value. If select is True, the custom entry is also selected. If save is True, the selection is saved to .tdl.conf.
set_option_list(list,select=None,conserve_selection=True)
This changes the list of available option settings. The select keyword can be set to an index in order to immediately select that option, otherwise it will attempt to preserve the current selection, unless conserve_selection is False.
num_options()
Returns the number of options in the list (+1 for the custom value, if supported)
get_option(n)
Returns the value of option #n in the list
get_option_str(n)
Returns the string representation (i.e. what is written to the config file) of option #n in the list.
get_option_desc(n)
Returns the string description (i.e. what is shown in the GUI) of option #n in the list. This is usually equivalent to get_option_str(), but for list options created from a dict the description may be different (e.g. more verbose.)
Methods specific to menus
toggle options
Menus created with the toggle option exhibit all the behaviour (and support all the methods) of boolean options.
set_summary(text)
Sets a summary text that is displayed to the right of the menu title. An initial value for the summary may be passed in via a summary= keyword when the menu is created.
