]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[hci] Allow tab key to be used to cycle through UI elements
authorMichael Brown <mcb30@ipxe.org>
Thu, 20 Jun 2024 19:21:57 +0000 (12:21 -0700)
committerMichael Brown <mcb30@ipxe.org>
Thu, 20 Jun 2024 20:14:35 +0000 (13:14 -0700)
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>
src/hci/jumpscroll.c
src/hci/tui/menu_ui.c
src/hci/tui/settings_ui.c
src/include/ipxe/jumpscroll.h

index dd6bcac2b27a8af80646bd293780af11575c8171..641f781a010b9f682f59b7a7abe0215f989f9129 100644 (file)
@@ -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 ) );
 }
 
 /**
index cac61a7da6ed98704f44bfffa3e01075acc801ba..067e2d8ca5fc8d8329d2b61e3be340d26d1f9016 100644 (file)
@@ -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;
index 10c942321920cba7076079efedc295aaec4f3a90..bc08750a05ec452be6a7914d5bfbff20611939b0 100644 (file)
@@ -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;
 
index 7a5b111c16494ee1572cfc75b22d00399dd0e9bc..470f08e7183a30e085e59fc45ab0a6a43da36b63 100644 (file)
@@ -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 */
@@ -21,6 +23,35 @@ struct jump_scroller {
        unsigned int first;
 };
 
+/**
+ * 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
  *
@@ -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 */