implement CheckBox and RadioButton controls

This commit is contained in:
Vadim Lopatin 2014-04-17 16:17:58 +04:00
parent 53e1898487
commit 4c4846e4a7
35 changed files with 355 additions and 31 deletions

7
.gitignore vendored
View File

@ -1,5 +1,10 @@
Debug
Release
Unittest
ui.log
obj
*.suo
Thumbs.db
.dub
bin
*.obj

View File

@ -65,6 +65,7 @@ Hello World
// setup resource directories - will use only existing directories
drawableCache.setResourcePaths(resourceDirs);
// optinally setup internatilnalization (if used)
// setup i18n - look for i18n directory inside one of passed directories
i18n.findTranslationsDir(resourceDirs);
// select translation file - for english language
@ -72,7 +73,10 @@ Hello World
// create window
Window window = Platform.instance.createWindow("My Window", null);
// create some widget to show in window
window.mainWidget = (new Button()).text("Hello world"d);
// show window
window.show();
// run message loop
return Platform.instance.enterMessageLoop();
}

View File

@ -54,12 +54,12 @@
<objname />
<libname />
<doDocComments>0</doDocComments>
<docdir />
<docname />
<docdir>docs</docdir>
<docname>docs/index.html</docname>
<modules_ddoc />
<ddocfiles />
<doHdrGeneration>0</doHdrGeneration>
<hdrdir />
<hdrdir>include</hdrdir>
<hdrname />
<doXGeneration>1</doXGeneration>
<xfilename>$(IntDir)\$(TargetName).json</xfilename>

View File

@ -12,8 +12,10 @@ extern (C) int UIAppMain(string[] args) {
// resource directory search paths
string[] resourceDirs = [
appendPath(exePath, "../../../res/"), // for Visual D and DUB builds
appendPath(exePath, "../../../res/mdpi/"), // for Visual D and DUB builds
appendPath(exePath, "../../../../res/"),// for Mono-D builds
appendPath(exePath, "res/") // when res dir is located at the same directory as executable
appendPath(exePath, "../../../../res/mdpi/"),// for Mono-D builds
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);
@ -70,9 +72,9 @@ extern (C) int UIAppMain(string[] args) {
LinearLayout hlayout = new HorizontalLayout();
//hlayout.addChild((new Button()).text("<<")); //.textColor(0x40FF4000)
hlayout.addChild((new TextWidget()).text("Several").alignment(Align.Center));
hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center));
hlayout.addChild((new ImageWidget()).drawableId("btn_radio").padding(Rect(5,5,5,5)).alignment(Align.Center));
hlayout.addChild((new TextWidget()).text("items").alignment(Align.Center));
hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center));
hlayout.addChild((new ImageWidget()).drawableId("btn_check").padding(Rect(5,5,5,5)).alignment(Align.Center));
hlayout.addChild((new TextWidget()).text("in horizontal layout"));
hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center));
//hlayout.addChild((new Button()).text(">>")); //.textColor(0x40FF4000)
@ -84,6 +86,9 @@ extern (C) int UIAppMain(string[] args) {
vlayout.addChild((new TextWidget()).text("VLayout line 1").textColor(0x40FF4000)); //
vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40FF8000));
vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40008000));
vlayout.addChild(new RadioButton("rb1", "Radio button 1"d));
vlayout.addChild(new RadioButton("rb2", "Radio button 2"d));
vlayout.addChild(new RadioButton("rb3", "Radio button 3"d));
vlayout.layoutWidth(FILL_PARENT);
vlayoutgroup.addChild(vlayout);
vlayoutgroup.layoutWidth(FILL_PARENT);
@ -94,12 +99,13 @@ extern (C) int UIAppMain(string[] args) {
ScrollBar sb = new ScrollBar("hscroll", Orientation.Horizontal);
layout.addChild(sb.layoutHeight(WRAP_CONTENT).layoutWidth(FILL_PARENT));
layout.addChild((new Button("BTN2")).textColor(0x000000FF).text("Button2"));
layout.addChild((new CheckBox("BTN2", "Some checkbox"d)));
layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
layout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)));
layout.addChild((new TextWidget()).textColor(0xFF4000).text("Text widget2").padding(Rect(5,5,5,5)).margins(Rect(5,5,5,5)).backgroundColor(0xA0A0A0));
layout.addChild((new Button("BTN3")).textColor(0x000000FF).text("Button3").layoutHeight(FILL_PARENT));
layout.addChild((new TextWidget()).textColor(0x004000).text("Text widget3 with very long text"));
layout.addChild((new RadioButton("BTN3", "Some radio button"d)));
layout.addChild((new TextWidget(null, "Text widget3 with very long text"d)).textColor(0x004000));
layout.addChild(new VSpacer()); // vertical spacer to fill extra space
layout.childById("BTN1").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; });
layout.childById("BTN2").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; });

