TWL themes

TWL stands for Themeable Widget Toolkit. TWL comes with many useful widgets and new widgets are easily created. It has a powerful framework for applying customizable themes to widgets. A theme customizes everything that is drawn for a widget. Creating themes is fundamental to making use of TWL in an application.

Contrary to most GUI toolkits, with TWL it is easiest to start by create a new theme from scratch. As each new widget is used in the GUI that is being built, that widget's theme will be created. While TWL has premade themes, making use of them requires thorough knowledge of how themes work. Also, premade themes typically contain many widgets that an application does not make use of. Beginning TWL by attempting to edit a large, complex theme is quite daunting.

The tutorial covers how to create themes for all basic TWL widgets. A good portion of TWL feature's are explored in the process. The end result isn't a terribly pretty theme, but it should be clear how to use your own graphics for your own themes.

Theme Editor setup

TWL comes with a powerful tool for customizing themes. The tool itself is built with TWL and serves as a great example of the complex user interfaces that are possible. The Theme Editor can be run by clicking the following link:

http://twl.l33tlabs.org/themer/themer.jnlp

To get started in a new theme, run the Theme Editor and create a new project by clicking File -> New Project. This creates three files:

  • font_00.png and font.fnt: This is a default font. It can be replaced later using Tools -> Create Font. A font is made up of an image containing all the glyphs and an XML file describing the glyph information (advance, kerning, etc).
  • An XML theme file that contains your theme's information.

Theme defaults

The XML theme file is loaded in the XML viewer, which is the upper left pane of the Theme Editor:

defaults.gif

The first node is named "normal" and is of type "fontDef", which is a font definition. When selected, its parameters are shown in the parameters pane, which is below the XML viewer:

defaults-font.gif

The name is an identifier that can be used to reference the font definition in other parts of the theme. It is named "normal" because this font definition is for regular text on a widget. The font file name is that of the file automatically created with the new project. The font color is self explanatory.

Under the "normal" font definition is a number of "fontParam" nodes. These specify a condition and a font color:

defaults-fontparam.png

The condition is simply a string that can be set on a widget. The theme can change based on the condition strings. In this case, the font color will change to red if the "error" condition is set on the widget.

Under the "normal" font definition is an node titled "<inputMapDef>", which is an input map definition. This is used to map inputs such as ctrl+C to commands such as "copy". The Theme Editor shows its type as "Unknown", meaning that editing this element is currently not supported. The curious can open the theme XML file in a text editor to see the default input map, otherwise just ignore it for now.

Next, there is a theme node named "-defaults". Themes can inherit from other themes, and the "-defaults" theme is intended to provide defaults for many common theme parameters. A common TWL convetion is to start theme names with "-" if they are "abstract" (intended to be extended and not used directly). Click each node to see its values. Most nodes are not very interesting at this point, but do notice that the "font" node has a value of "normal". This references the font definition described above.

The last node in the XML viewer is named "label". This is where things begin to get interesting. TWL has a Label widget that is used to display text. By default, the Label widget has a theme of "label". This means TWL will look for a theme with this name and use those parameters for rendering the Label. There are no parameters under the "label" theme, because the Label widget is very simple and only needs a few parameters. Clicking the "label" theme shows it inherits from the "-defaults" theme.

Widget preview

The Theme Editor has the ability to render a GUI, allowing the theme to be visualized as it is built. Click Widgets -> Built-in Widgets -> Label. A Label widget will appear in the preview pane, which is the black pane in lower center of the Theme Editor:

widget-label.gif

To prove this Label is using the theme, go ahead and change the font color for the "normal" font definition. The Label widget will change in real time.

Widgets are shown in the widget pane, which is in the upper right of the Theme Editor. The widget's name is colored red when the theme cannot be found. The name is colored orange when the theme is found, but some theme parameters could not be found. Hover the mouse over than name to see which parameters are missing:

theme-warnings.png

