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.
23 #include <gpxe/settings.h>
24 #include <gpxe/editbox.h>
28 * Configuration settings UI
33 extern struct nvo_block *ugly_nvo_hack;
36 #define CPAIR_NORMAL 1
37 #define CPAIR_SELECT 2
42 #define SETTINGS_LIST_ROW 3
43 #define SETTINGS_LIST_COL 1
46 /** Layout of text within a setting widget */
55 } __attribute__ (( packed ));
57 /** A setting widget */
58 struct setting_widget {
59 /** Configuration context */
60 struct config_context *context;
61 /** Configuration setting */
62 struct config_setting *setting;
67 /** Edit box widget used for editing setting */
68 struct edit_box editbox;
69 /** Editing active flag */
71 /** Buffer for setting's value */
72 char value[256]; /* enough size for a DHCP string */
75 /** Registered configuration settings */
76 static struct config_setting
77 config_settings[0] __table_start ( config_settings );
78 static struct config_setting
79 config_settings_end[0] __table_end ( config_settings );
80 #define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
83 * Load setting widget value from configuration context
85 * @v widget Setting widget
88 static void load_setting ( struct setting_widget *widget ) {
90 /* Mark as not editing */
93 /* Read current setting value */
94 if ( widget->setting->type->show ( widget->context, widget->setting,
96 sizeof ( widget->value ) ) != 0 ) {
97 widget->value[0] = '\0';
100 /* Initialise edit box */
101 init_editbox ( &widget->editbox, widget->value,
102 sizeof ( widget->value ), NULL, widget->row,
103 ( widget->col + offsetof ( struct setting_row, value )),
104 sizeof ( ( ( struct setting_row * ) NULL )->value ) );
108 * Save setting widget value back to configuration context
110 * @v widget Setting widget
112 static int save_setting ( struct setting_widget *widget ) {
113 return widget->setting->type->set ( widget->context, widget->setting,
118 * Initialise setting widget
120 * @v widget Setting widget
121 * @v context Configuration context
122 * @v setting Configuration setting
124 * @v col Screen column
126 static void init_setting ( struct setting_widget *widget,
127 struct config_context *context,
128 struct config_setting *setting,
129 unsigned int row, unsigned int col ) {
131 /* Initialise widget structure */
132 memset ( widget, 0, sizeof ( *widget ) );
133 widget->context = context;
134 widget->setting = setting;
138 /* Read current setting value */
139 load_setting ( widget );
143 * Draw setting widget
145 * @v widget Setting widget
147 static void draw_setting ( struct setting_widget *widget ) {
148 struct setting_row row;
150 unsigned int curs_col;
153 /* Fill row with spaces */
154 memset ( &row, ' ', sizeof ( row ) );
157 /* Construct dot-padded name */
158 memset ( row.name, '.', sizeof ( row.name ) );
159 len = strlen ( widget->setting->name );
160 if ( len > sizeof ( row.name ) )
161 len = sizeof ( row.name );
162 memcpy ( row.name, widget->setting->name, len );
164 /* Construct space-padded value */
165 value = widget->value;
167 value = "<not specified>";
168 len = strlen ( value );
169 if ( len > sizeof ( row.value ) )
170 len = sizeof ( row.value );
171 memcpy ( row.value, value, len );
172 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
176 mvprintw ( widget->row, widget->col, "%s", row.start );
177 move ( widget->row, curs_col );
178 if ( widget->editing )
179 draw_editbox ( &widget->editbox );
183 * Edit setting widget
185 * @v widget Setting widget
186 * @v key Key pressed by user
187 * @ret key Key returned to application, or zero
189 static int edit_setting ( struct setting_widget *widget, int key ) {
191 return edit_editbox ( &widget->editbox, key );
195 * Initialise setting widget by index
197 * @v widget Setting widget
198 * @v context Configuration context
199 * @v index Index of setting with settings list
201 static void init_setting_index ( struct setting_widget *widget,
202 struct config_context *context,
203 unsigned int index ) {
204 init_setting ( widget, context, &config_settings[index],
205 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
208 static void alert ( const char *fmt, ... ) {
213 va_start ( args, fmt );
214 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
217 color_set ( CPAIR_ALERT, NULL );
218 mvprintw ( ALERT_ROW, ( ( COLS - len ) / 2 ), "%s", buf );
220 color_set ( CPAIR_NORMAL, NULL );
221 move ( ALERT_ROW, 0 );
225 static void main_loop ( struct config_context *context ) {
226 struct setting_widget widget;
227 unsigned int current = 0;
233 /* Print initial screen content */
234 color_set ( CPAIR_NORMAL, NULL );
235 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
236 init_setting_index ( &widget, context, i );
237 draw_setting ( &widget );
241 /* Redraw current setting */
242 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
244 draw_setting ( &widget );
245 color_set ( CPAIR_NORMAL, NULL );
248 if ( widget.editing ) {
249 key = edit_setting ( &widget, key );
251 case 0x0a: /* Enter */
252 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
253 alert ( " Could not set %s: %s ",
254 widget.setting->name,
258 case 0x03: /* Ctrl-C */
259 load_setting ( &widget );
269 if ( next < ( NUM_SETTINGS - 1 ) )
277 edit_setting ( &widget, key );
280 if ( next != current ) {
281 draw_setting ( &widget );
282 init_setting_index ( &widget, context, next );
290 void uitest ( void ) {
291 struct config_context dummy_context;
293 dummy_context.options = ugly_nvo_hack->options;
297 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
298 init_pair ( CPAIR_SELECT, COLOR_BLACK, COLOR_WHITE );
299 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
300 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
301 color_set ( CPAIR_NORMAL, NULL );
304 main_loop ( &dummy_context );