diff options
author | Benjamin Poirier <bpoirier@suse.de> | 2013-04-16 10:07:23 -0400 |
---|---|---|
committer | Yann E. MORIN <yann.morin.1998@free.fr> | 2013-04-16 16:00:31 -0400 |
commit | 9a69abf80edf2ea0dac058cab156879d29362788 (patch) | |
tree | b94e9a202805b4de9afce670e17ba720592d2cc5 | |
parent | edb749f4390b3c1604233dc7c4fb0361f472e712 (diff) |
menuconfig: Add "breadcrumbs" navigation aid
Displays a trail of the menu entries used to get to the current menu.
Signed-off-by: Benjamin Poirier <bpoirier@suse.de>
Tested-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
[yann.morin.1998@free.fr: small, trivial code re-ordering]
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
-rw-r--r-- | scripts/kconfig/list.h | 27 | ||||
-rw-r--r-- | scripts/kconfig/lxdialog/dialog.h | 7 | ||||
-rw-r--r-- | scripts/kconfig/lxdialog/util.c | 45 | ||||
-rw-r--r-- | scripts/kconfig/mconf.c | 71 |
4 files changed, 147 insertions, 3 deletions
diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h index b87206cc92f4..ea1d58119d20 100644 --- a/scripts/kconfig/list.h +++ b/scripts/kconfig/list.h | |||
@@ -101,4 +101,31 @@ static inline void list_add_tail(struct list_head *_new, struct list_head *head) | |||
101 | __list_add(_new, head->prev, head); | 101 | __list_add(_new, head->prev, head); |
102 | } | 102 | } |
103 | 103 | ||
104 | /* | ||
105 | * Delete a list entry by making the prev/next entries | ||
106 | * point to each other. | ||
107 | * | ||
108 | * This is only for internal list manipulation where we know | ||
109 | * the prev/next entries already! | ||
110 | */ | ||
111 | static inline void __list_del(struct list_head *prev, struct list_head *next) | ||
112 | { | ||
113 | next->prev = prev; | ||
114 | prev->next = next; | ||
115 | } | ||
116 | |||
117 | #define LIST_POISON1 ((void *) 0x00100100) | ||
118 | #define LIST_POISON2 ((void *) 0x00200200) | ||
119 | /** | ||
120 | * list_del - deletes entry from list. | ||
121 | * @entry: the element to delete from the list. | ||
122 | * Note: list_empty() on entry does not return true after this, the entry is | ||
123 | * in an undefined state. | ||
124 | */ | ||
125 | static inline void list_del(struct list_head *entry) | ||
126 | { | ||
127 | __list_del(entry->prev, entry->next); | ||
128 | entry->next = LIST_POISON1; | ||
129 | entry->prev = LIST_POISON2; | ||
130 | } | ||
104 | #endif | 131 | #endif |
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index 307022a8beef..1099337079b6 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h | |||
@@ -106,8 +106,14 @@ struct dialog_color { | |||
106 | int hl; /* highlight this item */ | 106 | int hl; /* highlight this item */ |
107 | }; | 107 | }; |
108 | 108 | ||
109 | struct subtitle_list { | ||
110 | struct subtitle_list *next; | ||
111 | const char *text; | ||
112 | }; | ||
113 | |||
109 | struct dialog_info { | 114 | struct dialog_info { |
110 | const char *backtitle; | 115 | const char *backtitle; |
116 | struct subtitle_list *subtitles; | ||
111 | struct dialog_color screen; | 117 | struct dialog_color screen; |
112 | struct dialog_color shadow; | 118 | struct dialog_color shadow; |
113 | struct dialog_color dialog; | 119 | struct dialog_color dialog; |
@@ -196,6 +202,7 @@ int on_key_resize(void); | |||
196 | 202 | ||
197 | int init_dialog(const char *backtitle); | 203 | int init_dialog(const char *backtitle); |
198 | void set_dialog_backtitle(const char *backtitle); | 204 | void set_dialog_backtitle(const char *backtitle); |
205 | void set_dialog_subtitles(struct subtitle_list *subtitles); | ||
199 | void end_dialog(int x, int y); | 206 | void end_dialog(int x, int y); |
200 | void attr_clear(WINDOW * win, int height, int width, chtype attr); | 207 | void attr_clear(WINDOW * win, int height, int width, chtype attr); |
201 | void dialog_clear(void); | 208 | void dialog_clear(void); |
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index 109d53117d22..a0e97c299410 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c | |||
@@ -257,12 +257,48 @@ void dialog_clear(void) | |||
257 | attr_clear(stdscr, LINES, COLS, dlg.screen.atr); | 257 | attr_clear(stdscr, LINES, COLS, dlg.screen.atr); |
258 | /* Display background title if it exists ... - SLH */ | 258 | /* Display background title if it exists ... - SLH */ |
259 | if (dlg.backtitle != NULL) { | 259 | if (dlg.backtitle != NULL) { |
260 | int i; | 260 | int i, len = 0, skip = 0; |
261 | struct subtitle_list *pos; | ||
261 | 262 | ||
262 | wattrset(stdscr, dlg.screen.atr); | 263 | wattrset(stdscr, dlg.screen.atr); |
263 | mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); | 264 | mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); |
265 | |||
266 | for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { | ||
267 | /* 3 is for the arrow and spaces */ | ||
268 | len += strlen(pos->text) + 3; | ||
269 | } | ||
270 | |||
264 | wmove(stdscr, 1, 1); | 271 | wmove(stdscr, 1, 1); |
265 | for (i = 1; i < COLS - 1; i++) | 272 | if (len > COLS - 2) { |
273 | const char *ellipsis = "[...] "; | ||
274 | waddstr(stdscr, ellipsis); | ||
275 | skip = len - (COLS - 2 - strlen(ellipsis)); | ||
276 | } | ||
277 | |||
278 | for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { | ||
279 | if (skip == 0) | ||
280 | waddch(stdscr, ACS_RARROW); | ||
281 | else | ||
282 | skip--; | ||
283 | |||
284 | if (skip == 0) | ||
285 | waddch(stdscr, ' '); | ||
286 | else | ||
287 | skip--; | ||
288 | |||
289 | if (skip < strlen(pos->text)) { | ||
290 | waddstr(stdscr, pos->text + skip); | ||
291 | skip = 0; | ||
292 | } else | ||
293 | skip -= strlen(pos->text); | ||
294 | |||
295 | if (skip == 0) | ||
296 | waddch(stdscr, ' '); | ||
297 | else | ||
298 | skip--; | ||
299 | } | ||
300 | |||
301 | for (i = len + 1; i < COLS - 1; i++) | ||
266 | waddch(stdscr, ACS_HLINE); | 302 | waddch(stdscr, ACS_HLINE); |
267 | } | 303 | } |
268 | wnoutrefresh(stdscr); | 304 | wnoutrefresh(stdscr); |
@@ -302,6 +338,11 @@ void set_dialog_backtitle(const char *backtitle) | |||
302 | dlg.backtitle = backtitle; | 338 | dlg.backtitle = backtitle; |
303 | } | 339 | } |
304 | 340 | ||
341 | void set_dialog_subtitles(struct subtitle_list *subtitles) | ||
342 | { | ||
343 | dlg.subtitles = subtitles; | ||
344 | } | ||
345 | |||
305 | /* | 346 | /* |
306 | * End using dialog functions. | 347 | * End using dialog functions. |
307 | */ | 348 | */ |
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index c5418d622a05..387dc8daf7b2 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c | |||
@@ -311,6 +311,50 @@ static void set_config_filename(const char *config_filename) | |||
311 | filename[sizeof(filename)-1] = '\0'; | 311 | filename[sizeof(filename)-1] = '\0'; |
312 | } | 312 | } |
313 | 313 | ||
314 | struct subtitle_part { | ||
315 | struct list_head entries; | ||
316 | const char *text; | ||
317 | }; | ||
318 | static LIST_HEAD(trail); | ||
319 | |||
320 | static struct subtitle_list *subtitles; | ||
321 | static void set_subtitle(void) | ||
322 | { | ||
323 | struct subtitle_part *sp; | ||
324 | struct subtitle_list *pos, *tmp; | ||
325 | |||
326 | for (pos = subtitles; pos != NULL; pos = tmp) { | ||
327 | tmp = pos->next; | ||
328 | free(pos); | ||
329 | } | ||
330 | |||
331 | subtitles = NULL; | ||
332 | list_for_each_entry(sp, &trail, entries) { | ||
333 | if (sp->text) { | ||
334 | if (pos) { | ||
335 | pos->next = xcalloc(sizeof(*pos), 1); | ||
336 | pos = pos->next; | ||
337 | } else { | ||
338 | subtitles = pos = xcalloc(sizeof(*pos), 1); | ||
339 | } | ||
340 | pos->text = sp->text; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | set_dialog_subtitles(subtitles); | ||
345 | } | ||
346 | |||
347 | static void reset_subtitle(void) | ||
348 | { | ||
349 | struct subtitle_list *pos, *tmp; | ||
350 | |||
351 | for (pos = subtitles; pos != NULL; pos = tmp) { | ||
352 | tmp = pos->next; | ||
353 | free(pos); | ||
354 | } | ||
355 | subtitles = NULL; | ||
356 | set_dialog_subtitles(subtitles); | ||
357 | } | ||
314 | 358 | ||
315 | struct search_data { | 359 | struct search_data { |
316 | struct list_head *head; | 360 | struct list_head *head; |
@@ -353,6 +397,8 @@ static void search_conf(void) | |||
353 | char *dialog_input; | 397 | char *dialog_input; |
354 | int dres, vscroll = 0, hscroll = 0; | 398 | int dres, vscroll = 0, hscroll = 0; |
355 | bool again; | 399 | bool again; |
400 | struct gstr sttext; | ||
401 | struct subtitle_part stpart; | ||
356 | 402 | ||
357 | title = str_new(); | 403 | title = str_new(); |
358 | str_printf( &title, _("Enter %s (sub)string to search for " | 404 | str_printf( &title, _("Enter %s (sub)string to search for " |
@@ -379,6 +425,11 @@ again: | |||
379 | if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) | 425 | if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) |
380 | dialog_input += strlen(CONFIG_); | 426 | dialog_input += strlen(CONFIG_); |
381 | 427 | ||
428 | sttext = str_new(); | ||
429 | str_printf(&sttext, "Search (%s)", dialog_input_result); | ||
430 | stpart.text = str_get(&sttext); | ||
431 | list_add_tail(&stpart.entries, &trail); | ||
432 | |||
382 | sym_arr = sym_re_search(dialog_input); | 433 | sym_arr = sym_re_search(dialog_input); |
383 | do { | 434 | do { |
384 | LIST_HEAD(head); | 435 | LIST_HEAD(head); |
@@ -392,6 +443,7 @@ again: | |||
392 | struct jump_key *pos, *tmp; | 443 | struct jump_key *pos, *tmp; |
393 | 444 | ||
394 | res = get_relations_str(sym_arr, &head); | 445 | res = get_relations_str(sym_arr, &head); |
446 | set_subtitle(); | ||
395 | dres = show_textbox_ext(_("Search Results"), (char *) | 447 | dres = show_textbox_ext(_("Search Results"), (char *) |
396 | str_get(&res), 0, 0, keys, &vscroll, | 448 | str_get(&res), 0, 0, keys, &vscroll, |
397 | &hscroll, &update_text, (void *) | 449 | &hscroll, &update_text, (void *) |
@@ -408,6 +460,8 @@ again: | |||
408 | } while (again); | 460 | } while (again); |
409 | free(sym_arr); | 461 | free(sym_arr); |
410 | str_free(&title); | 462 | str_free(&title); |
463 | list_del(trail.prev); | ||
464 | str_free(&sttext); | ||
411 | } | 465 | } |
412 | 466 | ||
413 | static void build_conf(struct menu *menu) | 467 | static void build_conf(struct menu *menu) |
@@ -592,16 +646,24 @@ static void conf(struct menu *menu, struct menu *active_menu) | |||
592 | { | 646 | { |
593 | struct menu *submenu; | 647 | struct menu *submenu; |
594 | const char *prompt = menu_get_prompt(menu); | 648 | const char *prompt = menu_get_prompt(menu); |
649 | struct subtitle_part stpart; | ||
595 | struct symbol *sym; | 650 | struct symbol *sym; |
596 | int res; | 651 | int res; |
597 | int s_scroll = 0; | 652 | int s_scroll = 0; |
598 | 653 | ||
654 | if (menu != &rootmenu) | ||
655 | stpart.text = menu_get_prompt(menu); | ||
656 | else | ||
657 | stpart.text = NULL; | ||
658 | list_add_tail(&stpart.entries, &trail); | ||
659 | |||
599 | while (1) { | 660 | while (1) { |
600 | item_reset(); | 661 | item_reset(); |
601 | current_menu = menu; | 662 | current_menu = menu; |
602 | build_conf(menu); | 663 | build_conf(menu); |
603 | if (!child_count) | 664 | if (!child_count) |
604 | break; | 665 | break; |
666 | set_subtitle(); | ||
605 | dialog_clear(); | 667 | dialog_clear(); |
606 | res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), | 668 | res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), |
607 | _(menu_instructions), | 669 | _(menu_instructions), |
@@ -643,13 +705,17 @@ static void conf(struct menu *menu, struct menu *active_menu) | |||
643 | case 2: | 705 | case 2: |
644 | if (sym) | 706 | if (sym) |
645 | show_help(submenu); | 707 | show_help(submenu); |
646 | else | 708 | else { |
709 | reset_subtitle(); | ||
647 | show_helptext(_("README"), _(mconf_readme)); | 710 | show_helptext(_("README"), _(mconf_readme)); |
711 | } | ||
648 | break; | 712 | break; |
649 | case 3: | 713 | case 3: |
714 | reset_subtitle(); | ||
650 | conf_save(); | 715 | conf_save(); |
651 | break; | 716 | break; |
652 | case 4: | 717 | case 4: |
718 | reset_subtitle(); | ||
653 | conf_load(); | 719 | conf_load(); |
654 | break; | 720 | break; |
655 | case 5: | 721 | case 5: |
@@ -682,6 +748,8 @@ static void conf(struct menu *menu, struct menu *active_menu) | |||
682 | break; | 748 | break; |
683 | } | 749 | } |
684 | } | 750 | } |
751 | |||
752 | list_del(trail.prev); | ||
685 | } | 753 | } |
686 | 754 | ||
687 | static int show_textbox_ext(const char *title, char *text, int r, int c, int | 755 | static int show_textbox_ext(const char *title, char *text, int r, int c, int |
@@ -884,6 +952,7 @@ static int handle_exit(void) | |||
884 | int res; | 952 | int res; |
885 | 953 | ||
886 | save_and_exit = 1; | 954 | save_and_exit = 1; |
955 | reset_subtitle(); | ||
887 | dialog_clear(); | 956 | dialog_clear(); |
888 | if (conf_get_changed()) | 957 | if (conf_get_changed()) |
889 | res = dialog_yesno(NULL, | 958 | res = dialog_yesno(NULL, |