Note that because the "-defaults" theme provides defaults for many parameters (such as "background"), those parameters won't show up in the list of parameters that could not be found.

Widgets in the preview pane can be inspected by selecting them in the widget pane. Alternatively, the magnifying glass icon can be dragged and dropped on a widget in the preview pane. The chosen widget's properties are shown in the widget property pane, which is in the bottom right of the Theme Editor:

widget-properties.gif

This shows everything about the widget: what theme is applied, the text the widget uses, etc. The properties can be modified to see how the theme reacts.

Button

Click Widgets -> Built-in Widgets -> Button. This displays the Button widget in the preview pane:

widget-button1.gif

Nothing is displayed because by default the Button widget uses a theme named "button", which has not been defined. To do this, click the root in the XML viewer, then click the "plus" button which is in the toolbar under the XML viewer:

create-theme.gif

Choose "Create a new theme node", then name the new node "button". Be sure to press enter or click the checkbox next to the typed name so it will be applied. Once the theme is named "button", the preview pane will redraw the Button widget:

widget-button2.gif

The button text can now be seen because the "button" theme by default inherits from the "-defaults" theme:

button-defaults.gif

The Button widget uses a parameter named "font" to display its text, and this parameter is provided by the "-defaults" theme.

Backgrounds

The button still doesn't look like a button yet. It needs some graphics. For this tutorial, this graphic will be used to skin various widgets:

widgets.png

Save this file in the theme's project folder. Click the root in the XML viewer, then click the "plus" button and choose "Create new images node". Specify the image and click OK:

specify-image.gif

The PNG image is loaded in the image pane, which is in the upper center of the Theme Editor:

widgets-image1.png

The order of the nodes in the XML viewer is significant. The "button" theme won't be able to use the PNG image node unless the "button" theme comes *after* the PNG image node. Use the "Up" button on the toolbar under the XML viewer to move the PNG image node until it is the first node under the root. If this is not done, it can be very perplexing when images are not being applied.

Next, be sure the PNG image node is selected in the XML viewer, click the "plus" button, and choose "Create new area node". This is used to slice the image up into pieces. Name the area "box". Notice that the image disappears in the image pane when the area node is selected. To fix this, click the "All" button in the image pane. Now click and drag on either the X or Y widget in the image pane to zoom in, and click and drag the image to pan until the border in the upper left is easily visible. The dashed lines show the area node's bounds. Click and drag them to surround the portion of the image that will be used for the button's background:

widgets-image3.png

The dashed lines are somewhat difficult to see in the screenshot. The area's bounds are displayed in the parameters pane and can also be edited there:

box-params1.png

Next, check "No Center" and check both "Split X positions" and "Split Y positions". Click and drag (or double click) the widgets under the checkboxes to get these values:

box-params2.png

The image pane will now look like this:

widgets-image4.png

This cuts the image up into 9 pieces: the four corners, the four images between the corners, and the center. The four images between the corners will be stretched. The center is not used because "No Center" was checked.

To apply the image to the button, select the "button" theme in the XML viewer, click the "plus" button, and choose "Create a new image parameter". Change the name to "background" and set the "Image reference" to "box". The image is now applied to the button:

widget-button3.png

This works because the Button widget looks for a theme parameter named "background" to use for a background image. The "Image reference" points to the area that is named "box".

Select the "button" theme, click the "plus" button, and choose "Create a new border parameter". Change the name to "border". Click and drag the widgets to set "L" (left) and "R" (right) to 10. This gives the button a border, so there is more space around the button text:

widget-button4.png

Conditional backgrounds

The button should look like it is pressed when the mouse is down. Select the PNG image in the XML viewer, click the "plus" button, and choose "Create a new select node". Change the name to "button.background". The select node allows different nodes to be used based on various condition strings.

