summaryrefslogtreecommitdiffstats
path: root/src/hci
diff options
context:
space:
mode:
authorMichael Brown2015-03-03 04:51:08 +0100
committerMichael Brown2015-03-03 04:51:08 +0100
commitad2e82a65b8ed82683901f48d01bedc4a3a29df4 (patch)
treef482f944f2b49cab659a4261de7026ad5fac8e1c /src/hci
parent[menu] Abstract out the generic concept of a jump scroller (diff)
downloadipxe-ad2e82a65b8ed82683901f48d01bedc4a3a29df4.tar.gz
ipxe-ad2e82a65b8ed82683901f48d01bedc4a3a29df4.tar.xz
ipxe-ad2e82a65b8ed82683901f48d01bedc4a3a29df4.zip
[settings] Use generic jump scrolling abstraction
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/hci')
-rw-r--r--src/hci/tui/settings_ui.c351
1 files changed, 155 insertions, 196 deletions
diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c
index e66abe94..be421cc0 100644
--- a/src/hci/tui/settings_ui.c
+++ b/src/hci/tui/settings_ui.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdarg.h>
@@ -29,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/editbox.h>
#include <ipxe/keys.h>
#include <ipxe/ansicol.h>
+#include <ipxe/jumpscroll.h>
#include <ipxe/settings_ui.h>
#include <config/branding.h>
@@ -48,7 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define INSTRUCTION_ROW ( LINES - 2U )
#define INSTRUCTION_PAD " "
-/** Layout of text within a setting widget */
+/** Layout of text within a setting row */
#define SETTING_ROW_TEXT( cols ) struct { \
char start[0]; \
char pad1[1]; \
@@ -64,8 +69,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
char nul; \
} __attribute__ (( packed ))
-/** A setting row widget */
-struct setting_row_widget {
+/** A settings user interface row */
+struct settings_ui_row {
/** Target configuration settings block
*
* Valid only for rows that lead to new settings blocks.
@@ -83,8 +88,6 @@ struct setting_row_widget {
struct setting setting;
/** Screen row */
unsigned int row;
- /** Screen column */
- unsigned int col;
/** Edit box widget used for editing setting */
struct edit_box editbox;
/** Editing in progress flag */
@@ -93,28 +96,24 @@ struct setting_row_widget {
char value[256]; /* enough size for a DHCP string */
};
-/** A settings widget */
-struct setting_widget {
+/** A settings user interface */
+struct settings_ui {
/** Settings block */
struct settings *settings;
- /** Number of rows */
- unsigned int num_rows;
- /** Current row index */
- unsigned int current;
- /** Index of the first visible row, for scrolling. */
- unsigned int first_visible;
- /** Active row */
- struct setting_row_widget row;
+ /** Jump scroller */
+ struct jump_scroller scroll;
+ /** Current row */
+ struct settings_ui_row row;
};
/**
- * Select a setting row
+ * Select a setting
*
- * @v widget Setting widget
+ * @v ui Settings user interface
* @v index Index of setting row
- * @ret count Number of settings rows
+ * @ret count Number of setting rows
*/
-static unsigned int select_setting_row ( struct setting_widget *widget,
+static unsigned int select_setting_row ( struct settings_ui *ui,
unsigned int index ) {
SETTING_ROW_TEXT ( COLS ) *text;
struct settings *settings;
@@ -123,25 +122,22 @@ static unsigned int select_setting_row ( struct setting_widget *widget,
unsigned int count = 0;
/* Initialise structure */
- memset ( &widget->row, 0, sizeof ( widget->row ) );
- widget->current = index;
- widget->row.row = ( SETTINGS_LIST_ROW + index - widget->first_visible );
- widget->row.col = SETTINGS_LIST_COL;
+ memset ( &ui->row, 0, sizeof ( ui->row ) );
+ ui->row.row = ( SETTINGS_LIST_ROW + index - ui->scroll.first );
/* Include parent settings block, if applicable */
- if ( widget->settings->parent && ( count++ == index ) ) {
- widget->row.settings = widget->settings->parent;
- snprintf ( widget->row.value, sizeof ( widget->row.value ),
+ if ( ui->settings->parent && ( count++ == index ) ) {
+ ui->row.settings = ui->settings->parent;
+ snprintf ( ui->row.value, sizeof ( ui->row.value ),
"../" );
}
/* Include any child settings blocks, if applicable */
- list_for_each_entry ( settings, &widget->settings->children, siblings ){
+ list_for_each_entry ( settings, &ui->settings->children, siblings ) {
if ( count++ == index ) {
- widget->row.settings = settings;
- snprintf ( widget->row.value,
- sizeof ( widget->row.value ), "%s/",
- settings->name );
+ ui->row.settings = settings;
+ snprintf ( ui->row.value, sizeof ( ui->row.value ),
+ "%s/", settings->name );
}
}
@@ -149,7 +145,7 @@ static unsigned int select_setting_row ( struct setting_widget *widget,
for_each_table_entry ( setting, SETTINGS ) {
/* Skip inapplicable settings */
- if ( ! setting_applies ( widget->settings, setting ) )
+ if ( ! setting_applies ( ui->settings, setting ) )
continue;
/* Skip duplicate settings */
@@ -159,18 +155,16 @@ static unsigned int select_setting_row ( struct setting_widget *widget,
/* Read current setting value and origin */
if ( count++ == index ) {
- fetchf_setting ( widget->settings, setting,
- &widget->row.origin,
- &widget->row.setting,
- widget->row.value,
- sizeof ( widget->row.value ) );
+ fetchf_setting ( ui->settings, setting, &ui->row.origin,
+ &ui->row.setting, ui->row.value,
+ sizeof ( ui->row.value ) );
}
}
/* Initialise edit box */
- init_editbox ( &widget->row.editbox, widget->row.value,
- sizeof ( widget->row.value ), NULL, widget->row.row,
- ( widget->row.col +
+ init_editbox ( &ui->row.editbox, ui->row.value,
+ sizeof ( ui->row.value ), NULL, ui->row.row,
+ ( SETTINGS_LIST_COL +
offsetof ( typeof ( *text ), u.setting.value ) ),
sizeof ( text->u.setting.value ), 0 );
@@ -198,9 +192,9 @@ static size_t string_copy ( char *dest, const char *src, size_t len ) {
/**
* Draw setting row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_setting_row ( struct setting_widget *widget ) {
+static void draw_setting_row ( struct settings_ui *ui ) {
SETTING_ROW_TEXT ( COLS ) text;
unsigned int curs_offset;
char *value;
@@ -210,12 +204,12 @@ static void draw_setting_row ( struct setting_widget *widget ) {
text.nul = '\0';
/* Construct row content */
- if ( widget->row.settings ) {
+ if ( ui->row.settings ) {
/* Construct space-padded name */
curs_offset = ( offsetof ( typeof ( text ), u.settings ) +
string_copy ( text.u.settings,
- widget->row.value,
+ ui->row.value,
sizeof ( text.u.settings ) ) );
} else {
@@ -223,11 +217,11 @@ static void draw_setting_row ( struct setting_widget *widget ) {
/* Construct dot-padded name */
memset ( text.u.setting.name, '.',
sizeof ( text.u.setting.name ) );
- string_copy ( text.u.setting.name, widget->row.setting.name,
+ string_copy ( text.u.setting.name, ui->row.setting.name,
sizeof ( text.u.setting.name ) );
/* Construct space-padded value */
- value = widget->row.value;
+ value = ui->row.value;
if ( ! *value )
value = "<not specified>";
curs_offset = ( offsetof ( typeof ( text ), u.setting.value ) +
@@ -236,37 +230,34 @@ static void draw_setting_row ( struct setting_widget *widget ) {
}
/* Print row */
- if ( ( widget->row.origin == widget->settings ) ||
- ( widget->row.settings != NULL ) ) {
+ if ( ( ui->row.origin == ui->settings ) || ( ui->row.settings != NULL ))
attron ( A_BOLD );
- }
- mvprintw ( widget->row.row, widget->row.col, "%s", text.start );
+ mvprintw ( ui->row.row, SETTINGS_LIST_COL, "%s", text.start );
attroff ( A_BOLD );
- move ( widget->row.row, widget->row.col + curs_offset );
+ move ( ui->row.row, ( SETTINGS_LIST_COL + curs_offset ) );
}
/**
- * Edit setting widget
+ * Edit setting ui
*
- * @v widget Setting widget
+ * @v ui Settings UI
* @v key Key pressed by user
* @ret key Key returned to application, or zero
*/
-static int edit_setting ( struct setting_widget *widget, int key ) {
- assert ( widget->row.setting.name != NULL );
- widget->row.editing = 1;
- return edit_editbox ( &widget->row.editbox, key );
+static int edit_setting ( struct settings_ui *ui, int key ) {
+ assert ( ui->row.setting.name != NULL );
+ ui->row.editing = 1;
+ return edit_editbox ( &ui->row.editbox, key );
}
/**
- * Save setting widget value back to configuration settings
+ * Save setting ui value back to configuration settings
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static int save_setting ( struct setting_widget *widget ) {
- assert ( widget->row.setting.name != NULL );
- return storef_setting ( widget->settings, &widget->row.setting,
- widget->row.value );
+static int save_setting ( struct settings_ui *ui ) {
+ assert ( ui->row.setting.name != NULL );
+ return storef_setting ( ui->settings, &ui->row.setting, ui->row.value );
}
/**
@@ -341,13 +332,13 @@ static void alert ( const char *fmt, ... ) {
/**
* Draw title row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_title_row ( struct setting_widget *widget ) {
+static void draw_title_row ( struct settings_ui *ui ) {
const char *name;
clearmsg ( TITLE_ROW );
- name = settings_name ( widget->settings );
+ name = settings_name ( ui->settings );
attron ( A_BOLD );
msg ( TITLE_ROW, PRODUCT_SHORT_NAME " configuration settings%s%s",
( name[0] ? " - " : "" ), name );
@@ -357,88 +348,73 @@ static void draw_title_row ( struct setting_widget *widget ) {
/**
* Draw information row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_info_row ( struct setting_widget *widget ) {
+static void draw_info_row ( struct settings_ui *ui ) {
char buf[32];
/* Draw nothing unless this row represents a setting */
clearmsg ( INFO_ROW );
clearmsg ( INFO_ROW + 1 );
- if ( ! widget->row.setting.name )
+ if ( ! ui->row.setting.name )
return;
/* Determine a suitable setting name */
- setting_name ( ( widget->row.origin ?
- widget->row.origin : widget->settings ),
- &widget->row.setting, buf, sizeof ( buf ) );
+ setting_name ( ( ui->row.origin ?
+ ui->row.origin : ui->settings ),
+ &ui->row.setting, buf, sizeof ( buf ) );
/* Draw row */
attron ( A_BOLD );
- msg ( INFO_ROW, "%s - %s", buf, widget->row.setting.description );
+ msg ( INFO_ROW, "%s - %s", buf, ui->row.setting.description );
attroff ( A_BOLD );
color_set ( CPAIR_URL, NULL );
- msg ( ( INFO_ROW + 1 ), PRODUCT_SETTING_URI, widget->row.setting.name );
+ msg ( ( INFO_ROW + 1 ), PRODUCT_SETTING_URI, ui->row.setting.name );
color_set ( CPAIR_NORMAL, NULL );
}
/**
* Draw instruction row
*
- * @v widget Setting widget
+ * @v ui Settings UI
*/
-static void draw_instruction_row ( struct setting_widget *widget ) {
+static void draw_instruction_row ( struct settings_ui *ui ) {
clearmsg ( INSTRUCTION_ROW );
- if ( widget->row.editing ) {
+ if ( ui->row.editing ) {
msg ( INSTRUCTION_ROW,
"Enter - accept changes" INSTRUCTION_PAD
"Ctrl-C - discard changes" );
} else {
msg ( INSTRUCTION_ROW,
"%sCtrl-X - exit configuration utility",
- ( ( widget->row.origin == widget->settings ) ?
+ ( ( ui->row.origin == ui->settings ) ?
"Ctrl-D - delete setting" INSTRUCTION_PAD : "" ) );
}
}
/**
- * Reveal setting row
+ * Draw the current block of setting rows
*
- * @v widget Setting widget
- * @v index Index of setting row
+ * @v ui Settings UI
*/
-static void reveal_setting_row ( struct setting_widget *widget,
- unsigned int index ) {
+static void draw_setting_rows ( struct settings_ui *ui ) {
unsigned int i;
- /* Simply return if setting N is already on-screen. */
- if ( index - widget->first_visible < SETTINGS_LIST_ROWS )
- return;
-
- /* Jump scroll to make the specified setting row visible. */
- while ( widget->first_visible < index )
- widget->first_visible += SETTINGS_LIST_ROWS;
- while ( widget->first_visible > index )
- widget->first_visible -= SETTINGS_LIST_ROWS;
-
- /* Draw ellipses 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 )
- < widget->num_rows ? "..." : " " ) );
+ /* Draw ellipses before and/or after the list as necessary */
+ color_set ( CPAIR_SEPARATOR, NULL );
+ mvaddstr ( ( SETTINGS_LIST_ROW - 1 ), ( SETTINGS_LIST_COL + 1 ),
+ jump_scroll_is_first ( &ui->scroll ) ? " " : "..." );
+ mvaddstr ( ( SETTINGS_LIST_ROW + SETTINGS_LIST_ROWS ),
+ ( SETTINGS_LIST_COL + 1 ),
+ jump_scroll_is_last ( &ui->scroll ) ? " " : "..." );
+ color_set ( CPAIR_NORMAL, NULL );
/* Draw visible settings. */
- for ( i = 0; i < SETTINGS_LIST_ROWS; i++ ) {
- if ( ( widget->first_visible + i ) < widget->num_rows ) {
- select_setting_row ( widget,
- widget->first_visible + i );
- draw_setting_row ( widget );
+ for ( i = 0 ; i < SETTINGS_LIST_ROWS ; i++ ) {
+ if ( ( ui->scroll.first + i ) < ui->scroll.count ) {
+ select_setting_row ( ui, ( ui->scroll.first + i ) );
+ draw_setting_row ( ui );
} else {
clearmsg ( SETTINGS_LIST_ROW + i );
}
@@ -446,69 +422,72 @@ static void reveal_setting_row ( struct setting_widget *widget,
}
/**
- * Reveal setting row
+ * Select settings block
*
- * @v widget Setting widget
+ * @v ui Settings UI
* @v settings Settings block
*/
-static void init_widget ( struct setting_widget *widget,
- struct settings *settings ) {
-
- widget->settings = settings_target ( settings );
- widget->num_rows = select_setting_row ( widget, 0 );
- widget->first_visible = SETTINGS_LIST_ROWS;
- draw_title_row ( widget );
- reveal_setting_row ( widget, 0 );
- select_setting_row ( widget, 0 );
+static void select_settings ( struct settings_ui *ui,
+ struct settings *settings ) {
+
+ ui->settings = settings_target ( settings );
+ ui->scroll.count = select_setting_row ( ui, 0 );
+ ui->scroll.rows = SETTINGS_LIST_ROWS;
+ ui->scroll.current = 0;
+ ui->scroll.first = 0;
+ draw_title_row ( ui );
+ draw_setting_rows ( ui );
+ select_setting_row ( ui, 0 );
}
static int main_loop ( struct settings *settings ) {
- struct setting_widget widget;
+ struct settings_ui ui;
+ unsigned int previous;
int redraw = 1;
int move;
- unsigned int next;
int key;
int rc;
/* Print initial screen content */
color_set ( CPAIR_NORMAL, NULL );
- memset ( &widget, 0, sizeof ( widget ) );
- init_widget ( &widget, settings );
+ memset ( &ui, 0, sizeof ( ui ) );
+ select_settings ( &ui, settings );
while ( 1 ) {
/* Redraw rows if necessary */
if ( redraw ) {
- draw_info_row ( &widget );
- draw_instruction_row ( &widget );
- color_set ( ( widget.row.editing ?
+ draw_info_row ( &ui );
+ draw_instruction_row ( &ui );
+ color_set ( ( ui.row.editing ?
CPAIR_EDIT : CPAIR_SELECT ), NULL );
- draw_setting_row ( &widget );
+ draw_setting_row ( &ui );
color_set ( CPAIR_NORMAL, NULL );
- curs_set ( widget.row.editing );
+ curs_set ( ui.row.editing );
redraw = 0;
}
- if ( widget.row.editing ) {
+ /* Edit setting, if we are currently editing */
+ if ( ui.row.editing ) {
/* Sanity check */
- assert ( widget.row.setting.name != NULL );
+ assert ( ui.row.setting.name != NULL );
/* Redraw edit box */
color_set ( CPAIR_EDIT, NULL );
- draw_editbox ( &widget.row.editbox );
+ draw_editbox ( &ui.row.editbox );
color_set ( CPAIR_NORMAL, NULL );
/* Process keypress */
- key = edit_setting ( &widget, getkey ( 0 ) );
+ key = edit_setting ( &ui, getkey ( 0 ) );
switch ( key ) {
case CR:
case LF:
- if ( ( rc = save_setting ( &widget ) ) != 0 )
+ if ( ( rc = save_setting ( &ui ) ) != 0 )
alert ( " %s ", strerror ( rc ) );
/* Fall through */
case CTRL_C:
- select_setting_row ( &widget, widget.current );
+ select_setting_row ( &ui, ui.scroll.current );
redraw = 1;
break;
default:
@@ -516,72 +495,52 @@ static int main_loop ( struct settings *settings ) {
break;
}
- } else {
+ continue;
+ }
- /* Process keypress */
- key = getkey ( 0 );
- move = 0;
- switch ( key ) {
- case KEY_UP:
- move = -1;
- break;
- case KEY_DOWN:
- move = +1;
- break;
- case KEY_PPAGE:
- move = ( widget.first_visible -
- widget.current - 1 );
- break;
- case KEY_NPAGE:
- move = ( widget.first_visible - widget.current
- + SETTINGS_LIST_ROWS );
- break;
- case KEY_HOME:
- move = -widget.num_rows;
- break;
- case KEY_END:
- move = +widget.num_rows;
- break;
- case CTRL_D:
- if ( ! widget.row.setting.name )
- break;
- if ( ( rc = delete_setting ( widget.settings,
- &widget.row.setting ) ) != 0 ) {
- alert ( " %s ", strerror ( rc ) );
- }
- select_setting_row ( &widget, widget.current );
+ /* Otherwise, navigate through settings */
+ key = getkey ( 0 );
+ move = jump_scroll_key ( &ui.scroll, key );
+ if ( move ) {
+ previous = ui.scroll.current;
+ jump_scroll_move ( &ui.scroll, move );
+ if ( ui.scroll.current != previous ) {
+ draw_setting_row ( &ui );
redraw = 1;
+ if ( jump_scroll ( &ui.scroll ) )
+ draw_setting_rows ( &ui );
+ select_setting_row ( &ui, ui.scroll.current );
+ }
+ continue;
+ }
+
+ /* Handle non-navigation keys */
+ switch ( key ) {
+ case CTRL_D:
+ if ( ! ui.row.setting.name )
break;
- case CTRL_X:
- return 0;
- case CR:
- case LF:
- if ( widget.row.settings ) {
- init_widget ( &widget,
- widget.row.settings );
- redraw = 1;
- }
- /* Fall through */
- default:
- if ( widget.row.setting.name ) {
- edit_setting ( &widget, key );
- redraw = 1;
- }
- break;
+ if ( ( rc = delete_setting ( ui.settings,
+ &ui.row.setting ) ) != 0 ){
+ alert ( " %s ", strerror ( rc ) );
+ }
+ select_setting_row ( &ui, ui.scroll.current );
+ redraw = 1;
+ break;
+ case CTRL_X:
+ return 0;
+ case CR:
+ case LF:
+ if ( ui.row.settings ) {
+ select_settings ( &ui, ui.row.settings );
+ redraw = 1;
}
- if ( move ) {
- next = ( widget.current + move );
- if ( ( int ) next < 0 )
- next = 0;
- if ( next >= widget.num_rows )
- next = ( widget.num_rows - 1 );
- if ( next != widget.current ) {
- draw_setting_row ( &widget );
- redraw = 1;
- reveal_setting_row ( &widget, next );
- select_setting_row ( &widget, next );
- }
+ /* Fall through */
+ default:
+ if ( ui.row.setting.name ) {
+ edit_setting ( &ui, key );
+ redraw = 1;
}
+ break;
}
}
}