diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d
index 39512412..ba43def4 100644
--- a/examples/example1/src/main.d
+++ b/examples/example1/src/main.d
@@ -1,4 +1,4 @@
-module winmain;
+module main;
import dlangui.all;
import std.stdio;
@@ -24,13 +24,6 @@ extern (C) int UIAppMain(string[] args) {
// select translation file - for english language
i18n.load("en.ini"); //"ru.ini", "en.ini"
-
- DrawBufRef img = imageCache.get("C:\\projects\\d\\dlangui\\res\\mdpi\\btn_radio_on_holo_light.png");
- ColorDrawBuf buf = cast(ColorDrawBuf)img.get;
- //GrayDrawBuf gbuf = cast(GrayDrawBuf)img.get;
- uint * row = buf.scanLine(0);
- Log.d("btn_radio_on_holo_light pixels: ", row[0], row[1], row[2]);
-
// create window
Window window = Platform.instance.createWindow("My Window", null);
diff --git a/res/btn_default_small.xml b/res/btn_default_small.xml
index 358969f7..5485ea03 100644
--- a/res/btn_default_small.xml
+++ b/res/btn_default_small.xml
@@ -1,25 +1,33 @@
-
-
-
- android:state_focused="true" />
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/mdpi/btn_default_small_normal.9.png b/res/mdpi/btn_default_small_normal.9.png
new file mode 100644
index 00000000..5dddd464
Binary files /dev/null and b/res/mdpi/btn_default_small_normal.9.png differ
diff --git a/res/mdpi/btn_default_small_normal_disable.9.png b/res/mdpi/btn_default_small_normal_disable.9.png
new file mode 100644
index 00000000..6ab5c4a2
Binary files /dev/null and b/res/mdpi/btn_default_small_normal_disable.9.png differ
diff --git a/res/mdpi/btn_default_small_normal_disable_focused.9.png b/res/mdpi/btn_default_small_normal_disable_focused.9.png
new file mode 100644
index 00000000..c65bace3
Binary files /dev/null and b/res/mdpi/btn_default_small_normal_disable_focused.9.png differ
diff --git a/res/mdpi/btn_default_small_pressed.9.png b/res/mdpi/btn_default_small_pressed.9.png
new file mode 100644
index 00000000..43e82f97
Binary files /dev/null and b/res/mdpi/btn_default_small_pressed.9.png differ
diff --git a/res/mdpi/btn_default_small_selected.9.png b/res/mdpi/btn_default_small_selected.9.png
new file mode 100644
index 00000000..7a376a97
Binary files /dev/null and b/res/mdpi/btn_default_small_selected.9.png differ
diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d
index e0b97828..51bbee49 100644
--- a/src/dlangui/widgets/controls.d
+++ b/src/dlangui/widgets/controls.d
@@ -261,9 +261,26 @@ class RadioButton : ImageTextButton {
styleId = "TRANSPARENT_BUTTON_BACKGROUND";
checkable = true;
}
+
+ void uncheckSiblings() {
+ Widget p = parent;
+ if (!p)
+ return;
+ for (int i = 0; i < p.childCount; i++) {
+ Widget child = p.child(i);
+ if (child is this)
+ continue;
+ RadioButton rb = cast(RadioButton)child;
+ if (rb)
+ rb.checked = false;
+ }
+ }
+
// called to process click and notify listeners
override protected bool handleClick() {
+ uncheckSiblings();
checked = true;
+
return super.handleClick();
}
@@ -279,6 +296,7 @@ class Button : Widget {
this(string ID = null) {
super(ID);
styleId = "BUTTON";
+ clickable = true;
focusable = true;
trackHover = true;
}
@@ -399,6 +417,7 @@ class ScrollBar : AbstractSlider, OnClickHandler {
super(ID);
styleId = "PAGE_SCROLL";
trackHover = true;
+ clickable = true;
}
}
diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d
index ce8be428..66cf932e 100644
--- a/src/dlangui/widgets/lists.d
+++ b/src/dlangui/widgets/lists.d
@@ -236,7 +236,7 @@ class ListWidget : WidgetGroup, OnScrollHandler {
}
/// override to handle focus changes
- override protected void onFocusChange(bool focused) {
+ override protected void handleFocusChange(bool focused) {
updateSelectedItemFocus();
}
diff --git a/src/dlangui/widgets/menu.d b/src/dlangui/widgets/menu.d
index abfd671c..99431e57 100644
--- a/src/dlangui/widgets/menu.d
+++ b/src/dlangui/widgets/menu.d
@@ -90,6 +90,7 @@ class MenuItemWidget : HorizontalLayout {
_label.text = _item.label;
addChild(_label);
trackHover = true;
+ clickable = true;
}
}
diff --git a/src/dlangui/widgets/tabs.d b/src/dlangui/widgets/tabs.d
index f5509454..79c6e2e3 100644
--- a/src/dlangui/widgets/tabs.d
+++ b/src/dlangui/widgets/tabs.d
@@ -20,6 +20,7 @@ Authors: $(WEB coolreader.org, Vadim Lopatin)
*/
module dlangui.widgets.tabs;
+import dlangui.core.signals;
import dlangui.widgets.layouts;
import dlangui.widgets.controls;
@@ -82,6 +83,7 @@ class TabItemWidget : HorizontalLayout {
addChild(_label);
addChild(_closeButton);
setItem(item);
+ clickable = true;
trackHover = true;
}
protected bool onClick(Widget source) {
diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d
index c0635dfc..7b297b41 100644
--- a/src/dlangui/widgets/widget.d
+++ b/src/dlangui/widgets/widget.d
@@ -52,10 +52,21 @@ enum Orientation : ubyte {
Horizontal
}
+/// interface - slot for onClick
interface OnClickHandler {
bool onClick(Widget source);
}
+/// interface - slot for onCheckChanged
+interface OnCheckHandler {
+ bool onCheckChanged(Widget source, bool checked);
+}
+
+/// interface - slot for onFocusChanged
+interface OnFocusHandler {
+ bool onFocusChanged(Widget source, bool focused);
+}
+
class Widget {
/// widget id
protected string _id;
@@ -152,10 +163,15 @@ class Widget {
@property uint state() const {
if ((_state & State.Parent) != 0 && _parent !is null)
return _parent.state;
- return _state;
+ return _state | State.WindowFocused; // TODO:
}
/// override to handle focus changes
- protected void onFocusChange(bool focused) {
+ protected void handleFocusChange(bool focused) {
+ onFocusChangeListener(this, checked);
+ }
+ /// override to handle check changes
+ protected void handleCheckChange(bool checked) {
+ onCheckChangeListener(this, checked);
}
/// set new widget state (set of flags from State enum)
@property Widget state(uint newState) {
@@ -166,9 +182,14 @@ class Widget {
invalidate();
// notify focus changes
if ((oldState & State.Focused) && !(newState & State.Focused))
- onFocusChange(false);
+ handleFocusChange(false);
else if (!(oldState & State.Focused) && (newState & State.Focused))
- onFocusChange(true);
+ handleFocusChange(true);
+ // notify checked changes
+ if ((oldState & State.Checked) && !(newState & State.Checked))
+ handleCheckChange(false);
+ else if (!(oldState & State.Checked) && (newState & State.Checked))
+ handleCheckChange(true);
}
return this;
}
@@ -337,13 +358,23 @@ class Widget {
return _pos.isPointInside(x, y);
}
+ /// return true if state has State.Enabled flag set
+ @property bool enabled() { return (state & State.Enabled) != 0; }
+ /// change enabled state
+ @property Widget enabled(bool flg) { flg ? setState(State.Enabled) : resetState(State.Enabled); return this; }
+
protected bool _clickable;
+ /// when true, user can click this control, and get onClick listeners called
@property bool clickable() { return _clickable; }
@property Widget clickable(bool flg) { _clickable = flg; return this; }
+ @property bool canClick() { return _clickable && enabled && visible; }
protected bool _checkable;
+ /// when true, control supports Checked state
@property bool checkable() { return _checkable; }
@property Widget checkable(bool flg) { _checkable = flg; return this; }
+ @property bool canCheck() { return _checkable && enabled && visible; }
+
protected bool _checked;
/// get checked state
@@ -425,7 +456,7 @@ class Widget {
/// process key event, return true if event is processed.
bool onKeyEvent(KeyEvent event) {
- if (clickable) {
+ if (canClick) {
// support onClick event initiated by Space or Return keys
if (event.action == KeyAction.KeyDown) {
if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) {
@@ -448,7 +479,7 @@ class Widget {
bool onMouseEvent(MouseEvent event) {
//Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")");
// support onClick
- if (clickable) {
+ if (canClick) {
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
setState(State.Pressed);
if (focusable)
@@ -497,10 +528,16 @@ class Widget {
return false;
}
+ // =======================================================
+ // Signals
/// on click event listener (bool delegate(Widget))
Signal!OnClickHandler onClickListener;
-
+ /// checked state change event listener (bool delegate(Widget, bool))
+ Signal!OnCheckHandler onCheckChangeListener;
+ /// focus state change event listener (bool delegate(Widget, bool))
+ Signal!OnFocusHandler onFocusChangeListener;
+
// =======================================================
// Layout and measurement methods