-
Notifications
You must be signed in to change notification settings - Fork 121
Adding New Theme
Read following tutorials before this one:
- Adding Resources - how to add resource files
Theme is an .xml resource file of special structure. It's a bit similar to theme files in Android.
Theme ID is name of resource file w/o .xml suffix.
It's a good practice to use theme_
prefix in theme resource files.
Template for custom theme file - resource file theme_my_cool.xml:
<?xml version="1.0" encoding="utf-8"?>
<theme
id="theme_my_cool"
parent="theme_default">
</theme>
<theme>
is a main element of theme file. It's main attributes: id
is theme id, must correspond to resource file name. parent
is optional attribute, referencing to parent theme.
If parent theme is specified, it will be loaded (included) before loading of this theme content. This behavior allows to override only a part of standard theme.
More attributes may be specified in <theme>
element, e.g. default font size and face.
<theme>
element may contain <style>
, <state>
, <drawable>
, and <color>
child elements.
theme
and style
elements are similar. theme
is just a special case of style
.
Difference:
- Attribute values specified in theme are used as fallback values, if not specified in style.
-
parent
attribute ofstyle
refers to base style, to use as fallback for attributes not specified in this element. -
parent
attribute oftheme
refers to parent theme resource, not to parent style. -
theme
may containstyle
elements, butstyle
cannot contain nestedstyle
elements.
Following section is applicable to theme
element as well.
Style is a set of properties describing look&feel of widgets or widget parts.
Sample style with id STATIC_TEXT which uses TEXT style as base, and changes margins, padding, alignment and text color.
<style id="STATIC_TEXT"
parent="TEXT"
margins="0,0,1,0"
padding="1,0,1,0"
align="Left|VCenter"
textColor="#FF0000"
>
</style>
id
mandatory attribute defines unique id of style. Used by application to assign this style to some widgets.
widget.styleId = "STATIC_TEXT";
parent
attribute refers to parent style id. Parent style is used for getting properties which are not specified in this style.
Parent styles must be defined before child styles.
theme
acts as a parent for all styles which don't have parent
attribute specified.
name | type | description | example |
---|---|---|---|
id | id string | unique id for style | id="MY_STYLE" |
parent | id string | id of parent style to use as a fallback for properties not specified in current style | parent="BUTTON" |
backgroundImageId | drawable resource id | id drawable resource to draw as widget background (includes padding, excludes margins) | backgroundImageId="button_bg_blue" |
backgroundColor | color | color to draw as widget background (includes padding, excludes margins) | backgroundColor="#FF00FF" |
align | alignment | List of alignment flags (combined with |): Left, Right, Top, Bottom, HCenter, VCenter, Center, TopLeft | align="Center" |
textColor | color | color to draw text in widget | textColor="#FF00FF" |
margins | dimensions | margins from widget box to parent box (widget background is excluded from margins) | margins="10px,5pt,3,3" |
padding | dimensions | padding widget box to content (widget background will include padding) | padding="3,4,1em,1.5em" |
minWidth | dimension | minimal width of widget | minWidth="300px" |
maxWidth | dimension | maximal width of widget | maxWidth="300pt" |
minHeight | dimension | minimal height of widget | minHeight="3em" |
maxHeight | dimension | maximal height of widget | maxHeight="100" |
maxLines | integer | maximal number of text lines; applicable to some types of widgets | maxLines="3" |
fontFace | font face | list of font face to use for displaying text | fontFace="Arial;DjVu Sans" |
fontFamily | font family | font family to use for displaying text: SansSerif, Serif, Cursive, Fantasy, MonoSpace, Unspecified | fontFamily="MonoSpace" |
fontSize | dimension | size of font for displaying text in widget | fontSize="12pt" |
fontWeight | font weight | weight of font - either "bold" or "normal" | fontWeight="bold" |
layoutWidth | layout dimension | FILL_PARENT, WRAP_CONTENT or fixed dimension | layoutWidth="fill" |
layoutHeight | layout dimension | FILL_PARENT, WRAP_CONTENT or fixed dimension | layoutHeight="wrap" |
alpha | dimension | widget transparency (0==opaque, 100%==transparent) | alpha="50%" |
textFlags | text flags | text property flags - set of HotKeys, UnderlineHotKeys, UnderlineHotKeysWhenAltPressed, Underline | textFlags="Underline" |
focusRectColors | focus rect colors | defines focus rectangle properties | focusRectColors="#000" |
Unique id for style; string starting with a..z, may contain digits, hyphens and underscores.
Example: "my_style1"
Number with optional type suffix (similar to CSS)
sample value | description |
---|---|
123px | 123 pixels |
123 | integer 123 (usually same as px) |
123pt | 12 points (scaled for different DPI) |
1.5em | 1.5 of line height (scaled based on font size) |
10% | 10 % of base dimension |
Comma separated list of 4 dimensions. E.g. "1,2,3,4"
(1, 2, 3, 4 mean any hex digit)
sample value | description |
---|---|
button_background | Drawable resource id, e.g. may correspond to file "button_background.9.png" |
win_background.tiled | Drawable resource id, e.g. may correspond to file "win_background.png" which will be drawn TILED |
#123 | solid color RGB value |
#1234 | solid color ARGB value |
#112233 | solid color RRGGBB value |
#11223344 | solid color AARRGGBB value |
@null | No drawable (transparent) |
{......} | Special inline drawable definition for Console mode |
sample value | description |
---|---|
#123 | RGB value |
#1234 | ARGB value |
#112233 | RRGGBB value |
#11223344 | AARRGGBB value |
@null | transparent color |
transparent | transparent color |
red | standard color name: red, green, blue, white, black, gray, lightgray, silver |
-
state
- override some properties for different states -
color
- define or override named color -
drawable
- define or override named drawable (e.g. image or color) -
length
- define or override named dimension value (custom numeric property)
state
element redefines part of parent style properties for particular combination of widget state flags.
State element is similar to usual style element, but instead of id and parent attributes it has a set of state selection attributes. These attributes are boolean - can be either "true" or "false".
When widget is looking for state aware properties, it tries to find matching state in current style, and uses property value from it. If property is not overridden in state, or no matching state is found, property value from style
element or its parent will be used.
State selectors work like in Android. State attributes may be prefixed with "android:".
State selection attributes correspond to State
enum flags.
attribute name | description |
---|---|
state_pressed | widget is pressed |
state_focused | widget is focused |
state_default | widget is default control (e.g. default button) |
state_hovered | mouse is over widget |
state_selected | widget is selected (e.g. item in list) |
state_checkable | widget check state can be changed |
state_checked | widget is checked (e.g. checkbox button or menu item) |
state_enabled | widget is enabled (can be focused, changed, pressed, selected, etc...) |
state_activated | |
state_window_focused | focused widget is in the same widget group as this widget (or in the same window) |
As a child of theme
, style
or state
elements, color
element defines or overrides custom named color value.
Samples of using custom colors in code.
// use global color from current theme
_window.backgroundColor = currentTheme.customColor("dialog_background");
// use custom color from widget style
_selectionColorFocused = style.customColor("editor_selection_focused");
As a child of theme
, style
or state
elements, drawable
element defines or overrides custom named drawable resource.
Sample of getting custom drawable from current style in code:
DrawableRef gaugeDrawable = style.customDrawable("progress_bar_gauge");
As a child of theme
, style
or state
elements, length
element defines or overrides custom named numeric or dimension value.
Sample of using custom length:
_buttonOverlap = edit.customLength("overlap", 0);
Let's create app with custom theme - changed buttons look & feel.
Simple DLangUI project directory structure:
themetest
dub.json
src
app.d
win_app.def
views
resources.list
res
theme_custom.xml
dub.json:
{
"name": "themetest",
"targetPath": "bin",
"targetType": "executable",
"sourceFiles-windows": ["$PACKAGE_DIR/src/win_app.def"],
"dependencies": {
"dlangui": "~master"
}
}
win_app.def:
EXETYPE NT
SUBSYSTEM WINDOWS
app.d:
module app;
import dlangui;
mixin APP_ENTRY_POINT;
/// entry point for dlangui based application
extern (C) int UIAppMain(string[] args) {
// create window
Window window = Platform.instance.createWindow("DlangUI example - ThemeTest", null);
// create some widget to show in window
window.mainWidget = parseML(q{
VerticalLayout {
margins: 10pt
padding: 10pt
layoutWidth: fill
// red bold text with size = 150% of base style size and font face Arial
TextWidget { text: "Theme test for DlangUI" }
Button { text: "Sample button 1 (enabled)" }
Button { text: "Sample button 2 (enabled)" }
Button { text: "Sample button 3 (disabled)"; enabled: false }
}
});
// show window
window.show();
// run message loop
return Platform.instance.enterMessageLoop();
}
Updated directory structure - adding resources in views/ directory:
themetest
dub.json
src
app.d
win_app.def
views
resources.list
res
theme_custom.xml
Update dub.json, add stringImportPaths section.
dub.json:
{
"name": "themetest",
"targetPath": "bin",
"targetType": "executable",
"stringImportPaths": ["views", "views/res"],
"sourceFiles-windows": ["$PACKAGE_DIR/src/win_app.def"],
"dependencies": {
"dlangui": "~master"
}
}
views/resources.list:
res/theme_custom.xml
Put empty theme stub to theme_custom.xml
Our new theme will have resource id theme_custom
and will be based on default theme theme_default
views/res/theme_custom.xml:
<?xml version="1.0" encoding="utf-8"?>
<theme
id="theme_custom"
parent="theme_default"
>
</theme>
In app.d, you need to set current theme to theme_custom
and register custom application resources.
app.d:
...
/// entry point for dlangui based application
extern (C) int UIAppMain(string[] args) {
// embed and register app resources listed in file views/resources.list
embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
// load theme from file "theme_custom.xml"
Platform.instance.uiTheme = "theme_custom";
// create window
...
Let's redefine style of standard buttons. It will be applied to all widgets which are using BUTTON
style.
Add new style
element inside of theme
element.
Let's describe simple button style with solid color background.
Properties of widget which we will set:
- id="BUTTON" -- ID of our style; this style exists in parent theme, so it will be redefined (modified)
- align="Center" -- Align button text at center of button
- margins="5pt,5pt,5pt,5pt" -- big margins (space between widget background and other controls)
- padding="5pt,5pt,5pt,5pt" -- big padding (space between widget content and background rect bounds)
- fontSize="200%" -- font size is twice bigger than standard
- fontWeight="bold" -- bold
- backgroundColor="#8080FF" -- light blue background by default
If we need to change some properties depending on widget state, we can use state
child elements. Alternative solution - if only background has to be changed - use state drawable
as widget background.
We will set different properties for states
- disabled button -- change text color to half transparent black
- enabled pressed button -- change background color
- enabled focused hovered button -- change background color and text color
- enabled focused -- change background color
- enabled hovered button -- change text color
Updated theme_custom.xml:
<?xml version="1.0" encoding="utf-8"?>
<theme
id="theme_custom"
parent="theme_default"
>
<style id="BUTTON"
align="Center"
margins="5pt,5pt,5pt,5pt"
padding="5pt,5pt,5pt,5pt"
fontSize="200%"
fontWeight="bold"
backgroundColor="#C0D8FF"
>
<state state_enabled="false" textColor="#C0000000"/>
<state state_pressed="true" backgroundColor="#8080FF"/>
<state state_focused="true" state_hovered="true" backgroundColor="#C0E0FF" textColor="#FF8000"/>
<state state_focused="true" backgroundColor="#C0E0FF"/>
<state state_focused="false" state_hovered="true" textColor="#FF8000"/>
</style>
</theme>
You can create new style instead of overriding existing.
...
<style id="CUSTOM_BUTTON"
...
And set this style ID to widgets in app.d (DML):
Button { text: "Sample button 1 (enabled)"; styleId: CUSTOM_BUTTON }
Button { text: "Sample button 2 (enabled)"; styleId: CUSTOM_BUTTON }
Button { text: "Sample button 3 (disabled)"; enabled: false; styleId: CUSTOM_BUTTON }
In code, style may be as well assigned using widget styleId property:
myButton.styleId = "CUSTOM_BUTTON";