ClanLib SDK

Theming Model

Theme Parts

The most important class in the clanGUI theming model is the CL_ThemePart class. Essentially clanGUI themes are built around the concept that you can divide any component into areas which are then styled. A theme part is a rectangular area that is rendered in a certain way and may contain properties that hint how text and other things should be rendered within this area.

Typically theme parts are used in a nested way by the GUI components. For example, CL_ScrollBar contains the following theme parts:

One of the key features of a theme part is that it defines a content area within a render area. The render area is the rectangular area covering the entire part and the content area is the area the component may want to place additional content. CL_ThemePart contains functions that allow you to map from render area to content area and the other way. CL_ScrollBar in the above example uses these functions to position the scrollbar parts within the background part and in the same manner it uses the preferred size properties of the button parts to position the scroll track areas.

In code, the above scrollbar may have been placed like this:

CL_ThemePart background_part(component);
CL_ThemePart up_button_part(component, "button.up");
CL_ThemePart upper_track_part(component, "track.up");
CL_ThemePart thumb_part(component, "thumb");
CL_ThemePart lower_track_part(component, "track.down");
CL_ThemePart down_button_part(component, "button.down");

CL_Size component_size = component->get_size();
CL_Rect background_render_area(CL_Point(0,0), component_size);
CL_Rect background_content_area = background_part.get_content_area(background_render_area);
CL_Rect up_button_area(
	background_content_area.left,
	background_content_area.top,
	background_content_area.right,
	background_content_area.top + up_button_part.get_preferred_height());
CL_Rect button_button_area(
	background_content_area.left,
	background_content_area.bottom - down_button_part.get_preferred_height(),
	background_content_area.right,
	background_content_area.bottom);
...

The rectangles are used during the rendering. CL_ThemePart itself does not contain any information about the placement of a part:

background_part.render(gc, background_render_area);
up_button_part.render(gc, up_button_area);
down_button_part.render(gc, button_button_area);
...

Each theme part can have multiple states set, which may affect how the part is rendered and the size of its content area. Typically the standard components uses certain states such as hot and disabled, but they may also include their own states. States are set like this:

background_part.set_state("disabled", true);
background_part.set_state("hot", false);

The Default Theme

All theme parts are rendered by the current CL_GUITheme set on the CL_GUIManager object. You can implement your own theme rendering by implementing the CL_GUITheme class, but in most situations the easier way is to use the default theme provided by CL_GUIThemeDefault.

The default theme uses CSS properties for the theme. Each theme part has a fully qualified CSS name that is generated based on the type name, class name and identifier of the CL_GUIComponent that owns the theme part and the name and states of the theme part itself.

Imagine a GUI component layout as follows:

The CSS selector name for the button up part is then: window frame.myframe scrollbar#scroll0 button.up:hot

button
{
	font = "tahoma";
}

button.up
{
	font-size = 18;
}

button:hot
{
	bg-color: yellow;
	font = "arial";
}

frame scrollbar button
{
	bg-image: image1;
}

frame scrollbar#scroll0 button.up:hot
{
	bg-image: image2;
}

The property set actually being chosen amongst the above CSS examples is frame scrollbar#scroll0 button.up:hot. This is because this is the CSS selector with the highest precedence according to the CSS selector rules, which mostly is determined by the number of elements in the selector and the order in which they are presented in the file.

Some CSS properties are cascading, which means that when the chosen property set does not include a property (e.g. font), it is inherited by the first property set with a matching CSS selector, in the usual order of precedence. So in this example the font will be Arial since button:hot has a higher precedence than button.

Standard CSS Properties

For further information about the CSS properties used by the standard components and the default theme engine, see the overview for the standard components.