Click the "plus" button again and choose "Create a new alias node". For the "Ref" parameter, choose "box". An alias node just points to another node, making it easy to reuse the same node multiple times. Because this alias has no "Condition" set, it will be used if none of the other nodes under the select node have conditions that are met.

Click the "Duplicate" button in the toolbar under the XML viewer, then click the newly duplicated alias node. Set the "Condition" to "If" and type "pressed" in the condition text box. Next, check "Inset" and set "T" (top) and "L" (left) to 2 and "B" (bottom) and "R" (right) to -2. This will shift the image down and to the right 2 pixels.

The XML viewer will now look like this:

composed.png

Go back to the "button" theme's "background" parameter and change the "Image reference" to "button.background". Now when the button is clicked in the preview pane, the button's background will shift down and to the right 2 pixels. This happens because the Button widget sets its "pressed" animation state to true when the mouse is pressed. The "button.background" select then chooses which background to use based on the "pressed" condition.

Conditional font parameters

The button's text should also look like it is pressed when the mouse is down. Select the "normal" font definition node and click the "Duplicate" button in the toolbar under the XML viewer. Change the name to "button.font". Click the "plus" button and choose "Add a new font parameter". Set the condition to "pressed" and set both "Offset X" and "Offset Y" to 2.

Select the "button" theme, click the "plus" button, and choose "Create a new font parameter". Change the name to "font" and set the "Font reference" to "button.font". The button text will now move down and to the right 2 pixels when the button is pressed.

Composite backgrounds

The image for the "box" area is white. This allows it to be tinted any color using the "Tint color" parameter for the area. The "box" image is just a border, the center is transparent. The idea is to use a separate image for the center, which can be tinted differently from the border.

Click the "box" theme, then the "Duplicate" button in the toolbar under the XML viewer. Change the name to "box bg" and change the "Rect" and split positions to:

boxbg-params.png

Also check "Border" and set all four border values to 2.

Click the image in the XML viewer, click the "plus" button, and choose "Create a new composed node". Change the name to "panel-blue". Click the "plus" button, choose "Create a new alias node", and set the "Ref" to "box bg". Adjust the "Tint color" to some shade of blue.

Click the "plus" button, choose "Create a new alias node", and set the "Ref" to "box". Adjust the "Tint color" to some shade of green.

Now go to the "button.background" select node and change the "Ref" for both aliases to "panel-blue". This will use the composed node for the button background image:

widget-button5.png

Select the "panel-blue" composed node and click the "Duplicate" button in the toolbar under the XML viewer. Change the name to "panel-red". Change the tint color of the first alias to some shade of red.

Select the "button.background" select node and add an alias node. Set the "Ref" to "panel-red" and change the condition to "hover". Under a select node, the child without a condition must always be last, so use the "Up" button on the toolbar under the XML viewer to move the alias up one.

Now when the mouse is over a button, the "panel-red" composed node will be used.

Widget

The Widget class is the base class for all TWL widgets. It can also be used on its own. It can be used as an invisible container for other widgets. It can also be given a theme for a more decorative container.

Create a new theme under the root and name it "panel". Add an image parameter to it named "background" and set the "Image reference" to "panel-blue".

Add a Widget to the preview pane by clicking Widgets -> Built-in Widgets -> Widget. Change the theme in the widget property pane to "panel". Set the widget's width and height so it can be seen:

widgets-panel.png

ToggleButton

Create a new theme under the root named "togglebutton". Set "Base theme reference" to "button". Add a ToggleButton widget to the preview pane by clicking Widgets -> Built-in Widgets -> ToggleButton.

A ToggleButton is just like a Button except it has a "selected" state to indicate that it is stuck down. The states can be seen in the widget properties pane. By inheriting from the "button" theme, the ToggleButton will look just like a Button. It just needs a little work to make it look stuck down when it has the "selected" state.

Go to the "button.background" select node and select the "IF(pressed)" child node. Change the condition to "pressed|selected". This will cause the condition to be met if the widget has either "pressed" or "selected". This will not affect a Button widget, since it doesn't have a "selected" state.

