[Settings] Enable jump scroll in config UI
authorGlenn Brown <glenn@myri.com>
Wed, 23 Jun 2010 20:18:34 +0000 (13:18 -0700)
committerStefan Hajnoczi <stefanha@gmail.com>
Thu, 24 Jun 2010 20:23:44 +0000 (21:23 +0100)
Implement jump scrolling with "..." displayed where the settings list
continues off-screen, because there are now too many settings to fit on
screen in the "config ..." text user interface.

Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
src/hci/tui/settings_ui.c

index 74ce6af..61ea3e4 100644 (file)
@@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define TITLE_ROW              1
 #define SETTINGS_LIST_ROW      3
 #define SETTINGS_LIST_COL      1
+#define SETTINGS_LIST_ROWS     16
 #define INFO_ROW               20
 #define ALERT_ROW              20
 #define INSTRUCTION_ROW                22
@@ -65,6 +66,8 @@ struct setting_row {
 struct setting_widget {
        /** Settings block */
        struct settings *settings;
+        /** Index of the first visible setting, for scrolling. */
+       unsigned int first_visible;
        /** Configuration setting */
        struct setting *setting;
        /** Screen row */
@@ -84,15 +87,13 @@ struct setting_widget {
 
 static void load_setting ( struct setting_widget *widget ) __nonnull;
 static int save_setting ( struct setting_widget *widget ) __nonnull;
-static void init_setting ( struct setting_widget *widget,
-                           struct settings *settings,
-                           struct setting *setting,
-                           unsigned int row, unsigned int col ) __nonnull;
+static void init_widget ( struct setting_widget *widget,
+                           struct settings *settings ) __nonnull;
 static void draw_setting ( struct setting_widget *widget ) __nonnull;
 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
-static void init_setting_index ( struct setting_widget *widget,
-                                 struct settings *settings,
-                                 unsigned int index ) __nonnull;
+static void select_setting ( struct setting_widget *widget,
+                            unsigned int index ) __nonnull;
+static void reveal ( struct setting_widget *widget, unsigned int n) __nonnull;
 static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
 static void valert ( const char *fmt, va_list args ) __nonnull;
@@ -135,28 +136,17 @@ static int save_setting ( struct setting_widget *widget ) {
 }
 
 /**
- * Initialise setting widget
+ * Initialise the scrolling setting widget, drawing initial display.
  *
  * @v widget           Setting widget
  * @v settings         Settings block
- * @v setting          Configuration setting
- * @v row              Screen row
- * @v col              Screen column
  */
-static void init_setting ( struct setting_widget *widget,
-                          struct settings *settings,
-                          struct setting *setting,
-                          unsigned int row, unsigned int col ) {
-
-       /* Initialise widget structure */
+static void init_widget ( struct setting_widget *widget,
+                         struct settings *settings ) {
        memset ( widget, 0, sizeof ( *widget ) );
        widget->settings = settings;
-       widget->setting = setting;
-       widget->row = row;
-       widget->col = col;
-
-       /* Read current setting value */
-       load_setting ( widget );
+       widget->first_visible = SETTINGS_LIST_ROWS;
+       reveal ( widget, 0 );
 }
 
 /**
@@ -212,19 +202,25 @@ static int edit_setting ( struct setting_widget *widget, int key ) {
 }
 
 /**
- * Initialise setting widget by index
+ * Select a setting for display updates, by index.
  *
  * @v widget           Setting widget
  * @v settings         Settings block
  * @v index            Index of setting with settings list
  */
-static void init_setting_index ( struct setting_widget *widget,
-                                struct settings *settings,
-                                unsigned int index ) {
+static void select_setting ( struct setting_widget *widget,
+                            unsigned int index ) {
        struct setting *all_settings = table_start ( SETTINGS );
+       unsigned int skip = offsetof ( struct setting_widget, setting );
+
+       /* Reset the widget, preserving static state. */
+       memset ( ( char * ) widget + skip, 0, sizeof ( *widget ) - skip );
+       widget->setting = &all_settings[index];
+       widget->row = SETTINGS_LIST_ROW + index - widget->first_visible;
+       widget->col = SETTINGS_LIST_COL;
 
-       init_setting ( widget, settings, &all_settings[index],
-                      ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
+       /* Read current setting value */
+       load_setting ( widget );
 }
 
 /**
@@ -334,22 +330,65 @@ static void draw_instruction_row ( int editing ) {
        }
 }
 
+/**
+ * Reveal a setting by index: Scroll the setting list to reveal the
+ * specified setting.
+ *
+ * @widget     The main loop's display widget.
+ * @n          The index of the setting to reveal.
+ */
+static void reveal ( struct setting_widget *widget, unsigned int n)
+{
+       unsigned int i;
+
+       /* Simply return if setting N is already on-screen. */
+       if ( n - widget->first_visible < SETTINGS_LIST_ROWS )
+               return;
+       
+       /* Jump scroll to make the specified setting visible. */
+       while ( widget->first_visible < n )
+               widget->first_visible += SETTINGS_LIST_ROWS;
+       while ( widget->first_visible > n )
+               widget->first_visible -= SETTINGS_LIST_ROWS;
+       
+       /* Draw elipses before and/or after the settings list to
+          represent any invisible settings. */
+       mvaddstr ( SETTINGS_LIST_ROW - 1,
+                  SETTINGS_LIST_COL + 1,
+                  widget->first_visible > 0 ? "..." : "   " );
+       mvaddstr ( SETTINGS_LIST_ROW + SETTINGS_LIST_ROWS,
+                  SETTINGS_LIST_COL + 1,
+                  ( widget->first_visible + SETTINGS_LIST_ROWS < NUM_SETTINGS
+                    ? "..."
+                    : "   " ) );
+       
+       /* Draw visible settings. */
+       for ( i = 0; i < SETTINGS_LIST_ROWS; i++ ) {
+               if ( widget->first_visible + i < NUM_SETTINGS ) {
+                       select_setting ( widget, widget->first_visible + i );
+                       draw_setting ( widget );
+               } else {
+                       clearmsg ( SETTINGS_LIST_ROW + i );
+               }
+       }
+
+       /* Set the widget to the current row, which will be redrawn
+          appropriately by the main loop. */
+       select_setting ( widget, n );
+}
+
 static int main_loop ( struct settings *settings ) {
        struct setting_widget widget;
        unsigned int current = 0;
        unsigned int next;
-       int i;
        int key;
        int rc;
 
        /* Print initial screen content */
        draw_title_row();
        color_set ( CPAIR_NORMAL, NULL );
-       for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
-               init_setting_index ( &widget, settings, i );
-               draw_setting ( &widget );
-       }
-
+       init_widget ( &widget, settings );
+       
        while ( 1 ) {
                /* Redraw information and instruction rows */
                draw_info_row ( widget.setting );
@@ -385,11 +424,11 @@ static int main_loop ( struct settings *settings ) {
                        switch ( key ) {
                        case KEY_DOWN:
                                if ( next < ( NUM_SETTINGS - 1 ) )
-                                       next++;
+                                       reveal ( &widget, ++next );
                                break;
                        case KEY_UP:
                                if ( next > 0 )
-                                       next--;
+                                       reveal ( &widget, --next ) ;
                                break;
                        case CTRL_X:
                                return 0;
@@ -399,7 +438,7 @@ static int main_loop ( struct settings *settings ) {
                        }       
                        if ( next != current ) {
                                draw_setting ( &widget );
-                               init_setting_index ( &widget, settings, next );
+                               select_setting ( &widget, next );
                                current = next;
                        }
                }