1 // Written in the D programming language.
2 
3 /**
4 DLANGUI library.
5 
6 This module contains declaration of themes and styles implementation.
7 
8 
9 
10 Synopsis:
11 
12 ----
13 import dlangui.widgets.styles;
14 
15 ----
16 
17 Copyright: Vadim Lopatin, 2014
18 License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
19 Authors:   $(WEB coolreader.org, Vadim Lopatin)
20 */
21 module dlangui.widgets.styles;
22 
23 import dlangui.core.types;
24 import dlangui.graphics.fonts;
25 import dlangui.graphics.drawbuf;
26 //import dlangui.graphics.images;
27 import dlangui.graphics.resources;
28 
29 immutable ubyte ALIGN_UNSPECIFIED = 0;
30 immutable uint COLOR_UNSPECIFIED = 0xFFDEADFF;
31 immutable uint COLOR_TRANSPARENT = 0xFFFFFFFF;
32 immutable ushort FONT_SIZE_UNSPECIFIED = 0xFFFF;
33 immutable ushort FONT_WEIGHT_UNSPECIFIED = 0x0000;
34 immutable ubyte FONT_STYLE_UNSPECIFIED = 0xFF;
35 immutable ubyte FONT_STYLE_NORMAL = 0x00;
36 immutable ubyte FONT_STYLE_ITALIC = 0x01;
37 /// use as widget.layout() param to avoid applying of parent size
38 immutable int SIZE_UNSPECIFIED = int.max;
39 
40 immutable int FILL_PARENT = int.max - 1;
41 immutable int WRAP_CONTENT = int.max - 2;
42 immutable int WEIGHT_UNSPECIFIED = -1;
43 
44 enum Align : ubyte {
45     Unspecified = ALIGN_UNSPECIFIED,
46     Left = 1,
47     Right = 2,
48     HCenter = 1 | 2,
49     Top = 4,
50     Bottom = 8,
51     VCenter = 4 | 8,
52     Center = VCenter | HCenter,
53 	TopLeft = Left | Top,
54 }
55 
56 class DrawableAttribute {
57     protected string _id;
58     protected string _drawableId;
59     protected DrawableRef _drawable;
60     protected bool _initialized;
61     this(string id, string drawableId) {
62         _id = id;
63         _drawableId = drawableId;
64     }
65     @property string id() const { return _id; }
66     @property string drawableId() const { return _drawableId; }
67     @property void drawableId(string newDrawable) { _drawableId = newDrawable; clear(); }
68     @property ref DrawableRef drawable() const {
69         if (!_drawable.isNull)
70             return (cast(DrawableAttribute)this)._drawable;
71         (cast(DrawableAttribute)this)._drawable = drawableCache.get(_id);
72         (cast(DrawableAttribute)this)._initialized = true;
73         return (cast(DrawableAttribute)this)._drawable;
74     }
75     void clear() {
76         _drawable.clear();
77         _initialized = false;
78     }
79 }
80 
81 /// style properties
82 class Style {
83 	protected string _id;
84 	protected Theme _theme;
85 	protected Style _parentStyle;
86 	protected string _parentId;
87 	protected uint _stateMask;
88 	protected uint _stateValue;
89 	protected ubyte _align = Align.TopLeft;
90 	protected ubyte _fontStyle = FONT_STYLE_UNSPECIFIED;
91 	protected FontFamily _fontFamily = FontFamily.Unspecified;
92 	protected ushort _fontSize = FONT_SIZE_UNSPECIFIED;
93 	protected ushort _fontWeight = FONT_WEIGHT_UNSPECIFIED;
94 	protected uint _backgroundColor = COLOR_UNSPECIFIED;
95 	protected uint _textColor = COLOR_UNSPECIFIED;
96 	protected string _fontFace;
97 	protected string _backgroundImageId;
98 	protected Rect _padding;
99 	protected Rect _margins;
100     protected int _minWidth = SIZE_UNSPECIFIED;
101     protected int _maxWidth = SIZE_UNSPECIFIED;
102     protected int _minHeight = SIZE_UNSPECIFIED;
103     protected int _maxHeight = SIZE_UNSPECIFIED;
104     protected int _layoutWidth = SIZE_UNSPECIFIED;
105     protected int _layoutHeight = SIZE_UNSPECIFIED;
106     protected int _layoutWeight = WEIGHT_UNSPECIFIED;
107 
108 	protected Style[] _substates;
109 	protected Style[] _children;
110 
111     protected DrawableAttribute[string] _customDrawables;
112 
113 	protected FontRef _font;
114 	protected DrawableRef _backgroundDrawable;
115 
116 	@property const(Theme) theme() const {
117 		if (_theme !is null)
118 			return _theme;
119 		return currentTheme;
120 	}
121 
122 	@property Theme theme() {
123 		if (_theme !is null)
124 			return _theme;
125 		return currentTheme;
126 	}
127 
128 	@property string id() const { return _id; }
129 
130 	@property const(Style) parentStyle() const {
131 		if (_parentStyle !is null)
132 			return _parentStyle;
133 		if (_parentId !is null && currentTheme !is null)
134 			return currentTheme.get(_parentId);
135 		return currentTheme;
136 	}
137 
138 	@property Style parentStyle() {
139 		if (_parentStyle !is null)
140 			return _parentStyle;
141 		if (_parentId !is null && currentTheme !is null)
142 			return currentTheme.get(_parentId);
143 		return currentTheme;
144 	}
145 
146     @property ref DrawableRef backgroundDrawable() const {
147 		if (!(cast(Style)this)._backgroundDrawable.isNull)
148 			return (cast(Style)this)._backgroundDrawable;
149         string image = backgroundImageId;
150         if (image !is null) {
151             (cast(Style)this)._backgroundDrawable = drawableCache.get(image);
152         } else {
153             uint color = backgroundColor;
154             (cast(Style)this)._backgroundDrawable = new SolidFillDrawable(color);
155         }
156         return (cast(Style)this)._backgroundDrawable;
157     }
158 
159     /// get custom drawable attribute
160     @property ref DrawableRef customDrawable(string id) {
161         if (id in _customDrawables)
162             return _customDrawables[id].drawable;
163         return parentStyle.customDrawable(id);
164     }
165 
166     /// get custom drawable attribute
167     @property string customDrawableId(string id) const {
168         if (id in _customDrawables)
169             return _customDrawables[id].drawableId;
170         return parentStyle.customDrawableId(id);
171     }
172 
173     /// sets custom drawable attribute for style
174     Style setCustomDrawable(string id, string resourceId) {
175         if (id in _customDrawables)
176             _customDrawables[id].drawableId = resourceId;
177         else
178             _customDrawables[id] = new DrawableAttribute(id, resourceId);
179         return this;
180     }
181 
182 
183     //===================================================
184     // font properties
185 
186 	@property ref FontRef font() const {
187 		if (!(cast(Style)this)._font.isNull)
188 			return (cast(Style)this)._font;
189 		string face = fontFace;
190 		int size = fontSize;
191 		ushort weight = fontWeight;
192 		bool italic = fontItalic;
193 		FontFamily family = fontFamily;
194 		(cast(Style)this)._font = FontManager.instance.getFont(size, weight, italic, family, face);
195 		return (cast(Style)this)._font;
196 	}
197 
198 	/// font size
199 	@property FontFamily fontFamily() const {
200         if (_fontFamily != FontFamily.Unspecified)
201             return _fontFamily;
202         else
203             return parentStyle.fontFamily;
204 	}
205 
206 	/// font size
207 	@property string fontFace() const {
208         if (_fontFace !is null)
209             return _fontFace;
210         else
211             return parentStyle.fontFace;
212 	}
213 
214 	/// font style - italic
215 	@property bool fontItalic() const {
216         if (_fontStyle != FONT_STYLE_UNSPECIFIED)
217             return _fontStyle == FONT_STYLE_ITALIC;
218         else
219             return parentStyle.fontItalic;
220 	}
221 
222 	/// font weight
223 	@property ushort fontWeight() const {
224         if (_fontWeight != FONT_WEIGHT_UNSPECIFIED)
225             return _fontWeight;
226         else
227             return parentStyle.fontWeight;
228 	}
229 
230 	/// font size
231 	@property ushort fontSize() const {
232         if (_fontSize != FONT_SIZE_UNSPECIFIED)
233             return _fontSize;
234         else
235             return parentStyle.fontSize;
236 	}
237 
238     //===================================================
239     // layout parameters: margins / padding
240 
241 	/// padding
242 	@property ref const(Rect) padding() const {
243 		if (_stateValue != 0)
244 			return parentStyle._padding;
245 		return _padding;
246 	}
247 
248 	/// margins
249 	@property ref const(Rect) margins() const {
250 		if (_stateValue != 0)
251 			return parentStyle._margins;
252 		return _margins;
253 	}
254 
255 	/// text color
256 	@property uint textColor() const {
257         if (_textColor != COLOR_UNSPECIFIED)
258             return _textColor;
259         else
260             return parentStyle.textColor;
261 	}
262 
263     //===================================================
264     // background
265 
266 	/// background color
267 	@property uint backgroundColor() const {
268         if (_backgroundColor != COLOR_UNSPECIFIED)
269             return _backgroundColor;
270         else
271             return parentStyle.backgroundColor;
272 	}
273 
274 	/// font size
275 	@property string backgroundImageId() const {
276         if (_backgroundImageId !is null)
277             return _backgroundImageId;
278         else
279             return parentStyle.backgroundImageId;
280 	}
281 
282     //===================================================
283     // size restrictions
284 
285 	/// minimal width constraint, 0 if limit is not set
286 	@property uint minWidth() const {
287         if (_minWidth != SIZE_UNSPECIFIED)
288             return _minWidth;
289         else
290             return parentStyle.minWidth;
291 	}
292 	/// max width constraint, returns SIZE_UNSPECIFIED if limit is not set
293 	@property uint maxWidth() const {
294         if (_maxWidth != SIZE_UNSPECIFIED)
295             return _maxWidth;
296         else
297             return parentStyle.maxWidth;
298 	}
299 	/// minimal height constraint, 0 if limit is not set
300 	@property uint minHeight() const {
301         if (_minHeight != SIZE_UNSPECIFIED)
302             return _minHeight;
303         else
304             return parentStyle.minHeight;
305 	}
306 	/// max height constraint, SIZE_UNSPECIFIED if limit is not set
307 	@property uint maxHeight() const {
308         if (_maxHeight != SIZE_UNSPECIFIED)
309             return _maxHeight;
310         else
311             return parentStyle.maxHeight;
312 	}
313     /// set min width constraint
314     @property Style minWidth(int value) {
315         _minWidth = value;
316         return this;
317     }
318     /// set max width constraint
319     @property Style maxWidth(int value) {
320         _maxWidth = value;
321         return this;
322     }
323     /// set min height constraint
324     @property Style minHeight(int value) {
325         _minHeight = value;
326         return this;
327     }
328     /// set max height constraint
329     @property Style maxHeight(int value) {
330         _maxHeight = value;
331         return this;
332     }
333 
334 
335 	/// layout width parameter
336 	@property uint layoutWidth() const {
337         if (_layoutWidth != SIZE_UNSPECIFIED)
338             return _layoutWidth;
339         else
340             return parentStyle.layoutWidth;
341 	}
342 
343 	/// layout height parameter
344 	@property uint layoutHeight() const {
345         if (_layoutHeight != SIZE_UNSPECIFIED)
346             return _layoutHeight;
347         else
348             return parentStyle.layoutHeight;
349 	}
350 
351 	/// layout weight parameter
352 	@property uint layoutWeight() const {
353         if (_layoutWeight != WEIGHT_UNSPECIFIED)
354             return _layoutWeight;
355         else
356             return parentStyle.layoutWeight;
357 	}
358 
359     /// set layout height
360     @property Style layoutHeight(int value) {
361         _layoutHeight = value;
362         return this;
363     }
364     /// set layout width
365     @property Style layoutWidth(int value) {
366         _layoutWidth = value;
367         return this;
368     }
369     /// set layout weight
370     @property Style layoutWeight(int value) {
371         _layoutWeight = value;
372         return this;
373     }
374 
375     //===================================================
376     // alignment
377 
378 	/// get full alignment (both vertical and horizontal)
379 	@property ubyte alignment() const { 
380         if (_align != Align.Unspecified)
381             return _align; 
382         else
383             return parentStyle.alignment;
384     }
385 	/// vertical alignment: Top / VCenter / Bottom
386 	@property ubyte valign() const { return alignment & Align.VCenter; }
387 	/// horizontal alignment: Left / HCenter / Right
388 	@property ubyte halign() const { return alignment & Align.HCenter; }
389 
390     /// set alignment
391     @property Style alignment(ubyte value) {
392         _align = value;
393         return this;
394     }
395 
396 	@property Style fontFace(string face) {
397 		_fontFace = face;
398 		_font.clear();
399 		return this;
400 	}
401 
402 	@property Style fontFamily(FontFamily family) {
403 		_fontFamily = family;
404 		_font.clear();
405 		return this;
406 	}
407 
408 	@property Style fontStyle(ubyte style) {
409 		_fontStyle = style;
410 		_font.clear();
411 		return this;
412 	}
413 
414 	@property Style fontWeight(ushort weight) {
415 		_fontWeight = weight;
416 		_font.clear();
417 		return this;
418 	}
419 
420 	@property Style fontSize(ushort size) {
421 		_fontSize = size;
422 		_font.clear();
423 		return this;
424 	}
425 
426 	@property Style textColor(uint color) {
427 		_textColor = color;
428 		return this;
429 	}
430 
431 	@property Style backgroundColor(uint color) {
432 		_backgroundColor = color;
433         _backgroundImageId = null;
434 		_backgroundDrawable.clear();
435 		return this;
436 	}
437 
438 	@property Style backgroundImageId(string image) {
439 		_backgroundImageId = image;
440 		_backgroundDrawable.clear();
441 		return this;
442 	}
443 
444 	@property Style margins(Rect rc) {
445 		_margins = rc;
446 		return this;
447 	}
448 
449 	@property Style padding(Rect rc) {
450 		_padding = rc;
451 		return this;
452 	}
453 
454 	private static int _instanceCount;
455 	this(Theme theme, string id) {
456 		_theme = theme;
457 		_parentStyle = theme;
458 		_id = id;
459 		Log.d("Created style ", _id, ", count=", ++_instanceCount);
460 	}
461 
462 	~this() {
463 		foreach(ref Style item; _substates) {
464 			Log.d("Destroying substate");
465 			destroy(item);
466 			item = null;
467 		}
468 		_substates.clear();
469 		foreach(ref Style item; _children) {
470 			destroy(item);
471 			item = null;
472 		}
473 		_children.clear();
474 		_backgroundDrawable.clear();
475 		_font.clear();
476 		Log.d("Destroyed style ", _id, ", parentId=", _parentId, ", state=", _stateMask, ", count=", --_instanceCount);
477 	}
478 
479 	/// create named substyle of this style
480 	Style createSubstyle(string id) {
481 		Style child = (_theme !is null ? _theme : currentTheme).createSubstyle(id);
482 		child._parentStyle = this;
483 		_children ~= child;
484 		return child;
485 	}
486 
487 	/// create state substyle for this style
488 	Style createState(uint stateMask = 0, uint stateValue = 0) {
489         assert(stateMask != 0);
490 		Log.d("Creating substate ", stateMask);
491 		Style child = (_theme !is null ? _theme : currentTheme).createSubstyle(null);
492 		child._parentStyle = this;
493 		child._stateMask = stateMask;
494 		child._stateValue = stateValue;
495 		child._backgroundColor = COLOR_UNSPECIFIED;
496 		_substates ~= child;
497 		return child;
498 	}
499 
500 	/// find substyle based on widget state (e.g. focused, pressed, ...)
501 	const(Style) forState(uint state) const {
502 		if (state == State.Normal)
503 			return this;
504         //Log.d("forState ", state, " styleId=", _id, " substates=", _substates.length);
505 		if (parentStyle !is null && _substates.length == 0 && parentStyle._substates.length > 0) //id is null && 
506 			return parentStyle.forState(state);
507 		foreach(item; _substates) {
508 			if ((item._stateMask & state) == item._stateValue)
509 				return item;
510 		}
511 		return this; // fallback to current style
512 	}
513 	
514 }
515 
516 /// Theme - root for style hierarhy.
517 class Theme : Style {
518 	protected Style[string] _byId;
519 
520 	this(string id) {
521 		super(this, id);
522 		_parentStyle = null;
523 		_backgroundColor = 0xFFFFFFFF; // transparent
524 		_textColor = 0x000000; // black
525 		_align = Align.TopLeft;
526 		_fontSize = 14; // TODO: from settings or screen properties / DPI
527 		_fontStyle = FONT_STYLE_NORMAL;
528 		_fontWeight = 400;
529 		//_fontFace = "Arial"; // TODO: from settings
530 		_fontFace = "Verdana"; // TODO: from settings
531         _fontFamily = FontFamily.SansSerif;
532         _minHeight = 0;
533         _minWidth = 0;
534         _layoutWidth = WRAP_CONTENT;
535         _layoutHeight = WRAP_CONTENT;
536         _layoutWeight = 1;
537 	}
538 	
539 	~this() {
540 		Log.d("Theme destructor");
541 		foreach(ref Style item; _byId) {
542 			destroy(item);
543 			item = null;
544 		}
545 		_byId.clear();
546 	}
547 
548 	/// create wrapper style which will have currentTheme.get(id) as parent instead of fixed parent - to modify some base style properties in widget
549 	Style modifyStyle(string id) {
550 		Style style = new Style(null, null);
551 		style._parentId = id;
552         style._align = Align.Unspecified; // inherit
553 		return style;
554 	}
555 
556 	// ================================================
557 	// override to avoid infinite recursion
558 	/// font size
559 	@property override string backgroundImageId() const {
560         return _backgroundImageId;
561 	}
562 	/// minimal width constraint, 0 if limit is not set
563 	@property override uint minWidth() const {
564         return _minWidth;
565 	}
566 	/// max width constraint, returns SIZE_UNSPECIFIED if limit is not set
567 	@property override uint maxWidth() const {
568         return _maxWidth;
569 	}
570 	/// minimal height constraint, 0 if limit is not set
571 	@property override uint minHeight() const {
572         return _minHeight;
573 	}
574 	/// max height constraint, SIZE_UNSPECIFIED if limit is not set
575 	@property override uint maxHeight() const {
576         return _maxHeight;
577 	}
578 
579     private DrawableRef _emptyDrawable;
580     @property override ref DrawableRef customDrawable(string id) const {
581         if (id in _customDrawables)
582             return _customDrawables[id].drawable;
583         return (cast(Theme)this)._emptyDrawable;
584     }
585 
586     @property override string customDrawableId(string id) const {
587         if (id in _customDrawables)
588             return _customDrawables[id].drawableId;
589         return null;
590     }
591 
592 	/// create new named style
593 	override Style createSubstyle(string id) {
594 		Style style = new Style(this, id);
595 		if (id !is null)
596 			_byId[id] = style;
597         style._parentStyle = this; // as initial value, use theme as parent
598 		return style;
599 	}
600 
601 	/// find style by id, returns theme if not style with specified ID is not found
602 	@property Style get(string id) {
603 		if (id !is null && id in _byId)
604 			return _byId[id];
605 		return this;
606 	}
607 	
608 	/// find substyle based on widget state (e.g. focused, pressed, ...)
609 	override const(Style) forState(uint state) const {
610 		return this;
611 	}
612 
613 	void dumpStats() {
614 		Log.d("Theme ", _id, ": children:", _children.length, ", substates:", _substates.length, ", mapsize:", _byId.length);
615 	}
616 }
617 
618 /// to access current theme
619 private __gshared Theme _currentTheme;
620 @property Theme currentTheme() { return _currentTheme; }
621 @property void currentTheme(Theme theme) { 
622 	if (_currentTheme !is null) {
623 		destroy(_currentTheme);
624 	}
625 	_currentTheme = theme; 
626 }
627 
628 immutable ATTR_SCROLLBAR_BUTTON_UP = "scrollbar_button_up";
629 immutable ATTR_SCROLLBAR_BUTTON_DOWN = "scrollbar_button_down";
630 immutable ATTR_SCROLLBAR_BUTTON_LEFT = "scrollbar_button_left";
631 immutable ATTR_SCROLLBAR_BUTTON_RIGHT = "scrollbar_button_right";
632 immutable ATTR_SCROLLBAR_INDICATOR_VERTICAL = "scrollbar_indicator_vertical";
633 immutable ATTR_SCROLLBAR_INDICATOR_HORIZONTAL = "scrollbar_indicator_horizontal";
634 
635 Theme createDefaultTheme() {
636 	Log.d("Creating default theme");
637 	Theme res = new Theme("default");
638     //res.fontSize(14);
639     version (Windows) {
640         res.fontFace = "Verdana";
641     }
642     //res.fontFace = "Arial Narrow";
643     res.fontSize = 13; // TODO: choose based on DPI
644     Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small").alignment(Align.Center);
645     res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center);
646     res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);
647     res.createSubstyle("BUTTON_ICON").alignment(Align.Center);
648     res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1));
649     res.createSubstyle("HSPACER").layoutWidth(FILL_PARENT).layoutWeight(100);
650     res.createSubstyle("VSPACER").layoutHeight(FILL_PARENT).layoutWeight(100);
651     //button.createState(State.Enabled | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
652     //button.createState(State.Enabled, 0).backgroundImageId("btn_default_small_normal_disable");
653     //button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
654     //button.createState(State.Focused, State.Focused).backgroundImageId("btn_default_small_selected");
655     //button.createState(State.Hovered, State.Hovered).backgroundImageId("btn_default_small_normal_hover");
656     res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_UP, "scrollbar_btn_up");
657     res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_DOWN, "scrollbar_btn_down");
658     res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_LEFT, "scrollbar_btn_left");
659     res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_RIGHT, "scrollbar_btn_right");
660     res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_VERTICAL, "scrollbar_indicator_vertical");
661     res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_HORIZONTAL, "scrollbar_indicator_horizontal");
662 
663     Style scrollbar = res.createSubstyle("SCROLLBAR");
664     scrollbar.backgroundColor(0xC0808080);
665     Style scrollbarButton = button.createSubstyle("SCROLLBAR_BUTTON");
666     Style scrollbarSlider = res.createSubstyle("SLIDER");
667     Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF);
668     scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
669     scrollbarPage.createState(State.Hovered, State.Hovered).backgroundColor(0xF0404080);
670 
671     Style tabUp = res.createSubstyle("TAB_UP");
672     tabUp.backgroundImageId("tab_up_background");
673     tabUp.layoutWidth(FILL_PARENT);
674     tabUp.createState(State.Selected, State.Selected).backgroundImageId("tab_up_backgrond_selected");
675     Style tabUpButtonText = res.createSubstyle("TAB_UP_BUTTON_TEXT");
676     tabUpButtonText.textColor(0x000000).fontSize(12).alignment(Align.Center);
677     tabUpButtonText.createState(State.Selected, State.Selected).textColor(0x000000);
678     tabUpButtonText.createState(State.Selected|State.Focused, State.Selected|State.Focused).textColor(0x000000);
679     tabUpButtonText.createState(State.Focused, State.Focused).textColor(0x000000);
680     tabUpButtonText.createState(State.Hovered, State.Hovered).textColor(0xFFE0E0);
681     Style tabUpButton = res.createSubstyle("TAB_UP_BUTTON");
682     tabUpButton.backgroundImageId("tab_btn_up");
683     //tabUpButton.backgroundImageId("tab_btn_up_normal");
684     //tabUpButton.createState(State.Selected, State.Selected).backgroundImageId("tab_btn_up_selected");
685     //tabUpButton.createState(State.Selected|State.Focused, State.Selected|State.Focused).backgroundImageId("tab_btn_up_focused_selected");
686     //tabUpButton.createState(State.Focused, State.Focused).backgroundImageId("tab_btn_up_focused");
687     //tabUpButton.createState(State.Hovered, State.Hovered).backgroundImageId("tab_btn_up_hover");
688     Style tabHost = res.createSubstyle("TAB_HOST");
689     tabHost.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
690     tabHost.backgroundColor(0xF0F0F0);
691     Style tabWidget = res.createSubstyle("TAB_WIDGET");
692 	tabWidget.padding(Rect(3,3,3,3)).backgroundColor(0xEEEEEE);
693     //tabWidget.backgroundImageId("frame_blue");
694 	//res.dumpStats();
695 
696     Style mainMenu = res.createSubstyle("MAIN_MENU").backgroundColor(0xEFEFF2).layoutWidth(FILL_PARENT);
697     Style mainMenuItem = res.createSubstyle("MAIN_MENU_ITEM").padding(Rect(4,2,4,2)).backgroundImageId("main_menu_item_background");
698     Style menuItem = res.createSubstyle("MENU_ITEM").padding(Rect(4,2,4,2)); //.backgroundColor(0xE0E080)   ;
699     menuItem.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000);
700     menuItem.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
701     menuItem.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
702     menuItem.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00);
703 
704     Style transparentButtonBackground = res.createSubstyle("TRANSPARENT_BUTTON_BACKGROUND").padding(Rect(4,2,4,2)); //.backgroundColor(0xE0E080)   ;
705     transparentButtonBackground.createState(State.Focused, State.Focused).backgroundColor(0xC0C0C000);
706     transparentButtonBackground.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
707     //transparentButtonBackground.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
708     transparentButtonBackground.createState(State.Hovered, State.Hovered).backgroundColor(0xD0FFFF00);
709 
710     Style poopupMenu = res.createSubstyle("POPUP_MENU").backgroundImageId("popup_menu_background_normal");
711 
712     Style listItem = res.createSubstyle("LIST_ITEM");
713     listItem.createState(State.Selected, State.Selected).backgroundColor(0xC04040FF).textColor(0x000000);
714     listItem.createState(State.Enabled, 0).textColor(0x80000000); // half transparent text for disabled item
715 
716 	return res;
717 }
718 
719 shared static ~this() {
720 	currentTheme = null;
721 }