From 122777f789a68512593e4aa6da3ace3d0d8664ec Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 20 Jun 2024 12:21:57 -0700 Subject: [hci] Allow tab key to be used to cycle through UI elements Add support for wraparound scrolling and allow the tab key to be used to move forward through a list of elements, wrapping back around to the beginning of the list on overflow. This is mildly useful for a menu, and likely to be a strong user expectation for an interactive form. Signed-off-by: Michael Brown --- src/hci/jumpscroll.c | 75 +++++++++++++++++++++++++++---------------- src/hci/tui/menu_ui.c | 6 ++-- src/hci/tui/settings_ui.c | 2 +- src/include/ipxe/jumpscroll.h | 36 +++++++++++++++++++-- 4 files changed, 86 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/hci/jumpscroll.c b/src/hci/jumpscroll.c index dd6bcac..641f781 100644 --- a/src/hci/jumpscroll.c +++ b/src/hci/jumpscroll.c @@ -39,7 +39,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v key Key pressed by user * @ret move Scroller movement, or zero */ -int jump_scroll_key ( struct jump_scroller *scroll, int key ) { +unsigned int jump_scroll_key ( struct jump_scroller *scroll, int key ) { + unsigned int flags = 0; + int16_t delta; /* Sanity checks */ assert ( scroll->rows != 0 ); @@ -52,20 +54,32 @@ int jump_scroll_key ( struct jump_scroller *scroll, int key ) { /* Handle key, if applicable */ switch ( key ) { case KEY_UP: - return -1; + delta = -1; + break; + case TAB: + flags = SCROLL_WRAP; + /* fall through */ case KEY_DOWN: - return +1; + delta = +1; + break; case KEY_PPAGE: - return ( scroll->first - scroll->current - 1 ); + delta = ( scroll->first - scroll->current - 1 ); + break; case KEY_NPAGE: - return ( scroll->first - scroll->current + scroll->rows ); + delta = ( scroll->first - scroll->current + scroll->rows ); + break; case KEY_HOME: - return -( scroll->count ); + delta = -( scroll->count ); + break; case KEY_END: - return +( scroll->count ); + delta = +( scroll->count ); + break; default: - return 0; + delta = 0; + break; } + + return ( SCROLL ( delta ) | flags ); } /** @@ -75,7 +89,9 @@ int jump_scroll_key ( struct jump_scroller *scroll, int key ) { * @v move Scroller movement * @ret move Continuing scroller movement (if applicable) */ -int jump_scroll_move ( struct jump_scroller *scroll, int move ) { +unsigned int jump_scroll_move ( struct jump_scroller *scroll, + unsigned int move ) { + int16_t delta = SCROLL_DELTA ( move ); int current = scroll->current; int last = ( scroll->count - 1 ); @@ -84,30 +100,35 @@ int jump_scroll_move ( struct jump_scroller *scroll, int move ) { assert ( scroll->count != 0 ); /* Move to the new current item */ - current += move; + current += delta; + + /* Default to continuing movement in the same direction */ + delta = ( ( delta >= 0 ) ? +1 : -1 ); /* Check for start/end of list */ - if ( current < 0 ) { - /* We have attempted to move before the start of the - * list. Move to the start of the list and continue - * moving forwards (if applicable). - */ - scroll->current = 0; - return +1; - } else if ( current > last ) { - /* We have attempted to move after the end of the - * list. Move to the end of the list and continue - * moving backwards (if applicable). + if ( ( current >= 0 ) && ( current <= last ) ) { + /* We are still within the list. Update the current + * item and continue moving in the same direction (if + * applicable). */ - scroll->current = last; - return -1; + scroll->current = current; } else { - /* Update the current item and continue moving in the - * same direction (if applicable). + /* We have attempted to move outside the list. If we + * are wrapping around, then continue in the same + * direction (if applicable), otherwise reverse. */ - scroll->current = current; - return ( ( move > 0 ) ? +1 : -1 ); + if ( ! ( move & SCROLL_WRAP ) ) + delta = -delta; + + /* Move to start or end of list as appropriate */ + if ( delta >= 0 ) { + scroll->current = 0; + } else { + scroll->current = last; + } } + + return ( SCROLL ( delta ) | ( move & SCROLL_FLAGS ) ); } /** diff --git a/src/hci/tui/menu_ui.c b/src/hci/tui/menu_ui.c index cac61a7..067e2d8 100644 --- a/src/hci/tui/menu_ui.c +++ b/src/hci/tui/menu_ui.c @@ -175,9 +175,9 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { struct menu_item *item; unsigned long timeout; unsigned int previous; + unsigned int move; int key; int i; - int move; int chosen = 0; int rc = 0; @@ -192,7 +192,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { ui->timeout -= timeout; /* Get key */ - move = 0; + move = SCROLL_NONE; key = getkey ( timeout ); if ( key < 0 ) { /* Choose default if we finally time out */ @@ -228,7 +228,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { if ( item->name ) { chosen = 1; } else { - move = +1; + move = SCROLL_DOWN; } } break; diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c index 10c9423..bc08750 100644 --- a/src/hci/tui/settings_ui.c +++ b/src/hci/tui/settings_ui.c @@ -381,8 +381,8 @@ static void select_settings ( struct settings_ui *ui, static int main_loop ( struct settings *settings ) { struct settings_ui ui; unsigned int previous; + unsigned int move; int redraw = 1; - int move; int key; int rc; diff --git a/src/include/ipxe/jumpscroll.h b/src/include/ipxe/jumpscroll.h index 7a5b111..470f08e 100644 --- a/src/include/ipxe/jumpscroll.h +++ b/src/include/ipxe/jumpscroll.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + /** A jump scroller */ struct jump_scroller { /** Maximum number of visible rows */ @@ -22,6 +24,35 @@ struct jump_scroller { }; /** + * Construct scroll movement + * + * @v delta Change in scroller position + * @ret move Scroll movement + */ +#define SCROLL( delta ) ( ( unsigned int ) ( uint16_t ) ( int16_t ) (delta) ) + +/** + * Extract change in scroller position + * + * @v move Scroll movement + * @ret delta Change in scroller position + */ +#define SCROLL_DELTA( scroll ) ( ( int16_t ) ( (scroll) & 0x0000ffffUL ) ) + +/** Scroll movement flags */ +#define SCROLL_FLAGS 0xffff0000UL +#define SCROLL_WRAP 0x80000000UL /**< Wrap around scrolling */ + +/** Do not scroll */ +#define SCROLL_NONE SCROLL ( 0 ) + +/** Scroll up by one line */ +#define SCROLL_UP SCROLL ( -1 ) + +/** Scroll down by one line */ +#define SCROLL_DOWN SCROLL ( +1 ) + +/** * Check if jump scroller is currently on first page * * @v scroll Jump scroller @@ -43,8 +74,9 @@ static inline int jump_scroll_is_last ( struct jump_scroller *scroll ) { return ( ( scroll->first + scroll->rows ) >= scroll->count ); } -extern int jump_scroll_key ( struct jump_scroller *scroll, int key ); -extern int jump_scroll_move ( struct jump_scroller *scroll, int move ); +extern unsigned int jump_scroll_key ( struct jump_scroller *scroll, int key ); +extern unsigned int jump_scroll_move ( struct jump_scroller *scroll, + unsigned int move ); extern int jump_scroll ( struct jump_scroller *scroll ); #endif /* _IPXE_JUMPSCROLL_H */ -- cgit v1.1