View File

@ -25,10 +25,12 @@ extern (C) int UIAppMain(string[] args) {
// create window
Window window = Platform.instance.createWindow("My Window", null);
window.mainWidget = (new Button()).text("sample button");
// create some widget to show in window
window.mainWidget = (new Button()).text("Hello world"d);
// show window
window.show();
//window.windowCaption = "New Window Caption";
// run message loop
return Platform.instance.enterMessageLoop();
}

65
res/btn_check.xml Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Enabled states -->
<item android:state_checked="true" android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on_holo_light" />
<item android:state_checked="false" android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off_holo_light" />
<item android:state_checked="true" android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on_pressed_holo_light" />
<item android:state_checked="false" android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off_pressed_holo_light" />
<item android:state_checked="true" android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on_focused_holo_light" />
<item android:state_checked="false" android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off_focused_holo_light" />
<item android:state_checked="false"
android:state_enabled="true"
android:drawable="@drawable/btn_check_off_holo_light" />
<item android:state_checked="true"
android:state_enabled="true"
android:drawable="@drawable/btn_check_on_holo_light" />
<!-- Disabled states -->
<item android:state_checked="true" android:state_window_focused="false"
android:drawable="@drawable/btn_check_on_disabled_holo_light" />
<item android:state_checked="false" android:state_window_focused="false"
android:drawable="@drawable/btn_check_off_disabled_holo_light" />
<item android:state_checked="true" android:state_focused="true"
android:drawable="@drawable/btn_check_on_disabled_focused_holo_light" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="@drawable/btn_check_off_disabled_focused_holo_light" />
<item android:state_checked="false" android:drawable="@drawable/btn_check_off_disabled_holo_light" />
<item android:state_checked="true" android:drawable="@drawable/btn_check_on_disabled_holo_light" />
</selector>

