Skip to content
Michael Bayne edited this page Jul 27, 2011 · 2 revisions

Element Styles

Elements are styled using a system similar to cascading style sheets. However, the styles are provided entirely programmatically and instead of using style names, one uses Styles instances which contain style configuration.

Basic Styles

Styles are used to configure a variety of properties of interface elements. These include the font used to render text, the color of the rendered text, highlight and shadow colors, whether a group aligns its children left, right or center, whether a label aligns its text left, right or center, and so forth.

The Style class defines properties that are applicable to a variety of element types (e.g. Style.FONT). Styles that are applicable to only a single element type are defined in the element's class (e.g. Group.BACKGROUND).

See Common Use Cases below for examples of configuring elements with styles.

Style Resolution

There are numerous elements that interplay in the resolution of styles: the type of the element in question (e.g. Button), the interface hierarchy (e.g. a Button, its parent Group, on up to the Root), and the state of the element (e.g. default, disabled, down).

Two classes model the configuration of styles in an interface: Styles and Stylesheet. Styles defines styles applied to a single user interface element (see below on how Styles are applied to multiple elements). Stylesheet defines styles that apply to all elements of a given type (e.g. Button, Label, etc.) and can only be configured on Group elements.

The resolution of a style proceeds as follows:

  1. The element's Styles instance is checked for the desired style in the element's current state. If a binding is found, it is used.

  2. If the element is itself a group, step 3 is performed using the element itself, otherwise the element's parent is checked, per the normal step 3 resolution.

  3. The Stylesheet configured for the element's parent group is checked for a binding for the triple (type, state, style) (e.g. (Button, down, background)). If one is found, it is used.

  4. If the style being sought is inherited, the original element's parent type is next queried for a binding (e.g. (Element, down, background)). If no binding is found, the next parent type is checked until Element has been checked. If the style being sought is not inherited, only the concrete type of the element will be checked.

  5. If no binding was found in step 3 and 4, the next parent Group will have its Stylesheet searched for a binding. The search will proceed thusly up to the Root group. If no binding is found at the Root, a global default (provided by the UI toolkit) will be used.

Though the resolution process may seem a bit complex, in general one uses it in a way that is simple and straightforward. The next section will describe these common use cases.

Common Use Cases

One will usually configure their Root element with a Stylesheet that configures the styles of all interface elements with the desired look and feel for the game in question.

Where common special stylings are desired for elements (e.g. title labels), one will generally configure a Styles instance as desired for the use case and configure that on all appropriate elements:

public static final Styles titleStyles = Styles.none().
  set(Style.FONT, ForPlay.graphics().createFont("Helvetica", Font.Style.BOLD, 24)).
  set(Style.COLOR, 0xFF222222);

Label title = new Label("Awesome Things!");
title.setStyles(titleStyles);

If all of the elements in a particular Group are meant to be customized in a particular way, a Stylesheet can be provided to the Group when constructed:

Stylesheet sheet = Stylesheet.builder().
  add(Button.class, Styles.none().set(Style.FONT, smallFont)).
  add(Label.class, Styles.none().set(Style.COLOR, 0xFF99CC99)).
  create();
Group group = new Group(layout, sheet);
Clone this wiki locally