key processing in menu

This commit is contained in:
Vadim Lopatin 2014-04-15 17:15:29 +04:00
parent 03621c071d
commit e9085c774b
6 changed files with 168 additions and 5 deletions

View File

@ -177,12 +177,44 @@ class Window {
_mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton);
}
protected Widget _focusedWidget;
/// returns current focused widget
@property Widget focusedWidget() {
if (!isChild(_focusedWidget))
_focusedWidget = null;
return _focusedWidget;
}
/// change focus to widget
Widget setFocus(Widget newFocus) {
if (!isChild(_focusedWidget))
_focusedWidget = null;
Widget oldFocus = _focusedWidget;
if (oldFocus is newFocus)
return oldFocus;
if (oldFocus !is null)
oldFocus.resetState(State.Focused);
if (newFocus is null || isChild(newFocus)) {
_focusedWidget = newFocus;
if (_focusedWidget !is null) {
Log.d("new focus: ", _focusedWidget.id);
_focusedWidget.setState(State.Focused);
}
}
return _focusedWidget;
}
protected bool dispatchKeyEvent(Widget root, KeyEvent event) {
return false;
}
/// dispatch keyboard event
bool dispatchKeyEvent(KeyEvent event) {
Widget focus = focusedWidget;
if (focus !is null) {
if (focus.onKeyEvent(event))
return true; // processed by focused widget
}
return false;
}

View File