Go to the "button.font" font definition and change the "pressed" condition to "pressed|selected".

Now the ToggleButton in the preview pane can be clicked and will stay stuck down.

Checkbox

TWL doesn't have a notion of a checkbox. The ToggleButton is identical in every way, it just looks different. Since TWL allows the looks to be completely customized, it is easy to make a ToggleButton look like a checkbox.

Add a new grid node under the PNG image node. Name it "checkbox.background". Set the weights this way:

checkbox-weights.png

Add four area nodes:

checkbox-grid.png

Set the bounds of the areas to:

  • 1,1,12,12
  • 31,1,12,12
  • 1,23,12,12
  • 31,23,12,12

This maps the grid to the four corners of the border used earlier for buttons.

Add a new area node to the PNG image node. Name it "checkbox.overlay". Set its bounds to the checkmark image:

check-params.png

Set the "If" condition to "selected". Set "Centered" to be pressed. Set "Inset" to -12,0,0,-7.

Create a new theme under the root named "checkbox". Add an image parameter named "background" and set it to "checkbox.background". Add another image parameter named "overlay" and set it to "checkbox.overlay". The overlay parameter is similar to a background, except it is draw on top.

Now add a ToggleButton to the preview pane and change its theme to "checkbox". Clear the text property. Set both the width and height to 24 (this matches the size of the "checkbox" grid). Set the X and Y to 25 so the top of the widget doesn't go outside the preview pane. When the ToggleButton is clicked, the "check" image will be overlayed:

widgets-checkbox.png

Radio Button

A radio button is really just a checkbox with a different overlay image. Select the "checkbox" theme in the XML viewer and click the "Duplicate" button in the toolbar under the XML viewer. Renamed the new theme to "radiobutton".

Under the PNG image, add a new alias node named "radiobutton.background" and set it to "checkbox.background". Change the "background" image parameter under "radiobutton" to "radiobutton.background". Note the "radiobutton" theme could just as easily used the "checkbox.background" area, but it is cleaner to explicitly define the image for the radio button, should it ever need to be changed in the future.

Under the PNG image, add a new area node named "radiobutton.background" and set its bounds to:

radiobutton-params.png

Set the "If" condition to "selected". Set "Centered" to be pressed.

Change the "overlay" image parameter under "radiobutton" to "radiobutton.overlay". The radio button will now look like this when selected:

widget-radiobutton.png

EditField

In TWL, the EditField widget provides a box for entering text.

Under the PNG image node, add a new alias node named "editfield.background" and set it to "box". Create a new theme named "editfield". Add a "background" image parameter and set it to "editfield.background". Add a "border" parameter and set it to 0,10,0,10.

Now create another theme under the "editfield" theme named "renderer". This is needed because internally the EditField uses a child widget to render the text so that the text can be clipped if it is longer than the EditField. Because the "renderer" theme is used to render the text, it determines the font that is used, not the "editfield" theme.

Add an EditField to the preview pane. Click in it and type some text. Its width can also be set so the text is not clipped:

widgets-editfield.png

Click and drag to select some text. The text turns blue because the "normal" font definition has an "IF textSelection" parameter set to blue.

The EditField would look better with a cursor. Under the PNG image node, add a new area node named "white". Select any single, solid white pixel, eg:

widgets-cursor.png

This area can be very useful. Create a new alias node named "editfield.cursor", set it to "white", and tint it a bright blue color. Now add an image parameter named "cursor" to the "editfield" and set it to "editfield.cursor". A blue cursor will appear in the preview pane.

A selection background can also be specified. Under the PNG image node, add a new alias node named "editfield.selection", set it to "white", and tint it a blue color. Set the "A" (alpha) to 128 (50% opacity).

widgets-editfield2.png

Wildcard images

