Developer Guide - Rulesets - Interface
All user interface within a ruleset is defined using window classes. Windows are specific instances of window class assets. Windows act as containers for window controls. Window controls are the individual user interface units that implement functionality, such as number fields, scrollbar controls and status icons.
Windows can also be embedded within other windows using container window controls (subwindow) and window list controls (windowlist). This allows complex sheets to be built up to support concepts, such as inventory lists and PC sheet tabs.
All layout within FG is specified via pixel offsets starting at the top-left corner of the layout space. Windows are laid out relative to the FG tabletop display space, while window controls are laid out relative to the window instance which contains them.
The initial desktop view of the ruleset is defined by using panels and the desktop frame setting. All other top level window class instances are opened via interaction with the API or the interface within open window instances.
The appearance and functionality of each window is determined by the window class it is created from. A window class is a concept that defines a certain type of window used for a specific purpose. You can think of window classes as blueprints by which individual windows are built. Several existing windows can share the same window class.
Window classes are defined using the "windowclass" tag. Among the things defined are the default, minimum and maximum sizes of the window. The window class definition also lists the controls the windows created based on the class contain. The window class definition can also contain a script block to support more complex logic.
Examples of window classes are character sheets, image windows and NPC sheets.
<windowclass name="note"> <frame>storybox</frame> <placement> <size> <width>250</width> <height>306</height> </size> </placement> <sizelimits> <dynamic /> </sizelimits> <minimize>minimized_note</minimize> <playercontrol /> <sharable /> <tooltip> <field>name</field> </tooltip> <sheetdata> <windowreferencecontrol> <bounds>15,11,20,20</bounds> <icon> <normal>button_openwindow</normal> <pressed>button_emptytarget</pressed> </icon> <class>note</class> <description> <field>name</field> </description> </windowreferencecontrol> <stringfield name="name"> <bounds>40,13,-15,20</bounds> <empty>« New Note »</empty> <font>sheettext</font> <nodrag /> <nodragselect /> </stringfield> <stringfield name="text"> <bounds>10,40,-15,-15</bounds> <multilinespacing>18</multilinespacing> <font>sheettext</font> </stringfield> </sheetdata> </windowclass>
The individual windows created using a window class as a blueprint are called window instances. All window instances are identified by a unique combination of two parameters: the window class and the window database path.
The window database path is the database node whose child nodes contain the values for the data fields in the particular window. Thus, several windows of the same kind can exist, pointing to different data contents. Two windows with the same class and the same database path can't exist.
It is possible to create windows without a database path. The fields in such a window do not reference the database by default, and the values in the fields are therefore not stored when the window is closed and opened again. An unbound window's database path is treated as an empty string value, acting as a valid unique identifier for the database path of a window. Therefore, two unbound instances of a single window class can't exist at the same time.
Windows are also contained in some controls. A container window control (subwindow) contains a single window, and a window list control (windowlist) can contain zero or more windows. These windows are referred to as embedded windows. They contain the same definitions as top level windows, but do not typically contain size limits.
Windows can be created using link window controls (windowreferencecontrol), from desktop panel objects or via scripting. Embedded windows are automatically created by the containing window control.
Window objects are represented in scripts by windowinstance objects, which can be extended using the script block of the window class.
Examples of specific window instances are a PC sheet for a character named Langston, the NPC sheet for a goblin, or the map of the campaign world.
Controls are user interface elements contained in windows, and provide the concrete level of interaction possibilities for the user. There are several different types of controls available.
- Value controls = Contain a value of a specific type: number, string, formatted text, dice pool, token, window link, or image. There are dedicated control types for each value type.
- Utility controls = Provide means of organizing or navigating the interface. Examples include: subwindow, windowlist, scrollbar, scroller and buttonscrollers and buttons.
- Button control = Can be used as either a numerical value control (by defining multiple states), or as a utility control.
- Generic control = Basic control that only can specify an icon.
New functionality and meaning can be defined for controls by extending their operation through scripting.
The Ruleset API Reference contains information on each control type. Controls can be identified by looking in the Elements section for elements whose context (specified at the top of the element pages) is "windowinstance".
Controls are defined in the "sheetdata" section of a window class definition. The controls are laid out and drawn starting with the topmost entry in the sheet data definition. This means that when using anchoring (see below), the controls acting as anchors should always be specified first. When control areas overlap, the ones defined later will be drawn on top. All controls should have a position. The next section specifies the available positioning alternatives.
In addition to the positioning information below, controls have additional tags shared by all window controls to define background frames, tooltips, tab order, and more. See the Ruleset API Reference for the "windowcontrol" element for more information.
Almost any custom control types can be created by using a combination of a generic control type, widgets and templating. See below for information on widgets, and the separate Ruleset Templates topic for more information on templating.
There are two basic methods available for defining the position of a control in a window. First, the position of the control can be given as basic pixel coordinates. Second, the control edges can be anchored to follow the edges of another control or the window itself.
The basic format of static position coordinates is four positive integer numbers, measured in pixels.
- X coordinate (horizontal position of left edge)
- Y coordinate (vertical position of top edge)
- Width of the control
- Height of the control
The following example would create a control 150 pixels wide and 200 pixels high, set 15 pixels from the left edge of the window and 30 pixels from the top.
A slightly more complex set up involves negative coordinates. Any or all of the four numbers may be negated, with the following results, respectively:
- X coordinate of the left edge of the control is calculated from the right edge of the window
- Y coordinate of the top edge of the control is calculated from the bottom edge of the window
- Width of the control is automatically adjusted to be such that the right edge of the control is the specified number of pixels from the right edge of the window
- Height of the control is automatically adjusted to be such that the bottom edge of the control is the specified number of pixels from the bottom edge of the window
The following example creates a control whose left edge is 15 pixels from the left edge of the window, and right edge 15 pixels from the right edge of the window. The width would be equal to the window width minus 30 pixels. The top edge would be 40 pixels from the bottom of the window. The height of the control would be 25 pixels, due to the fact that the bottom edge would be calculated to be 15 pixels from the bottom of the window.
When using the anchored positioning scheme, edges of the control are tied to other controls in the window or to the window edges. The width and height of the controls can be explicitly specified, or calculated from the edges. Due to the verbose nature of anchor definitions, a shorthand notation defining some of the most common setups is provided as a convenience feature.
It is also possible to omit the anchoring on opposite edges or the width/height definition, to dynamically size a control to its contents, such as a string control growing to accommodate the text. In such cases, it is often recommended to omit only one edge (typically right or bottom) for best results.
To define anchors, use the "anchored" tag.
The edges are anchored by specifying a nested "left", "top", "right" or "bottom" tag. Each edge anchor can contain three children:
- "parent" tag or attribute = Contains a string value identifying the name of the control to which the edge is being anchored. If this tag is omitted or the empty value, the anchoring will be done to the window edges.
- "anchor" tag or attribute = Identifies the edge on the target from which the position is calculated. If this tag is omitted, the matching edge will be used (i.e. left anchors to left edge of parent)
- "offset" tag or attribute = Contains a number value by which the edge is adjusted after the anchoring calculations. A positive value indicates a shift to the right or down, a negative to the left or up.
An explicit width or height can be defined for an anchored control by specifying "width" and/or "height" attributes for the "anchored" tag, or by defining a "size" child tag with "width" and/or "height" children or attributes.
The following two definitions places the control to the right of a control called "label", with the top of the control being 5 pixels from the top of the window. The size of the control is 30 pixels by 22 pixels.
<anchored> <left> <parent>label</parent> <anchor>right</anchor> </left> <top> <anchor>top</anchor> <offset>5</offset> </top> <size> <width>30</width> <height>22</height> </size> </anchored>
<anchored width="30" height="22"> <left parent="label" anchor="right" /> <top offset="5" /> </anchored>
There is also a special construct available, for stacking any number of controls onto an anchoring control so that all the anchored controls avoid overlap. To do this, a fourth tag or attribute called "relation" may be specified inside the individual anchor tags.
If the value of this parameter is "absolute" (the default), the controls are placed as described above. A value of "relative" will cause the control to be anchored at the location of the last "relative" control that anchored to the parent control. The next successive "relative" control will receive an adjusted location based on the current control. A value of "current" will cause the control to be anchored at the location of the last "relative" control, similar to "relative". This value will not, however, adjust the position of the next "relative" or "current" control, and is useful for creating stacked rows or columns.
Some typical anchoring schemes can also be set up using a shorthand notation. To use the shorthand notation, three tags are placed under the <anchored> tag.
- "to" tag or attribute = Indicates the name of the control to anchor to. If specified, all specific anchors will use this value as the parent attribute unless overriden.
- "position" tag or attribute = Defines the position relative to the parent control (see above)
- "offset" tag or attribute = Contains two integer numbers, separated by a comma. These define the horizontal and vertical offset, respectively, applied to the positioning. These numbers are treated such that they increase the distance between the two controls, so the actual direction varies by position. For edge positions (insidetop, above, left, etc.), a positive offset will make the anchored control larger than the anchor target, while a negative offset will make it smaller.
The shorthand notation can be combined with the standard anchors, with the standard anchors overriding the shorthand form.
It is usually desirable to define the width and/or height explicitly, or specifying an additional anchor using the standard anchoring scheme. The following example creates a control to the right of "initresult". The height of the control is the same as the anchor target's, and the width is explicitly set to 34.
<anchored> <to>initresult</to> <position>right</position> <offset>5,0</offset> <size> <width>34</width> </size> </anchored> <pre> <pre> <anchored to="initresult" position="right" offset="5,0" width="34" />
Widgets are graphical elements that can be added to any control, to implement custom functionality or serve as indicators. They are not directly definable through the XML definition, and require a scripting implementation. There are two widget types available: text widgets and bitmap widgets.
Widgets are added to a control using the addTextWidget or addBitmapWidget API functions available to any window control. See the "widget" interface in the Ruleset API Reference for details on interacting with the widget script object.
Widgets are positioned relative to one of the corners or the center point of a control. The position of the widget may be offset in the vertical and horizontal directions.
Text widgets (textwidget) contain a text string and a font asset to use to display the text. For widgets that contain a string definable by the user, it is recommended to set the maximum width allowed. Text widget content causing the maximum width to be exceeded is truncated and preceded by three dots ("...").
Bitmap widgets (bitmapwidget interface) can contain icon asset graphic.
Each widget can optionally have a frame asset associated with it. The frame is drawn as the widget background, under the actual contents of the widget.
The elements that automatically appear on the tabletop when first loading a campaign are implemented using panels. A panel is a reference to a window class and tabletop layout information.
Each panel contains a window. The panel window is always created with no data source. The window class used for the panel should not contain any positioning or size constraints. In other regards, the window functions similarly to conventional windows and can contain all the same functionality. Panels are positioned relative to the tabletop or other panels similar to how controls are laid out within a window.
Panel definitions can contain a mode attribute defining whether they are created in "host" (GM), "client" (player) or "local" (manage characters) modes. These can be combined by indicating several in the value of the attribute, separated by a comma character. Omitting the mode attribute will cause the panel to be created in all modes. Similarly named panels with differing mode specifications can contain different contents.
The following creates a panel attached to the bottom of the desktop, being offset from the bottom by 15 pixels and having a height of 20 pixels. It spans the width of the desktop from the left edge to the left edge another panel called "shortcuts". It is only active when running as a session host.
<panel name="identitylist" modes="host"> <class>identitylist</class> <anchored> <bottom> <anchor>bottom</anchor> <offset>-15</offset> </bottom> <right> <parent>shortcuts</parent> <anchor>left</anchor> </right> <left> <anchor>left</anchor> </left> <size> <height>20</height> </size> </anchored> </panel>
<panel name="identitylist" modes="host"> <class>identitylist</class> <anchored> <bottom anchor="bottom" offset="-35" /> <right parent="shortcuts" anchor="left" /> <left anchor="left" /> <size height="20" /> </anchored> </panel>