@ -445,7 +445,7 @@ class Win32Window : Window {
} else if (action == KeyAction.Text && character != 0) {
dchar[] text;
text ~= character;
event = new KeyEvent(action, 0, _keyFlags, text);
event = new KeyEvent(action, 0, _keyFlags, cast(dstring)text);
}
bool res = false;
if (event !is null) {
@ -746,7 +746,7 @@ LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_KEYUP:
if (window !is null) {
int repeatCount = lParam & 0xFFFF;
if (window.onKey(message == WM_KEYDOWN ? KeyAction.KeyDown : KeyAction.KeyDown, wParam, repeatCount))
if (window.onKey(message == WM_KEYDOWN ? KeyAction.KeyDown : KeyAction.KeyUp, wParam, repeatCount))
return 0; // processed
return 0;
}

View File

@ -134,6 +134,7 @@ class ImageButton : ImageWidget {
super(ID);
styleId = "BUTTON";
_drawableId = drawableId;
focusable = true;
trackHover = true;
}
}
@ -146,6 +147,7 @@ class Button : Widget {
this(string ID = null) {
super(ID);
styleId = "BUTTON";
focusable = true;
trackHover = true;
}

View File

@ -161,6 +161,7 @@ class ListWidget : WidgetGroup, OnScrollHandler {
this(string ID = null, Orientation orientation = Orientation.Vertical) {
super(ID);
_orientation = orientation;
focusable = true;
_hoverItemIndex = -1;
_selectedItemIndex = -1;
_scrollbar = new ScrollBar("listscroll", orientation);
@ -469,6 +470,48 @@ class ListWidget : WidgetGroup, OnScrollHandler {
}
}
/// list navigation using keys
override bool onKeyEvent(KeyEvent event) {
if (itemCount == 0)
return false;
int navigationDelta = 0;
if (event.action == KeyAction.KeyDown) {
if (orientation == Orientation.Vertical) {
if (event.keyCode == KeyCode.DOWN)
navigationDelta = 1;
else if (event.keyCode == KeyCode.UP)
navigationDelta = -1;
} else {
if (event.keyCode == KeyCode.RIGHT)
navigationDelta = 1;
else if (event.keyCode == KeyCode.LEFT)
navigationDelta = -1;
}
}
if (_selectedItemIndex != -1 && event.action == KeyAction.KeyUp && (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN)) {
itemClicked(_selectedItemIndex);
return true;
}
if (navigationDelta != 0) {
int p = _selectedItemIndex;
if (p < 0) {
if (navigationDelta < 0)
p = itemCount - 1;
else
p = 0;
} else {
p += navigationDelta;
if (p < 0)
p = itemCount - 1;
else if (p >= itemCount)
p = 0;
}
selectItem(p);
return true;
}
return false;
}
/// process mouse event; return true if event is processed by widget.
override bool onMouseEvent(MouseEvent event) {
//Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")");
@ -486,6 +529,8 @@ class ListWidget : WidgetGroup, OnScrollHandler {
} else {
scrollOffset.x = _scrollPosition;
}
if (event.action == MouseAction.ButtonDown && (event.flags & (MouseFlag.LButton || MouseFlag.RButton)))
setFocus();
for (int i = 0; i < itemCount; i++) {
Rect itemrc = _itemRects[i];
itemrc.left += rc.left - scrollOffset.x;

View File

@ -106,9 +106,10 @@ class MenuWidgetBase : ListWidget {
_openedPopup = null;
_openedMenu = null;
selectItem(-1);
window.setFocus(this);
}
protected void openSubmenu(MenuItemWidget itemWidget) {
protected void openSubmenu(MenuItemWidget itemWidget, bool selectFirstItem) {
if (_openedPopup !is null) {
_openedPopup.close();
}
@ -118,6 +119,9 @@ class MenuWidgetBase : ListWidget {
popup.flags = PopupFlags.CloseOnClickOutside;
_openedPopup = popup;
_openedMenu = popupMenu;
window.setFocus(popupMenu);
if (selectFirstItem)
_openedMenu.selectItem(0);
}
/// override to handle change of selection
@ -131,7 +135,7 @@ class MenuWidgetBase : ListWidget {
if (itemWidget !is null) {
if (itemWidget.item.isSubmenu()) {
if (_selectOnHover) {
openSubmenu(itemWidget);
openSubmenu(itemWidget, false);
}
} else {
// normal item
@ -161,6 +165,10 @@ class MenuWidgetBase : ListWidget {
}
}
@property MenuItemWidget selectedMenuItemWidget() {
return _selectedItemIndex >= 0 ? cast(MenuItemWidget)_adapter.itemWidget(_selectedItemIndex) : null;
}
/// override to handle mouse up on item
override protected void itemClicked(int index) {
MenuItemWidget itemWidget = index >= 0 ? cast(MenuItemWidget)_adapter.itemWidget(index) : null;
@ -175,7 +183,7 @@ class MenuWidgetBase : ListWidget {
selectItem(-1);
selectOnHover = false;
} else {
openSubmenu(itemWidget);
openSubmenu(itemWidget, false);
selectOnHover = true;
}
} else {
@ -184,6 +192,46 @@ class MenuWidgetBase : ListWidget {
}
}
}
/// returns popup this menu is located in
@property PopupWidget thisPopup() {
return cast(PopupWidget)parent;
}
/// list navigation using keys
override bool onKeyEvent(KeyEvent event) {
// TODO:
if (orientation == Orientation.Horizontal) {
if (event.action == KeyAction.KeyDown) {
}
} else {
if (event.action == KeyAction.KeyDown) {
if (event.keyCode == KeyCode.LEFT) {
if (_parentMenu !is null && _parentMenu.orientation == Orientation.Vertical) {
if (thisPopup !is null) {
// back to parent menu on Left key
thisPopup.close();
return true;
}
}
return true;
} else if (event.keyCode == KeyCode.RIGHT) {
MenuItemWidget thisItem = selectedMenuItemWidget();
if (thisItem !is null && thisItem.item.isSubmenu) {
openSubmenu(thisItem, true);
return true;
}
return true;
}
} else if (event.action == KeyAction.KeyUp) {
if (event.keyCode == KeyCode.LEFT || event.keyCode == KeyCode.RIGHT) {
return true;
}
}
}
return super.onKeyEvent(event);
}
}
/// main menu (horizontal)

View File

@ -307,11 +307,42 @@ class Widget {
return _pos.isPointInside(x, y);
}
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));
}
/// sets focus to this widget, returns previously focused widget
Widget setFocus() {
if (window is null)
return null;
if (!_focusable)
return window.focusedWidget;
return window.setFocus(this);
}
// =======================================================
// Events
/// process key event, return true if event is processed.
bool onKeyEvent(KeyEvent event) {
if (_onClickListener !is null) {
// support onClick event initiated by Space or Return keys
if (event.action == KeyAction.KeyDown) {
if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) {
setState(State.Pressed);
return true;
}
}
if (event.action == KeyAction.KeyUp) {
if (event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN) {
resetState(State.Pressed);
_onClickListener(this);
return true;
}
}
}
return false;
}
@ -322,6 +353,8 @@ class Widget {
if (_onClickListener !is null) {
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
setState(State.Pressed);
if (focusable)
setFocus();
return true;
}
if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
@ -339,6 +372,9 @@ class Widget {
return true;
}
}
if (focusable && event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
setFocus();
}
if (trackHover) {
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
if ((state & State.Hovered)) {