xref: /freebsd/contrib/dialog/formbox.c (revision f4f33ea0c752ff0f9bfad34991d5bbb54e71133d)
14c8945a0SNathan Whitehorn /*
2*f4f33ea0SBaptiste Daroussin  *  $Id: formbox.c,v 1.95 2018/06/21 08:23:31 tom Exp $
34c8945a0SNathan Whitehorn  *
4*f4f33ea0SBaptiste Daroussin  *  formbox.c -- implements the form (i.e., some pairs label/editbox)
54c8945a0SNathan Whitehorn  *
6*f4f33ea0SBaptiste Daroussin  *  Copyright 2003-2016,2018	Thomas E. Dickey
74c8945a0SNathan Whitehorn  *
84c8945a0SNathan Whitehorn  *  This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn  *  it under the terms of the GNU Lesser General Public License, version 2.1
104c8945a0SNathan Whitehorn  *  as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn  *
124c8945a0SNathan Whitehorn  *  This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn  *  WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
154c8945a0SNathan Whitehorn  *  Lesser General Public License for more details.
164c8945a0SNathan Whitehorn  *
174c8945a0SNathan Whitehorn  *  You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn  *  License along with this program; if not, write to
194c8945a0SNathan Whitehorn  *	Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn  *	51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn  *	Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn  *
234c8945a0SNathan Whitehorn  *  This is adapted from source contributed by
244c8945a0SNathan Whitehorn  *	Valery Reznic (valery_reznic@users.sourceforge.net)
254c8945a0SNathan Whitehorn  */
264c8945a0SNathan Whitehorn 
274c8945a0SNathan Whitehorn #include <dialog.h>
284c8945a0SNathan Whitehorn #include <dlg_keys.h>
294c8945a0SNathan Whitehorn 
304c8945a0SNathan Whitehorn #define LLEN(n) ((n) * FORMBOX_TAGS)
314c8945a0SNathan Whitehorn 
324c8945a0SNathan Whitehorn #define ItemName(i)     items[LLEN(i) + 0]
334c8945a0SNathan Whitehorn #define ItemNameY(i)    items[LLEN(i) + 1]
344c8945a0SNathan Whitehorn #define ItemNameX(i)    items[LLEN(i) + 2]
354c8945a0SNathan Whitehorn #define ItemText(i)     items[LLEN(i) + 3]
364c8945a0SNathan Whitehorn #define ItemTextY(i)    items[LLEN(i) + 4]
374c8945a0SNathan Whitehorn #define ItemTextX(i)    items[LLEN(i) + 5]
384c8945a0SNathan Whitehorn #define ItemTextFLen(i) items[LLEN(i) + 6]
394c8945a0SNathan Whitehorn #define ItemTextILen(i) items[LLEN(i) + 7]
404c8945a0SNathan Whitehorn #define ItemHelp(i)     (dialog_vars.item_help ? items[LLEN(i) + 8] : dlg_strempty())
414c8945a0SNathan Whitehorn 
424c8945a0SNathan Whitehorn static bool
434c8945a0SNathan Whitehorn is_readonly(DIALOG_FORMITEM * item)
444c8945a0SNathan Whitehorn {
454c8945a0SNathan Whitehorn     return ((item->type & 2) != 0) || (item->text_flen <= 0);
464c8945a0SNathan Whitehorn }
474c8945a0SNathan Whitehorn 
484c8945a0SNathan Whitehorn static bool
494c8945a0SNathan Whitehorn is_hidden(DIALOG_FORMITEM * item)
504c8945a0SNathan Whitehorn {
514c8945a0SNathan Whitehorn     return ((item->type & 1) != 0);
524c8945a0SNathan Whitehorn }
534c8945a0SNathan Whitehorn 
544c8945a0SNathan Whitehorn static bool
554c8945a0SNathan Whitehorn in_window(WINDOW *win, int scrollamt, int y)
564c8945a0SNathan Whitehorn {
574c8945a0SNathan Whitehorn     return (y >= scrollamt && y - scrollamt < getmaxy(win));
584c8945a0SNathan Whitehorn }
594c8945a0SNathan Whitehorn 
604c8945a0SNathan Whitehorn static bool
614c8945a0SNathan Whitehorn ok_move(WINDOW *win, int scrollamt, int y, int x)
624c8945a0SNathan Whitehorn {
634c8945a0SNathan Whitehorn     return in_window(win, scrollamt, y)
644c8945a0SNathan Whitehorn 	&& (wmove(win, y - scrollamt, x) != ERR);
654c8945a0SNathan Whitehorn }
664c8945a0SNathan Whitehorn 
674c8945a0SNathan Whitehorn static void
684c8945a0SNathan Whitehorn move_past(WINDOW *win, int y, int x)
694c8945a0SNathan Whitehorn {
704c8945a0SNathan Whitehorn     if (wmove(win, y, x) == ERR)
714c8945a0SNathan Whitehorn 	wmove(win, y, getmaxx(win) - 1);
724c8945a0SNathan Whitehorn }
734c8945a0SNathan Whitehorn 
744c8945a0SNathan Whitehorn /*
754c8945a0SNathan Whitehorn  * Print form item
764c8945a0SNathan Whitehorn  */
774c8945a0SNathan Whitehorn static int
784c8945a0SNathan Whitehorn print_item(WINDOW *win, DIALOG_FORMITEM * item, int scrollamt, bool choice)
794c8945a0SNathan Whitehorn {
804c8945a0SNathan Whitehorn     int count = 0;
814c8945a0SNathan Whitehorn     int len;
824c8945a0SNathan Whitehorn 
834c8945a0SNathan Whitehorn     if (ok_move(win, scrollamt, item->name_y, item->name_x)) {
844c8945a0SNathan Whitehorn 	len = item->name_len;
854c8945a0SNathan Whitehorn 	len = MIN(len, getmaxx(win) - item->name_x);
864c8945a0SNathan Whitehorn 	if (len > 0) {
874c8945a0SNathan Whitehorn 	    dlg_show_string(win,
884c8945a0SNathan Whitehorn 			    item->name,
894c8945a0SNathan Whitehorn 			    0,
904c8945a0SNathan Whitehorn 			    menubox_attr,
914c8945a0SNathan Whitehorn 			    item->name_y - scrollamt,
924c8945a0SNathan Whitehorn 			    item->name_x,
934c8945a0SNathan Whitehorn 			    len,
944c8945a0SNathan Whitehorn 			    FALSE,
954c8945a0SNathan Whitehorn 			    FALSE);
964c8945a0SNathan Whitehorn 	    move_past(win, item->name_y - scrollamt, item->name_x + len);
974c8945a0SNathan Whitehorn 	    count = 1;
984c8945a0SNathan Whitehorn 	}
994c8945a0SNathan Whitehorn     }
1004c8945a0SNathan Whitehorn     if (item->text_len && ok_move(win, scrollamt, item->text_y, item->text_x)) {
1014c8945a0SNathan Whitehorn 	chtype this_item_attribute;
1024c8945a0SNathan Whitehorn 
1034c8945a0SNathan Whitehorn 	len = item->text_len;
1044c8945a0SNathan Whitehorn 	len = MIN(len, getmaxx(win) - item->text_x);
1054c8945a0SNathan Whitehorn 
1064c8945a0SNathan Whitehorn 	if (!is_readonly(item)) {
1074c8945a0SNathan Whitehorn 	    this_item_attribute = choice
1084c8945a0SNathan Whitehorn 		? form_active_text_attr
1094c8945a0SNathan Whitehorn 		: form_text_attr;
1104c8945a0SNathan Whitehorn 	} else {
1114c8945a0SNathan Whitehorn 	    this_item_attribute = form_item_readonly_attr;
1124c8945a0SNathan Whitehorn 	}
1134c8945a0SNathan Whitehorn 
1144c8945a0SNathan Whitehorn 	if (len > 0) {
1154c8945a0SNathan Whitehorn 	    dlg_show_string(win,
1164c8945a0SNathan Whitehorn 			    item->text,
1174c8945a0SNathan Whitehorn 			    0,
1184c8945a0SNathan Whitehorn 			    this_item_attribute,
1194c8945a0SNathan Whitehorn 			    item->text_y - scrollamt,
1204c8945a0SNathan Whitehorn 			    item->text_x,
1214c8945a0SNathan Whitehorn 			    len,
1224c8945a0SNathan Whitehorn 			    is_hidden(item),
1234c8945a0SNathan Whitehorn 			    FALSE);
1244c8945a0SNathan Whitehorn 	    move_past(win, item->text_y - scrollamt, item->text_x + len);
1254c8945a0SNathan Whitehorn 	    count = 1;
1264c8945a0SNathan Whitehorn 	}
1274c8945a0SNathan Whitehorn     }
1284c8945a0SNathan Whitehorn     return count;
1294c8945a0SNathan Whitehorn }
1304c8945a0SNathan Whitehorn 
1314c8945a0SNathan Whitehorn /*
1324c8945a0SNathan Whitehorn  * Print the entire form.
1334c8945a0SNathan Whitehorn  */
1344c8945a0SNathan Whitehorn static void
1354c8945a0SNathan Whitehorn print_form(WINDOW *win, DIALOG_FORMITEM * item, int total, int scrollamt, int choice)
1364c8945a0SNathan Whitehorn {
1374c8945a0SNathan Whitehorn     int n;
1384c8945a0SNathan Whitehorn     int count = 0;
1394c8945a0SNathan Whitehorn 
1404c8945a0SNathan Whitehorn     for (n = 0; n < total; ++n) {
1414c8945a0SNathan Whitehorn 	count += print_item(win, item + n, scrollamt, n == choice);
1424c8945a0SNathan Whitehorn     }
1434c8945a0SNathan Whitehorn     if (count) {
1444c8945a0SNathan Whitehorn 	wbkgdset(win, menubox_attr | ' ');
1454c8945a0SNathan Whitehorn 	wclrtobot(win);
1464c8945a0SNathan Whitehorn 	(void) wnoutrefresh(win);
1474c8945a0SNathan Whitehorn     }
1484c8945a0SNathan Whitehorn }
1494c8945a0SNathan Whitehorn 
1504c8945a0SNathan Whitehorn static int
1514c8945a0SNathan Whitehorn set_choice(DIALOG_FORMITEM item[], int choice, int item_no, bool * noneditable)
1524c8945a0SNathan Whitehorn {
1534c8945a0SNathan Whitehorn     int result = -1;
1544c8945a0SNathan Whitehorn     int i;
1554c8945a0SNathan Whitehorn 
1564c8945a0SNathan Whitehorn     *noneditable = FALSE;
1574c8945a0SNathan Whitehorn     if (!is_readonly(&item[choice])) {
1584c8945a0SNathan Whitehorn 	result = choice;
1594c8945a0SNathan Whitehorn     } else {
1604c8945a0SNathan Whitehorn 	for (i = 0; i < item_no; i++) {
1614c8945a0SNathan Whitehorn 	    if (!is_readonly(&(item[i]))) {
1624c8945a0SNathan Whitehorn 		result = i;
1634c8945a0SNathan Whitehorn 		break;
1644c8945a0SNathan Whitehorn 	    }
1654c8945a0SNathan Whitehorn 	}
1664c8945a0SNathan Whitehorn 	if (result < 0) {
1674c8945a0SNathan Whitehorn 	    *noneditable = TRUE;
1684c8945a0SNathan Whitehorn 	    result = 0;
1694c8945a0SNathan Whitehorn 	}
1704c8945a0SNathan Whitehorn     }
1714c8945a0SNathan Whitehorn     return result;
1724c8945a0SNathan Whitehorn }
1734c8945a0SNathan Whitehorn 
1744c8945a0SNathan Whitehorn /*
1754c8945a0SNathan Whitehorn  * Find the last y-value in the form.
1764c8945a0SNathan Whitehorn  */
1774c8945a0SNathan Whitehorn static int
1784c8945a0SNathan Whitehorn form_limit(DIALOG_FORMITEM item[])
1794c8945a0SNathan Whitehorn {
1804c8945a0SNathan Whitehorn     int n;
1814c8945a0SNathan Whitehorn     int limit = 0;
1824c8945a0SNathan Whitehorn     for (n = 0; item[n].name != 0; ++n) {
1834c8945a0SNathan Whitehorn 	if (limit < item[n].name_y)
1844c8945a0SNathan Whitehorn 	    limit = item[n].name_y;
1854c8945a0SNathan Whitehorn 	if (limit < item[n].text_y)
1864c8945a0SNathan Whitehorn 	    limit = item[n].text_y;
1874c8945a0SNathan Whitehorn     }
1884c8945a0SNathan Whitehorn     return limit;
1894c8945a0SNathan Whitehorn }
1904c8945a0SNathan Whitehorn 
1912a3e3873SBaptiste Daroussin static int
1922a3e3873SBaptiste Daroussin is_first_field(DIALOG_FORMITEM item[], int choice)
1932a3e3873SBaptiste Daroussin {
1942a3e3873SBaptiste Daroussin     int count = 0;
1952a3e3873SBaptiste Daroussin     while (choice >= 0) {
1962a3e3873SBaptiste Daroussin 	if (item[choice].text_flen > 0) {
1972a3e3873SBaptiste Daroussin 	    ++count;
1982a3e3873SBaptiste Daroussin 	}
1992a3e3873SBaptiste Daroussin 	--choice;
2002a3e3873SBaptiste Daroussin     }
2012a3e3873SBaptiste Daroussin 
2022a3e3873SBaptiste Daroussin     return (count == 1);
2032a3e3873SBaptiste Daroussin }
2042a3e3873SBaptiste Daroussin 
2052a3e3873SBaptiste Daroussin static int
2062a3e3873SBaptiste Daroussin is_last_field(DIALOG_FORMITEM item[], int choice, int item_no)
2072a3e3873SBaptiste Daroussin {
2082a3e3873SBaptiste Daroussin     int count = 0;
2092a3e3873SBaptiste Daroussin     while (choice < item_no) {
2102a3e3873SBaptiste Daroussin 	if (item[choice].text_flen > 0) {
2112a3e3873SBaptiste Daroussin 	    ++count;
2122a3e3873SBaptiste Daroussin 	}
2132a3e3873SBaptiste Daroussin 	++choice;
2142a3e3873SBaptiste Daroussin     }
2152a3e3873SBaptiste Daroussin 
2162a3e3873SBaptiste Daroussin     return (count == 1);
2172a3e3873SBaptiste Daroussin }
2182a3e3873SBaptiste Daroussin 
2194c8945a0SNathan Whitehorn /*
2204c8945a0SNathan Whitehorn  * Tab to the next field.
2214c8945a0SNathan Whitehorn  */
2224c8945a0SNathan Whitehorn static bool
2234c8945a0SNathan Whitehorn tab_next(WINDOW *win,
2244c8945a0SNathan Whitehorn 	 DIALOG_FORMITEM item[],
2254c8945a0SNathan Whitehorn 	 int item_no,
2264c8945a0SNathan Whitehorn 	 int stepsize,
2274c8945a0SNathan Whitehorn 	 int *choice,
2284c8945a0SNathan Whitehorn 	 int *scrollamt)
2294c8945a0SNathan Whitehorn {
2304c8945a0SNathan Whitehorn     int old_choice = *choice;
2314c8945a0SNathan Whitehorn     int old_scroll = *scrollamt;
2324c8945a0SNathan Whitehorn     bool wrapped = FALSE;
2334c8945a0SNathan Whitehorn 
2344c8945a0SNathan Whitehorn     do {
2354c8945a0SNathan Whitehorn 	do {
2364c8945a0SNathan Whitehorn 	    *choice += stepsize;
2374c8945a0SNathan Whitehorn 	    if (*choice < 0) {
2384c8945a0SNathan Whitehorn 		*choice = item_no - 1;
2394c8945a0SNathan Whitehorn 		wrapped = TRUE;
2404c8945a0SNathan Whitehorn 	    } else if (*choice >= item_no) {
2414c8945a0SNathan Whitehorn 		*choice = 0;
2424c8945a0SNathan Whitehorn 		wrapped = TRUE;
2434c8945a0SNathan Whitehorn 	    }
2444c8945a0SNathan Whitehorn 	} while ((*choice != old_choice) && is_readonly(&(item[*choice])));
2454c8945a0SNathan Whitehorn 
2464c8945a0SNathan Whitehorn 	if (item[*choice].text_flen > 0) {
2474c8945a0SNathan Whitehorn 	    int lo = MIN(item[*choice].name_y, item[*choice].text_y);
2484c8945a0SNathan Whitehorn 	    int hi = MAX(item[*choice].name_y, item[*choice].text_y);
2494c8945a0SNathan Whitehorn 
2504c8945a0SNathan Whitehorn 	    if (old_choice == *choice)
2514c8945a0SNathan Whitehorn 		break;
2524c8945a0SNathan Whitehorn 	    print_item(win, item + old_choice, *scrollamt, FALSE);
2534c8945a0SNathan Whitehorn 
2544c8945a0SNathan Whitehorn 	    if (*scrollamt < lo + 1 - getmaxy(win))
2554c8945a0SNathan Whitehorn 		*scrollamt = lo + 1 - getmaxy(win);
2564c8945a0SNathan Whitehorn 	    if (*scrollamt > hi)
2574c8945a0SNathan Whitehorn 		*scrollamt = hi;
2584c8945a0SNathan Whitehorn 	    /*
2594c8945a0SNathan Whitehorn 	     * If we have to scroll to show a wrap-around, it does get
2604c8945a0SNathan Whitehorn 	     * confusing.  Just give up rather than scroll.  Tab'ing to the
2614c8945a0SNathan Whitehorn 	     * next field in a multi-column form is a different matter.  Scroll
2624c8945a0SNathan Whitehorn 	     * for that.
2634c8945a0SNathan Whitehorn 	     */
2644c8945a0SNathan Whitehorn 	    if (*scrollamt != old_scroll) {
2654c8945a0SNathan Whitehorn 		if (wrapped) {
2664c8945a0SNathan Whitehorn 		    beep();
2674c8945a0SNathan Whitehorn 		    *scrollamt = old_scroll;
2684c8945a0SNathan Whitehorn 		    *choice = old_choice;
2694c8945a0SNathan Whitehorn 		} else {
2704c8945a0SNathan Whitehorn 		    scrollok(win, TRUE);
2714c8945a0SNathan Whitehorn 		    wscrl(win, *scrollamt - old_scroll);
2724c8945a0SNathan Whitehorn 		    scrollok(win, FALSE);
2734c8945a0SNathan Whitehorn 		}
2744c8945a0SNathan Whitehorn 	    }
2754c8945a0SNathan Whitehorn 	    break;
2764c8945a0SNathan Whitehorn 	}
2774c8945a0SNathan Whitehorn     } while (*choice != old_choice);
2784c8945a0SNathan Whitehorn 
2794c8945a0SNathan Whitehorn     return (old_choice != *choice) || (old_scroll != *scrollamt);
2804c8945a0SNathan Whitehorn }
2814c8945a0SNathan Whitehorn 
2824c8945a0SNathan Whitehorn /*
2834c8945a0SNathan Whitehorn  * Scroll to the next page, putting the choice at the first editable field
2844c8945a0SNathan Whitehorn  * in that page.  Note that fields are not necessarily in top-to-bottom order,
2854c8945a0SNathan Whitehorn  * nor is there necessarily a field on each row of the window.
2864c8945a0SNathan Whitehorn  */
2874c8945a0SNathan Whitehorn static bool
2884c8945a0SNathan Whitehorn scroll_next(WINDOW *win, DIALOG_FORMITEM item[], int stepsize, int *choice, int *scrollamt)
2894c8945a0SNathan Whitehorn {
2902a3e3873SBaptiste Daroussin     bool result = TRUE;
2914c8945a0SNathan Whitehorn     int old_choice = *choice;
2924c8945a0SNathan Whitehorn     int old_scroll = *scrollamt;
2934c8945a0SNathan Whitehorn     int old_row = MIN(item[old_choice].text_y, item[old_choice].name_y);
2944c8945a0SNathan Whitehorn     int target = old_scroll + stepsize;
2954c8945a0SNathan Whitehorn     int n;
2964c8945a0SNathan Whitehorn 
2974c8945a0SNathan Whitehorn     if (stepsize < 0) {
2984c8945a0SNathan Whitehorn 	if (old_row != old_scroll)
2994c8945a0SNathan Whitehorn 	    target = old_scroll;
3004c8945a0SNathan Whitehorn 	else
3014c8945a0SNathan Whitehorn 	    target = old_scroll + stepsize;
3022a3e3873SBaptiste Daroussin 	if (target < 0) {
3032a3e3873SBaptiste Daroussin 	    result = FALSE;
3042a3e3873SBaptiste Daroussin 	}
3054c8945a0SNathan Whitehorn     } else {
3062a3e3873SBaptiste Daroussin 	if (target > form_limit(item)) {
3072a3e3873SBaptiste Daroussin 	    result = FALSE;
3082a3e3873SBaptiste Daroussin 	}
3094c8945a0SNathan Whitehorn     }
3104c8945a0SNathan Whitehorn 
3112a3e3873SBaptiste Daroussin     if (result) {
3124c8945a0SNathan Whitehorn 	for (n = 0; item[n].name != 0; ++n) {
3134c8945a0SNathan Whitehorn 	    if (item[n].text_flen > 0) {
3144c8945a0SNathan Whitehorn 		int new_row = MIN(item[n].text_y, item[n].name_y);
3154c8945a0SNathan Whitehorn 		if (abs(new_row - target) < abs(old_row - target)) {
3164c8945a0SNathan Whitehorn 		    old_row = new_row;
3174c8945a0SNathan Whitehorn 		    *choice = n;
3184c8945a0SNathan Whitehorn 		}
3194c8945a0SNathan Whitehorn 	    }
3204c8945a0SNathan Whitehorn 	}
3214c8945a0SNathan Whitehorn 
3224c8945a0SNathan Whitehorn 	if (old_choice != *choice)
3234c8945a0SNathan Whitehorn 	    print_item(win, item + old_choice, *scrollamt, FALSE);
3244c8945a0SNathan Whitehorn 
3254c8945a0SNathan Whitehorn 	*scrollamt = *choice;
3264c8945a0SNathan Whitehorn 	if (*scrollamt != old_scroll) {
3274c8945a0SNathan Whitehorn 	    scrollok(win, TRUE);
3284c8945a0SNathan Whitehorn 	    wscrl(win, *scrollamt - old_scroll);
3294c8945a0SNathan Whitehorn 	    scrollok(win, FALSE);
3304c8945a0SNathan Whitehorn 	}
3312a3e3873SBaptiste Daroussin 	result = (old_choice != *choice) || (old_scroll != *scrollamt);
3322a3e3873SBaptiste Daroussin     }
3332a3e3873SBaptiste Daroussin     if (!result)
3342a3e3873SBaptiste Daroussin 	beep();
3352a3e3873SBaptiste Daroussin     return result;
3364c8945a0SNathan Whitehorn }
3374c8945a0SNathan Whitehorn 
3384c8945a0SNathan Whitehorn /*
3394c8945a0SNathan Whitehorn  * Do a sanity check on the field length, and return the "right" value.
3404c8945a0SNathan Whitehorn  */
3414c8945a0SNathan Whitehorn static int
3424c8945a0SNathan Whitehorn real_length(DIALOG_FORMITEM * item)
3434c8945a0SNathan Whitehorn {
3444c8945a0SNathan Whitehorn     return (item->text_flen > 0
3454c8945a0SNathan Whitehorn 	    ? item->text_flen
3464c8945a0SNathan Whitehorn 	    : (item->text_flen < 0
3474c8945a0SNathan Whitehorn 	       ? -item->text_flen
3484c8945a0SNathan Whitehorn 	       : item->text_len));
3494c8945a0SNathan Whitehorn }
3504c8945a0SNathan Whitehorn 
3514c8945a0SNathan Whitehorn /*
3524c8945a0SNathan Whitehorn  * Compute the form size, setup field buffers.
3534c8945a0SNathan Whitehorn  */
3544c8945a0SNathan Whitehorn static void
3554c8945a0SNathan Whitehorn make_FORM_ELTs(DIALOG_FORMITEM * item,
3564c8945a0SNathan Whitehorn 	       int item_no,
3574c8945a0SNathan Whitehorn 	       int *min_height,
3584c8945a0SNathan Whitehorn 	       int *min_width)
3594c8945a0SNathan Whitehorn {
3604c8945a0SNathan Whitehorn     int i;
3614c8945a0SNathan Whitehorn     int min_w = 0;
3624c8945a0SNathan Whitehorn     int min_h = 0;
3634c8945a0SNathan Whitehorn 
3644c8945a0SNathan Whitehorn     for (i = 0; i < item_no; ++i) {
3654c8945a0SNathan Whitehorn 	int real_len = real_length(item + i);
3664c8945a0SNathan Whitehorn 
3674c8945a0SNathan Whitehorn 	/*
3684c8945a0SNathan Whitehorn 	 * Special value '0' for text_flen: no input allowed
3694c8945a0SNathan Whitehorn 	 * Special value '0' for text_ilen: 'be the same as text_flen'
3704c8945a0SNathan Whitehorn 	 */
3714c8945a0SNathan Whitehorn 	if (item[i].text_ilen == 0)
3724c8945a0SNathan Whitehorn 	    item[i].text_ilen = real_len;
3734c8945a0SNathan Whitehorn 
3744c8945a0SNathan Whitehorn 	min_h = MAX(min_h, item[i].name_y + 1);
3754c8945a0SNathan Whitehorn 	min_h = MAX(min_h, item[i].text_y + 1);
3764c8945a0SNathan Whitehorn 	min_w = MAX(min_w, item[i].name_x + 1 + item[i].name_len);
3774c8945a0SNathan Whitehorn 	min_w = MAX(min_w, item[i].text_x + 1 + real_len);
3784c8945a0SNathan Whitehorn 
3794c8945a0SNathan Whitehorn 	item[i].text_len = real_length(item + i);
3804c8945a0SNathan Whitehorn 
3814c8945a0SNathan Whitehorn 	/*
3824c8945a0SNathan Whitehorn 	 * We do not know the actual length of .text, so we allocate it here
3834c8945a0SNathan Whitehorn 	 * to ensure it is big enough.
3844c8945a0SNathan Whitehorn 	 */
3854c8945a0SNathan Whitehorn 	if (item[i].text_flen > 0) {
3864c8945a0SNathan Whitehorn 	    int max_len = dlg_max_input(MAX(item[i].text_ilen + 1, MAX_LEN));
3874c8945a0SNathan Whitehorn 	    char *old_text = item[i].text;
3884c8945a0SNathan Whitehorn 
3894c8945a0SNathan Whitehorn 	    item[i].text = dlg_malloc(char, (size_t) max_len + 1);
3904c8945a0SNathan Whitehorn 	    assert_ptr(item[i].text, "make_FORM_ELTs");
3914c8945a0SNathan Whitehorn 
3924c8945a0SNathan Whitehorn 	    sprintf(item[i].text, "%.*s", item[i].text_ilen, old_text);
3934c8945a0SNathan Whitehorn 
3944c8945a0SNathan Whitehorn 	    if (item[i].text_free) {
3954c8945a0SNathan Whitehorn 		item[i].text_free = FALSE;
3964c8945a0SNathan Whitehorn 		free(old_text);
3974c8945a0SNathan Whitehorn 	    }
3984c8945a0SNathan Whitehorn 	    item[i].text_free = TRUE;
3994c8945a0SNathan Whitehorn 	}
4004c8945a0SNathan Whitehorn     }
4014c8945a0SNathan Whitehorn 
4024c8945a0SNathan Whitehorn     *min_height = min_h;
4034c8945a0SNathan Whitehorn     *min_width = min_w;
4044c8945a0SNathan Whitehorn }
4054c8945a0SNathan Whitehorn 
4064c8945a0SNathan Whitehorn int
4074c8945a0SNathan Whitehorn dlg_default_formitem(DIALOG_FORMITEM * items)
4084c8945a0SNathan Whitehorn {
4094c8945a0SNathan Whitehorn     int result = 0;
4104c8945a0SNathan Whitehorn 
4114c8945a0SNathan Whitehorn     if (dialog_vars.default_item != 0) {
4124c8945a0SNathan Whitehorn 	int count = 0;
4134c8945a0SNathan Whitehorn 	while (items->name != 0) {
4144c8945a0SNathan Whitehorn 	    if (!strcmp(dialog_vars.default_item, items->name)) {
4154c8945a0SNathan Whitehorn 		result = count;
4164c8945a0SNathan Whitehorn 		break;
4174c8945a0SNathan Whitehorn 	    }
4184c8945a0SNathan Whitehorn 	    ++items;
4194c8945a0SNathan Whitehorn 	    count++;
4204c8945a0SNathan Whitehorn 	}
4214c8945a0SNathan Whitehorn     }
4224c8945a0SNathan Whitehorn     return result;
4234c8945a0SNathan Whitehorn }
4244c8945a0SNathan Whitehorn 
4254c8945a0SNathan Whitehorn #define sTEXT -1
4264c8945a0SNathan Whitehorn 
4274c8945a0SNathan Whitehorn static int
4284c8945a0SNathan Whitehorn next_valid_buttonindex(int state, int extra, bool non_editable)
4294c8945a0SNathan Whitehorn {
4304c8945a0SNathan Whitehorn     state = dlg_next_ok_buttonindex(state, extra);
4314c8945a0SNathan Whitehorn     while (non_editable && state == sTEXT)
4324c8945a0SNathan Whitehorn 	state = dlg_next_ok_buttonindex(state, sTEXT);
4334c8945a0SNathan Whitehorn     return state;
4344c8945a0SNathan Whitehorn }
4354c8945a0SNathan Whitehorn 
4364c8945a0SNathan Whitehorn static int
4374c8945a0SNathan Whitehorn prev_valid_buttonindex(int state, int extra, bool non_editable)
4384c8945a0SNathan Whitehorn {
4394c8945a0SNathan Whitehorn     state = dlg_prev_ok_buttonindex(state, extra);
4404c8945a0SNathan Whitehorn     while (non_editable && state == sTEXT)
4414c8945a0SNathan Whitehorn 	state = dlg_prev_ok_buttonindex(state, sTEXT);
4424c8945a0SNathan Whitehorn     return state;
4434c8945a0SNathan Whitehorn }
4444c8945a0SNathan Whitehorn 
4454c8945a0SNathan Whitehorn #define NAVIGATE_BINDINGS \
4464c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), \
4474c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), \
4484c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  CHR_NEXT ), \
4494c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_DOWN ), \
450*f4f33ea0SBaptiste Daroussin 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_RIGHT ), \
4514c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_NEXT ), \
4524c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  CHR_PREVIOUS ), \
4534c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_PREVIOUS ), \
454*f4f33ea0SBaptiste Daroussin 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_LEFT ), \
4554c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_UP ), \
4564c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ), \
4574c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE )
4584c8945a0SNathan Whitehorn /*
4592a3e3873SBaptiste Daroussin  * Display a form for entering a number of fields
4604c8945a0SNathan Whitehorn  */
4614c8945a0SNathan Whitehorn int
4624c8945a0SNathan Whitehorn dlg_form(const char *title,
4634c8945a0SNathan Whitehorn 	 const char *cprompt,
4644c8945a0SNathan Whitehorn 	 int height,
4654c8945a0SNathan Whitehorn 	 int width,
4664c8945a0SNathan Whitehorn 	 int form_height,
4674c8945a0SNathan Whitehorn 	 int item_no,
4684c8945a0SNathan Whitehorn 	 DIALOG_FORMITEM * items,
4694c8945a0SNathan Whitehorn 	 int *current_item)
4704c8945a0SNathan Whitehorn {
4714c8945a0SNathan Whitehorn     /* *INDENT-OFF* */
4724c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding[] = {
473682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
4744c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
4754c8945a0SNathan Whitehorn 	NAVIGATE_BINDINGS,
476*f4f33ea0SBaptiste Daroussin 	TOGGLEKEY_BINDINGS,
4774c8945a0SNathan Whitehorn 	END_KEYS_BINDING
4784c8945a0SNathan Whitehorn     };
4794c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding2[] = {
4804c8945a0SNathan Whitehorn 	INPUTSTR_BINDINGS,
481682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
4824c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
4834c8945a0SNathan Whitehorn 	NAVIGATE_BINDINGS,
484*f4f33ea0SBaptiste Daroussin 	/* no TOGGLEKEY_BINDINGS, since that includes space... */
4854c8945a0SNathan Whitehorn 	END_KEYS_BINDING
4864c8945a0SNathan Whitehorn     };
4874c8945a0SNathan Whitehorn     /* *INDENT-ON* */
4884c8945a0SNathan Whitehorn 
4894c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
4904c8945a0SNathan Whitehorn     int old_height = height;
4914c8945a0SNathan Whitehorn     int old_width = width;
4924c8945a0SNathan Whitehorn #endif
4934c8945a0SNathan Whitehorn 
4944c8945a0SNathan Whitehorn     int form_width;
495*f4f33ea0SBaptiste Daroussin     bool first = TRUE;
496*f4f33ea0SBaptiste Daroussin     bool first_trace = TRUE;
4974c8945a0SNathan Whitehorn     int chr_offset = 0;
498*f4f33ea0SBaptiste Daroussin     int state = (dialog_vars.default_button >= 0
499*f4f33ea0SBaptiste Daroussin 		 ? dlg_default_button()
500*f4f33ea0SBaptiste Daroussin 		 : sTEXT);
5014c8945a0SNathan Whitehorn     int x, y, cur_x, cur_y, box_x, box_y;
5024c8945a0SNathan Whitehorn     int code;
5034c8945a0SNathan Whitehorn     int key = 0;
5044c8945a0SNathan Whitehorn     int fkey;
5054c8945a0SNathan Whitehorn     int choice = dlg_default_formitem(items);
5064c8945a0SNathan Whitehorn     int new_choice, new_scroll;
5074c8945a0SNathan Whitehorn     int scrollamt = 0;
5084c8945a0SNathan Whitehorn     int result = DLG_EXIT_UNKNOWN;
5094c8945a0SNathan Whitehorn     int min_width = 0, min_height = 0;
5104c8945a0SNathan Whitehorn     bool was_autosize = (height == 0 || width == 0);
5114c8945a0SNathan Whitehorn     bool show_buttons = FALSE;
5124c8945a0SNathan Whitehorn     bool scroll_changed = FALSE;
5134c8945a0SNathan Whitehorn     bool field_changed = FALSE;
5144c8945a0SNathan Whitehorn     bool non_editable = FALSE;
5154c8945a0SNathan Whitehorn     WINDOW *dialog, *form;
516*f4f33ea0SBaptiste Daroussin     char *prompt;
5174c8945a0SNathan Whitehorn     const char **buttons = dlg_ok_labels();
5184c8945a0SNathan Whitehorn     DIALOG_FORMITEM *current;
5194c8945a0SNathan Whitehorn 
520*f4f33ea0SBaptiste Daroussin     DLG_TRACE(("# %sform args:\n", (dialog_vars.formitem_type
521*f4f33ea0SBaptiste Daroussin 				    ? "password"
522*f4f33ea0SBaptiste Daroussin 				    : "")));
523*f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("title", title);
524*f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("message", cprompt);
525*f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("height", height);
526*f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("width", width);
527*f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("lheight", form_height);
528*f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("llength", item_no);
529*f4f33ea0SBaptiste Daroussin     /* FIXME dump the items[][] too */
530*f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("current", *current_item);
531*f4f33ea0SBaptiste Daroussin 
5324c8945a0SNathan Whitehorn     make_FORM_ELTs(items, item_no, &min_height, &min_width);
5334c8945a0SNathan Whitehorn     dlg_button_layout(buttons, &min_width);
5344c8945a0SNathan Whitehorn     dlg_does_output();
5354c8945a0SNathan Whitehorn 
5364c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
5374c8945a0SNathan Whitehorn   retry:
5384c8945a0SNathan Whitehorn #endif
5394c8945a0SNathan Whitehorn 
540*f4f33ea0SBaptiste Daroussin     prompt = dlg_strclone(cprompt);
541*f4f33ea0SBaptiste Daroussin     dlg_tab_correct_str(prompt);
5424c8945a0SNathan Whitehorn     dlg_auto_size(title, prompt, &height, &width,
5434c8945a0SNathan Whitehorn 		  1 + 3 * MARGIN,
5444c8945a0SNathan Whitehorn 		  MAX(26, 2 + min_width));
5454c8945a0SNathan Whitehorn 
5464c8945a0SNathan Whitehorn     if (form_height == 0)
5474c8945a0SNathan Whitehorn 	form_height = min_height;
5484c8945a0SNathan Whitehorn 
5494c8945a0SNathan Whitehorn     if (was_autosize) {
5504c8945a0SNathan Whitehorn 	form_height = MIN(SLINES - height, form_height);
5514c8945a0SNathan Whitehorn 	height += form_height;
5524c8945a0SNathan Whitehorn     } else {
5534c8945a0SNathan Whitehorn 	int thigh = 0;
5544c8945a0SNathan Whitehorn 	int twide = 0;
5554c8945a0SNathan Whitehorn 	dlg_auto_size(title, prompt, &thigh, &twide, 0, width);
5564c8945a0SNathan Whitehorn 	thigh = SLINES - (height - (thigh + 1 + 3 * MARGIN));
5574c8945a0SNathan Whitehorn 	form_height = MIN(thigh, form_height);
5584c8945a0SNathan Whitehorn     }
5594c8945a0SNathan Whitehorn 
5604c8945a0SNathan Whitehorn     dlg_print_size(height, width);
5614c8945a0SNathan Whitehorn     dlg_ctl_size(height, width);
5624c8945a0SNathan Whitehorn 
5634c8945a0SNathan Whitehorn     x = dlg_box_x_ordinate(width);
5644c8945a0SNathan Whitehorn     y = dlg_box_y_ordinate(height);
5654c8945a0SNathan Whitehorn 
5664c8945a0SNathan Whitehorn     dialog = dlg_new_window(height, width, y, x);
5674c8945a0SNathan Whitehorn     dlg_register_window(dialog, "formbox", binding);
5684c8945a0SNathan Whitehorn     dlg_register_buttons(dialog, "formbox", buttons);
5694c8945a0SNathan Whitehorn 
5704c8945a0SNathan Whitehorn     dlg_mouse_setbase(x, y);
5714c8945a0SNathan Whitehorn 
5722a3e3873SBaptiste Daroussin     dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
5732a3e3873SBaptiste Daroussin     dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
5744c8945a0SNathan Whitehorn     dlg_draw_title(dialog, title);
5754c8945a0SNathan Whitehorn 
576*f4f33ea0SBaptiste Daroussin     dlg_attrset(dialog, dialog_attr);
5774c8945a0SNathan Whitehorn     dlg_print_autowrap(dialog, prompt, height, width);
5784c8945a0SNathan Whitehorn 
5794c8945a0SNathan Whitehorn     form_width = width - 6;
5804c8945a0SNathan Whitehorn     getyx(dialog, cur_y, cur_x);
5812a3e3873SBaptiste Daroussin     (void) cur_x;
5824c8945a0SNathan Whitehorn     box_y = cur_y + 1;
5834c8945a0SNathan Whitehorn     box_x = (width - form_width) / 2 - 1;
5844c8945a0SNathan Whitehorn 
5854c8945a0SNathan Whitehorn     /* create new window for the form */
5864c8945a0SNathan Whitehorn     form = dlg_sub_window(dialog, form_height, form_width, y + box_y + 1,
5874c8945a0SNathan Whitehorn 			  x + box_x + 1);
5882a3e3873SBaptiste Daroussin     dlg_register_window(form, "formfield", binding2);
5894c8945a0SNathan Whitehorn 
5904c8945a0SNathan Whitehorn     /* draw a box around the form items */
5914c8945a0SNathan Whitehorn     dlg_draw_box(dialog, box_y, box_x, form_height + 2, form_width + 2,
5922a3e3873SBaptiste Daroussin 		 menubox_border_attr, menubox_border2_attr);
5934c8945a0SNathan Whitehorn 
5944c8945a0SNathan Whitehorn     /* register the new window, along with its borders */
5954c8945a0SNathan Whitehorn     dlg_mouse_mkbigregion(getbegy(form) - getbegy(dialog),
5964c8945a0SNathan Whitehorn 			  getbegx(form) - getbegx(dialog),
5974c8945a0SNathan Whitehorn 			  getmaxy(form),
5984c8945a0SNathan Whitehorn 			  getmaxx(form),
5994c8945a0SNathan Whitehorn 			  KEY_MAX, 1, 1, 3 /* by cells */ );
6004c8945a0SNathan Whitehorn 
6014c8945a0SNathan Whitehorn     show_buttons = TRUE;
6024c8945a0SNathan Whitehorn     scroll_changed = TRUE;
6034c8945a0SNathan Whitehorn 
6044c8945a0SNathan Whitehorn     choice = set_choice(items, choice, item_no, &non_editable);
6054c8945a0SNathan Whitehorn     current = &items[choice];
6064c8945a0SNathan Whitehorn     if (non_editable)
6074c8945a0SNathan Whitehorn 	state = next_valid_buttonindex(state, sTEXT, non_editable);
6084c8945a0SNathan Whitehorn 
6094c8945a0SNathan Whitehorn     while (result == DLG_EXIT_UNKNOWN) {
6104c8945a0SNathan Whitehorn 	int edit = FALSE;
6114c8945a0SNathan Whitehorn 
6124c8945a0SNathan Whitehorn 	if (scroll_changed) {
6134c8945a0SNathan Whitehorn 	    print_form(form, items, item_no, scrollamt, choice);
6144c8945a0SNathan Whitehorn 	    dlg_draw_scrollbar(dialog,
6154c8945a0SNathan Whitehorn 			       scrollamt,
6164c8945a0SNathan Whitehorn 			       scrollamt,
6174c8945a0SNathan Whitehorn 			       scrollamt + form_height + 1,
6184c8945a0SNathan Whitehorn 			       min_height,
6194c8945a0SNathan Whitehorn 			       box_x + 1,
6204c8945a0SNathan Whitehorn 			       box_x + form_width,
6214c8945a0SNathan Whitehorn 			       box_y,
6224c8945a0SNathan Whitehorn 			       box_y + form_height + 1,
6232a3e3873SBaptiste Daroussin 			       menubox_border2_attr,
6244c8945a0SNathan Whitehorn 			       menubox_border_attr);
6254c8945a0SNathan Whitehorn 	    scroll_changed = FALSE;
6264c8945a0SNathan Whitehorn 	}
6274c8945a0SNathan Whitehorn 
6284c8945a0SNathan Whitehorn 	if (show_buttons) {
6294c8945a0SNathan Whitehorn 	    dlg_item_help("");
6304c8945a0SNathan Whitehorn 	    dlg_draw_buttons(dialog, height - 2, 0, buttons,
6314c8945a0SNathan Whitehorn 			     ((state < 0)
6324c8945a0SNathan Whitehorn 			      ? 1000	/* no such button, not highlighted */
6334c8945a0SNathan Whitehorn 			      : state),
6344c8945a0SNathan Whitehorn 			     FALSE, width);
6354c8945a0SNathan Whitehorn 	    show_buttons = FALSE;
6364c8945a0SNathan Whitehorn 	}
6374c8945a0SNathan Whitehorn 
6382a3e3873SBaptiste Daroussin 	if (first_trace) {
6392a3e3873SBaptiste Daroussin 	    first_trace = FALSE;
6402a3e3873SBaptiste Daroussin 	    dlg_trace_win(dialog);
6412a3e3873SBaptiste Daroussin 	}
6422a3e3873SBaptiste Daroussin 
6434c8945a0SNathan Whitehorn 	if (field_changed || state == sTEXT) {
6444c8945a0SNathan Whitehorn 	    if (field_changed)
6454c8945a0SNathan Whitehorn 		chr_offset = 0;
6464c8945a0SNathan Whitehorn 	    current = &items[choice];
6474c8945a0SNathan Whitehorn 	    dialog_vars.max_input = current->text_ilen;
6484c8945a0SNathan Whitehorn 	    dlg_item_help(current->help);
6494c8945a0SNathan Whitehorn 	    dlg_show_string(form, current->text, chr_offset,
6504c8945a0SNathan Whitehorn 			    form_active_text_attr,
6514c8945a0SNathan Whitehorn 			    current->text_y - scrollamt,
6524c8945a0SNathan Whitehorn 			    current->text_x,
6534c8945a0SNathan Whitehorn 			    current->text_len,
6544c8945a0SNathan Whitehorn 			    is_hidden(current), first);
6552a3e3873SBaptiste Daroussin 	    wsyncup(form);
6562a3e3873SBaptiste Daroussin 	    wcursyncup(form);
6574c8945a0SNathan Whitehorn 	    field_changed = FALSE;
6584c8945a0SNathan Whitehorn 	}
6594c8945a0SNathan Whitehorn 
6602a3e3873SBaptiste Daroussin 	key = dlg_mouse_wgetch((state == sTEXT) ? form : dialog, &fkey);
6614c8945a0SNathan Whitehorn 	if (dlg_result_key(key, fkey, &result))
6624c8945a0SNathan Whitehorn 	    break;
6634c8945a0SNathan Whitehorn 
6644c8945a0SNathan Whitehorn 	/* handle non-functionkeys */
6654c8945a0SNathan Whitehorn 	if (!fkey) {
6664c8945a0SNathan Whitehorn 	    if (state != sTEXT) {
6674c8945a0SNathan Whitehorn 		code = dlg_char_to_button(key, buttons);
6684c8945a0SNathan Whitehorn 		if (code >= 0) {
6694c8945a0SNathan Whitehorn 		    dlg_del_window(dialog);
6704c8945a0SNathan Whitehorn 		    result = dlg_ok_buttoncode(code);
6714c8945a0SNathan Whitehorn 		    continue;
6724c8945a0SNathan Whitehorn 		}
6734c8945a0SNathan Whitehorn 	    }
6744c8945a0SNathan Whitehorn 	}
6754c8945a0SNathan Whitehorn 
6764c8945a0SNathan Whitehorn 	/* handle functionkeys */
6774c8945a0SNathan Whitehorn 	if (fkey) {
6784c8945a0SNathan Whitehorn 	    bool do_scroll = FALSE;
6794c8945a0SNathan Whitehorn 	    bool do_tab = FALSE;
6804c8945a0SNathan Whitehorn 	    int move_by = 0;
6814c8945a0SNathan Whitehorn 
6824c8945a0SNathan Whitehorn 	    switch (key) {
6834c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_PPAGE):
6844c8945a0SNathan Whitehorn 	    case DLGK_PAGE_PREV:
6854c8945a0SNathan Whitehorn 		do_scroll = TRUE;
6864c8945a0SNathan Whitehorn 		move_by = -form_height;
6874c8945a0SNathan Whitehorn 		break;
6884c8945a0SNathan Whitehorn 
6894c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_NPAGE):
6904c8945a0SNathan Whitehorn 	    case DLGK_PAGE_NEXT:
6914c8945a0SNathan Whitehorn 		do_scroll = TRUE;
6924c8945a0SNathan Whitehorn 		move_by = form_height;
6934c8945a0SNathan Whitehorn 		break;
6944c8945a0SNathan Whitehorn 
695*f4f33ea0SBaptiste Daroussin 	    case DLGK_TOGGLE:
6964c8945a0SNathan Whitehorn 	    case DLGK_ENTER:
6974c8945a0SNathan Whitehorn 		dlg_del_window(dialog);
698682c9e0fSNathan Whitehorn 		result = (state >= 0) ? dlg_enter_buttoncode(state) : DLG_EXIT_OK;
6994c8945a0SNathan Whitehorn 		continue;
7004c8945a0SNathan Whitehorn 
7014c8945a0SNathan Whitehorn 	    case DLGK_GRID_LEFT:
7024c8945a0SNathan Whitehorn 		if (state == sTEXT)
7034c8945a0SNathan Whitehorn 		    break;
7044c8945a0SNathan Whitehorn 		/* FALLTHRU */
7054c8945a0SNathan Whitehorn 	    case DLGK_ITEM_PREV:
7064c8945a0SNathan Whitehorn 		if (state == sTEXT) {
7074c8945a0SNathan Whitehorn 		    do_tab = TRUE;
7084c8945a0SNathan Whitehorn 		    move_by = -1;
7094c8945a0SNathan Whitehorn 		    break;
7104c8945a0SNathan Whitehorn 		} else {
7114c8945a0SNathan Whitehorn 		    state = prev_valid_buttonindex(state, 0, non_editable);
7124c8945a0SNathan Whitehorn 		    show_buttons = TRUE;
7134c8945a0SNathan Whitehorn 		    continue;
7144c8945a0SNathan Whitehorn 		}
7154c8945a0SNathan Whitehorn 
7162a3e3873SBaptiste Daroussin 	    case DLGK_FORM_PREV:
7172a3e3873SBaptiste Daroussin 		if (state == sTEXT && !is_first_field(items, choice)) {
7182a3e3873SBaptiste Daroussin 		    do_tab = TRUE;
7192a3e3873SBaptiste Daroussin 		    move_by = -1;
7202a3e3873SBaptiste Daroussin 		    break;
7212a3e3873SBaptiste Daroussin 		} else {
7222a3e3873SBaptiste Daroussin 		    int old_state = state;
7232a3e3873SBaptiste Daroussin 		    state = prev_valid_buttonindex(state, sTEXT, non_editable);
7242a3e3873SBaptiste Daroussin 		    show_buttons = TRUE;
7252a3e3873SBaptiste Daroussin 		    if (old_state >= 0 && state == sTEXT) {
7262a3e3873SBaptiste Daroussin 			new_choice = item_no - 1;
7272a3e3873SBaptiste Daroussin 			if (choice != new_choice) {
7282a3e3873SBaptiste Daroussin 			    print_item(form, items + choice, scrollamt, FALSE);
7292a3e3873SBaptiste Daroussin 			    choice = new_choice;
7302a3e3873SBaptiste Daroussin 			}
7312a3e3873SBaptiste Daroussin 		    }
7322a3e3873SBaptiste Daroussin 		    continue;
7332a3e3873SBaptiste Daroussin 		}
7342a3e3873SBaptiste Daroussin 
7354c8945a0SNathan Whitehorn 	    case DLGK_FIELD_PREV:
7364c8945a0SNathan Whitehorn 		state = prev_valid_buttonindex(state, sTEXT, non_editable);
7374c8945a0SNathan Whitehorn 		show_buttons = TRUE;
7384c8945a0SNathan Whitehorn 		continue;
7394c8945a0SNathan Whitehorn 
7404c8945a0SNathan Whitehorn 	    case DLGK_FIELD_NEXT:
7414c8945a0SNathan Whitehorn 		state = next_valid_buttonindex(state, sTEXT, non_editable);
7424c8945a0SNathan Whitehorn 		show_buttons = TRUE;
7434c8945a0SNathan Whitehorn 		continue;
7444c8945a0SNathan Whitehorn 
7454c8945a0SNathan Whitehorn 	    case DLGK_GRID_RIGHT:
7464c8945a0SNathan Whitehorn 		if (state == sTEXT)
7474c8945a0SNathan Whitehorn 		    break;
7484c8945a0SNathan Whitehorn 		/* FALLTHRU */
7494c8945a0SNathan Whitehorn 
7504c8945a0SNathan Whitehorn 	    case DLGK_ITEM_NEXT:
7514c8945a0SNathan Whitehorn 		if (state == sTEXT) {
7524c8945a0SNathan Whitehorn 		    do_tab = TRUE;
7534c8945a0SNathan Whitehorn 		    move_by = 1;
7544c8945a0SNathan Whitehorn 		    break;
7554c8945a0SNathan Whitehorn 		} else {
7564c8945a0SNathan Whitehorn 		    state = next_valid_buttonindex(state, 0, non_editable);
7574c8945a0SNathan Whitehorn 		    show_buttons = TRUE;
7584c8945a0SNathan Whitehorn 		    continue;
7594c8945a0SNathan Whitehorn 		}
7604c8945a0SNathan Whitehorn 
7612a3e3873SBaptiste Daroussin 	    case DLGK_FORM_NEXT:
7622a3e3873SBaptiste Daroussin 		if (state == sTEXT && !is_last_field(items, choice, item_no)) {
7632a3e3873SBaptiste Daroussin 		    do_tab = TRUE;
7642a3e3873SBaptiste Daroussin 		    move_by = 1;
7652a3e3873SBaptiste Daroussin 		    break;
7662a3e3873SBaptiste Daroussin 		} else {
7672a3e3873SBaptiste Daroussin 		    state = next_valid_buttonindex(state, sTEXT, non_editable);
7682a3e3873SBaptiste Daroussin 		    show_buttons = TRUE;
7692a3e3873SBaptiste Daroussin 		    if (state == sTEXT && choice) {
7702a3e3873SBaptiste Daroussin 			print_item(form, items + choice, scrollamt, FALSE);
7712a3e3873SBaptiste Daroussin 			choice = 0;
7722a3e3873SBaptiste Daroussin 		    }
7732a3e3873SBaptiste Daroussin 		    continue;
7742a3e3873SBaptiste Daroussin 		}
7752a3e3873SBaptiste Daroussin 
7764c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7774c8945a0SNathan Whitehorn 	    case KEY_RESIZE:
778*f4f33ea0SBaptiste Daroussin 		dlg_will_resize(dialog);
7794c8945a0SNathan Whitehorn 		/* reset data */
7804c8945a0SNathan Whitehorn 		height = old_height;
7814c8945a0SNathan Whitehorn 		width = old_width;
782*f4f33ea0SBaptiste Daroussin 		free(prompt);
7834c8945a0SNathan Whitehorn 		dlg_clear();
784*f4f33ea0SBaptiste Daroussin 		dlg_unregister_window(form);
7854c8945a0SNathan Whitehorn 		dlg_del_window(dialog);
7864c8945a0SNathan Whitehorn 		dlg_mouse_free_regions();
787*f4f33ea0SBaptiste Daroussin 		/* repaint */
7884c8945a0SNathan Whitehorn 		goto retry;
7894c8945a0SNathan Whitehorn #endif
7904c8945a0SNathan Whitehorn 	    default:
7914c8945a0SNathan Whitehorn #if USE_MOUSE
7924c8945a0SNathan Whitehorn 		if (is_DLGK_MOUSE(key)) {
7934c8945a0SNathan Whitehorn 		    if (key >= DLGK_MOUSE(KEY_MAX)) {
7944c8945a0SNathan Whitehorn 			int cell = key - DLGK_MOUSE(KEY_MAX);
7954c8945a0SNathan Whitehorn 			int row = (cell / getmaxx(form)) + scrollamt;
7964c8945a0SNathan Whitehorn 			int col = (cell % getmaxx(form));
7974c8945a0SNathan Whitehorn 			int n;
7984c8945a0SNathan Whitehorn 
7994c8945a0SNathan Whitehorn 			for (n = 0; n < item_no; ++n) {
8004c8945a0SNathan Whitehorn 			    if (items[n].name_y == row
8014c8945a0SNathan Whitehorn 				&& items[n].name_x <= col
8024c8945a0SNathan Whitehorn 				&& (items[n].name_x + items[n].name_len > col
8034c8945a0SNathan Whitehorn 				    || (items[n].name_y == items[n].text_y
8044c8945a0SNathan Whitehorn 					&& items[n].text_x > col))) {
8054c8945a0SNathan Whitehorn 				if (!is_readonly(&(items[n]))) {
8064c8945a0SNathan Whitehorn 				    field_changed = TRUE;
8074c8945a0SNathan Whitehorn 				    break;
8084c8945a0SNathan Whitehorn 				}
8094c8945a0SNathan Whitehorn 			    }
8104c8945a0SNathan Whitehorn 			    if (items[n].text_y == row
8114c8945a0SNathan Whitehorn 				&& items[n].text_x <= col
8124c8945a0SNathan Whitehorn 				&& items[n].text_x + items[n].text_ilen > col) {
8134c8945a0SNathan Whitehorn 				if (!is_readonly(&(items[n]))) {
8144c8945a0SNathan Whitehorn 				    field_changed = TRUE;
8154c8945a0SNathan Whitehorn 				    break;
8164c8945a0SNathan Whitehorn 				}
8174c8945a0SNathan Whitehorn 			    }
8184c8945a0SNathan Whitehorn 			}
8194c8945a0SNathan Whitehorn 			if (field_changed) {
8204c8945a0SNathan Whitehorn 			    print_item(form, items + choice, scrollamt, FALSE);
8214c8945a0SNathan Whitehorn 			    choice = n;
8224c8945a0SNathan Whitehorn 			    continue;
8234c8945a0SNathan Whitehorn 			}
8244c8945a0SNathan Whitehorn 			beep();
8254c8945a0SNathan Whitehorn 		    } else if ((code = dlg_ok_buttoncode(key - M_EVENT)) >= 0) {
8264c8945a0SNathan Whitehorn 			result = code;
8274c8945a0SNathan Whitehorn 		    }
8284c8945a0SNathan Whitehorn 		    continue;
8294c8945a0SNathan Whitehorn 		}
8304c8945a0SNathan Whitehorn #endif
8314c8945a0SNathan Whitehorn 		break;
8324c8945a0SNathan Whitehorn 	    }
8334c8945a0SNathan Whitehorn 
8344c8945a0SNathan Whitehorn 	    new_scroll = scrollamt;
8354c8945a0SNathan Whitehorn 	    new_choice = choice;
8364c8945a0SNathan Whitehorn 	    if (do_scroll) {
8374c8945a0SNathan Whitehorn 		if (scroll_next(form, items, move_by, &new_choice, &new_scroll)) {
8384c8945a0SNathan Whitehorn 		    if (choice != new_choice) {
8394c8945a0SNathan Whitehorn 			choice = new_choice;
8404c8945a0SNathan Whitehorn 			field_changed = TRUE;
8414c8945a0SNathan Whitehorn 		    }
8424c8945a0SNathan Whitehorn 		    if (scrollamt != new_scroll) {
8434c8945a0SNathan Whitehorn 			scrollamt = new_scroll;
8444c8945a0SNathan Whitehorn 			scroll_changed = TRUE;
8454c8945a0SNathan Whitehorn 		    }
8464c8945a0SNathan Whitehorn 		}
8474c8945a0SNathan Whitehorn 		continue;
8484c8945a0SNathan Whitehorn 	    }
8494c8945a0SNathan Whitehorn 	    if (do_tab) {
8504c8945a0SNathan Whitehorn 		if (tab_next(form, items, item_no, move_by, &new_choice, &new_scroll)) {
8514c8945a0SNathan Whitehorn 		    if (choice != new_choice) {
8524c8945a0SNathan Whitehorn 			choice = new_choice;
8534c8945a0SNathan Whitehorn 			field_changed = TRUE;
8544c8945a0SNathan Whitehorn 		    }
8554c8945a0SNathan Whitehorn 		    if (scrollamt != new_scroll) {
8564c8945a0SNathan Whitehorn 			scrollamt = new_scroll;
8574c8945a0SNathan Whitehorn 			scroll_changed = TRUE;
8584c8945a0SNathan Whitehorn 		    }
8594c8945a0SNathan Whitehorn 		}
8604c8945a0SNathan Whitehorn 		continue;
8614c8945a0SNathan Whitehorn 	    }
8624c8945a0SNathan Whitehorn 	}
8634c8945a0SNathan Whitehorn 
8644c8945a0SNathan Whitehorn 	if (state == sTEXT) {	/* Input box selected */
8654c8945a0SNathan Whitehorn 	    if (!is_readonly(current))
8664c8945a0SNathan Whitehorn 		edit = dlg_edit_string(current->text, &chr_offset, key,
8674c8945a0SNathan Whitehorn 				       fkey, first);
8684c8945a0SNathan Whitehorn 	    if (edit) {
8694c8945a0SNathan Whitehorn 		dlg_show_string(form, current->text, chr_offset,
8704c8945a0SNathan Whitehorn 				form_active_text_attr,
8714c8945a0SNathan Whitehorn 				current->text_y - scrollamt,
8724c8945a0SNathan Whitehorn 				current->text_x,
8734c8945a0SNathan Whitehorn 				current->text_len,
8744c8945a0SNathan Whitehorn 				is_hidden(current), first);
8754c8945a0SNathan Whitehorn 		continue;
8764c8945a0SNathan Whitehorn 	    }
8774c8945a0SNathan Whitehorn 	}
8784c8945a0SNathan Whitehorn 
8794c8945a0SNathan Whitehorn     }
8804c8945a0SNathan Whitehorn 
8814c8945a0SNathan Whitehorn     dlg_mouse_free_regions();
882*f4f33ea0SBaptiste Daroussin     dlg_unregister_window(form);
8834c8945a0SNathan Whitehorn     dlg_del_window(dialog);
8844c8945a0SNathan Whitehorn     free(prompt);
8854c8945a0SNathan Whitehorn 
8864c8945a0SNathan Whitehorn     *current_item = choice;
8874c8945a0SNathan Whitehorn     return result;
8884c8945a0SNathan Whitehorn }
8894c8945a0SNathan Whitehorn 
8904c8945a0SNathan Whitehorn /*
8914c8945a0SNathan Whitehorn  * Free memory owned by a list of DIALOG_FORMITEM's.
8924c8945a0SNathan Whitehorn  */
8934c8945a0SNathan Whitehorn void
8944c8945a0SNathan Whitehorn dlg_free_formitems(DIALOG_FORMITEM * items)
8954c8945a0SNathan Whitehorn {
8964c8945a0SNathan Whitehorn     int n;
8974c8945a0SNathan Whitehorn     for (n = 0; items[n].name != 0; ++n) {
8984c8945a0SNathan Whitehorn 	if (items[n].name_free)
8994c8945a0SNathan Whitehorn 	    free(items[n].name);
9004c8945a0SNathan Whitehorn 	if (items[n].text_free)
9014c8945a0SNathan Whitehorn 	    free(items[n].text);
9024c8945a0SNathan Whitehorn 	if (items[n].help_free && items[n].help != dlg_strempty())
9034c8945a0SNathan Whitehorn 	    free(items[n].help);
9044c8945a0SNathan Whitehorn     }
9054c8945a0SNathan Whitehorn     free(items);
9064c8945a0SNathan Whitehorn }
9074c8945a0SNathan Whitehorn 
9084c8945a0SNathan Whitehorn /*
9094c8945a0SNathan Whitehorn  * The script accepts values beginning at 1, while curses starts at 0.
9104c8945a0SNathan Whitehorn  */
9114c8945a0SNathan Whitehorn int
9124c8945a0SNathan Whitehorn dlg_ordinate(const char *s)
9134c8945a0SNathan Whitehorn {
9144c8945a0SNathan Whitehorn     int result = atoi(s);
9154c8945a0SNathan Whitehorn     if (result > 0)
9164c8945a0SNathan Whitehorn 	--result;
9174c8945a0SNathan Whitehorn     else
9184c8945a0SNathan Whitehorn 	result = 0;
9194c8945a0SNathan Whitehorn     return result;
9204c8945a0SNathan Whitehorn }
9214c8945a0SNathan Whitehorn 
9224c8945a0SNathan Whitehorn int
9234c8945a0SNathan Whitehorn dialog_form(const char *title,
9244c8945a0SNathan Whitehorn 	    const char *cprompt,
9254c8945a0SNathan Whitehorn 	    int height,
9264c8945a0SNathan Whitehorn 	    int width,
9274c8945a0SNathan Whitehorn 	    int form_height,
9284c8945a0SNathan Whitehorn 	    int item_no,
9294c8945a0SNathan Whitehorn 	    char **items)
9304c8945a0SNathan Whitehorn {
9314c8945a0SNathan Whitehorn     int result;
932*f4f33ea0SBaptiste Daroussin     int choice = 0;
9334c8945a0SNathan Whitehorn     int i;
9344c8945a0SNathan Whitehorn     DIALOG_FORMITEM *listitems;
9354c8945a0SNathan Whitehorn     DIALOG_VARS save_vars;
9364c8945a0SNathan Whitehorn     bool show_status = FALSE;
937febdb468SDevin Teske     char *help_result;
9384c8945a0SNathan Whitehorn 
9394c8945a0SNathan Whitehorn     dlg_save_vars(&save_vars);
9404c8945a0SNathan Whitehorn     dialog_vars.separate_output = TRUE;
9414c8945a0SNathan Whitehorn 
9424c8945a0SNathan Whitehorn     listitems = dlg_calloc(DIALOG_FORMITEM, (size_t) item_no + 1);
9434c8945a0SNathan Whitehorn     assert_ptr(listitems, "dialog_form");
9444c8945a0SNathan Whitehorn 
9454c8945a0SNathan Whitehorn     for (i = 0; i < item_no; ++i) {
9464c8945a0SNathan Whitehorn 	listitems[i].type = dialog_vars.formitem_type;
9474c8945a0SNathan Whitehorn 	listitems[i].name = ItemName(i);
9484c8945a0SNathan Whitehorn 	listitems[i].name_len = (int) strlen(ItemName(i));
9494c8945a0SNathan Whitehorn 	listitems[i].name_y = dlg_ordinate(ItemNameY(i));
9504c8945a0SNathan Whitehorn 	listitems[i].name_x = dlg_ordinate(ItemNameX(i));
9514c8945a0SNathan Whitehorn 	listitems[i].text = ItemText(i);
9524c8945a0SNathan Whitehorn 	listitems[i].text_len = (int) strlen(ItemText(i));
9534c8945a0SNathan Whitehorn 	listitems[i].text_y = dlg_ordinate(ItemTextY(i));
9544c8945a0SNathan Whitehorn 	listitems[i].text_x = dlg_ordinate(ItemTextX(i));
9554c8945a0SNathan Whitehorn 	listitems[i].text_flen = atoi(ItemTextFLen(i));
9564c8945a0SNathan Whitehorn 	listitems[i].text_ilen = atoi(ItemTextILen(i));
9574c8945a0SNathan Whitehorn 	listitems[i].help = ((dialog_vars.item_help)
9584c8945a0SNathan Whitehorn 			     ? ItemHelp(i)
9594c8945a0SNathan Whitehorn 			     : dlg_strempty());
9604c8945a0SNathan Whitehorn     }
9614c8945a0SNathan Whitehorn 
9624c8945a0SNathan Whitehorn     result = dlg_form(title,
9634c8945a0SNathan Whitehorn 		      cprompt,
9644c8945a0SNathan Whitehorn 		      height,
9654c8945a0SNathan Whitehorn 		      width,
9664c8945a0SNathan Whitehorn 		      form_height,
9674c8945a0SNathan Whitehorn 		      item_no,
9684c8945a0SNathan Whitehorn 		      listitems,
9694c8945a0SNathan Whitehorn 		      &choice);
9704c8945a0SNathan Whitehorn 
9714c8945a0SNathan Whitehorn     switch (result) {
9724c8945a0SNathan Whitehorn     case DLG_EXIT_OK:		/* FALLTHRU */
9734c8945a0SNathan Whitehorn     case DLG_EXIT_EXTRA:
9744c8945a0SNathan Whitehorn 	show_status = TRUE;
9754c8945a0SNathan Whitehorn 	break;
9764c8945a0SNathan Whitehorn     case DLG_EXIT_HELP:
977febdb468SDevin Teske 	dlg_add_help_formitem(&result, &help_result, &listitems[choice]);
9784c8945a0SNathan Whitehorn 	show_status = dialog_vars.help_status;
979febdb468SDevin Teske 	dlg_add_string(help_result);
9804c8945a0SNathan Whitehorn 	if (show_status)
9814c8945a0SNathan Whitehorn 	    dlg_add_separator();
9824c8945a0SNathan Whitehorn 	break;
9834c8945a0SNathan Whitehorn     }
9844c8945a0SNathan Whitehorn     if (show_status) {
9854c8945a0SNathan Whitehorn 	for (i = 0; i < item_no; i++) {
9864c8945a0SNathan Whitehorn 	    if (listitems[i].text_flen > 0) {
9874c8945a0SNathan Whitehorn 		dlg_add_string(listitems[i].text);
9884c8945a0SNathan Whitehorn 		dlg_add_separator();
9894c8945a0SNathan Whitehorn 	    }
9904c8945a0SNathan Whitehorn 	}
9912a3e3873SBaptiste Daroussin 	dlg_add_last_key(-1);
9924c8945a0SNathan Whitehorn     }
9934c8945a0SNathan Whitehorn 
9944c8945a0SNathan Whitehorn     dlg_free_formitems(listitems);
9954c8945a0SNathan Whitehorn     dlg_restore_vars(&save_vars);
9964c8945a0SNathan Whitehorn 
9974c8945a0SNathan Whitehorn     return result;
9984c8945a0SNathan Whitehorn }
999