A widget often has many images. Specifying the area under the PNG image node and then specifying it again under the theme is tedious. A wildcard can be used in the image parameter to make this easier, though understanding what is going on can be a bit tricky at first.

Under the "editfield" theme, delete the "background", "cursor", and "selection" image parameters. Add a new image parameter. Delete the text in the name so it is blank. Set the "Image reference" to "editfield.*". Note that the preview pane shows the EditField still successfully finds the "editfield.background", "editfield.cursor", and "editfield.selection" images.

When the EditField widget needs an image, it looks at its image parameters. If it finds one that matches, it uses the matching parameter's image reference to find the image. Otherwise, if an image parameter has a wildcard, it takes the image parameter name (if any) plus the image reference with the "*" replaced by the name of the image it is looking for. It then uses the result as the image reference.

For example, the widget needs an image named "background". It looks for an image parameter named "background". If it were to find one, it would use its image reference to find the image. Instead, it finds an image parameter with a name of "" and an image reference of "editfield.*". Since the image parameter name is blank, it isn't used. The widget replaces the "*" with "background" and uses the resulting "editfield.background" as the image reference to find the image.

A common problem occurs if the image parameter is given a name. In the previous example, if the image parameter with the wildcard was named "images", then the resulting image reference would have been "images.editfield.background".

When using an image reference without a wildcard, if the image cannot be found, the Theme Editor will highlight the node in the XML viewer in red. When using a wildcard, this can't be done since the wildcard can match any number of images. What a wildcard matches can be seen by clicking the "jump" button next to the image reference field:

wildcard.png

Horizontal Scrollbar

Add an HScrollbar to the preview pane. The widget pane shows that the widget uses a theme named "hscrollbar", with three themes under that named "leftbutton", "rightbutton", and "thumb". Create these themes:

hscrollbar-themes.png

The "hscrollbar" theme in the widget pane changes from red to orange. Hover over the theme to see what is missing:

hscrollbar-missing.png

Add a boolean parameter named "scaleThumb" to the "hscrollbar" theme . The "hscrollbar" theme in the widget pane is now black, indicating that all the theme parameters it needs have been found. However, nothing is drawn in the preview pane because the themes that make up the HScrollbar inherit from "-defaults", which provides a "background" image parameter set to "none".

Add an image parameter named "background" to all four themes. For "hscrollbar" set the background to "box". For the others, set the background to "panel-blue". In the widget property pane, increase the width of the HScrollbar so the thumb button can be dragged. The widget is now visible and can be manipulated with the mouse:

widget-hscrollbar.png

It would be nice if the HScrollbar button had a different image when pressed with the mouse. This is the same behavior as "button.background", but without the "Inset" that shifts the button when pressed. Select "button.background" and click the "Duplicate" button in the toolbar under the XML viewer. Name the new select "hscrollbar.button". Change the "pressed|selected" condition to just "pressed" and uncheck "Inset". Now change the "leftbutton", "rightbutton", and "thumb" backgrounds to use "hscrollbar.button". These three buttons will now turn red when the mouse is over or pressed on them.

The size of the buttons is determined by their background image. The "panel-blue" composed node is made using the "box" area, which is 42x34. This is the minimum size the HScrollbar buttons will size to. To make them smaller, select "hscrollbar.button", check "Size overwrite horizontal", and set it to 26:

widget-hscrollbar2.png

Maybe the "thumb" button could look better. Select the PNG image and add an area node named "hscrollbar.thumb.overlay". Check "Centered" and set the area bounds like this:

hscrollbar-thumb-params.png

Now add an images node to the "thumb" theme and name it "overlay". The result:

widget-hscrollbar3.png

If the "scaleThumb" boolean parameter is set to true, the thumb will increase in size as appropriate for the scrollbar's width, minValue, maxValue, and pageSize.

Vertical Scrollbar

