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
);
27 #include <gpxe/settings.h>
28 #include <gpxe/editbox.h>
29 #include <gpxe/keys.h>
30 #include <gpxe/settings_ui.h>
34 * Option configuration console
39 #define CPAIR_NORMAL 1
40 #define CPAIR_SELECT 2
46 #define SETTINGS_LIST_ROW 3
47 #define SETTINGS_LIST_COL 1
48 #define SETTINGS_LIST_ROWS 16
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
{
68 struct settings
*settings
;
69 /** Index of the first visible setting, for scrolling. */
70 unsigned int first_visible
;
71 /** Configuration setting */
72 struct setting
*setting
;
77 /** Edit box widget used for editing setting */
78 struct edit_box editbox
;
79 /** Editing in progress flag */
81 /** Buffer for setting's value */
82 char value
[256]; /* enough size for a DHCP string */
85 /** Number of registered configuration settings */
86 #define NUM_SETTINGS table_num_entries ( SETTINGS )
88 static void load_setting ( struct setting_widget
*widget
) __nonnull
;
89 static int save_setting ( struct setting_widget
*widget
) __nonnull
;
90 static void init_widget ( struct setting_widget
*widget
,
91 struct settings
*settings
) __nonnull
;
92 static void draw_setting ( struct setting_widget
*widget
) __nonnull
;
93 static int edit_setting ( struct setting_widget
*widget
, int key
) __nonnull
;
94 static void select_setting ( struct setting_widget
*widget
,
95 unsigned int index
) __nonnull
;
96 static void reveal ( struct setting_widget
*widget
, unsigned int n
) __nonnull
;
97 static void vmsg ( unsigned int row
, const char *fmt
, va_list args
) __nonnull
;
98 static void msg ( unsigned int row
, const char *fmt
, ... ) __nonnull
;
99 static void valert ( const char *fmt
, va_list args
) __nonnull
;
100 static void alert ( const char *fmt
, ... ) __nonnull
;
101 static void draw_info_row ( struct setting
*setting
) __nonnull
;
102 static int main_loop ( struct settings
*settings
) __nonnull
;
105 * Load setting widget value from configuration settings
107 * @v widget Setting widget
110 static void load_setting ( struct setting_widget
*widget
) {
112 /* Mark as not editing */
115 /* Read current setting value */
116 if ( fetchf_setting ( widget
->settings
, widget
->setting
,
117 widget
->value
, sizeof ( widget
->value
) ) < 0 ) {
118 widget
->value
[0] = '\0';
121 /* Initialise edit box */
122 init_editbox ( &widget
->editbox
, widget
->value
,
123 sizeof ( widget
->value
), NULL
, widget
->row
,
124 ( widget
->col
+ offsetof ( struct setting_row
, value
)),
125 sizeof ( ( ( struct setting_row
* ) NULL
)->value
), 0);
129 * Save setting widget value back to configuration settings
131 * @v widget Setting widget
133 static int save_setting ( struct setting_widget
*widget
) {
134 return storef_setting ( widget
->settings
, widget
->setting
,
139 * Initialise the scrolling setting widget, drawing initial display.
141 * @v widget Setting widget
142 * @v settings Settings block
144 static void init_widget ( struct setting_widget
*widget
,
145 struct settings
*settings
) {
146 memset ( widget
, 0, sizeof ( *widget
) );
147 widget
->settings
= settings
;
148 widget
->first_visible
= SETTINGS_LIST_ROWS
;
149 reveal ( widget
, 0 );
153 * Draw setting widget
155 * @v widget Setting widget
157 static void draw_setting ( struct setting_widget
*widget
) {
158 struct setting_row row
;
160 unsigned int curs_col
;
163 /* Fill row with spaces */
164 memset ( &row
, ' ', sizeof ( row
) );
167 /* Construct dot-padded name */
168 memset ( row
.name
, '.', sizeof ( row
.name
) );
169 len
= strlen ( widget
->setting
->name
);
170 if ( len
> sizeof ( row
.name
) )
171 len
= sizeof ( row
.name
);
172 memcpy ( row
.name
, widget
->setting
->name
, len
);
174 /* Construct space-padded value */
175 value
= widget
->value
;
177 value
= "<not specified>";
178 len
= strlen ( value
);
179 if ( len
> sizeof ( row
.value
) )
180 len
= sizeof ( row
.value
);
181 memcpy ( row
.value
, value
, len
);
182 curs_col
= ( widget
->col
+ offsetof ( typeof ( row
), value
)
186 mvprintw ( widget
->row
, widget
->col
, "%s", row
.start
);
187 move ( widget
->row
, curs_col
);
188 if ( widget
->editing
)
189 draw_editbox ( &widget
->editbox
);
193 * Edit setting widget
195 * @v widget Setting widget
196 * @v key Key pressed by user
197 * @ret key Key returned to application, or zero
199 static int edit_setting ( struct setting_widget
*widget
, int key
) {
201 return edit_editbox ( &widget
->editbox
, key
);
205 * Select a setting for display updates, by index.
207 * @v widget Setting widget
208 * @v settings Settings block
209 * @v index Index of setting with settings list
211 static void select_setting ( struct setting_widget
*widget
,
212 unsigned int index
) {
213 struct setting
*all_settings
= table_start ( SETTINGS
);
214 unsigned int skip
= offsetof ( struct setting_widget
, setting
);
216 /* Reset the widget, preserving static state. */
217 memset ( ( char * ) widget
+ skip
, 0, sizeof ( *widget
) - skip
);
218 widget
->setting
= &all_settings
[index
];
219 widget
->row
= SETTINGS_LIST_ROW
+ index
- widget
->first_visible
;
220 widget
->col
= SETTINGS_LIST_COL
;
222 /* Read current setting value */
223 load_setting ( widget
);
227 * Print message centred on specified row
230 * @v fmt printf() format string
231 * @v args printf() argument list
233 static void vmsg ( unsigned int row
, const char *fmt
, va_list args
) {
237 len
= vsnprintf ( buf
, sizeof ( buf
), fmt
, args
);
238 mvprintw ( row
, ( ( COLS
- len
) / 2 ), "%s", buf
);
242 * Print message centred on specified row
245 * @v fmt printf() format string
246 * @v .. printf() arguments
248 static void msg ( unsigned int row
, const char *fmt
, ... ) {
251 va_start ( args
, fmt
);
252 vmsg ( row
, fmt
, args
);
257 * Clear message on specified row
261 static void clearmsg ( unsigned int row
) {
267 * Print alert message
269 * @v fmt printf() format string
270 * @v args printf() argument list
272 static void valert ( const char *fmt
, va_list args
) {
273 clearmsg ( ALERT_ROW
);
274 color_set ( CPAIR_ALERT
, NULL
);
275 vmsg ( ALERT_ROW
, fmt
, args
);
277 color_set ( CPAIR_NORMAL
, NULL
);
278 clearmsg ( ALERT_ROW
);
282 * Print alert message
284 * @v fmt printf() format string
285 * @v ... printf() arguments
287 static void alert ( const char *fmt
, ... ) {
290 va_start ( args
, fmt
);
291 valert ( fmt
, args
);
298 static void draw_title_row ( void ) {
300 msg ( TITLE_ROW
, "gPXE option configuration console" );
305 * Draw information row
307 * @v setting Current configuration setting
309 static void draw_info_row ( struct setting
*setting
) {
310 clearmsg ( INFO_ROW
);
312 msg ( INFO_ROW
, "%s - %s", setting
->name
, setting
->description
);
317 * Draw instruction row
319 * @v editing Editing in progress flag
321 static void draw_instruction_row ( int editing
) {
322 clearmsg ( INSTRUCTION_ROW
);
324 msg ( INSTRUCTION_ROW
,
325 "Enter - accept changes" INSTRUCTION_PAD
326 "Ctrl-C - discard changes" );
328 msg ( INSTRUCTION_ROW
,
329 "Ctrl-D - delete setting" INSTRUCTION_PAD
330 "Ctrl-X - exit configuration utility" );
335 * Reveal a setting by index: Scroll the setting list to reveal the
338 * @widget The main loop's display widget.
339 * @n The index of the setting to reveal.
341 static void reveal ( struct setting_widget
*widget
, unsigned int n
)
345 /* Simply return if setting N is already on-screen. */
346 if ( n
- widget
->first_visible
< SETTINGS_LIST_ROWS
)
349 /* Jump scroll to make the specified setting visible. */
350 while ( widget
->first_visible
< n
)
351 widget
->first_visible
+= SETTINGS_LIST_ROWS
;
352 while ( widget
->first_visible
> n
)
353 widget
->first_visible
-= SETTINGS_LIST_ROWS
;
355 /* Draw elipses before and/or after the settings list to
356 represent any invisible settings. */
357 mvaddstr ( SETTINGS_LIST_ROW
- 1,
358 SETTINGS_LIST_COL
+ 1,
359 widget
->first_visible
> 0 ? "..." : " " );
360 mvaddstr ( SETTINGS_LIST_ROW
+ SETTINGS_LIST_ROWS
,
361 SETTINGS_LIST_COL
+ 1,
362 ( widget
->first_visible
+ SETTINGS_LIST_ROWS
< NUM_SETTINGS
366 /* Draw visible settings. */
367 for ( i
= 0; i
< SETTINGS_LIST_ROWS
; i
++ ) {
368 if ( widget
->first_visible
+ i
< NUM_SETTINGS
) {
369 select_setting ( widget
, widget
->first_visible
+ i
);
370 draw_setting ( widget
);
372 clearmsg ( SETTINGS_LIST_ROW
+ i
);
376 /* Set the widget to the current row, which will be redrawn
377 appropriately by the main loop. */
378 select_setting ( widget
, n
);
381 static int main_loop ( struct settings
*settings
) {
382 struct setting_widget widget
;
383 unsigned int current
= 0;
388 /* Print initial screen content */
390 color_set ( CPAIR_NORMAL
, NULL
);
391 init_widget ( &widget
, settings
);
394 /* Redraw information and instruction rows */
395 draw_info_row ( widget
.setting
);
396 draw_instruction_row ( widget
.editing
);
398 /* Redraw current setting */
399 color_set ( ( widget
.editing
? CPAIR_EDIT
: CPAIR_SELECT
),
401 draw_setting ( &widget
);
402 color_set ( CPAIR_NORMAL
, NULL
);
405 if ( widget
.editing
) {
406 key
= edit_setting ( &widget
, key
);
410 if ( ( rc
= save_setting ( &widget
) ) != 0 ) {
411 alert ( " Could not set %s: %s ",
412 widget
.setting
->name
,
417 load_setting ( &widget
);
427 if ( next
< ( NUM_SETTINGS
- 1 ) )
428 reveal ( &widget
, ++next
);
432 reveal ( &widget
, --next
) ;
435 delete_setting ( widget
.settings
,
437 select_setting ( &widget
, next
);
438 draw_setting ( &widget
);
443 edit_setting ( &widget
, key
);
446 if ( next
!= current
) {
447 draw_setting ( &widget
);
448 select_setting ( &widget
, next
);
456 int settings_ui ( struct settings
*settings
) {
461 init_pair ( CPAIR_NORMAL
, COLOR_WHITE
, COLOR_BLUE
);
462 init_pair ( CPAIR_SELECT
, COLOR_WHITE
, COLOR_RED
);
463 init_pair ( CPAIR_EDIT
, COLOR_BLACK
, COLOR_CYAN
);
464 init_pair ( CPAIR_ALERT
, COLOR_WHITE
, COLOR_RED
);
465 color_set ( CPAIR_NORMAL
, NULL
);
468 rc
= main_loop ( settings
);