Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

settings_ui.c 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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. #include <stdarg.h>
  19. #include <unistd.h>
  20. #include <string.h>
  21. #include <curses.h>
  22. #include <console.h>
  23. #include <gpxe/settings.h>
  24. #include <gpxe/editbox.h>
  25. #include <gpxe/keys.h>
  26. #include <gpxe/settings_ui.h>
  27. /** @file
  28. *
  29. * Option configuration console
  30. *
  31. */
  32. #include <gpxe/nvo.h>
  33. extern struct nvo_block *ugly_nvo_hack;
  34. /* Colour pairs */
  35. #define CPAIR_NORMAL 1
  36. #define CPAIR_SELECT 2
  37. #define CPAIR_EDIT 3
  38. #define CPAIR_ALERT 4
  39. /* Screen layout */
  40. #define TITLE_ROW 1
  41. #define SETTINGS_LIST_ROW 3
  42. #define SETTINGS_LIST_COL 1
  43. #define INFO_ROW 20
  44. #define ALERT_ROW 20
  45. #define INSTRUCTION_ROW 22
  46. #define INSTRUCTION_PAD " "
  47. /** Layout of text within a setting widget */
  48. struct setting_row {
  49. char start[0];
  50. char pad1[1];
  51. char name[15];
  52. char pad2[1];
  53. char value[60];
  54. char pad3[1];
  55. char nul;
  56. } __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;
  63. /** Screen row */
  64. unsigned int row;
  65. /** Screen column */
  66. unsigned int col;
  67. /** Edit box widget used for editing setting */
  68. struct edit_box editbox;
  69. /** Editing in progress flag */
  70. int editing;
  71. /** Buffer for setting's value */
  72. char value[256]; /* enough size for a DHCP string */
  73. };
  74. /** Registered configuration settings */
  75. static struct config_setting
  76. config_settings[0] __table_start ( config_settings );
  77. static struct config_setting
  78. config_settings_end[0] __table_end ( config_settings );
  79. #define NUM_SETTINGS ( ( unsigned ) ( config_settings_end - config_settings ) )
  80. /**
  81. * Load setting widget value from configuration context
  82. *
  83. * @v widget Setting widget
  84. *
  85. */
  86. static void load_setting ( struct setting_widget *widget ) {
  87. /* Mark as not editing */
  88. widget->editing = 0;
  89. /* Read current setting value */
  90. if ( show_setting ( widget->context, widget->setting,
  91. widget->value, sizeof ( widget->value ) ) != 0 ) {
  92. widget->value[0] = '\0';
  93. }
  94. /* Initialise edit box */
  95. init_editbox ( &widget->editbox, widget->value,
  96. sizeof ( widget->value ), NULL, widget->row,
  97. ( widget->col + offsetof ( struct setting_row, value )),
  98. sizeof ( ( ( struct setting_row * ) NULL )->value ) );
  99. }
  100. /**
  101. * Save setting widget value back to configuration context
  102. *
  103. * @v widget Setting widget
  104. */
  105. static int save_setting ( struct setting_widget *widget ) {
  106. return set_setting ( widget->context, widget->setting, widget->value );
  107. }
  108. /**
  109. * Initialise setting widget
  110. *
  111. * @v widget Setting widget
  112. * @v context Configuration context
  113. * @v setting Configuration setting
  114. * @v row Screen row
  115. * @v col Screen column
  116. */
  117. static void init_setting ( struct setting_widget *widget,
  118. struct config_context *context,
  119. struct config_setting *setting,
  120. unsigned int row, unsigned int col ) {
  121. /* Initialise widget structure */
  122. memset ( widget, 0, sizeof ( *widget ) );
  123. widget->context = context;
  124. widget->setting = setting;
  125. widget->row = row;
  126. widget->col = col;
  127. /* Read current setting value */
  128. load_setting ( widget );
  129. }
  130. /**
  131. * Draw setting widget
  132. *
  133. * @v widget Setting widget
  134. */
  135. static void draw_setting ( struct setting_widget *widget ) {
  136. struct setting_row row;
  137. unsigned int len;
  138. unsigned int curs_col;
  139. char *value;
  140. /* Fill row with spaces */
  141. memset ( &row, ' ', sizeof ( row ) );
  142. row.nul = '\0';
  143. /* Construct dot-padded name */
  144. memset ( row.name, '.', sizeof ( row.name ) );
  145. len = strlen ( widget->setting->name );
  146. if ( len > sizeof ( row.name ) )
  147. len = sizeof ( row.name );
  148. memcpy ( row.name, widget->setting->name, len );
  149. /* Construct space-padded value */
  150. value = widget->value;
  151. if ( ! *value )
  152. value = "<not specified>";
  153. len = strlen ( value );
  154. if ( len > sizeof ( row.value ) )
  155. len = sizeof ( row.value );
  156. memcpy ( row.value, value, len );
  157. curs_col = ( widget->col + offsetof ( typeof ( row ), value )
  158. + len );
  159. /* Print row */
  160. mvprintw ( widget->row, widget->col, "%s", row.start );
  161. move ( widget->row, curs_col );
  162. if ( widget->editing )
  163. draw_editbox ( &widget->editbox );
  164. }
  165. /**
  166. * Edit setting widget
  167. *
  168. * @v widget Setting widget
  169. * @v key Key pressed by user
  170. * @ret key Key returned to application, or zero
  171. */
  172. static int edit_setting ( struct setting_widget *widget, int key ) {
  173. widget->editing = 1;
  174. return edit_editbox ( &widget->editbox, key );
  175. }
  176. /**
  177. * Initialise setting widget by index
  178. *
  179. * @v widget Setting widget
  180. * @v context Configuration context
  181. * @v index Index of setting with settings list
  182. */
  183. static void init_setting_index ( struct setting_widget *widget,
  184. struct config_context *context,
  185. unsigned int index ) {
  186. init_setting ( widget, context, &config_settings[index],
  187. ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL );
  188. }
  189. /**
  190. * Print message centred on specified row
  191. *
  192. * @v row Row
  193. * @v fmt printf() format string
  194. * @v args printf() argument list
  195. */
  196. static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
  197. char buf[COLS];
  198. size_t len;
  199. len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
  200. mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
  201. }
  202. /**
  203. * Print message centred on specified row
  204. *
  205. * @v row Row
  206. * @v fmt printf() format string
  207. * @v .. printf() arguments
  208. */
  209. static void msg ( unsigned int row, const char *fmt, ... ) {
  210. va_list args;
  211. va_start ( args, fmt );
  212. vmsg ( row, fmt, args );
  213. va_end ( args );
  214. }
  215. /**
  216. * Clear message on specified row
  217. *
  218. * @v row Row
  219. */
  220. static void clearmsg ( unsigned int row ) {
  221. move ( row, 0 );
  222. clrtoeol();
  223. }
  224. /**
  225. * Print alert message
  226. *
  227. * @v fmt printf() format string
  228. * @v args printf() argument list
  229. */
  230. static void valert ( const char *fmt, va_list args ) {
  231. clearmsg ( ALERT_ROW );
  232. color_set ( CPAIR_ALERT, NULL );
  233. vmsg ( ALERT_ROW, fmt, args );
  234. sleep ( 2 );
  235. color_set ( CPAIR_NORMAL, NULL );
  236. clearmsg ( ALERT_ROW );
  237. }
  238. /**
  239. * Print alert message
  240. *
  241. * @v fmt printf() format string
  242. * @v ... printf() arguments
  243. */
  244. static void alert ( const char *fmt, ... ) {
  245. va_list args;
  246. va_start ( args, fmt );
  247. valert ( fmt, args );
  248. va_end ( args );
  249. }
  250. /**
  251. * Draw title row
  252. */
  253. static void draw_title_row ( void ) {
  254. attron ( A_BOLD );
  255. msg ( TITLE_ROW, "gPXE option configuration console" );
  256. attroff ( A_BOLD );
  257. }
  258. /**
  259. * Draw information row
  260. *
  261. * @v setting Current configuration setting
  262. */
  263. static void draw_info_row ( struct config_setting *setting ) {
  264. clearmsg ( INFO_ROW );
  265. attron ( A_BOLD );
  266. msg ( INFO_ROW, "%s (%s) - %s", setting->name,
  267. setting->type->description, setting->description );
  268. attroff ( A_BOLD );
  269. }
  270. /**
  271. * Draw instruction row
  272. *
  273. * @v editing Editing in progress flag
  274. */
  275. static void draw_instruction_row ( int editing ) {
  276. clearmsg ( INSTRUCTION_ROW );
  277. if ( editing ) {
  278. msg ( INSTRUCTION_ROW,
  279. "Enter - accept changes" INSTRUCTION_PAD
  280. "Ctrl-C - discard changes" );
  281. } else {
  282. msg ( INSTRUCTION_ROW,
  283. "Ctrl-S - save configuration" );
  284. }
  285. }
  286. static int main_loop ( struct config_context *context ) {
  287. struct setting_widget widget;
  288. unsigned int current = 0;
  289. unsigned int next;
  290. int i;
  291. int key;
  292. int rc;
  293. /* Print initial screen content */
  294. draw_title_row();
  295. color_set ( CPAIR_NORMAL, NULL );
  296. for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) {
  297. init_setting_index ( &widget, context, i );
  298. draw_setting ( &widget );
  299. }
  300. while ( 1 ) {
  301. /* Redraw information and instruction rows */
  302. draw_info_row ( widget.setting );
  303. draw_instruction_row ( widget.editing );
  304. /* Redraw current setting */
  305. color_set ( ( widget.editing ? CPAIR_EDIT : CPAIR_SELECT ),
  306. NULL );
  307. draw_setting ( &widget );
  308. color_set ( CPAIR_NORMAL, NULL );
  309. key = getkey();
  310. if ( widget.editing ) {
  311. key = edit_setting ( &widget, key );
  312. switch ( key ) {
  313. case CR:
  314. case LF:
  315. if ( ( rc = save_setting ( &widget ) ) != 0 ) {
  316. alert ( " Could not set %s: %s ",
  317. widget.setting->name,
  318. strerror ( rc ) );
  319. }
  320. /* Fall through */
  321. case CTRL_C:
  322. load_setting ( &widget );
  323. break;
  324. default:
  325. /* Do nothing */
  326. break;
  327. }
  328. } else {
  329. next = current;
  330. switch ( key ) {
  331. case KEY_DOWN:
  332. if ( next < ( NUM_SETTINGS - 1 ) )
  333. next++;
  334. break;
  335. case KEY_UP:
  336. if ( next > 0 )
  337. next--;
  338. break;
  339. case CTRL_S:
  340. if ( ( rc = nvo_save ( ugly_nvo_hack ) ) != 0){
  341. alert ( " Could not save options: %s ",
  342. strerror ( rc ) );
  343. }
  344. return rc;
  345. default:
  346. edit_setting ( &widget, key );
  347. break;
  348. }
  349. if ( next != current ) {
  350. draw_setting ( &widget );
  351. init_setting_index ( &widget, context, next );
  352. current = next;
  353. }
  354. }
  355. }
  356. }
  357. int settings_ui ( struct config_context *context ) {
  358. int rc;
  359. initscr();
  360. start_color();
  361. init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
  362. init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
  363. init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
  364. init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
  365. color_set ( CPAIR_NORMAL, NULL );
  366. erase();
  367. rc = main_loop ( context );
  368. endwin();
  369. return rc;
  370. }