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.
25 #include <gpxe/settings.h>
26 #include <gpxe/editbox.h>
27 #include <gpxe/keys.h>
28 #include <gpxe/settings_ui.h>
32 * Option configuration console
37 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 ) )
90 static void load_setting ( struct setting_widget *widget ) __nonnull;
91 static int save_setting ( struct setting_widget *widget ) __nonnull;
92 static void init_setting ( struct setting_widget *widget,
93 struct config_context *context,
94 struct config_setting *setting,
95 unsigned int row, unsigned int col ) __nonnull;
96 static void draw_setting ( struct setting_widget *widget ) __nonnull;
97 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
98 static void init_setting_index ( struct setting_widget *widget,
99 struct config_context *context,
100 unsigned int index ) __nonnull;
101 static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
102 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
103 static void valert ( const char *fmt, va_list args ) __nonnull;
104 static void alert ( const char *fmt, ... ) __nonnull;
105 static void draw_info_row ( struct config_setting *setting ) __nonnull;
106 static int main_loop ( struct config_context *context ) __nonnull;
109 * Load setting widget value from configuration context
111 * @v widget Setting widget
114 static void load_setting ( struct setting_widget *widget ) {
116 /* Mark as not editing */
119 /* Read current setting value */
120 if ( show_setting ( widget->context, widget->setting,
121 widget->value, sizeof ( widget->value ) ) != 0 ) {
122 widget->value[0] = '\0';
125 /* Initialise edit box */
126 init_editbox ( &widget->editbox, widget->value,
127 sizeof ( widget->value ), NULL, widget->row,
128 ( widget->col + offsetof ( struct setting_row, value )),
129 sizeof ( ( ( struct setting_row * ) NULL )->value ) );
133 * Save setting widget value back to configuration context
135 * @v widget Setting widget
137 static int save_setting ( struct setting_widget *widget ) {
138 return set_setting ( widget->context, widget->setting, widget->value );
142 * Initialise setting widget
144 * @v widget Setting widget
145 * @v context Configuration context
146 * @v setting Configuration setting
148 * @v col Screen column
150 static void init_setting ( struct setting_widget *widget,
151 struct config_context *context,
152 struct config_setting *setting,
153 unsigned int row, unsigned int col ) {
155 /* Initialise widget structure */
156 memset ( widget, 0, sizeof ( *widget ) );
157 widget->context = context;
158 widget->setting = setting;
162 /* Read current setting value */
163 load_setting ( widget );
167 * Draw setting widget
169 * @v widget Setting widget
171 static void draw_setting ( struct setting_widget *widget ) {
172 struct setting_row row;
174 unsigned int curs_col;
177 /* Fill row with spaces */
178 memset ( &row, ' ', sizeof ( row ) );
181 /* Construct dot-padded name */
182 memset ( row.name, '.', sizeof ( row.name ) );
183 len = strlen ( widget->setting->name );
184 if ( len > sizeof ( row.name ) )
185 len = sizeof ( row.name );
186 memcpy ( row.name, widget->setting->name, len );
188 /* Construct space-padded value */
189 value = widget->value;
191 value = "<not specified>";
192 len = strlen ( value );
193 if ( len > sizeof ( row.value ) )
194 len = sizeof ( row.value );
195 memcpy ( row.value, value, len );
196 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
200 mvprintw ( widget->row, widget->col, "%s", row.start );
201 move ( widget->row, curs_col );
202 if ( widget->editing )
203 draw_editbox ( &widget->editbox );
207 * Edit setting widget
209 * @v widget Setting widget
210 * @v key Key pressed by user
211 * @ret key Key returned to application, or zero
213 static int edit_setting ( struct setting_widget *widget, int key ) {
215 return edit_editbox ( &widget->editbox, key );
219 * Initialise setting widget by index
221 * @v widget Setting widget
222 * @v context Configuration context
223 * @v index Index of setting with settings list
225 static void init_setting_index ( struct setting_widget *widget,
226 struct config_context *context,
227 unsigned int index ) {
228 init_setting ( widget, context, &config_settings[index],
229 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
233 * Print message centred on specified row
236 * @v fmt printf() format string
237 * @v args printf() argument list
239 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
243 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
244 mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
248 * Print message centred on specified row
251 * @v fmt printf() format string
252 * @v .. printf() arguments
254 static void msg ( unsigned int row, const char *fmt, ... ) {
257 va_start ( args, fmt );
258 vmsg ( row, fmt, args );
263 * Clear message on specified row
267 static void clearmsg ( unsigned int row ) {
273 * Print alert message
275 * @v fmt printf() format string
276 * @v args printf() argument list
278 static void valert ( const char *fmt, va_list args ) {
279 clearmsg ( ALERT_ROW );
280 color_set ( CPAIR_ALERT, NULL );
281 vmsg ( ALERT_ROW, fmt, args );
283 color_set ( CPAIR_NORMAL, NULL );
284 clearmsg ( ALERT_ROW );
288 * Print alert message
290 * @v fmt printf() format string
291 * @v ... printf() arguments
293 static void alert ( const char *fmt, ... ) {
296 va_start ( args, fmt );
297 valert ( fmt, args );
304 static void draw_title_row ( void ) {
306 msg ( TITLE_ROW, "gPXE option configuration console" );
311 * Draw information row
313 * @v setting Current configuration setting
315 static void draw_info_row ( struct config_setting *setting ) {
316 clearmsg ( INFO_ROW );
318 msg ( INFO_ROW, "%s (%s) - %s", setting->name,
319 setting->type->description, setting->description );
324 * Draw instruction row
326 * @v editing Editing in progress flag
328 static void draw_instruction_row ( int editing ) {
329 clearmsg ( INSTRUCTION_ROW );
331 msg ( INSTRUCTION_ROW,
332 "Enter - accept changes" INSTRUCTION_PAD
333 "Ctrl-C - discard changes" );
335 msg ( INSTRUCTION_ROW,
336 "Ctrl-S - save configuration" );
340 static int main_loop ( struct config_context *context ) {
341 struct setting_widget widget;
342 unsigned int current = 0;
348 /* Print initial screen content */
350 color_set ( CPAIR_NORMAL, NULL );
351 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
352 init_setting_index ( &widget, context, i );
353 draw_setting ( &widget );
357 /* Redraw information and instruction rows */
358 draw_info_row ( widget.setting );
359 draw_instruction_row ( widget.editing );
361 /* Redraw current setting */
362 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
364 draw_setting ( &widget );
365 color_set ( CPAIR_NORMAL, NULL );
368 if ( widget.editing ) {
369 key = edit_setting ( &widget, key );
373 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
374 alert ( " Could not set %s: %s ",
375 widget.setting->name,
380 load_setting ( &widget );
390 if ( next < ( NUM_SETTINGS - 1 ) )
398 if ( ( rc = nvo_save ( ugly_nvo_hack ) ) != 0){
399 alert ( " Could not save options: %s ",
404 edit_setting ( &widget, key );
407 if ( next != current ) {
408 draw_setting ( &widget );
409 init_setting_index ( &widget, context, next );
417 int settings_ui ( struct config_context *context ) {
422 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
423 init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
424 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
425 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
426 color_set ( CPAIR_NORMAL, NULL );
429 rc = main_loop ( context );