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 }