Add memtest support.
[syslinux-debian/hramrach.git] / gpxe / src / hci / tui / settings_ui.c
blob74ce6afb136a6ba18f518664df1b8a237b5da8dc
1 /*
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.
19 FILE_LICENCE ( GPL2_OR_LATER );
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <curses.h>
26 #include <console.h>
27 #include <gpxe/settings.h>
28 #include <gpxe/editbox.h>
29 #include <gpxe/keys.h>
30 #include <gpxe/settings_ui.h>
32 /** @file
34 * Option configuration console
38 /* Colour pairs */
39 #define CPAIR_NORMAL 1
40 #define CPAIR_SELECT 2
41 #define CPAIR_EDIT 3
42 #define CPAIR_ALERT 4
44 /* Screen layout */
45 #define TITLE_ROW 1
46 #define SETTINGS_LIST_ROW 3
47 #define SETTINGS_LIST_COL 1
48 #define INFO_ROW 20
49 #define ALERT_ROW 20
50 #define INSTRUCTION_ROW 22
51 #define INSTRUCTION_PAD " "
53 /** Layout of text within a setting widget */
54 struct setting_row {
55 char start[0];
56 char pad1[1];
57 char name[15];
58 char pad2[1];
59 char value[60];
60 char pad3[1];
61 char nul;
62 } __attribute__ (( packed ));
64 /** A setting widget */
65 struct setting_widget {
66 /** Settings block */
67 struct settings *settings;
68 /** Configuration setting */
69 struct setting *setting;
70 /** Screen row */
71 unsigned int row;
72 /** Screen column */
73 unsigned int col;
74 /** Edit box widget used for editing setting */
75 struct edit_box editbox;
76 /** Editing in progress flag */
77 int editing;
78 /** Buffer for setting's value */
79 char value[256]; /* enough size for a DHCP string */
82 /** Number of registered configuration settings */
83 #define NUM_SETTINGS table_num_entries ( SETTINGS )
85 static void load_setting ( struct setting_widget *widget ) __nonnull;
86 static int save_setting ( struct setting_widget *widget ) __nonnull;
87 static void init_setting ( struct setting_widget *widget,
88 struct settings *settings,
89 struct setting *setting,
90 unsigned int row, unsigned int col ) __nonnull;
91 static void draw_setting ( struct setting_widget *widget ) __nonnull;
92 static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
93 static void init_setting_index ( struct setting_widget *widget,
94 struct settings *settings,
95 unsigned int index ) __nonnull;
96 static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
97 static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
98 static void valert ( const char *fmt, va_list args ) __nonnull;
99 static void alert ( const char *fmt, ... ) __nonnull;
100 static void draw_info_row ( struct setting *setting ) __nonnull;
101 static int main_loop ( struct settings *settings ) __nonnull;
104 * Load setting widget value from configuration settings
106 * @v widget Setting widget
109 static void load_setting ( struct setting_widget *widget ) {
111 /* Mark as not editing */
112 widget->editing = 0;
114 /* Read current setting value */
115 if ( fetchf_setting ( widget->settings, widget->setting,
116 widget->value, sizeof ( widget->value ) ) < 0 ) {
117 widget->value[0] = '\0';
120 /* Initialise edit box */
121 init_editbox ( &widget->editbox, widget->value,
122 sizeof ( widget->value ), NULL, widget->row,
123 ( widget->col + offsetof ( struct setting_row, value )),
124 sizeof ( ( ( struct setting_row * ) NULL )->value ), 0);
128 * Save setting widget value back to configuration settings
130 * @v widget Setting widget
132 static int save_setting ( struct setting_widget *widget ) {
133 return storef_setting ( widget->settings, widget->setting,
134 widget->value );
138 * Initialise setting widget
140 * @v widget Setting widget
141 * @v settings Settings block
142 * @v setting Configuration setting
143 * @v row Screen row
144 * @v col Screen column
146 static void init_setting ( struct setting_widget *widget,
147 struct settings *settings,
148 struct setting *setting,
149 unsigned int row, unsigned int col ) {
151 /* Initialise widget structure */
152 memset ( widget, 0, sizeof ( *widget ) );
153 widget->settings = settings;
154 widget->setting = setting;
155 widget->row = row;
156 widget->col = col;
158 /* Read current setting value */
159 load_setting ( widget );
163 * Draw setting widget
165 * @v widget Setting widget
167 static void draw_setting ( struct setting_widget *widget ) {
168 struct setting_row row;
169 unsigned int len;
170 unsigned int curs_col;
171 char *value;
173 /* Fill row with spaces */
174 memset ( &row, ' ', sizeof ( row ) );
175 row.nul = '\0';
177 /* Construct dot-padded name */
178 memset ( row.name, '.', sizeof ( row.name ) );
179 len = strlen ( widget->setting->name );
180 if ( len > sizeof ( row.name ) )
181 len = sizeof ( row.name );
182 memcpy ( row.name, widget->setting->name, len );
184 /* Construct space-padded value */
185 value = widget->value;
186 if ( ! *value )
187 value = "<not specified>";
188 len = strlen ( value );
189 if ( len > sizeof ( row.value ) )
190 len = sizeof ( row.value );
191 memcpy ( row.value, value, len );
192 curs_col = ( widget->col + offsetof ( typeof ( row ), value )
193 + len );
195 /* Print row */
196 mvprintw ( widget->row, widget->col, "%s", row.start );
197 move ( widget->row, curs_col );
198 if ( widget->editing )
199 draw_editbox ( &widget->editbox );
203 * Edit setting widget
205 * @v widget Setting widget
206 * @v key Key pressed by user
207 * @ret key Key returned to application, or zero
209 static int edit_setting ( struct setting_widget *widget, int key ) {
210 widget->editing = 1;
211 return edit_editbox ( &widget->editbox, key );
215 * Initialise setting widget by index
217 * @v widget Setting widget
218 * @v settings Settings block
219 * @v index Index of setting with settings list
221 static void init_setting_index ( struct setting_widget *widget,
222 struct settings *settings,
223 unsigned int index ) {
224 struct setting *all_settings = table_start ( SETTINGS );
226 init_setting ( widget, settings, &all_settings[index],
227 ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
231 * Print message centred on specified row
233 * @v row Row
234 * @v fmt printf() format string
235 * @v args printf() argument list
237 static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
238 char buf[COLS];
239 size_t len;
241 len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
242 mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
246 * Print message centred on specified row
248 * @v row Row
249 * @v fmt printf() format string
250 * @v .. printf() arguments
252 static void msg ( unsigned int row, const char *fmt, ... ) {
253 va_list args;
255 va_start ( args, fmt );
256 vmsg ( row, fmt, args );
257 va_end ( args );
261 * Clear message on specified row
263 * @v row Row
265 static void clearmsg ( unsigned int row ) {
266 move ( row, 0 );
267 clrtoeol();
271 * Print alert message
273 * @v fmt printf() format string
274 * @v args printf() argument list
276 static void valert ( const char *fmt, va_list args ) {
277 clearmsg ( ALERT_ROW );
278 color_set ( CPAIR_ALERT, NULL );
279 vmsg ( ALERT_ROW, fmt, args );
280 sleep ( 2 );
281 color_set ( CPAIR_NORMAL, NULL );
282 clearmsg ( ALERT_ROW );
286 * Print alert message
288 * @v fmt printf() format string
289 * @v ... printf() arguments
291 static void alert ( const char *fmt, ... ) {
292 va_list args;
294 va_start ( args, fmt );
295 valert ( fmt, args );
296 va_end ( args );
300 * Draw title row
302 static void draw_title_row ( void ) {
303 attron ( A_BOLD );
304 msg ( TITLE_ROW, "gPXE option configuration console" );
305 attroff ( A_BOLD );
309 * Draw information row
311 * @v setting Current configuration setting
313 static void draw_info_row ( struct setting *setting ) {
314 clearmsg ( INFO_ROW );
315 attron ( A_BOLD );
316 msg ( INFO_ROW, "%s - %s", setting->name, setting->description );
317 attroff ( A_BOLD );
321 * Draw instruction row
323 * @v editing Editing in progress flag
325 static void draw_instruction_row ( int editing ) {
326 clearmsg ( INSTRUCTION_ROW );
327 if ( editing ) {
328 msg ( INSTRUCTION_ROW,
329 "Enter - accept changes" INSTRUCTION_PAD
330 "Ctrl-C - discard changes" );
331 } else {
332 msg ( INSTRUCTION_ROW,
333 "Ctrl-X - exit configuration utility" );
337 static int main_loop ( struct settings *settings ) {
338 struct setting_widget widget;
339 unsigned int current = 0;
340 unsigned int next;
341 int i;
342 int key;
343 int rc;
345 /* Print initial screen content */
346 draw_title_row();
347 color_set ( CPAIR_NORMAL, NULL );
348 for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
349 init_setting_index ( &widget, settings, i );
350 draw_setting ( &widget );
353 while ( 1 ) {
354 /* Redraw information and instruction rows */
355 draw_info_row ( widget.setting );
356 draw_instruction_row ( widget.editing );
358 /* Redraw current setting */
359 color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
360 NULL );
361 draw_setting ( &widget );
362 color_set ( CPAIR_NORMAL, NULL );
364 key = getkey();
365 if ( widget.editing ) {
366 key = edit_setting ( &widget, key );
367 switch ( key ) {
368 case CR:
369 case LF:
370 if ( ( rc = save_setting ( &widget ) ) != 0 ) {
371 alert ( " Could not set %s: %s ",
372 widget.setting->name,
373 strerror ( rc ) );
375 /* Fall through */
376 case CTRL_C:
377 load_setting ( &widget );
378 break;
379 default:
380 /* Do nothing */
381 break;
383 } else {
384 next = current;
385 switch ( key ) {
386 case KEY_DOWN:
387 if ( next < ( NUM_SETTINGS - 1 ) )
388 next++;
389 break;
390 case KEY_UP:
391 if ( next > 0 )
392 next--;
393 break;
394 case CTRL_X:
395 return 0;
396 default:
397 edit_setting ( &widget, key );
398 break;
400 if ( next != current ) {
401 draw_setting ( &widget );
402 init_setting_index ( &widget, settings, next );
403 current = next;
410 int settings_ui ( struct settings *settings ) {
411 int rc;
413 initscr();
414 start_color();
415 init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
416 init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
417 init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
418 init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
419 color_set ( CPAIR_NORMAL, NULL );
420 erase();
422 rc = main_loop ( settings );
424 endwin();
426 return rc;