Preference Panel Plug-in Reference Manual

This document describes how to incoporate a panel for setting Grail preferences into the Grail browser.

Note that preference panels do not create preferences, they are for controlling established ones. To incorporate new preferences into the system, you must create an entry in grail-defaults preferences file, and hook them up with the relevant Grail mechanisms using the Grail preferences object interface. See the Preferences infrastructure document for background on the Grail preferences mechanisms, and the section on the GUI framework for details on the underlying preference panel support mechanisms, in particular.

For a representative example of a preference panel, see in the Grail source's prefspanels subdirectory.

Preference Panel Modules

Specific preference panels are defined in modules with a particular name and location:

Preference Panel Class

To create a preference panel, define a class in your panel module which:

In addition to the low-level self.RegisterUI() mechanism, the framework provides a few routines for creating widgets, such as entries and buttons, which are regularly proportioned and which take care of the preference coupling. See the preferences-widgets section, below.

The panel framework has a few useful instance variables:
The Grail application object
The browser from which the panel was last posted. It's possible that the browser has been discarded since the panel was posted, so the panel should check the value of self.browser.valid() to verify that the browser is still around, and use any browser in if it is not.
There are also a few conveniences for preference panel developers.

Using self.RegisterUI() to Couple Widgets With Preferences

RegisterUI takes the following arguments:

The self.RegisterUI() method associates the preference, identified by the group and component, with the setter and getter routines. The Framework then uses the setter and getter routines to transfer the values between the widget and the preference.

For example, when the panel "Done" button is pushed, the getter routines are used to obtain the current values registered in the panel widgets and apply them to the associated preferences. Or when the revert button is pushed, the setter routines are used to register the current preference settings in their associated widgets, and so forth.

The framework also provides a utility for use with self.RegisterUI(), self.widget_set_func(widget). It takes any widget which uses the textvariable config option for controlling the widget setting, and returns a routine which can be used as the Getter routine for RegisterUI(). For things like button widgets, you can use the var.Set() methods of their Tkinter variables directly.

Framework Preferences Widgets

The framework provides a number of routines with two features:

Currently, the repertoire consists of:

self.PrefsWidgetLabel(frame, text, label_width=25)
Mainly for use by the other prefs widgets. PrefsWidgetLabel packs frame with a text label so it takes up label_width space but has the text right-justified. This means the text will end just before the label_width column. By packing widgets in the frame to the right of this label, they all can line up at the same column. (This depends on the text fitting in - embed \n newlines for text longer than label_width chars.)
self.PrefsCheckButton(frame, general-text, specific-text, group, component, label_width=25):
Produce a check button with general-text left-side label (see above) and coupled with the Boolean preference specified by group/component.
self.PrefsRadioButton(frame, general-text, specific-text, group, component, type_name, label_width=25):
Produce a frame of radio buttons with general-text left-side label (see above) and coupled with the preference of specified type.
self.PrefsEntry(parent, label, group, component, type_name, label_width=25, entry_height=1, entry_width=None, composite=0):
Produce an entry widget, or a text widget with vertical scrolling if entry_height is greater than one, coupled with the preference of specified type.

You can pack multiple instances of these entry widgets in the together, eg to make a

"Width: #### Height: #####"

widget, composed of two such entry widgets, by setting the composite keyword argument. This will override the label-lineup feature, so the combination can be used together with a left-side self.PrefsWidgetLabel() to make a composite widget line for the panel:

"Browser geometry: Width: #### Height: #####"
For examples using these widgets, see in the grail distribution prefspanels directory.