popup and menu improvements

This commit is contained in:
Vadim Lopatin 2014-04-15 11:13:49 +04:00
parent 8d5833640f
commit 321e657661
3 changed files with 64 additions and 4 deletions

View File

@ -78,6 +78,7 @@ class Window {
for (int j = i; j < _popups.length - 1; j++)
_popups[j] = _popups[j + 1];
_popups.length--;
p.onClose();
destroy(p);
// force redraw
_mainWidget.invalidate();
@ -340,14 +341,25 @@ class Window {
processed = checkRemoveTracking(event);
}
if (!res) {
bool insideOneOfPopups = false;
for (int i = cast(int)_popups.length - 1; i >= 0; i--) {
auto p = _popups[i];
if (dispatchMouseEvent(p, event))
return true;
if (p.isPointInside(event.x, event.y))
insideOneOfPopups = true;
}
for (int i = cast(int)_popups.length - 1; i >= 0; i--) {
auto p = _popups[i];
if (!insideOneOfPopups) {
if (p.onMouseEventOutside(event)) // stop loop when true is returned, but allow other main widget to handle event
break;
} else {
if (dispatchMouseEvent(p, event))
return true;
}
}
res = dispatchMouseEvent(_mainWidget, event);
}
return res || processed;
return res || processed || _mainWidget.needDraw;
}
/// checks content widgets for necessary redraw and/or layout

View File

@ -102,11 +102,20 @@ class MenuWidgetBase : ListWidget {
ownAdapter = adapter;
}
protected void onPopupClosed(PopupWidget p) {
_openedPopup = null;
_openedMenu = null;
selectItem(-1);
}
protected void openSubmenu(MenuItemWidget itemWidget) {
if (_openedPopup !is null)
if (_openedPopup !is null) {
_openedPopup.close();
}
PopupMenu popupMenu = new PopupMenu(itemWidget.item, this);
PopupWidget popup = window.showPopup(popupMenu, itemWidget, PopupAlign.Below);
popup.onPopupCloseListener = &onPopupClosed;
popup.flags = PopupFlags.CloseOnClickOutside;
_openedPopup = popup;
_openedMenu = popupMenu;
}

View File

@ -17,10 +17,29 @@ struct PopupAnchor {
uint alignment = PopupAlign.Center;
}
/// popup behavior flags - for PopupWidget.flags property
enum PopupFlags : uint {
/// close popup when mouse button clicked outside of its bounds
CloseOnClickOutside = 1,
}
/// popup widget container
class PopupWidget : LinearLayout {
protected PopupAnchor _anchor;
protected bool _modal;
protected uint _flags;
protected void delegate(PopupWidget popup) _onPopupCloseListener;
/// popup close listener (called right before closing)
@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; }
/// returns popup behavior flags (combination of PopupFlags)
@property uint flags() { return _flags; }
/// set popup behavior flags (combination of PopupFlags)
@property PopupWidget flags(uint flags) { _flags = flags; return this; }
/// access to popup anchor
@property ref PopupAnchor anchor() { return _anchor; }
/// returns true if popup is modal
@ -37,6 +56,12 @@ class PopupWidget : LinearLayout {
window.removePopup(this);
}
/// just call on close listener
void onClose() {
if (_onPopupCloseListener !is null)
_onPopupCloseListener(this);
}
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) {
if (visibility == Visibility.Gone) {
@ -77,4 +102,18 @@ class PopupWidget : LinearLayout {
//styleId = "POPUP_MENU";
addChild(content);
}
/// called for mouse activity outside shown popup bounds
bool onMouseEventOutside(MouseEvent event) {
if (visibility != Visibility.Visible)
return false;
if (_flags & PopupFlags.CloseOnClickOutside) {
if (event.action == MouseAction.ButtonDown) {
// clicked outside - close popup
close();
return false;
}
}
return false;
}
}