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