support changing of theme

This commit is contained in:
Vadim Lopatin 2014-05-19 15:35:13 +04:00
parent 1f9e1eba27
commit 60776f2ce9
6 changed files with 282 additions and 26 deletions

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<theme
id="theme_custom1"
parent="theme_default"
fontSize="24"
>
<style id="BUTTON"
backgroundImageId="btn_default_small"
align="Center"
margins="5,5,5,5"
/>
<style id="BUTTON_TRANSPARENT"
backgroundImageId="btn_default_small_transparent"
align="Center"
/>
<style id="BUTTON_LABEL"
layoutWidth="FILL_PARENT"
align="Left|VCenter"
/>
<style id="BUTTON_ICON"
align="Center"
/>
<style id="TEXT"
margins="2,2,2,2"
padding="1,1,1,1"
/>
<style id="HSPACER"
layoutWidth="FILL_PARENT"
layoutWeight="100"
minWidth="5"
/>
<style id="VSPACER"
layoutHeight="FILL_PARENT"
layoutWeight="100"
minHeight="5"
/>
<style id="BUTTON_NOMARGINS"
backgroundImageId="btn_default_small"
align="Center"
/>
<drawable id="scrollbar_button_up" value="scrollbar_btn_up"/>
<drawable id="scrollbar_button_down" value="scrollbar_btn_down"/>
<srawable id="scrollbar_button_left" value="scrollbar_btn_left"/>
<drawable id="scrollbar_button_right" value="scrollbar_btn_right"/>
<drawable id="scrollbar_indicator_vertical" value="scrollbar_indicator_vertical"/>
<drawable id="scrollbar_indicator_horizontal" value="scrollbar_indicator_horizontal"/>
<style id="SCROLLBAR"
backgroundColor="#C0808080"
align="Center"
/>
<style id="SCROLLBAR_BUTTON" parent="BUTTON"
/>
<style id="SLIDER"
/>
<style id="PAGE_SCROLL"
backgroundColor="#FFFFFFFF"
>
<state state_pressed="true" backgroundColor="#C0404080"/>
<state state_hovered="true" backgroundColor="#F0404080"/>
</style>
<style id="TAB_UP"
backgroundImageId="tab_up_background"
layoutWidth="FILL_PARENT"
>
<state state_selected="true" backgroundImageId="tab_up_backgrond_selected"/>
</style>
<style id="TAB_UP_BUTTON_TEXT"
textColor="#000000"
fontSize="16"
align="Center"
>
<state state_selected="true" state_focused="true" textColor="#000000"/>
<state state_selected="true" textColor="#000000"/>
<state state_focused="true" textColor="#000000"/>
<state state_hovered="true" textColor="#FFE0E0"/>
</style>
<style id="TAB_UP_BUTTON"
backgroundImageId="tab_btn_up"
/>
<style id="TAB_HOST"
layoutWidth="FILL_PARENT"
layoutHeight="FILL_PARENT"
backgroundColor="#F0F0F0"
/>
<style id="TAB_WIDGET"
padding="3,3,3,3"
backgroundColor="#EEEEEE"
/>
<style id="MAIN_MENU"
layoutWidth="FILL_PARENT"
backgroundColor="#404040"
/>
<style id="MAIN_MENU_ITEM"
padding="4,2,4,2"
backgroundImageId="main_menu_item_background"
textColor="#E0E0E0"
textFlags="Parent"
/>
<style id="MENU_ITEM"
padding="4,2,4,2"
>
<state state_focused="true" backgroundColor="#40C0C000"/>
<state state_pressed="true" backgroundColor="#4080C000"/>
<state state_selected="true" backgroundColor="#00F8F9Fa"/>
<state state_hovered="true" backgroundColor="#C0FFFF00"/>
</style>
<style id="MENU_ICON"
margins="2,2,2,2"
align="Left|VCenter"
>
<state state_enabled="false" alpha="160"/>
</style>
<style id="MENU_LABEL"
margins="4,2,4,2"
align="Left|VCenter"
textFlags="UnderlineHotKeys"
>
<state state_enabled="false" textColor="#80404040"/>
</style>
<style id="MAIN_MENU_LABEL"
margins="4,2,4,2"
align="Left|VCenter"
textFlags="Parent"
>
<state state_enabled="false" textColor="#80404040"/>
</style>
<style id="MENU_ACCEL"
margins="4,2,4,2"
align="Left|VCenter"
>
<state state_enabled="false" textColor="#80404040"/>
</style>
<style id="TRANSPARENT_BUTTON_BACKGROUND"
backgroundImageId="transparent_button_background"
padding="4,2,4,2"
/>
<style id="POPUP_MENU"
backgroundImageId="popup_menu_background_normal"
/>
<style id="LIST_ITEM"
backgroundImageId="list_item_background"
/>
<style id="EDIT_LINE"
backgroundImageId="editbox_background"
padding="5,6,5,6"
margins="2,2,2,2"
minWidth="40"
fontFace="Arial"
fontFamily="SansSerif"
fontSize="20"
/>
<style id="EDIT_BOX"
backgroundImageId="editbox_background"
padding="5,6,5,6"
margins="2,2,2,2"
minWidth="100"
minHeight="60"
layoutWidth="FILL_PARENT"
layoutHeight="FILL_PARENT"
fontFace="Courier New"
fontFamily="MonoSpace"
fontSize="20"
/>
</theme>

