2 * $Id: buildlist.c,v 1.56 2012/12/31 00:38:57 tom Exp $
4 * buildlist.c -- implements the buildlist dialog
6 * Copyright 2012 Thomas E. Dickey
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License, version 2.1
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to
19 * Free Software Foundation, Inc.
20 * 51 Franklin St., Fifth Floor
21 * Boston, MA 02110, USA.
28 * Visually like menubox, but two columns.
34 #define KEY_TOGGLE ' '
35 #define KEY_LEFTCOL '^'
36 #define KEY_RIGHTCOL '$'
38 #define MIN_HIGH (1 + (5 * MARGIN))
49 DIALOG_LISTITEM
*items
;
50 int base_y
; /* base for mouse coordinates */
52 int use_height
; /* actual size of column box */
61 * Print list item. The 'selected' parameter is true if 'choice' is the
62 * current item. That one is colored differently from the other items.
65 print_item(ALL_DATA
* data
,
67 DIALOG_LISTITEM
* item
,
71 chtype save
= dlg_get_attrs(win
);
73 bool both
= (!dialog_vars
.no_tags
&& !dialog_vars
.no_items
);
75 int climit
= (data
->item_x
- data
->check_x
- 1);
76 const char *show
= (dialog_vars
.no_items
80 /* Clear 'residue' of last item */
81 (void) wattrset(win
, menubox_attr
);
82 (void) wmove(win
, choice
, 0);
83 for (i
= 0; i
< getmaxx(win
); i
++)
84 (void) waddch(win
, ' ');
86 (void) wmove(win
, choice
, data
->check_x
);
87 (void) wattrset(win
, menubox_attr
);
90 dlg_print_listitem(win
, item
->name
, climit
, first
, selected
);
91 (void) waddch(win
, ' ');
95 (void) wmove(win
, choice
, data
->item_x
);
96 climit
= (getmaxx(win
) - data
->item_x
+ 1);
97 dlg_print_listitem(win
, show
, climit
, first
, selected
);
100 dlg_item_help(item
->help
);
102 (void) wattrset(win
, save
);
106 * Prints either the left (unselected) or right (selected) list.
109 print_1_list(ALL_DATA
* data
,
113 MY_DATA
*moi
= data
->list
+ selected
;
114 WINDOW
*win
= moi
->win
;
117 int max_rows
= getmaxy(win
);
119 for (i
= j
= 0; j
< max_rows
; i
++) {
120 int ii
= i
+ moi
->top_index
;
121 if (ii
>= data
->item_no
) {
123 } else if (!(selected
^ (data
->items
[ii
].state
!= 0))) {
131 if (wmove(win
, last
, 0) != ERR
)
133 (void) wnoutrefresh(win
);
137 * Return the previous item from the list, staying in the same column. If no
138 * further movement is possible, return the same choice as given.
141 prev_item(ALL_DATA
* data
, int choice
, int selected
)
146 for (n
= choice
- 1; n
>= 0; --n
) {
147 if ((data
->items
[n
].state
!= 0) == selected
) {
156 * Return true if the given choice is on the first page in the current column.
159 stop_prev(ALL_DATA
* data
, int choice
, int selected
)
161 return (prev_item(data
, choice
, selected
) == choice
);
165 check_hotkey(DIALOG_LISTITEM
* items
, int choice
, int selected
)
169 if ((items
[choice
].state
!= 0) == selected
) {
170 if (dlg_match_char(dlg_last_getc(),
173 : items
[choice
].name
))) {
181 * Return the next item from the list, staying in the same column. If no
182 * further movement is possible, return the same choice as given.
185 next_item(ALL_DATA
* data
, int choice
, int selected
)
190 for (n
= choice
+ 1; n
< data
->item_no
; ++n
) {
191 if ((data
->items
[n
].state
!= 0) == selected
) {
196 dlg_trace_msg("next_item(%d) ->%d\n", choice
, result
);
201 * Translate a choice from items[] to a row-number in an unbounded column,
205 index2row(ALL_DATA
* data
, int choice
, int selected
)
209 for (n
= 0; n
< data
->item_no
; ++n
) {
210 if ((data
->items
[n
].state
!= 0) == selected
) {
220 * Return the first choice from items[] for the given column.
223 first_item(ALL_DATA
* data
, int selected
)
228 for (n
= 0; n
< data
->item_no
; ++n
) {
229 if ((data
->items
[n
].state
!= 0) == selected
) {
238 * Return the last choice from items[] for the given column.
241 last_item(ALL_DATA
* data
, int selected
)
246 for (n
= data
->item_no
- 1; n
>= 0; --n
) {
247 if ((data
->items
[n
].state
!= 0) == selected
) {
256 * Convert a row-number back to an item number, i.e., index into items[].
259 row2index(ALL_DATA
* data
, int row
, int selected
)
263 for (n
= 0; n
< data
->item_no
; ++n
) {
264 if ((data
->items
[n
].state
!= 0) == selected
) {
275 skip_rows(ALL_DATA
* data
, int row
, int skip
, int selected
)
277 int choice
= row2index(data
, row
, selected
);
281 for (n
= choice
+ 1; n
< data
->item_no
; ++n
) {
282 if ((data
->items
[n
].state
!= 0) == selected
) {
288 } else if (skip
< 0) {
289 for (n
= choice
- 1; n
>= 0; --n
) {
290 if ((data
->items
[n
].state
!= 0) == selected
) {
301 * Find the closest item in the given column starting with the given choice.
304 closest_item(ALL_DATA
* data
, int choice
, int selected
)
311 for (n
= choice
; n
>= 0; --n
) {
312 if ((data
->items
[n
].state
!= 0) == selected
) {
317 for (n
= choice
; n
< data
->item_no
; ++n
) {
318 if ((data
->items
[n
].state
!= 0) == selected
) {
323 if (prev
!= choice
) {
325 if (next
!= choice
) {
326 if ((choice
- prev
) > (next
- choice
)) {
330 } else if (next
!= choice
) {
337 print_both(ALL_DATA
* data
,
342 WINDOW
*dialog
= wgetparent(data
->list
[0].win
);
344 getyx(dialog
, cur_y
, cur_x
);
345 for (selected
= 0; selected
< 2; ++selected
) {
346 MY_DATA
*moi
= data
->list
+ selected
;
347 WINDOW
*win
= moi
->win
;
348 int thumb_top
= index2row(data
, moi
->top_index
, selected
);
349 int thumb_max
= index2row(data
, -1, selected
);
350 int thumb_end
= thumb_top
+ getmaxy(win
);
352 print_1_list(data
, choice
, selected
);
354 dlg_mouse_setcode(selected
* KEY_MAX
);
355 dlg_draw_scrollbar(dialog
,
356 (long) (moi
->top_index
),
358 (long) MIN(thumb_end
, thumb_max
),
360 moi
->box_x
+ data
->check_x
,
361 moi
->box_x
+ getmaxx(win
),
363 moi
->box_y
+ getmaxy(win
) + 1,
364 menubox_border2_attr
,
365 menubox_border_attr
);
367 (void) wmove(dialog
, cur_y
, cur_x
);
368 dlg_mouse_setcode(0);
372 set_top_item(ALL_DATA
* data
, int value
, int selected
)
374 if (value
!= data
->list
[selected
].top_index
) {
375 dlg_trace_msg("set top of %s column to %d\n",
376 selected
? "right" : "left",
378 data
->list
[selected
].top_index
= value
;
383 * Adjust the top-index as needed to ensure that it and the given item are
387 fix_top_item(ALL_DATA
* data
, int cur_item
, int selected
)
389 int top_item
= data
->list
[selected
].top_index
;
390 int cur_row
= index2row(data
, cur_item
, selected
);
391 int top_row
= index2row(data
, top_item
, selected
);
393 if (cur_row
< top_row
) {
395 } else if ((cur_row
- top_row
) > data
->use_height
) {
396 top_item
= row2index(data
, cur_row
+ 1 - data
->use_height
, selected
);
398 if (cur_row
< data
->use_height
) {
399 top_item
= row2index(data
, 0, selected
);
401 dlg_trace_msg("fix_top_item(cur_item %d, selected %d) ->top_item %d\n",
402 cur_item
, selected
, top_item
);
403 set_top_item(data
, top_item
, selected
);
407 * This is an alternate interface to 'buildlist' which allows the application
408 * to read the list item states back directly without putting them in the
412 dlg_buildlist(const char *title
,
418 DIALOG_LISTITEM
* items
,
424 static DLG_KEYS_BINDING binding
[] = {
427 DLG_KEYS_DATA( DLGK_FIELD_NEXT
, KEY_RIGHT
),
428 DLG_KEYS_DATA( DLGK_FIELD_NEXT
, TAB
),
429 DLG_KEYS_DATA( DLGK_FIELD_PREV
, KEY_BTAB
),
430 DLG_KEYS_DATA( DLGK_FIELD_PREV
, KEY_LEFT
),
431 DLG_KEYS_DATA( DLGK_ITEM_FIRST
, KEY_HOME
),
432 DLG_KEYS_DATA( DLGK_ITEM_LAST
, KEY_END
),
433 DLG_KEYS_DATA( DLGK_ITEM_LAST
, KEY_LL
),
434 DLG_KEYS_DATA( DLGK_ITEM_NEXT
, '+' ),
435 DLG_KEYS_DATA( DLGK_ITEM_NEXT
, KEY_DOWN
),
436 DLG_KEYS_DATA( DLGK_ITEM_NEXT
, CHR_NEXT
),
437 DLG_KEYS_DATA( DLGK_ITEM_PREV
, '-' ),
438 DLG_KEYS_DATA( DLGK_ITEM_PREV
, KEY_UP
),
439 DLG_KEYS_DATA( DLGK_ITEM_PREV
, CHR_PREVIOUS
),
440 DLG_KEYS_DATA( DLGK_PAGE_NEXT
, KEY_NPAGE
),
441 DLG_KEYS_DATA( DLGK_PAGE_NEXT
, DLGK_MOUSE(KEY_NPAGE
) ),
442 DLG_KEYS_DATA( DLGK_PAGE_NEXT
, DLGK_MOUSE(KEY_NPAGE
+KEY_MAX
) ),
443 DLG_KEYS_DATA( DLGK_PAGE_PREV
, KEY_PPAGE
),
444 DLG_KEYS_DATA( DLGK_PAGE_PREV
, DLGK_MOUSE(KEY_PPAGE
) ),
445 DLG_KEYS_DATA( DLGK_PAGE_PREV
, DLGK_MOUSE(KEY_PPAGE
+KEY_MAX
) ),
446 DLG_KEYS_DATA( DLGK_GRID_LEFT
, KEY_LEFTCOL
),
447 DLG_KEYS_DATA( DLGK_GRID_RIGHT
, KEY_RIGHTCOL
),
453 int old_height
= height
;
454 int old_width
= width
;
457 MY_DATA
*data
= all
.list
;
458 int i
, j
, k
, key2
, found
, x
, y
, cur_x
, cur_y
;
460 bool save_visit
= dialog_state
.visit_items
;
464 int name_width
, text_width
, full_width
, list_width
;
465 int result
= DLG_EXIT_UNKNOWN
;
469 char *prompt
= dlg_strclone(cprompt
);
470 const char **buttons
= dlg_ok_labels();
471 const char *widget_name
= "buildlist";
476 * Unlike other uses of --visit-items, we have two windows to visit.
478 if (dialog_state
.visit_cols
)
479 dialog_state
.visit_cols
= 2;
481 memset(&all
, 0, sizeof(all
));
483 all
.item_no
= item_no
;
485 if (dialog_vars
.default_item
!= 0) {
486 cur_item
= dlg_default_listitem(items
);
488 if ((cur_item
= first_item(&all
, 0)) < 0)
489 cur_item
= first_item(&all
, 1);
491 button
= (dialog_state
.visit_items
492 ? (items
[cur_item
].state
? sRIGHT
: sLEFT
)
493 : dlg_default_button());
496 dlg_tab_correct_str(prompt
);
502 all
.use_height
= list_height
;
503 all
.use_width
= (2 * (dlg_calc_list_width(item_no
, items
)
507 all
.use_width
= MAX(26, all
.use_width
);
508 if (all
.use_height
== 0) {
509 /* calculate height without items (4) */
510 dlg_auto_size(title
, prompt
, &height
, &width
, MIN_HIGH
, all
.use_width
);
511 dlg_calc_listh(&height
, &all
.use_height
, item_no
);
513 dlg_auto_size(title
, prompt
,
515 MIN_HIGH
+ all
.use_height
, all
.use_width
);
517 dlg_button_layout(buttons
, &width
);
518 dlg_print_size(height
, width
);
519 dlg_ctl_size(height
, width
);
521 /* we need at least two states */
522 if (states
== 0 || strlen(states
) < 2)
524 num_states
= (int) strlen(states
);
526 x
= dlg_box_x_ordinate(width
);
527 y
= dlg_box_y_ordinate(height
);
529 dialog
= dlg_new_window(height
, width
, y
, x
);
530 dlg_register_window(dialog
, widget_name
, binding
);
531 dlg_register_buttons(dialog
, widget_name
, buttons
);
533 dlg_mouse_setbase(all
.base_x
= x
, all
.base_y
= y
);
535 dlg_draw_box2(dialog
, 0, 0, height
, width
, dialog_attr
, border_attr
, border2_attr
);
536 dlg_draw_bottom_box2(dialog
, border_attr
, border2_attr
, dialog_attr
);
537 dlg_draw_title(dialog
, title
);
539 (void) wattrset(dialog
, dialog_attr
);
540 dlg_print_autowrap(dialog
, prompt
, height
, width
);
542 list_width
= (width
- 6 * MARGIN
- 2) / 2;
543 getyx(dialog
, cur_y
, cur_x
);
544 data
[0].box_y
= cur_y
+ 1;
545 data
[0].box_x
= MARGIN
+ 1;
546 data
[1].box_y
= cur_y
+ 1;
547 data
[1].box_x
= data
[0].box_x
+ 1 + 2 * MARGIN
+ list_width
;
550 * After displaying the prompt, we know how much space we really have.
551 * Limit the list to avoid overwriting the ok-button.
553 if (all
.use_height
+ MIN_HIGH
> height
- cur_y
)
554 all
.use_height
= height
- MIN_HIGH
- cur_y
;
555 if (all
.use_height
<= 0)
558 for (k
= 0; k
< 2; ++k
) {
559 /* create new window for the list */
560 data
[k
].win
= dlg_sub_window(dialog
, all
.use_height
, list_width
,
561 y
+ data
[k
].box_y
+ 1,
562 x
+ data
[k
].box_x
+ 1);
564 /* draw a box around the list items */
565 dlg_draw_box(dialog
, data
[k
].box_y
, data
[k
].box_x
,
566 all
.use_height
+ 2 * MARGIN
,
567 list_width
+ 2 * MARGIN
,
568 menubox_border_attr
, menubox_border2_attr
);
573 /* Find length of longest item to center buildlist */
574 for (i
= 0; i
< item_no
; i
++) {
575 text_width
= MAX(text_width
, dlg_count_columns(items
[i
].text
));
576 name_width
= MAX(name_width
, dlg_count_columns(items
[i
].name
));
579 /* If the name+text is wider than the list is allowed, then truncate
580 * one or both of them. If the name is no wider than 1/4 of the list,
583 all
.use_width
= (list_width
- 6 * MARGIN
);
584 if (dialog_vars
.no_tags
&& !dialog_vars
.no_items
) {
585 full_width
= MIN(all
.use_width
, text_width
);
586 } else if (dialog_vars
.no_items
) {
587 full_width
= MIN(all
.use_width
, name_width
);
592 && text_width
+ name_width
> all
.use_width
) {
593 int need
= (int) (0.25 * all
.use_width
);
594 if (name_width
> need
) {
595 int want
= (int) (all
.use_width
* ((double) name_width
) /
596 (text_width
+ name_width
));
597 name_width
= (want
> need
) ? want
: need
;
599 text_width
= all
.use_width
- name_width
;
601 full_width
= text_width
+ name_width
;
604 all
.check_x
= (all
.use_width
- full_width
) / 2;
605 all
.item_x
= ((dialog_vars
.no_tags
607 : (dialog_vars
.no_items
612 /* ensure we are scrolled to show the current choice */
613 j
= MIN(all
.use_height
, item_no
);
614 for (i
= 0; i
< 2; ++i
) {
616 if ((items
[cur_item
].state
!= 0) == i
) {
617 top_item
= cur_item
- j
+ 1;
620 set_top_item(&all
, top_item
, i
);
622 set_top_item(&all
, 0, i
);
626 /* register the new window, along with its borders */
627 for (i
= 0; i
< 2; ++i
) {
628 dlg_mouse_mkbigregion(data
[i
].box_y
+ 1,
632 2 * KEY_MAX
+ (i
* (1 + all
.use_height
)),
633 1, 1, 1 /* by lines */ );
636 dlg_draw_buttons(dialog
, height
- 2, 0, buttons
, button
, FALSE
, width
);
638 while (result
== DLG_EXIT_UNKNOWN
) {
639 int which
= (items
[cur_item
].state
!= 0);
640 MY_DATA
*moi
= data
+ which
;
641 int at_top
= index2row(&all
, moi
->top_index
, which
);
642 int at_end
= index2row(&all
, -1, which
);
643 int at_bot
= skip_rows(&all
, at_top
, all
.use_height
, which
);
645 dlg_trace_msg("\t** state %d:%d top %d (%d:%d:%d) %d\n",
646 cur_item
, item_no
- 1,
648 at_top
, at_bot
, at_end
,
652 print_both(&all
, cur_item
);
653 dlg_trace_win(dialog
);
657 if (button
< 0) { /* --visit-items */
658 int cur_row
= index2row(&all
, cur_item
, which
);
659 cur_y
= (data
[which
].box_y
664 cur_x
= (data
[which
].box_x
666 dlg_trace_msg("\t...visit row %d (%d,%d)\n", cur_row
, cur_y
, cur_x
);
667 wmove(dialog
, cur_y
, cur_x
);
670 key
= dlg_mouse_wgetch(dialog
, &fkey
);
671 if (dlg_result_key(key
, fkey
, &result
))
674 was_mouse
= (fkey
&& is_DLGK_MOUSE(key
));
680 } else if (key
>= 2 * KEY_MAX
) {
681 i
= (key
- 2 * KEY_MAX
) % (1 + all
.use_height
);
682 j
= (key
- 2 * KEY_MAX
) / (1 + all
.use_height
);
683 k
= row2index(&all
, i
+ at_top
, j
);
684 dlg_trace_msg("MOUSE column %d, row %d ->item %d\n", j
, i
, k
);
685 if (k
>= 0 && j
< 2) {
688 * Mouse click was in the other column.
691 fix_top_item(&all
, k
, j
);
694 at_top
= index2row(&all
, moi
->top_index
, which
);
695 at_bot
= skip_rows(&all
, at_top
, all
.use_height
, which
);
697 print_both(&all
, cur_item
);
698 key
= KEY_TOGGLE
; /* force the selected item to toggle */
704 } else if (key
>= KEY_MIN
) {
707 key
= KEY_RIGHTCOL
; /* switch to right-column */
714 key
= KEY_LEFTCOL
; /* switch to left-column */
718 key
= dlg_lookup_key(dialog
, key
, &fkey
);
722 * A space toggles the item status. Normally we put the cursor on
723 * the next available item in the same column. But if there are no
724 * more items in the column, move the cursor to the other column.
726 if (key
== KEY_TOGGLE
) {
728 int new_state
= items
[cur_item
].state
+ 1;
730 if ((new_choice
= next_item(&all
, cur_item
, which
)) == cur_item
) {
731 new_choice
= prev_item(&all
, cur_item
, which
);
733 dlg_trace_msg("cur_item %d, new_choice:%d\n", cur_item
, new_choice
);
734 if (new_state
>= num_states
)
737 items
[cur_item
].state
= new_state
;
738 if (cur_item
== moi
->top_index
) {
739 set_top_item(&all
, new_choice
, which
);
742 if (new_choice
>= 0) {
743 fix_top_item(&all
, cur_item
, !which
);
744 cur_item
= new_choice
;
746 print_both(&all
, cur_item
);
747 dlg_trace_win(dialog
);
748 continue; /* wait for another key press */
752 * Check if key pressed matches first character of any item tag in
753 * list. If there is more than one match, we will cycle through
754 * each one as the same key is pressed repeatedly.
758 if (button
< 0 || !dialog_state
.visit_items
) {
759 for (j
= cur_item
+ 1; j
< item_no
; j
++) {
760 if (check_hotkey(items
, j
, which
)) {
767 for (j
= 0; j
<= cur_item
; j
++) {
768 if (check_hotkey(items
, j
, which
)) {
777 } else if ((j
= dlg_char_to_button(key
, buttons
)) >= 0) {
785 * A single digit (1-9) positions the selection to that line in the
791 && (key
- '1' < at_bot
)) {
796 if (!found
&& fkey
) {
798 case DLGK_FIELD_PREV
:
799 if ((button
== sRIGHT
) && dialog_state
.visit_items
) {
800 key
= DLGK_GRID_LEFT
;
803 button
= dlg_prev_button(buttons
, button
);
804 dlg_draw_buttons(dialog
, height
- 2, 0, buttons
, button
,
806 if (button
== sRIGHT
) {
807 key
= DLGK_GRID_RIGHT
;
813 case DLGK_FIELD_NEXT
:
814 if ((button
== sLEFT
) && dialog_state
.visit_items
) {
815 key
= DLGK_GRID_RIGHT
;
818 button
= dlg_next_button(buttons
, button
);
819 dlg_draw_buttons(dialog
, height
- 2, 0, buttons
, button
,
821 if (button
== sLEFT
) {
822 key
= DLGK_GRID_LEFT
;
831 if (!found
&& fkey
) {
836 i
= closest_item(&all
, cur_item
, 0);
837 fix_top_item(&all
, i
, 0);
839 case DLGK_GRID_RIGHT
:
840 i
= closest_item(&all
, cur_item
, 1);
841 fix_top_item(&all
, i
, 1);
844 if (cur_item
> moi
->top_index
) {
846 } else if (moi
->top_index
!= 0) {
848 if ((temp
-= all
.use_height
) < 0)
850 i
= row2index(&all
, temp
, which
);
854 if ((at_end
- at_bot
) < all
.use_height
) {
856 row2index(&all
, at_end
, which
),
860 row2index(&all
, at_bot
, which
),
865 row2index(&all
, at_top
, which
),
868 at_bot
= skip_rows(&all
, at_top
, all
.use_height
, which
);
869 at_bot
= MIN(at_bot
, at_end
);
872 case DLGK_ITEM_FIRST
:
873 i
= first_item(&all
, which
);
876 i
= last_item(&all
, which
);
879 i
= prev_item(&all
, cur_item
, which
);
880 if (stop_prev(&all
, cur_item
, which
))
884 i
= next_item(&all
, cur_item
, which
);
894 int now_at
= index2row(&all
, i
, which
);
898 dlg_trace_msg("<--CHOICE %d\n", i
);
899 dlg_trace_msg("<--topITM %d\n", moi
->top_index
);
900 dlg_trace_msg("<--now_at %d\n", now_at
);
901 dlg_trace_msg("<--at_top %d\n", at_top
);
902 dlg_trace_msg("<--at_bot %d\n", at_bot
);
904 if (now_at
>= at_bot
) {
905 while (now_at
>= at_bot
) {
906 if ((at_bot
- at_top
) >= all
.use_height
) {
908 next_item(&all
, moi
->top_index
, which
),
911 at_top
= index2row(&all
, moi
->top_index
, which
);
912 at_bot
= skip_rows(&all
, at_top
, all
.use_height
, which
);
914 dlg_trace_msg("...at_bot %d (now %d vs %d)\n",
915 at_bot
, now_at
, at_end
);
916 dlg_trace_msg("...topITM %d\n", moi
->top_index
);
917 dlg_trace_msg("...at_top %d (diff %d)\n", at_top
,
920 if (at_bot
>= at_end
) {
922 * If we bumped into the end, move the top-item
923 * down by one line so that we can display the
924 * last item in the list.
926 if ((at_bot
- at_top
) > all
.use_height
) {
928 next_item(&all
, moi
->top_index
, which
),
930 } else if (at_top
> 0 &&
931 (at_bot
- at_top
) >= all
.use_height
) {
933 next_item(&all
, moi
->top_index
, which
),
939 dlg_trace_msg("OOPS-forward\n");
943 } else if (now_at
< at_top
) {
944 while (now_at
< at_top
) {
945 old_item
= moi
->top_index
;
947 prev_item(&all
, moi
->top_index
, which
),
949 at_top
= index2row(&all
, moi
->top_index
, which
);
951 dlg_trace_msg("...at_top %d (now %d)\n", at_top
, now_at
);
952 dlg_trace_msg("...topITM %d\n", moi
->top_index
);
954 if (moi
->top_index
>= old_item
)
956 if (at_top
<= now_at
)
959 dlg_trace_msg("OOPS-backward\n");
964 dlg_trace_msg("-->now_at %d\n", now_at
);
966 print_both(&all
, cur_item
);
968 dlg_trace_win(dialog
);
969 continue; /* wait for another key press */
975 result
= dlg_enter_buttoncode(button
);
984 dlg_del_window(dialog
);
986 dlg_mouse_free_regions();
991 if ((key2
= dlg_ok_buttoncode(key
)) >= 0) {
1003 dialog_state
.visit_cols
= save_visit
;
1004 dlg_del_window(dialog
);
1005 dlg_mouse_free_regions();
1007 *current_item
= cur_item
;
1012 * Display a dialog box with a list of options that can be turned on or off
1015 dialog_buildlist(const char *title
,
1016 const char *cprompt
,
1026 DIALOG_LISTITEM
*listitems
;
1027 bool separate_output
= dialog_vars
.separate_output
;
1028 bool show_status
= FALSE
;
1031 listitems
= dlg_calloc(DIALOG_LISTITEM
, (size_t) item_no
+ 1);
1032 assert_ptr(listitems
, "dialog_buildlist");
1034 for (i
= j
= 0; i
< item_no
; ++i
) {
1035 listitems
[i
].name
= items
[j
++];
1036 listitems
[i
].text
= (dialog_vars
.no_items
1039 listitems
[i
].state
= !dlg_strcmp(items
[j
++], "on");
1040 listitems
[i
].help
= ((dialog_vars
.item_help
)
1044 dlg_align_columns(&listitems
[0].text
, (int) sizeof(DIALOG_LISTITEM
), item_no
);
1046 result
= dlg_buildlist(title
,
1058 case DLG_EXIT_OK
: /* FALLTHRU */
1059 case DLG_EXIT_EXTRA
:
1063 dlg_add_result("HELP ");
1064 show_status
= dialog_vars
.help_status
;
1065 if (USE_ITEM_HELP(listitems
[current
].help
)) {
1067 if (separate_output
) {
1068 dlg_add_string(listitems
[current
].help
);
1069 dlg_add_separator();
1071 dlg_add_quoted(listitems
[current
].help
);
1074 dlg_add_string(listitems
[current
].help
);
1076 result
= DLG_EXIT_ITEM_HELP
;
1079 if (separate_output
) {
1080 dlg_add_string(listitems
[current
].name
);
1081 dlg_add_separator();
1083 dlg_add_quoted(listitems
[current
].name
);
1086 dlg_add_string(listitems
[current
].name
);
1093 for (i
= 0; i
< item_no
; i
++) {
1094 if (listitems
[i
].state
) {
1095 if (separate_output
) {
1096 dlg_add_string(listitems
[i
].name
);
1097 dlg_add_separator();
1099 if (dlg_need_separator())
1100 dlg_add_separator();
1101 dlg_add_quoted(listitems
[i
].name
);
1107 dlg_free_columns(&listitems
[0].text
, (int) sizeof(DIALOG_LISTITEM
), item_no
);