xref: /dragonfly/contrib/dialog/formbox.c (revision a8e38dc0)
15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez  *  $Id: formbox.c,v 1.106 2022/04/06 08:04:48 tom Exp $
35382d832SPeter Avalos  *
45940c9abSDaniel Fojt  *  formbox.c -- implements the form (i.e., some pairs label/editbox)
55382d832SPeter Avalos  *
6*a8e38dc0SAntonio Huete Jimenez  *  Copyright 2003-2021,2022	Thomas E. Dickey
75382d832SPeter Avalos  *
85382d832SPeter Avalos  *  This program is free software; you can redistribute it and/or modify
95382d832SPeter Avalos  *  it under the terms of the GNU Lesser General Public License, version 2.1
105382d832SPeter Avalos  *  as published by the Free Software Foundation.
115382d832SPeter Avalos  *
125382d832SPeter Avalos  *  This program is distributed in the hope that it will be useful, but
135382d832SPeter Avalos  *  WITHOUT ANY WARRANTY; without even the implied warranty of
145382d832SPeter Avalos  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155382d832SPeter Avalos  *  Lesser General Public License for more details.
165382d832SPeter Avalos  *
175382d832SPeter Avalos  *  You should have received a copy of the GNU Lesser General Public
185382d832SPeter Avalos  *  License along with this program; if not, write to
195382d832SPeter Avalos  *	Free Software Foundation, Inc.
205382d832SPeter Avalos  *	51 Franklin St., Fifth Floor
215382d832SPeter Avalos  *	Boston, MA 02110, USA.
225382d832SPeter Avalos  *
235382d832SPeter Avalos  *  This is adapted from source contributed by
245382d832SPeter Avalos  *	Valery Reznic (valery_reznic@users.sourceforge.net)
255382d832SPeter Avalos  */
265382d832SPeter Avalos 
27*a8e38dc0SAntonio Huete Jimenez #include <dlg_internals.h>
285382d832SPeter Avalos #include <dlg_keys.h>
295382d832SPeter Avalos 
305382d832SPeter Avalos #define LLEN(n) ((n) * FORMBOX_TAGS)
315382d832SPeter Avalos 
325382d832SPeter Avalos #define ItemName(i)     items[LLEN(i) + 0]
335382d832SPeter Avalos #define ItemNameY(i)    items[LLEN(i) + 1]
345382d832SPeter Avalos #define ItemNameX(i)    items[LLEN(i) + 2]
355382d832SPeter Avalos #define ItemText(i)     items[LLEN(i) + 3]
365382d832SPeter Avalos #define ItemTextY(i)    items[LLEN(i) + 4]
375382d832SPeter Avalos #define ItemTextX(i)    items[LLEN(i) + 5]
385382d832SPeter Avalos #define ItemTextFLen(i) items[LLEN(i) + 6]
395382d832SPeter Avalos #define ItemTextILen(i) items[LLEN(i) + 7]
405382d832SPeter Avalos #define ItemHelp(i)     (dialog_vars.item_help ? items[LLEN(i) + 8] : dlg_strempty())
415382d832SPeter Avalos 
425382d832SPeter Avalos static bool
is_readonly(DIALOG_FORMITEM * item)435382d832SPeter Avalos is_readonly(DIALOG_FORMITEM * item)
445382d832SPeter Avalos {
455382d832SPeter Avalos     return ((item->type & 2) != 0) || (item->text_flen <= 0);
465382d832SPeter Avalos }
475382d832SPeter Avalos 
485382d832SPeter Avalos static bool
is_hidden(DIALOG_FORMITEM * item)495382d832SPeter Avalos is_hidden(DIALOG_FORMITEM * item)
505382d832SPeter Avalos {
515382d832SPeter Avalos     return ((item->type & 1) != 0);
525382d832SPeter Avalos }
535382d832SPeter Avalos 
545382d832SPeter Avalos static bool
in_window(WINDOW * win,int scrollamt,int y)555382d832SPeter Avalos in_window(WINDOW *win, int scrollamt, int y)
565382d832SPeter Avalos {
575382d832SPeter Avalos     return (y >= scrollamt && y - scrollamt < getmaxy(win));
585382d832SPeter Avalos }
595382d832SPeter Avalos 
605382d832SPeter Avalos static bool
ok_move(WINDOW * win,int scrollamt,int y,int x)615382d832SPeter Avalos ok_move(WINDOW *win, int scrollamt, int y, int x)
625382d832SPeter Avalos {
635382d832SPeter Avalos     return in_window(win, scrollamt, y)
645382d832SPeter Avalos 	&& (wmove(win, y - scrollamt, x) != ERR);
655382d832SPeter Avalos }
665382d832SPeter Avalos 
675382d832SPeter Avalos static void
move_past(WINDOW * win,int y,int x)685382d832SPeter Avalos move_past(WINDOW *win, int y, int x)
695382d832SPeter Avalos {
705382d832SPeter Avalos     if (wmove(win, y, x) == ERR)
715382d832SPeter Avalos 	wmove(win, y, getmaxx(win) - 1);
725382d832SPeter Avalos }
735382d832SPeter Avalos 
745382d832SPeter Avalos /*
755382d832SPeter Avalos  * Print form item
765382d832SPeter Avalos  */
775382d832SPeter Avalos static int
print_item(WINDOW * win,DIALOG_FORMITEM * item,int scrollamt,bool choice)785382d832SPeter Avalos print_item(WINDOW *win, DIALOG_FORMITEM * item, int scrollamt, bool choice)
795382d832SPeter Avalos {
805382d832SPeter Avalos     int count = 0;
815382d832SPeter Avalos     int len;
825382d832SPeter Avalos 
835382d832SPeter Avalos     if (ok_move(win, scrollamt, item->name_y, item->name_x)) {
845382d832SPeter Avalos 	len = item->name_len;
855382d832SPeter Avalos 	len = MIN(len, getmaxx(win) - item->name_x);
865382d832SPeter Avalos 	if (len > 0) {
875382d832SPeter Avalos 	    dlg_show_string(win,
885382d832SPeter Avalos 			    item->name,
895382d832SPeter Avalos 			    0,
905382d832SPeter Avalos 			    menubox_attr,
915382d832SPeter Avalos 			    item->name_y - scrollamt,
925382d832SPeter Avalos 			    item->name_x,
935382d832SPeter Avalos 			    len,
945382d832SPeter Avalos 			    FALSE,
955382d832SPeter Avalos 			    FALSE);
965382d832SPeter Avalos 	    move_past(win, item->name_y - scrollamt, item->name_x + len);
975382d832SPeter Avalos 	    count = 1;
985382d832SPeter Avalos 	}
995382d832SPeter Avalos     }
1005382d832SPeter Avalos     if (item->text_len && ok_move(win, scrollamt, item->text_y, item->text_x)) {
1015382d832SPeter Avalos 	chtype this_item_attribute;
1025382d832SPeter Avalos 
1035382d832SPeter Avalos 	len = item->text_len;
1045382d832SPeter Avalos 	len = MIN(len, getmaxx(win) - item->text_x);
1055382d832SPeter Avalos 
1065382d832SPeter Avalos 	if (!is_readonly(item)) {
1075382d832SPeter Avalos 	    this_item_attribute = choice
1085382d832SPeter Avalos 		? form_active_text_attr
1095382d832SPeter Avalos 		: form_text_attr;
1105382d832SPeter Avalos 	} else {
1115382d832SPeter Avalos 	    this_item_attribute = form_item_readonly_attr;
1125382d832SPeter Avalos 	}
1135382d832SPeter Avalos 
1145382d832SPeter Avalos 	if (len > 0) {
1155382d832SPeter Avalos 	    dlg_show_string(win,
1165382d832SPeter Avalos 			    item->text,
1175382d832SPeter Avalos 			    0,
1185382d832SPeter Avalos 			    this_item_attribute,
1195382d832SPeter Avalos 			    item->text_y - scrollamt,
1205382d832SPeter Avalos 			    item->text_x,
1215382d832SPeter Avalos 			    len,
1225382d832SPeter Avalos 			    is_hidden(item),
1235382d832SPeter Avalos 			    FALSE);
1245382d832SPeter Avalos 	    move_past(win, item->text_y - scrollamt, item->text_x + len);
1255382d832SPeter Avalos 	    count = 1;
1265382d832SPeter Avalos 	}
1275382d832SPeter Avalos     }
1285382d832SPeter Avalos     return count;
1295382d832SPeter Avalos }
1305382d832SPeter Avalos 
1315382d832SPeter Avalos /*
1325382d832SPeter Avalos  * Print the entire form.
1335382d832SPeter Avalos  */
1345382d832SPeter Avalos static void
print_form(WINDOW * win,DIALOG_FORMITEM * item,int total,int scrollamt,int choice)1355382d832SPeter Avalos print_form(WINDOW *win, DIALOG_FORMITEM * item, int total, int scrollamt, int choice)
1365382d832SPeter Avalos {
1375382d832SPeter Avalos     int n;
1385382d832SPeter Avalos     int count = 0;
1395382d832SPeter Avalos 
1405382d832SPeter Avalos     for (n = 0; n < total; ++n) {
1415382d832SPeter Avalos 	count += print_item(win, item + n, scrollamt, n == choice);
1425382d832SPeter Avalos     }
1435382d832SPeter Avalos     if (count) {
1445382d832SPeter Avalos 	wbkgdset(win, menubox_attr | ' ');
1455382d832SPeter Avalos 	wclrtobot(win);
1465382d832SPeter Avalos 	(void) wnoutrefresh(win);
1475382d832SPeter Avalos     }
1485382d832SPeter Avalos }
1495382d832SPeter Avalos 
1505382d832SPeter Avalos static int
set_choice(DIALOG_FORMITEM item[],int choice,int item_no,bool * noneditable)1515382d832SPeter Avalos set_choice(DIALOG_FORMITEM item[], int choice, int item_no, bool * noneditable)
1525382d832SPeter Avalos {
1535382d832SPeter Avalos     int result = -1;
1545382d832SPeter Avalos 
1555382d832SPeter Avalos     *noneditable = FALSE;
1565382d832SPeter Avalos     if (!is_readonly(&item[choice])) {
1575382d832SPeter Avalos 	result = choice;
1585382d832SPeter Avalos     } else {
1595940c9abSDaniel Fojt 	int i;
1605940c9abSDaniel Fojt 
1615382d832SPeter Avalos 	for (i = 0; i < item_no; i++) {
1625382d832SPeter Avalos 	    if (!is_readonly(&(item[i]))) {
1635382d832SPeter Avalos 		result = i;
1645382d832SPeter Avalos 		break;
1655382d832SPeter Avalos 	    }
1665382d832SPeter Avalos 	}
1675382d832SPeter Avalos 	if (result < 0) {
1685382d832SPeter Avalos 	    *noneditable = TRUE;
1695382d832SPeter Avalos 	    result = 0;
1705382d832SPeter Avalos 	}
1715382d832SPeter Avalos     }
1725382d832SPeter Avalos     return result;
1735382d832SPeter Avalos }
1745382d832SPeter Avalos 
1755382d832SPeter Avalos /*
1765382d832SPeter Avalos  * Find the last y-value in the form.
1775382d832SPeter Avalos  */
1785382d832SPeter Avalos static int
form_limit(DIALOG_FORMITEM item[])1795382d832SPeter Avalos form_limit(DIALOG_FORMITEM item[])
1805382d832SPeter Avalos {
1815382d832SPeter Avalos     int n;
1825382d832SPeter Avalos     int limit = 0;
1835382d832SPeter Avalos     for (n = 0; item[n].name != 0; ++n) {
1845382d832SPeter Avalos 	if (limit < item[n].name_y)
1855382d832SPeter Avalos 	    limit = item[n].name_y;
1865382d832SPeter Avalos 	if (limit < item[n].text_y)
1875382d832SPeter Avalos 	    limit = item[n].text_y;
1885382d832SPeter Avalos     }
1895382d832SPeter Avalos     return limit;
1905382d832SPeter Avalos }
1915382d832SPeter Avalos 
1925382d832SPeter Avalos static int
is_first_field(DIALOG_FORMITEM item[],int choice)1935382d832SPeter Avalos is_first_field(DIALOG_FORMITEM item[], int choice)
1945382d832SPeter Avalos {
1955382d832SPeter Avalos     int count = 0;
1965382d832SPeter Avalos     while (choice >= 0) {
1975382d832SPeter Avalos 	if (item[choice].text_flen > 0) {
1985382d832SPeter Avalos 	    ++count;
1995382d832SPeter Avalos 	}
2005382d832SPeter Avalos 	--choice;
2015382d832SPeter Avalos     }
2025382d832SPeter Avalos 
2035382d832SPeter Avalos     return (count == 1);
2045382d832SPeter Avalos }
2055382d832SPeter Avalos 
2065382d832SPeter Avalos static int
is_last_field(DIALOG_FORMITEM item[],int choice,int item_no)2075382d832SPeter Avalos is_last_field(DIALOG_FORMITEM item[], int choice, int item_no)
2085382d832SPeter Avalos {
2095382d832SPeter Avalos     int count = 0;
2105382d832SPeter Avalos     while (choice < item_no) {
2115382d832SPeter Avalos 	if (item[choice].text_flen > 0) {
2125382d832SPeter Avalos 	    ++count;
2135382d832SPeter Avalos 	}
2145382d832SPeter Avalos 	++choice;
2155382d832SPeter Avalos     }
2165382d832SPeter Avalos 
2175382d832SPeter Avalos     return (count == 1);
2185382d832SPeter Avalos }
2195382d832SPeter Avalos 
2205382d832SPeter Avalos /*
2215382d832SPeter Avalos  * Tab to the next field.
2225382d832SPeter Avalos  */
2235382d832SPeter Avalos static bool
tab_next(WINDOW * win,DIALOG_FORMITEM item[],int item_no,int stepsize,int * choice,int * scrollamt)2245382d832SPeter Avalos tab_next(WINDOW *win,
2255382d832SPeter Avalos 	 DIALOG_FORMITEM item[],
2265382d832SPeter Avalos 	 int item_no,
2275382d832SPeter Avalos 	 int stepsize,
2285382d832SPeter Avalos 	 int *choice,
2295382d832SPeter Avalos 	 int *scrollamt)
2305382d832SPeter Avalos {
2315382d832SPeter Avalos     int old_choice = *choice;
2325382d832SPeter Avalos     int old_scroll = *scrollamt;
2335382d832SPeter Avalos     bool wrapped = FALSE;
2345382d832SPeter Avalos 
2355382d832SPeter Avalos     do {
2365382d832SPeter Avalos 	do {
2375382d832SPeter Avalos 	    *choice += stepsize;
2385382d832SPeter Avalos 	    if (*choice < 0) {
2395382d832SPeter Avalos 		*choice = item_no - 1;
2405382d832SPeter Avalos 		wrapped = TRUE;
2415382d832SPeter Avalos 	    } else if (*choice >= item_no) {
2425382d832SPeter Avalos 		*choice = 0;
2435382d832SPeter Avalos 		wrapped = TRUE;
2445382d832SPeter Avalos 	    }
2455382d832SPeter Avalos 	} while ((*choice != old_choice) && is_readonly(&(item[*choice])));
2465382d832SPeter Avalos 
2475382d832SPeter Avalos 	if (item[*choice].text_flen > 0) {
2485382d832SPeter Avalos 	    int lo = MIN(item[*choice].name_y, item[*choice].text_y);
2495382d832SPeter Avalos 	    int hi = MAX(item[*choice].name_y, item[*choice].text_y);
2505382d832SPeter Avalos 
2515382d832SPeter Avalos 	    if (old_choice == *choice)
2525382d832SPeter Avalos 		break;
2535382d832SPeter Avalos 	    print_item(win, item + old_choice, *scrollamt, FALSE);
2545382d832SPeter Avalos 
2555382d832SPeter Avalos 	    if (*scrollamt < lo + 1 - getmaxy(win))
2565382d832SPeter Avalos 		*scrollamt = lo + 1 - getmaxy(win);
2575382d832SPeter Avalos 	    if (*scrollamt > hi)
2585382d832SPeter Avalos 		*scrollamt = hi;
2595382d832SPeter Avalos 	    /*
2605382d832SPeter Avalos 	     * If we have to scroll to show a wrap-around, it does get
2615382d832SPeter Avalos 	     * confusing.  Just give up rather than scroll.  Tab'ing to the
2625382d832SPeter Avalos 	     * next field in a multi-column form is a different matter.  Scroll
2635382d832SPeter Avalos 	     * for that.
2645382d832SPeter Avalos 	     */
2655382d832SPeter Avalos 	    if (*scrollamt != old_scroll) {
2665382d832SPeter Avalos 		if (wrapped) {
2675382d832SPeter Avalos 		    beep();
2685382d832SPeter Avalos 		    *scrollamt = old_scroll;
2695382d832SPeter Avalos 		    *choice = old_choice;
2705382d832SPeter Avalos 		} else {
2715382d832SPeter Avalos 		    scrollok(win, TRUE);
2725382d832SPeter Avalos 		    wscrl(win, *scrollamt - old_scroll);
2735382d832SPeter Avalos 		    scrollok(win, FALSE);
2745382d832SPeter Avalos 		}
2755382d832SPeter Avalos 	    }
2765382d832SPeter Avalos 	    break;
2775382d832SPeter Avalos 	}
2785382d832SPeter Avalos     } while (*choice != old_choice);
2795382d832SPeter Avalos 
2805382d832SPeter Avalos     return (old_choice != *choice) || (old_scroll != *scrollamt);
2815382d832SPeter Avalos }
2825382d832SPeter Avalos 
2835382d832SPeter Avalos /*
2845382d832SPeter Avalos  * Scroll to the next page, putting the choice at the first editable field
2855382d832SPeter Avalos  * in that page.  Note that fields are not necessarily in top-to-bottom order,
2865382d832SPeter Avalos  * nor is there necessarily a field on each row of the window.
2875382d832SPeter Avalos  */
2885382d832SPeter Avalos static bool
scroll_next(WINDOW * win,DIALOG_FORMITEM item[],int stepsize,int * choice,int * scrollamt)2895382d832SPeter Avalos scroll_next(WINDOW *win, DIALOG_FORMITEM item[], int stepsize, int *choice, int *scrollamt)
2905382d832SPeter Avalos {
2915382d832SPeter Avalos     bool result = TRUE;
2925382d832SPeter Avalos     int old_choice = *choice;
2935382d832SPeter Avalos     int old_scroll = *scrollamt;
2945382d832SPeter Avalos     int old_row = MIN(item[old_choice].text_y, item[old_choice].name_y);
2955382d832SPeter Avalos     int target = old_scroll + stepsize;
2965382d832SPeter Avalos 
2975382d832SPeter Avalos     if (stepsize < 0) {
2985382d832SPeter Avalos 	if (old_row != old_scroll)
2995382d832SPeter Avalos 	    target = old_scroll;
3005382d832SPeter Avalos 	else
3015382d832SPeter Avalos 	    target = old_scroll + stepsize;
3025382d832SPeter Avalos 	if (target < 0) {
3035382d832SPeter Avalos 	    result = FALSE;
3045382d832SPeter Avalos 	}
3055382d832SPeter Avalos     } else {
3065382d832SPeter Avalos 	if (target > form_limit(item)) {
3075382d832SPeter Avalos 	    result = FALSE;
3085382d832SPeter Avalos 	}
3095382d832SPeter Avalos     }
3105382d832SPeter Avalos 
3115382d832SPeter Avalos     if (result) {
3125940c9abSDaniel Fojt 	int n;
3135940c9abSDaniel Fojt 
3145382d832SPeter Avalos 	for (n = 0; item[n].name != 0; ++n) {
3155382d832SPeter Avalos 	    if (item[n].text_flen > 0) {
3165382d832SPeter Avalos 		int new_row = MIN(item[n].text_y, item[n].name_y);
3175382d832SPeter Avalos 		if (abs(new_row - target) < abs(old_row - target)) {
3185382d832SPeter Avalos 		    old_row = new_row;
3195382d832SPeter Avalos 		    *choice = n;
3205382d832SPeter Avalos 		}
3215382d832SPeter Avalos 	    }
3225382d832SPeter Avalos 	}
3235382d832SPeter Avalos 
3245382d832SPeter Avalos 	if (old_choice != *choice)
3255382d832SPeter Avalos 	    print_item(win, item + old_choice, *scrollamt, FALSE);
3265382d832SPeter Avalos 
3275382d832SPeter Avalos 	*scrollamt = *choice;
3285382d832SPeter Avalos 	if (*scrollamt != old_scroll) {
3295382d832SPeter Avalos 	    scrollok(win, TRUE);
3305382d832SPeter Avalos 	    wscrl(win, *scrollamt - old_scroll);
3315382d832SPeter Avalos 	    scrollok(win, FALSE);
3325382d832SPeter Avalos 	}
3335382d832SPeter Avalos 	result = (old_choice != *choice) || (old_scroll != *scrollamt);
3345382d832SPeter Avalos     }
3355382d832SPeter Avalos     if (!result)
3365382d832SPeter Avalos 	beep();
3375382d832SPeter Avalos     return result;
3385382d832SPeter Avalos }
3395382d832SPeter Avalos 
3405382d832SPeter Avalos /*
3415382d832SPeter Avalos  * Do a sanity check on the field length, and return the "right" value.
3425382d832SPeter Avalos  */
3435382d832SPeter Avalos static int
real_length(DIALOG_FORMITEM * item)3445382d832SPeter Avalos real_length(DIALOG_FORMITEM * item)
3455382d832SPeter Avalos {
3465382d832SPeter Avalos     return (item->text_flen > 0
3475382d832SPeter Avalos 	    ? item->text_flen
3485382d832SPeter Avalos 	    : (item->text_flen < 0
3495382d832SPeter Avalos 	       ? -item->text_flen
3505382d832SPeter Avalos 	       : item->text_len));
3515382d832SPeter Avalos }
3525382d832SPeter Avalos 
3535382d832SPeter Avalos /*
3545382d832SPeter Avalos  * Compute the form size, setup field buffers.
3555382d832SPeter Avalos  */
3565382d832SPeter Avalos static void
make_FORM_ELTs(DIALOG_FORMITEM * item,int item_no,int * min_height,int * min_width)3575382d832SPeter Avalos make_FORM_ELTs(DIALOG_FORMITEM * item,
3585382d832SPeter Avalos 	       int item_no,
3595382d832SPeter Avalos 	       int *min_height,
3605382d832SPeter Avalos 	       int *min_width)
3615382d832SPeter Avalos {
3625382d832SPeter Avalos     int i;
3635382d832SPeter Avalos     int min_w = 0;
3645382d832SPeter Avalos     int min_h = 0;
3655382d832SPeter Avalos 
3665382d832SPeter Avalos     for (i = 0; i < item_no; ++i) {
3675382d832SPeter Avalos 	int real_len = real_length(item + i);
3685382d832SPeter Avalos 
3695382d832SPeter Avalos 	/*
3705382d832SPeter Avalos 	 * Special value '0' for text_flen: no input allowed
3715382d832SPeter Avalos 	 * Special value '0' for text_ilen: 'be the same as text_flen'
3725382d832SPeter Avalos 	 */
3735382d832SPeter Avalos 	if (item[i].text_ilen == 0)
3745382d832SPeter Avalos 	    item[i].text_ilen = real_len;
3755382d832SPeter Avalos 
3765382d832SPeter Avalos 	min_h = MAX(min_h, item[i].name_y + 1);
3775382d832SPeter Avalos 	min_h = MAX(min_h, item[i].text_y + 1);
3785382d832SPeter Avalos 	min_w = MAX(min_w, item[i].name_x + 1 + item[i].name_len);
3795382d832SPeter Avalos 	min_w = MAX(min_w, item[i].text_x + 1 + real_len);
3805382d832SPeter Avalos 
3815382d832SPeter Avalos 	item[i].text_len = real_length(item + i);
3825382d832SPeter Avalos 
3835382d832SPeter Avalos 	/*
3845382d832SPeter Avalos 	 * We do not know the actual length of .text, so we allocate it here
3855382d832SPeter Avalos 	 * to ensure it is big enough.
3865382d832SPeter Avalos 	 */
3875382d832SPeter Avalos 	if (item[i].text_flen > 0) {
3885382d832SPeter Avalos 	    int max_len = dlg_max_input(MAX(item[i].text_ilen + 1, MAX_LEN));
3895382d832SPeter Avalos 	    char *old_text = item[i].text;
3905382d832SPeter Avalos 
3915382d832SPeter Avalos 	    item[i].text = dlg_malloc(char, (size_t) max_len + 1);
3925382d832SPeter Avalos 	    assert_ptr(item[i].text, "make_FORM_ELTs");
3935382d832SPeter Avalos 
3945382d832SPeter Avalos 	    sprintf(item[i].text, "%.*s", item[i].text_ilen, old_text);
3955382d832SPeter Avalos 
3965382d832SPeter Avalos 	    if (item[i].text_free) {
3975382d832SPeter Avalos 		free(old_text);
3985382d832SPeter Avalos 	    }
3995382d832SPeter Avalos 	    item[i].text_free = TRUE;
4005382d832SPeter Avalos 	}
4015382d832SPeter Avalos     }
4025382d832SPeter Avalos 
4035382d832SPeter Avalos     *min_height = min_h;
4045382d832SPeter Avalos     *min_width = min_w;
4055382d832SPeter Avalos }
4065382d832SPeter Avalos 
4075382d832SPeter Avalos int
dlg_default_formitem(DIALOG_FORMITEM * items)4085382d832SPeter Avalos dlg_default_formitem(DIALOG_FORMITEM * items)
4095382d832SPeter Avalos {
4105382d832SPeter Avalos     int result = 0;
4115382d832SPeter Avalos 
4125382d832SPeter Avalos     if (dialog_vars.default_item != 0) {
4135382d832SPeter Avalos 	int count = 0;
4145382d832SPeter Avalos 	while (items->name != 0) {
4155382d832SPeter Avalos 	    if (!strcmp(dialog_vars.default_item, items->name)) {
4165382d832SPeter Avalos 		result = count;
4175382d832SPeter Avalos 		break;
4185382d832SPeter Avalos 	    }
4195382d832SPeter Avalos 	    ++items;
4205382d832SPeter Avalos 	    count++;
4215382d832SPeter Avalos 	}
4225382d832SPeter Avalos     }
4235382d832SPeter Avalos     return result;
4245382d832SPeter Avalos }
4255382d832SPeter Avalos 
4265382d832SPeter Avalos #define sTEXT -1
4275382d832SPeter Avalos 
4285382d832SPeter Avalos static int
next_valid_buttonindex(int state,int extra,bool non_editable)4295382d832SPeter Avalos next_valid_buttonindex(int state, int extra, bool non_editable)
4305382d832SPeter Avalos {
4315382d832SPeter Avalos     state = dlg_next_ok_buttonindex(state, extra);
4325382d832SPeter Avalos     while (non_editable && state == sTEXT)
4335382d832SPeter Avalos 	state = dlg_next_ok_buttonindex(state, sTEXT);
4345382d832SPeter Avalos     return state;
4355382d832SPeter Avalos }
4365382d832SPeter Avalos 
4375382d832SPeter Avalos static int
prev_valid_buttonindex(int state,int extra,bool non_editable)4385382d832SPeter Avalos prev_valid_buttonindex(int state, int extra, bool non_editable)
4395382d832SPeter Avalos {
4405382d832SPeter Avalos     state = dlg_prev_ok_buttonindex(state, extra);
4415382d832SPeter Avalos     while (non_editable && state == sTEXT)
4425382d832SPeter Avalos 	state = dlg_prev_ok_buttonindex(state, sTEXT);
4435382d832SPeter Avalos     return state;
4445382d832SPeter Avalos }
4455382d832SPeter Avalos 
4465382d832SPeter Avalos #define NAVIGATE_BINDINGS \
4475382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), \
4485382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), \
4495382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  CHR_NEXT ), \
4505382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_DOWN ), \
4515940c9abSDaniel Fojt 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_RIGHT ), \
4525382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_ITEM_NEXT,  KEY_NEXT ), \
4535382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  CHR_PREVIOUS ), \
4545382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_PREVIOUS ), \
4555940c9abSDaniel Fojt 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_LEFT ), \
4565382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_ITEM_PREV,  KEY_UP ), \
4575382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ), \
4585382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE )
4595382d832SPeter Avalos /*
4605382d832SPeter Avalos  * Display a form for entering a number of fields
4615382d832SPeter Avalos  */
4625382d832SPeter Avalos 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)4635382d832SPeter Avalos dlg_form(const char *title,
4645382d832SPeter Avalos 	 const char *cprompt,
4655382d832SPeter Avalos 	 int height,
4665382d832SPeter Avalos 	 int width,
4675382d832SPeter Avalos 	 int form_height,
4685382d832SPeter Avalos 	 int item_no,
4695382d832SPeter Avalos 	 DIALOG_FORMITEM * items,
4705382d832SPeter Avalos 	 int *current_item)
4715382d832SPeter Avalos {
4725382d832SPeter Avalos     /* *INDENT-OFF* */
4735382d832SPeter Avalos     static DLG_KEYS_BINDING binding[] = {
4745382d832SPeter Avalos 	HELPKEY_BINDINGS,
4755382d832SPeter Avalos 	ENTERKEY_BINDINGS,
4765382d832SPeter Avalos 	NAVIGATE_BINDINGS,
4775940c9abSDaniel Fojt 	TOGGLEKEY_BINDINGS,
4785382d832SPeter Avalos 	END_KEYS_BINDING
4795382d832SPeter Avalos     };
4805382d832SPeter Avalos     static DLG_KEYS_BINDING binding2[] = {
4815382d832SPeter Avalos 	INPUTSTR_BINDINGS,
4825382d832SPeter Avalos 	HELPKEY_BINDINGS,
4835382d832SPeter Avalos 	ENTERKEY_BINDINGS,
4845382d832SPeter Avalos 	NAVIGATE_BINDINGS,
4855940c9abSDaniel Fojt 	/* no TOGGLEKEY_BINDINGS, since that includes space... */
4865382d832SPeter Avalos 	END_KEYS_BINDING
4875382d832SPeter Avalos     };
4885382d832SPeter Avalos     /* *INDENT-ON* */
4895382d832SPeter Avalos 
4905382d832SPeter Avalos #ifdef KEY_RESIZE
4915382d832SPeter Avalos     int old_height = height;
4925382d832SPeter Avalos     int old_width = width;
493*a8e38dc0SAntonio Huete Jimenez     int old_fhigh = form_height;
4945382d832SPeter Avalos #endif
4955382d832SPeter Avalos 
4965382d832SPeter Avalos     int form_width;
4975940c9abSDaniel Fojt     bool first = TRUE;
4985940c9abSDaniel Fojt     bool first_trace = TRUE;
4995382d832SPeter Avalos     int chr_offset = 0;
5005940c9abSDaniel Fojt     int state = (dialog_vars.default_button >= 0
5015940c9abSDaniel Fojt 		 ? dlg_default_button()
5025940c9abSDaniel Fojt 		 : sTEXT);
5035382d832SPeter Avalos     int x, y, cur_x, cur_y, box_x, box_y;
5045382d832SPeter Avalos     int code;
5055382d832SPeter Avalos     int fkey;
5065382d832SPeter Avalos     int choice = dlg_default_formitem(items);
5075382d832SPeter Avalos     int new_choice, new_scroll;
5085382d832SPeter Avalos     int scrollamt = 0;
5095382d832SPeter Avalos     int result = DLG_EXIT_UNKNOWN;
5105382d832SPeter Avalos     int min_width = 0, min_height = 0;
5115382d832SPeter Avalos     bool was_autosize = (height == 0 || width == 0);
5125382d832SPeter Avalos     bool show_buttons = FALSE;
5135382d832SPeter Avalos     bool scroll_changed = FALSE;
5145382d832SPeter Avalos     bool field_changed = FALSE;
5155382d832SPeter Avalos     bool non_editable = FALSE;
5165382d832SPeter Avalos     WINDOW *dialog, *form;
5175940c9abSDaniel Fojt     char *prompt;
5185382d832SPeter Avalos     const char **buttons = dlg_ok_labels();
5195382d832SPeter Avalos     DIALOG_FORMITEM *current;
5205382d832SPeter Avalos 
5215940c9abSDaniel Fojt     DLG_TRACE(("# %sform args:\n", (dialog_vars.formitem_type
5225940c9abSDaniel Fojt 				    ? "password"
5235940c9abSDaniel Fojt 				    : "")));
5245940c9abSDaniel Fojt     DLG_TRACE2S("title", title);
5255940c9abSDaniel Fojt     DLG_TRACE2S("message", cprompt);
5265940c9abSDaniel Fojt     DLG_TRACE2N("height", height);
5275940c9abSDaniel Fojt     DLG_TRACE2N("width", width);
5285940c9abSDaniel Fojt     DLG_TRACE2N("lheight", form_height);
5295940c9abSDaniel Fojt     DLG_TRACE2N("llength", item_no);
5305940c9abSDaniel Fojt     /* FIXME dump the items[][] too */
5315940c9abSDaniel Fojt     DLG_TRACE2N("current", *current_item);
5325940c9abSDaniel Fojt 
5335382d832SPeter Avalos     make_FORM_ELTs(items, item_no, &min_height, &min_width);
5345382d832SPeter Avalos     dlg_button_layout(buttons, &min_width);
5355382d832SPeter Avalos     dlg_does_output();
5365382d832SPeter Avalos 
5375382d832SPeter Avalos #ifdef KEY_RESIZE
5385382d832SPeter Avalos   retry:
5395382d832SPeter Avalos #endif
5405382d832SPeter Avalos 
5415940c9abSDaniel Fojt     prompt = dlg_strclone(cprompt);
5425940c9abSDaniel Fojt     dlg_tab_correct_str(prompt);
5435382d832SPeter Avalos     dlg_auto_size(title, prompt, &height, &width,
5445382d832SPeter Avalos 		  1 + 3 * MARGIN,
5455382d832SPeter Avalos 		  MAX(26, 2 + min_width));
5465382d832SPeter Avalos 
5475382d832SPeter Avalos     if (form_height == 0)
5485382d832SPeter Avalos 	form_height = min_height;
5495382d832SPeter Avalos 
5505382d832SPeter Avalos     if (was_autosize) {
5515382d832SPeter Avalos 	form_height = MIN(SLINES - height, form_height);
5525382d832SPeter Avalos 	height += form_height;
5535382d832SPeter Avalos     } else {
5545382d832SPeter Avalos 	int thigh = 0;
5555382d832SPeter Avalos 	int twide = 0;
5565382d832SPeter Avalos 	dlg_auto_size(title, prompt, &thigh, &twide, 0, width);
5575382d832SPeter Avalos 	thigh = SLINES - (height - (thigh + 1 + 3 * MARGIN));
5585382d832SPeter Avalos 	form_height = MIN(thigh, form_height);
5595382d832SPeter Avalos     }
5605382d832SPeter Avalos 
5615382d832SPeter Avalos     dlg_print_size(height, width);
5625382d832SPeter Avalos     dlg_ctl_size(height, width);
5635382d832SPeter Avalos 
5645382d832SPeter Avalos     x = dlg_box_x_ordinate(width);
5655382d832SPeter Avalos     y = dlg_box_y_ordinate(height);
5665382d832SPeter Avalos 
5675382d832SPeter Avalos     dialog = dlg_new_window(height, width, y, x);
5685382d832SPeter Avalos     dlg_register_window(dialog, "formbox", binding);
5695382d832SPeter Avalos     dlg_register_buttons(dialog, "formbox", buttons);
5705382d832SPeter Avalos 
5715382d832SPeter Avalos     dlg_mouse_setbase(x, y);
5725382d832SPeter Avalos 
5735382d832SPeter Avalos     dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
5745382d832SPeter Avalos     dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
5755382d832SPeter Avalos     dlg_draw_title(dialog, title);
5765382d832SPeter Avalos 
5775940c9abSDaniel Fojt     dlg_attrset(dialog, dialog_attr);
5785382d832SPeter Avalos     dlg_print_autowrap(dialog, prompt, height, width);
5795382d832SPeter Avalos 
5805382d832SPeter Avalos     form_width = width - 6;
5815382d832SPeter Avalos     getyx(dialog, cur_y, cur_x);
5825382d832SPeter Avalos     (void) cur_x;
5835382d832SPeter Avalos     box_y = cur_y + 1;
5845382d832SPeter Avalos     box_x = (width - form_width) / 2 - 1;
5855382d832SPeter Avalos 
5865382d832SPeter Avalos     /* create new window for the form */
5875382d832SPeter Avalos     form = dlg_sub_window(dialog, form_height, form_width, y + box_y + 1,
5885382d832SPeter Avalos 			  x + box_x + 1);
5895382d832SPeter Avalos     dlg_register_window(form, "formfield", binding2);
5905382d832SPeter Avalos 
5915382d832SPeter Avalos     /* draw a box around the form items */
5925382d832SPeter Avalos     dlg_draw_box(dialog, box_y, box_x, form_height + 2, form_width + 2,
5935382d832SPeter Avalos 		 menubox_border_attr, menubox_border2_attr);
5945382d832SPeter Avalos 
5955382d832SPeter Avalos     /* register the new window, along with its borders */
5965382d832SPeter Avalos     dlg_mouse_mkbigregion(getbegy(form) - getbegy(dialog),
5975382d832SPeter Avalos 			  getbegx(form) - getbegx(dialog),
5985382d832SPeter Avalos 			  getmaxy(form),
5995382d832SPeter Avalos 			  getmaxx(form),
6005382d832SPeter Avalos 			  KEY_MAX, 1, 1, 3 /* by cells */ );
6015382d832SPeter Avalos 
6025382d832SPeter Avalos     show_buttons = TRUE;
6035382d832SPeter Avalos     scroll_changed = TRUE;
6045382d832SPeter Avalos 
6055382d832SPeter Avalos     choice = set_choice(items, choice, item_no, &non_editable);
6065382d832SPeter Avalos     current = &items[choice];
6075382d832SPeter Avalos     if (non_editable)
6085382d832SPeter Avalos 	state = next_valid_buttonindex(state, sTEXT, non_editable);
6095382d832SPeter Avalos 
6105382d832SPeter Avalos     while (result == DLG_EXIT_UNKNOWN) {
6115382d832SPeter Avalos 	int edit = FALSE;
6125940c9abSDaniel Fojt 	int key;
6135382d832SPeter Avalos 
6145382d832SPeter Avalos 	if (scroll_changed) {
6155382d832SPeter Avalos 	    print_form(form, items, item_no, scrollamt, choice);
6165382d832SPeter Avalos 	    dlg_draw_scrollbar(dialog,
6175382d832SPeter Avalos 			       scrollamt,
6185382d832SPeter Avalos 			       scrollamt,
6195382d832SPeter Avalos 			       scrollamt + form_height + 1,
6205382d832SPeter Avalos 			       min_height,
6215382d832SPeter Avalos 			       box_x + 1,
6225382d832SPeter Avalos 			       box_x + form_width,
6235382d832SPeter Avalos 			       box_y,
6245382d832SPeter Avalos 			       box_y + form_height + 1,
6255382d832SPeter Avalos 			       menubox_border2_attr,
6265382d832SPeter Avalos 			       menubox_border_attr);
6275382d832SPeter Avalos 	    scroll_changed = FALSE;
6285382d832SPeter Avalos 	}
6295382d832SPeter Avalos 
6305382d832SPeter Avalos 	if (show_buttons) {
6315382d832SPeter Avalos 	    dlg_item_help("");
6325382d832SPeter Avalos 	    dlg_draw_buttons(dialog, height - 2, 0, buttons,
6335382d832SPeter Avalos 			     ((state < 0)
6345382d832SPeter Avalos 			      ? 1000	/* no such button, not highlighted */
6355382d832SPeter Avalos 			      : state),
6365382d832SPeter Avalos 			     FALSE, width);
6375382d832SPeter Avalos 	    show_buttons = FALSE;
6385382d832SPeter Avalos 	}
6395382d832SPeter Avalos 
6405382d832SPeter Avalos 	if (first_trace) {
6415382d832SPeter Avalos 	    first_trace = FALSE;
6425382d832SPeter Avalos 	    dlg_trace_win(dialog);
6435382d832SPeter Avalos 	}
6445382d832SPeter Avalos 
6455382d832SPeter Avalos 	if (field_changed || state == sTEXT) {
6465382d832SPeter Avalos 	    if (field_changed)
6475382d832SPeter Avalos 		chr_offset = 0;
6485382d832SPeter Avalos 	    current = &items[choice];
6495382d832SPeter Avalos 	    dlg_item_help(current->help);
6505382d832SPeter Avalos 	    dlg_show_string(form, current->text, chr_offset,
6515382d832SPeter Avalos 			    form_active_text_attr,
6525382d832SPeter Avalos 			    current->text_y - scrollamt,
6535382d832SPeter Avalos 			    current->text_x,
6545382d832SPeter Avalos 			    current->text_len,
6555382d832SPeter Avalos 			    is_hidden(current), first);
6565382d832SPeter Avalos 	    wsyncup(form);
6575382d832SPeter Avalos 	    wcursyncup(form);
6585382d832SPeter Avalos 	    field_changed = FALSE;
6595382d832SPeter Avalos 	}
6605382d832SPeter Avalos 
6615382d832SPeter Avalos 	key = dlg_mouse_wgetch((state == sTEXT) ? form : dialog, &fkey);
6625940c9abSDaniel Fojt 	if (dlg_result_key(key, fkey, &result)) {
6635382d832SPeter Avalos 	    break;
6645940c9abSDaniel Fojt 	}
6655382d832SPeter Avalos 
6665382d832SPeter Avalos 	/* handle non-functionkeys */
6675382d832SPeter Avalos 	if (!fkey) {
6685382d832SPeter Avalos 	    if (state != sTEXT) {
6695382d832SPeter Avalos 		code = dlg_char_to_button(key, buttons);
6705382d832SPeter Avalos 		if (code >= 0) {
6715382d832SPeter Avalos 		    dlg_del_window(dialog);
6725382d832SPeter Avalos 		    result = dlg_ok_buttoncode(code);
6735382d832SPeter Avalos 		    continue;
6745382d832SPeter Avalos 		}
6755382d832SPeter Avalos 	    }
6765382d832SPeter Avalos 	}
6775382d832SPeter Avalos 
6785382d832SPeter Avalos 	/* handle functionkeys */
6795382d832SPeter Avalos 	if (fkey) {
6805382d832SPeter Avalos 	    bool do_scroll = FALSE;
6815382d832SPeter Avalos 	    bool do_tab = FALSE;
6825382d832SPeter Avalos 	    int move_by = 0;
6835382d832SPeter Avalos 
6845382d832SPeter Avalos 	    switch (key) {
6855382d832SPeter Avalos 	    case DLGK_MOUSE(KEY_PPAGE):
6865382d832SPeter Avalos 	    case DLGK_PAGE_PREV:
6875382d832SPeter Avalos 		do_scroll = TRUE;
6885382d832SPeter Avalos 		move_by = -form_height;
6895382d832SPeter Avalos 		break;
6905382d832SPeter Avalos 
6915382d832SPeter Avalos 	    case DLGK_MOUSE(KEY_NPAGE):
6925382d832SPeter Avalos 	    case DLGK_PAGE_NEXT:
6935382d832SPeter Avalos 		do_scroll = TRUE;
6945382d832SPeter Avalos 		move_by = form_height;
6955382d832SPeter Avalos 		break;
6965382d832SPeter Avalos 
6975940c9abSDaniel Fojt 	    case DLGK_TOGGLE:
6985382d832SPeter Avalos 	    case DLGK_ENTER:
6995382d832SPeter Avalos 		dlg_del_window(dialog);
7005382d832SPeter Avalos 		result = (state >= 0) ? dlg_enter_buttoncode(state) : DLG_EXIT_OK;
7015382d832SPeter Avalos 		continue;
702*a8e38dc0SAntonio Huete Jimenez 	    case DLGK_LEAVE:
703*a8e38dc0SAntonio Huete Jimenez 		if (state >= 0)
704*a8e38dc0SAntonio Huete Jimenez 		    result = dlg_ok_buttoncode(state);
705*a8e38dc0SAntonio Huete Jimenez 		break;
7065382d832SPeter Avalos 
7075382d832SPeter Avalos 	    case DLGK_GRID_LEFT:
7085382d832SPeter Avalos 		if (state == sTEXT)
7095382d832SPeter Avalos 		    break;
7105382d832SPeter Avalos 		/* FALLTHRU */
7115382d832SPeter Avalos 	    case DLGK_ITEM_PREV:
7125382d832SPeter Avalos 		if (state == sTEXT) {
7135382d832SPeter Avalos 		    do_tab = TRUE;
7145382d832SPeter Avalos 		    move_by = -1;
7155382d832SPeter Avalos 		    break;
7165382d832SPeter Avalos 		} else {
7175382d832SPeter Avalos 		    state = prev_valid_buttonindex(state, 0, non_editable);
7185382d832SPeter Avalos 		    show_buttons = TRUE;
7195382d832SPeter Avalos 		    continue;
7205382d832SPeter Avalos 		}
7215382d832SPeter Avalos 
7225382d832SPeter Avalos 	    case DLGK_FORM_PREV:
7235382d832SPeter Avalos 		if (state == sTEXT && !is_first_field(items, choice)) {
7245382d832SPeter Avalos 		    do_tab = TRUE;
7255382d832SPeter Avalos 		    move_by = -1;
7265382d832SPeter Avalos 		    break;
7275382d832SPeter Avalos 		} else {
7285382d832SPeter Avalos 		    int old_state = state;
7295382d832SPeter Avalos 		    state = prev_valid_buttonindex(state, sTEXT, non_editable);
7305382d832SPeter Avalos 		    show_buttons = TRUE;
7315382d832SPeter Avalos 		    if (old_state >= 0 && state == sTEXT) {
7325382d832SPeter Avalos 			new_choice = item_no - 1;
7335382d832SPeter Avalos 			if (choice != new_choice) {
7345382d832SPeter Avalos 			    print_item(form, items + choice, scrollamt, FALSE);
7355382d832SPeter Avalos 			    choice = new_choice;
7365382d832SPeter Avalos 			}
7375382d832SPeter Avalos 		    }
7385382d832SPeter Avalos 		    continue;
7395382d832SPeter Avalos 		}
7405382d832SPeter Avalos 
7415382d832SPeter Avalos 	    case DLGK_FIELD_PREV:
7425382d832SPeter Avalos 		state = prev_valid_buttonindex(state, sTEXT, non_editable);
7435382d832SPeter Avalos 		show_buttons = TRUE;
7445382d832SPeter Avalos 		continue;
7455382d832SPeter Avalos 
7465382d832SPeter Avalos 	    case DLGK_FIELD_NEXT:
7475382d832SPeter Avalos 		state = next_valid_buttonindex(state, sTEXT, non_editable);
7485382d832SPeter Avalos 		show_buttons = TRUE;
7495382d832SPeter Avalos 		continue;
7505382d832SPeter Avalos 
7515382d832SPeter Avalos 	    case DLGK_GRID_RIGHT:
7525382d832SPeter Avalos 		if (state == sTEXT)
7535382d832SPeter Avalos 		    break;
7545382d832SPeter Avalos 		/* FALLTHRU */
7555382d832SPeter Avalos 
7565382d832SPeter Avalos 	    case DLGK_ITEM_NEXT:
7575382d832SPeter Avalos 		if (state == sTEXT) {
7585382d832SPeter Avalos 		    do_tab = TRUE;
7595382d832SPeter Avalos 		    move_by = 1;
7605382d832SPeter Avalos 		    break;
7615382d832SPeter Avalos 		} else {
7625382d832SPeter Avalos 		    state = next_valid_buttonindex(state, 0, non_editable);
7635382d832SPeter Avalos 		    show_buttons = TRUE;
7645382d832SPeter Avalos 		    continue;
7655382d832SPeter Avalos 		}
7665382d832SPeter Avalos 
7675382d832SPeter Avalos 	    case DLGK_FORM_NEXT:
7685382d832SPeter Avalos 		if (state == sTEXT && !is_last_field(items, choice, item_no)) {
7695382d832SPeter Avalos 		    do_tab = TRUE;
7705382d832SPeter Avalos 		    move_by = 1;
7715382d832SPeter Avalos 		    break;
7725382d832SPeter Avalos 		} else {
7735382d832SPeter Avalos 		    state = next_valid_buttonindex(state, sTEXT, non_editable);
7745382d832SPeter Avalos 		    show_buttons = TRUE;
7755382d832SPeter Avalos 		    if (state == sTEXT && choice) {
7765382d832SPeter Avalos 			print_item(form, items + choice, scrollamt, FALSE);
7775382d832SPeter Avalos 			choice = 0;
7785382d832SPeter Avalos 		    }
7795382d832SPeter Avalos 		    continue;
7805382d832SPeter Avalos 		}
7815382d832SPeter Avalos 
7825382d832SPeter Avalos #ifdef KEY_RESIZE
7835382d832SPeter Avalos 	    case KEY_RESIZE:
7845940c9abSDaniel Fojt 		dlg_will_resize(dialog);
7855382d832SPeter Avalos 		/* reset data */
7865382d832SPeter Avalos 		height = old_height;
7875382d832SPeter Avalos 		width = old_width;
788*a8e38dc0SAntonio Huete Jimenez 		form_height = old_fhigh;
7895940c9abSDaniel Fojt 		free(prompt);
7905940c9abSDaniel Fojt 		_dlg_resize_cleanup(dialog);
7915940c9abSDaniel Fojt 		dlg_unregister_window(form);
7925382d832SPeter Avalos 		/* repaint */
7935382d832SPeter Avalos 		goto retry;
7945382d832SPeter Avalos #endif
7955382d832SPeter Avalos 	    default:
7965382d832SPeter Avalos #if USE_MOUSE
7975382d832SPeter Avalos 		if (is_DLGK_MOUSE(key)) {
7985382d832SPeter Avalos 		    if (key >= DLGK_MOUSE(KEY_MAX)) {
7995382d832SPeter Avalos 			int cell = key - DLGK_MOUSE(KEY_MAX);
8005382d832SPeter Avalos 			int row = (cell / getmaxx(form)) + scrollamt;
8015382d832SPeter Avalos 			int col = (cell % getmaxx(form));
8025382d832SPeter Avalos 			int n;
8035382d832SPeter Avalos 
8045382d832SPeter Avalos 			for (n = 0; n < item_no; ++n) {
8055382d832SPeter Avalos 			    if (items[n].name_y == row
8065382d832SPeter Avalos 				&& items[n].name_x <= col
8075382d832SPeter Avalos 				&& (items[n].name_x + items[n].name_len > col
8085382d832SPeter Avalos 				    || (items[n].name_y == items[n].text_y
8095382d832SPeter Avalos 					&& items[n].text_x > col))) {
8105382d832SPeter Avalos 				if (!is_readonly(&(items[n]))) {
8115382d832SPeter Avalos 				    field_changed = TRUE;
8125382d832SPeter Avalos 				    break;
8135382d832SPeter Avalos 				}
8145382d832SPeter Avalos 			    }
8155382d832SPeter Avalos 			    if (items[n].text_y == row
8165382d832SPeter Avalos 				&& items[n].text_x <= col
8175382d832SPeter Avalos 				&& items[n].text_x + items[n].text_ilen > col) {
8185382d832SPeter Avalos 				if (!is_readonly(&(items[n]))) {
8195382d832SPeter Avalos 				    field_changed = TRUE;
8205382d832SPeter Avalos 				    break;
8215382d832SPeter Avalos 				}
8225382d832SPeter Avalos 			    }
8235382d832SPeter Avalos 			}
8245382d832SPeter Avalos 			if (field_changed) {
8255382d832SPeter Avalos 			    print_item(form, items + choice, scrollamt, FALSE);
8265382d832SPeter Avalos 			    choice = n;
8275382d832SPeter Avalos 			    continue;
8285382d832SPeter Avalos 			}
8295382d832SPeter Avalos 			beep();
8305382d832SPeter Avalos 		    } else if ((code = dlg_ok_buttoncode(key - M_EVENT)) >= 0) {
8315382d832SPeter Avalos 			result = code;
8325382d832SPeter Avalos 		    }
8335382d832SPeter Avalos 		    continue;
8345382d832SPeter Avalos 		}
8355382d832SPeter Avalos #endif
8365382d832SPeter Avalos 		break;
8375382d832SPeter Avalos 	    }
8385382d832SPeter Avalos 
8395382d832SPeter Avalos 	    new_scroll = scrollamt;
8405382d832SPeter Avalos 	    new_choice = choice;
8415382d832SPeter Avalos 	    if (do_scroll) {
8425382d832SPeter Avalos 		if (scroll_next(form, items, move_by, &new_choice, &new_scroll)) {
8435382d832SPeter Avalos 		    if (choice != new_choice) {
8445382d832SPeter Avalos 			choice = new_choice;
8455382d832SPeter Avalos 			field_changed = TRUE;
8465382d832SPeter Avalos 		    }
8475382d832SPeter Avalos 		    if (scrollamt != new_scroll) {
8485382d832SPeter Avalos 			scrollamt = new_scroll;
8495382d832SPeter Avalos 			scroll_changed = TRUE;
8505382d832SPeter Avalos 		    }
8515382d832SPeter Avalos 		}
8525382d832SPeter Avalos 		continue;
8535382d832SPeter Avalos 	    }
8545382d832SPeter Avalos 	    if (do_tab) {
8555382d832SPeter Avalos 		if (tab_next(form, items, item_no, move_by, &new_choice, &new_scroll)) {
8565382d832SPeter Avalos 		    if (choice != new_choice) {
8575382d832SPeter Avalos 			choice = new_choice;
8585382d832SPeter Avalos 			field_changed = TRUE;
8595382d832SPeter Avalos 		    }
8605382d832SPeter Avalos 		    if (scrollamt != new_scroll) {
8615382d832SPeter Avalos 			scrollamt = new_scroll;
8625382d832SPeter Avalos 			scroll_changed = TRUE;
8635382d832SPeter Avalos 		    }
8645382d832SPeter Avalos 		}
8655382d832SPeter Avalos 		continue;
8665382d832SPeter Avalos 	    }
8675382d832SPeter Avalos 	}
8685382d832SPeter Avalos 
8695382d832SPeter Avalos 	if (state == sTEXT) {	/* Input box selected */
8705382d832SPeter Avalos 	    if (!is_readonly(current))
8715382d832SPeter Avalos 		edit = dlg_edit_string(current->text, &chr_offset, key,
8725382d832SPeter Avalos 				       fkey, first);
8735382d832SPeter Avalos 	    if (edit) {
8745382d832SPeter Avalos 		dlg_show_string(form, current->text, chr_offset,
8755382d832SPeter Avalos 				form_active_text_attr,
8765382d832SPeter Avalos 				current->text_y - scrollamt,
8775382d832SPeter Avalos 				current->text_x,
8785382d832SPeter Avalos 				current->text_len,
8795382d832SPeter Avalos 				is_hidden(current), first);
8805382d832SPeter Avalos 		continue;
8815382d832SPeter Avalos 	    }
8825382d832SPeter Avalos 	}
8835382d832SPeter Avalos 
8845382d832SPeter Avalos     }
8855382d832SPeter Avalos 
8865382d832SPeter Avalos     dlg_mouse_free_regions();
8875940c9abSDaniel Fojt     dlg_unregister_window(form);
8885382d832SPeter Avalos     dlg_del_window(dialog);
8895382d832SPeter Avalos     free(prompt);
8905382d832SPeter Avalos 
8915382d832SPeter Avalos     *current_item = choice;
8925382d832SPeter Avalos     return result;
8935382d832SPeter Avalos }
8945382d832SPeter Avalos 
8955382d832SPeter Avalos /*
8965382d832SPeter Avalos  * Free memory owned by a list of DIALOG_FORMITEM's.
8975382d832SPeter Avalos  */
8985382d832SPeter Avalos void
dlg_free_formitems(DIALOG_FORMITEM * items)8995382d832SPeter Avalos dlg_free_formitems(DIALOG_FORMITEM * items)
9005382d832SPeter Avalos {
9015382d832SPeter Avalos     int n;
9025382d832SPeter Avalos     for (n = 0; items[n].name != 0; ++n) {
9035382d832SPeter Avalos 	if (items[n].name_free)
9045382d832SPeter Avalos 	    free(items[n].name);
9055382d832SPeter Avalos 	if (items[n].text_free)
9065382d832SPeter Avalos 	    free(items[n].text);
9075382d832SPeter Avalos 	if (items[n].help_free && items[n].help != dlg_strempty())
9085382d832SPeter Avalos 	    free(items[n].help);
9095382d832SPeter Avalos     }
9105382d832SPeter Avalos     free(items);
9115382d832SPeter Avalos }
9125382d832SPeter Avalos 
9135382d832SPeter Avalos /*
9145382d832SPeter Avalos  * The script accepts values beginning at 1, while curses starts at 0.
9155382d832SPeter Avalos  */
9165382d832SPeter Avalos int
dlg_ordinate(const char * s)9175382d832SPeter Avalos dlg_ordinate(const char *s)
9185382d832SPeter Avalos {
9195382d832SPeter Avalos     int result = atoi(s);
9205382d832SPeter Avalos     if (result > 0)
9215382d832SPeter Avalos 	--result;
9225382d832SPeter Avalos     else
9235382d832SPeter Avalos 	result = 0;
9245382d832SPeter Avalos     return result;
9255382d832SPeter Avalos }
9265382d832SPeter Avalos 
9275382d832SPeter Avalos int
dialog_form(const char * title,const char * cprompt,int height,int width,int form_height,int item_no,char ** items)9285382d832SPeter Avalos dialog_form(const char *title,
9295382d832SPeter Avalos 	    const char *cprompt,
9305382d832SPeter Avalos 	    int height,
9315382d832SPeter Avalos 	    int width,
9325382d832SPeter Avalos 	    int form_height,
9335382d832SPeter Avalos 	    int item_no,
9345382d832SPeter Avalos 	    char **items)
9355382d832SPeter Avalos {
9365382d832SPeter Avalos     int result;
9375940c9abSDaniel Fojt     int choice = 0;
9385382d832SPeter Avalos     int i;
9395382d832SPeter Avalos     DIALOG_FORMITEM *listitems;
9405382d832SPeter Avalos     DIALOG_VARS save_vars;
9415382d832SPeter Avalos     bool show_status = FALSE;
9421ef6786aSJohn Marino     char *help_result;
9435382d832SPeter Avalos 
9445382d832SPeter Avalos     dlg_save_vars(&save_vars);
9455382d832SPeter Avalos     dialog_vars.separate_output = TRUE;
9465382d832SPeter Avalos 
9475382d832SPeter Avalos     listitems = dlg_calloc(DIALOG_FORMITEM, (size_t) item_no + 1);
9485382d832SPeter Avalos     assert_ptr(listitems, "dialog_form");
9495382d832SPeter Avalos 
9505382d832SPeter Avalos     for (i = 0; i < item_no; ++i) {
9515382d832SPeter Avalos 	listitems[i].type = dialog_vars.formitem_type;
9525382d832SPeter Avalos 	listitems[i].name = ItemName(i);
9535382d832SPeter Avalos 	listitems[i].name_len = (int) strlen(ItemName(i));
9545382d832SPeter Avalos 	listitems[i].name_y = dlg_ordinate(ItemNameY(i));
9555382d832SPeter Avalos 	listitems[i].name_x = dlg_ordinate(ItemNameX(i));
9565382d832SPeter Avalos 	listitems[i].text = ItemText(i);
9575382d832SPeter Avalos 	listitems[i].text_len = (int) strlen(ItemText(i));
9585382d832SPeter Avalos 	listitems[i].text_y = dlg_ordinate(ItemTextY(i));
9595382d832SPeter Avalos 	listitems[i].text_x = dlg_ordinate(ItemTextX(i));
9605382d832SPeter Avalos 	listitems[i].text_flen = atoi(ItemTextFLen(i));
9615382d832SPeter Avalos 	listitems[i].text_ilen = atoi(ItemTextILen(i));
9625382d832SPeter Avalos 	listitems[i].help = ((dialog_vars.item_help)
9635382d832SPeter Avalos 			     ? ItemHelp(i)
9645382d832SPeter Avalos 			     : dlg_strempty());
9655382d832SPeter Avalos     }
9665382d832SPeter Avalos 
9675382d832SPeter Avalos     result = dlg_form(title,
9685382d832SPeter Avalos 		      cprompt,
9695382d832SPeter Avalos 		      height,
9705382d832SPeter Avalos 		      width,
9715382d832SPeter Avalos 		      form_height,
9725382d832SPeter Avalos 		      item_no,
9735382d832SPeter Avalos 		      listitems,
9745382d832SPeter Avalos 		      &choice);
9755382d832SPeter Avalos 
9765382d832SPeter Avalos     switch (result) {
9775382d832SPeter Avalos     case DLG_EXIT_OK:		/* FALLTHRU */
9785382d832SPeter Avalos     case DLG_EXIT_EXTRA:
9795382d832SPeter Avalos 	show_status = TRUE;
9805382d832SPeter Avalos 	break;
9815382d832SPeter Avalos     case DLG_EXIT_HELP:
9821ef6786aSJohn Marino 	dlg_add_help_formitem(&result, &help_result, &listitems[choice]);
9835382d832SPeter Avalos 	show_status = dialog_vars.help_status;
9841ef6786aSJohn Marino 	dlg_add_string(help_result);
9855382d832SPeter Avalos 	if (show_status)
9865382d832SPeter Avalos 	    dlg_add_separator();
9875382d832SPeter Avalos 	break;
9885382d832SPeter Avalos     }
9895382d832SPeter Avalos     if (show_status) {
9905382d832SPeter Avalos 	for (i = 0; i < item_no; i++) {
9915382d832SPeter Avalos 	    if (listitems[i].text_flen > 0) {
9925382d832SPeter Avalos 		dlg_add_string(listitems[i].text);
9935382d832SPeter Avalos 		dlg_add_separator();
9945382d832SPeter Avalos 	    }
9955382d832SPeter Avalos 	}
9961ef6786aSJohn Marino 	dlg_add_last_key(-1);
9975382d832SPeter Avalos     }
9985382d832SPeter Avalos 
9995382d832SPeter Avalos     dlg_free_formitems(listitems);
10005382d832SPeter Avalos     dlg_restore_vars(&save_vars);
10015382d832SPeter Avalos 
10025382d832SPeter Avalos     return result;
10035382d832SPeter Avalos }
1004