source: bootcd/isolinux/syslinux-6.03/gpxe/src/hci/tui/settings_ui.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 10.3 KB
Line 
1/*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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.
17 */
18
19FILE_LICENCE ( GPL2_OR_LATER );
20
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>
31
32/** @file
33 *
34 * Option configuration console
35 *
36 */
37
38/* Colour pairs */
39#define CPAIR_NORMAL    1
40#define CPAIR_SELECT    2
41#define CPAIR_EDIT      3
42#define CPAIR_ALERT     4
43
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 "     "
52
53/** Layout of text within a setting widget */
54struct 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 ));
63
64/** A setting widget */
65struct 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 */
80};
81
82/** Number of registered configuration settings */
83#define NUM_SETTINGS table_num_entries ( SETTINGS )
84
85static void load_setting ( struct setting_widget *widget ) __nonnull;
86static int save_setting ( struct setting_widget *widget ) __nonnull;
87static void init_setting ( struct setting_widget *widget,
88                           struct settings *settings,
89                           struct setting *setting,
90                           unsigned int row, unsigned int col ) __nonnull;
91static void draw_setting ( struct setting_widget *widget ) __nonnull;
92static int edit_setting ( struct setting_widget *widget, int key ) __nonnull;
93static void init_setting_index ( struct setting_widget *widget,
94                                 struct settings *settings,
95                                 unsigned int index ) __nonnull;
96static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull;
97static void msg ( unsigned int row, const char *fmt, ... ) __nonnull;
98static void valert ( const char *fmt, va_list args ) __nonnull;
99static void alert ( const char *fmt, ... ) __nonnull;
100static void draw_info_row ( struct setting *setting ) __nonnull;
101static int main_loop ( struct settings *settings ) __nonnull;
102
103/**
104 * Load setting widget value from configuration settings
105 *
106 * @v widget            Setting widget
107 *
108 */
109static void load_setting ( struct setting_widget *widget ) {
110
111        /* Mark as not editing */
112        widget->editing = 0;
113
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';
118        }       
119
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);
125}
126
127/**
128 * Save setting widget value back to configuration settings
129 *
130 * @v widget            Setting widget
131 */
132static int save_setting ( struct setting_widget *widget ) {
133        return storef_setting ( widget->settings, widget->setting,
134                                widget->value );
135}
136
137/**
138 * Initialise setting widget
139 *
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
145 */
146static void init_setting ( struct setting_widget *widget,
147                           struct settings *settings,
148                           struct setting *setting,
149                           unsigned int row, unsigned int col ) {
150
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;
157
158        /* Read current setting value */
159        load_setting ( widget );
160}
161
162/**
163 * Draw setting widget
164 *
165 * @v widget            Setting widget
166 */
167static void draw_setting ( struct setting_widget *widget ) {
168        struct setting_row row;
169        unsigned int len;
170        unsigned int curs_col;
171        char *value;
172
173        /* Fill row with spaces */
174        memset ( &row, ' ', sizeof ( row ) );
175        row.nul = '\0';
176
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 );
183
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 );
194
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 );
200}
201
202/**
203 * Edit setting widget
204 *
205 * @v widget            Setting widget
206 * @v key               Key pressed by user
207 * @ret key             Key returned to application, or zero
208 */
209static int edit_setting ( struct setting_widget *widget, int key ) {
210        widget->editing = 1;
211        return edit_editbox ( &widget->editbox, key );
212}
213
214/**
215 * Initialise setting widget by index
216 *
217 * @v widget            Setting widget
218 * @v settings          Settings block
219 * @v index             Index of setting with settings list
220 */
221static void init_setting_index ( struct setting_widget *widget,
222                                 struct settings *settings,
223                                 unsigned int index ) {
224        struct setting *all_settings = table_start ( SETTINGS );
225
226        init_setting ( widget, settings, &all_settings[index],
227                       ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
228}
229
230/**
231 * Print message centred on specified row
232 *
233 * @v row               Row
234 * @v fmt               printf() format string
235 * @v args              printf() argument list
236 */
237static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
238        char buf[COLS];
239        size_t len;
240
241        len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
242        mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
243}
244
245/**
246 * Print message centred on specified row
247 *
248 * @v row               Row
249 * @v fmt               printf() format string
250 * @v ..                printf() arguments
251 */
252static void msg ( unsigned int row, const char *fmt, ... ) {
253        va_list args;
254
255        va_start ( args, fmt );
256        vmsg ( row, fmt, args );
257        va_end ( args );
258}
259
260/**
261 * Clear message on specified row
262 *
263 * @v row               Row
264 */
265static void clearmsg ( unsigned int row ) {
266        move ( row, 0 );
267        clrtoeol();
268}
269
270/**
271 * Print alert message
272 *
273 * @v fmt               printf() format string
274 * @v args              printf() argument list
275 */
276static 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 );
283}
284
285/**
286 * Print alert message
287 *
288 * @v fmt               printf() format string
289 * @v ...               printf() arguments
290 */
291static void alert ( const char *fmt, ... ) {
292        va_list args;
293
294        va_start ( args, fmt );
295        valert ( fmt, args );
296        va_end ( args );
297}
298
299/**
300 * Draw title row
301 */
302static void draw_title_row ( void ) {
303        attron ( A_BOLD );
304        msg ( TITLE_ROW, "gPXE option configuration console" );
305        attroff ( A_BOLD );
306}
307
308/**
309 * Draw information row
310 *
311 * @v setting           Current configuration setting
312 */
313static 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 );
318}
319
320/**
321 * Draw instruction row
322 *
323 * @v editing           Editing in progress flag
324 */
325static 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" );
334        }
335}
336
337static 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;
344
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 );
351        }
352
353        while ( 1 ) {
354                /* Redraw information and instruction rows */
355                draw_info_row ( widget.setting );
356                draw_instruction_row ( widget.editing );
357
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 );
363
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 ) );
374                                }
375                                /* Fall through */
376                        case CTRL_C:
377                                load_setting ( &widget );
378                                break;
379                        default:
380                                /* Do nothing */
381                                break;
382                        }
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;
399                        }       
400                        if ( next != current ) {
401                                draw_setting ( &widget );
402                                init_setting_index ( &widget, settings, next );
403                                current = next;
404                        }
405                }
406        }
407       
408}
409
410int settings_ui ( struct settings *settings ) {
411        int rc;
412
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();
421       
422        rc = main_loop ( settings );
423
424        endwin();
425
426        return rc;
427}
Note: See TracBrowser for help on using the repository browser.