diff --git a/src/dlangui/widgets/combobox.d b/src/dlangui/widgets/combobox.d index 983494ac..099c82b2 100644 --- a/src/dlangui/widgets/combobox.d +++ b/src/dlangui/widgets/combobox.d @@ -1,3 +1,30 @@ +// Written in the D programming language. + +/** +This module contains Combo Box widgets implementation. + + + +Synopsis: + +---- +import dlangui.widgets.combobox; + +// creation of simple strings list +ComboBox box = new ComboBox("combo1", ["value 1"d, "value 2"d, "value 3"d]); + +// select first item +box.selectedItemIndex = 0; + +// get selected item text +println(box.text); + +---- + +Copyright: Vadim Lopatin, 2014 +License: Boost License 1.0 +Authors: Vadim Lopatin, coolreader.org@gmail.com +*/ module dlangui.widgets.combobox; import dlangui.widgets.widget; @@ -5,9 +32,11 @@ import dlangui.widgets.layouts; import dlangui.widgets.editors; import dlangui.widgets.lists; import dlangui.widgets.controls; +import dlangui.widgets.popup; private import std.algorithm; +/** Abstract ComboBox. */ class ComboBoxBase : HorizontalLayout, OnClickHandler { protected Widget _body; protected ImageButton _button; @@ -15,6 +44,9 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler { protected bool _ownAdapter; protected int _selectedItemIndex; + /** Handle item click. */ + Signal!OnItemSelectedHandler onItemClickListener; + protected Widget createSelectedItemWidget() { Widget res; if (_adapter && _selectedItemIndex < _adapter.itemCount) { @@ -34,11 +66,15 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler { } @property void selectedItemIndex(int index) { + if (_selectedItemIndex == index) + return; _selectedItemIndex = index; + if (onItemClickListener.assigned) + onItemClickListener(this, index); } override bool onClick(Widget source) { - // TODO + showPopup(); return true; } @@ -48,17 +84,56 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler { return res; } + protected ListWidget createPopup() { + ListWidget list = new ListWidget("POPUP_LIST"); + list.adapter = _adapter; + list.selectedItemIndex = _selectedItemIndex; + return list; + } + + protected PopupWidget _popup; + protected ListWidget _popupList; + + protected void showPopup() { + _popupList = createPopup(); + _popup = window.showPopup(_popupList, this, PopupAlign.Below | PopupAlign.FitAnchorSize); + _popup.flags = PopupFlags.CloseOnClickOutside; + _popup.styleId = "POPUP_MENU"; + _popup.onPopupCloseListener = delegate (PopupWidget source) { + _popup = null; + _popupList = null; + }; + _popupList.onItemSelectedListener = delegate(Widget source, int index) { + selectedItemIndex = index; + return true; + }; + _popupList.onItemClickListener = delegate(Widget source, int index) { + selectedItemIndex = index; + if (_popup !is null) + _popup.close(); + return true; + }; + _popupList.setFocus(); + } + this(string ID, ListAdapter adapter, bool ownAdapter = true) { super(ID); _adapter = adapter; _ownAdapter = ownAdapter; _body = createSelectedItemWidget(); + _body.onClickListener = this; _button = createButton(); + //_body.state = State.Parent; + //focusable = true; + _button.focusable = false; + _body.focusable = true; addChild(_body); addChild(_button); } } + +/** ComboBox with list of strings. */ class ComboBox : ComboBoxBase { protected StringListAdapter _adapter; diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index e2f5fab1..69b29c05 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -20,6 +20,7 @@ module dlangui.widgets.lists; import dlangui.widgets.widget; import dlangui.widgets.controls; +import dlangui.core.signals; /// list widget adapter provides items for list widgets interface ListAdapter { @@ -155,8 +156,25 @@ class StringListAdapter : ListAdapter { } } -/// List +/** interface - slot for onItemSelectedListener */ +interface OnItemSelectedHandler { + bool onItemSelected(Widget source, int itemIndex); +} + +/** interface - slot for onItemClickListener */ +interface OnItemClickHandler { + bool onItemClick(Widget source, int itemIndex); +} + + +/** List widget - shows content as hori*/ class ListWidget : WidgetGroup, OnScrollHandler { + + /** Handle selection change. */ + Signal!OnItemSelectedHandler onItemSelectedListener; + /** Handle item click. */ + Signal!OnItemSelectedHandler onItemClickListener; + protected Orientation _orientation = Orientation.Vertical; /// returns linear layout orientation (Vertical, Horizontal) @property Orientation orientation() { return _orientation; } @@ -308,10 +326,14 @@ class ListWidget : WidgetGroup, OnScrollHandler { /// override to handle change of selection protected void selectionChanged(int index, int previouslySelectedItem = -1) { + if (onItemSelectedListener.assigned) + onItemSelectedListener(this, index); } /// override to handle mouse up on item protected void itemClicked(int index) { + if (onItemClickListener.assigned) + onItemClickListener(this, index); } protected void updateSelectedItemFocus() { diff --git a/src/dlangui/widgets/popup.d b/src/dlangui/widgets/popup.d index 6d874652..6e84520c 100644 --- a/src/dlangui/widgets/popup.d +++ b/src/dlangui/widgets/popup.d @@ -22,6 +22,7 @@ module dlangui.widgets.popup; import dlangui.widgets.widget; import dlangui.widgets.layouts; +import dlangui.core.signals; import dlangui.platforms.common.platform; /// popup alignment option flags @@ -34,6 +35,8 @@ enum PopupAlign : uint { Right = 4, /// align to specified point Point = 8, + /// if popup content size is less than anchor's size, increase it to anchor size + FitAnchorSize = 16, } struct PopupAnchor { @@ -49,17 +52,24 @@ enum PopupFlags : uint { CloseOnClickOutside = 1, } +/** interface - slot for onPopupCloseListener */ +interface OnPopupCloseHandler { + void onPopupClosed(PopupWidget source); +} + /// popup widget container class PopupWidget : LinearLayout { protected PopupAnchor _anchor; protected bool _modal; protected uint _flags; - protected void delegate(PopupWidget popup) _onPopupCloseListener; + /** popup close signal */ + Signal!OnPopupCloseHandler onPopupCloseListener; + //protected void delegate(PopupWidget popup) _onPopupCloseListener; /// popup close listener (called right before closing) - @property void delegate(PopupWidget popup) onPopupCloseListener() { return _onPopupCloseListener; } + //@property void delegate(PopupWidget popup) onPopupCloseListener() { return _onPopupCloseListener; } /// set popup close listener (to call right before closing) - @property PopupWidget onPopupCloseListener(void delegate(PopupWidget popup) listener) { _onPopupCloseListener = listener; return this; } + //@property PopupWidget onPopupCloseListener(void delegate(PopupWidget popup) listener) { _onPopupCloseListener = listener; return this; } /// returns popup behavior flags (combination of PopupFlags) @property uint flags() { return _flags; } @@ -84,8 +94,8 @@ class PopupWidget : LinearLayout { /// just call on close listener void onClose() { - if (_onPopupCloseListener !is null) - _onPopupCloseListener(this); + if (onPopupCloseListener.assigned) + onPopupCloseListener(this); } /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). @@ -124,6 +134,9 @@ class PopupWidget : LinearLayout { r.left = anchorrc.right; r.top = anchorrc.top; } + if (anchor.alignment & PopupAlign.FitAnchorSize) + if (w < anchorrc.width) + w = anchorrc.width; } r.right = r.left + w; r.bottom = r.top + h;