settings_ui.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdio.h>
00022 #include <stdarg.h>
00023 #include <unistd.h>
00024 #include <string.h>
00025 #include <curses.h>
00026 #include <console.h>
00027 #include <gpxe/settings.h>
00028 #include <gpxe/editbox.h>
00029 #include <gpxe/keys.h>
00030 #include <gpxe/settings_ui.h>
00031 
00032 /** @file
00033  *
00034  * Option configuration console
00035  *
00036  */
00037 
00038 /* Colour pairs */
00039 #define CPAIR_NORMAL    1
00040 #define CPAIR_SELECT    2
00041 #define CPAIR_EDIT      3
00042 #define CPAIR_ALERT     4
00043 
00044 /* Screen layout */
00045 #define TITLE_ROW               1
00046 #define SETTINGS_LIST_ROW       3
00047 #define SETTINGS_LIST_COL       1
00048 #define INFO_ROW                20
00049 #define ALERT_ROW               20
00050 #define INSTRUCTION_ROW         22
00051 #define INSTRUCTION_PAD "     "
00052 
00053 /** Layout of text within a setting widget */
00054 struct setting_row {
00055         char start[0];
00056         char pad1[1];
00057         char name[15];
00058         char pad2[1];
00059         char value[60];
00060         char pad3[1];
00061         char nul;
00062 } __attribute__ (( packed ));
00063 
00064 /** A setting widget */
00065 struct setting_widget {
00066         /** Settings block */
00067         struct settings *settings;
00068         /** Configuration setting */
00069         struct setting *setting;
00070         /** Screen row */
00071         unsigned int row;
00072         /** Screen column */
00073         unsigned int col;
00074         /** Edit box widget used for editing setting */
00075         struct edit_box editbox;
00076         /** Editing in progress flag */
00077         int editing;
00078         /** Buffer for setting's value */
00079         char value[256]; /* enough size for a DHCP string */
00080 };
00081 
00082 /** Number of registered configuration settings */
00083 #define NUM_SETTINGS table_num_entries ( SETTINGS )
00084 
00085 static void load_setting ( struct setting_widget *widget ) __nonnull;
00086 static int save_setting ( struct setting_widget *widget ) __nonnull;
00087 static void init_setting ( struct setting_widget *widget,
00088                            struct settings *settings,
00089                            struct setting *setting,
00090                            unsigned int row, unsigned int col ) __nonnull;
00091 static void draw_setting ( struct setting_widget *widget ) __nonnull;
00092 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
00093 static void init_setting_index ( struct setting_widget *widget,
00094                                  struct settings *settings,
00095                                  unsigned int index ) __nonnull;
00096 static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
00097 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
00098 static void valert ( const char *fmt, va_list args ) __nonnull;
00099 static void alert ( const char *fmt, ... ) __nonnull;
00100 static void draw_info_row ( struct setting *setting ) __nonnull;
00101 static int main_loop ( struct settings *settings ) __nonnull;
00102 
00103 /**
00104  * Load setting widget value from configuration settings
00105  *
00106  * @v widget            Setting widget
00107  *
00108  */
00109 static void load_setting ( struct setting_widget *widget ) {
00110 
00111         /* Mark as not editing */
00112         widget->editing = 0;
00113 
00114         /* Read current setting value */
00115         if ( fetchf_setting ( widget->settings, widget->setting,
00116                               widget->value, sizeof ( widget->value ) ) < 0 ) {
00117                 widget->value[0] = '\0';
00118         }       
00119 
00120         /* Initialise edit box */
00121         init_editbox ( &widget->editbox, widget->value,
00122                        sizeof ( widget->value ), NULL, widget->row,
00123                        ( widget->col + offsetof ( struct setting_row, value )),
00124                        sizeof ( ( ( struct setting_row * ) NULL )->value ), 0);
00125 }
00126 
00127 /**
00128  * Save setting widget value back to configuration settings
00129  *
00130  * @v widget            Setting widget
00131  */
00132 static int save_setting ( struct setting_widget *widget ) {
00133         return storef_setting ( widget->settings, widget->setting,
00134                                 widget->value );
00135 }
00136 
00137 /**
00138  * Initialise setting widget
00139  *
00140  * @v widget            Setting widget
00141  * @v settings          Settings block
00142  * @v setting           Configuration setting
00143  * @v row               Screen row
00144  * @v col               Screen column
00145  */
00146 static void init_setting ( struct setting_widget *widget,
00147                            struct settings *settings,
00148                            struct setting *setting,
00149                            unsigned int row, unsigned int col ) {
00150 
00151         /* Initialise widget structure */
00152         memset ( widget, 0, sizeof ( *widget ) );
00153         widget->settings = settings;
00154         widget->setting = setting;
00155         widget->row = row;
00156         widget->col = col;
00157 
00158         /* Read current setting value */
00159         load_setting ( widget );
00160 }
00161 
00162 /**
00163  * Draw setting widget
00164  *
00165  * @v widget            Setting widget
00166  */
00167 static void draw_setting ( struct setting_widget *widget ) {
00168         struct setting_row row;
00169         unsigned int len;
00170         unsigned int curs_col;
00171         char *value;
00172 
00173         /* Fill row with spaces */
00174         memset ( &row, ' ', sizeof ( row ) );
00175         row.nul = '\0';
00176 
00177         /* Construct dot-padded name */
00178         memset ( row.name, '.', sizeof ( row.name ) );
00179         len = strlen ( widget->setting->name );
00180         if ( len > sizeof ( row.name ) )
00181                 len = sizeof ( row.name );
00182         memcpy ( row.name, widget->setting->name, len );
00183 
00184         /* Construct space-padded value */
00185         value = widget->value;
00186         if ( ! *value )
00187                 value = "<not specified>";
00188         len = strlen ( value );
00189         if ( len > sizeof ( row.value ) )
00190                 len = sizeof ( row.value );
00191         memcpy ( row.value, value, len );
00192         curs_col = ( widget->col + offsetof ( typeof ( row ), value )
00193                      + len );
00194 
00195         /* Print row */
00196         mvprintw ( widget->row, widget->col, "%s", row.start );
00197         move ( widget->row, curs_col );
00198         if ( widget->editing )
00199                 draw_editbox ( &widget->editbox );
00200 }
00201 
00202 /**
00203  * Edit setting widget
00204  *
00205  * @v widget            Setting widget
00206  * @v key               Key pressed by user
00207  * @ret key             Key returned to application, or zero
00208  */
00209 static int edit_setting ( struct setting_widget *widget, int key ) {
00210         widget->editing = 1;
00211         return edit_editbox ( &widget->editbox, key );
00212 }
00213 
00214 /**
00215  * Initialise setting widget by index
00216  *
00217  * @v widget            Setting widget
00218  * @v settings          Settings block
00219  * @v index             Index of setting with settings list
00220  */
00221 static void init_setting_index ( struct setting_widget *widget,
00222                                  struct settings *settings,
00223                                  unsigned int index ) {
00224         struct setting *all_settings = table_start ( SETTINGS );
00225 
00226         init_setting ( widget, settings, &all_settings[index],
00227                        ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
00228 }
00229 
00230 /**
00231  * Print message centred on specified row
00232  *
00233  * @v row               Row
00234  * @v fmt               printf() format string
00235  * @v args              printf() argument list
00236  */
00237 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
00238         char buf[COLS];
00239         size_t len;
00240 
00241         len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
00242         mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
00243 }
00244 
00245 /**
00246  * Print message centred on specified row
00247  *
00248  * @v row               Row
00249  * @v fmt               printf() format string
00250  * @v ..                printf() arguments
00251  */
00252 static void msg ( unsigned int row, const char *fmt, ... ) {
00253         va_list args;
00254 
00255         va_start ( args, fmt );
00256         vmsg ( row, fmt, args );
00257         va_end ( args );
00258 }
00259 
00260 /**
00261  * Clear message on specified row
00262  *
00263  * @v row               Row
00264  */
00265 static void clearmsg ( unsigned int row ) {
00266         move ( row, 0 );
00267         clrtoeol();
00268 }
00269 
00270 /**
00271  * Print alert message
00272  *
00273  * @v fmt               printf() format string
00274  * @v args              printf() argument list
00275  */
00276 static void valert ( const char *fmt, va_list args ) {
00277         clearmsg ( ALERT_ROW );
00278         color_set ( CPAIR_ALERT, NULL );
00279         vmsg ( ALERT_ROW, fmt, args );
00280         sleep ( 2 );
00281         color_set ( CPAIR_NORMAL, NULL );
00282         clearmsg ( ALERT_ROW );
00283 }
00284 
00285 /**
00286  * Print alert message
00287  *
00288  * @v fmt               printf() format string
00289  * @v ...               printf() arguments
00290  */
00291 static void alert ( const char *fmt, ... ) {
00292         va_list args;
00293 
00294         va_start ( args, fmt );
00295         valert ( fmt, args );
00296         va_end ( args );
00297 }
00298 
00299 /**
00300  * Draw title row
00301  */
00302 static void draw_title_row ( void ) {
00303         attron ( A_BOLD );
00304         msg ( TITLE_ROW, "gPXE option configuration console" );
00305         attroff ( A_BOLD );
00306 }
00307 
00308 /**
00309  * Draw information row
00310  *
00311  * @v setting           Current configuration setting
00312  */
00313 static void draw_info_row ( struct setting *setting ) {
00314         clearmsg ( INFO_ROW );
00315         attron ( A_BOLD );
00316         msg ( INFO_ROW, "%s - %s", setting->name, setting->description );
00317         attroff ( A_BOLD );
00318 }
00319 
00320 /**
00321  * Draw instruction row
00322  *
00323  * @v editing           Editing in progress flag
00324  */
00325 static void draw_instruction_row ( int editing ) {
00326         clearmsg ( INSTRUCTION_ROW );
00327         if ( editing ) {
00328                 msg ( INSTRUCTION_ROW,
00329                       "Enter - accept changes" INSTRUCTION_PAD
00330                       "Ctrl-C - discard changes" );
00331         } else {
00332                 msg ( INSTRUCTION_ROW,
00333                       "Ctrl-X - exit configuration utility" );
00334         }
00335 }
00336 
00337 static int main_loop ( struct settings *settings ) {
00338         struct setting_widget widget;
00339         unsigned int current = 0;
00340         unsigned int next;
00341         int i;
00342         int key;
00343         int rc;
00344 
00345         /* Print initial screen content */
00346         draw_title_row();
00347         color_set ( CPAIR_NORMAL, NULL );
00348         for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
00349                 init_setting_index ( &widget, settings, i );
00350                 draw_setting ( &widget );
00351         }
00352 
00353         while ( 1 ) {
00354                 /* Redraw information and instruction rows */
00355                 draw_info_row ( widget.setting );
00356                 draw_instruction_row ( widget.editing );
00357 
00358                 /* Redraw current setting */
00359                 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
00360                             NULL );
00361                 draw_setting ( &widget );
00362                 color_set ( CPAIR_NORMAL, NULL );
00363 
00364                 key = getkey();
00365                 if ( widget.editing ) {
00366                         key = edit_setting ( &widget, key );
00367                         switch ( key ) {
00368                         case CR:
00369                         case LF:
00370                                 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
00371                                         alert ( " Could not set %s: %s ",
00372                                                 widget.setting->name,
00373                                                 strerror ( rc ) );
00374                                 }
00375                                 /* Fall through */
00376                         case CTRL_C:
00377                                 load_setting ( &widget );
00378                                 break;
00379                         default:
00380                                 /* Do nothing */
00381                                 break;
00382                         }
00383                 } else {
00384                         next = current;
00385                         switch ( key ) {
00386                         case KEY_DOWN:
00387                                 if ( next < ( NUM_SETTINGS - 1 ) )
00388                                         next++;
00389                                 break;
00390                         case KEY_UP:
00391                                 if ( next > 0 )
00392                                         next--;
00393                                 break;
00394                         case CTRL_X:
00395                                 return 0;
00396                         default:
00397                                 edit_setting ( &widget, key );
00398                                 break;
00399                         }       
00400                         if ( next != current ) {
00401                                 draw_setting ( &widget );
00402                                 init_setting_index ( &widget, settings, next );
00403                                 current = next;
00404                         }
00405                 }
00406         }
00407         
00408 }
00409 
00410 int settings_ui ( struct settings *settings ) {
00411         int rc;
00412 
00413         initscr();
00414         start_color();
00415         init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
00416         init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
00417         init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
00418         init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
00419         color_set ( CPAIR_NORMAL, NULL );
00420         erase();
00421         
00422         rc = main_loop ( settings );
00423 
00424         endwin();
00425 
00426         return rc;
00427 }

Generated on Tue Apr 6 20:01:06 2010 for gPXE by  doxygen 1.5.7.1