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>
29 * Configuration settings UI
34 extern struct nvo_block *ugly_nvo_hack;
37 #define CPAIR_NORMAL 1
38 #define CPAIR_SELECT 2
44 #define SETTINGS_LIST_ROW 3
45 #define SETTINGS_LIST_COL 1
49 /** Layout of text within a setting widget */
58 } __attribute__ (( packed ));
60 /** A setting widget */
61 struct setting_widget {
62 /** Configuration context */
63 struct config_context *context;
64 /** Configuration setting */
65 struct config_setting *setting;
70 /** Edit box widget used for editing setting */
71 struct edit_box editbox;
72 /** Editing active flag */
74 /** Buffer for setting's value */
75 char value[256]; /* enough size for a DHCP string */
78 /** Registered configuration settings */
79 static struct config_setting
80 config_settings[0] __table_start ( config_settings );
81 static struct config_setting
82 config_settings_end[0] __table_end ( config_settings );
83 #define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
86 * Load setting widget value from configuration context
88 * @v widget Setting widget
91 static void load_setting ( struct setting_widget *widget ) {
93 /* Mark as not editing */
96 /* Read current setting value */
97 if ( show_setting ( widget->context, widget->setting,
98 widget->value, sizeof ( widget->value ) ) != 0 ) {
99 widget->value[0] = '\0';
102 /* Initialise edit box */
103 init_editbox ( &widget->editbox, widget->value,
104 sizeof ( widget->value ), NULL, widget->row,
105 ( widget->col + offsetof ( struct setting_row, value )),
106 sizeof ( ( ( struct setting_row * ) NULL )->value ) );
110 * Save setting widget value back to configuration context
112 * @v widget Setting widget
114 static int save_setting ( struct setting_widget *widget ) {
115 return set_setting ( widget->context, widget->setting, widget->value );
119 * Initialise setting widget
121 * @v widget Setting widget
122 * @v context Configuration context
123 * @v setting Configuration setting
125 * @v col Screen column
127 static void init_setting ( struct setting_widget *widget,
128 struct config_context *context,
129 struct config_setting *setting,
130 unsigned int row, unsigned int col ) {
132 /* Initialise widget structure */
133 memset ( widget, 0, sizeof ( *widget ) );
134 widget->context = context;
135 widget->setting = setting;
139 /* Read current setting value */
140 load_setting ( widget );
144 * Draw setting widget
146 * @v widget Setting widget
148 static void draw_setting ( struct setting_widget *widget ) {
149 struct setting_row row;
151 unsigned int curs_col;
154 /* Fill row with spaces */
155 memset ( &row, ' ', sizeof ( row ) );
158 /* Construct dot-padded name */
159 memset ( row.name, '.', sizeof ( row.name ) );
160 len = strlen ( widget->setting->name );
161 if ( len > sizeof ( row.name ) )
162 len = sizeof ( row.name );
163 memcpy ( row.name, widget->setting->name, len );
165 /* Construct space-padded value */
166 value = widget->value;
168 value = "<not specified>";
169 len = strlen ( value );
170 if ( len > sizeof ( row.value ) )
171 len = sizeof ( row.value );
172 memcpy ( row.value, value, len );
173 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
177 mvprintw ( widget->row, widget->col, "%s", row.start );
178 move ( widget->row, curs_col );
179 if ( widget->editing )
180 draw_editbox ( &widget->editbox );
184 * Edit setting widget
186 * @v widget Setting widget
187 * @v key Key pressed by user
188 * @ret key Key returned to application, or zero
190 static int edit_setting ( struct setting_widget *widget, int key ) {
192 return edit_editbox ( &widget->editbox, key );
196 * Initialise setting widget by index
198 * @v widget Setting widget
199 * @v context Configuration context
200 * @v index Index of setting with settings list
202 static void init_setting_index ( struct setting_widget *widget,
203 struct config_context *context,
204 unsigned int index ) {
205 init_setting ( widget, context, &config_settings[index],
206 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
210 * Print message centred on specified row
213 * @v fmt printf() format string
214 * @v args printf() argument list
216 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
220 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
221 mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
225 * Print message centred on specified row
228 * @v fmt printf() format string
229 * @v .. printf() arguments
231 static void msg ( unsigned int row, const char *fmt, ... ) {
234 va_start ( args, fmt );
235 vmsg ( row, fmt, args );
240 * Clear message on specified row
244 static void clearmsg ( unsigned int row ) {
250 * Print alert message
252 * @v fmt printf() format string
253 * @v args printf() argument list
255 static void valert ( const char *fmt, va_list args ) {
256 color_set ( CPAIR_ALERT, NULL );
257 vmsg ( ALERT_ROW, fmt, args );
259 color_set ( CPAIR_NORMAL, NULL );
260 clearmsg ( ALERT_ROW );
264 * Print alert message
266 * @v fmt printf() format string
267 * @v ... printf() arguments
269 static void alert ( const char *fmt, ... ) {
272 va_start ( args, fmt );
273 valert ( fmt, args );
277 static void main_loop ( struct config_context *context ) {
278 struct setting_widget widget;
279 unsigned int current = 0;
285 /* Print initial screen content */
286 color_set ( CPAIR_NORMAL, NULL );
288 msg ( BANNER_ROW, "gPXE option configuration console" );
290 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
291 init_setting_index ( &widget, context, i );
292 draw_setting ( &widget );
296 /* Redraw information row */
297 clearmsg ( INFO_ROW );
298 msg ( INFO_ROW, "%s (%s) - %s", widget.setting->name,
299 widget.setting->type->description,
300 widget.setting->description );
302 /* Redraw current setting */
303 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
305 draw_setting ( &widget );
306 color_set ( CPAIR_NORMAL, NULL );
309 if ( widget.editing ) {
310 key = edit_setting ( &widget, key );
312 case 0x0a: /* Enter */
313 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
314 alert ( " Could not set %s: %s ",
315 widget.setting->name,
319 case 0x03: /* Ctrl-C */
320 load_setting ( &widget );
330 if ( next < ( NUM_SETTINGS - 1 ) )
338 edit_setting ( &widget, key );
341 if ( next != current ) {
342 draw_setting ( &widget );
343 init_setting_index ( &widget, context, next );
351 void uitest ( void ) {
352 struct config_context dummy_context;
354 dummy_context.options = ugly_nvo_hack->options;
358 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
359 init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
360 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
361 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
362 color_set ( CPAIR_NORMAL, NULL );
365 main_loop ( &dummy_context );