Add a VScrollbar to the preview pane. This widget is very similar to an HScrollbar. Select the "hscrollbar" theme and click "Duplicate", then rename the new theme to "vscrollbar". Rename the "leftbutton" to "upbutton" and the "rightbutton" to "downbutton".

widget-vscrollbar1.png

Obviously the buttons are too narrow and too tall. Duplicate "hscrollbar.button" and name it "vscrollbar.button". The "box" area is 42x34 and "hscrollbar.button" used "Size overwrite horizontal" set to 26, so the HScrollbar button sizes are 26x34. The VScrollbar button sizes should be 34x26. For the "vscrollbar.button" theme, set the size overwrite for horizontal to 26 and vertical to 34. Next, change the background of the three themes under "vscrollbar" to use "vscrollbar.button":

widget-vscrollbar2.png

The last thing to do is fix the thumb overlay. Duplicate "hscrollbar.thumb.overlay", name it "vscrollbar.thumb.overlay", and set the bounds:

vscrollbar-thumb-params.png

Change the bakground of the "thumb" theme under "vscrollbar" to "vscrollbar.thumb.overlay":

widget-vscrollbar3.png

Scrollpane

Add a TextArea to the preview pane. Note in the widget pane that the TextArea is in a Scrollpane. Create the necessary themes for the scroll pane and also a "hasDragButton" boolean parameter:

scrollpane-themes.png

Change the "hscrollbar" under "scrollpane" to inherit from "hscrollbar". Change the "vscrollbar" under "scrollpane" to inherit from "vscrollbar".

Nothing appears in the preview pane yet. Create a theme named "textarea". We will finish themeing TextArea later, but this is enough to make the scrollbar visible:

widget-scrollpane.png

In the widget property pane, change the "fixed" setting on the Scrollpane to see either the horizontal or vertical scrollbar, or choose "none" for both. Adjust the width and height of the Scrollpane to see how the scrollbars react.

If "hasDragButton" is checked, when both scrollbars appear, the space in the lower right corner, between the scrollbars, can be clicked and dragged. To see the drag button, create a theme named "dragButton" under "scrollpane" and have it inherit from "button". Set the Scrollpane "fixed" property to "none" and click the "Adjust Size" button to get the Scrollpane to redraw with the drag button visible:

widget-scrollpane-drag.png

TextArea

The TextArea is an advanced widget. It can simply display text with wrapping, but it also has limited support for HTML and CSS. It supports embedded images, bullet points, hyperlinks, multiple fonts, block text, embedded widgets, and floating elements. A <a href="http://twl.l33tlabs.org/demo/textdemo.jnlp">demo application</a> is available. Be sure to click the "Table Demo" link and then click the image. The HTML files used by the demo can be seen <a href="http://hg.l33tlabs.org/twlexamples/file/tip/src/textarea/">here</a>.

Add a "parameter map" parameter named "fonts" to the "textarea" theme. Select "fonts" and add a font parameter named "default" and set it to "normal". This is the font used by the TextArea if a font is not specified. Fonts can be specified using CSS. Eg, if "fonts" has a font parameter named "big", then in the TextArea "<div style='font-family:big'>...</div>" can be used.

Add a "parameter map" parameter named "images" to the "textarea" theme. Images can be specified using an IMG tag. Eg, if "images" has an image parameter named "house" then in the TextArea "<img src='house'>" could be used.

ListBox

Add a ListBox to the preview pane. Create a new theme named "listbox". Add an image parameter named "background" and set it to "panel-blue". Under "listbox", creeate a new theme named "display" and have it inherit from "label". The "display" theme determines how the items in the ListBox are drawn:

widget-listbox1.png

To fix the text from being drawn too close to the edge, add a border parameter named "border" to the "listbox" theme. Set the border to 5,10,5,10.

Add a theme named "vscrollbar" to the "listbox" theme and set it to "vscrollbar". This will be used if the items in the list require vertical scrolling. The ListBox is automatically sized to be tall enough to fit all the elements. Add an integer parameter named "maxHeight" to "listbox" and set it to 150. Click the "Adjust Size" button to have the ListBox relayout with the new setting:

