focus movement using Tab/Shift+Tab)

This commit is contained in:
Vadim Lopatin 2014-04-25 14:20:04 +04:00
parent ec27010c86
commit 41aca2c44f
3 changed files with 90 additions and 13 deletions

View File

@ -857,6 +857,9 @@ class EditWidgetBase : WidgetGroup, EditableContentListener {
new Action(EditorActions.DocumentEnd, KeyCode.END, KeyFlag.Control),
new Action(EditorActions.SelectDocumentEnd, KeyCode.END, KeyFlag.Control | KeyFlag.Shift),
new Action(EditorActions.ScrollLineUp, KeyCode.UP, KeyFlag.Control),
new Action(EditorActions.ScrollLineDown, KeyCode.DOWN, KeyFlag.Control),
new Action(EditorActions.InsertNewLine, KeyCode.RETURN, 0),
new Action(EditorActions.InsertNewLine, KeyCode.RETURN, KeyFlag.Shift),
new Action(EditorActions.PrependNewLine, KeyCode.RETURN, KeyFlag.Control),

View File

@ -415,6 +415,7 @@ class TabHost : FrameLayout, TabHandler {
assert(widget.id !is null, "ID for tab host page is mandatory");
assert(_children.indexOf(id) == -1, "duplicate ID for tab host page");
_tabControl.addTab(widget.id, label, iconId, enableCloseButton);
widget.focusGroup = true; // doesn't allow move focus outside of tab content
addChild(widget);
return this;
}

View File

@ -482,41 +482,114 @@ class Widget {
return p;
}
private void findFocusableChildren(ref Widget[] results, Widget widgetToExclude) {
private static class TabOrderInfo {
Widget widget;
uint tabOrder;
uint childOrder;
Rect rect;
this(Widget widget, Rect rect) {
this.widget = widget;
this.tabOrder = widget.thisOrParentTabOrder();
this.rect = widget.pos;
}
override int opCmp(Object obj) {
TabOrderInfo v = cast(TabOrderInfo)obj;
if (tabOrder != 0 && v.tabOrder !=0) {
if (tabOrder < v.tabOrder)
return -1;
if (tabOrder > v.tabOrder)
return 1;
}
// place items with tabOrder 0 after items with tabOrder non-0
if (tabOrder != 0)
return -1;
if (v.tabOrder != 0)
return 1;
if (childOrder < v.childOrder)
return -1;
if (childOrder > v.childOrder)
return 1;
return 0;
}
}
private void findFocusableChildren(ref TabOrderInfo[] results, Rect clipRect) {
if (visibility != Visibility.Visible)
return;
if (widgetToExclude is this)
return; // doesn't include
Rect rc = _pos;
applyMargins(rc);
applyPadding(rc);
if (!rc.intersects(clipRect))
return; // out of clip rectangle
if (focusable) {
results ~= this;
TabOrderInfo item = new TabOrderInfo(this, rc);
results ~= item;
return;
}
rc.intersect(clipRect);
for (int i = 0; i < childCount(); i++) {
child(i).findFocusableChildren(results, widgetToExclude);
child(i).findFocusableChildren(results, rc);
}
}
/// find all focusables belonging to the same focusGroup as this widget (does not include current widget).
/// usually to be called for focused widget to get possible alternatives to navigate to
private Widget[] findFocusables() {
Widget[] result;
private TabOrderInfo[] findFocusables() {
TabOrderInfo[] result;
Widget group = focusGroupWidget();
group.findFocusableChildren(result, this);
group.findFocusableChildren(result, group.pos);
for (ushort i = 0; i < result.length; i++)
result[i].childOrder = i + 1;
sort(result);
return result;
}
protected ushort _tabOrder;
/// tab order - hint for focus movement using Tab/Shift+Tab
@property ushort tabOrder() { return _tabOrder; }
@property Widget tabOrder(ushort tabOrder) { _tabOrder = tabOrder; return this; }
private int thisOrParentTabOrder() {
if (_tabOrder)
return _tabOrder;
if (!parent)
return 0;
return parent.thisOrParentTabOrder;
}
/// call on focused widget, to find best
private Widget findNextFocusWidget(FocusMovement direction) {
if (direction == FocusMovement.None)
return this;
Widget[] focusables = findFocusables();
TabOrderInfo[] focusables = findFocusables();
if (!focusables.length)
return null;
int myIndex = -1;
for (int i = 0; i < focusables.length; i++) {
if (focusables[i].widget is this) {
myIndex = i;
break;
}
}
if (myIndex == -1)
return null; // not found myself
if (focusables.length == 1)
return focusables[0]; // single option - use it
Rect currentRect = pos;
// TODO:
return focusables[0];
return focusables[0].widget; // single option - use it
if (direction == FocusMovement.Next) {
// move forward
int index = myIndex + 1;
if (index >= focusables.length)
index = 0;
return focusables[index].widget;
} else if (direction == FocusMovement.Previous) {
// move back
int index = myIndex - 1;
if (index < 0)
index = cast(int)focusables.length - 1;
return focusables[index].widget;
} else {
// Left, Right, Up, Down
return focusables[0].widget;
}
}
bool handleMoveFocusUsingKeys(KeyEvent event) {