59
res/btn_radio.xml Normal file
View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_radio_on_holo_light" />
<item android:state_checked="false" android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_radio_off_holo_light" />
<item android:state_checked="true" android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/btn_radio_on_pressed_holo_light" />
<item android:state_checked="false" android:state_pressed="true"
android:state_enabled="true"
android:drawable="@drawable/btn_radio_off_pressed_holo_light" />
<item android:state_checked="true" android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_radio_on_focused_holo_light" />
<item android:state_checked="false" android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_radio_off_focused_holo_light" />
<item android:state_checked="false" android:state_enabled="true"
android:drawable="@drawable/btn_radio_off_holo_light" />
<item android:state_checked="true" android:state_enabled="true"
android:drawable="@drawable/btn_radio_on_holo_light" />
<!-- Disabled states -->
<item android:state_checked="true" android:state_window_focused="false"
android:drawable="@drawable/btn_radio_on_disabled_holo_light" />
<item android:state_checked="false" android:state_window_focused="false"
android:drawable="@drawable/btn_radio_off_disabled_holo_light" />
<item android:state_checked="true" android:state_focused="true"
android:drawable="@drawable/btn_radio_on_disabled_focused_holo_light" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="@drawable/btn_radio_off_disabled_focused_holo_light" />
<item android:state_checked="false" android:drawable="@drawable/btn_radio_off_disabled_holo_light" />
<item android:state_checked="true" android:drawable="@drawable/btn_radio_on_disabled_holo_light" />
</selector>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="main_menu_item_background_selected"
android:state_selected="true" />
<item
android:drawable="main_menu_item_background_hover"
android:state_hovered="true" />
<item
android:drawable="@null" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -21,8 +21,10 @@ extern (C) int UIAppMain(string[] args) {
appendPath(exePath, "../../../../res/"), // for Mono-D builds
appendPath(exePath, "res/") // 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
@ -30,7 +32,10 @@ extern (C) int UIAppMain(string[] args) {
// create window
Window window = Platform.instance.createWindow("My Window", null);
// create some widget to show in window
window.mainWidget = (new Button()).text("Hello world"d);
// show window
window.show();
// run message loop
return Platform.instance.enterMessageLoop();
}

View File

@ -351,6 +351,8 @@ class StateDrawable : Drawable {
foreach(item; element.elements) {
if (item.tag.name.equal("item")) {
string drawableId = attrValue(item, "drawable", "android:drawable");
if (drawableId.startsWith("@drawable/"))
drawableId = drawableId[10 .. $];
ColorTransform transform;
transform.addBefore = colorTransformFromStringAdd(attrValue(item, "color_transform_add1", "android:transform_color_add1"));
transform.multiply = colorTransformFromStringMult(attrValue(item, "color_transform_mul", "android:transform_color_mul"));
@ -394,8 +396,12 @@ class StateDrawable : Drawable {
override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
foreach(ref item; _stateList)
if (item.matchState(state)) {
if (!item.drawable.isNull)
if (!item.drawable.isNull) {
if (state & State.Checked) {
Log.d("Found item for checked state: ", item.stateMask, " ", item.stateValue);
}
item.drawable.drawTo(buf, rc, state, tilex0, tiley0);
}
return;
}
}
@ -620,24 +626,28 @@ class DrawableCache {
return _drawable;
if (_filename !is null) {
// reload from file
if (_filename.endsWith(".xml")) {
if (_filename.endsWith(".xml") || _filename.endsWith(".XML")) {
// XML drawables support
StateDrawable d = new StateDrawable();
if (!d.load(_filename)) {
Log.e("failed to load .xml drawable from ", _filename);
destroy(d);
_error = true;
} else {
Log.d("loaded .xml drawable from ", _filename);
_drawable = d;
}
} else {
// PNG/JPEG drawables support
DrawBufRef image = imageCache.get(_filename, transform);
if (!image.isNull) {
bool ninePatch = _filename.endsWith(".9.png");
bool ninePatch = _filename.endsWith(".9.png") || _filename.endsWith(".9.PNG");
_transformed[transform] = new ImageDrawable(image, _tiled, ninePatch);
return _transformed[transform];
} else
} else {
Log.e("failed to load image from ", _filename);
_error = true;
}
}
}
return _drawable;
@ -743,6 +753,8 @@ class DrawableCache {
if (fn !is null) {
_idToFileMap[id] = fn;
return fn;
} else {
Log.w("resource ", id, " is not found");
}
}
return null;

View File

@ -286,9 +286,11 @@ class Win32Font : Font {
lf.lfFaceName[def.face.length] = 0;
lf.lfHeight = -size;
lf.lfItalic = italic;
lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
lf.lfOutPrecision = OUT_OUTLINE_PRECIS; //OUT_TT_ONLY_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = ANTIALIASED_QUALITY;
//lf.lfQuality = NONANTIALIASED_QUALITY; //ANTIALIASED_QUALITY;
//lf.lfQuality = PROOF_QUALITY; //ANTIALIASED_QUALITY;
lf.lfQuality = size < 18 ? NONANTIALIASED_QUALITY : PROOF_QUALITY; //ANTIALIASED_QUALITY;
lf.lfPitchAndFamily = def.pitchAndFamily;
_hfont = CreateFontIndirectA(&lf);
_drawbuf = new Win32ColorDrawBuf(1, 1);

View File

@ -30,14 +30,33 @@ Authors: $(WEB coolreader.org, Vadim Lopatin)
module dlangui.widgets.controls;
import dlangui.widgets.widget;
import dlangui.widgets.layouts;
/// vertical spacer to fill empty space in vertical layouts
class VSpacer : Widget {
this() {
styleId = "VSpacer";
}
}
/// horizontal spacer to fill empty space in horizontal layouts
class HSpacer : Widget {
this() {
styleId = "HSpacer";
}
}
/// static text widget
class TextWidget : Widget {
this(string ID = null) {
this(string ID = null, string textResourceId = null) {
super(ID);
styleId = "TEXT";
_text = textResourceId;
}
this(string ID, dstring rawText) {
super(ID);
styleId = "TEXT";
_text = rawText;
}
protected UIString _text;
/// get widget text
@ -49,7 +68,7 @@ class TextWidget : Widget {
return this;
}
/// set text to show
@property Widget text(ref UIString s) {
override @property Widget text(ref UIString s) {
_text = s;
requestLayout();
return this;
@ -152,7 +171,11 @@ class ImageWidget : Widget {
sz.x = img.width;
sz.y = img.height;
applyAlign(rc, sz);
img.drawTo(buf, rc, state);
uint st = state;
if (state & State.Checked) {
Log.d("Drawing image for checked state");
}
img.drawTo(buf, rc, st);
}
}
}
@ -160,18 +183,98 @@ class ImageWidget : Widget {
/// button with image only
class ImageButton : ImageWidget {
this(string ID = null, string drawableId = null) {
super(ID);
super(ID, drawableId);
styleId = "BUTTON";
_drawableId = drawableId;
clickable = true;
focusable = true;
trackHover = true;
}
}
/// button with image and text
class ImageTextButton : HorizontalLayout {
protected ImageWidget _icon;
protected TextWidget _label;
override @property dstring text() { return _label.text; }
override @property Widget text(dstring s) { _label.text = s; requestLayout(); return this; }
override @property Widget text(ref UIString s) { _label.text = s; requestLayout(); return this; }
this(string ID = null, string drawableId = null, string textResourceId = null) {
super(ID);
styleId = "BUTTON";
_icon = new ImageWidget("icon", drawableId);
_label = new TextWidget("label", textResourceId);
_label.styleId = "BUTTON_LABEL";
_icon.state = State.Parent;
_label.state = State.Parent;
addChild(_icon);
addChild(_label);
clickable = true;
focusable = true;
trackHover = true;
}
this(string ID, string drawableId, dstring rawText) {
super(ID);
styleId = "BUTTON";
_icon = new ImageWidget("icon", drawableId);
_label = new TextWidget("label", rawText);
_label.styleId = "BUTTON_LABEL";
_icon.styleId = "BUTTON_ICON";
_icon.state = State.Parent;
_label.state = State.Parent;
addChild(_icon);
addChild(_label);
clickable = true;
focusable = true;
trackHover = true;
}
}
/// checkbox
class CheckBox : ImageTextButton {
this(string ID = null, string textResourceId = null) {
super(ID, "btn_check", textResourceId);
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
checkable = true;
}
this(string ID, dstring labelText) {
super(ID, "btn_check", labelText);
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
checkable = true;
}
// called to process click and notify listeners
override protected bool handleClick() {
checked = !checked;
return super.handleClick();
}
}
/// radio button
class RadioButton : ImageTextButton {
this(string ID = null, string textResourceId = null) {
super(ID, "btn_radio", textResourceId);
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
checkable = true;
}
this(string ID, dstring labelText) {
super(ID, "btn_radio", labelText);
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
checkable = true;
}
// called to process click and notify listeners
override protected bool handleClick() {
checked = true;
return super.handleClick();
}
}
/// Text only button
class Button : Widget {
protected UIString _text;
override @property dstring text() { return _text; }
override @property Widget text(dstring s) { _text = s; requestLayout(); return this; }
override @property Widget text(ref UIString s) { _text = s; requestLayout(); return this; }
@property Widget textResource(string s) { _text = s; requestLayout(); return this; }
this(string ID = null) {
super(ID);

View File

@ -523,10 +523,11 @@ class Theme : Style {
_backgroundColor = 0xFFFFFFFF; // transparent
_textColor = 0x000000; // black
_align = Align.TopLeft;
_fontSize = 24; // TODO: from settings or screen properties / DPI
_fontSize = 14; // TODO: from settings or screen properties / DPI
_fontStyle = FONT_STYLE_NORMAL;
_fontWeight = 400;
_fontFace = "Arial"; // TODO: from settings
//_fontFace = "Arial"; // TODO: from settings
_fontFace = "Verdana"; // TODO: from settings
_fontFamily = FontFamily.SansSerif;
_minHeight = 0;
_minWidth = 0;
@ -635,10 +636,18 @@ Theme createDefaultTheme() {
Log.d("Creating default theme");
Theme res = new Theme("default");
//res.fontSize(14);
res.fontSize(24);
version (Windows) {
res.fontFace = "Verdana";
}
//res.fontFace = "Arial Narrow";
res.fontSize = 13; // TODO: choose based on DPI
Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small").alignment(Align.Center);
Style buttonTransparent = res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center);
Style text = res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1));
res.createSubstyle("BUTTON_TRANSPARENT").backgroundImageId("btn_default_small_transparent").alignment(Align.Center);
res.createSubstyle("BUTTON_LABEL").layoutWidth(FILL_PARENT).alignment(Align.Left|Align.VCenter);
res.createSubstyle("BUTTON_ICON").alignment(Align.Center);
res.createSubstyle("TEXT").margins(Rect(2,2,2,2)).padding(Rect(1,1,1,1));
res.createSubstyle("HSPACER").layoutWidth(FILL_PARENT).layoutWeight(100);
res.createSubstyle("VSPACER").layoutHeight(FILL_PARENT).layoutWeight(100);
//button.createState(State.Enabled | State.Focused, State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
//button.createState(State.Enabled, 0).backgroundImageId("btn_default_small_normal_disable");
//button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
@ -692,6 +701,12 @@ Theme createDefaultTheme() {
menuItem.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
menuItem.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00);
Style transparentButtonBackground = res.createSubstyle("TRANSPARENT_BUTTON_BACKGROUND").padding(Rect(4,2,4,2)); //.backgroundColor(0xE0E080) ;
transparentButtonBackground.createState(State.Focused, State.Focused).backgroundColor(0x40C0C000);
transparentButtonBackground.createState(State.Pressed, State.Pressed).backgroundColor(0x4080C000);
transparentButtonBackground.createState(State.Selected, State.Selected).backgroundColor(0x00F8F9Fa);
transparentButtonBackground.createState(State.Hovered, State.Hovered).backgroundColor(0xC0FFFF00);
Style poopupMenu = res.createSubstyle("POPUP_MENU").backgroundImageId("popup_menu_background_normal");
Style listItem = res.createSubstyle("LIST_ITEM");

View File

@ -259,6 +259,8 @@ class Widget {
@property dstring text() { return ""; }
/// sets widget content text (override to support this)
@property Widget text(dstring s) { return this; }
/// sets widget content text (override to support this)
@property Widget text(ref UIString s) { return this; }
//==================================================================
// Layout and drawing related methods
@ -337,12 +339,39 @@ class Widget {
return _pos.isPointInside(x, y);
}
protected bool _clickable;
@property bool clickable() { return _clickable; }
@property Widget clickable(bool flg) { _clickable = flg; return this; }
protected bool _checkable;
@property bool checkable() { return _checkable; }
@property Widget checkable(bool flg) { _checkable = flg; return this; }
protected bool _checked;
/// get checked state
@property bool checked() { return (state & State.Checked) != 0; }
/// set checked state
@property Widget checked(bool flg) {
if (flg != checked) {
if (flg)
setState(State.Checked);
else
resetState(State.Checked);
invalidate();
}
return this;
}
protected bool _focusable;
@property bool focusable() { return _focusable; }
@property Widget focusable(bool flg) { _focusable = flg; return this; }
@property bool focused() {
return (window !is null && window.focusedWidget is this && (state & State.Focused));
}
/// returns true if this widget and all its parents are visible
@property bool visible() {
if (visibility != Visibility.Visible)
@ -390,9 +419,15 @@ class Widget {
// =======================================================
// Events
// called to process click and notify listeners
protected bool handleClick() {
bool res = onClickListener(this);
return res;
}
/// process key event, return true if event is processed.
bool onKeyEvent(KeyEvent event) {
if (onClickListener.assigned) {
if (clickable) {
// support onClick event initiated by Space or Return keys
if (event.action == KeyAction.KeyDown) {
if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) {
@ -403,7 +438,7 @@ class Widget {
if (event.action == KeyAction.KeyUp) {
if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) {
resetState(State.Pressed);
onClickListener(this);
handleClick();
return true;
}
}
@ -415,7 +450,7 @@ class Widget {
bool onMouseEvent(MouseEvent event) {
//Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")");
// support onClick
if (onClickListener.assigned) {
if (clickable) {
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
setState(State.Pressed);
if (focusable)
@ -424,7 +459,7 @@ class Widget {
}
if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
resetState(State.Pressed);
onClickListener(this);
handleClick();
return true;
}
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {