2018-12-18 12:13:35 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2009-11-25 10:28:43 +00:00
|
|
|
/*
|
2018-12-18 12:13:35 +00:00
|
|
|
* Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
|
2009-11-25 10:28:43 +00:00
|
|
|
*
|
|
|
|
* Derived from menuconfig.
|
|
|
|
*/
|
2024-08-12 12:48:50 +00:00
|
|
|
#include <xalloc.h>
|
2009-11-25 10:28:43 +00:00
|
|
|
#include "nconf.h"
|
2018-02-08 16:19:07 +00:00
|
|
|
#include "lkc.h"
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2021-04-10 19:45:34 +00:00
|
|
|
int attr_normal;
|
|
|
|
int attr_main_heading;
|
|
|
|
int attr_main_menu_box;
|
|
|
|
int attr_main_menu_fore;
|
|
|
|
int attr_main_menu_back;
|
|
|
|
int attr_main_menu_grey;
|
|
|
|
int attr_main_menu_heading;
|
|
|
|
int attr_scrollwin_text;
|
|
|
|
int attr_scrollwin_heading;
|
|
|
|
int attr_scrollwin_box;
|
|
|
|
int attr_dialog_text;
|
|
|
|
int attr_dialog_menu_fore;
|
|
|
|
int attr_dialog_menu_back;
|
|
|
|
int attr_dialog_box;
|
|
|
|
int attr_input_box;
|
|
|
|
int attr_input_heading;
|
|
|
|
int attr_input_text;
|
|
|
|
int attr_input_field;
|
|
|
|
int attr_function_text;
|
|
|
|
int attr_function_highlight;
|
|
|
|
|
|
|
|
#define COLOR_ATTR(_at, _fg, _bg, _hl) \
|
|
|
|
{ .attr = &(_at), .has_color = true, .color_fg = _fg, .color_bg = _bg, .highlight = _hl }
|
|
|
|
#define NO_COLOR_ATTR(_at, _hl) \
|
|
|
|
{ .attr = &(_at), .has_color = false, .highlight = _hl }
|
|
|
|
#define COLOR_DEFAULT -1
|
|
|
|
|
|
|
|
struct nconf_attr_param {
|
|
|
|
int *attr;
|
|
|
|
bool has_color;
|
|
|
|
int color_fg;
|
|
|
|
int color_bg;
|
|
|
|
int highlight;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct nconf_attr_param color_theme_params[] = {
|
|
|
|
COLOR_ATTR(attr_normal, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_main_heading, COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD | A_UNDERLINE),
|
|
|
|
COLOR_ATTR(attr_main_menu_box, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_main_menu_fore, COLOR_DEFAULT, COLOR_DEFAULT, A_REVERSE),
|
|
|
|
COLOR_ATTR(attr_main_menu_back, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_main_menu_grey, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_main_menu_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD),
|
|
|
|
COLOR_ATTR(attr_scrollwin_text, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_scrollwin_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD),
|
|
|
|
COLOR_ATTR(attr_scrollwin_box, COLOR_YELLOW, COLOR_DEFAULT, A_BOLD),
|
|
|
|
COLOR_ATTR(attr_dialog_text, COLOR_DEFAULT, COLOR_DEFAULT, A_BOLD),
|
|
|
|
COLOR_ATTR(attr_dialog_menu_fore, COLOR_RED, COLOR_DEFAULT, A_STANDOUT),
|
|
|
|
COLOR_ATTR(attr_dialog_menu_back, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_dialog_box, COLOR_YELLOW, COLOR_DEFAULT, A_BOLD),
|
|
|
|
COLOR_ATTR(attr_input_box, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_input_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD),
|
|
|
|
COLOR_ATTR(attr_input_text, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL),
|
|
|
|
COLOR_ATTR(attr_input_field, COLOR_DEFAULT, COLOR_DEFAULT, A_UNDERLINE),
|
|
|
|
COLOR_ATTR(attr_function_text, COLOR_YELLOW, COLOR_DEFAULT, A_REVERSE),
|
|
|
|
COLOR_ATTR(attr_function_highlight, COLOR_DEFAULT, COLOR_DEFAULT, A_BOLD),
|
|
|
|
{ /* sentinel */ }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct nconf_attr_param no_color_theme_params[] = {
|
|
|
|
NO_COLOR_ATTR(attr_normal, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_main_heading, A_BOLD | A_UNDERLINE),
|
|
|
|
NO_COLOR_ATTR(attr_main_menu_box, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_main_menu_fore, A_STANDOUT),
|
|
|
|
NO_COLOR_ATTR(attr_main_menu_back, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_main_menu_grey, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_main_menu_heading, A_BOLD),
|
|
|
|
NO_COLOR_ATTR(attr_scrollwin_text, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_scrollwin_heading, A_BOLD),
|
|
|
|
NO_COLOR_ATTR(attr_scrollwin_box, A_BOLD),
|
|
|
|
NO_COLOR_ATTR(attr_dialog_text, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_dialog_menu_fore, A_STANDOUT),
|
|
|
|
NO_COLOR_ATTR(attr_dialog_menu_back, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_dialog_box, A_BOLD),
|
|
|
|
NO_COLOR_ATTR(attr_input_box, A_BOLD),
|
|
|
|
NO_COLOR_ATTR(attr_input_heading, A_BOLD),
|
|
|
|
NO_COLOR_ATTR(attr_input_text, A_NORMAL),
|
|
|
|
NO_COLOR_ATTR(attr_input_field, A_UNDERLINE),
|
|
|
|
NO_COLOR_ATTR(attr_function_text, A_REVERSE),
|
|
|
|
NO_COLOR_ATTR(attr_function_highlight, A_BOLD),
|
|
|
|
{ /* sentinel */ }
|
|
|
|
};
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2017-05-23 01:44:57 +00:00
|
|
|
void set_colors(void)
|
2009-11-25 10:28:43 +00:00
|
|
|
{
|
2021-04-10 19:45:34 +00:00
|
|
|
const struct nconf_attr_param *p;
|
|
|
|
int pair = 0;
|
|
|
|
|
2009-11-25 10:28:43 +00:00
|
|
|
if (has_colors()) {
|
2021-04-10 19:45:34 +00:00
|
|
|
start_color();
|
|
|
|
use_default_colors();
|
|
|
|
p = color_theme_params;
|
2009-11-25 10:28:43 +00:00
|
|
|
} else {
|
2021-04-10 19:45:34 +00:00
|
|
|
p = no_color_theme_params;
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
|
|
|
|
2021-04-10 19:45:34 +00:00
|
|
|
for (; p->attr; p++) {
|
|
|
|
int attr = p->highlight;
|
|
|
|
|
|
|
|
if (p->has_color) {
|
|
|
|
pair++;
|
|
|
|
init_pair(pair, p->color_fg, p->color_bg);
|
|
|
|
attr |= COLOR_PAIR(pair);
|
|
|
|
}
|
|
|
|
|
|
|
|
*p->attr = attr;
|
|
|
|
}
|
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
/* this changes the windows attributes !!! */
|
kconfig: nconf: refactor in print_in_middle()
This helper is the same as the sample code in the NCURSES HOWTO [1],
but it is over-engineering to be used for nconf.
I do not see any good reason to use the 'float' type just for the
division by 2.
All the call-sites pass a non-NULL pointer to the first argument,
so 'if (win == NULL) win = stdscr;' is dead code.
'if (startx != 0) x = startx;' is dead code because 'x' will be
overridden some lines below, by 'x = startx + (int)temp;'.
All the call-sites pass a non-zero value to the second argument,
so 'if (starty != 0)' is always true.
getyx(win, y, x) is also dead-code because both 'y' and 'x' are
overridden.
All the call-sites pass 0 to the third parameter, so 'startx' can
be removed.
All the call-sites pass a non-zero value to the fourth parameter,
so 'if (width == 0) width = 80;' is dead code.
The window will be refreshed later, so there is no need to call
refresh() in this function.
Change the type of the last parameter from 'chtype' to 'int' to be
aligned with the prototype, 'int wattrset(WINDOW *win, int attrs);'
I also slightly cleaned up the indentation style.
[1]: https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/color.html
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
2021-04-12 01:12:27 +00:00
|
|
|
void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs)
|
|
|
|
{
|
|
|
|
wattrset(win, attrs);
|
|
|
|
mvwprintw(win, y, (width - strlen(str)) / 2, "%s", str);
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int get_line_no(const char *text)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int total = 1;
|
|
|
|
|
|
|
|
if (!text)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; text[i] != '\0'; i++)
|
|
|
|
if (text[i] == '\n')
|
|
|
|
total++;
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_line(const char *text, int line_no)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int lines = 0;
|
|
|
|
|
|
|
|
if (!text)
|
2017-05-23 01:44:57 +00:00
|
|
|
return NULL;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
for (i = 0; text[i] != '\0' && lines < line_no; i++)
|
|
|
|
if (text[i] == '\n')
|
|
|
|
lines++;
|
|
|
|
return text+i;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_line_length(const char *line)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
while (*line != '\0' && *line != '\n') {
|
|
|
|
line++;
|
|
|
|
res++;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print all lines to the window. */
|
|
|
|
void fill_window(WINDOW *win, const char *text)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
int total_lines = get_line_no(text);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
getmaxyx(win, y, x);
|
|
|
|
/* do not go over end of line */
|
|
|
|
total_lines = min(total_lines, y);
|
|
|
|
for (i = 0; i < total_lines; i++) {
|
|
|
|
char tmp[x+10];
|
|
|
|
const char *line = get_line(text, i);
|
|
|
|
int len = get_line_length(line);
|
|
|
|
strncpy(tmp, line, min(len, x));
|
|
|
|
tmp[len] = '\0';
|
2010-07-23 07:04:14 +00:00
|
|
|
mvwprintw(win, i, 0, "%s", tmp);
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the message, and buttons.
|
|
|
|
* each button must be a char*
|
|
|
|
* return the selected button
|
|
|
|
*
|
|
|
|
* this dialog is used for 2 different things:
|
|
|
|
* 1) show a text box, no buttons.
|
|
|
|
* 2) show a dialog, with horizontal buttons
|
|
|
|
*/
|
|
|
|
int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char *btn;
|
|
|
|
int btns_width = 0;
|
|
|
|
int msg_lines = 0;
|
|
|
|
int msg_width = 0;
|
|
|
|
int total_width;
|
|
|
|
int win_rows = 0;
|
|
|
|
WINDOW *win;
|
|
|
|
WINDOW *msg_win;
|
|
|
|
WINDOW *menu_win;
|
|
|
|
MENU *menu;
|
|
|
|
ITEM *btns[btn_num+1];
|
|
|
|
int i, x, y;
|
|
|
|
int res = -1;
|
|
|
|
|
|
|
|
|
|
|
|
va_start(ap, btn_num);
|
|
|
|
for (i = 0; i < btn_num; i++) {
|
|
|
|
btn = va_arg(ap, char *);
|
|
|
|
btns[i] = new_item(btn, "");
|
|
|
|
btns_width += strlen(btn)+1;
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
btns[btn_num] = NULL;
|
|
|
|
|
|
|
|
/* find the widest line of msg: */
|
|
|
|
msg_lines = get_line_no(msg);
|
|
|
|
for (i = 0; i < msg_lines; i++) {
|
|
|
|
const char *line = get_line(msg, i);
|
|
|
|
int len = get_line_length(line);
|
|
|
|
if (msg_width < len)
|
|
|
|
msg_width = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_width = max(msg_width, btns_width);
|
|
|
|
/* place dialog in middle of screen */
|
2013-05-13 09:23:58 +00:00
|
|
|
y = (getmaxy(stdscr)-(msg_lines+4))/2;
|
|
|
|
x = (getmaxx(stdscr)-(total_width+4))/2;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* create the windows */
|
|
|
|
if (btn_num > 0)
|
|
|
|
win_rows = msg_lines+4;
|
|
|
|
else
|
|
|
|
win_rows = msg_lines+2;
|
|
|
|
|
|
|
|
win = newwin(win_rows, total_width+4, y, x);
|
|
|
|
keypad(win, TRUE);
|
|
|
|
menu_win = derwin(win, 1, btns_width, win_rows-2,
|
|
|
|
1+(total_width+2-btns_width)/2);
|
|
|
|
menu = new_menu(btns);
|
|
|
|
msg_win = derwin(win, win_rows-2, msg_width, 1,
|
|
|
|
1+(total_width+2-msg_width)/2);
|
|
|
|
|
2021-04-10 19:45:34 +00:00
|
|
|
set_menu_fore(menu, attr_dialog_menu_fore);
|
|
|
|
set_menu_back(menu, attr_dialog_menu_back);
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(win, attr_dialog_box);
|
2009-11-25 10:28:43 +00:00
|
|
|
box(win, 0, 0);
|
|
|
|
|
|
|
|
/* print message */
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(msg_win, attr_dialog_text);
|
2009-11-25 10:28:43 +00:00
|
|
|
fill_window(msg_win, msg);
|
|
|
|
|
|
|
|
set_menu_win(menu, win);
|
|
|
|
set_menu_sub(menu, menu_win);
|
|
|
|
set_menu_format(menu, 1, btn_num);
|
|
|
|
menu_opts_off(menu, O_SHOWDESC);
|
|
|
|
menu_opts_off(menu, O_SHOWMATCH);
|
|
|
|
menu_opts_on(menu, O_ONEVALUE);
|
|
|
|
menu_opts_on(menu, O_NONCYCLIC);
|
|
|
|
set_menu_mark(menu, "");
|
|
|
|
post_menu(menu);
|
|
|
|
|
|
|
|
|
|
|
|
touchwin(win);
|
|
|
|
refresh_all_windows(main_window);
|
|
|
|
while ((res = wgetch(win))) {
|
|
|
|
switch (res) {
|
|
|
|
case KEY_LEFT:
|
|
|
|
menu_driver(menu, REQ_LEFT_ITEM);
|
|
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
|
|
menu_driver(menu, REQ_RIGHT_ITEM);
|
|
|
|
break;
|
2024-10-14 09:18:28 +00:00
|
|
|
case 9: /* TAB */
|
|
|
|
if (btn_num > 1) {
|
|
|
|
/* cycle through buttons */
|
|
|
|
if (item_index(current_item(menu)) == btn_num - 1)
|
|
|
|
menu_driver(menu, REQ_FIRST_ITEM);
|
|
|
|
else
|
|
|
|
menu_driver(menu, REQ_NEXT_ITEM);
|
|
|
|
}
|
|
|
|
break;
|
2009-11-25 10:28:43 +00:00
|
|
|
case 10: /* ENTER */
|
|
|
|
case 27: /* ESCAPE */
|
|
|
|
case ' ':
|
|
|
|
case KEY_F(F_BACK):
|
|
|
|
case KEY_F(F_EXIT):
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
touchwin(win);
|
|
|
|
refresh_all_windows(main_window);
|
|
|
|
|
|
|
|
if (res == 10 || res == ' ') {
|
|
|
|
res = item_index(current_item(menu));
|
|
|
|
break;
|
|
|
|
} else if (res == 27 || res == KEY_F(F_BACK) ||
|
|
|
|
res == KEY_F(F_EXIT)) {
|
|
|
|
res = KEY_EXIT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unpost_menu(menu);
|
|
|
|
free_menu(menu);
|
|
|
|
for (i = 0; i < btn_num; i++)
|
|
|
|
free_item(btns[i]);
|
|
|
|
|
|
|
|
delwin(win);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dialog_inputbox(WINDOW *main_window,
|
|
|
|
const char *title, const char *prompt,
|
2011-09-01 17:52:20 +00:00
|
|
|
const char *init, char **resultp, int *result_len)
|
2009-11-25 10:28:43 +00:00
|
|
|
{
|
|
|
|
int prompt_lines = 0;
|
|
|
|
int prompt_width = 0;
|
|
|
|
WINDOW *win;
|
|
|
|
WINDOW *prompt_win;
|
|
|
|
WINDOW *form_win;
|
|
|
|
PANEL *panel;
|
2016-11-24 22:10:23 +00:00
|
|
|
int i, x, y, lines, columns, win_lines, win_cols;
|
2009-11-25 10:28:43 +00:00
|
|
|
int res = -1;
|
|
|
|
int cursor_position = strlen(init);
|
2011-09-01 17:52:21 +00:00
|
|
|
int cursor_form_win;
|
2011-09-01 17:52:20 +00:00
|
|
|
char *result = *resultp;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2016-11-24 22:10:23 +00:00
|
|
|
getmaxyx(stdscr, lines, columns);
|
|
|
|
|
2011-09-01 17:52:20 +00:00
|
|
|
if (strlen(init)+1 > *result_len) {
|
|
|
|
*result_len = strlen(init)+1;
|
2018-02-08 16:19:07 +00:00
|
|
|
*resultp = result = xrealloc(result, *result_len);
|
2011-09-01 17:52:20 +00:00
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
/* find the widest line of msg: */
|
|
|
|
prompt_lines = get_line_no(prompt);
|
|
|
|
for (i = 0; i < prompt_lines; i++) {
|
|
|
|
const char *line = get_line(prompt, i);
|
|
|
|
int len = get_line_length(line);
|
|
|
|
prompt_width = max(prompt_width, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (title)
|
|
|
|
prompt_width = max(prompt_width, strlen(title));
|
|
|
|
|
2016-11-24 22:10:23 +00:00
|
|
|
win_lines = min(prompt_lines+6, lines-2);
|
|
|
|
win_cols = min(prompt_width+7, columns-2);
|
|
|
|
prompt_lines = max(win_lines-6, 0);
|
|
|
|
prompt_width = max(win_cols-7, 0);
|
|
|
|
|
2009-11-25 10:28:43 +00:00
|
|
|
/* place dialog in middle of screen */
|
2016-11-24 22:10:23 +00:00
|
|
|
y = (lines-win_lines)/2;
|
|
|
|
x = (columns-win_cols)/2;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2011-09-01 17:52:20 +00:00
|
|
|
strncpy(result, init, *result_len);
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
/* create the windows */
|
2016-11-24 22:10:23 +00:00
|
|
|
win = newwin(win_lines, win_cols, y, x);
|
2009-11-25 10:28:43 +00:00
|
|
|
prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
|
|
|
|
form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
|
|
|
|
keypad(form_win, TRUE);
|
|
|
|
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(form_win, attr_input_field);
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(win, attr_input_box);
|
2009-11-25 10:28:43 +00:00
|
|
|
box(win, 0, 0);
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(win, attr_input_heading);
|
2009-11-25 10:28:43 +00:00
|
|
|
if (title)
|
|
|
|
mvwprintw(win, 0, 3, "%s", title);
|
|
|
|
|
|
|
|
/* print message */
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(prompt_win, attr_input_text);
|
2009-11-25 10:28:43 +00:00
|
|
|
fill_window(prompt_win, prompt);
|
|
|
|
|
|
|
|
mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
|
2011-09-01 17:52:21 +00:00
|
|
|
cursor_form_win = min(cursor_position, prompt_width-1);
|
|
|
|
mvwprintw(form_win, 0, 0, "%s",
|
|
|
|
result + cursor_position-cursor_form_win);
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
/* create panels */
|
|
|
|
panel = new_panel(win);
|
|
|
|
|
|
|
|
/* show the cursor */
|
|
|
|
curs_set(1);
|
|
|
|
|
|
|
|
touchwin(win);
|
|
|
|
refresh_all_windows(main_window);
|
|
|
|
while ((res = wgetch(form_win))) {
|
|
|
|
int len = strlen(result);
|
|
|
|
switch (res) {
|
|
|
|
case 10: /* ENTER */
|
|
|
|
case 27: /* ESCAPE */
|
|
|
|
case KEY_F(F_HELP):
|
|
|
|
case KEY_F(F_EXIT):
|
|
|
|
case KEY_F(F_BACK):
|
|
|
|
break;
|
2019-03-25 15:16:47 +00:00
|
|
|
case 8: /* ^H */
|
|
|
|
case 127: /* ^? */
|
2009-11-25 10:28:43 +00:00
|
|
|
case KEY_BACKSPACE:
|
|
|
|
if (cursor_position > 0) {
|
|
|
|
memmove(&result[cursor_position-1],
|
|
|
|
&result[cursor_position],
|
|
|
|
len-cursor_position+1);
|
|
|
|
cursor_position--;
|
2011-09-01 17:52:21 +00:00
|
|
|
cursor_form_win--;
|
|
|
|
len--;
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_DC:
|
|
|
|
if (cursor_position >= 0 && cursor_position < len) {
|
|
|
|
memmove(&result[cursor_position],
|
|
|
|
&result[cursor_position+1],
|
|
|
|
len-cursor_position+1);
|
2011-09-01 17:52:21 +00:00
|
|
|
len--;
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_UP:
|
|
|
|
case KEY_RIGHT:
|
2011-09-01 17:52:21 +00:00
|
|
|
if (cursor_position < len) {
|
2009-11-25 10:28:43 +00:00
|
|
|
cursor_position++;
|
2011-09-01 17:52:21 +00:00
|
|
|
cursor_form_win++;
|
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
break;
|
|
|
|
case KEY_DOWN:
|
|
|
|
case KEY_LEFT:
|
2011-09-01 17:52:21 +00:00
|
|
|
if (cursor_position > 0) {
|
2009-11-25 10:28:43 +00:00
|
|
|
cursor_position--;
|
2011-09-01 17:52:21 +00:00
|
|
|
cursor_form_win--;
|
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
break;
|
2011-09-01 17:52:22 +00:00
|
|
|
case KEY_HOME:
|
|
|
|
cursor_position = 0;
|
|
|
|
cursor_form_win = 0;
|
|
|
|
break;
|
|
|
|
case KEY_END:
|
|
|
|
cursor_position = len;
|
|
|
|
cursor_form_win = min(cursor_position, prompt_width-1);
|
|
|
|
break;
|
2009-11-25 10:28:43 +00:00
|
|
|
default:
|
2011-09-01 17:52:20 +00:00
|
|
|
if ((isgraph(res) || isspace(res))) {
|
|
|
|
/* one for new char, one for '\0' */
|
|
|
|
if (len+2 > *result_len) {
|
|
|
|
*result_len = len+2;
|
|
|
|
*resultp = result = realloc(result,
|
|
|
|
*result_len);
|
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
/* insert the char at the proper position */
|
|
|
|
memmove(&result[cursor_position+1],
|
|
|
|
&result[cursor_position],
|
2011-09-01 17:52:19 +00:00
|
|
|
len-cursor_position+1);
|
2009-11-25 10:28:43 +00:00
|
|
|
result[cursor_position] = res;
|
|
|
|
cursor_position++;
|
2011-09-01 17:52:21 +00:00
|
|
|
cursor_form_win++;
|
|
|
|
len++;
|
2009-11-25 10:28:43 +00:00
|
|
|
} else {
|
2011-09-01 17:52:18 +00:00
|
|
|
mvprintw(0, 0, "unknown key: %d\n", res);
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2011-09-01 17:52:21 +00:00
|
|
|
if (cursor_form_win < 0)
|
|
|
|
cursor_form_win = 0;
|
|
|
|
else if (cursor_form_win > prompt_width-1)
|
|
|
|
cursor_form_win = prompt_width-1;
|
|
|
|
|
2009-11-25 10:28:43 +00:00
|
|
|
wmove(form_win, 0, 0);
|
|
|
|
wclrtoeol(form_win);
|
|
|
|
mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
|
2011-09-01 17:52:21 +00:00
|
|
|
mvwprintw(form_win, 0, 0, "%s",
|
|
|
|
result + cursor_position-cursor_form_win);
|
|
|
|
wmove(form_win, 0, cursor_form_win);
|
2009-11-25 10:28:43 +00:00
|
|
|
touchwin(win);
|
|
|
|
refresh_all_windows(main_window);
|
|
|
|
|
|
|
|
if (res == 10) {
|
|
|
|
res = 0;
|
|
|
|
break;
|
|
|
|
} else if (res == 27 || res == KEY_F(F_BACK) ||
|
|
|
|
res == KEY_F(F_EXIT)) {
|
|
|
|
res = KEY_EXIT;
|
|
|
|
break;
|
|
|
|
} else if (res == KEY_F(F_HELP)) {
|
|
|
|
res = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* hide the cursor */
|
|
|
|
curs_set(0);
|
|
|
|
del_panel(panel);
|
|
|
|
delwin(prompt_win);
|
|
|
|
delwin(form_win);
|
|
|
|
delwin(win);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* refresh all windows in the correct order */
|
|
|
|
void refresh_all_windows(WINDOW *main_window)
|
|
|
|
{
|
|
|
|
update_panels();
|
|
|
|
touchwin(main_window);
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void show_scroll_win(WINDOW *main_window,
|
|
|
|
const char *title,
|
|
|
|
const char *text)
|
2023-08-09 00:42:20 +00:00
|
|
|
{
|
|
|
|
(void)show_scroll_win_ext(main_window, title, (char *)text, NULL, NULL, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* layman's scrollable window... */
|
|
|
|
int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text,
|
|
|
|
int *vscroll, int *hscroll,
|
|
|
|
extra_key_cb_fn extra_key_cb, void *data)
|
2009-11-25 10:28:43 +00:00
|
|
|
{
|
|
|
|
int res;
|
|
|
|
int total_lines = get_line_no(text);
|
2013-05-13 09:23:58 +00:00
|
|
|
int x, y, lines, columns;
|
2009-11-25 10:28:43 +00:00
|
|
|
int start_x = 0, start_y = 0;
|
|
|
|
int text_lines = 0, text_cols = 0;
|
|
|
|
int total_cols = 0;
|
|
|
|
int win_cols = 0;
|
|
|
|
int win_lines = 0;
|
|
|
|
int i = 0;
|
|
|
|
WINDOW *win;
|
|
|
|
WINDOW *pad;
|
|
|
|
PANEL *panel;
|
2023-08-09 00:42:20 +00:00
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
if (hscroll)
|
|
|
|
start_x = *hscroll;
|
|
|
|
if (vscroll)
|
|
|
|
start_y = *vscroll;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2013-05-13 09:23:58 +00:00
|
|
|
getmaxyx(stdscr, lines, columns);
|
|
|
|
|
2009-11-25 10:28:43 +00:00
|
|
|
/* find the widest line of msg: */
|
|
|
|
total_lines = get_line_no(text);
|
|
|
|
for (i = 0; i < total_lines; i++) {
|
|
|
|
const char *line = get_line(text, i);
|
|
|
|
int len = get_line_length(line);
|
|
|
|
total_cols = max(total_cols, len+2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the pad */
|
|
|
|
pad = newpad(total_lines+10, total_cols+10);
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(pad, attr_scrollwin_text);
|
2009-11-25 10:28:43 +00:00
|
|
|
fill_window(pad, text);
|
|
|
|
|
2013-05-13 09:23:58 +00:00
|
|
|
win_lines = min(total_lines+4, lines-2);
|
|
|
|
win_cols = min(total_cols+2, columns-2);
|
2009-11-25 10:28:43 +00:00
|
|
|
text_lines = max(win_lines-4, 0);
|
|
|
|
text_cols = max(win_cols-2, 0);
|
|
|
|
|
|
|
|
/* place window in middle of screen */
|
2013-05-13 09:23:58 +00:00
|
|
|
y = (lines-win_lines)/2;
|
|
|
|
x = (columns-win_cols)/2;
|
2009-11-25 10:28:43 +00:00
|
|
|
|
|
|
|
win = newwin(win_lines, win_cols, y, x);
|
|
|
|
keypad(win, TRUE);
|
|
|
|
/* show the help in the help window, and show the help panel */
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(win, attr_scrollwin_box);
|
2009-11-25 10:28:43 +00:00
|
|
|
box(win, 0, 0);
|
2021-04-10 19:45:34 +00:00
|
|
|
wattrset(win, attr_scrollwin_heading);
|
2009-11-25 10:28:43 +00:00
|
|
|
mvwprintw(win, 0, 3, " %s ", title);
|
|
|
|
panel = new_panel(win);
|
|
|
|
|
|
|
|
/* handle scrolling */
|
2023-08-09 00:42:20 +00:00
|
|
|
while (!done) {
|
2009-11-25 10:28:43 +00:00
|
|
|
copywin(pad, win, start_y, start_x, 2, 2, text_lines,
|
|
|
|
text_cols, 0);
|
|
|
|
print_in_middle(win,
|
|
|
|
text_lines+2,
|
|
|
|
text_cols,
|
|
|
|
"<OK>",
|
2021-04-10 19:45:34 +00:00
|
|
|
attr_dialog_menu_fore);
|
2009-11-25 10:28:43 +00:00
|
|
|
wrefresh(win);
|
|
|
|
|
|
|
|
res = wgetch(win);
|
|
|
|
switch (res) {
|
|
|
|
case KEY_NPAGE:
|
|
|
|
case ' ':
|
2012-07-24 20:12:03 +00:00
|
|
|
case 'd':
|
2009-11-25 10:28:43 +00:00
|
|
|
start_y += text_lines-2;
|
|
|
|
break;
|
|
|
|
case KEY_PPAGE:
|
2012-07-24 20:12:03 +00:00
|
|
|
case 'u':
|
2009-11-25 10:28:43 +00:00
|
|
|
start_y -= text_lines+2;
|
|
|
|
break;
|
|
|
|
case KEY_HOME:
|
|
|
|
start_y = 0;
|
|
|
|
break;
|
|
|
|
case KEY_END:
|
|
|
|
start_y = total_lines-text_lines;
|
|
|
|
break;
|
|
|
|
case KEY_DOWN:
|
|
|
|
case 'j':
|
|
|
|
start_y++;
|
|
|
|
break;
|
|
|
|
case KEY_UP:
|
|
|
|
case 'k':
|
|
|
|
start_y--;
|
|
|
|
break;
|
|
|
|
case KEY_LEFT:
|
|
|
|
case 'h':
|
|
|
|
start_x--;
|
|
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
|
|
case 'l':
|
|
|
|
start_x++;
|
|
|
|
break;
|
2023-08-09 00:42:20 +00:00
|
|
|
default:
|
|
|
|
if (extra_key_cb) {
|
|
|
|
size_t start = (get_line(text, start_y) - text);
|
|
|
|
size_t end = (get_line(text, start_y + text_lines) - text);
|
|
|
|
|
|
|
|
if (extra_key_cb(res, start, end, data)) {
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|
2023-08-09 00:42:20 +00:00
|
|
|
if (res == 0 || res == 10 || res == 27 || res == 'q' ||
|
2012-07-24 20:12:03 +00:00
|
|
|
res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
|
|
|
|
res == KEY_F(F_EXIT))
|
2009-11-25 10:28:43 +00:00
|
|
|
break;
|
|
|
|
if (start_y < 0)
|
|
|
|
start_y = 0;
|
|
|
|
if (start_y >= total_lines-text_lines)
|
|
|
|
start_y = total_lines-text_lines;
|
|
|
|
if (start_x < 0)
|
|
|
|
start_x = 0;
|
|
|
|
if (start_x >= total_cols-text_cols)
|
|
|
|
start_x = total_cols-text_cols;
|
2023-08-09 00:42:20 +00:00
|
|
|
}
|
2009-11-25 10:28:43 +00:00
|
|
|
|
2023-08-09 00:42:20 +00:00
|
|
|
if (hscroll)
|
|
|
|
*hscroll = start_x;
|
|
|
|
if (vscroll)
|
|
|
|
*vscroll = start_y;
|
2009-11-25 10:28:43 +00:00
|
|
|
del_panel(panel);
|
|
|
|
delwin(win);
|
|
|
|
refresh_all_windows(main_window);
|
2023-08-09 00:42:20 +00:00
|
|
|
return res;
|
2009-11-25 10:28:43 +00:00
|
|
|
}
|