kconfig/lxdialog: support resize

In all dialogs now properly catch KEY_RESIZE and take proper action.
In mconf try to behave sensibly when a dialog routine returns
-ERRDISPLAYTOOSMALL.

The original check for a screnn size of 80x19 is kept for now.
It may make sense to remove it later, but thats anyway what
much text is adjusted for.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
index 39becb7..cf69708 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -125,6 +125,12 @@
 		}
 	}
 
+do_resize:
+	if (getmaxy(stdscr) < (height + 6))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 6))
+		return -ERRDISPLAYTOOSMALL;
+
 	max_choice = MIN(list_height, item_count());
 
 	/* center dialog box on screen */
@@ -303,6 +309,11 @@
 		case KEY_ESC:
 			key = on_key_esc(dialog);
 			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 
 		/* Now, update everything... */
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index a7cfdec..8dea47f 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -86,6 +86,9 @@
 #define ACS_DARROW 'v'
 #endif
 
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
 /*
  *   Color definitions
  */
@@ -181,6 +184,7 @@
 
 /* generic key handlers */
 int on_key_esc(WINDOW *win);
+int on_key_resize(void);
 
 void init_dialog(const char *backtitle);
 void reset_dialog(void);
@@ -199,8 +203,8 @@
 int dialog_msgbox(const char *title, const char *prompt, int height,
 		  int width, int pause);
 int dialog_textbox(const char *title, const char *file, int height, int width);
-int dialog_menu(const char *title, const char *prompt, int height, int width,
-		int menu_height, const void *selected, int *s_scroll);
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll);
 int dialog_checklist(const char *title, const char *prompt, int height,
 		     int width, int list_height);
 extern char dialog_input_result[];
diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
index edb7975..05e7206 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -49,6 +49,17 @@
 	char *instr = dialog_input_result;
 	WINDOW *dialog;
 
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (getmaxy(stdscr) <= (height - 2))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) <= (width - 2))
+		return -ERRDISPLAYTOOSMALL;
+
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	y = (LINES - height) / 2;
@@ -86,11 +97,6 @@
 	wmove(dialog, box_y, box_x);
 	wattrset(dialog, dlg.inputbox.atr);
 
-	if (!init)
-		instr[0] = '\0';
-	else
-		strcpy(instr, init);
-
 	input_x = strlen(instr);
 
 	if (input_x >= box_width) {
@@ -220,6 +226,10 @@
 		case KEY_ESC:
 			key = on_key_esc(dialog);
 			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 	}
 
diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
index d3305ba..fcd95a9 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -179,14 +179,25 @@
 /*
  * Display a menu for choosing among a number of options
  */
-int dialog_menu(const char *title, const char *prompt, int height, int width,
-                int menu_height, const void *selected, int *s_scroll)
+int dialog_menu(const char *title, const char *prompt,
+                const void *selected, int *s_scroll)
 {
 	int i, j, x, y, box_x, box_y;
+	int height, width, menu_height;
 	int key = 0, button = 0, scroll = 0, choice = 0;
 	int first_item =  0, max_choice;
 	WINDOW *dialog, *menu;
 
+do_resize:
+	height = getmaxy(stdscr);
+	width = getmaxx(stdscr);
+	if (height < 15 || width < 65)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 10;
+
 	max_choice = MIN(menu_height, item_count());
 
 	/* center dialog box on screen */
@@ -226,7 +237,10 @@
 	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
 		 dlg.menubox_border.atr, dlg.menubox.atr);
 
-	item_x = (menu_width - 70) / 2;
+	if (menu_width >= 80)
+		item_x = (menu_width - 70) / 2;
+	else
+		item_x = 4;
 
 	/* Set choice to default item */
 	item_foreach()
@@ -407,6 +421,11 @@
 		case KEY_ESC:
 			key = on_key_esc(menu);
 			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
 		}
 	}
 	delwin(menu);
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index a99e1f4..fabfc1a 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -25,7 +25,7 @@
 static void print_page(WINDOW * win, int height, int width);
 static void print_line(WINDOW * win, int row, int width);
 static char *get_line(void);
-static void print_position(WINDOW * win, int height, int width);
+static void print_position(WINDOW * win);
 
 static int hscroll;
 static int begin_reached, end_reached, page_length;
