From 9f91359c2ebd574ff1698ec944f6e84603e49e48 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 21 Jul 2004 14:28:57 +0000 Subject: Allow user to select ListWidget entries by typing them (see FR #922921) svn-id: r14295 --- gui/ListWidget.cpp | 98 ++++++++++++++++++++++++++++++++++++++++-------------- gui/ListWidget.h | 4 +++ 2 files changed, 77 insertions(+), 25 deletions(-) (limited to 'gui') diff --git a/gui/ListWidget.cpp b/gui/ListWidget.cpp index aba5abcd23..4ef2d6f56b 100644 --- a/gui/ListWidget.cpp +++ b/gui/ListWidget.cpp @@ -41,6 +41,8 @@ ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h) _caretVisible = false; _caretTime = 0; + + _quickSelectTime = 0; // FIXME: This flag should come from widget definition _editable = true; @@ -125,48 +127,94 @@ void ListWidget::handleMouseWheel(int x, int y, int direction) { _scrollBar->handleMouseWheel(x, y, direction); } + +static int matchingCharsIgnoringCase(const char *x, const char *y, bool &stop) { + int match = 0; + while (*x && *y && toupper(*x) == toupper(*y)) { + ++x; + ++y; + ++match; + } + stop = !*y || (*x && (toupper(*x) >= toupper(*y))); + return match; +} + bool ListWidget::handleKeyDown(uint16 ascii, int keycode, int modifiers) { bool handled = true; bool dirty = false; int oldSelectedItem = _selectedItem; - if (_editMode) { + if (!_editMode && isprint((char)ascii)) { + // Quick selection mode: Go to first list item starting with this key + // (or a substring accumulated from the last couple key presses). + // Only works in a useful fashion if the list entries are sorted. + // TODO: Maybe this should be off by default, and instead we add a + // method "enableQuickSelect()" or so ? + uint32 time = g_system->get_msecs(); + if (_quickSelectTime < time) { + _quickSelectStr = (char)ascii; + } else { + _quickSelectStr += (char)ascii; + } + _quickSelectTime = time + 300; // TODO: Turn this into a proper constant (kQuickSelectDelay ?) + + + // FIXME: This is bad slow code (it scans the list linearly each time a + // key is pressed); it could be much faster. Only of importance if we have + // quite big lists to deal with -- so for now we can live with this lazy + // implementation :-) + int newSelectedItem = 0; + int bestMatch = 0; + bool stop; + for (StringList::const_iterator i = _list.begin(); i != _list.end(); ++i) { + const int match = matchingCharsIgnoringCase(i->c_str(), _quickSelectStr.c_str(), stop); + if (match > bestMatch || stop) { + _selectedItem = newSelectedItem; + bestMatch = match; + if (stop) + break; + } + newSelectedItem++; + } + + scrollToCurrent(); + } else if (_editMode) { if (_caretVisible) drawCaret(true); switch (keycode) { - case '\n': // enter/return - case '\r': - // enter, confirm edit and exit editmode - _editMode = false; - dirty = true; - sendCommand(kListItemActivatedCmd, _selectedItem); - break; - case 27: // escape - // ESC, abort edit and exit editmode - _editMode = false; - dirty = true; - _list[_selectedItem] = _backupString; - break; - case 8: // backspace - _list[_selectedItem].deleteLastChar(); + case '\n': // enter/return + case '\r': + // confirm edit and exit editmode + _editMode = false; + dirty = true; + sendCommand(kListItemActivatedCmd, _selectedItem); + break; + case 27: // escape + // abort edit and exit editmode + _editMode = false; + dirty = true; + _list[_selectedItem] = _backupString; + break; + case 8: // backspace + _list[_selectedItem].deleteLastChar(); + dirty = true; + break; + default: + if (isprint((char)ascii)) { + _list[_selectedItem] += (char)ascii; dirty = true; - break; - default: - if (isprint((char)ascii)) { - _list[_selectedItem] += (char)ascii; - dirty = true; - } else { - handled = false; - } + } else { + handled = false; + } } } else { // not editmode switch (keycode) { - case '\n': // enter + case '\n': // enter/return case '\r': if (_selectedItem >= 0) { // override continuous enter keydown diff --git a/gui/ListWidget.h b/gui/ListWidget.h index 5a7827c57f..f2e9092660 100644 --- a/gui/ListWidget.h +++ b/gui/ListWidget.h @@ -56,8 +56,12 @@ protected: ScrollBarWidget *_scrollBar; int _currentKeyDown; String _backupString; + bool _caretVisible; uint32 _caretTime; + + String _quickSelectStr; + uint32 _quickSelectTime; public: ListWidget(GuiObject *boss, int x, int y, int w, int h); virtual ~ListWidget(); -- cgit v1.2.3