Add (partly-functional) user interface for editing configuration settings
authorMichael Brown <mcb30@etherboot.org>
Wed, 20 Dec 2006 03:04:07 +0000 (03:04 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 20 Dec 2006 03:04:07 +0000 (03:04 +0000)
src/Makefile
src/hci/tui/settings_ui.c [new file with mode: 0644]

index fae083f..9c98909 100644 (file)
@@ -144,7 +144,8 @@ SRCDIRS             += drivers/bitbash
 SRCDIRS                += interface/pxe
 SRCDIRS                += tests
 SRCDIRS                += crypto
-SRCDIRS                += hci hci/commands hci/mucurses
+SRCDIRS                += hci hci/commands hci/tui
+SRCDIRS                += hci/mucurses hci/mucurses/widgets
 
 # NON_AUTO_SRCS lists files that are excluded from the normal
 # automatic build system.
diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c
new file mode 100644 (file)
index 0000000..8ba5d76
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <curses.h>
+#include <console.h>
+#include <gpxe/settings.h>
+#include <gpxe/editbox.h>
+
+/** @file
+ *
+ * Configuration settings UI
+ *
+ */
+
+#include <gpxe/nvo.h>
+extern struct nvo_block *ugly_nvo_hack;
+
+/* Colour pairs */
+#define CPAIR_NORMAL   1
+#define CPAIR_SELECT   2
+#define CPAIR_EDIT     3
+
+/* Screen layout */
+#define SETTINGS_LIST_ROW      3
+#define SETTINGS_LIST_COL      1
+
+/** Layout of text within a setting widget */
+struct setting_row {
+       char start[0];
+       char pad1[1];
+       char name[15];
+       char pad2[1];
+       char value[60];
+       char pad3[1];
+       char nul;
+} __attribute__ (( packed ));
+
+/** A setting widget */
+struct setting_widget {
+       /** Configuration context */
+       struct config_context *context;
+       /** Configuration setting */
+       struct config_setting *setting;
+       /** Screen row */
+       unsigned int row;
+       /** Screen column */
+       unsigned int col;
+       /** Edit box widget used for editing setting */
+       struct edit_box editbox;
+       /** Editing active flag */
+       int editing;
+       /** Buffer for setting's value */
+       char value[256]; /* enough size for a DHCP string */
+};
+
+/** Registered configuration settings */
+static struct config_setting
+config_settings[0] __table_start ( config_settings );
+static struct config_setting
+config_settings_end[0] __table_end ( config_settings );
+#define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
+
+/**
+ * Load setting widget value from configuration context
+ *
+ * @v widget           Setting widget
+ *
+ */
+static void load_setting ( struct setting_widget *widget ) {
+
+       /* Mark as not editing */
+       widget->editing = 0;
+
+       /* Read current setting value */
+       if ( widget->setting->type->show ( widget->context, widget->setting,
+                                          widget->value,
+                                          sizeof ( widget->value ) ) != 0 ) {
+               widget->value[0] = '\0';
+       }       
+
+       /* Initialise edit box */
+       init_editbox ( &widget->editbox, widget->value,
+                      sizeof ( widget->value ), NULL, widget->row,
+                      ( widget->col + offsetof ( struct setting_row, value )),
+                      sizeof ( ( ( struct setting_row * ) NULL )->value ) );
+}
+
+/**
+ * Save setting widget value back to configuration context
+ *
+ * @v widget           Setting widget
+ */
+static int save_setting ( struct setting_widget *widget ) {
+       widget->editing = 0;
+       return widget->setting->type->set ( widget->context, widget->setting,
+                                           widget->value );
+}
+
+/**
+ * Initialise setting widget
+ *
+ * @v widget           Setting widget
+ * @v context          Configuration context
+ * @v setting          Configuration setting
+ * @v row              Screen row
+ * @v col              Screen column
+ */
+static void init_setting ( struct setting_widget *widget,
+                          struct config_context *context,
+                          struct config_setting *setting,
+                          unsigned int row, unsigned int col ) {
+
+       /* Initialise widget structure */
+       memset ( widget, 0, sizeof ( *widget ) );
+       widget->context = context;
+       widget->setting = setting;
+       widget->row = row;
+       widget->col = col;
+
+       /* Read current setting value */
+       load_setting ( widget );
+}
+
+/**
+ * Draw setting widget
+ *
+ * @v widget           Setting widget
+ */
+static void draw_setting ( struct setting_widget *widget ) {
+       struct setting_row row;
+       unsigned int len;
+       unsigned int curs_col;
+       char *value;
+
+       /* Fill row with spaces */
+       memset ( &row, ' ', sizeof ( row ) );
+       row.nul = '\0';
+
+       /* Construct dot-padded name */
+       memset ( row.name, '.', sizeof ( row.name ) );
+       len = strlen ( widget->setting->name );
+       if ( len > sizeof ( row.name ) )
+               len = sizeof ( row.name );
+       memcpy ( row.name, widget->setting->name, len );
+
+       /* Construct space-padded value */
+       value = widget->value;
+       if ( ! *value )
+               value = "<not specified>";
+       len = strlen ( value );
+       if ( len > sizeof ( row.value ) )
+               len = sizeof ( row.value );
+       memcpy ( row.value, value, len );
+       curs_col = ( widget->col + offsetof ( typeof ( row ), value )
+                    + len );
+
+       /* Print row */
+       mvprintw ( widget->row, widget->col, "%s", row.start );
+       move ( widget->row, curs_col );
+       if ( widget->editing )
+               draw_editbox ( &widget->editbox );
+}
+
+/**
+ * Edit setting widget
+ *
+ * @v widget           Setting widget
+ * @v key              Key pressed by user
+ * @ret key            Key returned to application, or zero
+ */
+static int edit_setting ( struct setting_widget *widget, int key ) {
+       widget->editing = 1;
+       return edit_editbox ( &widget->editbox, key );
+}
+
+/**
+ * Initialise setting widget by index
+ *
+ * @v widget           Setting widget
+ * @v context          Configuration context
+ * @v index            Index of setting with settings list
+ */
+static void init_setting_index ( struct setting_widget *widget,
+                                struct config_context *context,
+                                unsigned int index ) {
+       init_setting ( widget, context, &config_settings[index],
+                      ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
+}
+
+static void main_loop ( struct config_context *context ) {
+       struct setting_widget widget;
+       unsigned int current = 0;
+       unsigned int next;
+       int i;
+       int key;
+       int rc;
+
+       /* Print initial screen content */
+       color_set ( CPAIR_NORMAL, NULL );
+       for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
+               init_setting_index ( &widget, context, i );
+               draw_setting ( &widget );
+       }
+
+       while ( 1 ) {
+               /* Redraw current setting */
+               color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
+                           NULL );
+               draw_setting ( &widget );
+               color_set ( CPAIR_NORMAL, NULL );
+
+               key = getchar();
+               if ( widget.editing ) {
+                       key = edit_setting ( &widget, key );
+                       switch ( key ) {
+                       case 0x0a: /* Enter */
+                               if ( ( rc = save_setting ( &widget ) ) != 0 ) {
+                                       
+                               }
+                               break;
+                       case 0x03: /* Ctrl-C */
+                               load_setting ( &widget );
+                               break;
+                       default:
+                               /* Do nothing */
+                               break;
+                       }
+               } else {
+                       next = current;
+                       switch ( key ) {
+                       case '+':
+                               if ( next < ( NUM_SETTINGS - 1 ) )
+                                       next++;
+                               break;
+                       case '-':
+                               if ( next > 0 )
+                                       next--;
+                               break;
+                       default:
+                               edit_setting ( &widget, key );
+                               break;
+                       }       
+                       if ( next != current ) {
+                               draw_setting ( &widget );
+                               init_setting_index ( &widget, context, next );
+                               current = next;
+                       }
+               }
+       }
+       
+}
+
+void uitest ( void ) {
+       struct config_context dummy_context;
+
+       dummy_context.options = ugly_nvo_hack->options;
+
+       initscr();
+       start_color();
+       init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
+       init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
+       init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_GREEN );
+       color_set ( CPAIR_NORMAL, NULL );
+       erase();
+       
+       main_loop ( &dummy_context );
+
+       endwin();
+}