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/keys.h>
27 #include <gpxe/settings_ui.h>
31 * Option configuration console
36 extern struct nvo_block *ugly_nvo_hack;
40 #define CPAIR_NORMAL 1
41 #define CPAIR_SELECT 2
47 #define SETTINGS_LIST_ROW 3
48 #define SETTINGS_LIST_COL 1
51 #define INSTRUCTION_ROW 22
52 #define INSTRUCTION_PAD " "
54 /** Layout of text within a setting widget */
63 } __attribute__ (( packed ));
65 /** A setting widget */
66 struct setting_widget {
67 /** Configuration context */
68 struct config_context *context;
69 /** Configuration setting */
70 struct config_setting *setting;
75 /** Edit box widget used for editing setting */
76 struct edit_box editbox;
77 /** Editing in progress flag */
79 /** Buffer for setting's value */
80 char value[256]; /* enough size for a DHCP string */
83 /** Registered configuration settings */
84 static struct config_setting config_settings[0]
85 __table_start ( struct config_setting, config_settings );
86 static struct config_setting config_settings_end[0]
87 __table_end ( struct config_setting, config_settings );
88 #define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
91 * Load setting widget value from configuration context
93 * @v widget Setting widget
96 static void load_setting ( struct setting_widget *widget ) {
98 /* Mark as not editing */
101 /* Read current setting value */
102 if ( show_setting ( widget->context, widget->setting,
103 widget->value, sizeof ( widget->value ) ) != 0 ) {
104 widget->value[0] = '\0';
107 /* Initialise edit box */
108 init_editbox ( &widget->editbox, widget->value,
109 sizeof ( widget->value ), NULL, widget->row,
110 ( widget->col + offsetof ( struct setting_row, value )),
111 sizeof ( ( ( struct setting_row * ) NULL )->value ) );
115 * Save setting widget value back to configuration context
117 * @v widget Setting widget
119 static int save_setting ( struct setting_widget *widget ) {
120 return set_setting ( widget->context, widget->setting, widget->value );
124 * Initialise setting widget
126 * @v widget Setting widget
127 * @v context Configuration context
128 * @v setting Configuration setting
130 * @v col Screen column
132 static void init_setting ( struct setting_widget *widget,
133 struct config_context *context,
134 struct config_setting *setting,
135 unsigned int row, unsigned int col ) {
137 /* Initialise widget structure */
138 memset ( widget, 0, sizeof ( *widget ) );
139 widget->context = context;
140 widget->setting = setting;
144 /* Read current setting value */
145 load_setting ( widget );
149 * Draw setting widget
151 * @v widget Setting widget
153 static void draw_setting ( struct setting_widget *widget ) {
154 struct setting_row row;
156 unsigned int curs_col;
159 /* Fill row with spaces */
160 memset ( &row, ' ', sizeof ( row ) );
163 /* Construct dot-padded name */
164 memset ( row.name, '.', sizeof ( row.name ) );
165 len = strlen ( widget->setting->name );
166 if ( len > sizeof ( row.name ) )
167 len = sizeof ( row.name );
168 memcpy ( row.name, widget->setting->name, len );
170 /* Construct space-padded value */
171 value = widget->value;
173 value = "<not specified>";
174 len = strlen ( value );
175 if ( len > sizeof ( row.value ) )
176 len = sizeof ( row.value );
177 memcpy ( row.value, value, len );
178 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
182 mvprintw ( widget->row, widget->col, "%s", row.start );
183 move ( widget->row, curs_col );
184 if ( widget->editing )
185 draw_editbox ( &widget->editbox );
189 * Edit setting widget
191 * @v widget Setting widget
192 * @v key Key pressed by user
193 * @ret key Key returned to application, or zero
195 static int edit_setting ( struct setting_widget *widget, int key ) {
197 return edit_editbox ( &widget->editbox, key );
201 * Initialise setting widget by index
203 * @v widget Setting widget
204 * @v context Configuration context
205 * @v index Index of setting with settings list
207 static void init_setting_index ( struct setting_widget *widget,
208 struct config_context *context,
209 unsigned int index ) {
210 init_setting ( widget, context, &config_settings[index],
211 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
215 * Print message centred on specified row
218 * @v fmt printf() format string
219 * @v args printf() argument list
221 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
225 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
226 mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
230 * Print message centred on specified row
233 * @v fmt printf() format string
234 * @v .. printf() arguments
236 static void msg ( unsigned int row, const char *fmt, ... ) {
239 va_start ( args, fmt );
240 vmsg ( row, fmt, args );
245 * Clear message on specified row
249 static void clearmsg ( unsigned int row ) {
255 * Print alert message
257 * @v fmt printf() format string
258 * @v args printf() argument list
260 static void valert ( const char *fmt, va_list args ) {
261 clearmsg ( ALERT_ROW );
262 color_set ( CPAIR_ALERT, NULL );
263 vmsg ( ALERT_ROW, fmt, args );
265 color_set ( CPAIR_NORMAL, NULL );
266 clearmsg ( ALERT_ROW );
270 * Print alert message
272 * @v fmt printf() format string
273 * @v ... printf() arguments
275 static void alert ( const char *fmt, ... ) {
278 va_start ( args, fmt );
279 valert ( fmt, args );
286 static void draw_title_row ( void ) {
288 msg ( TITLE_ROW, "gPXE option configuration console" );
293 * Draw information row
295 * @v setting Current configuration setting
297 static void draw_info_row ( struct config_setting *setting ) {
298 clearmsg ( INFO_ROW );
300 msg ( INFO_ROW, "%s (%s) - %s", setting->name,
301 setting->type->description, setting->description );
306 * Draw instruction row
308 * @v editing Editing in progress flag
310 static void draw_instruction_row ( int editing ) {
311 clearmsg ( INSTRUCTION_ROW );
313 msg ( INSTRUCTION_ROW,
314 "Enter - accept changes" INSTRUCTION_PAD
315 "Ctrl-C - discard changes" );
317 msg ( INSTRUCTION_ROW,
318 "Ctrl-S - save configuration" );
322 static int main_loop ( struct config_context *context ) {
323 struct setting_widget widget;
324 unsigned int current = 0;
330 /* Print initial screen content */
332 color_set ( CPAIR_NORMAL, NULL );
333 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
334 init_setting_index ( &widget, context, i );
335 draw_setting ( &widget );
339 /* Redraw information and instruction rows */
340 draw_info_row ( widget.setting );
341 draw_instruction_row ( widget.editing );
343 /* Redraw current setting */
344 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
346 draw_setting ( &widget );
347 color_set ( CPAIR_NORMAL, NULL );
350 if ( widget.editing ) {
351 key = edit_setting ( &widget, key );
355 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
356 alert ( " Could not set %s: %s ",
357 widget.setting->name,
362 load_setting ( &widget );
372 if ( next < ( NUM_SETTINGS - 1 ) )
380 if ( ( rc = nvo_save ( ugly_nvo_hack ) ) != 0){
381 alert ( " Could not save options: %s ",
386 edit_setting ( &widget, key );
389 if ( next != current ) {
390 draw_setting ( &widget );
391 init_setting_index ( &widget, context, next );
399 int settings_ui ( struct config_context *context ) {
404 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
405 init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
406 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
407 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
408 color_set ( CPAIR_NORMAL, NULL );
411 rc = main_loop ( context );