@@ -33,14 +33,28 @@
 static const char *page;
 
 /*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+							  int cur_y, int cur_x)
+{
+	print_page(box, boxh, boxw);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
+
+
+/*
  * Display text from a file in a dialog box.
  */
-int dialog_textbox(const char *title, const char *tbuf, int height, int width)
+int dialog_textbox(const char *title, const char *tbuf,
+		   int initial_height, int initial_width)
 {
 	int i, x, y, cur_x, cur_y, key = 0;
-	int texth, textw;
+	int height, width, boxh, boxw;
 	int passed_end;
-	WINDOW *dialog, *text;
+	WINDOW *dialog, *box;
 
 	begin_reached = 1;
 	end_reached = 0;
@@ -49,6 +63,25 @@
 	buf = tbuf;
 	page = buf;	/* page is pointer to start of page to be displayed */
 
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < 8 || width < 8)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
+
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	y = (LINES - height) / 2;
@@ -58,14 +91,14 @@
 	dialog = newwin(height, width, y, x);
 	keypad(dialog, TRUE);
 
-	/* Create window for text region, used for scrolling text */
-	texth = height - 4;
-	textw = width - 2;
-	text = subwin(dialog, texth, textw, y + 1, x + 1);
-	wattrset(text, dlg.dialog.atr);
-	wbkgdset(text, dlg.dialog.atr & A_COLOR);
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
 
-	keypad(text, TRUE);
+	keypad(box, TRUE);
 
 	/* register the new window, along with its borders */
 	draw_box(dialog, 0, 0, height, width,
@@ -86,11 +119,8 @@
 	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
 
 	/* Print first page of text */
-	attr_clear(text, texth, textw, dlg.dialog.atr);
-	print_page(text, texth, textw);
-	print_position(dialog, height, width);
-	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-	wrefresh(dialog);
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
 
 	while ((key != KEY_ESC) && (key != '\n')) {
 		key = wgetch(dialog);
@@ -99,7 +129,7 @@
 		case 'e':
 		case 'X':
 		case 'x':
-			delwin(text);
+			delwin(box);
 			delwin(dialog);
 			return 0;
 		case 'g':	/* First page */
@@ -107,10 +137,8 @@
 			if (!begin_reached) {
 				begin_reached = 1;
 				page = buf;
-				print_page(text, texth, textw);
-				print_position(dialog, height, width);
-				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-				wrefresh(dialog);
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x);
 			}
 			break;
 		case 'G':	/* Last page */
@@ -119,11 +147,9 @@
 			end_reached = 1;
 			/* point to last char in buf */
 			page = buf + strlen(buf);
-			back_lines(texth);
-			print_page(text, texth, textw);
-			print_position(dialog, height, width);
-			wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-			wrefresh(dialog);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
 			break;
 		case 'K':	/* Previous line */
 		case 'k':
@@ -138,16 +164,16 @@
 				 * point to start of next page. This is done
 				 * by calling get_line() in the following
 				 * 'for' loop. */
-				scrollok(text, TRUE);
-				wscrl(text, -1);	/* Scroll text region down one line */
-				scrollok(text, FALSE);
+				scrollok(box, TRUE);
+				wscrl(box, -1);	/* Scroll box region down one line */
+				scrollok(box, FALSE);
 				page_length = 0;
 				passed_end = 0;
-				for (i = 0; i < texth; i++) {
+				for (i = 0; i < boxh; i++) {
 					if (!i) {
 						/* print first line of page */
-						print_line(text, 0, textw);
-						wnoutrefresh(text);
+						print_line(box, 0, boxw);
+						wnoutrefresh(box);
 					} else
 						/* Called to update 'end_reached' and 'page' */
 						get_line();
@@ -157,7 +183,7 @@
 						passed_end = 1;
 				}
 
-				print_position(dialog, height, width);
+				print_position(dialog);
 				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
 				wrefresh(dialog);
 			}
@@ -167,23 +193,21 @@
 		case KEY_PPAGE:
 			if (begin_reached)
 				break;
-			back_lines(page_length + texth);
-			print_page(text, texth, textw);
-			print_position(dialog, height, width);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
 			break;
 		case 'J':	/* Next line */
 		case 'j':
 		case KEY_DOWN:
 			if (!end_reached) {
 				begin_reached = 0;
-				scrollok(text, TRUE);
-				scroll(text);	/* Scroll text region up one line */
-				scrollok(text, FALSE);
-				print_line(text, texth - 1, textw);
-				wnoutrefresh(text);
-				print_position(dialog, height, width);
+				scrollok(box, TRUE);
+				scroll(box);	/* Scroll box region up one line */
+				scrollok(box, FALSE);
+				print_line(box, boxh - 1, boxw);
+				wnoutrefresh(box);
+				print_position(dialog);
 				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
 				wrefresh(dialog);
 			}
@@ -194,10 +218,8 @@
 				break;
 
 			begin_reached = 0;
-			print_page(text, texth, textw);
-			print_position(dialog, height, width);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
 			break;
 		case '0':	/* Beginning of line */
 		case 'H':	/* Scroll left */
@@ -212,9 +234,8 @@
 				hscroll--;
 			/* Reprint current page to scroll horizontally */
 			back_lines(page_length);
-			print_page(text, texth, textw);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
 			break;
 		case 'L':	/* Scroll right */
 		case 'l':
@@ -224,16 +245,21 @@
 			hscroll++;
 			/* Reprint current page to scroll horizontally */
 			back_lines(page_length);
-			print_page(text, texth, textw);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			refresh_text_box(dialog, box, boxh, boxw,
+					 cur_y, cur_x);
 			break;
 		case KEY_ESC:
 			key = on_key_esc(dialog);
 			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 	}
