mirror of https://github.com/buggins/dlangui.git
FileDialog - move to file in list by typing first letters of its name - fix #312
This commit is contained in:
parent
a112994a4f
commit
a60b65a338
|
@ -212,6 +212,39 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
||||||
return openDirectory(_path, null);
|
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) {
|
protected bool openDirectory(string dir, string selectedItemPath) {
|
||||||
dir = buildNormalizedPath(dir);
|
dir = buildNormalizedPath(dir);
|
||||||
Log.d("FileDialog.openDirectory(", dir, ")");
|
Log.d("FileDialog.openDirectory(", dir, ")");
|
||||||
|
@ -502,6 +535,12 @@ class FileDialog : Dialog, CustomGridCellAdapter {
|
||||||
_fileList.cellPopupMenu = &getCellPopupMenu;
|
_fileList.cellPopupMenu = &getCellPopupMenu;
|
||||||
_fileList.menuItemAction = &handleAction;
|
_fileList.menuItemAction = &handleAction;
|
||||||
|
|
||||||
|
_fileList.keyEvent = delegate(Widget source, KeyEvent event) {
|
||||||
|
if (_shortcutHelper.onKeyEvent(event))
|
||||||
|
locateFileInList(_shortcutHelper.text);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
rightPanel.addChild(_edPath);
|
rightPanel.addChild(_edPath);
|
||||||
rightPanel.addChild(_fileList);
|
rightPanel.addChild(_fileList);
|
||||||
rightPanel.addChild(fnlayout);
|
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).
|
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
||||||
override void layout(Rect rc) {
|
override void layout(Rect rc) {
|
||||||
super.layout(rc);
|
super.layout(rc);
|
||||||
|
|
|
@ -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;
|
enum ONE_SECOND = 10_000_000L;
|
||||||
|
|
||||||
/// Helper to handle animation progress
|
/// Helper to handle animation progress
|
||||||
|
|
Loading…
Reference in New Issue