mirror of https://github.com/buggins/dlangui.git
Tab control: support navigation between tabs with Ctrl+Tab / Ctrl+Shift+Tab
This commit is contained in:
parent
de9bdf2965
commit
4c1615ffa6
|
@ -276,6 +276,7 @@ class Window {
|
|||
return _focusedWidget;
|
||||
}
|
||||
|
||||
/// dispatch key event to widgets which have wantsKeyTracking == true
|
||||
protected bool dispatchKeyEvent(Widget root, KeyEvent event) {
|
||||
if (root.visibility != Visibility.Visible)
|
||||
return false;
|
||||
|
@ -313,9 +314,12 @@ class Window {
|
|||
return res;
|
||||
}
|
||||
Widget focus = focusedWidget;
|
||||
if (focus !is null) {
|
||||
while (focus) {
|
||||
if (focus.onKeyEvent(event))
|
||||
return true; // processed by focused widget
|
||||
if (focus.focusGroup)
|
||||
break;
|
||||
focus = focus.parent;
|
||||
}
|
||||
if (_mainWidget) {
|
||||
if (dispatchKeyEvent(_mainWidget, event))
|
||||
|
|
|
@ -30,8 +30,10 @@ interface TabHandler {
|
|||
void onTabChanged(string newActiveTabId, string previousTabId);
|
||||
}
|
||||
|
||||
|
||||
/// tab item metadata
|
||||
class TabItem {
|
||||
private static long _lastAccessCounter;
|
||||
private string _iconRes;
|
||||
private string _id;
|
||||
private UIString _label;
|
||||
|
@ -45,7 +47,7 @@ class TabItem {
|
|||
_id = id;
|
||||
_label = labelRes;
|
||||
_iconRes = iconRes;
|
||||
_lastAccessTs = std.datetime.Clock.currStdTime;
|
||||
_lastAccessTs = _lastAccessCounter++;
|
||||
}
|
||||
@property string iconId() const { return _iconRes; }
|
||||
@property string id() const { return _id; }
|
||||
|
@ -54,7 +56,9 @@ class TabItem {
|
|||
@property TabItem id(string id) { _id = id; return this; }
|
||||
@property long lastAccessTs() { return _lastAccessTs; }
|
||||
@property void lastAccessTs(long ts) { _lastAccessTs = ts; }
|
||||
void updateAccessTs() { _lastAccessTs = std.datetime.Clock.currStdTime; }
|
||||
void updateAccessTs() {
|
||||
_lastAccessTs = _lastAccessCounter++; //std.datetime.Clock.currStdTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// tab item widget - to show tab header
|
||||
|
@ -123,6 +127,10 @@ class TabItemList {
|
|||
return null;
|
||||
return _list[index];
|
||||
}
|
||||
/// get item by index
|
||||
TabItem opIndex(int index) {
|
||||
return get(index);
|
||||
}
|
||||
/// get item by id
|
||||
TabItem get(string id) {
|
||||
int idx = indexById(id);
|
||||
|
@ -130,6 +138,10 @@ class TabItemList {
|
|||
return null;
|
||||
return _list[idx];
|
||||
}
|
||||
/// get item by id
|
||||
TabItem opIndex(string id) {
|
||||
return get(id);
|
||||
}
|
||||
@property int length() const { return _len; }
|
||||
/// append new item
|
||||
TabItemList add(TabItem item) {
|
||||
|
@ -215,6 +227,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
static bool accessTimeComparator(TabItemWidget a, TabItemWidget b) {
|
||||
return (a.tabItem.lastAccessTs > b.tabItem.lastAccessTs);
|
||||
}
|
||||
|
||||
protected TabItemWidget[] sortedItems() {
|
||||
_sortedItems.length = _items.length;
|
||||
for (int i = 0; i < _items.length; i++)
|
||||
|
@ -222,6 +235,27 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
std.algorithm.sort!(accessTimeComparator)(_sortedItems);
|
||||
return _sortedItems;
|
||||
}
|
||||
|
||||
/// find next or previous tab index, based on access time
|
||||
int getNextItemIndex(int direction) {
|
||||
if (_items.length == 0)
|
||||
return -1;
|
||||
if (_items.length == 1)
|
||||
return 0;
|
||||
TabItemWidget[] items = sortedItems();
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
if (items[i].id == _selectedTabId) {
|
||||
int next = i + direction;
|
||||
if (next < 0)
|
||||
next = cast(int)(items.length - 1);
|
||||
if (next >= items.length)
|
||||
next = 0;
|
||||
return _items.indexById(items[next].id);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// remove tab
|
||||
TabControl removeTab(string id) {
|
||||
int index = _items.indexById(id);
|
||||
|
@ -261,7 +295,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
string id = source.id;
|
||||
int index = tabIndex(id);
|
||||
if (index >= 0) {
|
||||
selectTab(index);
|
||||
selectTab(index, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -341,7 +375,13 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
|
||||
protected string _selectedTabId;
|
||||
|
||||
void selectTab(int index) {
|
||||
void updateAccessTs() {
|
||||
int index = _items.indexById(_selectedTabId);
|
||||
if (index >= 0)
|
||||
_items[index].updateAccessTs();
|
||||
}
|
||||
|
||||
void selectTab(int index, bool updateAccess) {
|
||||
if (_children.get(index + 1).compareId(_selectedTabId))
|
||||
return; // already selected
|
||||
string previousSelectedTab = _selectedTabId;
|
||||
|
@ -349,6 +389,8 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
if (index == i - 1) {
|
||||
_children.get(i).state = State.Selected;
|
||||
_selectedTabId = _children.get(i).id;
|
||||
if (updateAccess)
|
||||
updateAccessTs();
|
||||
} else {
|
||||
_children.get(i).state = State.Normal;
|
||||
}
|
||||
|
@ -356,6 +398,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
if (onTabChangedListener.assigned)
|
||||
onTabChangedListener(_selectedTabId, previousSelectedTab);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// container for widgets controlled by TabControl
|
||||
|
@ -411,7 +454,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
|
||||
//widget.focusGroup = true; // doesn't allow move focus outside of tab content
|
||||
addChild(widget);
|
||||
return this;
|
||||
}
|
||||
|
@ -425,10 +468,10 @@ class TabHost : FrameLayout, TabHandler {
|
|||
return this;
|
||||
}
|
||||
/// select tab
|
||||
void selectTab(string ID) {
|
||||
void selectTab(string ID, bool updateAccess) {
|
||||
int index = _tabControl.tabIndex(ID);
|
||||
if (index != -1) {
|
||||
_tabControl.selectTab(index);
|
||||
_tabControl.selectTab(index, updateAccess);
|
||||
}
|
||||
}
|
||||
// /// request relayout of widget and its children
|
||||
|
@ -463,6 +506,7 @@ class TabWidget : VerticalLayout, TabHandler {
|
|||
styleId = STYLE_TAB_WIDGET;
|
||||
addChild(_tabControl);
|
||||
addChild(_tabHost);
|
||||
focusGroup = true;
|
||||
}
|
||||
|
||||
/// signal of tab change (e.g. by clicking on tab header)
|
||||
|
@ -494,8 +538,13 @@ class TabWidget : VerticalLayout, TabHandler {
|
|||
}
|
||||
|
||||
/// select tab
|
||||
void selectTab(string ID) {
|
||||
_tabHost.selectTab(ID);
|
||||
void selectTab(string ID, bool updateAccess = true) {
|
||||
_tabHost.selectTab(ID, updateAccess);
|
||||
}
|
||||
|
||||
/// select tab
|
||||
void selectTab(int index, bool updateAccess = true) {
|
||||
_tabControl.selectTab(index, updateAccess);
|
||||
}
|
||||
|
||||
/// returns tab item by id (null if index out of range)
|
||||
|
@ -510,4 +559,30 @@ class TabWidget : VerticalLayout, TabHandler {
|
|||
int tabIndex(string id) {
|
||||
return _tabControl.tabIndex(id);
|
||||
}
|
||||
|
||||
private bool _tabNavigationInProgress;
|
||||
|
||||
/// process key event, return true if event is processed.
|
||||
override bool onKeyEvent(KeyEvent event) {
|
||||
if (_tabNavigationInProgress) {
|
||||
if (event.action == KeyAction.KeyDown || event.action == KeyAction.KeyUp) {
|
||||
if (!(event.flags & KeyFlag.Control)) {
|
||||
_tabNavigationInProgress = false;
|
||||
_tabControl.updateAccessTs();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.action == KeyAction.KeyDown) {
|
||||
if (event.keyCode == KeyCode.TAB && (event.flags & KeyFlag.Control)) {
|
||||
// support Ctrl+Tab and Ctrl+Shift+Tab for navigation
|
||||
_tabNavigationInProgress = true;
|
||||
int direction = (event.flags & KeyFlag.Shift) ? - 1 : 1;
|
||||
int index = _tabControl.getNextItemIndex(direction);
|
||||
if (index >= 0)
|
||||
selectTab(index, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onKeyEvent(event);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue