Back Home

How To Write a Widget Definition

The Purpose of a WidgetDef

The WidgetDef is intended to be an addition to the library that expands the number of specified elements in the ELVIS language. Having written a widget definition for a given widget, the associated output code to write that widget need no longer be mastered by the user trying to utilize that widget in a GUI. In a sense, a widget definition is like a package for housing more complicated code that can be generated by only knowing a few specifications about the desired outcome. For example, in the case of a window, one needs only to know details like the size and title of the window, rather than how to actually "create" a window in any given output language. Widget definitions are constructed with a pointer to the associated widget object in the GUIFile and a pointer to the widget's parent widget definition, in the event that the widget needs to consult with information stored in it's parent's definition.

The Structure of a WidgetDef

There are 10 methods associated with any given widget definition, of which 8 must be overridden:

String getLanguage()

Returns the name of the language that the widget is associated with, as a fail safe ensuring that misplaced definitions don't pollute code intended for different languages.

String preamble()

Returns a string associated with any code that instantiates or creates the widget. In the case of a Window widget, the code might look like this:

return String.format("%s = new JFrame();\n", widget.id);

String postamble()

Returns a string associated with any code that needs to appear after the attributes and children have been set. In the case of a window, the code might look like this:

return String.format("%s.pack();\n", widget.id);

postamble() is defaulted to return an empty string, and need not be overridden if no postamble is required.

List<String> getVariables()

Returns a list of variables associated with the widget corresponding to anything that needs to be accessible at runtime by back-end code. Variables should be specified as public - the language definition automatically screens anonymous widgets and resets their visibility to private.

Map<String,List<String>> getDefaults()

Returns a Map of Strings to Lists of Strings that should correspond to default values for any attributes handled by the widget. Attributes without specified defaults are treated as bad attributes if not overridden and can cause unexpected results. If no default is desired, a placeholder default should still be specified.

String addAttributes(GUIAttributes attrs)

Returns the code manipulating any of the given attributes of a widget. AddAttributes is guarunteed to be called first of any of the widget methods, so attributes specified in the GUIAttributes can be used to set variables affecting other parts of the code generation. An example of Window attribute code might look like this:

return String.format("%s.setTitle(%s);\n", widget.id, GUIAttributes.getString("title"));

String addChild(String childType, String childId, GUIAttributes attrs)

Returns the code associated with adding a widget child to the parent widget's nesting schema. An example of the add code for a window might look like this:

return String.format("%s.getContentPane.add(%s);\n", widget.id, childId);

List getModifiers()

If one wishes to specify an API for accessing and modifying widget properties at runtime without directly interacting with the outputted code, functions to do so can be specified in the getModifiers method, and will then be included or excluded in the outputted code based on the ELVIS file's specifications for suppressing or allowing modifiers.

Set<String> getImports()

Returns a set of strings corresponding to the native libraries that must be imported for the widget in question. Library files should be specified raw, as in "javax.swing.JFrame" - the language definition will translate the needed libraries into the appropriate import statements.

Set<String> getInnerClasses()

If a widget does not correspond to a simple type in the output langauge, it is often useful to use inner classes as a block in which to place self contained code packages associated with the widget. The getInnerClasses method returns a set of strings describing any inner classes utilized by the widget to define and manipulate (at runtime) the widget and it's associated GUI. Since inner classes are likely to be needed for the minority of widgets, getInnerClasses defaults to returning an empty set, and need not be overridden if no inner classes are desired.

Structure of a Widget

The widget is the electronic representation of all the information specified about a given widget in the ELVIS file. It has 8 basic components:

String id

The identifier of the widget, to be used as the name of the primary widget component variable.

String type

The type of the widget. Not the type specified by the output code, but the ELVIS type, used to determine children are nested in legitimate ways and to determine the appropriate widget definition to be consulted.

Widget parent

A pointer to the widget's parent in the nesting structure. Each widget may have at most one parent - the parent pointer is null for top-level widgets.

List<Widget> children

A list of pointers to the widget's children in the nesting structure. Each widget may have any number of children.

Map<String,List<String>> attrs

A map relating attribute names to the list of strings associated with that attribute in the ELVIS file.

GUIFile file

A pointer to the overall GUIFile object associated with the program, in the event global settings or flags need to be consulted.

int lineNum

The ELVIS file line number where the widget was declared. Used for throwing exceptions.

Map<String, Integer> attrLineNums

A mapping of attribute names to the ELVIS file line numbers where they were specified. Used for throwing exceptions.

Documentation

The WidgetDef documentation is available here.