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.DocumentEnd, KeyCode.END, KeyFlag.Control),
new Action(EditorActions.SelectDocumentEnd, KeyCode.END, KeyFlag.Control | KeyFlag.Shift), 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, 0),
new Action(EditorActions.InsertNewLine, KeyCode.RETURN, KeyFlag.Shift), new Action(EditorActions.InsertNewLine, KeyCode.RETURN, KeyFlag.Shift),
new Action(EditorActions.PrependNewLine, KeyCode.RETURN, KeyFlag.Control), 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(widget.id !is null, "ID for tab host page is mandatory");
assert(_children.indexOf(id) == -1, "duplicate ID for tab host page"); assert(_children.indexOf(id) == -1, "duplicate ID for tab host page");
_tabControl.addTab(widget.id, label, iconId, enableCloseButton); _tabControl.addTab(widget.id, label, iconId, enableCloseButton);
widget.focusGroup = true; // doesn't allow move focus outside of tab content
addChild(widget); addChild(widget);
return this; return this;
} }

View File

@ -482,41 +482,114 @@ class Widget {
return p; 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) if (visibility != Visibility.Visible)
return; return;
if (widgetToExclude is this) Rect rc = _pos;
return; // doesn't include applyMargins(rc);
applyPadding(rc);
if (!rc.intersects(clipRect))
return; // out of clip rectangle
if (focusable) { if (focusable) {
results ~= this; TabOrderInfo item = new TabOrderInfo(this, rc);
results ~= item;
return; return;
} }
rc.intersect(clipRect);
for (int i = 0; i < childCount(); i++) { 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). /// 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 /// usually to be called for focused widget to get possible alternatives to navigate to
private Widget[] findFocusables() { private TabOrderInfo[] findFocusables() {
Widget[] result; TabOrderInfo[] result;
Widget group = focusGroupWidget(); 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; 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 /// call on focused widget, to find best
private Widget findNextFocusWidget(FocusMovement direction) { private Widget findNextFocusWidget(FocusMovement direction) {
if (direction == FocusMovement.None) if (direction == FocusMovement.None)
return this; return this;
Widget[] focusables = findFocusables(); TabOrderInfo[] focusables = findFocusables();
if (!focusables.length) if (!focusables.length)
return null; 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) if (focusables.length == 1)
return focusables[0]; // single option - use it return focusables[0].widget; // single option - use it
Rect currentRect = pos; if (direction == FocusMovement.Next) {
// TODO: // move forward
return focusables[0]; 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) { bool handleMoveFocusUsingKeys(KeyEvent event) {