A CoreGUI2 interface is composed by at least 2 XML documents:
- The master document contains information about tabs and other "global" stuff.
- The interface document contains the description of the interface.
The master documents begin with the <coregui_master> tag, and the interface documents begin with <coregui_interface>. Master documents should include a <version> tag. Although versioning is not implemented yet, it might be useful in the future. It's recommended that you include it, and specify version 2 (so it becomes <version>2</version>).
A master document must indicate at least one interface document. Each interface document is specified in <tab> tags (because they're displayed as top tabs, and that should also be familiar to pkg_edit.php devs). There isn't a limitation on the maximum number of tabs allowed per cg2 master, but it's probably not a good idea to have more than 6 or 7 interfaces, since our current themes doesn't scale too well.
Instead of specifying the interface documents in XML using the <tab> tag, you can use the <tab_function> tag to specify a function that should return the exact same fields that would be returned when parsing <tab> tags (as a PHP array, of course). As of now this isn't implemented yet, but it's a 5-minute (or even less) job, so if you need it done, drop me a note and I'll add it to cg2.
The <tab> tag is composed by the following <tags>:
- label: The name of the interface that is described in the XML. This will be used in $pgtitle, and is also used in the tab's title.
- interface: The name of the interface that this entry represents.
In the future, the <url> tag might be implemented so that cg2 tabs can link to non-cg2 interfaces (another trivial task).
The notion of widgets should be pretty much straightforward (it's borrowed from pkg_edit's fields). Each widget represents a button, a select, or something like that. It's similar to real GUI programming (Qt, Gtk, Winforms, etc.) in some aspects.
You must also define a <config_key> for your interface (it's how you're gonna identify it). If you don't specify a <config_key>, the settings in your interface won't be saved to config.xml. This is particularly good for cg2 pages that only display information or allow you to define some parameters and execute a database query, showing the results afterwards, for example.
An element holds widgets. The way the widgets are displayed depends on the type of the element. Currently, there are 3 types of elements: form, table and step. A form is pretty much what pkg_edit.php was - it simply displays the widgets, nothing fancy about it. A table displays configuration options that can be added, removed, moved around, edited, etc. (think Firewall -> Rules). Finally, the step type is just like the form type, except that it contains next, previous, cancel and finish buttons. That allows you to construct wizards.
If your <element> is of the <table> type, you can define the <buttons> tag. For example, you might want to use only an add button and a delete button. So use <buttons>add,edit</buttons>. So far only 4 button types are defined: add, edit, delete, move. More buttons can be added on demand, and a "custom" button type should be implemented in the future.
Every <widget> tag must also specify a <type>, which is an identifier for the type of the widget (for example, "select", "button", "port", "subnet"). Check cg2_widgets.inc for a list of possible widget types.
Some widgets require more than the type specification. In fact, so far there isn't a single widget that is fully functional without other properties set. This document would be too long if we tried to explain the specs for each widget. Right now, there's no documentation for that (we should start documenting cg2_widgets.inc with something like Doxygen), but cg2_widgets.inc is fairly simple.
Although all widgets are free to require any property they want, most of them share similar properties. Here is a list of the most commonly used properties:
- name: It's the name of the widget. If you specify a name, you can get the widget's config by its name. Otherwise, it's config won't be saved to the config and won't be available to your program through the special global variables ($page_status['config'], more on this later).
- label: The string will specify in this property should be thought as the way the user will refer to the field. If you have already coded an interface for pfSense, think of this as the string that goes into vncell/vncellreq, or the fielddescr property for pkg_edit.php interfaces. This only applies for regular widgets - widgets like HeaderWidget set $this->drawsself to "true", so we don't draw the vncell area for them, and instead supply the raw <tr>.
- description: This will appear right below the widget. All widgets that inherit from the Widget class, don't override the getElement method and don't have $this->draws_self set support this.
Some widgets also make use of the <caption> tag. The CheckboxWidget uses it to display some information next to the checkbox (it's good for supplying information that is more complete than what's supplied in the label tag, but less complete than what's supplied in the description property). The Button widget and its descendants use it to set the string that's written on the button.
Widgets that allow choice generally receive their options from <option> tags. Those tags can appear multiple times in the same widget, and should contain the tags <label> and <name>, where <label> is the text that should be selected so that the value of the widget becomes <name>.
Most fields can display a default value if the page has not been saved to config.xml yet. Those use the property <value>. Widgets should be aware whether they are getting their value from default values set by the interface developer or if they are using values retrieved from config.xml, and adapt their look accordinagly.
There's a special widget type named "custom". It allows you to create your own widgets (generally by inheriting from cg2_widgets.inc's Widget class) and specify their class in the <class> tag.
For tables, you can also use the <not_in_table/> property. Widgets marked with that tag won't show up in tables, only in forms and wizards.
There's also the value_merger field. It merges the value of two or more wizards using either AND (<merge_and>foo_field,bar_field</merge_and>) or OR (<merge_or>foo_field,bar_field</merge_or>). It's only used in tables.
TextboxWidgets accept two special options: <validation_regex> and <validation_message>. When validating textbox widgets, if <validation_regex> is set, the widget will be validated against the regex specified (using Perl regular expressions). If it doesn't validate, the string specified in <validation_message> will be displayed as an input error.
CoreGUI2 is callback-oriented. Instead of defining PHP snippets that are eval'ed when there's an event, you should use function names that will be called when those events occur. Note that most (or maybe all events) occur within the context of <element> tags.
The most useful event is probably <on_apply_event>. It's triggered when your settings are applied. In cg2 interfaces, you generally save the interface (by clicking any Submit button on a cg2 form) and then you apply the settings by clicking the "Apply settings" button. On apply events, you should resync your configuration to config files, restart services, etc..
In order to resync your config, you must obtain information on how the interface fields were set. To do that, you generally use get_element_config($key) where $key is the <config_key> of the interface. If your interface has more than one element, use get_element_config($key, $element_index). For tables, use get_table_rows($key) or get_table_rows($key, $element_index) to retrieve an array of config arrays (one for each row).
A config array is an array holding $name => $value pairs, just like config.xml. Fields that can contain multiple values might return $value as an array of values.
There are more utility functions, so take a look at cg2_util.inc for more info. See cg2_elements.inc for a list of the current supported events. Then add more information about them here in this wiki, if possible.
Do not ever try to use $_POST directly! $_POST should only be used by internal cg2 stuff. The names you give to the widgets aren't their real names in the resulting HTML. In fact, widgets might have more than 1 HTML name each, or maybe even no HTML names at all.
- Several parts of cg2 should be reorganized for clarity and readability.
- We're gonna use session UIDs in cg2 widget HTML names for security reasons.
- More widgets should be added.
- The wizard could use some more polishing.
- Add some sort of custom button for tables.
This document is a rough introduction to the cg2 system. It's incomplete, and might contain many grammar/spelling mistakes and blatant omissions. It might also be innacurate. Feel free to expand or correct it (and expand or correct cg2 as well).
Many things are still not documented. Volunteers needed.