2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <gpxe/settings.h>
25 #include <gpxe/editbox.h>
26 #include <gpxe/settings_ui.h>
30 * Option configuration console
35 extern struct nvo_block *ugly_nvo_hack;
39 #define CPAIR_NORMAL 1
40 #define CPAIR_SELECT 2
46 #define SETTINGS_LIST_ROW 3
47 #define SETTINGS_LIST_COL 1
50 #define INSTRUCTION_ROW 22
51 #define INSTRUCTION_PAD " "
53 /** Layout of text within a setting widget */
62 } __attribute__ (( packed ));
64 /** A setting widget */
65 struct setting_widget {
66 /** Configuration context */
67 struct config_context *context;
68 /** Configuration setting */
69 struct config_setting *setting;
74 /** Edit box widget used for editing setting */
75 struct edit_box editbox;
76 /** Editing in progress flag */
78 /** Buffer for setting's value */
79 char value[256]; /* enough size for a DHCP string */
82 /** Registered configuration settings */
83 static struct config_setting
84 config_settings[0] __table_start ( config_settings );
85 static struct config_setting
86 config_settings_end[0] __table_end ( config_settings );
87 #define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
90 * Load setting widget value from configuration context
92 * @v widget Setting widget
95 static void load_setting ( struct setting_widget *widget ) {
97 /* Mark as not editing */
100 /* Read current setting value */
101 if ( show_setting ( widget->context, widget->setting,
102 widget->value, sizeof ( widget->value ) ) != 0 ) {
103 widget->value[0] = '\0';
106 /* Initialise edit box */
107 init_editbox ( &widget->editbox, widget->value,
108 sizeof ( widget->value ), NULL, widget->row,
109 ( widget->col + offsetof ( struct setting_row, value )),
110 sizeof ( ( ( struct setting_row * ) NULL )->value ) );
114 * Save setting widget value back to configuration context
116 * @v widget Setting widget
118 static int save_setting ( struct setting_widget *widget ) {
119 return set_setting ( widget->context, widget->setting, widget->value );
123 * Initialise setting widget
125 * @v widget Setting widget
126 * @v context Configuration context
127 * @v setting Configuration setting
129 * @v col Screen column
131 static void init_setting ( struct setting_widget *widget,
132 struct config_context *context,
133 struct config_setting *setting,
134 unsigned int row, unsigned int col ) {
136 /* Initialise widget structure */
137 memset ( widget, 0, sizeof ( *widget ) );
138 widget->context = context;
139 widget->setting = setting;
143 /* Read current setting value */
144 load_setting ( widget );
148 * Draw setting widget
150 * @v widget Setting widget
152 static void draw_setting ( struct setting_widget *widget ) {
153 struct setting_row row;
155 unsigned int curs_col;
158 /* Fill row with spaces */
159 memset ( &row, ' ', sizeof ( row ) );
162 /* Construct dot-padded name */
163 memset ( row.name, '.', sizeof ( row.name ) );
164 len = strlen ( widget->setting->name );
165 if ( len > sizeof ( row.name ) )
166 len = sizeof ( row.name );
167 memcpy ( row.name, widget->setting->name, len );
169 /* Construct space-padded value */
170 value = widget->value;
172 value = "<not specified>";
173 len = strlen ( value );
174 if ( len > sizeof ( row.value ) )
175 len = sizeof ( row.value );
176 memcpy ( row.value, value, len );
177 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
181 mvprintw ( widget->row, widget->col, "%s", row.start );
182 move ( widget->row, curs_col );
183 if ( widget->editing )
184 draw_editbox ( &widget->editbox );
188 * Edit setting widget
190 * @v widget Setting widget
191 * @v key Key pressed by user
192 * @ret key Key returned to application, or zero
194 static int edit_setting ( struct setting_widget *widget, int key ) {
196 return edit_editbox ( &widget->editbox, key );
200 * Initialise setting widget by index
202 * @v widget Setting widget
203 * @v context Configuration context
204 * @v index Index of setting with settings list
206 static void init_setting_index ( struct setting_widget *widget,
207 struct config_context *context,
208 unsigned int index ) {
209 init_setting ( widget, context, &config_settings[index],
210 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
214 * Print message centred on specified row
217 * @v fmt printf() format string
218 * @v args printf() argument list
220 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
224 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
225 mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
229 * Print message centred on specified row
232 * @v fmt printf() format string
233 * @v .. printf() arguments
235 static void msg ( unsigned int row, const char *fmt, ... ) {
238 va_start ( args, fmt );
239 vmsg ( row, fmt, args );
244 * Clear message on specified row
248 static void clearmsg ( unsigned int row ) {
254 * Print alert message
256 * @v fmt printf() format string
257 * @v args printf() argument list
259 static void valert ( const char *fmt, va_list args ) {
260 clearmsg ( ALERT_ROW );
261 color_set ( CPAIR_ALERT, NULL );
262 vmsg ( ALERT_ROW, fmt, args );
264 color_set ( CPAIR_NORMAL, NULL );
265 clearmsg ( ALERT_ROW );
269 * Print alert message
271 * @v fmt printf() format string
272 * @v ... printf() arguments
274 static void alert ( const char *fmt, ... ) {
277 va_start ( args, fmt );
278 valert ( fmt, args );
285 static void draw_title_row ( void ) {
287 msg ( TITLE_ROW, "gPXE option configuration console" );
292 * Draw information row
294 * @v setting Current configuration setting
296 static void draw_info_row ( struct config_setting *setting ) {
297 clearmsg ( INFO_ROW );
299 msg ( INFO_ROW, "%s (%s) - %s", setting->name,
300 setting->type->description, setting->description );
305 * Draw instruction row
307 * @v editing Editing in progress flag
309 static void draw_instruction_row ( int editing ) {
310 clearmsg ( INSTRUCTION_ROW );
312 msg ( INSTRUCTION_ROW,
313 "Enter - accept changes" INSTRUCTION_PAD
314 "Ctrl-C - discard changes" );
316 msg ( INSTRUCTION_ROW,
317 "Ctrl-S - save configuration" );
321 static int main_loop ( struct config_context *context ) {
322 struct setting_widget widget;
323 unsigned int current = 0;
329 /* Print initial screen content */
331 color_set ( CPAIR_NORMAL, NULL );
332 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
333 init_setting_index ( &widget, context, i );
334 draw_setting ( &widget );
338 /* Redraw information and instruction rows */
339 draw_info_row ( widget.setting );
340 draw_instruction_row ( widget.editing );
342 /* Redraw current setting */
343 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
345 draw_setting ( &widget );
346 color_set ( CPAIR_NORMAL, NULL );
349 if ( widget.editing ) {
350 key = edit_setting ( &widget, key );
352 case 0x0a: /* Enter */
353 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
354 alert ( " Could not set %s: %s ",
355 widget.setting->name,
359 case 0x03: /* Ctrl-C */
360 load_setting ( &widget );
370 if ( next < ( NUM_SETTINGS - 1 ) )
377 case 0x13: /* Ctrl-S */
378 if ( ( rc = nvo_save ( ugly_nvo_hack ) ) != 0){
379 alert ( " Could not save options: %s ",
384 edit_setting ( &widget, key );
387 if ( next != current ) {
388 draw_setting ( &widget );
389 init_setting_index ( &widget, context, next );
397 int settings_ui ( struct config_context *context ) {
402 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
403 init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
404 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
405 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
406 color_set ( CPAIR_NORMAL, NULL );
409 rc = main_loop ( context );