View File

@ -89,18 +89,13 @@ extern (C) int UIAppMain(string[] args) {
appendPath(exePath, "../res/mdpi/"), // when res dir is located at project directory
appendPath(exePath, "../../res/mdpi/") // when res dir is located at the same directory as executable
];
// setup resource directories - will use only existing directories
drawableCache.setResourcePaths(resourceDirs);
// setup i18n - look for i18n directory inside one of passed directories
i18n.findTranslationsDir(resourceDirs);
// select translation file - for english language
i18n.load("en.ini"); //"ru.ini", "en.ini"
Theme theme = loadTheme("theme_default");
if (theme) {
Log.d("Applying loaded theme ", theme.id);
currentTheme = theme;
}
// setup resource directories - will use only existing directories
Platform.instance.resourceDirs = resourceDirs;
// select translation file - for english language
Platform.instance.uiLanguage = "en";
// load theme from file "theme_default.xml"
Platform.instance.uiTheme = "theme_default";
// create window
Window window = Platform.instance.createWindow("My Window", null);
@ -142,12 +137,10 @@ extern (C) int UIAppMain(string[] args) {
return false;
if (item.id == 611) {
// set interface language to english
i18n.load("en.ini");
contentLayout.requestLayout();
platform.instance.uiLanguage = "en";
} else if (item.id == 612) {
// set interface language to russian
i18n.load("ru.ini", "en.ini");
contentLayout.requestLayout();
platform.instance.uiLanguage = "ru";
}
return true;
};
@ -157,10 +150,24 @@ extern (C) int UIAppMain(string[] args) {
ruLang.onMenuItemClick = onLangChange;
langItem.add(enLang);
langItem.add(ruLang);
MenuItem themeItem = new MenuItem(new Action(62, "MENU_VIEW_THEME"));
themeItem.add((new MenuItem(new Action(621, "MENU_VIEW_THEME_DEFAULT"))).type(MenuItemType.Radio).checked(true));
themeItem.add((new MenuItem(new Action(622, "MENU_VIEW_THEME_CUSTOM1"))).type(MenuItemType.Radio));
viewItem.add(langItem);
MenuItem themeItem = new MenuItem(new Action(62, "MENU_VIEW_THEME"));
MenuItem theme1 = (new MenuItem(new Action(621, "MENU_VIEW_THEME_DEFAULT"))).type(MenuItemType.Radio).checked(true);
MenuItem theme2 = (new MenuItem(new Action(622, "MENU_VIEW_THEME_CUSTOM1"))).type(MenuItemType.Radio);
auto onThemeChange = delegate (MenuItem item) {
if (!item.checked)
return false;
if (item.id == 621) {
platform.instance.uiTheme = "theme_default";
} else if (item.id == 622) {
platform.instance.uiTheme = "theme_custom1";
}
return true;
};
theme1.onMenuItemClick = onThemeChange;
theme2.onMenuItemClick = onThemeChange;
themeItem.add(theme1);
themeItem.add(theme2);
viewItem.add(themeItem);
MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<theme id="theme_default" >
<theme id="theme_default" fontSize="15" >
<style id="BUTTON"
backgroundImageId="btn_default_small"
align="Center"
@ -62,7 +62,6 @@
</style>
<style id="TAB_UP_BUTTON_TEXT"
textColor="#000000"
backgroundImageId="tab_up_background"
fontSize="12"
align="Center"
>

View File

@ -28,7 +28,12 @@ import dlangui.widgets.popup;
import dlangui.graphics.drawbuf;
private import dlangui.graphics.gldrawbuf;
private import std.algorithm;
/**
* Window abstraction layer. Widgets can be shown only inside window.
*
*/
class Window {
protected int _dx;
protected int _dy;
@ -49,8 +54,17 @@ class Window {
_mainWidget.window = this;
}
abstract void show();
/// returns window caption
abstract @property string windowCaption();
/// sets window caption
abstract @property void windowCaption(string caption);
/// requests layout for main widget and popups
void requestLayout() {
if (_mainWidget)
_mainWidget.requestLayout();
foreach(p; _popups)
p.requestLayout();
}
void measure() {
if (_mainWidget !is null) {
_mainWidget.measure(_dx, _dy);
@ -524,6 +538,14 @@ class Window {
abstract void invalidate();
}
/**
* Platform abstraction layer.
*
* Represents application.
*
*
*
*/
class Platform {
static __gshared Platform _instance;
static void setInstance(Platform instance) {
@ -540,6 +562,60 @@ class Platform {
abstract dstring getClipboardText(bool mouseBuffer = false);
/// sets text to clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
abstract void setClipboardText(dstring text, bool mouseBuffer = false);
/// calls request layout for all windows
abstract void requestLayout();
protected string _uiLanguage;
/// returns currently selected UI language code
@property string uiLanguage() {
return _uiLanguage;
}
/// set UI language (e.g. "en", "fr", "ru")
@property Platform uiLanguage(string langCode) {
if (_uiLanguage.equal(langCode))
return this;
_uiLanguage = langCode;
if (langCode.equal("en"))
i18n.load("en.ini"); //"ru.ini", "en.ini"
else
i18n.load(langCode ~ ".ini", "en.ini");
requestLayout();
return this;
}
protected string _themeId;
@property string uiTheme() {
return _themeId;
}
/// sets application UI theme
@property Platform uiTheme(string themeResourceId) {
if (_themeId.equal(themeResourceId))
return this;
_themeId = themeResourceId;
Theme theme = loadTheme(themeResourceId);
if (!theme) {
Log.e("Cannot load theme from resource ", themeResourceId, " - will use default theme");
theme = createDefaultTheme();
} else {
Log.i("Applying loaded theme ", theme.id);
}
currentTheme = theme;
requestLayout();
return this;
}
protected string[] _resourceDirs;
/// returns list of resource directories
@property string[] resourceDirs() { return _resourceDirs; }
/// set list of directories to load resources from
@property Platform resourceDirs(string[] dirs) {
// setup resource directories - will use only existing directories
drawableCache.setResourcePaths(dirs);
_resourceDirs = drawableCache.resourcePaths;
// setup i18n - look for i18n directory inside one of passed directories
i18n.findTranslationsDir(dirs);
return this;
}
}
/// get current platform object instance

View File

@ -662,6 +662,15 @@ version(USE_SDL) {
return null;
}
/// calls request layout for all windows
override void requestLayout() {
foreach(w; _windowMap) {
w.requestLayout();
w.invalidate();
}
}
private uint _redrawEventId;
void sendRedrawEvent(uint windowId, uint code) {

View File

@ -976,7 +976,7 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
if ("fontFamily" in elem.tag.attr)
style.fontFamily = decodeFontFamily(elem.tag.attr["fontFamily"]);
if ("fontSize" in elem.tag.attr)
style.fontSize = cast(ushort)decodeDimension(elem.tag.attr["fontFace"]);
style.fontSize = cast(ushort)decodeDimension(elem.tag.attr["fontSize"]);
if ("layoutWidth" in elem.tag.attr)
style.layoutWidth = decodeLayoutDimension(elem.tag.attr["layoutWidth"]);
if ("layoutHeight" in elem.tag.attr)
@ -1021,7 +1021,7 @@ bool loadStyleAttributes(Style style, Element elem, bool allowStates) {
*
*/
bool loadTheme(Theme theme, Element doc, int level = 0) {
if (doc.tag.name.equal("theme")) {
if (!doc.tag.name.equal("theme")) {
Log.e("<theme> element should be main in theme file!");
return false;
}
@ -1040,11 +1040,10 @@ bool loadTheme(Theme theme, Element doc, int level = 0) {
// load <style>
string styleid = attrValue(styleitem, "id");
string styleparent = attrValue(styleitem, "parent");
if (styleid !is null) {
if (styleid.length) {
// create new style
Style parentStyle = null;
if (styleparent !is null)
parentStyle = theme.get(styleparent);
parentStyle = theme.get(styleparent);
Style style = parentStyle.createSubstyle(styleid);
loadStyleAttributes(style, styleitem, true);
} else {
@ -1079,7 +1078,7 @@ bool loadTheme(Theme theme, string resourceId, int level = 0) {
Log.e("Invalid XML resource ", resourceId);
return false;
} catch (Throwable e) {
Log.e("Cannot read drawable resource ", resourceId, " from file ", filename);
Log.e("Cannot read XML resource ", resourceId, " from file ", filename, " exception: ", e);
return false;
}
}