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 #define CPAIR_NORMAL 1
38 #define CPAIR_SELECT 2
44 #define SETTINGS_LIST_ROW 3
45 #define SETTINGS_LIST_COL 1
48 #define INSTRUCTION_ROW 22
49 #define INSTRUCTION_PAD " "
51 /** Layout of text within a setting widget */
60 } __attribute__ (( packed ));
62 /** A setting widget */
63 struct setting_widget {
65 struct settings *settings;
66 /** Configuration setting */
67 struct setting *setting;
72 /** Edit box widget used for editing setting */
73 struct edit_box editbox;
74 /** Editing in progress flag */
76 /** Buffer for setting's value */
77 char value[256]; /* enough size for a DHCP string */
80 /** Number of registered configuration settings */
81 #define NUM_SETTINGS table_num_entries ( struct setting, SETTINGS )
83 static void load_setting ( struct setting_widget *widget ) __nonnull;
84 static int save_setting ( struct setting_widget *widget ) __nonnull;
85 static void init_setting ( struct setting_widget *widget,
86 struct settings *settings,
87 struct setting *setting,
88 unsigned int row, unsigned int col ) __nonnull;
89 static void draw_setting ( struct setting_widget *widget ) __nonnull;
90 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
91 static void init_setting_index ( struct setting_widget *widget,
92 struct settings *settings,
93 unsigned int index ) __nonnull;
94 static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
95 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
96 static void valert ( const char *fmt, va_list args ) __nonnull;
97 static void alert ( const char *fmt, ... ) __nonnull;
98 static void draw_info_row ( struct setting *setting ) __nonnull;
99 static int main_loop ( struct settings *settings ) __nonnull;
102 * Load setting widget value from configuration settings
104 * @v widget Setting widget
107 static void load_setting ( struct setting_widget *widget ) {
109 /* Mark as not editing */
112 /* Read current setting value */
113 if ( fetchf_setting ( widget->settings, widget->setting,
114 widget->value, sizeof ( widget->value ) ) < 0 ) {
115 widget->value[0] = '\0';
118 /* Initialise edit box */
119 init_editbox ( &widget->editbox, widget->value,
120 sizeof ( widget->value ), NULL, widget->row,
121 ( widget->col + offsetof ( struct setting_row, value )),
122 sizeof ( ( ( struct setting_row * ) NULL )->value ), 0);
126 * Save setting widget value back to configuration settings
128 * @v widget Setting widget
130 static int save_setting ( struct setting_widget *widget ) {
131 return storef_setting ( widget->settings, widget->setting,
136 * Initialise setting widget
138 * @v widget Setting widget
139 * @v settings Settings block
140 * @v setting Configuration setting
142 * @v col Screen column
144 static void init_setting ( struct setting_widget *widget,
145 struct settings *settings,
146 struct setting *setting,
147 unsigned int row, unsigned int col ) {
149 /* Initialise widget structure */
150 memset ( widget, 0, sizeof ( *widget ) );
151 widget->settings = settings;
152 widget->setting = setting;
156 /* Read current setting value */
157 load_setting ( widget );
161 * Draw setting widget
163 * @v widget Setting widget
165 static void draw_setting ( struct setting_widget *widget ) {
166 struct setting_row row;
168 unsigned int curs_col;
171 /* Fill row with spaces */
172 memset ( &row, ' ', sizeof ( row ) );
175 /* Construct dot-padded name */
176 memset ( row.name, '.', sizeof ( row.name ) );
177 len = strlen ( widget->setting->name );
178 if ( len > sizeof ( row.name ) )
179 len = sizeof ( row.name );
180 memcpy ( row.name, widget->setting->name, len );
182 /* Construct space-padded value */
183 value = widget->value;
185 value = "<not specified>";
186 len = strlen ( value );
187 if ( len > sizeof ( row.value ) )
188 len = sizeof ( row.value );
189 memcpy ( row.value, value, len );
190 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
194 mvprintw ( widget->row, widget->col, "%s", row.start );
195 move ( widget->row, curs_col );
196 if ( widget->editing )
197 draw_editbox ( &widget->editbox );
201 * Edit setting widget
203 * @v widget Setting widget
204 * @v key Key pressed by user
205 * @ret key Key returned to application, or zero
207 static int edit_setting ( struct setting_widget *widget, int key ) {
209 return edit_editbox ( &widget->editbox, key );
213 * Initialise setting widget by index
215 * @v widget Setting widget
216 * @v settings Settings block
217 * @v index Index of setting with settings list
219 static void init_setting_index ( struct setting_widget *widget,
220 struct settings *settings,
221 unsigned int index ) {
222 struct setting *all_settings =
223 table_start ( struct setting, SETTINGS );
225 init_setting ( widget, settings, &all_settings[index],
226 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
230 * Print message centred on specified row
233 * @v fmt printf() format string
234 * @v args printf() argument list
236 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
240 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
241 mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
245 * Print message centred on specified row
248 * @v fmt printf() format string
249 * @v .. printf() arguments
251 static void msg ( unsigned int row, const char *fmt, ... ) {
254 va_start ( args, fmt );
255 vmsg ( row, fmt, args );
260 * Clear message on specified row
264 static void clearmsg ( unsigned int row ) {
270 * Print alert message
272 * @v fmt printf() format string
273 * @v args printf() argument list
275 static void valert ( const char *fmt, va_list args ) {
276 clearmsg ( ALERT_ROW );
277 color_set ( CPAIR_ALERT, NULL );
278 vmsg ( ALERT_ROW, fmt, args );
280 color_set ( CPAIR_NORMAL, NULL );
281 clearmsg ( ALERT_ROW );
285 * Print alert message
287 * @v fmt printf() format string
288 * @v ... printf() arguments
290 static void alert ( const char *fmt, ... ) {
293 va_start ( args, fmt );
294 valert ( fmt, args );
301 static void draw_title_row ( void ) {
303 msg ( TITLE_ROW, "gPXE option configuration console" );
308 * Draw information row
310 * @v setting Current configuration setting
312 static void draw_info_row ( struct setting *setting ) {
313 clearmsg ( INFO_ROW );
315 msg ( INFO_ROW, "%s - %s", setting->name, setting->description );
320 * Draw instruction row
322 * @v editing Editing in progress flag
324 static void draw_instruction_row ( int editing ) {
325 clearmsg ( INSTRUCTION_ROW );
327 msg ( INSTRUCTION_ROW,
328 "Enter - accept changes" INSTRUCTION_PAD
329 "Ctrl-C - discard changes" );
331 msg ( INSTRUCTION_ROW,
332 "Ctrl-X - exit configuration utility" );
336 static int main_loop ( struct settings *settings ) {
337 struct setting_widget widget;
338 unsigned int current = 0;
344 /* Print initial screen content */
346 color_set ( CPAIR_NORMAL, NULL );
347 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
348 init_setting_index ( &widget, settings, i );
349 draw_setting ( &widget );
353 /* Redraw information and instruction rows */
354 draw_info_row ( widget.setting );
355 draw_instruction_row ( widget.editing );
357 /* Redraw current setting */
358 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
360 draw_setting ( &widget );
361 color_set ( CPAIR_NORMAL, NULL );
364 if ( widget.editing ) {
365 key = edit_setting ( &widget, key );
369 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
370 alert ( " Could not set %s: %s ",
371 widget.setting->name,
376 load_setting ( &widget );
386 if ( next < ( NUM_SETTINGS - 1 ) )
396 edit_setting ( &widget, key );
399 if ( next != current ) {
400 draw_setting ( &widget );
401 init_setting_index ( &widget, settings, next );
409 int settings_ui ( struct settings *settings ) {
414 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
415 init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
416 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
417 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
418 color_set ( CPAIR_NORMAL, NULL );
421 rc = main_loop ( settings );