xref: /freebsd/contrib/dialog/formbox.c (revision a96ef4501919d7ac08e94e98dc34b0bdd744802b)
14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin  *  $Id: formbox.c,v 1.103 2021/01/17 22:19:05 tom Exp $
34c8945a0SNathan Whitehorn  *
4f4f33ea0SBaptiste Daroussin  *  formbox.c -- implements the form (i.e., some pairs label/editbox)
54c8945a0SNathan Whitehorn  *
6*a96ef450SBaptiste Daroussin  *  Copyright 2003-2020,2021	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
is_readonly(DIALOG_FORMITEM * item)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
is_hidden(DIALOG_FORMITEM * item)494c8945a0SNathan Whitehorn is_hidden(DIALOG_FORMITEM * item)
504c8945a0SNathan Whitehorn {
514c8945a0SNathan Whitehorn     return ((item->type & 1) != 0);
524c8945a0SNathan Whitehorn }
534c8945a0SNathan Whitehorn 
544c8945a0SNathan Whitehorn static bool
in_window(WINDOW * win,int scrollamt,int y)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
ok_move(WINDOW * win,int scrollamt,int y,int x)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
move_past(WINDOW * win,int y,int x)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
print_item(WINDOW * win,DIALOG_FORMITEM * item,int scrollamt,bool choice)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
print_form(WINDOW * win,DIALOG_FORMITEM * item,int total,int scrollamt,int choice)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
set_choice(DIALOG_FORMITEM item[],int choice,int item_no,bool * noneditable)1514c8945a0SNathan Whitehorn set_choice(DIALOG_FORMITEM item[], int choice, int item_no, bool * noneditable)
1524c8945a0SNathan Whitehorn {
1534c8945a0SNathan Whitehorn     int result = -1;
1544c8945a0SNathan Whitehorn 
1554c8945a0SNathan Whitehorn     *noneditable = FALSE;
1564c8945a0SNathan Whitehorn     if (!is_readonly(&item[choice])) {
1574c8945a0SNathan Whitehorn 	result = choice;
1584c8945a0SNathan Whitehorn     } else {
159*a96ef450SBaptiste Daroussin 	int i;
160*a96ef450SBaptiste Daroussin 
1614c8945a0SNathan Whitehorn 	for (i = 0; i < item_no; i++) {
1624c8945a0SNathan Whitehorn 	    if (!is_readonly(&(item[i]))) {
1634c8945a0SNathan Whitehorn 		result = i;
1644c8945a0SNathan Whitehorn 		break;
1654c8945a0SNathan Whitehorn 	    }
1664c8945a0SNathan Whitehorn 	}
1674c8945a0SNathan Whitehorn 	if (result < 0) {
1684c8945a0SNathan Whitehorn 	    *noneditable = TRUE;
1694c8945a0SNathan Whitehorn 	    result = 0;
1704c8945a0SNathan Whitehorn 	}
1714c8945a0SNathan Whitehorn     }
1724c8945a0SNathan Whitehorn     return result;
1734c8945a0SNathan Whitehorn }
1744c8945a0SNathan Whitehorn 
1754c8945a0SNathan Whitehorn /*
1764c8945a0SNathan Whitehorn  * Find the last y-value in the form.
1774c8945a0SNathan Whitehorn  */
1784c8945a0SNathan Whitehorn static int
form_limit(DIALOG_FORMITEM item[])1794c8945a0SNathan Whitehorn form_limit(DIALOG_FORMITEM item[])
1804c8945a0SNathan Whitehorn {
1814c8945a0SNathan Whitehorn     int n;
1824c8945a0SNathan Whitehorn     int limit = 0;
1834c8945a0SNathan Whitehorn     for (n = 0; item[n].name != 0; ++n) {
1844c8945a0SNathan Whitehorn 	if (limit < item[n].name_y)
1854c8945a0SNathan Whitehorn 	    limit = item[n].name_y;
1864c8945a0SNathan Whitehorn 	if (limit < item[n].text_y)
1874c8945a0SNathan Whitehorn 	    limit = item[n].text_y;
1884c8945a0SNathan Whitehorn     }
1894c8945a0SNathan Whitehorn     return limit;
1904c8945a0SNathan Whitehorn }
1914c8945a0SNathan Whitehorn 
1922a3e3873SBaptiste Daroussin static int
is_first_field(DIALOG_FORMITEM item[],int choice)1932a3e3873SBaptiste Daroussin is_first_field(DIALOG_FORMITEM item[], int choice)
1942a3e3873SBaptiste Daroussin {
1952a3e3873SBaptiste Daroussin     int count = 0;
1962a3e3873SBaptiste Daroussin     while (choice >= 0) {
1972a3e3873SBaptiste Daroussin 	if (item[choice].text_flen > 0) {
1982a3e3873SBaptiste Daroussin 	    ++count;
1992a3e3873SBaptiste Daroussin 	}
2002a3e3873SBaptiste Daroussin 	--choice;
2012a3e3873SBaptiste Daroussin     }
2022a3e3873SBaptiste Daroussin 
2032a3e3873SBaptiste Daroussin     return (count == 1);
2042a3e3873SBaptiste Daroussin }
2052a3e3873SBaptiste Daroussin 
2062a3e3873SBaptiste Daroussin static int
is_last_field(DIALOG_FORMITEM item[],int choice,int item_no)2072a3e3873SBaptiste Daroussin is_last_field(DIALOG_FORMITEM item[], int choice, int item_no)
2082a3e3873SBaptiste Daroussin {
2092a3e3873SBaptiste Daroussin     int count = 0;
2102a3e3873SBaptiste Daroussin     while (choice < item_no) {
2112a3e3873SBaptiste Daroussin 	if (item[choice].text_flen > 0) {
2122a3e3873SBaptiste Daroussin 	    ++count;
2132a3e3873SBaptiste Daroussin 	}
2142a3e3873SBaptiste Daroussin 	++choice;
2152a3e3873SBaptiste Daroussin     }
2162a3e3873SBaptiste Daroussin 
2172a3e3873SBaptiste Daroussin     return (count == 1);
2182a3e3873SBaptiste Daroussin }
2192a3e3873SBaptiste Daroussin 
2204c8945a0SNathan Whitehorn /*
2214c8945a0SNathan Whitehorn  * Tab to the next field.
2224c8945a0SNathan Whitehorn  */
2234c8945a0SNathan Whitehorn static bool
tab_next(WINDOW * win,DIALOG_FORMITEM item[],int item_no,int stepsize,int * choice,int * scrollamt)2244c8945a0SNathan Whitehorn tab_next(WINDOW *win,
2254c8945a0SNathan Whitehorn 	 DIALOG_FORMITEM item[],
2264c8945a0SNathan Whitehorn 	 int item_no,
2274c8945a0SNathan Whitehorn 	 int stepsize,
2284c8945a0SNathan Whitehorn 	 int *choice,
2294c8945a0SNathan Whitehorn 	 int *scrollamt)
2304c8945a0SNathan Whitehorn {
2314c8945a0SNathan Whitehorn     int old_choice = *choice;
2324c8945a0SNathan Whitehorn     int old_scroll = *scrollamt;
2334c8945a0SNathan Whitehorn     bool wrapped = FALSE;
2344c8945a0SNathan Whitehorn 
2354c8945a0SNathan Whitehorn     do {
2364c8945a0SNathan Whitehorn 	do {
2374c8945a0SNathan Whitehorn 	    *choice += stepsize;
2384c8945a0SNathan Whitehorn 	    if (*choice < 0) {
2394c8945a0SNathan Whitehorn 		*choice = item_no - 1;
2404c8945a0SNathan Whitehorn 		wrapped = TRUE;
2414c8945a0SNathan Whitehorn 	    } else if (*choice >= item_no) {
2424c8945a0SNathan Whitehorn 		*choice = 0;
2434c8945a0SNathan Whitehorn 		wrapped = TRUE;
2444c8945a0SNathan Whitehorn 	    }
2454c8945a0SNathan Whitehorn 	} while ((*choice != old_choice) && is_readonly(&(item[*choice])));
2464c8945a0SNathan Whitehorn 
2474c8945a0SNathan Whitehorn 	if (item[*choice].text_flen > 0) {
2484c8945a0SNathan Whitehorn 	    int lo = MIN(item[*choice].name_y, item[*choice].text_y);
2494c8945a0SNathan Whitehorn 	    int hi = MAX(item[*choice].name_y, item[*choice].text_y);
2504c8945a0SNathan Whitehorn 
2514c8945a0SNathan Whitehorn 	    if (old_choice == *choice)
2524c8945a0SNathan Whitehorn 		break;
2534c8945a0SNathan Whitehorn 	    print_item(win, item + old_choice, *scrollamt, FALSE);
2544c8945a0SNathan Whitehorn 
2554c8945a0SNathan Whitehorn 	    if (*scrollamt < lo + 1 - getmaxy(win))
2564c8945a0SNathan Whitehorn 		*scrollamt = lo + 1 - getmaxy(win);
2574c8945a0SNathan Whitehorn 	    if (*scrollamt > hi)
2584c8945a0SNathan Whitehorn 		*scrollamt = hi;
2594c8945a0SNathan Whitehorn 	    /*
2604c8945a0SNathan Whitehorn 	     * If we have to scroll to show a wrap-around, it does get
2614c8945a0SNathan Whitehorn 	     * confusing.  Just give up rather than scroll.  Tab'ing to the
2624c8945a0SNathan Whitehorn 	     * next field in a multi-column form is a different matter.  Scroll
2634c8945a0SNathan Whitehorn 	     * for that.
2644c8945a0SNathan Whitehorn 	     */
2654c8945a0SNathan Whitehorn 	    if (*scrollamt != old_scroll) {
2664c8945a0SNathan Whitehorn 		if (wrapped) {
2674c8945a0SNathan Whitehorn 		    beep();
2684c8945a0SNathan Whitehorn 		    *scrollamt = old_scroll;
2694c8945a0SNathan Whitehorn 		    *choice = old_choice;
2704c8945a0SNathan Whitehorn 		} else {
2714c8945a0SNathan Whitehorn 		    scrollok(win, TRUE);
2724c8945a0SNathan Whitehorn 		    wscrl(win, *scrollamt - old_scroll);
2734c8945a0SNathan Whitehorn 		    scrollok(win, FALSE);
2744c8945a0SNathan Whitehorn 		}
2754c8945a0SNathan Whitehorn 	    }
2764c8945a0SNathan Whitehorn 	    break;
2774c8945a0SNathan Whitehorn 	}
2784c8945a0SNathan Whitehorn     } while (*choice != old_choice);
2794c8945a0SNathan Whitehorn 
2804c8945a0SNathan Whitehorn     return (old_choice != *choice) || (old_scroll != *scrollamt);
2814c8945a0SNathan Whitehorn }
2824c8945a0SNathan Whitehorn 
2834c8945a0SNathan Whitehorn /*
2844c8945a0SNathan Whitehorn  * Scroll to the next page, putting the choice at the first editable field
2854c8945a0SNathan Whitehorn  * in that page.  Note that fields are not necessarily in top-to-bottom order,
2864c8945a0SNathan Whitehorn  * nor is there necessarily a field on each row of the window.
2874c8945a0SNathan Whitehorn  */
2884c8945a0SNathan Whitehorn static bool
scroll_next(WINDOW * win,DIALOG_FORMITEM item[],int stepsize,int * choice,int * scrollamt)2894c8945a0SNathan Whitehorn scroll_next(WINDOW *win, DIALOG_FORMITEM item[], int stepsize, int *choice, int *scrollamt)
2904c8945a0SNathan Whitehorn {
2912a3e3873SBaptiste Daroussin     bool result = TRUE;
2924c8945a0SNathan Whitehorn     int old_choice = *choice;
2934c8945a0SNathan Whitehorn     int old_scroll = *scrollamt;
2944c8945a0SNathan Whitehorn     int old_row = MIN(item[old_choice].text_y, item[old_choice].name_y);
2954c8945a0SNathan Whitehorn     int target = old_scroll + stepsize;
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) {
312*a96ef450SBaptiste Daroussin 	int n;
313*a96ef450SBaptiste Daroussin 
3144c8945a0SNathan Whitehorn 	for (n = 0; item[n].name != 0; ++n) {
3154c8945a0SNathan Whitehorn 	    if (item[n].text_flen > 0) {
3164c8945a0SNathan Whitehorn 		int new_row = MIN(item[n].text_y, item[n].name_y);
3174c8945a0SNathan Whitehorn 		if (abs(new_row - target) < abs(old_row - target)) {
3184c8945a0SNathan Whitehorn 		    old_row = new_row;
3194c8945a0SNathan Whitehorn 		    *choice = n;
3204c8945a0SNathan Whitehorn 		}
3214c8945a0SNathan Whitehorn 	    }
3224c8945a0SNathan Whitehorn 	}
3234c8945a0SNathan Whitehorn 
3244c8945a0SNathan Whitehorn 	if (old_choice != *choice)
3254c8945a0SNathan Whitehorn 	    print_item(win, item + old_choice, *scrollamt, FALSE);
3264c8945a0SNathan Whitehorn 
3274c8945a0SNathan Whitehorn 	*scrollamt = *choice;
3284c8945a0SNathan Whitehorn 	if (*scrollamt != old_scroll) {
3294c8945a0SNathan Whitehorn 	    scrollok(win, TRUE);
3304c8945a0SNathan Whitehorn 	    wscrl(win, *scrollamt - old_scroll);
3314c8945a0SNathan Whitehorn 	    scrollok(win, FALSE);
3324c8945a0SNathan Whitehorn 	}
3332a3e3873SBaptiste Daroussin 	result = (old_choice != *choice) || (old_scroll != *scrollamt);
3342a3e3873SBaptiste Daroussin     }
3352a3e3873SBaptiste Daroussin     if (!result)
3362a3e3873SBaptiste Daroussin 	beep();
3372a3e3873SBaptiste Daroussin     return result;
3384c8945a0SNathan Whitehorn }
3394c8945a0SNathan Whitehorn 
3404c8945a0SNathan Whitehorn /*
3414c8945a0SNathan Whitehorn  * Do a sanity check on the field length, and return the "right" value.
3424c8945a0SNathan Whitehorn  */
3434c8945a0SNathan Whitehorn static int
real_length(DIALOG_FORMITEM * item)3444c8945a0SNathan Whitehorn real_length(DIALOG_FORMITEM * item)
3454c8945a0SNathan Whitehorn {
3464c8945a0SNathan Whitehorn     return (item->text_flen > 0
3474c8945a0SNathan Whitehorn 	    ? item->text_flen
3484c8945a0SNathan Whitehorn 	    : (item->text_flen < 0
3494c8945a0SNathan Whitehorn 	       ? -item->text_flen
3504c8945a0SNathan Whitehorn 	       : item->text_len));
3514c8945a0SNathan Whitehorn }
3524c8945a0SNathan Whitehorn 
3534c8945a0SNathan Whitehorn /*
3544c8945a0SNathan Whitehorn  * Compute the form size, setup field buffers.
3554c8945a0SNathan Whitehorn  */
3564c8945a0SNathan Whitehorn static void
make_FORM_ELTs(DIALOG_FORMITEM * item,int item_no,int * min_height,int * min_width)3574c8945a0SNathan Whitehorn make_FORM_ELTs(DIALOG_FORMITEM * item,
3584c8945a0SNathan Whitehorn 	       int item_no,
3594c8945a0SNathan Whitehorn 	       int *min_height,
3604c8945a0SNathan Whitehorn 	       int *min_width)
3614c8945a0SNathan Whitehorn {
3624c8945a0SNathan Whitehorn     int i;
3634c8945a0SNathan Whitehorn     int min_w = 0;
3644c8945a0SNathan Whitehorn     int min_h = 0;
3654c8945a0SNathan Whitehorn 
3664c8945a0SNathan Whitehorn     for (i = 0; i < item_no; ++i) {
3674c8945a0SNathan Whitehorn 	int real_len = real_length(item + i);
3684c8945a0SNathan Whitehorn 
3694c8945a0SNathan Whitehorn 	/*
3704c8945a0SNathan Whitehorn 	 * Special value '0' for text_flen: no input allowed
3714c8945a0SNathan Whitehorn 	 * Special value '0' for text_ilen: 'be the same as text_flen'
3724c8945a0SNathan Whitehorn 	 */
3734c8945a0SNathan Whitehorn 	if (item[i].text_ilen == 0)
3744c8945a0SNathan Whitehorn 	    item[i].text_ilen = real_len;
3754c8945a0SNathan Whitehorn 
3764c8945a0SNathan Whitehorn 	min_h = MAX(min_h, item[i].name_y + 1);
3774c8945a0SNathan Whitehorn 	min_h = MAX(min_h, item[i].text_y + 1);
3784c8945a0SNathan Whitehorn 	min_w = MAX(min_w, item[i].name_x + 1 + item[i].name_len);
3794c8945a0SNathan Whitehorn 	min_w = MAX(min_w, item[i].text_x + 1 + real_len);
3804c8945a0SNathan Whitehorn 
3814c8945a0SNathan Whitehorn 	item[i].text_len = real_length(item + i);
3824c8945a0SNathan Whitehorn 
3834c8945a0SNathan Whitehorn 	/*
3844c8945a0SNathan Whitehorn 	 * We do not know the actual length of .text, so we allocate it here
3854c8945a0SNathan Whitehorn 	 * to ensure it is big enough.
3864c8945a0SNathan Whitehorn 	 */
3874c8945a0SNathan Whitehorn 	if (item[i].text_flen > 0) {
3884c8945a0SNathan Whitehorn 	    int max_len = dlg_max_input(MAX(item[i].text_ilen + 1, MAX_LEN));
3894c8945a0SNathan Whitehorn 	    char *old_text = item[i].text;
3904c8945a0SNathan Whitehorn 
3914c8945a0SNathan Whitehorn 	    item[i].text = dlg_malloc(char, (size_t) max_len + 1);
3924c8945a0SNathan Whitehorn 	    assert_ptr(item[i].text, "make_FORM_ELTs");
3934c8945a0SNathan Whitehorn 
3944c8945a0SNathan Whitehorn 	    sprintf(item[i].text, "%.*s", item[i].text_ilen, old_text);
3954c8945a0SNathan Whitehorn 
3964c8945a0SNathan Whitehorn 	    if (item[i].text_free) {
3974c8945a0SNathan Whitehorn 		free(old_text);
3984c8945a0SNathan Whitehorn 	    }
3994c8945a0SNathan Whitehorn 	    item[i].text_free = TRUE;
4004c8945a0SNathan Whitehorn 	}
4014c8945a0SNathan Whitehorn     }
4024c8945a0SNathan Whitehorn 
4034c8945a0SNathan Whitehorn     *min_height = min_h;
4044c8945a0SNathan Whitehorn     *min_width = min_w;
4054c8945a0SNathan Whitehorn }
4064c8945a0SNathan Whitehorn 
4074c8945a0SNathan Whitehorn int
dlg_default_formitem(DIALOG_FORMITEM * items)4084c8945a0SNathan Whitehorn dlg_default_formitem(DIALOG_FORMITEM * items)
4094c8945a0SNathan Whitehorn {
4104c8945a0SNathan Whitehorn     int result = 0;
4114c8945a0SNathan Whitehorn 
4124c8945a0SNathan Whitehorn     if (dialog_vars.default_item != 0) {
4134c8945a0SNathan Whitehorn 	int count = 0;
4144c8945a0SNathan Whitehorn 	while (items->name != 0) {
4154c8945a0SNathan Whitehorn 	    if (!strcmp(dialog_vars.default_item, items->name)) {
4164c8945a0SNathan Whitehorn 		result = count;
4174c8945a0SNathan Whitehorn 		break;
4184c8945a0SNathan Whitehorn 	    }
4194c8945a0SNathan Whitehorn 	    ++items;
4204c8945a0SNathan Whitehorn 	    count++;
4214c8945a0SNathan Whitehorn 	}
4224c8945a0SNathan Whitehorn     }
4234c8945a0SNathan Whitehorn     return result;
4244c8945a0SNathan Whitehorn }
4254c8945a0SNathan Whitehorn 
4264c8945a0SNathan Whitehorn #define sTEXT -1
4274c8945a0SNathan Whitehorn 
4284c8945a0SNathan Whitehorn static int
next_valid_buttonindex(int state,int extra,bool non_editable)4294c8945a0SNathan Whitehorn next_valid_buttonindex(int state, int extra, bool non_editable)
4304c8945a0SNathan Whitehorn {
4314c8945a0SNathan Whitehorn     state = dlg_next_ok_buttonindex(state, extra);
4324c8945a0SNathan Whitehorn     while (non_editable && state == sTEXT)
4334c8945a0SNathan Whitehorn 	state = dlg_next_ok_buttonindex(state, sTEXT);
4344c8945a0SNathan Whitehorn     return state;
4354c8945a0SNathan Whitehorn }
4364c8945a0SNathan Whitehorn 
4374c8945a0SNathan Whitehorn static int
prev_valid_buttonindex(int state,int extra,bool non_editable)4384c8945a0SNathan Whitehorn prev_valid_buttonindex(int state, int extra, bool non_editable)
4394c8945a0SNathan Whitehorn {
4404c8945a0SNathan Whitehorn     state = dlg_prev_ok_buttonindex(state, extra);
4414c8945a0SNathan Whitehorn     while (non_editable && state == sTEXT)
4424c8945a0SNathan Whitehorn 	state = dlg_prev_ok_buttonindex(state, sTEXT);
4434c8945a0SNathan Whitehorn     return state;
4444c8945a0SNathan Whitehorn }
4454c8945a0SNathan Whitehorn 
4464c8945a0SNathan Whitehorn #define NAVIGATE_BINDINGS \
4474c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), \
4484c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), \
4494c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  CHR_NEXT ), \
4504c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_DOWN ), \
451f4f33ea0SBaptiste Daroussin 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_RIGHT ), \
4524c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_NEXT ), \
4534c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  CHR_PREVIOUS ), \
4544c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_PREVIOUS ), \
455f4f33ea0SBaptiste Daroussin 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_LEFT ), \
4564c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_UP ), \
4574c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ), \
4584c8945a0SNathan Whitehorn 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE )
4594c8945a0SNathan Whitehorn /*
4602a3e3873SBaptiste Daroussin  * Display a form for entering a number of fields
4614c8945a0SNathan Whitehorn  */
4624c8945a0SNathan Whitehorn int
dlg_form(const char * title,const char * cprompt,int height,int width,int form_height,int item_no,DIALOG_FORMITEM * items,int * current_item)4634c8945a0SNathan Whitehorn dlg_form(const char *title,
4644c8945a0SNathan Whitehorn 	 const char *cprompt,
4654c8945a0SNathan Whitehorn 	 int height,
4664c8945a0SNathan Whitehorn 	 int width,
4674c8945a0SNathan Whitehorn 	 int form_height,
4684c8945a0SNathan Whitehorn 	 int item_no,
4694c8945a0SNathan Whitehorn 	 DIALOG_FORMITEM * items,
4704c8945a0SNathan Whitehorn 	 int *current_item)
4714c8945a0SNathan Whitehorn {
4724c8945a0SNathan Whitehorn     /* *INDENT-OFF* */
4734c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding[] = {
474682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
4754c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
4764c8945a0SNathan Whitehorn 	NAVIGATE_BINDINGS,
477f4f33ea0SBaptiste Daroussin 	TOGGLEKEY_BINDINGS,
4784c8945a0SNathan Whitehorn 	END_KEYS_BINDING
4794c8945a0SNathan Whitehorn     };
4804c8945a0SNathan Whitehorn     static DLG_KEYS_BINDING binding2[] = {
4814c8945a0SNathan Whitehorn 	INPUTSTR_BINDINGS,
482682c9e0fSNathan Whitehorn 	HELPKEY_BINDINGS,
4834c8945a0SNathan Whitehorn 	ENTERKEY_BINDINGS,
4844c8945a0SNathan Whitehorn 	NAVIGATE_BINDINGS,
485f4f33ea0SBaptiste Daroussin 	/* no TOGGLEKEY_BINDINGS, since that includes space... */
4864c8945a0SNathan Whitehorn 	END_KEYS_BINDING
4874c8945a0SNathan Whitehorn     };
4884c8945a0SNathan Whitehorn     /* *INDENT-ON* */
4894c8945a0SNathan Whitehorn 
4904c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
4914c8945a0SNathan Whitehorn     int old_height = height;
4924c8945a0SNathan Whitehorn     int old_width = width;
4934c8945a0SNathan Whitehorn #endif
4944c8945a0SNathan Whitehorn 
4954c8945a0SNathan Whitehorn     int form_width;
496f4f33ea0SBaptiste Daroussin     bool first = TRUE;
497f4f33ea0SBaptiste Daroussin     bool first_trace = TRUE;
4984c8945a0SNathan Whitehorn     int chr_offset = 0;
499f4f33ea0SBaptiste Daroussin     int state = (dialog_vars.default_button >= 0
500f4f33ea0SBaptiste Daroussin 		 ? dlg_default_button()
501f4f33ea0SBaptiste Daroussin 		 : sTEXT);
5024c8945a0SNathan Whitehorn     int x, y, cur_x, cur_y, box_x, box_y;
5034c8945a0SNathan Whitehorn     int code;
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;
516f4f33ea0SBaptiste Daroussin     char *prompt;
5174c8945a0SNathan Whitehorn     const char **buttons = dlg_ok_labels();
5184c8945a0SNathan Whitehorn     DIALOG_FORMITEM *current;
5194c8945a0SNathan Whitehorn 
520f4f33ea0SBaptiste Daroussin     DLG_TRACE(("# %sform args:\n", (dialog_vars.formitem_type
521f4f33ea0SBaptiste Daroussin 				    ? "password"
522f4f33ea0SBaptiste Daroussin 				    : "")));
523f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("title", title);
524f4f33ea0SBaptiste Daroussin     DLG_TRACE2S("message", cprompt);
525f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("height", height);
526f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("width", width);
527f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("lheight", form_height);
528f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("llength", item_no);
529f4f33ea0SBaptiste Daroussin     /* FIXME dump the items[][] too */
530f4f33ea0SBaptiste Daroussin     DLG_TRACE2N("current", *current_item);
531f4f33ea0SBaptiste 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 
540f4f33ea0SBaptiste Daroussin     prompt = dlg_strclone(cprompt);
541f4f33ea0SBaptiste 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 
576f4f33ea0SBaptiste 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;
611*a96ef450SBaptiste Daroussin 	int key;
6124c8945a0SNathan Whitehorn 
6134c8945a0SNathan Whitehorn 	if (scroll_changed) {
6144c8945a0SNathan Whitehorn 	    print_form(form, items, item_no, scrollamt, choice);
6154c8945a0SNathan Whitehorn 	    dlg_draw_scrollbar(dialog,
6164c8945a0SNathan Whitehorn 			       scrollamt,
6174c8945a0SNathan Whitehorn 			       scrollamt,
6184c8945a0SNathan Whitehorn 			       scrollamt + form_height + 1,
6194c8945a0SNathan Whitehorn 			       min_height,
6204c8945a0SNathan Whitehorn 			       box_x + 1,
6214c8945a0SNathan Whitehorn 			       box_x + form_width,
6224c8945a0SNathan Whitehorn 			       box_y,
6234c8945a0SNathan Whitehorn 			       box_y + form_height + 1,
6242a3e3873SBaptiste Daroussin 			       menubox_border2_attr,
6254c8945a0SNathan Whitehorn 			       menubox_border_attr);
6264c8945a0SNathan Whitehorn 	    scroll_changed = FALSE;
6274c8945a0SNathan Whitehorn 	}
6284c8945a0SNathan Whitehorn 
6294c8945a0SNathan Whitehorn 	if (show_buttons) {
6304c8945a0SNathan Whitehorn 	    dlg_item_help("");
6314c8945a0SNathan Whitehorn 	    dlg_draw_buttons(dialog, height - 2, 0, buttons,
6324c8945a0SNathan Whitehorn 			     ((state < 0)
6334c8945a0SNathan Whitehorn 			      ? 1000	/* no such button, not highlighted */
6344c8945a0SNathan Whitehorn 			      : state),
6354c8945a0SNathan Whitehorn 			     FALSE, width);
6364c8945a0SNathan Whitehorn 	    show_buttons = FALSE;
6374c8945a0SNathan Whitehorn 	}
6384c8945a0SNathan Whitehorn 
6392a3e3873SBaptiste Daroussin 	if (first_trace) {
6402a3e3873SBaptiste Daroussin 	    first_trace = FALSE;
6412a3e3873SBaptiste Daroussin 	    dlg_trace_win(dialog);
6422a3e3873SBaptiste Daroussin 	}
6432a3e3873SBaptiste Daroussin 
6444c8945a0SNathan Whitehorn 	if (field_changed || state == sTEXT) {
6454c8945a0SNathan Whitehorn 	    if (field_changed)
6464c8945a0SNathan Whitehorn 		chr_offset = 0;
6474c8945a0SNathan Whitehorn 	    current = &items[choice];
6484c8945a0SNathan Whitehorn 	    dialog_vars.max_input = current->text_ilen;
6494c8945a0SNathan Whitehorn 	    dlg_item_help(current->help);
6504c8945a0SNathan Whitehorn 	    dlg_show_string(form, current->text, chr_offset,
6514c8945a0SNathan Whitehorn 			    form_active_text_attr,
6524c8945a0SNathan Whitehorn 			    current->text_y - scrollamt,
6534c8945a0SNathan Whitehorn 			    current->text_x,
6544c8945a0SNathan Whitehorn 			    current->text_len,
6554c8945a0SNathan Whitehorn 			    is_hidden(current), first);
6562a3e3873SBaptiste Daroussin 	    wsyncup(form);
6572a3e3873SBaptiste Daroussin 	    wcursyncup(form);
6584c8945a0SNathan Whitehorn 	    field_changed = FALSE;
6594c8945a0SNathan Whitehorn 	}
6604c8945a0SNathan Whitehorn 
6612a3e3873SBaptiste Daroussin 	key = dlg_mouse_wgetch((state == sTEXT) ? form : dialog, &fkey);
662*a96ef450SBaptiste Daroussin 	if (dlg_result_key(key, fkey, &result)) {
6634c8945a0SNathan Whitehorn 	    break;
664*a96ef450SBaptiste Daroussin 	}
6654c8945a0SNathan Whitehorn 
6664c8945a0SNathan Whitehorn 	/* handle non-functionkeys */
6674c8945a0SNathan Whitehorn 	if (!fkey) {
6684c8945a0SNathan Whitehorn 	    if (state != sTEXT) {
6694c8945a0SNathan Whitehorn 		code = dlg_char_to_button(key, buttons);
6704c8945a0SNathan Whitehorn 		if (code >= 0) {
6714c8945a0SNathan Whitehorn 		    dlg_del_window(dialog);
6724c8945a0SNathan Whitehorn 		    result = dlg_ok_buttoncode(code);
6734c8945a0SNathan Whitehorn 		    continue;
6744c8945a0SNathan Whitehorn 		}
6754c8945a0SNathan Whitehorn 	    }
6764c8945a0SNathan Whitehorn 	}
6774c8945a0SNathan Whitehorn 
6784c8945a0SNathan Whitehorn 	/* handle functionkeys */
6794c8945a0SNathan Whitehorn 	if (fkey) {
6804c8945a0SNathan Whitehorn 	    bool do_scroll = FALSE;
6814c8945a0SNathan Whitehorn 	    bool do_tab = FALSE;
6824c8945a0SNathan Whitehorn 	    int move_by = 0;
6834c8945a0SNathan Whitehorn 
6844c8945a0SNathan Whitehorn 	    switch (key) {
6854c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_PPAGE):
6864c8945a0SNathan Whitehorn 	    case DLGK_PAGE_PREV:
6874c8945a0SNathan Whitehorn 		do_scroll = TRUE;
6884c8945a0SNathan Whitehorn 		move_by = -form_height;
6894c8945a0SNathan Whitehorn 		break;
6904c8945a0SNathan Whitehorn 
6914c8945a0SNathan Whitehorn 	    case DLGK_MOUSE(KEY_NPAGE):
6924c8945a0SNathan Whitehorn 	    case DLGK_PAGE_NEXT:
6934c8945a0SNathan Whitehorn 		do_scroll = TRUE;
6944c8945a0SNathan Whitehorn 		move_by = form_height;
6954c8945a0SNathan Whitehorn 		break;
6964c8945a0SNathan Whitehorn 
697f4f33ea0SBaptiste Daroussin 	    case DLGK_TOGGLE:
6984c8945a0SNathan Whitehorn 	    case DLGK_ENTER:
6994c8945a0SNathan Whitehorn 		dlg_del_window(dialog);
700682c9e0fSNathan Whitehorn 		result = (state >= 0) ? dlg_enter_buttoncode(state) : DLG_EXIT_OK;
7014c8945a0SNathan Whitehorn 		continue;
702*a96ef450SBaptiste Daroussin 	    case DLGK_LEAVE:
703*a96ef450SBaptiste Daroussin 		if (state >= 0)
704*a96ef450SBaptiste Daroussin 		    result = dlg_ok_buttoncode(state);
705*a96ef450SBaptiste Daroussin 		break;
7064c8945a0SNathan Whitehorn 
7074c8945a0SNathan Whitehorn 	    case DLGK_GRID_LEFT:
7084c8945a0SNathan Whitehorn 		if (state == sTEXT)
7094c8945a0SNathan Whitehorn 		    break;
7104c8945a0SNathan Whitehorn 		/* FALLTHRU */
7114c8945a0SNathan Whitehorn 	    case DLGK_ITEM_PREV:
7124c8945a0SNathan Whitehorn 		if (state == sTEXT) {
7134c8945a0SNathan Whitehorn 		    do_tab = TRUE;
7144c8945a0SNathan Whitehorn 		    move_by = -1;
7154c8945a0SNathan Whitehorn 		    break;
7164c8945a0SNathan Whitehorn 		} else {
7174c8945a0SNathan Whitehorn 		    state = prev_valid_buttonindex(state, 0, non_editable);
7184c8945a0SNathan Whitehorn 		    show_buttons = TRUE;
7194c8945a0SNathan Whitehorn 		    continue;
7204c8945a0SNathan Whitehorn 		}
7214c8945a0SNathan Whitehorn 
7222a3e3873SBaptiste Daroussin 	    case DLGK_FORM_PREV:
7232a3e3873SBaptiste Daroussin 		if (state == sTEXT && !is_first_field(items, choice)) {
7242a3e3873SBaptiste Daroussin 		    do_tab = TRUE;
7252a3e3873SBaptiste Daroussin 		    move_by = -1;
7262a3e3873SBaptiste Daroussin 		    break;
7272a3e3873SBaptiste Daroussin 		} else {
7282a3e3873SBaptiste Daroussin 		    int old_state = state;
7292a3e3873SBaptiste Daroussin 		    state = prev_valid_buttonindex(state, sTEXT, non_editable);
7302a3e3873SBaptiste Daroussin 		    show_buttons = TRUE;
7312a3e3873SBaptiste Daroussin 		    if (old_state >= 0 && state == sTEXT) {
7322a3e3873SBaptiste Daroussin 			new_choice = item_no - 1;
7332a3e3873SBaptiste Daroussin 			if (choice != new_choice) {
7342a3e3873SBaptiste Daroussin 			    print_item(form, items + choice, scrollamt, FALSE);
7352a3e3873SBaptiste Daroussin 			    choice = new_choice;
7362a3e3873SBaptiste Daroussin 			}
7372a3e3873SBaptiste Daroussin 		    }
7382a3e3873SBaptiste Daroussin 		    continue;
7392a3e3873SBaptiste Daroussin 		}
7402a3e3873SBaptiste Daroussin 
7414c8945a0SNathan Whitehorn 	    case DLGK_FIELD_PREV:
7424c8945a0SNathan Whitehorn 		state = prev_valid_buttonindex(state, sTEXT, non_editable);
7434c8945a0SNathan Whitehorn 		show_buttons = TRUE;
7444c8945a0SNathan Whitehorn 		continue;
7454c8945a0SNathan Whitehorn 
7464c8945a0SNathan Whitehorn 	    case DLGK_FIELD_NEXT:
7474c8945a0SNathan Whitehorn 		state = next_valid_buttonindex(state, sTEXT, non_editable);
7484c8945a0SNathan Whitehorn 		show_buttons = TRUE;
7494c8945a0SNathan Whitehorn 		continue;
7504c8945a0SNathan Whitehorn 
7514c8945a0SNathan Whitehorn 	    case DLGK_GRID_RIGHT:
7524c8945a0SNathan Whitehorn 		if (state == sTEXT)
7534c8945a0SNathan Whitehorn 		    break;
7544c8945a0SNathan Whitehorn 		/* FALLTHRU */
7554c8945a0SNathan Whitehorn 
7564c8945a0SNathan Whitehorn 	    case DLGK_ITEM_NEXT:
7574c8945a0SNathan Whitehorn 		if (state == sTEXT) {
7584c8945a0SNathan Whitehorn 		    do_tab = TRUE;
7594c8945a0SNathan Whitehorn 		    move_by = 1;
7604c8945a0SNathan Whitehorn 		    break;
7614c8945a0SNathan Whitehorn 		} else {
7624c8945a0SNathan Whitehorn 		    state = next_valid_buttonindex(state, 0, non_editable);
7634c8945a0SNathan Whitehorn 		    show_buttons = TRUE;
7644c8945a0SNathan Whitehorn 		    continue;
7654c8945a0SNathan Whitehorn 		}
7664c8945a0SNathan Whitehorn 
7672a3e3873SBaptiste Daroussin 	    case DLGK_FORM_NEXT:
7682a3e3873SBaptiste Daroussin 		if (state == sTEXT && !is_last_field(items, choice, item_no)) {
7692a3e3873SBaptiste Daroussin 		    do_tab = TRUE;
7702a3e3873SBaptiste Daroussin 		    move_by = 1;
7712a3e3873SBaptiste Daroussin 		    break;
7722a3e3873SBaptiste Daroussin 		} else {
7732a3e3873SBaptiste Daroussin 		    state = next_valid_buttonindex(state, sTEXT, non_editable);
7742a3e3873SBaptiste Daroussin 		    show_buttons = TRUE;
7752a3e3873SBaptiste Daroussin 		    if (state == sTEXT && choice) {
7762a3e3873SBaptiste Daroussin 			print_item(form, items + choice, scrollamt, FALSE);
7772a3e3873SBaptiste Daroussin 			choice = 0;
7782a3e3873SBaptiste Daroussin 		    }
7792a3e3873SBaptiste Daroussin 		    continue;
7802a3e3873SBaptiste Daroussin 		}
7812a3e3873SBaptiste Daroussin 
7824c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7834c8945a0SNathan Whitehorn 	    case KEY_RESIZE:
784f4f33ea0SBaptiste Daroussin 		dlg_will_resize(dialog);
7854c8945a0SNathan Whitehorn 		/* reset data */
7864c8945a0SNathan Whitehorn 		height = old_height;
7874c8945a0SNathan Whitehorn 		width = old_width;
788f4f33ea0SBaptiste Daroussin 		free(prompt);
789*a96ef450SBaptiste Daroussin 		_dlg_resize_cleanup(dialog);
790f4f33ea0SBaptiste Daroussin 		dlg_unregister_window(form);
791f4f33ea0SBaptiste Daroussin 		/* repaint */
7924c8945a0SNathan Whitehorn 		goto retry;
7934c8945a0SNathan Whitehorn #endif
7944c8945a0SNathan Whitehorn 	    default:
7954c8945a0SNathan Whitehorn #if USE_MOUSE
7964c8945a0SNathan Whitehorn 		if (is_DLGK_MOUSE(key)) {
7974c8945a0SNathan Whitehorn 		    if (key >= DLGK_MOUSE(KEY_MAX)) {
7984c8945a0SNathan Whitehorn 			int cell = key - DLGK_MOUSE(KEY_MAX);
7994c8945a0SNathan Whitehorn 			int row = (cell / getmaxx(form)) + scrollamt;
8004c8945a0SNathan Whitehorn 			int col = (cell % getmaxx(form));
8014c8945a0SNathan Whitehorn 			int n;
8024c8945a0SNathan Whitehorn 
8034c8945a0SNathan Whitehorn 			for (n = 0; n < item_no; ++n) {
8044c8945a0SNathan Whitehorn 			    if (items[n].name_y == row
8054c8945a0SNathan Whitehorn 				&& items[n].name_x <= col
8064c8945a0SNathan Whitehorn 				&& (items[n].name_x + items[n].name_len > col
8074c8945a0SNathan Whitehorn 				    || (items[n].name_y == items[n].text_y
8084c8945a0SNathan Whitehorn 					&& items[n].text_x > col))) {
8094c8945a0SNathan Whitehorn 				if (!is_readonly(&(items[n]))) {
8104c8945a0SNathan Whitehorn 				    field_changed = TRUE;
8114c8945a0SNathan Whitehorn 				    break;
8124c8945a0SNathan Whitehorn 				}
8134c8945a0SNathan Whitehorn 			    }
8144c8945a0SNathan Whitehorn 			    if (items[n].text_y == row
8154c8945a0SNathan Whitehorn 				&& items[n].text_x <= col
8164c8945a0SNathan Whitehorn 				&& items[n].text_x + items[n].text_ilen > col) {
8174c8945a0SNathan Whitehorn 				if (!is_readonly(&(items[n]))) {
8184c8945a0SNathan Whitehorn 				    field_changed = TRUE;
8194c8945a0SNathan Whitehorn 				    break;
8204c8945a0SNathan Whitehorn 				}
8214c8945a0SNathan Whitehorn 			    }
8224c8945a0SNathan Whitehorn 			}
8234c8945a0SNathan Whitehorn 			if (field_changed) {
8244c8945a0SNathan Whitehorn 			    print_item(form, items + choice, scrollamt, FALSE);
8254c8945a0SNathan Whitehorn 			    choice = n;
8264c8945a0SNathan Whitehorn 			    continue;
8274c8945a0SNathan Whitehorn 			}
8284c8945a0SNathan Whitehorn 			beep();
8294c8945a0SNathan Whitehorn 		    } else if ((code = dlg_ok_buttoncode(key - M_EVENT)) >= 0) {
8304c8945a0SNathan Whitehorn 			result = code;
8314c8945a0SNathan Whitehorn 		    }
8324c8945a0SNathan Whitehorn 		    continue;
8334c8945a0SNathan Whitehorn 		}
8344c8945a0SNathan Whitehorn #endif
8354c8945a0SNathan Whitehorn 		break;
8364c8945a0SNathan Whitehorn 	    }
8374c8945a0SNathan Whitehorn 
8384c8945a0SNathan Whitehorn 	    new_scroll = scrollamt;
8394c8945a0SNathan Whitehorn 	    new_choice = choice;
8404c8945a0SNathan Whitehorn 	    if (do_scroll) {
8414c8945a0SNathan Whitehorn 		if (scroll_next(form, items, move_by, &new_choice, &new_scroll)) {
8424c8945a0SNathan Whitehorn 		    if (choice != new_choice) {
8434c8945a0SNathan Whitehorn 			choice = new_choice;
8444c8945a0SNathan Whitehorn 			field_changed = TRUE;
8454c8945a0SNathan Whitehorn 		    }
8464c8945a0SNathan Whitehorn 		    if (scrollamt != new_scroll) {
8474c8945a0SNathan Whitehorn 			scrollamt = new_scroll;
8484c8945a0SNathan Whitehorn 			scroll_changed = TRUE;
8494c8945a0SNathan Whitehorn 		    }
8504c8945a0SNathan Whitehorn 		}
8514c8945a0SNathan Whitehorn 		continue;
8524c8945a0SNathan Whitehorn 	    }
8534c8945a0SNathan Whitehorn 	    if (do_tab) {
8544c8945a0SNathan Whitehorn 		if (tab_next(form, items, item_no, move_by, &new_choice, &new_scroll)) {
8554c8945a0SNathan Whitehorn 		    if (choice != new_choice) {
8564c8945a0SNathan Whitehorn 			choice = new_choice;
8574c8945a0SNathan Whitehorn 			field_changed = TRUE;
8584c8945a0SNathan Whitehorn 		    }
8594c8945a0SNathan Whitehorn 		    if (scrollamt != new_scroll) {
8604c8945a0SNathan Whitehorn 			scrollamt = new_scroll;
8614c8945a0SNathan Whitehorn 			scroll_changed = TRUE;
8624c8945a0SNathan Whitehorn 		    }
8634c8945a0SNathan Whitehorn 		}
8644c8945a0SNathan Whitehorn 		continue;
8654c8945a0SNathan Whitehorn 	    }
8664c8945a0SNathan Whitehorn 	}
8674c8945a0SNathan Whitehorn 
8684c8945a0SNathan Whitehorn 	if (state == sTEXT) {	/* Input box selected */
8694c8945a0SNathan Whitehorn 	    if (!is_readonly(current))
8704c8945a0SNathan Whitehorn 		edit = dlg_edit_string(current->text, &chr_offset, key,
8714c8945a0SNathan Whitehorn 				       fkey, first);
8724c8945a0SNathan Whitehorn 	    if (edit) {
8734c8945a0SNathan Whitehorn 		dlg_show_string(form, current->text, chr_offset,
8744c8945a0SNathan Whitehorn 				form_active_text_attr,
8754c8945a0SNathan Whitehorn 				current->text_y - scrollamt,
8764c8945a0SNathan Whitehorn 				current->text_x,
8774c8945a0SNathan Whitehorn 				current->text_len,
8784c8945a0SNathan Whitehorn 				is_hidden(current), first);
8794c8945a0SNathan Whitehorn 		continue;
8804c8945a0SNathan Whitehorn 	    }
8814c8945a0SNathan Whitehorn 	}
8824c8945a0SNathan Whitehorn 
8834c8945a0SNathan Whitehorn     }
8844c8945a0SNathan Whitehorn 
8854c8945a0SNathan Whitehorn     dlg_mouse_free_regions();
886f4f33ea0SBaptiste Daroussin     dlg_unregister_window(form);
8874c8945a0SNathan Whitehorn     dlg_del_window(dialog);
8884c8945a0SNathan Whitehorn     free(prompt);
8894c8945a0SNathan Whitehorn 
8904c8945a0SNathan Whitehorn     *current_item = choice;
8914c8945a0SNathan Whitehorn     return result;
8924c8945a0SNathan Whitehorn }
8934c8945a0SNathan Whitehorn 
8944c8945a0SNathan Whitehorn /*
8954c8945a0SNathan Whitehorn  * Free memory owned by a list of DIALOG_FORMITEM's.
8964c8945a0SNathan Whitehorn  */
8974c8945a0SNathan Whitehorn void
dlg_free_formitems(DIALOG_FORMITEM * items)8984c8945a0SNathan Whitehorn dlg_free_formitems(DIALOG_FORMITEM * items)
8994c8945a0SNathan Whitehorn {
9004c8945a0SNathan Whitehorn     int n;
9014c8945a0SNathan Whitehorn     for (n = 0; items[n].name != 0; ++n) {
9024c8945a0SNathan Whitehorn 	if (items[n].name_free)
9034c8945a0SNathan Whitehorn 	    free(items[n].name);
9044c8945a0SNathan Whitehorn 	if (items[n].text_free)
9054c8945a0SNathan Whitehorn 	    free(items[n].text);
9064c8945a0SNathan Whitehorn 	if (items[n].help_free && items[n].help != dlg_strempty())
9074c8945a0SNathan Whitehorn 	    free(items[n].help);
9084c8945a0SNathan Whitehorn     }
9094c8945a0SNathan Whitehorn     free(items);
9104c8945a0SNathan Whitehorn }
9114c8945a0SNathan Whitehorn 
9124c8945a0SNathan Whitehorn /*
9134c8945a0SNathan Whitehorn  * The script accepts values beginning at 1, while curses starts at 0.
9144c8945a0SNathan Whitehorn  */
9154c8945a0SNathan Whitehorn int
dlg_ordinate(const char * s)9164c8945a0SNathan Whitehorn dlg_ordinate(const char *s)
9174c8945a0SNathan Whitehorn {
9184c8945a0SNathan Whitehorn     int result = atoi(s);
9194c8945a0SNathan Whitehorn     if (result > 0)
9204c8945a0SNathan Whitehorn 	--result;
9214c8945a0SNathan Whitehorn     else
9224c8945a0SNathan Whitehorn 	result = 0;
9234c8945a0SNathan Whitehorn     return result;
9244c8945a0SNathan Whitehorn }
9254c8945a0SNathan Whitehorn 
9264c8945a0SNathan Whitehorn int
dialog_form(const char * title,const char * cprompt,int height,int width,int form_height,int item_no,char ** items)9274c8945a0SNathan Whitehorn dialog_form(const char *title,
9284c8945a0SNathan Whitehorn 	    const char *cprompt,
9294c8945a0SNathan Whitehorn 	    int height,
9304c8945a0SNathan Whitehorn 	    int width,
9314c8945a0SNathan Whitehorn 	    int form_height,
9324c8945a0SNathan Whitehorn 	    int item_no,
9334c8945a0SNathan Whitehorn 	    char **items)
9344c8945a0SNathan Whitehorn {
9354c8945a0SNathan Whitehorn     int result;
936f4f33ea0SBaptiste Daroussin     int choice = 0;
9374c8945a0SNathan Whitehorn     int i;
9384c8945a0SNathan Whitehorn     DIALOG_FORMITEM *listitems;
9394c8945a0SNathan Whitehorn     DIALOG_VARS save_vars;
9404c8945a0SNathan Whitehorn     bool show_status = FALSE;
941febdb468SDevin Teske     char *help_result;
9424c8945a0SNathan Whitehorn 
9434c8945a0SNathan Whitehorn     dlg_save_vars(&save_vars);
9444c8945a0SNathan Whitehorn     dialog_vars.separate_output = TRUE;
9454c8945a0SNathan Whitehorn 
9464c8945a0SNathan Whitehorn     listitems = dlg_calloc(DIALOG_FORMITEM, (size_t) item_no + 1);
9474c8945a0SNathan Whitehorn     assert_ptr(listitems, "dialog_form");
9484c8945a0SNathan Whitehorn 
9494c8945a0SNathan Whitehorn     for (i = 0; i < item_no; ++i) {
9504c8945a0SNathan Whitehorn 	listitems[i].type = dialog_vars.formitem_type;
9514c8945a0SNathan Whitehorn 	listitems[i].name = ItemName(i);
9524c8945a0SNathan Whitehorn 	listitems[i].name_len = (int) strlen(ItemName(i));
9534c8945a0SNathan Whitehorn 	listitems[i].name_y = dlg_ordinate(ItemNameY(i));
9544c8945a0SNathan Whitehorn 	listitems[i].name_x = dlg_ordinate(ItemNameX(i));
9554c8945a0SNathan Whitehorn 	listitems[i].text = ItemText(i);
9564c8945a0SNathan Whitehorn 	listitems[i].text_len = (int) strlen(ItemText(i));
9574c8945a0SNathan Whitehorn 	listitems[i].text_y = dlg_ordinate(ItemTextY(i));
9584c8945a0SNathan Whitehorn 	listitems[i].text_x = dlg_ordinate(ItemTextX(i));
9594c8945a0SNathan Whitehorn 	listitems[i].text_flen = atoi(ItemTextFLen(i));
9604c8945a0SNathan Whitehorn 	listitems[i].text_ilen = atoi(ItemTextILen(i));
9614c8945a0SNathan Whitehorn 	listitems[i].help = ((dialog_vars.item_help)
9624c8945a0SNathan Whitehorn 			     ? ItemHelp(i)
9634c8945a0SNathan Whitehorn 			     : dlg_strempty());
9644c8945a0SNathan Whitehorn     }
9654c8945a0SNathan Whitehorn 
9664c8945a0SNathan Whitehorn     result = dlg_form(title,
9674c8945a0SNathan Whitehorn 		      cprompt,
9684c8945a0SNathan Whitehorn 		      height,
9694c8945a0SNathan Whitehorn 		      width,
9704c8945a0SNathan Whitehorn 		      form_height,
9714c8945a0SNathan Whitehorn 		      item_no,
9724c8945a0SNathan Whitehorn 		      listitems,
9734c8945a0SNathan Whitehorn 		      &choice);
9744c8945a0SNathan Whitehorn 
9754c8945a0SNathan Whitehorn     switch (result) {
9764c8945a0SNathan Whitehorn     case DLG_EXIT_OK:		/* FALLTHRU */
9774c8945a0SNathan Whitehorn     case DLG_EXIT_EXTRA:
9784c8945a0SNathan Whitehorn 	show_status = TRUE;
9794c8945a0SNathan Whitehorn 	break;
9804c8945a0SNathan Whitehorn     case DLG_EXIT_HELP:
981febdb468SDevin Teske 	dlg_add_help_formitem(&result, &help_result, &listitems[choice]);
9824c8945a0SNathan Whitehorn 	show_status = dialog_vars.help_status;
983febdb468SDevin Teske 	dlg_add_string(help_result);
9844c8945a0SNathan Whitehorn 	if (show_status)
9854c8945a0SNathan Whitehorn 	    dlg_add_separator();
9864c8945a0SNathan Whitehorn 	break;
9874c8945a0SNathan Whitehorn     }
9884c8945a0SNathan Whitehorn     if (show_status) {
9894c8945a0SNathan Whitehorn 	for (i = 0; i < item_no; i++) {
9904c8945a0SNathan Whitehorn 	    if (listitems[i].text_flen > 0) {
9914c8945a0SNathan Whitehorn 		dlg_add_string(listitems[i].text);
9924c8945a0SNathan Whitehorn 		dlg_add_separator();
9934c8945a0SNathan Whitehorn 	    }
9944c8945a0SNathan Whitehorn 	}
9952a3e3873SBaptiste Daroussin 	dlg_add_last_key(-1);
9964c8945a0SNathan Whitehorn     }
9974c8945a0SNathan Whitehorn 
9984c8945a0SNathan Whitehorn     dlg_free_formitems(listitems);
9994c8945a0SNathan Whitehorn     dlg_restore_vars(&save_vars);
10004c8945a0SNathan Whitehorn 
10014c8945a0SNathan Whitehorn     return result;
10024c8945a0SNathan Whitehorn }
1003