From c58c46c96cf490a1d585a28560dda138479f00be Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Mon, 7 Sep 2020 06:50:34 +0300 Subject: LookupWidget: Improved keyboard navigation --- src/ui/listwidget.c | 18 +++++++++++++++--- src/ui/listwidget.h | 2 ++ src/ui/lookupwidget.c | 38 ++++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 19 deletions(-) (limited to 'src/ui') diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 06689023..3e7203b8 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c @@ -179,8 +179,20 @@ void scrollOffset_ListWidget(iListWidget *d, int offset) { } } -static int visCount_ListWidget_(const iListWidget *d) { - return iMin(height_Rect(innerBounds_Widget(constAs_Widget(d))) / d->itemHeight + 2, +void scrollToItem_ListWidget(iListWidget *d, size_t index) { + const iRect rect = innerBounds_Widget(as_Widget(d)); + int yTop = d->itemHeight * index - d->scrollY; + int yBottom = yTop + d->itemHeight; + if (yBottom > height_Rect(rect)) { + scrollOffset_ListWidget(d, yBottom - height_Rect(rect)); + } + else if (yTop < 0) { + scrollOffset_ListWidget(d, yTop); + } +} + +int visCount_ListWidget(const iListWidget *d) { + return iMin(height_Rect(innerBounds_Widget(constAs_Widget(d))) / d->itemHeight, (int) size_PtrArray(&d->items)); } @@ -189,7 +201,7 @@ static iRanges visRange_ListWidget_(const iListWidget *d) { return (iRanges){ 0, 0 }; } iRanges vis = { d->scrollY / d->itemHeight, 0 }; - vis.end = iMin(size_PtrArray(&d->items), vis.start + visCount_ListWidget_(d)); + vis.end = iMin(size_PtrArray(&d->items), vis.start + visCount_ListWidget(d) + 1); return vis; } diff --git a/src/ui/listwidget.h b/src/ui/listwidget.h index 72b7dba4..29140c59 100644 --- a/src/ui/listwidget.h +++ b/src/ui/listwidget.h @@ -59,6 +59,7 @@ int itemHeight_ListWidget (const iListWidget *); int scrollPos_ListWidget (const iListWidget *); void setScrollPos_ListWidget (iListWidget *, int pos); +void scrollToItem_ListWidget (iListWidget *, size_t index); void scrollOffset_ListWidget (iListWidget *, int offset); void updateVisible_ListWidget (iListWidget *); void updateMouseHover_ListWidget (iListWidget *); @@ -67,6 +68,7 @@ iAnyObject *item_ListWidget (iListWidget *, size_t index); iAnyObject *hoverItem_ListWidget (iListWidget *); size_t numItems_ListWidget (const iListWidget *); +int visCount_ListWidget(const iListWidget *); size_t itemIndex_ListWidget(const iListWidget *, iInt2 pos); const iAnyObject *constItem_ListWidget (const iListWidget *, size_t index); const iAnyObject *constHoverItem_ListWidget (const iListWidget *); diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c index fbb5d365..c1c52708 100644 --- a/src/ui/lookupwidget.c +++ b/src/ui/lookupwidget.c @@ -372,9 +372,25 @@ static void setCursor_LookupWidget_(iLookupWidget *d, size_t index) { item->listItem.isSelected = iTrue; invalidateItem_ListWidget(d->list, d->cursor); } + scrollToItem_ListWidget(d->list, d->cursor); } } +static iBool moveCursor_LookupWidget_(iLookupWidget *d, int delta) { + const int dir = iSign(delta); + size_t cur = d->cursor; + size_t good = cur; + while (delta && ((dir < 0 && cur > 0) || (dir > 0 && cur < numItems_ListWidget(d->list) - 1))) { + cur += dir; + if (!item_LookupWidget_(d, cur)->listItem.isSeparator) { + delta -= dir; + good = cur; + } + } + setCursor_LookupWidget_(d, good); + return delta == 0; +} + static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { iWidget *w = as_Widget(d); const char *cmd = command_UserEvent(ev); @@ -431,29 +447,19 @@ static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { setFocus_Widget(url); return iTrue; case SDLK_UP: - for (;;) { - if (d->cursor == 0) { - setCursor_LookupWidget_(d, iInvalidPos); - setFocus_Widget(url); - break; - } - setCursor_LookupWidget_(d, d->cursor - 1); - if (!item_LookupWidget_(d, d->cursor)->listItem.isSeparator) { - break; - } + if (!moveCursor_LookupWidget_(d, -1)) { + setCursor_LookupWidget_(d, iInvalidPos); + setFocus_Widget(url); } return iTrue; case SDLK_DOWN: - while (d->cursor < numItems_ListWidget(d->list) - 1) { - setCursor_LookupWidget_(d, d->cursor + 1); - if (!item_LookupWidget_(d, d->cursor)->listItem.isSeparator) { - break; - } - } + moveCursor_LookupWidget_(d, +1); return iTrue; case SDLK_PAGEUP: + moveCursor_LookupWidget_(d, -visCount_ListWidget(d->list) + 1); return iTrue; case SDLK_PAGEDOWN: + moveCursor_LookupWidget_(d, visCount_ListWidget(d->list) - 1); return iTrue; case SDLK_HOME: setCursor_LookupWidget_(d, 1); -- cgit v1.2.3