widget-listbox2.png

The "display" theme gets the "selected" state when an item is selected. Select the PNG image and add an alias node named "listbox.display.background". Set the "Ref" to "white". Set the "Condition" to "If" and enter "selected" in the condition text box. Check "Tint" and choose an appropriately hideous green color. Finally, add an image parameter named "background" to the "display" theme and set it to "listbox.display.background". The ListBox will now show the selected item:

widget-listbox3.png

This shows how to use a solid color for selection. Of course, any image could have been used for the selected item background.

If desired, the "display" theme can be given a border parameter so the text is not so close to the left edge of the selection.

Combobox

Add a ComboBox to the preview pane. Create a new theme named "combobox" and have it inherit from "panel". Under "combobox", create a new theme named "display" and have it inherit from "label". Also under "combobox", create a new theme named "display" and have it inherit from "button". The ComboBox should now be visible:

widget-combobox1.png

The "combobox" theme is for the entire ComboBox widget. The "display" theme is for the left part of the widget that displays the currently selected item. The "button" theme is for the right part of the widget, which typically looks like a button for opening the ComboBox.

Currently nothing is drawn when the ComboBox is clicked. Under the root, create a new theme named "comboboxPopup". Under that, create a new theme named "listbox" and have it inherit from "listbox". The popup should now appear:

widget-combobox2.png

To fix the selected text from being drawn too close to the edge, add a border parameter named "border" to the "display" theme under "combobox". Set the border to 0,10,0,0.

Select the PNG image and add an area node named "combobox.button.overlay". Check "Centered" and set the area bounds like this:

combobox-params.png

Now add an images node to the "button" theme under "combobox" and name it "overlay". The result:

widget-combobox3.png

Focus Rectangle

Most GUIs have use a dotted rectangle to indicate when a widget has keyboard focus. Implementing this in TWL is slightly more advanced than what has been done so far. Begin by creating a grid node named "dotted box" under the PNG image. The grid will have 3 columns and 3 rows. Add an area for each cell, except for the center add an alias set to "none":

focus-theme.png

Set the bounds of each area to match this image:

focus-grid.png

Row 0, column 1 and row 2, column 1 should both be set to "Repeat horizontal". Row 1, column 0 and row 1, column 2 should both be set to "Repeat vertical".

Next, set the "Inset" of the "dotted box" to 6,6,6,6.

Create a new select node named "focus-rectangle" under PNG image. Add an alias node to it set to "none". This will be the default state, which is always last. Add an alias node set to "dotted box" and set the condition to "IF" and the condition text to "keyboardFocus". Move the node up one so it is not last.

Select the "button" theme and add an image parameter named "overlay". Set it to "focus-rectangle". Add a Button to the preview and click it with the mouse to give it focus. The result:

widget-focus-button.png

Note that because the only widget in the preview is the Button, it isn't possible to unfocus the Button unless the menu Widgets -> Recreate Widgets is clicked.

When the button is clicked, it moves down and to the right 2 pixels, but the focus rectangle does not. To fix this, select the "IF(keyboardFocus)" alias under "focus-rectangle" and click "Duplicate". Change the condition for the first alias to "keyboardFocus+pressed". This will match when both states are true. It must be before the alias with condition "keyboardFocus", because the first image that matches will be used. Now set the "Inset" to 2,2,-2,-2. Now when the button is pressed, the focus rectangle will move down and to the right 2 pixels.

 TODO - allow wildcard?
TODO - show how to open theme editor theme
 TODO - mentioned using multiple of same PNG and empty image for organization


Creator: Nate Sweet on 2010/10/09 03:43
This wiki is licensed under a Creative Commons 2.0 license
XWiki Enterprise 1.8.17790 - Documentation