FileDialog - move to file in list by typing first letters of its name - fix #312

This commit is contained in:
Vadim Lopatin 2016-10-21 09:44:27 +03:00
parent a112994a4f
commit a60b65a338
2 changed files with 92 additions and 0 deletions

View File

@ -212,6 +212,39 @@ class FileDialog : Dialog, CustomGridCellAdapter {
return openDirectory(_path, null);
}
protected void locateFileInList(dstring pattern) {
if (!pattern.length)
return;
int selection = _fileList.row;
if (selection < 0)
selection = 0;
int index = -1; // first matched item
string mask = pattern.toUTF8;
// search forward from current row to end of list
for(int i = selection; i < _entries.length; i++) {
string fname = baseName(_entries[i].name);
if (fname.startsWith(mask)) {
index = i;
break;
}
}
if (index < 0) {
// search from beginning of list to current position
for(int i = 0; i < selection && i < _entries.length; i++) {
string fname = baseName(_entries[i].name);
if (fname.startsWith(mask)) {
index = i;
break;
}
}
}
if (index >= 0) {
// move selection
_fileList.selectCell(1, index + 1);
window.update();
}
}
protected bool openDirectory(string dir, string selectedItemPath) {
dir = buildNormalizedPath(dir);
Log.d("FileDialog.openDirectory(", dir, ")");
@ -502,6 +535,12 @@ class FileDialog : Dialog, CustomGridCellAdapter {
_fileList.cellPopupMenu = &getCellPopupMenu;
_fileList.menuItemAction = &handleAction;
_fileList.keyEvent = delegate(Widget source, KeyEvent event) {
if (_shortcutHelper.onKeyEvent(event))
locateFileInList(_shortcutHelper.text);
return false;
};
rightPanel.addChild(_edPath);
rightPanel.addChild(_fileList);
rightPanel.addChild(fnlayout);
@ -530,6 +569,8 @@ class FileDialog : Dialog, CustomGridCellAdapter {
}
protected TextTypingShortcutHelper _shortcutHelper;
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) {
super.layout(rc);

View File

@ -1792,6 +1792,57 @@ class WidgetGroupDefaultDrawing : WidgetGroup {
}
}
/// helper for locating items in list, tree, table or other controls by typing their name
struct TextTypingShortcutHelper {
int timeoutMillis = 800; // expiration time for entered text; after timeout collected text will be cleared
private long _lastUpdateTimeStamp;
private dchar[] _text;
/// cancel text collection (next typed text will be collected from scratch)
void cancel() {
_text.length = 0;
_lastUpdateTimeStamp = 0;
}
/// returns collected text string - use it for lookup
@property dstring text() { return _text.dup; }
/// pass key event here; returns true if search text is updated and you can move selection using it
bool onKeyEvent(KeyEvent event) {
long ts = currentTimeMillis;
if (_lastUpdateTimeStamp && ts - _lastUpdateTimeStamp > timeoutMillis)
cancel();
if (event.action == KeyAction.Text) {
_text ~= event.text;
_lastUpdateTimeStamp = ts;
return _text.length > 0;
}
if (event.action == KeyAction.KeyDown || event.action == KeyAction.KeyUp) {
switch (event.keyCode) with (KeyCode) {
case LEFT:
case RIGHT:
case UP:
case DOWN:
case HOME:
case END:
case TAB:
case PAGEUP:
case PAGEDOWN:
case BACK:
cancel();
break;
default:
break;
}
}
return false;
}
/// cancel text typing on some mouse events, if necessary
void onMouseEvent(MouseEvent event) {
if (event.action == MouseAction.ButtonUp || event.action == MouseAction.ButtonDown)
cancel();
}
}
enum ONE_SECOND = 10_000_000L;
/// Helper to handle animation progress