Prepare Custom Widgets for Theming
This article relates to the old property-based theming system.
Since 1.1M4, RAP provides a new mechanism for theming based on CSS which is
now the default (see
here).
Thus, the preferred way of making widgets themeable is currently changing.
If you develop new custom widgets, please refer to the RAP newsgroup and
look for updates of
this article in the Eclipse CVS.
Once you wrote a custom widget, you might want to allow your users to customize
some aspects of its presentation.
To do so, you have to provide a couple of resources that are relevant for the
theming and register the widget with the extension point
org.eclipse.rap.ui.themeableWidgets
.
The resources must conform to a naming convention so that they can be found.
Once a custom widget is registered with the extension point, they are
located by their name.
Extension Point themeableWidgets
You have to register your custom RWT widget with the extension point
org.eclipse.rap.ui.themeableWidgets
.
As a result of the resolve-by-name strategy, only the custom widget class must
be registered.
The following is an example of a themeable widget extension definition:
<extension
point="org.eclipse.rap.ui.themeableWidgets">
<widget
id="my.custom.datepicker"
class="my.custom.controls.DatePicker">
</widget>
</extension>
Resources that are relevant for Theming
The custom widget must provide the theme-relevant resources in a package which
is named after the schema
<internal-package>.<widget>kit
where
<internal-package>
is the package name with the segment "internal" inserted somewhere in the path
and
<widget>
is the lower case class name of the custom widget.
For example, if your custom widget is my.custom.XWidget
, you must
create a package
my.custom.internal.xwidgetkit
or attribute
my.internal.custom.xwidgetkit
for your files.
By the way, if you are already familiar with the concept of life-cycle adapters
(LCAs), they reside in the very same package.
Theming relevant resources include:
-
A theme adapter class that provides a bridge between your
theming and SWT.
-
A theme definition file that defines new theming keys for
your widget.
-
An appearance fragment file which defines new qooxdoo
appearances.
None of these resources are mandatory, resources which are found are respected,
but those which are missing do not hurt.
For more complex widgets, you might also need to provide a JavaScript file of
its own to be passed to client side. However, those are additional resources
which are not automatically discovered but must be registered manually.
Theme Adapter
This is a class that implements the interface
org.eclipse.rwt.theme.IControlThemeAdapter
.
The name must match the pattern
<Widget>ThemeAdapter
.
You must provide such a class if your custom widget's default values for
background color, foreground color, font, or border width differ from the
defaults of its superclass.
What's the use of the Theme Adapter?
Your custom widget will always be an (indirect) descendant of the class
org.eclipse.swt.widgets.Control
.
This class defines a couple of getter methods, which must be aware of the
widget's default values, which depend on the current theme.
Namely, this includes the methods
- getBackground(),
- getForeground(),
- getFont(), and
- getBorderWidth().
If a custom value has been set for one of these properties using the according
setter method, the getters will simply return this value.
But if either no custom value has been set or the value has explicitly been set
to
null
, the widget displays its default and the getters must
reflect the actual state of the widget.
For example, if your custom widget has a light gray background by default, the
method
getBackground
should return this color instead of
null
.
The value can depend on the particular instance of the widget, e.g. a widget
created with the style flag
SWT.BORDER
might be displayed with a
different border than one without this flag.
In order to provide the
Control
class with the necessary
information, you have to implement the theme adapter.
Theme Definition File
The theme definition file is an XML-file with the name
<Widget>.theme.xml
.
You must provide this file if you want to define new theming keys which allow
to make certain aspects of your widget's presentation configurable.
Its contents must conform with the schema that is outlined by the following
example:
<theme>
<color name="mywidget.background"
description="Background color for MyWidget"
default="248, 248, 255"/>
<border name="mywidget.border"
description="Default border for MyWidget"
default="1 black"/>
<image name="mywidget.active.bgimage"
description="Background image for title bar of active Shells"
default="resource/images/mywidget_bg.png"/>
...
</theme>
The root element is named
theme
and contains one or more elements
that define new theming keys.
The possible types are:
- Color (
color
)
- Dimension (
dimension
)
- Box Dimension (
boxdim
)
- Border (
border
)
- Font (
font
)
- Image (
image
)
Every definition must provide the following attributes:
-
name
: contains the name of the key.
This name can be freely chosen, but to avoid conflicts, it should start with the
custom widget name.
-
description
: contains a description that allows the user to
understand which aspects of the widget are affected by this key.
-
default
contains the default value for this theming key in a
valid format (see the article on
RWT Theming) for
format definitions.
-
targetPath
: (optional) only for images, this attribute
must can specify a target path to copy the image to.
Within the qooxdoo appearance theme, you can later refer to the image using the
path widget/<targetPath>
.
Update: Since RAP 1.1, this attribute is optional.
It might be dropped completely in the future.
If you don't specify a targetPath, it is automatically set to the key
given in the attribute name
.
Appearance Fragment
The appearance fragment file is a piece of JavaScipt code to be included in the
qooxdoo appearance theme.
For details on the qooxdoo theming, refer to
https://qooxdoo.org/documentation/0.7/theme_support,
especially the section on appearances.
The appearance fragment file must have the name <Widget>.appearances.js
.
Normally, the contents of the file are directly included in the appearance
section of the generated qooxdoo theme file.
Unfortunately, some JavaScript editors might generate warnings as the file
contains only a fragment and not a complete valid JavaScript program.
In this case, you can surround the fragment with some extra dummy code that
makes your JavaScript editor happy.
The fragment to be actually included must be enclosed in two lines that contain
the words BEGIN TEMPLATE
and END TEMPLATE
as shown in
the example below.
If these lines are present, only the lines in between are included in the
appearance theme.
appearances = {
// BEGIN TEMPLATE //
"my-custom" : {
style : function( states ) {
var tv = new org.eclipse.swt.theme.ThemeValues( states );
return {
border : tv.getBorder( states.rwt_BORDER ? "mycontrol.BORDER.border" : "mycontrol.border" ),
backgroundColor : tv.getColor( "mycontrol.background" ),
padding : tv.getBoxDimension( "mycontrol.padding" ),
backgroundImage : tv.getImage( "mycontrol.background.image" )
}
}
}
// END TEMPLATE //
};
In the above example, the state rwt_BORDER
signals that the
SWT.BORDER
style flag is set.
This state is not automatically available.
It must explicitly be set in the life-cycle adapter (LCA).
If you don't provide an LCA on your own, this is done in the LCA of your super
class (usually CompositeLCA), otherwise it is your responsibility to make the
required states available.
Update:
Since RAP 1.1M3, you should not refer to the names of colors, borders,
and fonts in your appearance. Also, the makro THEME_VALUE()
is
obsolete.
To refer to theme values, use an instance of the class ThemeValues as shown in
the example above.
This class transforms all types of theme values in a format suitable for the
qooxdoo appearance theme.
Moreover, it supports widget variants and tries to resolve the variant value
first.