2503 lines
86 KiB
C
2503 lines
86 KiB
C
/* bfu.c
|
|
* (c) 2002 Mikulas Patocka
|
|
* This file is a part of the Links program, released under GPL.
|
|
*/
|
|
|
|
#include "links.h"
|
|
|
|
static void menu_func(struct window *, struct links_event *, int);
|
|
static void mainmenu_func(struct window *, struct links_event *, int);
|
|
|
|
struct memory_list *getml(void *p, ...)
|
|
{
|
|
struct memory_list *ml;
|
|
va_list ap;
|
|
int n = 0;
|
|
void *q = p;
|
|
va_start(ap, p);
|
|
while (q) {
|
|
if (n == MAXINT) overalloc();
|
|
n++, q = va_arg(ap, void *);
|
|
}
|
|
if ((unsigned)n > (MAXINT - sizeof(struct memory_list)) / sizeof(void *)) overalloc();
|
|
ml = mem_alloc(sizeof(struct memory_list) + n * sizeof(void *));
|
|
ml->n = n;
|
|
n = 0;
|
|
q = p;
|
|
va_end(ap);
|
|
va_start(ap, p);
|
|
while (q) ml->p[n++] = q, q = va_arg(ap, void *);
|
|
va_end(ap);
|
|
return ml;
|
|
}
|
|
|
|
void add_to_ml(struct memory_list **ml, ...)
|
|
{
|
|
struct memory_list *nml;
|
|
va_list ap;
|
|
int n = 0;
|
|
void *q;
|
|
if (!*ml) {
|
|
*ml = mem_alloc(sizeof(struct memory_list));
|
|
(*ml)->n = 0;
|
|
}
|
|
va_start(ap, ml);
|
|
while ((q = va_arg(ap, void *))) {
|
|
if (n == MAXINT) overalloc();
|
|
n++;
|
|
}
|
|
if ((unsigned)n + (unsigned)((*ml)->n) > (MAXINT - sizeof(struct memory_list)) / sizeof(void *)) overalloc();
|
|
nml = mem_realloc(*ml, sizeof(struct memory_list) + (n + (*ml)->n) * sizeof(void *));
|
|
va_end(ap);
|
|
va_start(ap, ml);
|
|
while ((q = va_arg(ap, void *))) nml->p[nml->n++] = q;
|
|
*ml = nml;
|
|
va_end(ap);
|
|
}
|
|
|
|
void freeml(struct memory_list *ml)
|
|
{
|
|
int i;
|
|
if (!ml) return;
|
|
for (i = 0; i < ml->n; i++) mem_free(ml->p[i]);
|
|
mem_free(ml);
|
|
}
|
|
|
|
static inline int is_utf_8(struct terminal *term)
|
|
{
|
|
#ifdef G
|
|
if (F) return 1;
|
|
#endif
|
|
#ifdef ENABLE_UTF8
|
|
if (term_charset(term) == utf8_table) return 1;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static inline int ttxtlen(struct terminal *term, unsigned char *s)
|
|
{
|
|
#ifdef ENABLE_UTF8
|
|
if (term_charset(term) == utf8_table)
|
|
return strlen_utf8(s);
|
|
#endif
|
|
return (int)strlen(cast_const_char s);
|
|
}
|
|
|
|
static inline int txtlen(struct terminal *term, unsigned char *s)
|
|
{
|
|
#ifdef G
|
|
if (F)
|
|
return g_text_width(bfu_style_wb, s);
|
|
else
|
|
#endif
|
|
return ttxtlen(term, s);
|
|
}
|
|
|
|
#ifdef G
|
|
struct style *bfu_style_wb, *bfu_style_wb_b, *bfu_style_bw, *bfu_style_bw_u;
|
|
struct style *bfu_style_bw_mono;
|
|
struct style *bfu_style_wb_mono, *bfu_style_wb_mono_u;
|
|
|
|
long bfu_fg_color, bfu_bg_color;
|
|
|
|
void init_bfu(void)
|
|
{
|
|
if (!F) return;
|
|
bfu_bg_color = dip_get_color_sRGB(G_BFU_BG_COLOR);
|
|
bfu_fg_color = dip_get_color_sRGB(G_BFU_FG_COLOR);
|
|
bfu_style_wb = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, 0);
|
|
bfu_style_wb_b = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, 0);
|
|
bfu_style_bw = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, 0);
|
|
bfu_style_bw_u = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, FF_UNDERLINE);
|
|
bfu_style_bw_mono = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, FF_MONOSPACED);
|
|
bfu_style_wb_mono = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, FF_MONOSPACED);
|
|
bfu_style_wb_mono_u = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, FF_UNDERLINE | FF_MONOSPACED);
|
|
}
|
|
|
|
#define G_DIALOG_FIELD_WIDTH g_char_width(bfu_style_wb_mono, ' ')
|
|
|
|
void shutdown_bfu(void)
|
|
{
|
|
if (!F) return;
|
|
g_free_style(bfu_style_wb);
|
|
g_free_style(bfu_style_wb_b);
|
|
g_free_style(bfu_style_bw);
|
|
g_free_style(bfu_style_bw_u);
|
|
g_free_style(bfu_style_bw_mono);
|
|
g_free_style(bfu_style_wb_mono);
|
|
g_free_style(bfu_style_wb_mono_u);
|
|
}
|
|
|
|
#else
|
|
|
|
void init_bfu(void) {}
|
|
void shutdown_bfu(void) {}
|
|
|
|
#endif
|
|
|
|
unsigned char m_bar = 0;
|
|
|
|
static unsigned select_hotkey(struct terminal *term, unsigned char *text, unsigned char *hotkey, unsigned *hotkeys, int n)
|
|
{
|
|
unsigned c;
|
|
if (hotkey == M_BAR) return 0;
|
|
if (text) {
|
|
text = stracpy(get_text_translation(text, term));
|
|
charset_upcase_string(&text, term_charset(term));
|
|
}
|
|
hotkey = get_text_translation(hotkey, term);
|
|
while (1) {
|
|
int i;
|
|
c = GET_TERM_CHAR(term, &hotkey);
|
|
if (!c) break;
|
|
c = charset_upcase(c, term_charset(term));
|
|
for (i = 0; i < n; i++) if (hotkeys[i] == c) goto cont;
|
|
if (!text || cp_strchr(term_charset(term), text, c)) break;
|
|
cont:;
|
|
}
|
|
if (text) mem_free(text);
|
|
return c;
|
|
}
|
|
|
|
void do_menu_selected(struct terminal *term, struct menu_item *items, void *data, int selected, void (*free_function)(void *), void *free_data)
|
|
{
|
|
int i;
|
|
struct menu *menu;
|
|
for (i = 0; items[i].text; i++) if (i == (MAXINT - sizeof(struct menu)) / sizeof(unsigned)) overalloc();
|
|
menu = mem_alloc(sizeof(struct menu) + (!i ? 0 : i - 1) * sizeof(unsigned));
|
|
menu->selected = selected;
|
|
menu->view = 0;
|
|
menu->ni = i;
|
|
menu->items = items;
|
|
menu->data = data;
|
|
menu->free_function = free_function;
|
|
menu->free_data = free_data;
|
|
for (i = 0; i < menu->ni; i++)
|
|
menu->hotkeys[i] = select_hotkey(term, !term->spec->braille ? items[i].text : NULL, items[i].hotkey, menu->hotkeys, i);
|
|
#ifdef G
|
|
if (F) {
|
|
if ((unsigned)menu->ni > MAXINT / sizeof(unsigned char *)) overalloc();
|
|
menu->hktxt1 = mem_calloc(menu->ni * sizeof(unsigned char *));
|
|
menu->hktxt2 = mem_calloc(menu->ni * sizeof(unsigned char *));
|
|
menu->hktxt3 = mem_calloc(menu->ni * sizeof(unsigned char *));
|
|
for (i = 0; i < menu->ni; i++) {
|
|
unsigned char *txt = get_text_translation(items[i].text, term);
|
|
unsigned char *txt2, *txt3 = txt;
|
|
if (items[i].hotkey != M_BAR) while (*txt3) {
|
|
unsigned u;
|
|
txt2 = txt3;
|
|
GET_UTF_8(txt3, u);
|
|
u = uni_upcase(u);
|
|
if (u == menu->hotkeys[i]) {
|
|
menu->hktxt1[i] = memacpy(txt, txt2 - txt);
|
|
menu->hktxt2[i] = memacpy(txt2, txt3 - txt2);
|
|
menu->hktxt3[i] = stracpy(txt3);
|
|
goto x;
|
|
}
|
|
}
|
|
menu->hktxt1[i] = stracpy(txt);
|
|
menu->hktxt2[i] = stracpy(cast_uchar "");
|
|
menu->hktxt3[i] = stracpy(cast_uchar "");
|
|
x:;
|
|
}
|
|
}
|
|
#endif
|
|
add_window(term, menu_func, menu);
|
|
}
|
|
|
|
void do_menu(struct terminal *term, struct menu_item *items, void *data)
|
|
{
|
|
do_menu_selected(term, items, data, 0, NULL, NULL);
|
|
}
|
|
|
|
static void select_menu(struct terminal *term, struct menu *menu)
|
|
{
|
|
struct menu_item *it;
|
|
void (*func)(struct terminal *, void *, void *);
|
|
void *data1;
|
|
void *data2;
|
|
if (menu->selected < 0 || menu->selected >= menu->ni) return;
|
|
it = &menu->items[menu->selected];
|
|
func = it->func;
|
|
data1 = it->data;
|
|
data2 = menu->data;
|
|
if (it->hotkey == M_BAR) return;
|
|
flush_terminal(term);
|
|
if (!it->in_m) {
|
|
struct window *win;
|
|
struct list_head *lwin;
|
|
foreach(struct window, win, lwin, term->windows) {
|
|
if (win->handler != menu_func && win->handler != mainmenu_func)
|
|
break;
|
|
lwin = lwin->prev;
|
|
delete_window(win);
|
|
}
|
|
}
|
|
func(term, data1, data2);
|
|
}
|
|
|
|
static unsigned char *get_rtext(unsigned char *rtext)
|
|
{
|
|
if (!strcmp(cast_const_char rtext, ">")) return MENU_SUBMENU;
|
|
return rtext;
|
|
}
|
|
|
|
static void count_menu_size(struct terminal *term, struct menu *menu)
|
|
{
|
|
int sx = term->x;
|
|
int sy = term->y;
|
|
int mx = gf_val(4, 2 * (G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER));
|
|
int my;
|
|
for (my = 0; my < menu->ni; my++) {
|
|
int s;
|
|
#ifdef G
|
|
if (menu->items[my].free_i & MENU_FONT_LIST) {
|
|
struct style *st = g_get_style_font(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE,
|
|
(menu->items[my].free_i & MENU_FONT_LIST_BOLD ? FF_BOLD : 0) |
|
|
(menu->items[my].free_i & MENU_FONT_LIST_MONO ? FF_MONOSPACED : 0),
|
|
menu->items[my].data);
|
|
s = g_text_width(st, menu->items[my].text);
|
|
g_free_style(st);
|
|
} else
|
|
#endif
|
|
s = txtlen(term, get_text_translation(menu->items[my].text, term)) + txtlen(term, get_text_translation(get_rtext(menu->items[my].rtext), term)) + gf_val(MENU_HOTKEY_SPACE, G_MENU_HOTKEY_SPACE) * (get_text_translation(get_rtext(menu->items[my].rtext), term)[0] != 0);
|
|
s += gf_val(4, 2 * (G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER));
|
|
if (s > mx) mx = s;
|
|
}
|
|
my = gf_val(my, my * G_BFU_FONT_SIZE);
|
|
my += gf_val(2, 2 * G_MENU_TOP_BORDER);
|
|
if (mx > sx) mx = sx;
|
|
if (my > sy) my = sy;
|
|
#ifdef G
|
|
if (F) {
|
|
my -= 2 * G_MENU_TOP_BORDER;
|
|
my -= my % G_BFU_FONT_SIZE;
|
|
my += 2 * G_MENU_TOP_BORDER;
|
|
}
|
|
#endif
|
|
menu->nview = gf_val(my - 2, (my - 2 * G_MENU_TOP_BORDER) / G_BFU_FONT_SIZE);
|
|
menu->xw = mx;
|
|
menu->yw = my;
|
|
if ((menu->x = menu->xp) < 0) menu->x = 0;
|
|
if ((menu->y = menu->yp) < 0) menu->y = 0;
|
|
if (menu->x + mx > sx) menu->x = sx - mx;
|
|
if (menu->y + my > sy) menu->y = sy - my;
|
|
if (term->spec->braille) {
|
|
menu->x = -1;
|
|
menu->y = -1;
|
|
menu->xw = term->x + 2;
|
|
menu->yw = term->y + 2;
|
|
menu->nview = term->y;
|
|
}
|
|
#ifdef G
|
|
if (F) set_window_pos(menu->win, menu->x, menu->y, menu->x + menu->xw, menu->y + menu->yw);
|
|
#endif
|
|
}
|
|
|
|
static void scroll_menu(struct menu *menu, int d)
|
|
{
|
|
int c = 0;
|
|
int w = menu->nview;
|
|
int scr_i = SCROLL_ITEMS > (w-1)/2 ? (w-1)/2 : SCROLL_ITEMS;
|
|
if (scr_i < 0) scr_i = 0;
|
|
if (w < 0) w = 0;
|
|
menu->selected += d;
|
|
while (1) {
|
|
if (c++ > menu->ni) {
|
|
menu->selected = -1;
|
|
menu->view = 0;
|
|
return;
|
|
}
|
|
if (menu->selected < 0) menu->selected = 0;
|
|
if (menu->selected >= menu->ni) menu->selected = menu->ni - 1;
|
|
if (menu->ni && menu->items[menu->selected].hotkey != M_BAR) break;
|
|
menu->selected += d;
|
|
}
|
|
if (menu->selected < menu->view + scr_i) menu->view = menu->selected - scr_i;
|
|
if (menu->selected >= menu->view + w - scr_i - 1) menu->view = menu->selected - w + scr_i + 1;
|
|
if (menu->view > menu->ni - w) menu->view = menu->ni - w;
|
|
if (menu->view < 0) menu->view = 0;
|
|
}
|
|
|
|
static void display_menu_txt(struct terminal *term, void *menu_)
|
|
{
|
|
struct menu *menu = (struct menu *)menu_;
|
|
int p, s;
|
|
int setc = 0;
|
|
fill_area(term, menu->x+1, menu->y+1, menu->xw-2, menu->yw-2, ' ', COLOR_MENU_TEXT);
|
|
draw_frame(term, menu->x, menu->y, menu->xw, menu->yw, COLOR_MENU_FRAME, 1);
|
|
set_window_ptr(menu->win, menu->x, menu->y);
|
|
for (p = menu->view, s = menu->y + 1; p < menu->ni && p < menu->view + menu->yw - 2; p++, s++) {
|
|
int x;
|
|
int h = 0;
|
|
unsigned c;
|
|
unsigned char *tmptext = get_text_translation(menu->items[p].text, term);
|
|
unsigned char co = p == menu->selected ? h = 1, COLOR_MENU_SELECTED : COLOR_MENU_TEXT;
|
|
if (h) {
|
|
setc = 1;
|
|
set_cursor(term, menu->x + 1 + !!term->spec->braille, s, term->x - 1, term->y - 1);
|
|
/*set_window_ptr(menu->win, menu->x+3, s+1);*/
|
|
set_window_ptr(menu->win, menu->x+menu->xw, s);
|
|
fill_area(term, menu->x+1, s, menu->xw-2, 1, ' ', co);
|
|
}
|
|
if (term->spec->braille) h = 1;
|
|
if (menu->items[p].hotkey != M_BAR || (tmptext[0])) {
|
|
unsigned char *rt = get_text_translation(get_rtext(menu->items[p].rtext), term);
|
|
int l = ttxtlen(term, rt);
|
|
for (x = 0;; x++) {
|
|
c = GET_TERM_CHAR(term, &rt);
|
|
if (!c) break;
|
|
if (!term->spec->braille) {
|
|
if (menu->xw - 4 >= l - x)
|
|
set_char(term, menu->x + menu->xw - 2 - l + x, s, c, co);
|
|
} else {
|
|
set_char(term, menu->x + ttxtlen(term, tmptext) + 4 + x + 2, s, c, COLOR_MENU_HOTKEY);
|
|
}
|
|
}
|
|
for (x = 0; x < menu->xw - 4; x++) {
|
|
c = GET_TERM_CHAR(term, &tmptext);
|
|
if (!c) break;
|
|
set_char(term, menu->x + x + 2 + 2 * !!term->spec->braille, s, c, !h && charset_upcase(c, term_charset(term)) == menu->hotkeys[p] ? h = 1, COLOR_MENU_HOTKEY : co);
|
|
}
|
|
if (term->spec->braille && menu->hotkeys[p]) {
|
|
set_char(term, menu->x + 2, s, menu->hotkeys[p], COLOR_MENU_HOTKEY);
|
|
}
|
|
} else {
|
|
set_char(term, menu->x, s, 0xc3, COLOR_MENU_FRAME | ATTR_FRAME);
|
|
fill_area(term, menu->x+1, s, menu->xw-2, 1, 0xc4, COLOR_MENU_FRAME | ATTR_FRAME);
|
|
set_char(term, menu->x+menu->xw-1, s, 0xb4, COLOR_MENU_FRAME | ATTR_FRAME);
|
|
}
|
|
}
|
|
if (!setc && term->spec->braille) {
|
|
set_cursor(term, menu->x + 1, menu->y + 1, term->x - 1, term->y - 1);
|
|
}
|
|
}
|
|
|
|
static int menu_oldview = -1;
|
|
static int menu_oldsel = -1;
|
|
|
|
#ifdef G
|
|
|
|
static int menu_ptr_set;
|
|
|
|
static void display_menu_item_gfx(struct terminal *term, struct menu *menu, int it)
|
|
{
|
|
struct menu_item *item = &menu->items[it];
|
|
struct graphics_device *dev = term->dev;
|
|
int y;
|
|
if (it < menu->view || it >= menu->ni || it >= menu->view + menu->nview) return;
|
|
y = menu->y + G_MENU_TOP_BORDER + (it - menu->view) * G_BFU_FONT_SIZE;
|
|
if (item->hotkey == M_BAR && !get_text_translation(item->text, term)[0]) {
|
|
drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + (G_BFU_FONT_SIZE - 1) / 2, bfu_bg_color);
|
|
drv->draw_hline(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y + (G_BFU_FONT_SIZE - 1) / 2, menu->x + menu->xw - G_MENU_LEFT_BORDER / 2, bfu_fg_color);
|
|
drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y + (G_BFU_FONT_SIZE - 1) / 2 + 1, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
|
|
} else {
|
|
int p;
|
|
struct rect r;
|
|
unsigned char *rtext = get_text_translation(get_rtext(item->rtext), term);
|
|
if (it != menu->selected) {
|
|
drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y, menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER, y + G_BFU_FONT_SIZE, bfu_bg_color);
|
|
} else {
|
|
menu->xl1 = menu->x;
|
|
menu->yl1 = y;
|
|
menu->xl2 = menu->x + menu->xw;
|
|
menu->yl2 = y + G_BFU_FONT_SIZE;
|
|
menu_ptr_set = 1;
|
|
set_window_ptr(menu->win, menu->x + menu->xw, y);
|
|
drv->fill_area(dev, menu->x + (G_MENU_LEFT_BORDER - 1) / 2 + 1, y, menu->x + G_MENU_LEFT_BORDER, y + G_BFU_FONT_SIZE, bfu_bg_color);
|
|
drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
|
|
drv->fill_area(dev, menu->x + G_MENU_LEFT_BORDER, y, menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER, y + G_BFU_FONT_SIZE, bfu_fg_color);
|
|
}
|
|
restrict_clip_area(dev, &r, menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y + G_BFU_FONT_SIZE);
|
|
if (it == menu->selected) {
|
|
struct style *style_wb;
|
|
if (menu->items[it].free_i & MENU_FONT_LIST) {
|
|
style_wb = g_get_style_font(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE,
|
|
(menu->items[it].free_i & MENU_FONT_LIST_BOLD ? FF_BOLD : 0) |
|
|
(menu->items[it].free_i & MENU_FONT_LIST_MONO ? FF_MONOSPACED : 0),
|
|
menu->items[it].data);
|
|
} else {
|
|
style_wb = bfu_style_wb;
|
|
}
|
|
p = menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER;
|
|
g_print_text(dev, p, y, style_wb, menu->hktxt1[it], &p);
|
|
g_print_text(dev, p, y, style_wb, menu->hktxt2[it], &p);
|
|
g_print_text(dev, p, y, style_wb, menu->hktxt3[it], &p);
|
|
if (menu->items[it].free_i & MENU_FONT_LIST) {
|
|
g_free_style(style_wb);
|
|
}
|
|
} else {
|
|
struct style *style_bw, *style_bw_u;
|
|
if (menu->items[it].free_i & MENU_FONT_LIST) {
|
|
style_bw = style_bw_u = g_get_style_font(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE,
|
|
(menu->items[it].free_i & MENU_FONT_LIST_BOLD ? FF_BOLD : 0) |
|
|
(menu->items[it].free_i & MENU_FONT_LIST_MONO ? FF_MONOSPACED : 0),
|
|
menu->items[it].data);
|
|
} else {
|
|
style_bw = bfu_style_bw;
|
|
style_bw_u = bfu_style_bw_u;
|
|
}
|
|
p = menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER;
|
|
g_print_text(dev, p, y, style_bw, menu->hktxt1[it], &p);
|
|
g_print_text(dev, p, y, style_bw_u, menu->hktxt2[it], &p);
|
|
g_print_text(dev, p, y, style_bw, menu->hktxt3[it], &p);
|
|
if (menu->items[it].free_i & MENU_FONT_LIST) {
|
|
g_free_style(style_bw);
|
|
}
|
|
}
|
|
if (!*rtext) {
|
|
set_clip_area(dev, &r);
|
|
if (p > menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER) p = menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER;
|
|
if (it != menu->selected)
|
|
drv->fill_area(dev, p, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
|
|
else
|
|
drv->fill_area(dev, p, y, menu->x + menu->xw - G_MENU_LEFT_BORDER, y + G_BFU_FONT_SIZE, bfu_fg_color);
|
|
} else {
|
|
int s = menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER - g_text_width(bfu_style_wb, rtext);
|
|
if (s < p) s = p;
|
|
drv->fill_area(dev, p, y, s, y + G_BFU_FONT_SIZE, it != menu->selected ? bfu_bg_color : bfu_fg_color);
|
|
g_print_text(dev, s, y, it != menu->selected ? bfu_style_bw : bfu_style_wb, rtext, NULL);
|
|
set_clip_area(dev, &r);
|
|
if (it != menu->selected)
|
|
drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
|
|
else
|
|
drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - G_MENU_LEFT_BORDER, y + G_BFU_FONT_SIZE, bfu_fg_color);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void display_menu_gfx(struct terminal *term, void *menu_)
|
|
{
|
|
struct menu *menu = (struct menu *)menu_;
|
|
int p;
|
|
struct graphics_device *dev = term->dev;
|
|
if (menu_oldview == menu->view) {
|
|
if (menu_oldsel >= 0 && menu_oldsel < menu->ni && menu_oldsel < menu->view + menu->nview) display_menu_item_gfx(term, menu, menu_oldsel);
|
|
if (menu->selected >= 0 && menu->selected < menu->ni && menu->selected < menu->view + menu->nview) display_menu_item_gfx(term, menu, menu->selected);
|
|
return;
|
|
}
|
|
#define PX1 (menu->x + (G_MENU_LEFT_BORDER - 1) / 2)
|
|
#define PX2 (menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2)
|
|
#define PY1 (menu->y + (G_MENU_TOP_BORDER - 1) / 2)
|
|
#define PY2 (menu->y + menu->yw - (G_MENU_TOP_BORDER + 1) / 2)
|
|
drv->fill_area(dev, menu->x, menu->y, menu->x + menu->xw, PY1, bfu_bg_color);
|
|
drv->fill_area(dev, menu->x, PY1, PX1, PY2 + 1, bfu_bg_color);
|
|
drv->fill_area(dev, PX2 + 1, PY1, menu->x + menu->xw, PY2 + 1, bfu_bg_color);
|
|
drv->fill_area(dev, menu->x, PY2 + 1, menu->x + menu->xw, menu->y + menu->yw, bfu_bg_color);
|
|
drv->draw_hline(dev, PX1, PY1, PX2 + 1, bfu_fg_color);
|
|
drv->draw_hline(dev, PX1, PY2, PX2 + 1, bfu_fg_color);
|
|
drv->draw_vline(dev, PX1, PY1 + 1, PY2, bfu_fg_color);
|
|
drv->draw_vline(dev, PX2, PY1 + 1, PY2, bfu_fg_color);
|
|
drv->fill_area(dev, PX1 + 1, PY1 + 1, PX2, menu->y + G_MENU_TOP_BORDER, bfu_bg_color);
|
|
drv->fill_area(dev, PX1 + 1, menu->y + menu->yw - G_MENU_TOP_BORDER, PX2, PY2, bfu_bg_color);
|
|
menu->xl1 = menu->yl1 = menu->xl2 = menu->yl2 = 0;
|
|
menu_ptr_set = 0;
|
|
for (p = menu->view; p < menu->ni && p < menu->view + menu->nview; p++) display_menu_item_gfx(term, menu, p);
|
|
if (!menu_ptr_set) set_window_ptr(menu->win, menu->x, menu->y);
|
|
}
|
|
|
|
#endif
|
|
|
|
static void menu_func(struct window *win, struct links_event *ev, int fwd)
|
|
{
|
|
int s = 0;
|
|
int xp, yp;
|
|
struct menu *menu = win->data;
|
|
menu->win = win;
|
|
switch ((int)ev->ev) {
|
|
case EV_INIT:
|
|
case EV_RESIZE:
|
|
get_parent_ptr(win, &menu->xp, &menu->yp);
|
|
count_menu_size(win->term, menu);
|
|
goto xxx;
|
|
case EV_REDRAW:
|
|
get_parent_ptr(win, &xp, &yp);
|
|
if (xp != menu->xp || yp != menu->yp) {
|
|
menu->xp = xp;
|
|
menu->yp = yp;
|
|
count_menu_size(win->term, menu);
|
|
}
|
|
xxx:
|
|
menu->selected--;
|
|
scroll_menu(menu, 1);
|
|
draw_to_window(win, gf_val(display_menu_txt, display_menu_gfx), menu);
|
|
break;
|
|
case EV_MOUSE:
|
|
if ((ev->b & BM_ACT) == B_MOVE) break;
|
|
if ((ev->b & BM_BUTT) == B_FOURTH ||
|
|
(ev->b & BM_BUTT) == B_FIFTH) {
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto go_lr;
|
|
break;
|
|
}
|
|
if ((ev->b & BM_BUTT) == B_SIXTH) {
|
|
break;
|
|
}
|
|
if (ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y || ev->y >= menu->y+menu->yw) {
|
|
int f = 1;
|
|
struct window *w1;
|
|
struct list_head *w1l;
|
|
foreachfrom(struct window, w1, w1l, win->term->windows, &win->list_entry) {
|
|
struct menu *m1;
|
|
if (w1->handler == mainmenu_func) {
|
|
#ifdef G
|
|
struct mainmenu *m2 = w1->data;
|
|
if (F && !f && ev->x >= m2->xl1 && ev->x < m2->xl2 && ev->y >= m2->yl1 && ev->y < m2->yl2) goto bbb;
|
|
#endif
|
|
if (ev->y < LL) goto del;
|
|
break;
|
|
}
|
|
if (w1->handler != menu_func) break;
|
|
m1 = w1->data;
|
|
#ifdef G
|
|
if (F && !f && ev->x >= m1->xl1 && ev->x < m1->xl2 && ev->y >= m1->yl1 && ev->y < m1->yl2) goto bbb;
|
|
#endif
|
|
if (ev->x > m1->x && ev->x < m1->x+m1->xw-1 && ev->y > m1->y && ev->y < m1->y+m1->yw-1) goto del;
|
|
f--;
|
|
}
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto del;
|
|
if (0) del:delete_window_ev(win, ev);
|
|
#ifdef G
|
|
bbb:;
|
|
#endif
|
|
} else {
|
|
if (!(ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y + gf_val(1, G_MENU_TOP_BORDER) || ev->y >= menu->y + menu->yw - gf_val(1, G_MENU_TOP_BORDER))) {
|
|
int s = gf_val(ev->y - menu->y-1 + menu->view, (ev->y - menu->y - G_MENU_TOP_BORDER) / G_BFU_FONT_SIZE + menu->view);
|
|
if (s >= 0 && s < menu->ni && menu->items[s].hotkey != M_BAR) {
|
|
menu_oldview = menu->view;
|
|
menu_oldsel = menu->selected;
|
|
menu->selected = s;
|
|
scroll_menu(menu, 0);
|
|
draw_to_window(win, gf_val(display_menu_txt, display_menu_gfx), menu);
|
|
menu_oldview = menu_oldsel = -1;
|
|
if ((ev->b & BM_ACT) == B_UP /*|| menu->items[s].in_m*/) select_menu(win->term, menu);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EV_KBD:
|
|
if (ev->y & KBD_PASTING) break;
|
|
if (ev->x == KBD_LEFT || ev->x == KBD_RIGHT) {
|
|
go_lr:
|
|
if (win->list_entry.next == &win->term->windows)
|
|
goto mm;
|
|
if (list_struct(win->list_entry.next, struct window)->handler == mainmenu_func)
|
|
goto mm;
|
|
if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_FIFTH) goto mm;
|
|
if (ev->ev == EV_KBD && ev->x == KBD_RIGHT) goto enter;
|
|
delete_window(win);
|
|
break;
|
|
}
|
|
if (ev->x == KBD_ESC) {
|
|
if (win->list_entry.next == &win->term->windows)
|
|
ev = NULL;
|
|
else if (list_struct(win->list_entry.next, struct window)->handler != mainmenu_func)
|
|
ev = NULL;
|
|
delete_window_ev(win, ev);
|
|
break;
|
|
}
|
|
if (KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT) {
|
|
mm:
|
|
delete_window_ev(win, ev);
|
|
break;
|
|
}
|
|
menu_oldview = menu->view;
|
|
menu_oldsel = menu->selected;
|
|
if (ev->x == KBD_UP) scroll_menu(menu, -1);
|
|
else if (ev->x == KBD_DOWN) scroll_menu(menu, 1);
|
|
else if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) menu->selected = -1, scroll_menu(menu, 1);
|
|
else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) menu->selected = menu->ni, scroll_menu(menu, -1);
|
|
else if (ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
|
|
if ((menu->selected -= menu->yw / LL - 3) < -1) menu->selected = -1;
|
|
if ((menu->view -= menu->yw / LL - 2) < 0) menu->view = 0;
|
|
scroll_menu(menu, -1);
|
|
}
|
|
else if (ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) {
|
|
if ((menu->selected += menu->yw / LL - 3) > menu->ni) menu->selected = menu->ni;
|
|
if ((menu->view += menu->yw / LL - 2) >= menu->ni - menu->yw + 2) menu->view = menu->ni - menu->yw + 2;
|
|
scroll_menu(menu, 1);
|
|
}
|
|
else if (ev->x > ' ') {
|
|
int i;
|
|
for (i = 0; i < menu->ni; i++) {
|
|
if (charset_upcase(ev->x, term_charset(win->term)) == menu->hotkeys[i]) {
|
|
menu->selected = i;
|
|
scroll_menu(menu, 0);
|
|
s = 1;
|
|
}
|
|
}
|
|
}
|
|
draw_to_window(win, gf_val(display_menu_txt, display_menu_gfx), menu);
|
|
if (s || ev->x == KBD_ENTER || ev->x == ' ') {
|
|
enter:
|
|
menu_oldview = menu_oldsel = -1;
|
|
select_menu(win->term, menu);
|
|
}
|
|
menu_oldview = menu_oldsel = -1;
|
|
break;
|
|
case EV_ABORT:
|
|
#ifdef G
|
|
if (F) {
|
|
int i;
|
|
for (i = 0; i < menu->ni; i++) {
|
|
mem_free(menu->hktxt1[i]);
|
|
mem_free(menu->hktxt2[i]);
|
|
mem_free(menu->hktxt3[i]);
|
|
}
|
|
mem_free(menu->hktxt1);
|
|
mem_free(menu->hktxt2);
|
|
mem_free(menu->hktxt3);
|
|
}
|
|
#endif
|
|
if (menu->items->free_i) {
|
|
int i;
|
|
for (i = 0; i < menu->ni; i++) {
|
|
if (menu->items[i].free_i & MENU_FREE_TEXT) mem_free(menu->items[i].text);
|
|
if (menu->items[i].free_i & MENU_FREE_RTEXT) mem_free(menu->items[i].rtext);
|
|
if (menu->items[i].free_i & MENU_FREE_HOTKEY) mem_free(menu->items[i].hotkey);
|
|
}
|
|
if (menu->items->free_i & MENU_FREE_ITEMS)
|
|
mem_free(menu->items);
|
|
}
|
|
if (menu->free_function)
|
|
register_bottom_half(menu->free_function, menu->free_data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void do_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel)
|
|
{
|
|
int i;
|
|
struct mainmenu *menu;
|
|
for (i = 0; items[i].text; i++) if (i == (MAXINT - sizeof(struct mainmenu)) / sizeof(unsigned)) overalloc();
|
|
menu = mem_alloc(sizeof(struct mainmenu) + (!i ? 0 : i - 1) * sizeof(unsigned));
|
|
menu->selected = sel == -1 ? 0 : sel;
|
|
menu->ni = i;
|
|
menu->items = items;
|
|
menu->data = data;
|
|
for (i = 0; i < menu->ni; i++)
|
|
menu->hotkeys[i] = select_hotkey(term, NULL, items[i].hotkey, menu->hotkeys, i);
|
|
add_window(term, mainmenu_func, menu);
|
|
if (sel != -1) {
|
|
/* icc_volatile is workaround for some weird bug in icc or linker,
|
|
it results in unaligned sse load */
|
|
icc_volatile struct links_event ev = {EV_KBD, KBD_ENTER, 0, 0};
|
|
struct window *win = list_struct(term->windows.next, struct window);
|
|
win->handler(win, (struct links_event *)&ev, 0);
|
|
}
|
|
}
|
|
|
|
static void display_mainmenu(struct terminal *term, void *menu_)
|
|
{
|
|
struct mainmenu *menu = (struct mainmenu *)menu_;
|
|
if (!F) {
|
|
int i;
|
|
int p = 2;
|
|
fill_area(term, 0, 0, term->x, 1, ' ', COLOR_MAINMENU);
|
|
for (i = 0; i < menu->ni; i++) {
|
|
int s = 0;
|
|
unsigned c;
|
|
unsigned char *tmptext = get_text_translation(menu->items[i].text, term);
|
|
unsigned char co = i == menu->selected ? s = 1, COLOR_MAINMENU_SELECTED : COLOR_MAINMENU;
|
|
if (i == menu->selected) {
|
|
fill_area(term, p, 0, 2, 1, ' ', co);
|
|
menu->sp = p;
|
|
set_cursor(term, p, 0, term->x - 1, term->y - 1);
|
|
set_window_ptr(menu->win, p, 1);
|
|
}
|
|
if (term->spec->braille) {
|
|
s = 1;
|
|
if (menu->hotkeys[i]) set_char(term, p, 0, menu->hotkeys[i], COLOR_MAINMENU_HOTKEY);
|
|
}
|
|
p += 2;
|
|
for (;; p++) {
|
|
c = GET_TERM_CHAR(term, &tmptext);
|
|
if (!c) break;
|
|
set_char(term, p, 0, c, !s && charset_upcase(c, term_charset(term)) == menu->hotkeys[i] ? s = 1, COLOR_MAINMENU_HOTKEY : co);
|
|
}
|
|
if (i == menu->selected) {
|
|
fill_area(term, p, 0, 2, 1, ' ', co);
|
|
}
|
|
p += 2;
|
|
}
|
|
#ifdef G
|
|
} else {
|
|
struct graphics_device *dev = term->dev;
|
|
int i, p;
|
|
drv->fill_area(dev, 0, 0, p = G_MAINMENU_LEFT_BORDER, G_BFU_FONT_SIZE, bfu_bg_color);
|
|
for (i = 0; i < menu->ni; i++) {
|
|
int s = i == menu->selected;
|
|
unsigned char *text = get_text_translation(menu->items[i].text, term);
|
|
if (s) {
|
|
menu->xl1 = p;
|
|
menu->yl1 = 0;
|
|
set_window_ptr(menu->win, p, G_BFU_FONT_SIZE);
|
|
}
|
|
drv->fill_area(dev, p, 0, p + G_MAINMENU_BORDER, G_BFU_FONT_SIZE, s ? bfu_fg_color : bfu_bg_color);
|
|
p += G_MAINMENU_BORDER;
|
|
g_print_text(dev, p, 0, s ? bfu_style_wb : bfu_style_bw, text, &p);
|
|
drv->fill_area(dev, p, 0, p + G_MAINMENU_BORDER, G_BFU_FONT_SIZE, s ? bfu_fg_color : bfu_bg_color);
|
|
p += G_MAINMENU_BORDER;
|
|
if (s) {
|
|
menu->xl2 = p;
|
|
menu->yl2 = G_BFU_FONT_SIZE;
|
|
}
|
|
}
|
|
drv->fill_area(dev, p, 0, term->x, G_BFU_FONT_SIZE, bfu_bg_color);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void select_mainmenu(struct terminal *term, struct mainmenu *menu)
|
|
{
|
|
struct menu_item *it;
|
|
if (menu->selected < 0 || menu->selected >= menu->ni) return;
|
|
it = &menu->items[menu->selected];
|
|
if (it->hotkey == M_BAR) return;
|
|
if (!it->in_m) {
|
|
struct window *win;
|
|
struct list_head *lwin;
|
|
foreach(struct window, win, lwin, term->windows) {
|
|
if (win->handler != menu_func && win->handler != mainmenu_func)
|
|
break;
|
|
lwin = lwin->prev;
|
|
delete_window(win);
|
|
}
|
|
}
|
|
it->func(term, it->data, menu->data);
|
|
}
|
|
|
|
static void mainmenu_func(struct window *win, struct links_event *ev, int fwd)
|
|
{
|
|
int s = 0;
|
|
int in_menu;
|
|
struct mainmenu *menu = win->data;
|
|
menu->win = win;
|
|
switch ((int)ev->ev) {
|
|
case EV_INIT:
|
|
case EV_RESIZE:
|
|
#ifdef G
|
|
if (F) set_window_pos(win, 0, 0, win->term->x, G_BFU_FONT_SIZE);
|
|
#endif
|
|
/*-fallthrough*/
|
|
case EV_REDRAW:
|
|
draw_to_window(win, display_mainmenu, menu);
|
|
break;
|
|
case EV_MOUSE:
|
|
in_menu = ev->x >= 0 && ev->x < win->term->x && ev->y >= 0 && ev->y < LL;
|
|
if ((ev->b & BM_ACT) == B_MOVE) break;
|
|
if ((ev->b & BM_BUTT) == B_FOURTH) {
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto go_left;
|
|
break;
|
|
}
|
|
if ((ev->b & BM_BUTT) == B_FIFTH) {
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto go_right;
|
|
break;
|
|
}
|
|
if ((ev->b & BM_BUTT) == B_SIXTH) {
|
|
break;
|
|
}
|
|
if ((ev->b & BM_ACT) == B_DOWN && !in_menu) delete_window_ev(win, ev);
|
|
else if (in_menu) {
|
|
int i;
|
|
int p = gf_val(2, G_MAINMENU_LEFT_BORDER);
|
|
for (i = 0; i < menu->ni; i++) {
|
|
int o = p;
|
|
unsigned char *tmptext = get_text_translation(menu->items[i].text, win->term);
|
|
p += txtlen(win->term, tmptext) + gf_val(4, 2 * G_MAINMENU_BORDER);
|
|
if (ev->x >= o && ev->x < p) {
|
|
menu->selected = i;
|
|
draw_to_window(win, display_mainmenu, menu);
|
|
if ((ev->b & BM_ACT) == B_UP || (menu->items[s].in_m && !win->term->spec->braille)) select_mainmenu(win->term, menu);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EV_KBD:
|
|
if (ev->y & KBD_PASTING) break;
|
|
if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL) || ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
|
|
select_mainmenu(win->term, menu);
|
|
break;
|
|
} else if (ev->x == KBD_LEFT) {
|
|
go_left:
|
|
if (!menu->selected--) menu->selected = menu->ni - 1;
|
|
s = 1;
|
|
if (fwd) s = 2;
|
|
} else if (ev->x == KBD_RIGHT) {
|
|
go_right:
|
|
if (++menu->selected >= menu->ni) menu->selected = 0;
|
|
s = 1;
|
|
if (fwd) s = 2;
|
|
} else if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
|
|
menu->selected = 0;
|
|
s = 1;
|
|
} else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
|
|
menu->selected = menu->ni - 1;
|
|
s = 1;
|
|
} else if (ev->x > ' ') {
|
|
int i;
|
|
s = 1;
|
|
for (i = 0; i < menu->ni; i++) {
|
|
if (charset_upcase(ev->x, term_charset(win->term)) == menu->hotkeys[i]) {
|
|
menu->selected = i;
|
|
s = 2;
|
|
}
|
|
}
|
|
}
|
|
if (!s) {
|
|
delete_window_ev(win, KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT ? ev : NULL);
|
|
break;
|
|
}
|
|
draw_to_window(win, display_mainmenu, menu);
|
|
if (s == 2) select_mainmenu(win->term, menu);
|
|
break;
|
|
case EV_ABORT:
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct menu_item *new_menu(int free_i)
|
|
{
|
|
struct menu_item *mi;
|
|
mi = mem_calloc(sizeof(struct menu_item));
|
|
mi->free_i = free_i;
|
|
return mi;
|
|
}
|
|
|
|
void add_to_menu(struct menu_item **mi, unsigned char *text, unsigned char *rtext, unsigned char *hotkey, void (*func)(struct terminal *, void *, void *), void *data, int in_m, int pos)
|
|
{
|
|
struct menu_item *mii;
|
|
int n;
|
|
if (pos != -1) {
|
|
n = pos;
|
|
if ((*mi)[n].text) internal_error("invalid menu position %d", n);
|
|
} else {
|
|
for (n = 0; (*mi)[n].text; n++) if (n == MAXINT) overalloc();
|
|
}
|
|
if (((unsigned)n + 2) > MAXINT / sizeof(struct menu_item)) overalloc();
|
|
mii = mem_realloc(*mi, (n + 2) * sizeof(struct menu_item));
|
|
*mi = mii;
|
|
memcpy(mii + n + 1, mii + n, sizeof(struct menu_item));
|
|
mii[n].text = text;
|
|
mii[n].rtext = rtext;
|
|
mii[n].hotkey = hotkey;
|
|
mii[n].func = func;
|
|
mii[n].data = data;
|
|
mii[n].in_m = in_m;
|
|
}
|
|
|
|
void do_dialog(struct terminal *term, struct dialog *dlg, struct memory_list *ml)
|
|
{
|
|
struct dialog_data *dd;
|
|
struct dialog_item *d;
|
|
int n = 0;
|
|
for (d = dlg->items; d->type != D_END; d++) {
|
|
if (n == MAXINT) overalloc();
|
|
n++;
|
|
}
|
|
if ((unsigned)n > (MAXINT - sizeof(struct dialog_data)) / sizeof(struct dialog_item_data)) overalloc();
|
|
dd = mem_calloc(sizeof(struct dialog_data) + sizeof(struct dialog_item_data) * n);
|
|
dd->dlg = dlg;
|
|
dd->n = n;
|
|
dd->ml = ml;
|
|
add_window(term, dialog_func, dd);
|
|
}
|
|
|
|
void display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel)
|
|
{
|
|
struct terminal *term = dlg->win->term;
|
|
if (!F) switch (di->item->type) {
|
|
unsigned char co;
|
|
unsigned char *text, *t;
|
|
int vposlen, cposlen;
|
|
case D_CHECKBOX:
|
|
/* radio or checkbox */
|
|
if (di->checked) print_text(term, di->x, di->y, 3, cast_uchar "[X]", COLOR_DIALOG_CHECKBOX);
|
|
else print_text(term, di->x, di->y, 3, cast_uchar "[ ]", COLOR_DIALOG_CHECKBOX);
|
|
if (sel) {
|
|
set_cursor(term, di->x + 1, di->y, di->x + 1, di->y);
|
|
set_window_ptr(dlg->win, di->x, di->y);
|
|
}
|
|
break;
|
|
case D_FIELD:
|
|
case D_FIELD_PASS:
|
|
fill_area(term, di->x, di->y, di->l, 1, ' ', COLOR_DIALOG_FIELD);
|
|
if (di->vpos > di->cpos) di->vpos = di->cpos;
|
|
vposlen = ttxtlen(term, di->cdata + di->vpos);
|
|
cposlen = ttxtlen(term, di->cdata + di->cpos);
|
|
if (!di->l) {
|
|
di->vpos = di->cpos;
|
|
vposlen = cposlen;
|
|
} else {
|
|
while (vposlen - cposlen > di->l - 1) {
|
|
t = di->cdata + di->vpos;
|
|
GET_TERM_CHAR(term, &t);
|
|
di->vpos = (int)(t - di->cdata);
|
|
vposlen--;
|
|
}
|
|
}
|
|
if (di->item->type == D_FIELD_PASS) {
|
|
t = mem_alloc(vposlen + 1);
|
|
memset(t, '*', vposlen);
|
|
t[vposlen] = 0;
|
|
} else {
|
|
t = di->cdata + di->vpos;
|
|
}
|
|
print_text(term, di->x, di->y, di->l, t, COLOR_DIALOG_FIELD_TEXT);
|
|
if (di->item->type == D_FIELD_PASS) mem_free(t);
|
|
if (sel) {
|
|
set_cursor(term, di->x + vposlen - cposlen, di->y, di->x + vposlen - cposlen, di->y);
|
|
set_window_ptr(dlg->win, di->x, di->y);
|
|
}
|
|
break;
|
|
case D_BUTTON:
|
|
co = sel ? COLOR_DIALOG_BUTTON_SELECTED : COLOR_DIALOG_BUTTON;
|
|
text = get_text_translation(di->item->text, term);
|
|
print_text(term, di->x, di->y, 2, cast_uchar "[ ", co);
|
|
print_text(term, di->x + 2, di->y, ttxtlen(term, text), text, co);
|
|
print_text(term, di->x + 2 + ttxtlen(term, text), di->y, 2, cast_uchar " ]", co);
|
|
if (sel) {
|
|
set_cursor(term, di->x + 2, di->y, di->x + 2, di->y);
|
|
set_window_ptr(dlg->win, di->x, di->y);
|
|
}
|
|
break;
|
|
default:
|
|
internal_error("display_dlg_item: unknown item: %d", di->item->type);
|
|
#ifdef G
|
|
} else {
|
|
struct rect rr;
|
|
struct graphics_device *dev = term->dev;
|
|
if (!dlg->s) restrict_clip_area(dev, &rr, dlg->rr.x1, dlg->rr.y1, dlg->rr.x2, dlg->rr.y2);
|
|
switch (di->item->type) {
|
|
int p, pp;
|
|
struct style *st;
|
|
unsigned char *text, *text2, *text3, *tt, *t;
|
|
struct rect r;
|
|
case D_CHECKBOX:
|
|
p = di->x;
|
|
if (di->checked) {
|
|
if (!sel) g_print_text(dev, di->x, di->y, bfu_style_bw, di->item->gid?cast_uchar(G_DIALOG_RADIO_L G_DIALOG_RADIO_X G_DIALOG_RADIO_R):cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R), &p);
|
|
else {
|
|
g_print_text(dev, di->x, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_L:cast_uchar G_DIALOG_CHECKBOX_L, &p);
|
|
g_print_text(dev, p, di->y, bfu_style_bw_u, di->item->gid?cast_uchar G_DIALOG_RADIO_X:cast_uchar G_DIALOG_CHECKBOX_X, &p);
|
|
g_print_text(dev, p, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_R:cast_uchar G_DIALOG_CHECKBOX_R, &p);
|
|
}
|
|
} else {
|
|
int s = g_text_width(bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_X:cast_uchar G_DIALOG_CHECKBOX_X);
|
|
g_print_text(dev, di->x, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_L:cast_uchar G_DIALOG_CHECKBOX_L, &p);
|
|
if (!sel) drv->fill_area(dev, p, di->y, p + s, di->y + G_BFU_FONT_SIZE, bfu_bg_color), p += s;
|
|
else {
|
|
restrict_clip_area(dev, &r, p, di->y, p + s, di->y + G_BFU_FONT_SIZE);
|
|
g_print_text(dev, p, di->y, bfu_style_bw_u, cast_uchar " ", NULL);
|
|
p += s;
|
|
set_clip_area(dev, &r);
|
|
}
|
|
g_print_text(dev, p, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_R:cast_uchar G_DIALOG_CHECKBOX_R, &p);
|
|
}
|
|
di->l = p - di->x;
|
|
if (sel) set_window_ptr(dlg->win, di->x, di->y + G_BFU_FONT_SIZE);
|
|
if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, p, di->y + G_BFU_FONT_SIZE);
|
|
break;
|
|
case D_FIELD:
|
|
case D_FIELD_PASS:
|
|
text = memacpy(di->cdata, di->cpos);
|
|
if (*(text2 = text3 = di->cdata + di->cpos)) {
|
|
GET_UTF_8(text3, p);
|
|
text2 = memacpy(text2, text3 - text2);
|
|
} else {
|
|
text2 = stracpy(cast_uchar " ");
|
|
text3 = cast_uchar "";
|
|
}
|
|
if (!text2) {
|
|
mem_free(text);
|
|
break;
|
|
}
|
|
text3 = stracpy(text3);
|
|
if (di->item->type == D_FIELD_PASS) {
|
|
unsigned d;
|
|
for (tt = t = text; *tt; ) {
|
|
t = tt;
|
|
GET_UTF_8(tt, d);
|
|
*t++ = '*';
|
|
}
|
|
*t = 0;
|
|
if (di->cdata[di->cpos]) {
|
|
for (tt = t = text2; *tt; ) {
|
|
t = tt;
|
|
GET_UTF_8(tt, d);
|
|
*t++ = '*';
|
|
}
|
|
*t = 0;
|
|
for (tt = t = text3; *tt; ) {
|
|
t = tt;
|
|
GET_UTF_8(tt, d);
|
|
*t++ = '*';
|
|
}
|
|
*t = 0;
|
|
}
|
|
}
|
|
p = g_text_width(bfu_style_wb_mono, text);
|
|
pp = g_text_width(bfu_style_wb_mono, text2);
|
|
if (di->vpos + di->l < p + pp) di->vpos = p + pp - di->l;
|
|
if (di->vpos > p) di->vpos = p;
|
|
if (di->vpos < 0) di->vpos = 0;
|
|
|
|
if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
|
|
restrict_clip_area(dev, &r, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
|
|
p = di->x - di->vpos;
|
|
g_print_text(dev, p, di->y, bfu_style_wb_mono, text, &p);
|
|
g_print_text(dev, p, di->y, sel ? bfu_style_wb_mono_u : bfu_style_wb_mono, text2, &p);
|
|
g_print_text(dev, p, di->y, bfu_style_wb_mono, text3, &p);
|
|
drv->fill_area(dev, p, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE, bfu_fg_color);
|
|
set_clip_area(dev, &r);
|
|
mem_free(text);
|
|
mem_free(text2);
|
|
mem_free(text3);
|
|
if (sel) {
|
|
set_window_ptr(dlg->win, di->x, di->y);
|
|
}
|
|
|
|
break;
|
|
case D_BUTTON:
|
|
st = sel ? bfu_style_wb_b : bfu_style_bw;
|
|
text = get_text_translation(di->item->text, term);
|
|
text2 = mem_alloc(strlen(cast_const_char text) + 5);
|
|
strcpy(cast_char text2, cast_const_char G_DIALOG_BUTTON_L);
|
|
strcpy(cast_char(text2 + 2), cast_const_char text);
|
|
strcat(cast_char text2, cast_const_char G_DIALOG_BUTTON_R);
|
|
di->l = 0;
|
|
g_print_text(dev, di->x, di->y, st, text2, &di->l);
|
|
mem_free(text2);
|
|
if (dlg->s) exclude_from_set(&dlg->s, di->x, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE);
|
|
if (sel) set_window_ptr(dlg->win, di->x, di->y + G_BFU_FONT_SIZE);
|
|
break;
|
|
default:
|
|
internal_error("display_dlg_item: unknown item: %d", di->item->type);
|
|
}
|
|
if (!dlg->s) set_clip_area(dev, &rr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
struct dspd {
|
|
struct dialog_data *dlg;
|
|
struct dialog_item_data *di;
|
|
int sel;
|
|
};
|
|
|
|
static void u_display_dlg_item(struct terminal *term, void *p)
|
|
{
|
|
struct dspd *d = p;
|
|
display_dlg_item(d->dlg, d->di, d->sel);
|
|
}
|
|
|
|
static void x_display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel)
|
|
{
|
|
struct dspd dspd;
|
|
dspd.dlg = dlg, dspd.di = di, dspd.sel = sel;
|
|
draw_to_window(dlg->win, u_display_dlg_item, &dspd);
|
|
}
|
|
|
|
static void dlg_select_item(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
if (di->item->type == D_CHECKBOX) {
|
|
if (!di->item->gid) di -> checked = *(int *)di->cdata = !*(int *)di->cdata;
|
|
else {
|
|
int i;
|
|
for (i = 0; i < dlg->n; i++) {
|
|
if (dlg->items[i].item->type == D_CHECKBOX && dlg->items[i].item->gid == di->item->gid) {
|
|
*(int *)dlg->items[i].cdata = di->item->gnum;
|
|
dlg->items[i].checked = 0;
|
|
x_display_dlg_item(dlg, &dlg->items[i], 0);
|
|
}
|
|
}
|
|
di->checked = 1;
|
|
}
|
|
x_display_dlg_item(dlg, di, 1);
|
|
}
|
|
else if (di->item->type == D_BUTTON) di->item->fn(dlg, di);
|
|
}
|
|
|
|
static unsigned char *dlg_get_history_string(struct terminal *term, struct history_item *hi, int l)
|
|
{
|
|
unsigned char *s;
|
|
int ch = term_charset(term);
|
|
s = convert(utf8_table, ch, hi->str, NULL);
|
|
if (strlen(cast_const_char s) >= (size_t)l)
|
|
s[l - 1] = 0;
|
|
if (ch == utf8_table) {
|
|
int r = (int)strlen(cast_const_char s);
|
|
unsigned char *p = s;
|
|
while (r) {
|
|
int chl = utf8chrlen(*p);
|
|
if (chl > r) {
|
|
*p = 0;
|
|
break;
|
|
}
|
|
p += chl;
|
|
r -= chl;
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
static void dlg_set_history(struct terminal *term, struct dialog_item_data *di)
|
|
{
|
|
unsigned char *s;
|
|
if (di->cur_hist == &di->history) s = stracpy(cast_uchar "");
|
|
else s = dlg_get_history_string(term, list_struct(di->cur_hist, struct history_item), di->item->dlen);
|
|
strcpy(cast_char di->cdata, cast_const_char s);
|
|
di->cpos = (int)strlen(cast_const_char s);
|
|
di->vpos = 0;
|
|
mem_free(s);
|
|
}
|
|
|
|
static int dlg_mouse(struct dialog_data *dlg, struct dialog_item_data *di, struct links_event *ev)
|
|
{
|
|
switch (di->item->type) {
|
|
case D_BUTTON:
|
|
if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + gf_val(ttxtlen(dlg->win->term, get_text_translation(di->item->text, dlg->win->term)) + 4, di->l)) return 0;
|
|
if (dlg->selected != di - dlg->items) {
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
|
|
dlg->selected = (int)(di - dlg->items);
|
|
x_display_dlg_item(dlg, di, 1);
|
|
}
|
|
if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
|
|
return 1;
|
|
case D_FIELD:
|
|
case D_FIELD_PASS:
|
|
if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + di->l) return 0;
|
|
if (!is_utf_8(dlg->win->term)) {
|
|
if ((size_t)(di->cpos = di->vpos + ev->x - di->x) > strlen(cast_const_char di->cdata)) di->cpos = (int)strlen(cast_const_char di->cdata);
|
|
} else {
|
|
int p, u;
|
|
unsigned char *t = di->cdata;
|
|
p = di->x - di->vpos;
|
|
while (1) {
|
|
di->cpos = (int)(t - di->cdata);
|
|
if (!*t) break;
|
|
GET_UTF_8(t, u);
|
|
if (!u) continue;
|
|
if (!F) p++;
|
|
#ifdef G
|
|
else p += g_char_width(bfu_style_wb_mono, u);
|
|
#endif
|
|
if (p > ev->x) break;
|
|
}
|
|
}
|
|
if (dlg->selected != di - dlg->items) {
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
|
|
dlg->selected = (int)(di - dlg->items);
|
|
x_display_dlg_item(dlg, di, 1);
|
|
} else x_display_dlg_item(dlg, di, 1);
|
|
return 1;
|
|
case D_CHECKBOX:
|
|
if (gf_val(ev->y != di->y, ev->y < di->y || ev->y >= di->y + G_BFU_FONT_SIZE) || ev->x < di->x || ev->x >= di->x + gf_val(3, di->l)) return 0;
|
|
if (dlg->selected != di - dlg->items) {
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
|
|
dlg->selected = (int)(di - dlg->items);
|
|
x_display_dlg_item(dlg, di, 1);
|
|
}
|
|
if ((ev->b & BM_ACT) == B_UP) dlg_select_item(dlg, di);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void redraw_dialog_items(struct terminal *term, void *dlg_)
|
|
{
|
|
struct dialog_data *dlg = (struct dialog_data *)dlg_;
|
|
int i;
|
|
for (i = 0; i < dlg->n; i++) display_dlg_item(dlg, &dlg->items[i], i == dlg->selected);
|
|
}
|
|
|
|
static int dlg_is_braille_moving(struct dialog_data *dlg)
|
|
{
|
|
return dlg->win->term->spec->braille && (dlg->dlg->fn == msg_box_fn || dlg->dlg->fn == download_window_function);
|
|
}
|
|
|
|
static void redraw_dialog(struct terminal *term, void *dlg_)
|
|
{
|
|
struct dialog_data *dlg = (struct dialog_data *)dlg_;
|
|
#ifdef G
|
|
int i;
|
|
#endif
|
|
dlg->dlg->fn(dlg);
|
|
redraw_dialog_items(term, dlg);
|
|
if (dlg_is_braille_moving(dlg)) {
|
|
if (dlg->brl_y < dlg->items[0].y - 3)
|
|
set_cursor(term, dlg->x + 6, dlg->y + 3 + dlg->brl_y, dlg->x + 6, dlg->y + 3 + dlg->brl_y);
|
|
}
|
|
#ifdef G
|
|
if (F) {
|
|
set_clip_area(term->dev, &dlg->r);
|
|
for (i = 0; i < dlg->s->m; i++) if (is_rect_valid(&dlg->s->r[i]))
|
|
drv->fill_area(term->dev, dlg->s->r[i].x1, dlg->s->r[i].y1, dlg->s->r[i].x2, dlg->s->r[i].y2, bfu_bg_color);
|
|
mem_free(dlg->s);
|
|
dlg->s = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void tab_compl(struct terminal *term, void *hi_, void *win_)
|
|
{
|
|
struct history_item *hi = (struct history_item *)hi_;
|
|
struct window *win = (struct window *)win_;
|
|
struct links_event ev = {EV_REDRAW, 0, 0, 0};
|
|
struct dialog_item_data *di = &((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected];
|
|
unsigned char *s = dlg_get_history_string(term, hi, di->item->dlen);
|
|
strcpy(cast_char di->cdata, cast_const_char s);
|
|
di->cpos = (int)strlen(cast_const_char s);
|
|
di->vpos = 0;
|
|
mem_free(s);
|
|
ev.x = term->x;
|
|
ev.y = term->y;
|
|
dialog_func(win, &ev, 0);
|
|
}
|
|
|
|
static void do_tab_compl(struct terminal *term, struct list_head *history, struct window *win)
|
|
{
|
|
unsigned char *cdata = ((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected].cdata;
|
|
int l = (int)strlen(cast_const_char cdata), n = 0;
|
|
struct history_item *hi;
|
|
struct list_head *lhi;
|
|
struct menu_item *items = DUMMY;
|
|
foreach(struct history_item, hi, lhi, *history) {
|
|
unsigned char *s = dlg_get_history_string(term, hi, MAXINT);
|
|
if (!strncmp(cast_const_char cdata, cast_const_char s, l)) {
|
|
if (!(n & (ALLOC_GR - 1))) {
|
|
if ((unsigned)n > MAXINT / sizeof(struct menu_item) - ALLOC_GR - 1) overalloc();
|
|
items = mem_realloc(items, (n + ALLOC_GR + 1) * sizeof(struct menu_item));
|
|
}
|
|
items[n].text = s;
|
|
items[n].rtext = cast_uchar "";
|
|
items[n].hotkey = cast_uchar "";
|
|
items[n].func = tab_compl;
|
|
items[n].rtext = cast_uchar "";
|
|
items[n].data = hi;
|
|
items[n].in_m = 0;
|
|
items[n].free_i = MENU_FREE_ITEMS | MENU_FREE_TEXT;
|
|
if (n == MAXINT) overalloc();
|
|
n++;
|
|
} else {
|
|
mem_free(s);
|
|
}
|
|
}
|
|
if (n == 1) {
|
|
tab_compl(term, items->data, win);
|
|
mem_free(items->text);
|
|
mem_free(items);
|
|
return;
|
|
}
|
|
if (n) {
|
|
memset(&items[n], 0, sizeof(struct menu_item));
|
|
do_menu_selected(term, items, win, n - 1, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void dialog_func(struct window *win, struct links_event *ev, int fwd)
|
|
{
|
|
int i;
|
|
struct terminal *term = win->term;
|
|
struct dialog_data *dlg = win->data;
|
|
struct dialog_item_data *di;
|
|
|
|
dlg->win = win;
|
|
|
|
/* Use nonstandard event handlers */
|
|
if (dlg->dlg->handle_event && dlg->dlg->handle_event(dlg, ev) == EVENT_PROCESSED) {
|
|
return;
|
|
}
|
|
|
|
switch ((int)ev->ev) {
|
|
case EV_INIT:
|
|
for (i = 0; i < dlg->n; i++) {
|
|
/* highc_volatile because of a compiler bug */
|
|
struct dialog_item_data * highc_volatile di = &dlg->items[i];
|
|
memset(di, 0, sizeof(struct dialog_item_data));
|
|
di->item = &dlg->dlg->items[i];
|
|
di->cdata = mem_alloc(di->item->dlen);
|
|
if (di->item->dlen)
|
|
memcpy(di->cdata, di->item->data, di->item->dlen);
|
|
if (di->item->type == D_CHECKBOX) {
|
|
if (di->item->gid) {
|
|
if (*(int *)di->cdata == di->item->gnum) di->checked = 1;
|
|
} else if (*(int *)di->cdata) di->checked = 1;
|
|
}
|
|
init_list(di->history);
|
|
di->cur_hist = &di->history;
|
|
if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
|
|
if (di->item->history) {
|
|
struct history_item *j;
|
|
struct list_head *lj;
|
|
foreach(struct history_item, j, lj, di->item->history->items) {
|
|
struct history_item *hi;
|
|
size_t sl = strlen(cast_const_char j->str);
|
|
if (sl > MAXINT - sizeof(struct history_item)) overalloc();
|
|
hi = mem_alloc(sizeof(struct history_item) + sl);
|
|
strcpy(cast_char hi->str, cast_const_char j->str);
|
|
add_to_list(di->history, hi);
|
|
}
|
|
}
|
|
di->cpos = (int)strlen(cast_const_char di->cdata);
|
|
}
|
|
}
|
|
dlg->selected = 0;
|
|
/*-fallthrough*/
|
|
case EV_RESIZE:
|
|
/* this must be really called twice !!! */
|
|
draw_to_window(dlg->win, redraw_dialog, dlg);
|
|
/*-fallthrough*/
|
|
case EV_REDRAW:
|
|
redraw:
|
|
draw_to_window(dlg->win, redraw_dialog, dlg);
|
|
break;
|
|
case EV_MOUSE:
|
|
if ((ev->b & BM_ACT) == B_MOVE) break;
|
|
if ((ev->b & BM_BUTT) == B_FOURTH) {
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto go_prev;
|
|
break;
|
|
}
|
|
if ((ev->b & BM_BUTT) == B_FIFTH) {
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto go_next;
|
|
break;
|
|
}
|
|
if ((ev->b & BM_BUTT) == B_SIXTH) {
|
|
if ((ev->b & BM_ACT) == B_DOWN) goto go_enter;
|
|
break;
|
|
}
|
|
for (i = 0; i < dlg->n; i++) if (dlg_mouse(dlg, &dlg->items[i], ev)) break;
|
|
if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_MIDDLE) {
|
|
di = &dlg->items[dlg->selected]; /* don't delete this!!! it's here because of jump from mouse event */
|
|
if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) goto clipbd_paste;
|
|
}
|
|
break;
|
|
case EV_KBD:
|
|
di = &dlg->items[dlg->selected];
|
|
if (ev->y & KBD_PASTING) {
|
|
if (!((di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) &&
|
|
(ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT)))))
|
|
break;
|
|
}
|
|
if (ev->x == KBD_UP && dlg_is_braille_moving(dlg)) {
|
|
if (dlg->brl_y) dlg->brl_y--;
|
|
goto redraw;
|
|
}
|
|
if (ev->x == KBD_DOWN && dlg_is_braille_moving(dlg)) {
|
|
if (dlg->brl_y < dlg->items[0].y - 3) dlg->brl_y++;
|
|
goto redraw;
|
|
}
|
|
if ((ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL) || ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) && dlg_is_braille_moving(dlg)) {
|
|
dlg->brl_y = 0;
|
|
goto redraw;
|
|
}
|
|
if ((ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) && dlg_is_braille_moving(dlg)) {
|
|
dlg->brl_y = dlg->items[0].y - 4;
|
|
goto redraw;
|
|
}
|
|
if ((ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) && dlg_is_braille_moving(dlg)) {
|
|
dlg->brl_y = dlg->items[0].y - 3;
|
|
goto redraw;
|
|
}
|
|
if (di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) {
|
|
if (ev->x == KBD_UP && di->cur_hist->prev != &di->history) {
|
|
di->cur_hist = di->cur_hist->prev;
|
|
dlg_set_history(term, di);
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_DOWN && di->cur_hist != &di->history) {
|
|
di->cur_hist = di->cur_hist->next;
|
|
dlg_set_history(term, di);
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_RIGHT) {
|
|
if ((size_t)di->cpos < strlen(cast_const_char di->cdata)) {
|
|
if (!is_utf_8(term)) di->cpos++;
|
|
else {
|
|
int u;
|
|
unsigned char *p = di->cdata + di->cpos;
|
|
GET_UTF_8(p, u);
|
|
di->cpos = (int)(p - di->cdata);
|
|
}
|
|
}
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_LEFT) {
|
|
if (di->cpos > 0) {
|
|
if (!is_utf_8(term)) di->cpos--;
|
|
else {
|
|
unsigned char *p = di->cdata + di->cpos;
|
|
BACK_UTF_8(p, di->cdata);
|
|
di->cpos = (int)(p - di->cdata);
|
|
}
|
|
}
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
|
|
di->cpos = 0;
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
|
|
di->cpos = (int)strlen(cast_const_char di->cdata);
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
|
|
unsigned char *u;
|
|
unsigned char p[2] = { 0, 0 };
|
|
if (cp2u(ev->x, term_charset(term)) == -1)
|
|
break;
|
|
if (!is_utf_8(term)) {
|
|
p[0] = (unsigned char)ev->x, u = p;
|
|
} else {
|
|
u = encode_utf_8(ev->x);
|
|
}
|
|
if (strlen(cast_const_char di->cdata) + strlen(cast_const_char u) < (size_t)di->item->dlen) {
|
|
memmove(di->cdata + di->cpos + strlen(cast_const_char u), di->cdata + di->cpos, strlen(cast_const_char di->cdata) - di->cpos + 1);
|
|
memcpy(&di->cdata[di->cpos], u, strlen(cast_const_char u));
|
|
di->cpos += (int)strlen(cast_const_char u);
|
|
}
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_BS) {
|
|
if (di->cpos) {
|
|
int s = 1;
|
|
if (is_utf_8(term)) {
|
|
unsigned u;
|
|
unsigned char *p, *pp;
|
|
p = di->cdata;
|
|
a:
|
|
pp = p;
|
|
GET_UTF_8(p, u);
|
|
if (p < di->cdata + di->cpos) goto a;
|
|
s = (int)(p - pp);
|
|
}
|
|
memmove(di->cdata + di->cpos - s, di->cdata + di->cpos, strlen(cast_const_char di->cdata) - di->cpos + s);
|
|
di->cpos -= s;
|
|
}
|
|
goto dsp_f;
|
|
}
|
|
if (ev->x == KBD_DEL || (upcase(ev->x) == 'D' && ev->y & KBD_CTRL)) {
|
|
if ((size_t)di->cpos < strlen(cast_const_char di->cdata)) {
|
|
int s = 1;
|
|
if (is_utf_8(term)) {
|
|
unsigned u;
|
|
unsigned char *p = di->cdata + di->cpos;
|
|
GET_UTF_8(p, u);
|
|
s = (int)(p - (di->cdata + di->cpos));
|
|
}
|
|
memmove(di->cdata + di->cpos, di->cdata + di->cpos + s, strlen(cast_const_char di->cdata) - di->cpos + s);
|
|
}
|
|
goto dsp_f;
|
|
}
|
|
if (upcase(ev->x) == 'U' && ev->y & KBD_CTRL) {
|
|
unsigned char *a = memacpy(di->cdata, di->cpos);
|
|
if (a) {
|
|
set_clipboard_text(term, a);
|
|
mem_free(a);
|
|
}
|
|
memmove(di->cdata, di->cdata + di->cpos, strlen(cast_const_char di->cdata + di->cpos) + 1);
|
|
di->cpos = 0;
|
|
goto dsp_f;
|
|
}
|
|
if (upcase(ev->x) == 'K' && ev->y & KBD_CTRL) {
|
|
set_clipboard_text(term, di->cdata + di->cpos);
|
|
di->cdata[di->cpos] = 0;
|
|
goto dsp_f;
|
|
}
|
|
/* Copy to clipboard */
|
|
if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL) || ev->x == KBD_COPY) {
|
|
set_clipboard_text(term, di->cdata);
|
|
break; /* We don't need to redraw */
|
|
}
|
|
/* FIXME -- why keyboard shortcuts with shift don't works??? */
|
|
/* Cut to clipboard */
|
|
if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL) || ev->x == KBD_CUT) {
|
|
set_clipboard_text(term, di->cdata);
|
|
di->cdata[0] = 0;
|
|
di->cpos = 0;
|
|
goto dsp_f;
|
|
}
|
|
/* Paste from clipboard */
|
|
if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL) || ev->x == KBD_PASTE) {
|
|
unsigned char *clipboard;
|
|
clipbd_paste:
|
|
clipboard = get_clipboard_text(term);
|
|
if (clipboard) {
|
|
unsigned char *nl = clipboard;
|
|
while ((nl = cast_uchar strchr(cast_const_char nl, '\n'))) *nl = ' ';
|
|
if (strlen(cast_const_char di->cdata) + strlen(cast_const_char clipboard) < (size_t)di->item->dlen ||
|
|
strlen(cast_const_char di->cdata) + strlen(cast_const_char clipboard) < strlen(cast_const_char di->cdata)) {
|
|
memmove(di->cdata + di->cpos + strlen(cast_const_char clipboard), di->cdata + di->cpos, strlen(cast_const_char di->cdata) - di->cpos + 1);
|
|
memcpy(&di->cdata[di->cpos], clipboard, strlen(cast_const_char clipboard));
|
|
di->cpos += (int)strlen(cast_const_char clipboard);
|
|
}
|
|
mem_free(clipboard);
|
|
}
|
|
goto dsp_f;
|
|
}
|
|
if ((upcase(ev->x) == 'W' && ev->y & KBD_CTRL) || ev->x == KBD_FIND) {
|
|
do_tab_compl(term, &di->history, win);
|
|
goto dsp_f;
|
|
}
|
|
goto gh;
|
|
dsp_f:
|
|
x_display_dlg_item(dlg, di, 1);
|
|
break;
|
|
}
|
|
if ((ev->x == KBD_ENTER && di->item->type == D_BUTTON) || ev->x == ' ') {
|
|
dlg_select_item(dlg, di);
|
|
break;
|
|
}
|
|
gh:
|
|
if (ev->x > ' ') for (i = 0; i < dlg->n; i++) {
|
|
unsigned char *tx = get_text_translation(dlg->dlg->items[i].text, term);
|
|
if (dlg->dlg->items[i].type == D_BUTTON && charset_upcase(GET_TERM_CHAR(term, &tx), term_charset(term)) == charset_upcase(ev->x, term_charset(term))) goto sel;
|
|
}
|
|
if (ev->x == KBD_ENTER) {
|
|
go_enter:
|
|
for (i = 0; i < dlg->n; i++)
|
|
if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ENTER) goto sel;
|
|
break;
|
|
}
|
|
if (ev->x == KBD_ESC) {
|
|
for (i = 0; i < dlg->n; i++)
|
|
if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ESC) goto sel;
|
|
break;
|
|
}
|
|
if (0) {
|
|
sel:
|
|
if (dlg->selected != i) {
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
|
|
x_display_dlg_item(dlg, &dlg->items[i], 1);
|
|
dlg->selected = i;
|
|
}
|
|
dlg_select_item(dlg, &dlg->items[i]);
|
|
break;
|
|
}
|
|
if (((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN || ev->x == KBD_RIGHT) && (dlg->n > 1 || term->spec->braille)) {
|
|
go_next:
|
|
if (term->spec->braille) dlg->brl_y = dlg->items[0].y - 3;
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
|
|
if ((++dlg->selected) >= dlg->n) dlg->selected = 0;
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
|
|
break;
|
|
}
|
|
if (((ev->x == KBD_TAB && ev->y) || ev->x == KBD_UP || ev->x == KBD_LEFT) && (dlg->n > 1 || term->spec->braille)) {
|
|
go_prev:
|
|
if (term->spec->braille) dlg->brl_y = dlg->items[0].y - 3;
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
|
|
if ((--dlg->selected) < 0) dlg->selected = dlg->n - 1;
|
|
x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
|
|
break;
|
|
}
|
|
break;
|
|
case EV_ABORT:
|
|
/* Moved this line up so that the dlg would have access to its
|
|
member vars before they get freed. */
|
|
if (dlg->dlg->abort) dlg->dlg->abort(dlg);
|
|
for (i = 0; i < dlg->n; i++) {
|
|
struct dialog_item_data *di = &dlg->items[i];
|
|
if (di->cdata) mem_free(di->cdata);
|
|
free_list(struct history_item, di->history);
|
|
}
|
|
freeml(dlg->ml);
|
|
}
|
|
}
|
|
|
|
/* gid and gnum are 100 times greater than boundaries (e.g. if gid==1 boundary is 0.01) */
|
|
int check_float(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
char *end;
|
|
double d = strtod(cast_const_char di->cdata, &end);
|
|
if (!*di->cdata || *end || di->cdata[strspn(cast_const_char di->cdata, "0123456789.")] || *di->cdata == (unsigned char)'.') {
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
if (d < 0 || d > di->item->gnum || 100 * d < di->item->gid || 100 * d > di->item->gnum) {
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int check_number(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
char *end;
|
|
long l = strtol(cast_const_char di->cdata, &end, 10);
|
|
if (!*di->cdata || *end) {
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
if (l < di->item->gid || l > di->item->gnum) {
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int check_hex_number(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
char *end;
|
|
long l = strtol(cast_const_char di->cdata, &end, 16);
|
|
if (!*di->cdata || *end) {
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
if (l < di->item->gid || l > di->item->gnum) {
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int check_nonempty(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
unsigned char *p;
|
|
for (p = di->cdata; *p; p++) if (*p > ' ') return 0;
|
|
msg_box(dlg->win->term, NULL, TEXT_(T_BAD_STRING), AL_CENTER, TEXT_(T_EMPTY_STRING_NOT_ALLOWED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
|
|
static int check_local_ip_address_internal(struct dialog_data *dlg, struct dialog_item_data *di, int pf)
|
|
{
|
|
int s;
|
|
int rs;
|
|
unsigned char *p = di->cdata;
|
|
if (!*p) {
|
|
return 0;
|
|
}
|
|
s = socket_and_bind(pf, p);
|
|
if (s != -1) {
|
|
EINTRLOOP(rs, close(s));
|
|
} else {
|
|
if (1
|
|
#ifdef ENFILE
|
|
&& errno != ENFILE
|
|
#endif
|
|
#ifdef EMFILE
|
|
&& errno != EMFILE
|
|
#endif
|
|
#ifdef ENOBUFS
|
|
&& errno != ENOBUFS
|
|
#endif
|
|
#ifdef ENOMEM
|
|
&& errno != ENOMEM
|
|
#endif
|
|
) {
|
|
unsigned char *er = strerror_alloc(errno, dlg->win->term);
|
|
unsigned char *ad = stracpy(p);
|
|
msg_box(dlg->win->term, getml(er, ad, NULL), TEXT_(T_BAD_IP_ADDRESS), AL_CENTER, TEXT_(T_UNABLE_TO_USE_LOCAL_IP_ADDRESS), cast_uchar " ", ad, cast_uchar ": ", er, MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int check_local_ip_address(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
return check_local_ip_address_internal(dlg, di, PF_INET);
|
|
}
|
|
|
|
int check_local_ipv6_address(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
#ifdef SUPPORT_IPV6
|
|
return check_local_ip_address_internal(dlg, di, PF_INET6);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int cancel_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
delete_window(dlg->win);
|
|
return 0;
|
|
}
|
|
|
|
int check_dialog(struct dialog_data *dlg)
|
|
{
|
|
int i;
|
|
for (i = 0; i < dlg->n; i++)
|
|
if (dlg->dlg->items[i].type == D_CHECKBOX || dlg->dlg->items[i].type == D_FIELD || dlg->dlg->items[i].type == D_FIELD_PASS)
|
|
if (dlg->dlg->items[i].fn && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) {
|
|
dlg->selected = i;
|
|
draw_to_window(dlg->win, redraw_dialog_items, dlg);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void get_dialog_data(struct dialog_data *dlg)
|
|
{
|
|
int i;
|
|
for (i = 0; i < dlg->n; i++) {
|
|
/* highc_volatile because of a compiler bug */
|
|
void * highc_volatile p1 = dlg->dlg->items[i].data;
|
|
void * highc_volatile p2 = dlg->items[i].cdata;
|
|
highc_volatile int l = dlg->dlg->items[i].dlen;
|
|
if (l)
|
|
memcpy(p1, p2, l);
|
|
}
|
|
}
|
|
|
|
int ok_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
void (*fn)(void *) = dlg->dlg->refresh;
|
|
void *data = dlg->dlg->refresh_data;
|
|
if (check_dialog(dlg)) return 1;
|
|
get_dialog_data(dlg);
|
|
if (fn) fn(data);
|
|
return cancel_dialog(dlg, di);
|
|
}
|
|
|
|
void center_dlg(struct dialog_data *dlg)
|
|
{
|
|
if (!dlg->win->term->spec->braille) {
|
|
dlg->x = (dlg->win->term->x - dlg->xw) / 2;
|
|
dlg->y = (dlg->win->term->y - dlg->yw) / 2;
|
|
} else {
|
|
dlg->x = -6;
|
|
dlg->y = -1;
|
|
dlg->xw = dlg->win->term->x + 12;
|
|
dlg->yw = dlg->win->term->y + 3;
|
|
}
|
|
}
|
|
|
|
void draw_dlg(struct dialog_data *dlg)
|
|
{
|
|
if (!F) {
|
|
int i, tpos;
|
|
struct terminal *term = dlg->win->term;
|
|
fill_area(term, dlg->x, dlg->y, dlg->xw, dlg->yw, ' ', COLOR_DIALOG);
|
|
draw_frame(term, dlg->x + DIALOG_LEFT_BORDER, dlg->y + DIALOG_TOP_BORDER, dlg->xw - 2 * DIALOG_LEFT_BORDER, dlg->yw - 2 * DIALOG_TOP_BORDER, COLOR_DIALOG_FRAME, DIALOG_FRAME);
|
|
i = ttxtlen(term, get_text_translation(dlg->dlg->title, term));
|
|
tpos = (dlg->xw - i) / 2;
|
|
if (term->spec->braille) tpos = 9;
|
|
print_text(term, tpos + dlg->x - 1, dlg->y + DIALOG_TOP_BORDER, 1, cast_uchar " ", COLOR_DIALOG_TITLE);
|
|
print_text(term, tpos + dlg->x, dlg->y + DIALOG_TOP_BORDER, i, get_text_translation(dlg->dlg->title, term), COLOR_DIALOG_TITLE);
|
|
print_text(term, tpos + dlg->x + i, dlg->y + DIALOG_TOP_BORDER, 1, cast_uchar " ", COLOR_DIALOG_TITLE);
|
|
#ifdef G
|
|
} else {
|
|
struct graphics_device *dev = dlg->win->term->dev;
|
|
struct rect r;
|
|
struct rect rt;
|
|
unsigned char *text = get_text_translation(dlg->dlg->title, dlg->win->term);
|
|
int xtl = txtlen(dlg->win->term, text);
|
|
int tl = xtl + 2 * G_DIALOG_TITLE_BORDER;
|
|
int TXT_X, TXT_Y;
|
|
if (tl > dlg->xw - 2 * G_DIALOG_LEFT_BORDER - 2 * G_DIALOG_VLINE_SPACE) tl = dlg->xw - 2 * G_DIALOG_LEFT_BORDER - 2 * G_DIALOG_VLINE_SPACE;
|
|
TXT_X = dlg->x + (dlg->xw - tl) / 2;
|
|
TXT_Y = dlg->y + G_DIALOG_TOP_BORDER + (G_DIALOG_HLINE_SPACE + 1) / 2 - G_BFU_FONT_SIZE / 2;
|
|
if (TXT_Y < dlg->y) TXT_Y = dlg->y;
|
|
if (TXT_Y < dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1 - G_BFU_FONT_SIZE) TXT_Y = dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1 - G_BFU_FONT_SIZE;
|
|
set_window_pos(dlg->win, dlg->x, dlg->y, dlg->x + dlg->xw, dlg->y + dlg->yw);
|
|
|
|
restrict_clip_area(dev, &r, TXT_X, TXT_Y, TXT_X + tl, TXT_Y + G_BFU_FONT_SIZE);
|
|
rt.x1 = TXT_X;
|
|
rt.x2 = TXT_X + tl;
|
|
rt.y1 = TXT_Y;
|
|
rt.y2 = TXT_Y + G_BFU_FONT_SIZE;
|
|
if (xtl > tl) g_print_text(dev, TXT_X, TXT_Y, bfu_style_wb, text, NULL);
|
|
else {
|
|
drv->fill_area(dev, TXT_X, TXT_Y, TXT_X + (tl - xtl) / 2, TXT_Y + G_BFU_FONT_SIZE, bfu_fg_color);
|
|
g_print_text(dev, TXT_X + (tl - xtl) / 2, TXT_Y, bfu_style_wb, text, NULL);
|
|
drv->fill_area(dev, TXT_X + (tl - xtl) / 2 + xtl, TXT_Y, TXT_X + tl, TXT_Y + G_BFU_FONT_SIZE, bfu_fg_color);
|
|
}
|
|
set_clip_area(dev, &r);
|
|
|
|
drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER, TXT_X, bfu_fg_color);
|
|
drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, TXT_X, bfu_fg_color);
|
|
drv->draw_hline(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER, bfu_fg_color);
|
|
drv->draw_hline(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, bfu_fg_color);
|
|
drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER, bfu_fg_color);
|
|
drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, bfu_fg_color);
|
|
|
|
drv->draw_vline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_fg_color);
|
|
drv->draw_vline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1, bfu_fg_color);
|
|
drv->draw_vline(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + G_DIALOG_TOP_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_fg_color);
|
|
drv->draw_vline(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1, bfu_fg_color);
|
|
|
|
drv->fill_area(dev, dlg->x, dlg->y, TXT_X, dlg->y + G_DIALOG_TOP_BORDER, bfu_bg_color);
|
|
drv->fill_area(dev, TXT_X, dlg->y, TXT_X + tl, TXT_Y, bfu_bg_color);
|
|
drv->fill_area(dev, TXT_X + tl, dlg->y, dlg->x + dlg->xw, dlg->y + G_DIALOG_TOP_BORDER, bfu_bg_color);
|
|
drv->fill_area(dev, dlg->x, dlg->y + G_DIALOG_TOP_BORDER, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER, bfu_bg_color);
|
|
drv->fill_area(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER, dlg->x + dlg->xw, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER, bfu_bg_color);
|
|
drv->fill_area(dev, dlg->x, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER, dlg->x + dlg->xw, dlg->y + dlg->yw, bfu_bg_color);
|
|
|
|
drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + G_DIALOG_TOP_BORDER + 1, TXT_X, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, bfu_bg_color);
|
|
drv->fill_area(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER + 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, bfu_bg_color);
|
|
drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, bfu_bg_color);
|
|
drv->fill_area(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, bfu_bg_color);
|
|
drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_bg_color);
|
|
|
|
dlg->s = init_rect_set();
|
|
dlg->rr.x1 = dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE + 1;
|
|
dlg->rr.x2 = dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1;
|
|
dlg->rr.y1 = dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1;
|
|
dlg->rr.y2 = dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1;
|
|
add_to_rect_set(&dlg->s, &dlg->rr);
|
|
exclude_rect_from_set(&dlg->s, &rt);
|
|
restrict_clip_area(dev, &dlg->r, dlg->rr.x1, dlg->rr.y1, dlg->rr.x2, dlg->rr.y2);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void max_text_width(struct terminal *term, unsigned char *text, int *width, int align)
|
|
{
|
|
if (term->spec->braille) *width = term->x;
|
|
text = get_text_translation(text, term);
|
|
do {
|
|
int c = 0;
|
|
while (*text && *text != '\n') {
|
|
if (!is_utf_8(term)) text++, c++;
|
|
else {
|
|
int u;
|
|
GET_UTF_8(text, u);
|
|
if (!F) c++;
|
|
#ifdef G
|
|
else c += g_char_width(align & AL_MONO ? bfu_style_wb_mono : bfu_style_wb, u);
|
|
#endif
|
|
}
|
|
}
|
|
if (c > *width) *width = c;
|
|
} while (*(text++));
|
|
}
|
|
|
|
void min_text_width(struct terminal *term, unsigned char *text, int *width, int align)
|
|
{
|
|
if (term->spec->braille) *width = term->x;
|
|
text = get_text_translation(text, term);
|
|
do {
|
|
int c = 0;
|
|
while (*text && *text != '\n' && *text != ' ') {
|
|
if (!is_utf_8(term)) text++, c++;
|
|
else {
|
|
int u;
|
|
GET_UTF_8(text, u);
|
|
if (!F) c++;
|
|
#ifdef G
|
|
else c += g_char_width(align & AL_MONO ? bfu_style_wb_mono : bfu_style_wb, u);
|
|
#endif
|
|
}
|
|
}
|
|
if (c > *width) *width = c;
|
|
} while (*(text++));
|
|
}
|
|
|
|
int dlg_format_text(struct dialog_data *dlg, struct terminal *term, unsigned char *text, int x, int *y, int w, int *rw, unsigned char co, int align)
|
|
{
|
|
int xx = x;
|
|
#ifdef G
|
|
unsigned char *tx2;
|
|
#endif
|
|
text = get_text_translation(text, dlg->win->term);
|
|
if (dlg->win->term->spec->braille && !(align & AL_NOBRLEXP)) w = dlg->win->term->x;
|
|
if (!F) while (1) {
|
|
unsigned char *t1;
|
|
unsigned ch;
|
|
int cx, lbr;
|
|
|
|
t1 = text;
|
|
cx = 0;
|
|
lbr = 0;
|
|
next_chr:
|
|
ch = GET_TERM_CHAR(dlg->win->term, &t1);
|
|
if (ch == ' ') {
|
|
lbr = cx;
|
|
}
|
|
if (ch && ch != '\n') {
|
|
if (cx == w) {
|
|
if (!lbr) lbr = cx;
|
|
goto print_line;
|
|
}
|
|
cx++;
|
|
goto next_chr;
|
|
}
|
|
if (!ch && !cx)
|
|
break;
|
|
lbr = cx;
|
|
print_line:
|
|
if (rw && lbr > *rw) *rw = lbr;
|
|
xx = x;
|
|
if ((align & AL_MASK) == AL_CENTER && !dlg->win->term->spec->braille) {
|
|
xx += (w - lbr) / 2;
|
|
}
|
|
for (; lbr--; xx++) {
|
|
ch = GET_TERM_CHAR(dlg->win->term, &text);
|
|
if (term) set_char(term, xx, *y, ch, co);
|
|
}
|
|
xx++;
|
|
if (*text == ' ' || *text == '\n') text++;
|
|
(*y)++;
|
|
}
|
|
#ifdef G
|
|
else if ((tx2 = cast_uchar strchr(cast_const_char text, '\n'))) {
|
|
unsigned char *txt = stracpy(text);
|
|
unsigned char *tx1 = txt;
|
|
tx2 = txt + (tx2 - text);
|
|
do {
|
|
*tx2 = 0;
|
|
dlg_format_text(dlg, term, tx1, x, y, w, rw, co, align);
|
|
tx1 = tx2 + 1;
|
|
} while ((tx2 = cast_uchar strchr(cast_const_char tx1, '\n')));
|
|
dlg_format_text(dlg, term, tx1, x, y, w, rw, co, align);
|
|
mem_free(txt);
|
|
} else {
|
|
int www;
|
|
unsigned char *txt;
|
|
struct wrap_struct ww;
|
|
int r;
|
|
ww.style = align & AL_MONO ? bfu_style_bw_mono : bfu_style_bw;
|
|
ww.width = w;
|
|
new_ln:
|
|
ww.text = text;
|
|
ww.obj = NULL;
|
|
ww.pos = 0;
|
|
ww.last_wrap = NULL;
|
|
ww.last_wrap_obj = NULL;
|
|
ww.force_break = 1;
|
|
r = g_wrap_text(&ww);
|
|
if (!r) {
|
|
txt = memacpy(text, ww.last_wrap - text);
|
|
www = g_text_width(ww.style, txt);
|
|
if (!term) mem_free(txt);
|
|
text = ww.last_wrap;
|
|
if (*text == ' ') text++;
|
|
} else {
|
|
www = ww.pos;
|
|
txt = text;
|
|
}
|
|
if (term) {
|
|
int xx = (align & AL_MASK) == AL_CENTER ? x + (w - www) / 2 : x;
|
|
g_print_text(dlg->win->term->dev, xx, *y, ww.style, txt, NULL);
|
|
if (dlg->s) exclude_from_set(&dlg->s, xx, *y, xx + www, *y + G_BFU_FONT_SIZE);
|
|
if (!r) mem_free(txt);
|
|
}
|
|
if (www > w) www = w;
|
|
if (rw && www > *rw) *rw = www;
|
|
*y += G_BFU_FONT_SIZE;
|
|
if (!r) goto new_ln;
|
|
}
|
|
#endif
|
|
return xx - x;
|
|
}
|
|
|
|
void max_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, int *width)
|
|
{
|
|
int w = gf_val(-2, -G_DIALOG_BUTTON_SPACE);
|
|
int i;
|
|
if (term->spec->braille) *width = term->x;
|
|
for (i = 0; i < n; i++) w += txtlen(term, get_text_translation((butt++)->item->text, term)) + gf_val(6, G_DIALOG_BUTTON_SPACE + txtlen(term, cast_uchar G_DIALOG_BUTTON_L) + txtlen(term, cast_uchar G_DIALOG_BUTTON_R));
|
|
if (w > *width) *width = w;
|
|
}
|
|
|
|
void min_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n, int *width)
|
|
{
|
|
int i;
|
|
if (term->spec->braille) *width = term->x;
|
|
for (i = 0; i < n; i++) {
|
|
int w = txtlen(term, get_text_translation((butt++)->item->text, term)) + gf_val(4, txtlen(term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)));
|
|
if (w > *width) *width = w;
|
|
}
|
|
}
|
|
|
|
void dlg_format_buttons(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *butt, int n, int x, int *y, int w, int *rw, int align)
|
|
{
|
|
int i1 = 0;
|
|
if (dlg->win->term->spec->braille) w = dlg->win->term->x;
|
|
while (i1 < n) {
|
|
int i2 = i1 + 1;
|
|
int mw;
|
|
while (i2 < n) {
|
|
mw = 0;
|
|
max_buttons_width(dlg->win->term, butt + i1, i2 - i1 + 1, &mw);
|
|
if (mw <= w) i2++;
|
|
else break;
|
|
}
|
|
mw = 0;
|
|
max_buttons_width(dlg->win->term, butt + i1, i2 - i1, &mw);
|
|
if (rw && mw > *rw) if ((*rw = mw) > w) *rw = w;
|
|
if (term) {
|
|
int i;
|
|
int p = x + ((align & AL_MASK) == AL_CENTER ? (w - mw) / 2 : 0);
|
|
for (i = i1; i < i2; i++) {
|
|
butt[i].x = p;
|
|
butt[i].y = *y;
|
|
p += (butt[i].l = txtlen(dlg->win->term, get_text_translation(butt[i].item->text, dlg->win->term)) + gf_val(4, txtlen(dlg->win->term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) + gf_val(2, G_DIALOG_BUTTON_SPACE);
|
|
}
|
|
}
|
|
*y += 2 * LL;
|
|
i1 = i2;
|
|
}
|
|
}
|
|
|
|
void dlg_format_checkbox(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *chkb, int x, int *y, int w, int *rw, unsigned char *text)
|
|
{
|
|
int k = gf_val(4, txtlen(dlg->win->term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE);
|
|
if (term) {
|
|
chkb->x = x;
|
|
chkb->y = *y;
|
|
}
|
|
if (rw) *rw -= k;
|
|
dlg_format_text(dlg, term, text, x + k, y, w - k, rw, COLOR_DIALOG_CHECKBOX_TEXT, AL_LEFT | AL_NOBRLEXP);
|
|
if (rw) *rw += k;
|
|
}
|
|
|
|
void dlg_format_checkboxes(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *chkb, int n, int x, int *y, int w, int *rw, unsigned char * const *texts)
|
|
{
|
|
if (dlg->win->term->spec->braille) w = dlg->win->term->x;
|
|
while (n) {
|
|
dlg_format_checkbox(dlg, term, chkb, x, y, w, rw, texts[0]);
|
|
texts++; chkb++; n--;
|
|
}
|
|
}
|
|
|
|
void checkboxes_width(struct terminal *term, unsigned char * const *texts, int n, int *w, void (*fn)(struct terminal *, unsigned char *, int *, int))
|
|
{
|
|
int k = gf_val(4, txtlen(term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE);
|
|
while (n--) {
|
|
*w -= k;
|
|
fn(term, get_text_translation(texts[0], term), w, 0);
|
|
*w += k;
|
|
texts++;
|
|
}
|
|
}
|
|
|
|
void dlg_format_field(struct dialog_data *dlg, struct terminal *term, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align)
|
|
{
|
|
if (dlg->win->term->spec->braille) w = dlg->win->term->x;
|
|
if (term) {
|
|
int l = gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
|
|
item->x = x;
|
|
item->y = *y;
|
|
item->l = w;
|
|
if (item->l > l)
|
|
item->l = l;
|
|
if (rw && item->l > *rw) *rw = item->l;
|
|
}
|
|
(*y) += LL;
|
|
}
|
|
|
|
void dlg_format_text_and_field(struct dialog_data *dlg, struct terminal *term, unsigned char *text, struct dialog_item_data *item, int x, int *y, int w, int *rw, unsigned char co, int align)
|
|
{
|
|
if (!dlg->win->term->spec->braille) {
|
|
dlg_format_text(dlg, term, text, x, y, w, rw, co, align);
|
|
dlg_format_field(dlg, term, item, x, y, w, rw, align);
|
|
} else {
|
|
int pos = dlg_format_text(dlg, term, text, x, y, w, rw, co, align);
|
|
if (pos >= w - 4) (*y)++, pos = 0;
|
|
if (term) {
|
|
item->x = x + pos;
|
|
item->y = *y - 1;
|
|
item->l = w - pos;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
/* Layout for generic boxes */
|
|
void dlg_format_box(struct terminal *term, struct terminal *t2, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align) {
|
|
item->x = x;
|
|
item->y = *y;
|
|
item->l = w;
|
|
if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w;
|
|
(*y) += item->item->gid;
|
|
}
|
|
#endif
|
|
|
|
void max_group_width(struct terminal *term, unsigned char * const *texts, struct dialog_item_data *item, int n, int *w)
|
|
{
|
|
int ww = 0;
|
|
if (term->spec->braille) *w = term->x;
|
|
while (n--) {
|
|
int wx = item->item->type == D_CHECKBOX ? gf_val(4, txtlen(term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE) :
|
|
item->item->type == D_BUTTON ? txtlen(term, get_text_translation(item->item->text, term)) + (gf_val(4, txtlen(term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) :
|
|
gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
|
|
wx += txtlen(term, get_text_translation(texts[0], term)) + gf_val(1, G_DIALOG_GROUP_TEXT_SPACE);
|
|
if (n) gf_val(wx++, wx += G_DIALOG_GROUP_SPACE);
|
|
ww += wx;
|
|
texts++;
|
|
item++;
|
|
}
|
|
if (ww > *w) *w = ww;
|
|
}
|
|
|
|
void min_group_width(struct terminal *term, unsigned char * const *texts, struct dialog_item_data *item, int n, int *w)
|
|
{
|
|
if (term->spec->braille) *w = term->x;
|
|
while (n--) {
|
|
int wx = item->item->type == D_CHECKBOX ? gf_val(4, txtlen(term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_CHECKBOX_SPACE) :
|
|
item->item->type == D_BUTTON ? txtlen(term, get_text_translation(item->item->text, term)) + (gf_val(4, txtlen(term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) :
|
|
gf_val(item->item->dlen + 1, (item->item->dlen + 1) * G_DIALOG_FIELD_WIDTH);
|
|
wx += txtlen(term, get_text_translation(texts[0], term));
|
|
if (wx > *w) *w = wx;
|
|
texts++;
|
|
item++;
|
|
}
|
|
}
|
|
|
|
void dlg_format_group(struct dialog_data *dlg, struct terminal *term, unsigned char * const *texts, struct dialog_item_data *item, int n, int x, int *y, int w, int *rw)
|
|
{
|
|
int f = 1;
|
|
int nx = 0;
|
|
if (dlg->win->term->spec->braille) w = dlg->win->term->x;
|
|
while (n--) {
|
|
int wx = item->item->type == D_CHECKBOX ? gf_val(3, txtlen(dlg->win->term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R))) :
|
|
item->item->type == D_BUTTON ? txtlen(dlg->win->term, get_text_translation(item->item->text, dlg->win->term)) + (gf_val(4, txtlen(dlg->win->term, cast_uchar(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R)))) :
|
|
gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
|
|
int sl;
|
|
if (get_text_translation(texts[0], dlg->win->term)[0]) sl = txtlen(dlg->win->term, get_text_translation(texts[0], dlg->win->term)) + gf_val(1, G_DIALOG_GROUP_TEXT_SPACE);
|
|
else sl = 0;
|
|
wx += sl;
|
|
if (dlg->win->term->spec->braille) {
|
|
if (!f) {
|
|
nx = 0;
|
|
(*y) += LL;
|
|
} else f = 0;
|
|
} else if (nx && nx + wx > w) {
|
|
nx = 0;
|
|
(*y) += 2 * LL;
|
|
}
|
|
if (term) {
|
|
if (!F) print_text(term, x + nx + 4 * (item->item->type == D_CHECKBOX), *y, ttxtlen(term, get_text_translation(texts[0], dlg->win->term)), get_text_translation(texts[0], dlg->win->term), COLOR_DIALOG_TEXT);
|
|
#ifdef G
|
|
else {
|
|
int l, ll;
|
|
l = ll = x + nx + (item->item->type == D_CHECKBOX ? txtlen(dlg->win->term, cast_uchar(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) + G_DIALOG_GROUP_TEXT_SPACE : 0);
|
|
g_print_text(term->dev, ll, *y, bfu_style_bw, get_text_translation(texts[0], dlg->win->term), &ll);
|
|
exclude_from_set(&dlg->s, l, *y, ll, *y + G_BFU_FONT_SIZE);
|
|
}
|
|
#endif
|
|
item->x = x + nx + sl * (item->item->type != D_CHECKBOX);
|
|
item->y = *y;
|
|
if (item->item->type == D_FIELD || item->item->type == D_FIELD_PASS) item->l = gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH);
|
|
}
|
|
if (rw && nx + wx > *rw) if ((*rw = nx + wx) > w) *rw = w;
|
|
nx += wx + gf_val(1, G_DIALOG_GROUP_SPACE);
|
|
texts++;
|
|
item++;
|
|
}
|
|
(*y) += LL;
|
|
}
|
|
|
|
void checkbox_list_fn(struct dialog_data *dlg)
|
|
{
|
|
struct terminal *term = dlg->win->term;
|
|
int n_checkboxes;
|
|
int max = 0, min = 0;
|
|
int w, rw;
|
|
int y = 0;
|
|
for (n_checkboxes = 0; ((unsigned char **)dlg->dlg->udata)[n_checkboxes]; n_checkboxes++)
|
|
;
|
|
checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &max, max_text_width);
|
|
checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &min, min_text_width);
|
|
max_buttons_width(term, dlg->items + n_checkboxes, dlg->n - n_checkboxes, &max);
|
|
min_buttons_width(term, dlg->items + n_checkboxes, dlg->n - n_checkboxes, &min);
|
|
w = term->x * 9 / 10 - 2 * DIALOG_LB;
|
|
if (w > max) w = max;
|
|
if (w < min) w = min;
|
|
if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
|
|
if (w < 5) w = 5;
|
|
rw = 0;
|
|
dlg_format_checkboxes(dlg, NULL, dlg->items, n_checkboxes, 0, &y, w, &rw, dlg->dlg->udata);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, NULL, dlg->items + n_checkboxes, dlg->n - n_checkboxes, 0, &y, w, &rw, AL_CENTER);
|
|
w = rw;
|
|
dlg->xw = rw + 2 * DIALOG_LB;
|
|
dlg->yw = y + 2 * DIALOG_TB;
|
|
center_dlg(dlg);
|
|
draw_dlg(dlg);
|
|
y = dlg->y + DIALOG_TB + LL;
|
|
dlg_format_checkboxes(dlg, term, dlg->items, n_checkboxes, dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, term, dlg->items + n_checkboxes, dlg->n - n_checkboxes, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
|
|
}
|
|
|
|
void group_fn(struct dialog_data *dlg)
|
|
{
|
|
struct terminal *term = dlg->win->term;
|
|
int max = 0, min = 0;
|
|
int w, rw;
|
|
int y = 0;
|
|
max_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &max);
|
|
min_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &min);
|
|
max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
|
|
min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
|
|
w = term->x * 9 / 10 - 2 * DIALOG_LB;
|
|
if (w > max) w = max;
|
|
if (w < min) w = min;
|
|
if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
|
|
if (w < 1) w = 1;
|
|
rw = 0;
|
|
dlg_format_group(dlg, NULL, dlg->dlg->udata, dlg->items, dlg->n - 2, 0, &y, w, &rw);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, NULL, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, AL_CENTER);
|
|
w = rw;
|
|
dlg->xw = rw + 2 * DIALOG_LB;
|
|
dlg->yw = y + 2 * DIALOG_TB;
|
|
center_dlg(dlg);
|
|
draw_dlg(dlg);
|
|
y = dlg->y + DIALOG_TB + LL;
|
|
dlg_format_group(dlg, term, dlg->dlg->udata, dlg->items, dlg->n - 2, dlg->x + DIALOG_LB, &y, w, NULL);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, term, dlg->items + dlg->n - 2, 2, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
|
|
}
|
|
|
|
void msg_box_fn(struct dialog_data *dlg)
|
|
{
|
|
struct terminal *term = dlg->win->term;
|
|
int max = 0, min = 0;
|
|
int w, rw;
|
|
int y = 0;
|
|
unsigned char **ptr;
|
|
unsigned char *text = init_str();
|
|
int textl = 0;
|
|
for (ptr = dlg->dlg->udata; *ptr; ptr++) add_to_str(&text, &textl, get_text_translation(*ptr, term));
|
|
max_text_width(term, text, &max, dlg->dlg->align);
|
|
min_text_width(term, text, &min, dlg->dlg->align);
|
|
max_buttons_width(term, dlg->items, dlg->n, &max);
|
|
min_buttons_width(term, dlg->items, dlg->n, &min);
|
|
w = term->x * 9 / 10 - 2 * DIALOG_LB;
|
|
if (w > max) w = max;
|
|
if (w < min) w = min;
|
|
if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
|
|
if (w < 1) w = 1;
|
|
rw = 0;
|
|
dlg_format_text(dlg, NULL, text, 0, &y, w, &rw, COLOR_DIALOG_TEXT, dlg->dlg->align);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, NULL, dlg->items, dlg->n, 0, &y, w, &rw, AL_CENTER);
|
|
w = rw;
|
|
dlg->xw = rw + 2 * DIALOG_LB;
|
|
dlg->yw = y + 2 * DIALOG_TB;
|
|
center_dlg(dlg);
|
|
draw_dlg(dlg);
|
|
y = dlg->y + DIALOG_TB + LL;
|
|
dlg_format_text(dlg, term, text, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, dlg->dlg->align);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, term, dlg->items, dlg->n, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
|
|
mem_free(text);
|
|
}
|
|
|
|
static int msg_box_button(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
msg_button_fn msg_fn = di->item->u.msg_fn;
|
|
void *data = dlg->dlg->udata2;
|
|
msg_fn(data);
|
|
cancel_dialog(dlg, di);
|
|
return 0;
|
|
}
|
|
|
|
void msg_box_null(void *data)
|
|
{
|
|
}
|
|
|
|
/* coverity[+free : arg-1] */
|
|
void msg_box(struct terminal *term, struct memory_list *ml, unsigned char *title, int align, /*unsigned char *text, ..., void *data, int n,*/ ...)
|
|
{
|
|
struct dialog *dlg;
|
|
int i;
|
|
int n;
|
|
unsigned char *text;
|
|
unsigned char **udata;
|
|
void *udata2;
|
|
int udatan;
|
|
va_list ap;
|
|
va_start(ap, align);
|
|
udata = DUMMY;
|
|
udatan = 0;
|
|
do {
|
|
text = va_arg(ap, unsigned char *);
|
|
udatan++;
|
|
if ((unsigned)udatan > MAXINT / sizeof(unsigned char *)) overalloc();
|
|
udata = mem_realloc(udata, udatan * sizeof(unsigned char *));
|
|
udata[udatan - 1] = text;
|
|
} while (text);
|
|
udata2 = va_arg(ap, void *);
|
|
n = va_arg(ap, int);
|
|
if ((unsigned)n > (MAXINT - sizeof(struct dialog)) / sizeof(struct dialog_item) - 1) overalloc();
|
|
dlg = mem_calloc(sizeof(struct dialog) + (n + 1) * sizeof(struct dialog_item));
|
|
dlg->title = title;
|
|
dlg->fn = msg_box_fn;
|
|
dlg->udata = udata;
|
|
dlg->udata2 = udata2;
|
|
dlg->align = align;
|
|
for (i = 0; i < n; i++) {
|
|
unsigned char *m;
|
|
msg_button_fn msg_fn;
|
|
int flags;
|
|
m = va_arg(ap, unsigned char *);
|
|
msg_fn = va_arg(ap, msg_button_fn);
|
|
flags = va_arg(ap, int);
|
|
if (!m) {
|
|
i--, n--;
|
|
continue;
|
|
}
|
|
dlg->items[i].type = D_BUTTON;
|
|
dlg->items[i].gid = flags;
|
|
dlg->items[i].fn = msg_box_button;
|
|
dlg->items[i].dlen = 0;
|
|
dlg->items[i].text = m;
|
|
dlg->items[i].u.msg_fn = msg_fn;
|
|
}
|
|
va_end(ap);
|
|
dlg->items[i].type = D_END;
|
|
add_to_ml(&ml, dlg, udata, NULL);
|
|
do_dialog(term, dlg, ml);
|
|
}
|
|
|
|
void add_to_history(struct terminal *term, struct history *h, unsigned char *t)
|
|
{
|
|
unsigned char *s;
|
|
struct history_item *hi, *hs;
|
|
struct list_head *lhs;
|
|
size_t l;
|
|
if (!h || !t || !*t) return;
|
|
if (term) {
|
|
s = convert(term_charset(term), utf8_table, t, NULL);
|
|
} else {
|
|
s = t;
|
|
}
|
|
l = strlen(cast_const_char s);
|
|
if (l > MAXINT - sizeof(struct history_item)) overalloc();
|
|
hi = mem_alloc(sizeof(struct history_item) + l);
|
|
memcpy(hi->str, s, l + 1);
|
|
if (term)
|
|
mem_free(s);
|
|
if (term) foreach(struct history_item, hs, lhs, h->items) if (!strcmp(cast_const_char hs->str, cast_const_char hi->str)) {
|
|
lhs = lhs->prev;
|
|
del_from_list(hs);
|
|
mem_free(hs);
|
|
h->n--;
|
|
}
|
|
add_to_list(h->items, hi);
|
|
h->n++;
|
|
while (h->n > MAX_HISTORY_ITEMS) {
|
|
struct history_item *hd;
|
|
if (list_empty(h->items)) {
|
|
internal_error("history is empty");
|
|
h->n = 0;
|
|
return;
|
|
}
|
|
hd = list_struct(h->items.prev, struct history_item);
|
|
del_from_list(hd);
|
|
mem_free(hd);
|
|
h->n--;
|
|
}
|
|
}
|
|
|
|
static int input_field_cancel(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
input_field_button_fn fn = di->item->u.input_fn;
|
|
void *data = dlg->dlg->udata2;
|
|
unsigned char *text = dlg->items->cdata;
|
|
fn(data, text);
|
|
cancel_dialog(dlg, di);
|
|
return 0;
|
|
}
|
|
|
|
static int input_field_ok(struct dialog_data *dlg, struct dialog_item_data *di)
|
|
{
|
|
input_field_button_fn fn = di->item->u.input_fn;
|
|
void *data = dlg->dlg->udata2;
|
|
unsigned char *text = dlg->items->cdata;
|
|
if (check_dialog(dlg)) return 1;
|
|
add_to_history(dlg->win->term, dlg->dlg->items->history, text);
|
|
fn(data, text);
|
|
ok_dialog(dlg, di);
|
|
return 0;
|
|
}
|
|
|
|
static void input_field_fn(struct dialog_data *dlg)
|
|
{
|
|
struct terminal *term = dlg->win->term;
|
|
int max = 0, min = 0;
|
|
int w, rw;
|
|
int y = gf_val(-1, -G_BFU_FONT_SIZE);
|
|
if (dlg->win->term->spec->braille) y += LL;
|
|
max_text_width(term, dlg->dlg->udata, &max, AL_LEFT);
|
|
min_text_width(term, dlg->dlg->udata, &min, AL_LEFT);
|
|
max_buttons_width(term, dlg->items + 1, dlg->n - 1, &max);
|
|
min_buttons_width(term, dlg->items + 1, dlg->n - 1, &min);
|
|
if (max < dlg->dlg->items->dlen) max = dlg->dlg->items->dlen;
|
|
w = term->x * 9 / 10 - 2 * DIALOG_LB;
|
|
if (w > max) w = max;
|
|
if (w < min) w = min;
|
|
rw = w;
|
|
dlg_format_text_and_field(dlg, NULL, dlg->dlg->udata, dlg->items, 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, NULL, dlg->items + 1, dlg->n - 1, 0, &y, w, &rw, AL_CENTER);
|
|
w = rw;
|
|
dlg->xw = rw + 2 * DIALOG_LB;
|
|
dlg->yw = y + 2 * DIALOG_TB;
|
|
center_dlg(dlg);
|
|
draw_dlg(dlg);
|
|
y = dlg->y + DIALOG_TB;
|
|
if (dlg->win->term->spec->braille) y += LL;
|
|
dlg_format_text_and_field(dlg, term, dlg->dlg->udata, dlg->items, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
|
|
y += LL;
|
|
dlg_format_buttons(dlg, term, dlg->items + 1, dlg->n - 1, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
|
|
}
|
|
|
|
void input_field_null(void *d_, unsigned char *s_)
|
|
{
|
|
}
|
|
|
|
/* coverity[+free : arg-1] */
|
|
void input_field(struct terminal *term, struct memory_list *ml, unsigned char *title, unsigned char *text, void *data, struct history *history, int l, unsigned char *def, int min, int max, int (*check)(struct dialog_data *, struct dialog_item_data *), int n, ...)
|
|
{
|
|
struct dialog *dlg;
|
|
unsigned char *field;
|
|
va_list va;
|
|
int i;
|
|
if ((unsigned)n > MAXINT / sizeof(struct dialog_item) - 2) overalloc();
|
|
if ((unsigned)l > MAXINT - sizeof(struct dialog) - (2 + n) * sizeof(struct dialog_item)) overalloc();
|
|
dlg = mem_calloc(sizeof(struct dialog) + (2 + n) * sizeof(struct dialog_item) + l);
|
|
*(field = (unsigned char *)dlg + sizeof(struct dialog) + (2 + n) * sizeof(struct dialog_item)) = 0;
|
|
if (def) {
|
|
if (strlen(cast_const_char def) + 1 > (size_t)l) memcpy(field, def, l - 1);
|
|
else strcpy(cast_char field, cast_const_char def);
|
|
}
|
|
dlg->title = title;
|
|
dlg->fn = input_field_fn;
|
|
dlg->udata = text;
|
|
dlg->udata2 = data;
|
|
dlg->items[0].type = D_FIELD;
|
|
dlg->items[0].gid = min;
|
|
dlg->items[0].gnum = max;
|
|
dlg->items[0].fn = check;
|
|
dlg->items[0].history = history;
|
|
dlg->items[0].dlen = l;
|
|
dlg->items[0].data = field;
|
|
va_start(va, n);
|
|
for (i = 1; i <= n; i++) {
|
|
dlg->items[i].type = D_BUTTON;
|
|
dlg->items[i].gid = i == 1 ? B_ENTER : i == n ? B_ESC : 0;
|
|
dlg->items[i].fn = i != n || n == 1 ? input_field_ok : input_field_cancel;
|
|
dlg->items[i].dlen = 0;
|
|
dlg->items[i].text = va_arg(va, unsigned char *);
|
|
dlg->items[i].u.input_fn = va_arg(va, input_field_button_fn);
|
|
}
|
|
va_end(va);
|
|
|
|
dlg->items[i].type = D_END;
|
|
add_to_ml(&ml, dlg, NULL);
|
|
do_dialog(term, dlg, ml);
|
|
}
|
|
|
|
int find_msg_box(struct terminal *term, unsigned char *title, int (*sel)(void *, void *), void *data)
|
|
{
|
|
struct window *win;
|
|
struct list_head *lwin;
|
|
foreach(struct window, win, lwin, term->windows) if (win->handler == dialog_func) {
|
|
struct dialog_data *dd = win->data;
|
|
struct dialog *d = dd->dlg;
|
|
if (d->fn != msg_box_fn)
|
|
continue;
|
|
if (d->title == title) {
|
|
if (sel && !sel(data, d->udata2))
|
|
continue;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|