1217309Snwhitehorn/*
2251843Sbapt *  $Id: buttons.c,v 1.94 2012/12/30 20:51:01 tom Exp $
3217309Snwhitehorn *
4220749Snwhitehorn *  buttons.c -- draw buttons, e.g., OK/Cancel
5217309Snwhitehorn *
6251843Sbapt *  Copyright 2000-2011,2012	Thomas E. Dickey
7217309Snwhitehorn *
8217309Snwhitehorn *  This program is free software; you can redistribute it and/or modify
9217309Snwhitehorn *  it under the terms of the GNU Lesser General Public License, version 2.1
10217309Snwhitehorn *  as published by the Free Software Foundation.
11217309Snwhitehorn *
12217309Snwhitehorn *  This program is distributed in the hope that it will be useful, but
13217309Snwhitehorn *  WITHOUT ANY WARRANTY; without even the implied warranty of
14217309Snwhitehorn *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15217309Snwhitehorn *  Lesser General Public License for more details.
16217309Snwhitehorn *
17217309Snwhitehorn *  You should have received a copy of the GNU Lesser General Public
18217309Snwhitehorn *  License along with this program; if not, write to
19217309Snwhitehorn *	Free Software Foundation, Inc.
20217309Snwhitehorn *	51 Franklin St., Fifth Floor
21217309Snwhitehorn *	Boston, MA 02110, USA.
22217309Snwhitehorn */
23217309Snwhitehorn
24217309Snwhitehorn#include <dialog.h>
25217309Snwhitehorn#include <dlg_keys.h>
26217309Snwhitehorn
27217309Snwhitehorn#ifdef NEED_WCHAR_H
28217309Snwhitehorn#include <wchar.h>
29217309Snwhitehorn#endif
30217309Snwhitehorn
31251843Sbapt#define MIN_BUTTON (-dialog_state.visit_cols)
32217309Snwhitehorn
33217309Snwhitehornstatic void
34217309Snwhitehorncenter_label(char *buffer, int longest, const char *label)
35217309Snwhitehorn{
36217309Snwhitehorn    int len = dlg_count_columns(label);
37217309Snwhitehorn    int left = 0, right = 0;
38217309Snwhitehorn
39217309Snwhitehorn    *buffer = 0;
40217309Snwhitehorn    if (len < longest) {
41217309Snwhitehorn	left = (longest - len) / 2;
42217309Snwhitehorn	right = (longest - len - left);
43217309Snwhitehorn	if (left > 0)
44217309Snwhitehorn	    sprintf(buffer, "%*s", left, " ");
45217309Snwhitehorn    }
46217309Snwhitehorn    strcat(buffer, label);
47217309Snwhitehorn    if (right > 0)
48217309Snwhitehorn	sprintf(buffer + strlen(buffer), "%*s", right, " ");
49217309Snwhitehorn}
50217309Snwhitehorn
51217309Snwhitehorn/*
52217309Snwhitehorn * Parse a multibyte character out of the string, set it past the parsed
53217309Snwhitehorn * character.
54217309Snwhitehorn */
55217309Snwhitehornstatic int
56217309Snwhitehornstring_to_char(const char **stringp)
57217309Snwhitehorn{
58217309Snwhitehorn    int result;
59217309Snwhitehorn#ifdef USE_WIDE_CURSES
60217309Snwhitehorn    const char *string = *stringp;
61217309Snwhitehorn    size_t have = strlen(string);
62217309Snwhitehorn    size_t check;
63217309Snwhitehorn    size_t len;
64217309Snwhitehorn    wchar_t cmp2[2];
65217309Snwhitehorn    mbstate_t state;
66217309Snwhitehorn
67217309Snwhitehorn    memset(&state, 0, sizeof(state));
68217309Snwhitehorn    len = mbrlen(string, have, &state);
69217309Snwhitehorn    if ((int) len > 0 && len <= have) {
70217309Snwhitehorn	memset(&state, 0, sizeof(state));
71217309Snwhitehorn	memset(cmp2, 0, sizeof(cmp2));
72217309Snwhitehorn	check = mbrtowc(cmp2, string, len, &state);
73217309Snwhitehorn	if ((int) check <= 0)
74217309Snwhitehorn	    cmp2[0] = 0;
75217309Snwhitehorn	*stringp += len;
76217309Snwhitehorn    } else {
77217309Snwhitehorn	cmp2[0] = UCH(*string);
78217309Snwhitehorn	*stringp += 1;
79217309Snwhitehorn    }
80217309Snwhitehorn    result = cmp2[0];
81217309Snwhitehorn#else
82217309Snwhitehorn    const char *string = *stringp;
83217309Snwhitehorn    result = UCH(*string);
84217309Snwhitehorn    *stringp += 1;
85217309Snwhitehorn#endif
86217309Snwhitehorn    return result;
87217309Snwhitehorn}
88217309Snwhitehorn
89251843Sbaptstatic size_t
90251843Sbaptcount_labels(const char **labels)
91251843Sbapt{
92251843Sbapt    size_t result = 0;
93251843Sbapt    if (labels != 0) {
94251843Sbapt	while (*labels++ != 0) {
95251843Sbapt	    ++result;
96251843Sbapt	}
97251843Sbapt    }
98251843Sbapt    return result;
99251843Sbapt}
100251843Sbapt
101217309Snwhitehorn/*
102251843Sbapt * Check if the latest key should be added to the hotkey list.
103251843Sbapt */
104251843Sbaptstatic int
105251843Sbaptwas_hotkey(int this_key, int *used_keys, size_t next)
106251843Sbapt{
107251843Sbapt    int result = FALSE;
108251843Sbapt
109251843Sbapt    if (next != 0) {
110251843Sbapt	size_t n;
111251843Sbapt	for (n = 0; n < next; ++n) {
112251843Sbapt	    if (used_keys[n] == this_key) {
113251843Sbapt		result = TRUE;
114251843Sbapt		break;
115251843Sbapt	    }
116251843Sbapt	}
117251843Sbapt    }
118251843Sbapt    return result;
119251843Sbapt}
120251843Sbapt
121251843Sbapt/*
122251843Sbapt * Determine the hot-keys for a set of button-labels.  Normally these are
123251843Sbapt * the first uppercase character in each label.  However, if more than one
124251843Sbapt * button has the same first-uppercase, then we will (attempt to) look for
125251843Sbapt * an alternate.
126251843Sbapt *
127251843Sbapt * This allocates data which must be freed by the caller.
128251843Sbapt */
129251843Sbaptstatic int *
130251843Sbaptget_hotkeys(const char **labels)
131251843Sbapt{
132251843Sbapt    int *result = 0;
133251843Sbapt    size_t count = count_labels(labels);
134251843Sbapt    size_t n;
135251843Sbapt
136251843Sbapt    if ((result = dlg_calloc(int, count + 1)) != 0) {
137251843Sbapt	for (n = 0; n < count; ++n) {
138251843Sbapt	    const char *label = labels[n];
139251843Sbapt	    const int *indx = dlg_index_wchars(label);
140251843Sbapt	    int limit = dlg_count_wchars(label);
141251843Sbapt	    int i;
142251843Sbapt
143251843Sbapt	    for (i = 0; i < limit; ++i) {
144251843Sbapt		int first = indx[i];
145251843Sbapt		int check = UCH(label[first]);
146251843Sbapt#ifdef USE_WIDE_CURSES
147251843Sbapt		int last = indx[i + 1];
148251843Sbapt		if ((last - first) != 1) {
149251843Sbapt		    const char *temp = (label + first);
150251843Sbapt		    check = string_to_char(&temp);
151251843Sbapt		}
152251843Sbapt#endif
153251843Sbapt		if (dlg_isupper(check) && !was_hotkey(check, result, n)) {
154251843Sbapt		    result[n] = check;
155251843Sbapt		    break;
156251843Sbapt		}
157251843Sbapt	    }
158251843Sbapt	}
159251843Sbapt    }
160251843Sbapt    return result;
161251843Sbapt}
162251843Sbapt
163251843Sbapt/*
164217309Snwhitehorn * Print a button
165217309Snwhitehorn */
166217309Snwhitehornstatic void
167251843Sbaptprint_button(WINDOW *win, char *label, int hotkey, int y, int x, int selected)
168217309Snwhitehorn{
169217309Snwhitehorn    int i;
170217309Snwhitehorn    int state = 0;
171217309Snwhitehorn    const int *indx = dlg_index_wchars(label);
172217309Snwhitehorn    int limit = dlg_count_wchars(label);
173217309Snwhitehorn    chtype key_attr = (selected
174217309Snwhitehorn		       ? button_key_active_attr
175217309Snwhitehorn		       : button_key_inactive_attr);
176217309Snwhitehorn    chtype label_attr = (selected
177217309Snwhitehorn			 ? button_label_active_attr
178217309Snwhitehorn			 : button_label_inactive_attr);
179217309Snwhitehorn
180217309Snwhitehorn    (void) wmove(win, y, x);
181251843Sbapt    (void) wattrset(win, selected
182251843Sbapt		    ? button_active_attr
183251843Sbapt		    : button_inactive_attr);
184217309Snwhitehorn    (void) waddstr(win, "<");
185251843Sbapt    (void) wattrset(win, label_attr);
186217309Snwhitehorn    for (i = 0; i < limit; ++i) {
187251843Sbapt	int check;
188217309Snwhitehorn	int first = indx[i];
189217309Snwhitehorn	int last = indx[i + 1];
190217309Snwhitehorn
191217309Snwhitehorn	switch (state) {
192217309Snwhitehorn	case 0:
193251843Sbapt	    check = UCH(label[first]);
194217309Snwhitehorn#ifdef USE_WIDE_CURSES
195217309Snwhitehorn	    if ((last - first) != 1) {
196217309Snwhitehorn		const char *temp = (label + first);
197251843Sbapt		check = string_to_char(&temp);
198217309Snwhitehorn	    }
199217309Snwhitehorn#endif
200251843Sbapt	    if (check == hotkey) {
201251843Sbapt		(void) wattrset(win, key_attr);
202217309Snwhitehorn		state = 1;
203217309Snwhitehorn	    }
204217309Snwhitehorn	    break;
205217309Snwhitehorn	case 1:
206217309Snwhitehorn	    wattrset(win, label_attr);
207217309Snwhitehorn	    state = 2;
208217309Snwhitehorn	    break;
209217309Snwhitehorn	}
210217309Snwhitehorn	waddnstr(win, label + first, last - first);
211217309Snwhitehorn    }
212251843Sbapt    (void) wattrset(win, selected
213251843Sbapt		    ? button_active_attr
214251843Sbapt		    : button_inactive_attr);
215217309Snwhitehorn    (void) waddstr(win, ">");
216217309Snwhitehorn    (void) wmove(win, y, x + ((int) strspn(label, " ")) + 1);
217217309Snwhitehorn}
218217309Snwhitehorn
219217309Snwhitehorn/*
220217309Snwhitehorn * Count the buttons in the list.
221217309Snwhitehorn */
222217309Snwhitehornint
223217309Snwhitehorndlg_button_count(const char **labels)
224217309Snwhitehorn{
225217309Snwhitehorn    int result = 0;
226217309Snwhitehorn    while (*labels++ != 0)
227217309Snwhitehorn	++result;
228217309Snwhitehorn    return result;
229217309Snwhitehorn}
230217309Snwhitehorn
231217309Snwhitehorn/*
232217309Snwhitehorn * Compute the size of the button array in columns.  Return the total number of
233217309Snwhitehorn * columns in *length, and the longest button's columns in *longest
234217309Snwhitehorn */
235217309Snwhitehornvoid
236217309Snwhitehorndlg_button_sizes(const char **labels,
237217309Snwhitehorn		 int vertical,
238217309Snwhitehorn		 int *longest,
239217309Snwhitehorn		 int *length)
240217309Snwhitehorn{
241217309Snwhitehorn    int n;
242217309Snwhitehorn
243217309Snwhitehorn    *length = 0;
244217309Snwhitehorn    *longest = 0;
245217309Snwhitehorn    for (n = 0; labels[n] != 0; n++) {
246217309Snwhitehorn	if (vertical) {
247217309Snwhitehorn	    *length += 1;
248217309Snwhitehorn	    *longest = 1;
249217309Snwhitehorn	} else {
250217309Snwhitehorn	    int len = dlg_count_columns(labels[n]);
251217309Snwhitehorn	    if (len > *longest)
252217309Snwhitehorn		*longest = len;
253217309Snwhitehorn	    *length += len;
254217309Snwhitehorn	}
255217309Snwhitehorn    }
256217309Snwhitehorn    /*
257217309Snwhitehorn     * If we can, make all of the buttons the same size.  This is only optional
258217309Snwhitehorn     * for buttons laid out horizontally.
259217309Snwhitehorn     */
260217309Snwhitehorn    if (*longest < 6 - (*longest & 1))
261217309Snwhitehorn	*longest = 6 - (*longest & 1);
262217309Snwhitehorn    if (!vertical)
263217309Snwhitehorn	*length = *longest * n;
264217309Snwhitehorn}
265217309Snwhitehorn
266217309Snwhitehorn/*
267217309Snwhitehorn * Compute the size of the button array.
268217309Snwhitehorn */
269217309Snwhitehornint
270217309Snwhitehorndlg_button_x_step(const char **labels, int limit, int *gap, int *margin, int *step)
271217309Snwhitehorn{
272217309Snwhitehorn    int count = dlg_button_count(labels);
273217309Snwhitehorn    int longest;
274217309Snwhitehorn    int length;
275217309Snwhitehorn    int unused;
276217309Snwhitehorn    int used;
277251843Sbapt    int result;
278217309Snwhitehorn
279251843Sbapt    *margin = 0;
280251843Sbapt    if (count != 0) {
281251843Sbapt	dlg_button_sizes(labels, FALSE, &longest, &length);
282251843Sbapt	used = (length + (count * 2));
283251843Sbapt	unused = limit - used;
284217309Snwhitehorn
285251843Sbapt	if ((*gap = unused / (count + 3)) <= 0) {
286251843Sbapt	    if ((*gap = unused / (count + 1)) <= 0)
287251843Sbapt		*gap = 1;
288251843Sbapt	    *margin = *gap;
289251843Sbapt	} else {
290251843Sbapt	    *margin = *gap * 2;
291251843Sbapt	}
292251843Sbapt	*step = *gap + (used + count - 1) / count;
293251843Sbapt	result = (*gap > 0) && (unused >= 0);
294217309Snwhitehorn    } else {
295251843Sbapt	result = 0;
296217309Snwhitehorn    }
297251843Sbapt    return result;
298217309Snwhitehorn}
299217309Snwhitehorn
300217309Snwhitehorn/*
301217309Snwhitehorn * Make sure there is enough space for the buttons
302217309Snwhitehorn */
303217309Snwhitehornvoid
304217309Snwhitehorndlg_button_layout(const char **labels, int *limit)
305217309Snwhitehorn{
306217309Snwhitehorn    int width = 1;
307217309Snwhitehorn    int gap, margin, step;
308217309Snwhitehorn
309217309Snwhitehorn    if (labels != 0 && dlg_button_count(labels)) {
310217309Snwhitehorn	while (!dlg_button_x_step(labels, width, &gap, &margin, &step))
311217309Snwhitehorn	    ++width;
312217309Snwhitehorn	width += (4 * MARGIN);
313217309Snwhitehorn	if (width > COLS)
314217309Snwhitehorn	    width = COLS;
315217309Snwhitehorn	if (width > *limit)
316217309Snwhitehorn	    *limit = width;
317217309Snwhitehorn    }
318217309Snwhitehorn}
319217309Snwhitehorn
320217309Snwhitehorn/*
321217309Snwhitehorn * Print a list of buttons at the given position.
322217309Snwhitehorn */
323217309Snwhitehornvoid
324217309Snwhitehorndlg_draw_buttons(WINDOW *win,
325217309Snwhitehorn		 int y, int x,
326217309Snwhitehorn		 const char **labels,
327217309Snwhitehorn		 int selected,
328217309Snwhitehorn		 int vertical,
329217309Snwhitehorn		 int limit)
330217309Snwhitehorn{
331220749Snwhitehorn    chtype save = dlg_get_attrs(win);
332217309Snwhitehorn    int n;
333217309Snwhitehorn    int step = 0;
334217309Snwhitehorn    int length;
335217309Snwhitehorn    int longest;
336217309Snwhitehorn    int final_x;
337217309Snwhitehorn    int final_y;
338217309Snwhitehorn    int gap;
339217309Snwhitehorn    int margin;
340217309Snwhitehorn    size_t need;
341217309Snwhitehorn    char *buffer;
342217309Snwhitehorn
343217309Snwhitehorn    dlg_mouse_setbase(getbegx(win), getbegy(win));
344217309Snwhitehorn
345217309Snwhitehorn    getyx(win, final_y, final_x);
346217309Snwhitehorn
347217309Snwhitehorn    dlg_button_sizes(labels, vertical, &longest, &length);
348217309Snwhitehorn
349217309Snwhitehorn    if (vertical) {
350217309Snwhitehorn	y += 1;
351217309Snwhitehorn	step = 1;
352217309Snwhitehorn    } else {
353217309Snwhitehorn	dlg_button_x_step(labels, limit, &gap, &margin, &step);
354217309Snwhitehorn	x += margin;
355217309Snwhitehorn    }
356217309Snwhitehorn
357217309Snwhitehorn    /*
358217309Snwhitehorn     * Allocate a buffer big enough for any label.
359217309Snwhitehorn     */
360217309Snwhitehorn    need = (size_t) longest;
361251843Sbapt    if (need != 0) {
362251843Sbapt	int *hotkeys = get_hotkeys(labels);
363251843Sbapt	assert_ptr(hotkeys, "dlg_draw_buttons");
364217309Snwhitehorn
365251843Sbapt	for (n = 0; labels[n] != 0; ++n) {
366251843Sbapt	    need += strlen(labels[n]) + 1;
367251843Sbapt	}
368251843Sbapt	buffer = dlg_malloc(char, need);
369251843Sbapt	assert_ptr(buffer, "dlg_draw_buttons");
370217309Snwhitehorn
371251843Sbapt	/*
372251843Sbapt	 * Draw the labels.
373251843Sbapt	 */
374251843Sbapt	for (n = 0; labels[n] != 0; n++) {
375251843Sbapt	    center_label(buffer, longest, labels[n]);
376251843Sbapt	    mouse_mkbutton(y, x, dlg_count_columns(buffer), n);
377251843Sbapt	    print_button(win, buffer, hotkeys[n], y, x,
378251843Sbapt			 (selected == n) || (n == 0 && selected < 0));
379251843Sbapt	    if (selected == n)
380251843Sbapt		getyx(win, final_y, final_x);
381251843Sbapt
382251843Sbapt	    if (vertical) {
383251843Sbapt		if ((y += step) > limit)
384251843Sbapt		    break;
385251843Sbapt	    } else {
386251843Sbapt		if ((x += step) > limit)
387251843Sbapt		    break;
388251843Sbapt	    }
389217309Snwhitehorn	}
390251843Sbapt	(void) wmove(win, final_y, final_x);
391251843Sbapt	wrefresh(win);
392251843Sbapt	(void) wattrset(win, save);
393251843Sbapt	free(buffer);
394251843Sbapt	free(hotkeys);
395217309Snwhitehorn    }
396217309Snwhitehorn}
397217309Snwhitehorn
398217309Snwhitehorn/*
399217309Snwhitehorn * Match a given character against the beginning of the string, ignoring case
400217309Snwhitehorn * of the given character.  The matching string must begin with an uppercase
401217309Snwhitehorn * character.
402217309Snwhitehorn */
403217309Snwhitehornint
404217309Snwhitehorndlg_match_char(int ch, const char *string)
405217309Snwhitehorn{
406217309Snwhitehorn    if (string != 0) {
407217309Snwhitehorn	int cmp2 = string_to_char(&string);
408217309Snwhitehorn#ifdef USE_WIDE_CURSES
409217309Snwhitehorn	wint_t cmp1 = dlg_toupper(ch);
410217309Snwhitehorn	if (cmp2 != 0 && (wchar_t) cmp1 == (wchar_t) dlg_toupper(cmp2)) {
411217309Snwhitehorn	    return TRUE;
412217309Snwhitehorn	}
413217309Snwhitehorn#else
414217309Snwhitehorn	if (ch > 0 && ch < 256) {
415217309Snwhitehorn	    if (dlg_toupper(ch) == dlg_toupper(cmp2))
416217309Snwhitehorn		return TRUE;
417217309Snwhitehorn	}
418217309Snwhitehorn#endif
419217309Snwhitehorn    }
420217309Snwhitehorn    return FALSE;
421217309Snwhitehorn}
422217309Snwhitehorn
423217309Snwhitehorn/*
424217309Snwhitehorn * Find the first uppercase character in the label, which we may use for an
425217309Snwhitehorn * abbreviation.
426217309Snwhitehorn */
427217309Snwhitehornint
428217309Snwhitehorndlg_button_to_char(const char *label)
429217309Snwhitehorn{
430217309Snwhitehorn    int cmp = -1;
431217309Snwhitehorn
432217309Snwhitehorn    while (*label != 0) {
433217309Snwhitehorn	cmp = string_to_char(&label);
434217309Snwhitehorn	if (dlg_isupper(cmp)) {
435217309Snwhitehorn	    break;
436217309Snwhitehorn	}
437217309Snwhitehorn    }
438217309Snwhitehorn    return cmp;
439217309Snwhitehorn}
440217309Snwhitehorn
441217309Snwhitehorn/*
442217309Snwhitehorn * Given a list of button labels, and a character which may be the abbreviation
443217309Snwhitehorn * for one, find it, if it exists.  An abbreviation will be the first character
444217309Snwhitehorn * which happens to be capitalized in the label.
445217309Snwhitehorn */
446217309Snwhitehornint
447217309Snwhitehorndlg_char_to_button(int ch, const char **labels)
448217309Snwhitehorn{
449251843Sbapt    int result = DLG_EXIT_UNKNOWN;
450251843Sbapt
451217309Snwhitehorn    if (labels != 0) {
452251843Sbapt	int *hotkeys = get_hotkeys(labels);
453217309Snwhitehorn	int j;
454217309Snwhitehorn
455217309Snwhitehorn	ch = (int) dlg_toupper(dlg_last_getc());
456251843Sbapt
457251843Sbapt	if (hotkeys != 0) {
458251843Sbapt	    for (j = 0; labels[j] != 0; ++j) {
459251843Sbapt		if (ch == hotkeys[j]) {
460251843Sbapt		    dlg_flush_getc();
461251843Sbapt		    result = j;
462251843Sbapt		    break;
463251843Sbapt		}
464217309Snwhitehorn	    }
465251843Sbapt	    free(hotkeys);
466217309Snwhitehorn	}
467217309Snwhitehorn    }
468251843Sbapt
469251843Sbapt    return result;
470217309Snwhitehorn}
471217309Snwhitehorn
472217309Snwhitehornstatic const char *
473217309Snwhitehornmy_yes_label(void)
474217309Snwhitehorn{
475217309Snwhitehorn    return (dialog_vars.yes_label != NULL)
476217309Snwhitehorn	? dialog_vars.yes_label
477217309Snwhitehorn	: _("Yes");
478217309Snwhitehorn}
479217309Snwhitehorn
480217309Snwhitehornstatic const char *
481217309Snwhitehornmy_no_label(void)
482217309Snwhitehorn{
483217309Snwhitehorn    return (dialog_vars.no_label != NULL)
484217309Snwhitehorn	? dialog_vars.no_label
485217309Snwhitehorn	: _("No");
486217309Snwhitehorn}
487217309Snwhitehorn
488217309Snwhitehornstatic const char *
489217309Snwhitehornmy_ok_label(void)
490217309Snwhitehorn{
491217309Snwhitehorn    return (dialog_vars.ok_label != NULL)
492217309Snwhitehorn	? dialog_vars.ok_label
493217309Snwhitehorn	: _("OK");
494217309Snwhitehorn}
495217309Snwhitehorn
496217309Snwhitehornstatic const char *
497217309Snwhitehornmy_cancel_label(void)
498217309Snwhitehorn{
499217309Snwhitehorn    return (dialog_vars.cancel_label != NULL)
500217309Snwhitehorn	? dialog_vars.cancel_label
501217309Snwhitehorn	: _("Cancel");
502217309Snwhitehorn}
503217309Snwhitehorn
504217309Snwhitehornstatic const char *
505217309Snwhitehornmy_exit_label(void)
506217309Snwhitehorn{
507217309Snwhitehorn    return (dialog_vars.exit_label != NULL)
508217309Snwhitehorn	? dialog_vars.exit_label
509217309Snwhitehorn	: _("EXIT");
510217309Snwhitehorn}
511217309Snwhitehorn
512217309Snwhitehornstatic const char *
513217309Snwhitehornmy_extra_label(void)
514217309Snwhitehorn{
515217309Snwhitehorn    return (dialog_vars.extra_label != NULL)
516217309Snwhitehorn	? dialog_vars.extra_label
517217309Snwhitehorn	: _("Extra");
518217309Snwhitehorn}
519217309Snwhitehorn
520217309Snwhitehornstatic const char *
521217309Snwhitehornmy_help_label(void)
522217309Snwhitehorn{
523217309Snwhitehorn    return (dialog_vars.help_label != NULL)
524217309Snwhitehorn	? dialog_vars.help_label
525217309Snwhitehorn	: _("Help");
526217309Snwhitehorn}
527217309Snwhitehorn
528217309Snwhitehorn/*
529217309Snwhitehorn * Return a list of button labels.
530217309Snwhitehorn */
531217309Snwhitehornconst char **
532217309Snwhitehorndlg_exit_label(void)
533217309Snwhitehorn{
534217309Snwhitehorn    const char **result;
535224014Snwhitehorn    DIALOG_VARS save;
536217309Snwhitehorn
537217309Snwhitehorn    if (dialog_vars.extra_button) {
538224014Snwhitehorn	dlg_save_vars(&save);
539224014Snwhitehorn	dialog_vars.nocancel = TRUE;
540217309Snwhitehorn	result = dlg_ok_labels();
541224014Snwhitehorn	dlg_restore_vars(&save);
542217309Snwhitehorn    } else {
543217309Snwhitehorn	static const char *labels[3];
544217309Snwhitehorn	int n = 0;
545217309Snwhitehorn
546224014Snwhitehorn	if (!dialog_vars.nook)
547224014Snwhitehorn	    labels[n++] = my_exit_label();
548217309Snwhitehorn	if (dialog_vars.help_button)
549217309Snwhitehorn	    labels[n++] = my_help_label();
550224014Snwhitehorn	if (n == 0)
551224014Snwhitehorn	    labels[n++] = my_exit_label();
552217309Snwhitehorn	labels[n] = 0;
553217309Snwhitehorn
554217309Snwhitehorn	result = labels;
555217309Snwhitehorn    }
556217309Snwhitehorn    return result;
557217309Snwhitehorn}
558217309Snwhitehorn
559217309Snwhitehorn/*
560217309Snwhitehorn * Map the given button index for dlg_exit_label() into our exit-code.
561217309Snwhitehorn */
562217309Snwhitehornint
563217309Snwhitehorndlg_exit_buttoncode(int button)
564217309Snwhitehorn{
565224014Snwhitehorn    int result;
566224014Snwhitehorn    DIALOG_VARS save;
567224014Snwhitehorn
568224014Snwhitehorn    dlg_save_vars(&save);
569224014Snwhitehorn    dialog_vars.nocancel = TRUE;
570224014Snwhitehorn
571224014Snwhitehorn    result = dlg_ok_buttoncode(button);
572224014Snwhitehorn
573224014Snwhitehorn    dlg_restore_vars(&save);
574224014Snwhitehorn
575224014Snwhitehorn    return result;
576217309Snwhitehorn}
577217309Snwhitehorn
578217309Snwhitehornconst char **
579217309Snwhitehorndlg_ok_label(void)
580217309Snwhitehorn{
581251843Sbapt    static const char *labels[4];
582217309Snwhitehorn    int n = 0;
583217309Snwhitehorn
584217309Snwhitehorn    labels[n++] = my_ok_label();
585251843Sbapt    if (dialog_vars.extra_button)
586251843Sbapt	labels[n++] = my_extra_label();
587217309Snwhitehorn    if (dialog_vars.help_button)
588217309Snwhitehorn	labels[n++] = my_help_label();
589217309Snwhitehorn    labels[n] = 0;
590217309Snwhitehorn    return labels;
591217309Snwhitehorn}
592217309Snwhitehorn
593217309Snwhitehorn/*
594217309Snwhitehorn * Return a list of button labels for the OK/Cancel group.
595217309Snwhitehorn */
596217309Snwhitehornconst char **
597217309Snwhitehorndlg_ok_labels(void)
598217309Snwhitehorn{
599217309Snwhitehorn    static const char *labels[5];
600217309Snwhitehorn    int n = 0;
601217309Snwhitehorn
602217309Snwhitehorn    if (!dialog_vars.nook)
603217309Snwhitehorn	labels[n++] = my_ok_label();
604217309Snwhitehorn    if (dialog_vars.extra_button)
605217309Snwhitehorn	labels[n++] = my_extra_label();
606217309Snwhitehorn    if (!dialog_vars.nocancel)
607217309Snwhitehorn	labels[n++] = my_cancel_label();
608217309Snwhitehorn    if (dialog_vars.help_button)
609217309Snwhitehorn	labels[n++] = my_help_label();
610217309Snwhitehorn    labels[n] = 0;
611217309Snwhitehorn    return labels;
612217309Snwhitehorn}
613217309Snwhitehorn
614217309Snwhitehorn/*
615217309Snwhitehorn * Map the given button index for dlg_ok_labels() into our exit-code
616217309Snwhitehorn */
617217309Snwhitehornint
618217309Snwhitehorndlg_ok_buttoncode(int button)
619217309Snwhitehorn{
620217309Snwhitehorn    int result = DLG_EXIT_ERROR;
621217309Snwhitehorn    int n = !dialog_vars.nook;
622217309Snwhitehorn
623217309Snwhitehorn    if (!dialog_vars.nook && (button <= 0)) {
624217309Snwhitehorn	result = DLG_EXIT_OK;
625217309Snwhitehorn    } else if (dialog_vars.extra_button && (button == n++)) {
626217309Snwhitehorn	result = DLG_EXIT_EXTRA;
627217309Snwhitehorn    } else if (!dialog_vars.nocancel && (button == n++)) {
628217309Snwhitehorn	result = DLG_EXIT_CANCEL;
629217309Snwhitehorn    } else if (dialog_vars.help_button && (button == n)) {
630217309Snwhitehorn	result = DLG_EXIT_HELP;
631217309Snwhitehorn    }
632251843Sbapt    dlg_trace_msg("# dlg_ok_buttoncode(%d) = %d\n", button, result);
633217309Snwhitehorn    return result;
634217309Snwhitehorn}
635217309Snwhitehorn
636217309Snwhitehorn/*
637217309Snwhitehorn * Given that we're using dlg_ok_labels() to list buttons, find the next index
638217309Snwhitehorn * in the list of buttons.  The 'extra' parameter if negative provides a way to
639217309Snwhitehorn * enumerate extra active areas on the widget.
640217309Snwhitehorn */
641217309Snwhitehornint
642217309Snwhitehorndlg_next_ok_buttonindex(int current, int extra)
643217309Snwhitehorn{
644217309Snwhitehorn    int result = current + 1;
645217309Snwhitehorn
646217309Snwhitehorn    if (current >= 0
647217309Snwhitehorn	&& dlg_ok_buttoncode(result) < 0)
648217309Snwhitehorn	result = extra;
649217309Snwhitehorn    return result;
650217309Snwhitehorn}
651217309Snwhitehorn
652217309Snwhitehorn/*
653217309Snwhitehorn * Similarly, find the previous button index.
654217309Snwhitehorn */
655217309Snwhitehornint
656217309Snwhitehorndlg_prev_ok_buttonindex(int current, int extra)
657217309Snwhitehorn{
658217309Snwhitehorn    int result = current - 1;
659217309Snwhitehorn
660217309Snwhitehorn    if (result < extra) {
661217309Snwhitehorn	for (result = 0; dlg_ok_buttoncode(result + 1) >= 0; ++result) {
662217309Snwhitehorn	    ;
663217309Snwhitehorn	}
664217309Snwhitehorn    }
665217309Snwhitehorn    return result;
666217309Snwhitehorn}
667217309Snwhitehorn
668217309Snwhitehorn/*
669217309Snwhitehorn * Find the button-index for the "OK" or "Cancel" button, according to
670217309Snwhitehorn * whether --defaultno is given.  If --nocancel was given, we always return
671251843Sbapt * the index for the first button (usually "OK" unless --nook was used).
672217309Snwhitehorn */
673217309Snwhitehornint
674217309Snwhitehorndlg_defaultno_button(void)
675217309Snwhitehorn{
676217309Snwhitehorn    int result = 0;
677217309Snwhitehorn
678217309Snwhitehorn    if (dialog_vars.defaultno && !dialog_vars.nocancel) {
679217309Snwhitehorn	while (dlg_ok_buttoncode(result) != DLG_EXIT_CANCEL)
680217309Snwhitehorn	    ++result;
681217309Snwhitehorn    }
682251843Sbapt    dlg_trace_msg("# dlg_defaultno_button() = %d\n", result);
683217309Snwhitehorn    return result;
684217309Snwhitehorn}
685217309Snwhitehorn
686217309Snwhitehorn/*
687251843Sbapt * Find the button-index for a button named with --default-button. If the
688251843Sbapt * option was not specified, or if the selected button does not exist, return
689251843Sbapt * the index of the first button (usually "OK" unless --nook was used).
690251843Sbapt */
691251843Sbaptint
692251843Sbaptdlg_default_button(void)
693251843Sbapt{
694251843Sbapt    int i, n;
695251843Sbapt    int result = 0;
696251843Sbapt
697251843Sbapt    if (dialog_vars.default_button >= 0) {
698251843Sbapt	for (i = 0; (n = dlg_ok_buttoncode(i)) >= 0; i++) {
699251843Sbapt	    if (n == dialog_vars.default_button) {
700251843Sbapt		result = i;
701251843Sbapt		break;
702251843Sbapt	    }
703251843Sbapt	}
704251843Sbapt    }
705251843Sbapt    dlg_trace_msg("# dlg_default_button() = %d\n", result);
706251843Sbapt    return result;
707251843Sbapt}
708251843Sbapt
709251843Sbapt/*
710217309Snwhitehorn * Return a list of buttons for Yes/No labels.
711217309Snwhitehorn */
712217309Snwhitehornconst char **
713217309Snwhitehorndlg_yes_labels(void)
714217309Snwhitehorn{
715217309Snwhitehorn    const char **result;
716217309Snwhitehorn
717217309Snwhitehorn    if (dialog_vars.extra_button) {
718217309Snwhitehorn	result = dlg_ok_labels();
719217309Snwhitehorn    } else {
720217309Snwhitehorn	static const char *labels[4];
721217309Snwhitehorn	int n = 0;
722217309Snwhitehorn
723217309Snwhitehorn	labels[n++] = my_yes_label();
724217309Snwhitehorn	labels[n++] = my_no_label();
725217309Snwhitehorn	if (dialog_vars.help_button)
726217309Snwhitehorn	    labels[n++] = my_help_label();
727217309Snwhitehorn	labels[n] = 0;
728217309Snwhitehorn
729217309Snwhitehorn	result = labels;
730217309Snwhitehorn    }
731217309Snwhitehorn
732217309Snwhitehorn    return result;
733217309Snwhitehorn}
734217309Snwhitehorn
735217309Snwhitehorn/*
736217309Snwhitehorn * Map the given button index for dlg_yes_labels() into our exit-code.
737217309Snwhitehorn */
738217309Snwhitehornint
739217309Snwhitehorndlg_yes_buttoncode(int button)
740217309Snwhitehorn{
741217309Snwhitehorn    int result = DLG_EXIT_ERROR;
742217309Snwhitehorn
743217309Snwhitehorn    if (dialog_vars.extra_button) {
744217309Snwhitehorn	result = dlg_ok_buttoncode(button);
745217309Snwhitehorn    } else if (button == 0) {
746217309Snwhitehorn	result = DLG_EXIT_OK;
747217309Snwhitehorn    } else if (button == 1) {
748217309Snwhitehorn	result = DLG_EXIT_CANCEL;
749217309Snwhitehorn    } else if (button == 2 && dialog_vars.help_button) {
750217309Snwhitehorn	result = DLG_EXIT_HELP;
751217309Snwhitehorn    }
752217309Snwhitehorn
753217309Snwhitehorn    return result;
754217309Snwhitehorn}
755217309Snwhitehorn
756217309Snwhitehorn/*
757217309Snwhitehorn * Return the next index in labels[];
758217309Snwhitehorn */
759217309Snwhitehornint
760217309Snwhitehorndlg_next_button(const char **labels, int button)
761217309Snwhitehorn{
762251843Sbapt    if (button < -1)
763251843Sbapt	button = -1;
764251843Sbapt
765251843Sbapt    if (labels[button + 1] != 0) {
766217309Snwhitehorn	++button;
767251843Sbapt    } else {
768217309Snwhitehorn	button = MIN_BUTTON;
769251843Sbapt    }
770217309Snwhitehorn    return button;
771217309Snwhitehorn}
772217309Snwhitehorn
773217309Snwhitehorn/*
774217309Snwhitehorn * Return the previous index in labels[];
775217309Snwhitehorn */
776217309Snwhitehornint
777217309Snwhitehorndlg_prev_button(const char **labels, int button)
778217309Snwhitehorn{
779251843Sbapt    if (button > MIN_BUTTON) {
780217309Snwhitehorn	--button;
781251843Sbapt    } else {
782251843Sbapt	if (button < -1)
783251843Sbapt	    button = -1;
784251843Sbapt
785217309Snwhitehorn	while (labels[button + 1] != 0)
786217309Snwhitehorn	    ++button;
787217309Snwhitehorn    }
788217309Snwhitehorn    return button;
789217309Snwhitehorn}
790