-	delwin(text);
+	delwin(box);
 	delwin(dialog);
 	return key;		/* ESC pressed */
 }
@@ -353,13 +379,13 @@
 /*
  * Print current position
  */
-static void print_position(WINDOW * win, int height, int width)
+static void print_position(WINDOW * win)
 {
 	int percent;
 
 	wattrset(win, dlg.position_indicator.atr);
 	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
 	percent = (page - buf) * 100 / strlen(buf);
-	wmove(win, height - 3, width - 9);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
 	wprintw(win, "(%3d%%)", percent);
 }
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index cb21dc4..ebc781b 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -509,6 +509,12 @@
 	return -1;
 }
 
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
 
 struct dialog_list *item_cur;
 struct dialog_list item_nil;
diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c
index 8364f9d..ee0a04e 100644
--- a/scripts/kconfig/lxdialog/yesno.c
+++ b/scripts/kconfig/lxdialog/yesno.c
@@ -44,6 +44,12 @@
 	int i, x, y, key = 0, button = 0;
 	WINDOW *dialog;
 
+do_resize:
+	if (getmaxy(stdscr) < (height + 4))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 4))
+		return -ERRDISPLAYTOOSMALL;
+
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	y = (LINES - height) / 2;
@@ -96,6 +102,10 @@
 		case KEY_ESC:
 			key = on_key_esc(dialog);
 			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 	}
 
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index ef75d6c..f7abca4 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -606,9 +606,8 @@
 		reset_dialog();
 		res = dialog_menu(prompt ? prompt : _("Main Menu"),
 				  _(menu_instructions),
-				  rows, cols, rows - 10,
 				  active_menu, &s_scroll);
-		if (res == 1 || res == KEY_ESC)
+		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 			break;
 		if (!item_activate_selected())
 			continue;
@@ -617,7 +616,10 @@
 
 		submenu = item_data();
 		active_menu = item_data();
-		sym = submenu->sym;
+		if (submenu)
+			sym = submenu->sym;
+		else
+			sym = NULL;
 
 		switch (res) {
 		case 0:
@@ -683,7 +685,7 @@
 static void show_textbox(const char *title, const char *text, int r, int c)
 {
 	reset_dialog();
-	dialog_textbox(title, text, r ? r : rows, c ? c : cols);
+	dialog_textbox(title, text, r, c);
 }
 
 static void show_helptext(const char *title, const char *text)
@@ -756,6 +758,8 @@
 			break;
 		case KEY_ESC:
 			return;
+		case -ERRDISPLAYTOOSMALL:
+			return;
 		}
 	}
 }