aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2024-06-20 12:21:57 -0700
committerMichael Brown <mcb30@ipxe.org>2024-06-20 13:14:35 -0700
commit122777f789a68512593e4aa6da3ace3d0d8664ec (patch)
tree25e8fc721b355c45e6e10d53f9866e32369f05b2
parent76e0933d781474acf52000cba0afaebe32361667 (diff)
downloadipxe-122777f789a68512593e4aa6da3ace3d0d8664ec.zip
ipxe-122777f789a68512593e4aa6da3ace3d0d8664ec.tar.gz
ipxe-122777f789a68512593e4aa6da3ace3d0d8664ec.tar.bz2
[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 <mcb30@ipxe.org>
-rw-r--r--src/hci/jumpscroll.c75
-rw-r--r--src/hci/tui/menu_ui.c6
-rw-r--r--src/hci/tui/settings_ui.c2
-rw-r--r--src/include/ipxe/jumpscroll.h36
4 files changed, 86 insertions, 33 deletions
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 <stdint.h>
+
/** 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 */