/* bfu.c * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */ #include "links.h" int menu_font_size=G_BFU_DEFAULT_FONT_SIZE; unsigned long G_BFU_FG_COLOR; unsigned long G_BFU_BG_COLOR; unsigned long G_SCROLL_BAR_AREA_COLOR; unsigned long G_SCROLL_BAR_BAR_COLOR; unsigned long G_SCROLL_BAR_FRAME_COLOR; 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) n++, q = va_arg(ap, void *); if (!(ml = mem_alloc(sizeof(struct memory_list) + n * sizeof(void *)))) { va_end(ap); return NULL; } 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) { if (!(*ml = mem_alloc(sizeof(struct memory_list)))) return; (*ml)->n = 0; } va_start(ap, ml); while ((q = va_arg(ap, void *))) n++; if (!(nml = mem_realloc(*ml, sizeof(struct memory_list) + (n + (*ml)->n) * sizeof(void *)))) { va_end(ap); return; } 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); } #ifndef G #define txtlen strlen #else #define txtlen(x) (F ? g_text_width(bfu_style_wb, x) : strlen(x)) #endif #ifdef G int is_in_str(unsigned char *str, int u) { while (*str) { int v; GET_UTF_8(str, v); if (u >= 'a' && u <= 'z') u -= 'a' - 'A'; if (v >= 'a' && v <= 'z') v -= 'a' - 'A'; if (u == v) return 1; } return 0; } #endif #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; int G_DIALOG_FIELD_WIDTH; void init_bfu() { 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, G_BFU_DEFAULT_FONT, 0); bfu_style_wb_b = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, G_BFU_DEFAULT_FONT, 0); bfu_style_bw = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, G_BFU_DEFAULT_FONT, 0); bfu_style_bw_u = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, G_BFU_DEFAULT_FONT, FF_UNDERLINE); bfu_style_bw_mono = g_get_style(G_BFU_FG_COLOR, G_BFU_BG_COLOR, G_BFU_FONT_SIZE, "monospaced", 0); bfu_style_wb_mono = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, "monospaced", 0); bfu_style_wb_mono_u = g_get_style(G_BFU_BG_COLOR, G_BFU_FG_COLOR, G_BFU_FONT_SIZE, "monospaced", FF_UNDERLINE); G_DIALOG_FIELD_WIDTH = g_char_width(bfu_style_wb_mono, ' '); } void shutdown_bfu() { 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 shutdown_bfu() {} #endif void iinit_bfu() { G_BFU_FG_COLOR=G_DEFAULT_BFU_FG_COLOR; G_BFU_BG_COLOR=G_DEFAULT_BFU_BG_COLOR; G_SCROLL_BAR_AREA_COLOR=G_DEFAULT_SCROLL_BAR_AREA_COLOR; G_SCROLL_BAR_BAR_COLOR=G_DEFAULT_SCROLL_BAR_BAR_COLOR; G_SCROLL_BAR_FRAME_COLOR=G_DEFAULT_SCROLL_BAR_FRAME_COLOR; } unsigned char m_bar = 0; void menu_func(struct window *, struct event *, int); void mainmenu_func(struct window *, struct event *, int); void dialog_func(struct window *, struct event *, int); void do_menu_selected(struct terminal *term, struct menu_item *items, void *data, int selected) { struct menu *menu; if ((menu = mem_alloc(sizeof(struct menu)))) { menu->selected = selected; menu->view = 0; menu->items = items; menu->data = data; #ifdef G if (F) { int n, i; for (n = 0; items[n].text; n++) ; if (!(menu->hktxt1 = mem_calloc(n * sizeof(unsigned char *)))) { mem_free(menu); goto b; } if (!(menu->hktxt2 = mem_calloc(n * sizeof(unsigned char *)))) { mem_free(menu->hktxt1); mem_free(menu); goto b; } if (!(menu->hktxt3 = mem_calloc(n * sizeof(unsigned char *)))) { mem_free(menu->hktxt2); mem_free(menu->hktxt1); mem_free(menu); goto b; } for (i = 0; i < n; i++) { unsigned char *txt = _(items[i].text, term); unsigned char *ext = _(items[i].hotkey, term); unsigned char *txt2, *txt3 = txt; if (ext != M_BAR) while (*txt3) { int u; txt2 = txt3; GET_UTF_8(txt3, u); if (is_in_str(ext, u)) { 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(""); menu->hktxt3[i] = stracpy(""); x:; } } #endif add_window(term, menu_func, menu); } else #ifdef G b: #endif if (items->free_i) { int i; for (i = 0; items[i].text; i++) { if (items[i].free_i & 2) mem_free(items[i].text); if (items[i].free_i & 4) mem_free(items[i].rtext); } mem_free(items); } } void do_menu(struct terminal *term, struct menu_item *items, void *data) { do_menu_selected(term, items, data, 0); } void select_menu(struct terminal *term, struct menu *menu) { struct menu_item *it = &menu->items[menu->selected]; void (*func)(struct terminal *, void *, void *) = it->func; void *data1 = it->data; void *data2 = menu->data; if (menu->selected < 0 || menu->selected >= menu->ni || it->hotkey == M_BAR) return; if (!it->in_m) { struct window *win, *win1; for (win = term->windows.next; (void *)win != &term->windows && (win->handler == menu_func || win->handler == mainmenu_func); win1 = win->next, delete_window(win), win = win1) ; } func(term, data1, data2); } 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; menu->items[my].text; my++) { int s = txtlen(_(menu->items[my].text, term)) + txtlen(_(menu->items[my].rtext, term)) + gf_val(MENU_HOTKEY_SPACE, G_MENU_HOTKEY_SPACE) * (_(menu->items[my].rtext, term)[0] != 0) + gf_val(4, 2 * (G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER)); if (s > mx) mx = s; } menu->ni = my; 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; #ifdef G if (F) set_window_pos(menu->win, menu->x, menu->y, menu->x + menu->xw, menu->y + menu->yw); #endif } 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; } void display_menu_txt(struct terminal *term, struct menu *menu) { int p, s; fill_area(term, menu->x+1, menu->y+1, menu->xw-2, menu->yw-2, COLOR_MENU); 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 char c; unsigned char *tmptext = _(menu->items[p].text, term); int co = p == menu->selected ? h = 1, COLOR_MENU_SELECTED : COLOR_MENU; if (h) { set_cursor(term, menu->x+1, 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 (menu->items[p].hotkey != M_BAR || (tmptext[0])) { int l = strlen(_(menu->items[p].rtext, term)); for (x = l - 1; x >= 0 && menu->xw - 4 >= l - x && (c = _(menu->items[p].rtext, term)[x]); x--) set_char(term, menu->x + menu->xw - 2 - l + x, s, c | co); for (x = 0; x < menu->xw - 4 && (c = tmptext[x]); x++) set_char(term, menu->x + x + 2, s, !h && strchr(_(menu->items[p].hotkey, term), upcase(c)) ? h = 1, COLOR_MENU_HOTKEY | c : co | c); } else { set_char(term, menu->x, s, COLOR_MENU_FRAME | ATTR_FRAME | 0xc3); fill_area(term, menu->x+1, s, menu->xw-2, 1, COLOR_MENU_FRAME | ATTR_FRAME | 0xc4); set_char(term, menu->x+menu->xw-1, s, COLOR_MENU_FRAME | ATTR_FRAME | 0xb4); } } } int menu_oldview = -1; int menu_oldsel = -1; #ifdef G int menu_ptr_set; 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 && !_(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 = _(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) { p = menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER; g_print_text(drv, dev, p, y, bfu_style_wb, menu->hktxt1[it], &p); g_print_text(drv, dev, p, y, bfu_style_wb, menu->hktxt2[it], &p); g_print_text(drv, dev, p, y, bfu_style_wb, menu->hktxt3[it], &p); } else { p = menu->x + G_MENU_LEFT_BORDER + G_MENU_LEFT_INNER_BORDER; g_print_text(drv, dev, p, y, bfu_style_bw, menu->hktxt1[it], &p); g_print_text(drv, dev, p, y, bfu_style_bw_u, menu->hktxt2[it], &p); g_print_text(drv, dev, p, y, bfu_style_bw, menu->hktxt3[it], &p); } if (!*rtext) { drv->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(drv, dev, s, y, it != menu->selected ? bfu_style_bw : bfu_style_wb, rtext, NULL); drv->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); } } } void display_menu_gfx(struct terminal *term, 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 void menu_func(struct window *win, struct event *ev, int fwd) { int s = 0; int xp, yp; struct menu *menu = win->data; struct window *w1; menu->win = win; switch (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, (void (*)(struct terminal *, void *))gf_val(display_menu_txt, display_menu_gfx), menu); break; case EV_MOUSE: if ((ev->b & BM_ACT) == B_MOVE) 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; for (w1 = win; (void *)w1 != &win->term->windows; w1 = w1->next) { 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 < gf_val(1, G_BFU_FONT_SIZE)) { del:delete_window_ev(win, ev); goto bbb; } 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; bbb:; } 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, (void (*)(struct terminal *, void *))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->x == KBD_LEFT || ev->x == KBD_RIGHT) { if ((void *)win->next != &win->term->windows && win->next->handler == mainmenu_func) goto mm; /*for (w1 = win; (void *)w1 != &win->term->windows; w1 = w1->next) { if (w1->handler == mainmenu_func) goto mm; if (w1->handler != menu_func) break; }*/ if (ev->x == KBD_RIGHT) goto enter; delete_window(win); break; } if ((ev->x >= KBD_F1 && ev->x <= KBD_F12) || ev->y == KBD_ALT) { mm: delete_window_ev(win, ev); break; } if (ev->x == KBD_ESC) { delete_window_ev(win, (void *)win->next != &win->term->windows && win->next->handler == mainmenu_func ? ev : NULL); break; } menu_oldview = menu->view; menu_oldsel = menu->selected; if (ev->x == KBD_UP) scroll_menu(menu, -1); if (ev->x == KBD_DOWN) scroll_menu(menu, 1); if (ev->x == KBD_HOME) menu->selected = -1, scroll_menu(menu, 1); if (ev->x == KBD_END) menu->selected = menu->ni, scroll_menu(menu, -1); if (ev->x == KBD_PAGE_UP) { if ((menu->selected -= menu->yw / gf_val(1, G_BFU_FONT_SIZE) - 3) < -1) menu->selected = -1; if ((menu->view -= menu->yw / gf_val(1, G_BFU_FONT_SIZE) - 2) < 0) menu->view = 0; scroll_menu(menu, -1); } if (ev->x == KBD_PAGE_DOWN) { if ((menu->selected += menu->yw / gf_val(1, G_BFU_FONT_SIZE) - 3) > menu->ni) menu->selected = menu->ni; if ((menu->view += menu->yw / gf_val(1, G_BFU_FONT_SIZE) - 2) >= menu->ni - menu->yw + 2) menu->view = menu->ni - menu->yw + 2; scroll_menu(menu, 1); } if (ev->x > ' ' && ev->x < 256) { int i; for (i = 0; i < menu->ni; i++) if (strchr(_(menu->items[i].hotkey, win->term), upcase(ev->x))) { menu->selected = i; scroll_menu(menu, 0); s = 1; } } draw_to_window(win, (void (*)(struct terminal *, void *))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; menu->items[i].text; 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; menu->items[i].text; i++) { if (menu->items[i].free_i & 2) mem_free(menu->items[i].text); if (menu->items[i].free_i & 4) mem_free(menu->items[i].rtext); } mem_free(menu->items); } break; } } void do_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel) { struct mainmenu *menu; if ((menu = mem_alloc(sizeof(struct mainmenu)))) { menu->selected = sel == -1 ? 0 : sel; menu->items = items; menu->data = data; add_window(term, mainmenu_func, menu); if (sel != -1) { struct event ev = {EV_KBD, KBD_ENTER, 0, 0}; struct window *win = term->windows.next; win->handler(win, &ev, 0); } } } void display_mainmenu(struct terminal *term, struct mainmenu *menu) { if (!F) { int i; int p = 2; fill_area(term, 0, 0, term->x, 1, COLOR_MAINMENU | ' '); for (i = 0; menu->items[i].text; i++) { int s = 0; int j; unsigned char c; unsigned char *tmptext = _(menu->items[i].text, term); int co = i == menu->selected ? s = 1, COLOR_MAINMENU_SELECTED : COLOR_MAINMENU; if (s) { fill_area(term, p, 0, 2, 1, co); fill_area(term, p+strlen(tmptext)+2, 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); } p += 2; for (j = 0; (c = tmptext[j]); j++, p++) set_char(term, p, 0, (!s && strchr(_(menu->items[i].hotkey, term), upcase(c)) ? s = 1, COLOR_MAINMENU_HOTKEY : co) | c); p += 2; } menu->ni = i; #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; menu->items[i].text; i++) { int s = i == menu->selected; unsigned char *text = _(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(drv, 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); menu->ni = i; #endif } } void select_mainmenu(struct terminal *term, struct mainmenu *menu) { struct menu_item *it = &menu->items[menu->selected]; if (menu->selected < 0 || menu->selected >= menu->ni || it->hotkey == M_BAR) return; if (!it->in_m) { struct window *win; for (win = term->windows.next; (void *)win != &term->windows && (win->handler == menu_func || win->handler == mainmenu_func); delete_window(win)) ; } it->func(term, it->data, menu->data); } void mainmenu_func(struct window *win, struct event *ev, int fwd) { int s = 0; struct mainmenu *menu = win->data; menu->win = win; switch(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 case EV_REDRAW: draw_to_window(win, (void (*)(struct terminal *, void *))display_mainmenu, menu); break; case EV_MOUSE: if ((ev->b & BM_ACT) == B_MOVE) break; if ((ev->b & BM_ACT) == B_DOWN && ev->y >= gf_val(1, G_BFU_FONT_SIZE)) delete_window_ev(win, ev); else if (ev->y < gf_val(1, G_BFU_FONT_SIZE)) { int i; int p = gf_val(2, G_MAINMENU_LEFT_BORDER); for (i = 0; i < menu->ni; i++) { int o = p; unsigned char *tmptext = _(menu->items[i].text, win->term); p += txtlen(tmptext) + gf_val(4, 2 * G_MAINMENU_BORDER); if (ev->x >= o && ev->x < p) { menu->selected = i; draw_to_window(win, (void (*)(struct terminal *, void *))display_mainmenu, menu); if ((ev->b & BM_ACT) == B_UP || menu->items[s].in_m) select_mainmenu(win->term, menu); break; } } } break; case EV_KBD: if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN || ev->x == KBD_PAGE_UP) { select_mainmenu(win->term, menu); break; } if (ev->x == KBD_LEFT) { if (!menu->selected--) menu->selected = menu->ni - 1; s = 1; } if (ev->x == KBD_RIGHT) { if (++menu->selected >= menu->ni) menu->selected = 0; s = 1; } if (ev->x == KBD_HOME) { menu->selected = 0; s = 1; } if (ev->x == KBD_END) { menu->selected = menu->ni - 1; s = 1; } if ((ev->x == KBD_LEFT || ev->x == KBD_RIGHT) && fwd) { draw_to_window(win, (void (*)(struct terminal *, void *))display_mainmenu, menu); select_mainmenu(win->term, menu); break; } if (ev->x > ' ' && ev->x < 256) { int i; s = 1; for (i = 0; i < menu->ni; i++) if (strchr(_(menu->items[i].hotkey, win->term), upcase(ev->x))) { menu->selected = i; s = 2; } } else if (!s) { delete_window_ev(win, ev->x != KBD_ESC ? ev : NULL); break; } draw_to_window(win, (void (*)(struct terminal *, void *))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; if (!(mi = mem_alloc(sizeof(struct menu_item)))) return NULL; memset(mi, 0, 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) { struct menu_item *mii; int n; for (n = 0; (*mi)[n].text; n++) ; if (!(mii = mem_realloc(*mi, (n + 2) * sizeof(struct menu_item)))) return; *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++) n++; if (!(dd = mem_calloc(sizeof(struct dialog_data) + sizeof(struct dialog_item_data) * n))) return; 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) { int co; unsigned char *text; case D_CHECKBOX: if (di->item->gid) /* radio */ { if (di->checked) print_text(term, di->x, di->y, 3, "[X]", COLOR_DIALOG_CHECKBOX); else print_text(term, di->x, di->y, 3, "[ ]", COLOR_DIALOG_CHECKBOX); } else /* checkbox */ { if (di->checked) print_text(term, di->x, di->y, 3, "[X]", COLOR_DIALOG_CHECKBOX); else print_text(term, di->x, di->y, 3, "[ ]", 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: if (di->vpos + di->l <= di->cpos) di->vpos = di->cpos - di->l + 1; if (di->vpos > di->cpos) di->vpos = di->cpos; if (di->vpos < 0) di->vpos = 0; fill_area(term, di->x, di->y, di->l, 1, COLOR_DIALOG_FIELD); print_text(term, di->x, di->y, strlen(di->cdata + di->vpos) <= di->l ? strlen(di->cdata + di->vpos) : di->l, di->cdata + di->vpos, COLOR_DIALOG_FIELD_TEXT); if (sel) { set_cursor(term, di->x + di->cpos - di->vpos, di->y, di->x + di->cpos - di->vpos, 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 = _(di->item->text, term); print_text(term, di->x, di->y, 2, "[ ", co); print_text(term, di->x + 2, di->y, strlen(text), text, co); print_text(term, di->x + 2 + strlen(text), di->y, 2, " ]", 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("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; struct rect r; case D_CHECKBOX: p = di->x; if (di->checked) { if (!sel) g_print_text(drv, dev, di->x, di->y, bfu_style_bw, di->item->gid?(G_DIALOG_RADIO_L G_DIALOG_RADIO_X G_DIALOG_RADIO_R):(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R), &p); else { g_print_text(drv, dev, di->x, di->y, bfu_style_bw, di->item->gid?G_DIALOG_RADIO_L:G_DIALOG_CHECKBOX_L, &p); g_print_text(drv, dev, p, di->y, bfu_style_bw_u, di->item->gid?G_DIALOG_RADIO_X:G_DIALOG_CHECKBOX_X, &p); g_print_text(drv, dev, p, di->y, bfu_style_bw, di->item->gid?G_DIALOG_RADIO_R:G_DIALOG_CHECKBOX_R, &p); } } else { int s = g_text_width(bfu_style_bw, di->item->gid?G_DIALOG_RADIO_X:G_DIALOG_CHECKBOX_X); g_print_text(drv, dev, di->x, di->y, bfu_style_bw, di->item->gid?G_DIALOG_RADIO_L: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(drv, dev, p, di->y, bfu_style_bw_u, " ", NULL); p += s; drv->set_clip_area(dev, &r); } g_print_text(drv, dev, p, di->y, bfu_style_bw, di->item->gid?G_DIALOG_RADIO_R: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: if (!(text = memacpy(di->cdata, di->cpos))) break; if (*(text2 = text3 = di->cdata + di->cpos)) { GET_UTF_8(text3, p); text2 = memacpy(text2, text3 - text2); } else { text2 = stracpy(" "); text3 = ""; } if (!text2) { mem_free(text); break; } 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(drv, dev, p, di->y, bfu_style_wb_mono, text, &p); g_print_text(drv, dev, p, di->y, sel ? bfu_style_wb_mono_u : bfu_style_wb_mono, text2, &p); g_print_text(drv, 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); drv->set_clip_area(dev, &r); mem_free(text); mem_free(text2); 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 = _(di->item->text, term); if ((text2 = mem_alloc(strlen(text) + 5))) { strcpy(text2, G_DIALOG_BUTTON_L); strcpy(text2 + 2, text); strcat(text2, G_DIALOG_BUTTON_R); di->l = 0; g_print_text(drv, 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("display_dlg_item: unknown item: %d", di->item->type); } if (!dlg->s) drv->set_clip_area(dev, &rr); #endif } } struct dspd { struct dialog_data *dlg; struct dialog_item_data *di; int sel; }; void u_display_dlg_item(struct terminal *term, void *p) { struct dspd *d = p; display_dlg_item(d->dlg, d->di, d->sel); } 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); } 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); } void dlg_set_history(struct dialog_item_data *di) { unsigned char *s = ""; int l; if ((void *)di->cur_hist != &di->history) s = di->cur_hist->d; if ((l = strlen(s)) > di->item->dlen) l = di->item->dlen - 1; memcpy(di->cdata, s, l); di->cdata[l] = 0; di->cpos = l; } int dlg_mouse(struct dialog_data *dlg, struct dialog_item_data *di, struct 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(strlen(_(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 = 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: 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 (!F) { if ((di->cpos = di->vpos + ev->x - di->x) > strlen(di->cdata)) di->cpos = strlen(di->cdata); #ifdef G } else { int p, u; unsigned char *t = di->cdata; p = di->x - di->vpos; while (1) { di->cpos = t - di->cdata; if (!*t) break; GET_UTF_8(t, u); if (!u) continue; p += g_char_width(bfu_style_wb_mono, u); if (p > ev->x) break; } #endif } if (dlg->selected != di - dlg->items) { x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0); dlg->selected = 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 = 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; } void redraw_dialog_items(struct terminal *term, struct dialog_data *dlg) { int i; for (i = 0; i < dlg->n; i++) display_dlg_item(dlg, &dlg->items[i], i == dlg->selected); } void redraw_dialog(struct terminal *term, struct dialog_data *dlg) { #ifdef G int i; #endif dlg->dlg->fn(dlg); redraw_dialog_items(term, dlg); #ifdef G if (F) { drv->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 } void tab_compl(struct terminal *term, unsigned char *item, struct window *win) { struct event ev = {EV_REDRAW, 0, 0, 0}; struct dialog_item_data *di = &((struct dialog_data*)win->data)->items[((struct dialog_data*)win->data)->selected]; int l = strlen(item); if (l >= di->item->dlen) l = di->item->dlen - 1; memcpy(di->cdata, item, l); di->cdata[l] = 0; di->cpos = l; di->vpos = 0; ev.x = term->x; ev.y = term->y; dialog_func(win, &ev, 0); } 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 = strlen(cdata), n = 0; struct history_item *hi; struct menu_item *items = DUMMY, *i; foreach(hi, *history) if (!strncmp(cdata, hi->d, l)) { if (!(n & (ALLOC_GR - 1))) { if (!(i = mem_realloc(items, (n + ALLOC_GR + 1) * sizeof(struct menu_item)))) { mem_free(items); return; } items = i; } items[n].text = hi->d; items[n].rtext = ""; items[n].hotkey = ""; items[n].func = (void(*)(struct terminal *, void *, void *))tab_compl; items[n].rtext = ""; items[n].data = hi->d; items[n].in_m = 0; items[n].free_i = 1; n++; } if (n == 1) { tab_compl(term, items->data, win); mem_free(items); return; } if (n) { memset(&items[n], 0, sizeof(struct menu_item)); do_menu_selected(term, items, win, n - 1); } } void dialog_func(struct window *win, struct 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 (ev->ev) { case EV_INIT: for (i = 0; i < dlg->n; i++) { struct dialog_item_data *di = &dlg->items[i]; memset(di, 0, sizeof(struct dialog_item_data)); di->item = &dlg->dlg->items[i]; if ((di->cdata = mem_alloc(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 = (struct history_item *)&di->history; if (di->item->type == D_FIELD) { if (di->item->history) { struct history_item *j; /*int l = di->item->dlen;*/ foreach(j, di->item->history->items) { struct history_item *hi; if (!(hi = mem_alloc(sizeof(struct history_item) + strlen(j->d) + 1))) continue; strcpy(hi->d, j->d); add_to_list(di->history, hi); } } di->cpos = strlen(di->cdata); } } dlg->selected = 0; case EV_RESIZE: /* this must be really called twice !!! */ draw_to_window(dlg->win, (void (*)(struct terminal *, void *))redraw_dialog, dlg); case EV_REDRAW: draw_to_window(dlg->win, (void (*)(struct terminal *, void *))redraw_dialog, dlg); break; case EV_MOUSE: if ((ev->b & BM_ACT) == B_MOVE) break; for (i = 0; i < dlg->n; i++) if (dlg_mouse(dlg, &dlg->items[i], ev)) break; break; case EV_KBD: di = &dlg->items[dlg->selected]; if (di->item->type == D_FIELD) { if (ev->x == KBD_UP && (void *)di->cur_hist->prev != &di->history) { di->cur_hist = di->cur_hist->prev; dlg_set_history(di); goto dsp_f; } if (ev->x == KBD_DOWN && (void *)di->cur_hist != &di->history) { di->cur_hist = di->cur_hist->next; dlg_set_history(di); goto dsp_f; } if (ev->x == KBD_RIGHT) { if (di->cpos < strlen(di->cdata)) { if (!F) di->cpos++; #ifdef G else { int u; unsigned char *p = di->cdata + di->cpos; GET_UTF_8(p, u); di->cpos = p - di->cdata; } #endif } goto dsp_f; } if (ev->x == KBD_LEFT) { if (di->cpos > 0) { if (!F) di->cpos--; #ifdef G else { unsigned char *p = di->cdata + di->cpos; BACK_UTF_8(p, di->cdata); di->cpos = p - di->cdata; } #endif } goto dsp_f; } if (ev->x == KBD_HOME) { di->cpos = 0; goto dsp_f; } if (ev->x == KBD_END) { di->cpos = strlen(di->cdata); goto dsp_f; } if (ev->x >= ' ' && !ev->y) { unsigned char *u; unsigned char p[2] = { 0, 0 }; if (!F) p[0] = ev->x, u = p; #ifdef G else { u = encode_utf_8(ev->x); } #endif if (strlen(di->cdata) < di->item->dlen - strlen(u)) { memmove(di->cdata + di->cpos + strlen(u), di->cdata + di->cpos, strlen(di->cdata) - di->cpos + 1); memcpy(&di->cdata[di->cpos], u, strlen(u)); di->cpos += strlen(u); } goto dsp_f; } if (ev->x == KBD_BS) { if (di->cpos) { memmove(di->cdata + di->cpos - 1, di->cdata + di->cpos, strlen(di->cdata) - di->cpos + 1); di->cpos--; } goto dsp_f; } if (ev->x == KBD_DEL) { if (di->cpos < strlen(di->cdata)) memmove(di->cdata + di->cpos, di->cdata + di->cpos + 1, strlen(di->cdata) - di->cpos + 1); goto dsp_f; } if (upcase(ev->x) == 'U' && ev->y == KBD_CTRL) { memmove(di->cdata, di->cdata + di->cpos, strlen(di->cdata + di->cpos) + 1); di->cpos = 0; goto dsp_f; } /* Copy to clipboard */ if ((ev->x == KBD_INS && ev->y == KBD_CTRL) || (upcase(ev->x) == 'Z' && ev->y == KBD_CTRL)) { set_clipboard_text(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)) { set_clipboard_text(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)) { unsigned char * clipboard = get_clipboard_text(); if (clipboard) { strncpy(di->cdata , clipboard, di->item->dlen); di->cdata[di->item->dlen - 1] = 0; di->cpos = strlen(di->cdata); mem_free(clipboard); } goto dsp_f; } if (upcase(ev->x) == 'W' && ev->y & KBD_CTRL) { 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++) if (dlg->dlg->items[i].type == D_BUTTON && upcase(_(dlg->dlg->items[i].text, term)[0]) == upcase(ev->x)) { 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]); goto bla; } if (ev->x == KBD_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; 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; if (((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN || ev->x == KBD_RIGHT) && dlg->n > 1) { 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) { 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(di->history); } freeml(dlg->ml); } bla:; } /* 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) { unsigned char *end; double d = strtod(di->cdata, (char **)&end); if (!*di->cdata || *end) { msg_box(dlg->win->term, NULL, TEXT(T_BAD_NUMBER), AL_CENTER, TEXT(T_NUMBER_EXPECTED), NULL, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC); return 1; } if (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), NULL, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC); return 1; } return 0; } int check_number(struct dialog_data *dlg, struct dialog_item_data *di) { unsigned char *end; long l = strtol(di->cdata, (char **)&end, 10); if (!*di->cdata || *end) { msg_box(dlg->win->term, NULL, TEXT(T_BAD_NUMBER), AL_CENTER, TEXT(T_NUMBER_EXPECTED), NULL, 1, TEXT(T_CANCEL), 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), NULL, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC); return 1; } return 0; } int check_hex_number(struct dialog_data *dlg, struct dialog_item_data *di) { unsigned char *end; long l = strtol(di->cdata, (char **)&end, 16); if (!*di->cdata || *end) { msg_box(dlg->win->term, NULL, TEXT(T_BAD_NUMBER), AL_CENTER, TEXT(T_NUMBER_EXPECTED), NULL, 1, TEXT(T_CANCEL), 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), NULL, 1, TEXT(T_CANCEL), 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), NULL, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC); return 1; } 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) if (dlg->dlg->items[i].fn && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) { dlg->selected = i; draw_to_window(dlg->win, (void (*)(struct terminal *, void *))redraw_dialog_items, dlg); return 1; } return 0; } int ok_dialog(struct dialog_data *dlg, struct dialog_item_data *di) { int i; void (*fn)(void *) = dlg->dlg->refresh; void *data = dlg->dlg->refresh_data; if (check_dialog(dlg)) return 1; for (i = 0; i < dlg->n; i++) memcpy(dlg->dlg->items[i].data, dlg->items[i].cdata, dlg->dlg->items[i].dlen); if (fn) fn(data); i = cancel_dialog(dlg, di); return i; } void center_dlg(struct dialog_data *dlg) { dlg->x = (dlg->win->term->x - dlg->xw) / 2; dlg->y = (dlg->win->term->y - dlg->yw) / 2; } void draw_dlg(struct dialog_data *dlg) { if (!F) { int i; 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 = strlen(_(dlg->dlg->title, term)); print_text(term, (dlg->xw - i) / 2 + dlg->x - 1, dlg->y + DIALOG_TOP_BORDER, 1, " ", COLOR_DIALOG_TITLE); print_text(term, (dlg->xw - i) / 2 + dlg->x, dlg->y + DIALOG_TOP_BORDER, i, _(dlg->dlg->title, term), COLOR_DIALOG_TITLE); print_text(term, (dlg->xw - i) / 2 + dlg->x + i, dlg->y + DIALOG_TOP_BORDER, 1, " ", COLOR_DIALOG_TITLE); #ifdef G } else { struct graphics_device *dev = dlg->win->term->dev; struct rect r; struct rect rt; unsigned char *text = _(dlg->dlg->title, dlg->win->term); int xtl = txtlen(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; 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(drv, 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(drv, 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); } drv->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); /* drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE + 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, TXT_X, TXT_Y + G_BFU_FONT_SIZE, bfu_bg_color); drv->fill_area(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1, TXT_Y + G_BFU_FONT_SIZE, 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 = TXT_Y + G_BFU_FONT_SIZE;*/ 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) { text = _(text, term); do { int c = 0; while (*text && *text != '\n') { if (!F) text++, c++; #ifdef G else { int u; GET_UTF_8(text, u); 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) { text = _(text, term); do { int c = 0; while (*text && *text != '\n' && *text != ' ') { if (!F) text++, c++; #ifdef G else { int u; GET_UTF_8(text, u); c += g_char_width(align & AL_MONO ? bfu_style_wb_mono : bfu_style_wb, u); } #endif } if (c > *width) *width = c; } while (*(text++)); } void dlg_format_text(struct dialog_data *dlg, struct terminal *term, unsigned char *text, int x, int *y, int w, int *rw, int co, int align) { #ifdef G unsigned char *tx2; #endif text = _(text, dlg->win->term); if (!F) do { unsigned char *tx; unsigned char *tt = text; int s; int xx = x; do { while (*text && *text != '\n' && *text != ' ') { text++, xx++; } tx = ++text; xx++; if (*(text - 1) != ' ') break; while (*tx && *tx != '\n' && *tx != ' ') tx++; } while (tx - text + xx - x <= w); s = (align & AL_MASK) == AL_CENTER ? (w - (xx - 1 - x)) / 2 : 0; if (s < 0) s = 0; while (tt < text - 1) { if (s >= w) { s = 0, (*y)++; if (rw) *rw = w; rw = NULL; } if (term) set_char(term, x + s, *y, co | *tt); s++, tt++; } if (rw && xx - 1 - x > *rw) *rw = xx - 1 - x; (*y)++; } while (*(text - 1)); #ifdef G else if ((tx2 = strchr(text, '\n'))) { unsigned char *txt = stracpy(text); unsigned char *tx1 = txt; tx2 += txt - text; do { *tx2 = 0; dlg_format_text(dlg, term, tx1, x, y, w, rw, co, align); tx1 = tx2 + 1; } while ((tx2 = strchr(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.pos = 0; ww.last_wrap = NULL; ww.last_wrap_obj = NULL; 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 if (term) add_to_strn(&txt, "-"); } else { www = ww.pos; txt = text; } if (term) { int xx = (align & AL_MASK) == AL_CENTER ? x + (w - www) / 2 : x; g_print_text(drv, 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 } 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; for (i = 0; i < n; i++) w += txtlen(_((butt++)->item->text, term)) + gf_val(6, G_DIALOG_BUTTON_SPACE + txtlen(G_DIALOG_BUTTON_L) + txtlen(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; for (i = 0; i < n; i++) { int w = txtlen(_((butt++)->item->text, term)) + gf_val(4, txtlen(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; 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(_(butt[i].item->text, dlg->win->term)) + gf_val(4, txtlen(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R))) + gf_val(2, G_DIALOG_BUTTON_SPACE); } } *y += gf_val(2, G_BFU_FONT_SIZE * 2); 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(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); 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 **texts) { 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 **texts, int *w, void (*fn)(struct terminal *, unsigned char *, int *, int)) { int k = gf_val(4, txtlen(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R) + G_DIALOG_CHECKBOX_SPACE); while (texts[0]) { *w -= k; fn(term, _(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 (term) { item->x = x; item->y = *y; item->l = w; } /*if ((item->l = w) > item->item->dlen - 1) item->l = item->item->dlen - 1;*/ if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w; (*y) += gf_val(1, G_BFU_FONT_SIZE); } /* 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; } void max_group_width(struct terminal *term, unsigned char **texts, struct dialog_item_data *item, int n, int *w) { int ww = 0; while (n--) { int wx = item->item->type == D_CHECKBOX ? gf_val(4, txtlen(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R) + G_DIALOG_CHECKBOX_SPACE) : item->item->type == D_BUTTON ? txtlen(_(item->item->text, term)) + (gf_val(4, txtlen(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R))) : gf_val(item->item->dlen + 1, (item->item->dlen + 1) * G_DIALOG_FIELD_WIDTH); wx += txtlen(_(texts[0], term)); 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 **texts, struct dialog_item_data *item, int n, int *w) { while (n--) { int wx = item->item->type == D_CHECKBOX ? gf_val(4, txtlen(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R) + G_DIALOG_CHECKBOX_SPACE) : item->item->type == D_BUTTON ? txtlen(_(item->item->text, term)) + (gf_val(4, txtlen(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R))) : gf_val(item->item->dlen + 1, (item->item->dlen + 1) * G_DIALOG_FIELD_WIDTH); wx += txtlen(_(texts[0], term)); if (wx > *w) *w = wx; texts++; item++; } } void dlg_format_group(struct dialog_data *dlg, struct terminal *term, unsigned char **texts, struct dialog_item_data *item, int n, int x, int *y, int w, int *rw) { int nx = 0; while (n--) { int wx = item->item->type == D_CHECKBOX ? gf_val(3, txtlen(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R)) : item->item->type == D_BUTTON ? txtlen(_(item->item->text, dlg->win->term)) + (gf_val(4, txtlen(G_DIALOG_BUTTON_L G_DIALOG_BUTTON_R))) : gf_val(item->item->dlen, item->item->dlen * G_DIALOG_FIELD_WIDTH); int sl; if (_(texts[0], dlg->win->term)[0]) sl = txtlen(_(texts[0], dlg->win->term)) + gf_val(1, G_DIALOG_GROUP_TEXT_SPACE); else sl = 0; wx += sl; if (nx && nx + wx > w) { nx = 0; (*y) += gf_val(2, G_BFU_FONT_SIZE * 2); } if (term) { if (!F) print_text(term, x + nx + 4 * (item->item->type == D_CHECKBOX), *y, strlen(_(texts[0], dlg->win->term)), _(texts[0], dlg->win->term), COLOR_DIALOG_TEXT); #ifdef G else { int l, ll; l = ll = x + nx + (item->item->type == D_CHECKBOX ? txtlen(G_DIALOG_CHECKBOX_L G_DIALOG_CHECKBOX_X G_DIALOG_CHECKBOX_R) + G_DIALOG_GROUP_TEXT_SPACE : 0); g_print_text(drv, term->dev, ll, *y, bfu_style_bw, _(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->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) += gf_val(1, G_BFU_FONT_SIZE); } #define LL gf_val(1, G_BFU_FONT_SIZE) void checkbox_list_fn(struct dialog_data *dlg) { struct terminal *term = dlg->win->term; int max = 0, min = 0; int w, rw; int y = 0; checkboxes_width(term, dlg->dlg->udata, &max, max_text_width); checkboxes_width(term, dlg->dlg->udata, &min, min_text_width); 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 < 5) w = 5; rw = 0; dlg_format_checkboxes(dlg, NULL, dlg->items, dlg->n - 2, 0, &y, w, &rw, dlg->dlg->udata); 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_checkboxes(dlg, term, dlg->items, dlg->n - 2, dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata); y += LL; dlg_format_buttons(dlg, term, dlg->items + dlg->n - 2, 2, 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, _(*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); } int msg_box_button(struct dialog_data *dlg, struct dialog_item_data *di) { void (*fn)(void *) = (void (*)(void *))di->item->udata; void *data = dlg->dlg->udata2; /*struct dialog *dl = dlg->dlg;*/ if (fn) fn(data); cancel_dialog(dlg, di); return 0; } 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 { unsigned char **udata_; text = va_arg(ap, unsigned char *); na_kovarne__to_je_narez: if (!(udata_ = mem_realloc(udata, ++udatan * sizeof(unsigned char *)))) { mem_free(udata); va_end(ap); return; } udata = udata_; udata[udatan - 1] = text; if (text && !(align & AL_EXTD_TEXT)) { text = NULL; goto na_kovarne__to_je_narez; } } while (text); udata2 = va_arg(ap, void *); n = va_arg(ap, int); if (!(dlg = mem_alloc(sizeof(struct dialog) + (n + 1) * sizeof(struct dialog_item)))) { mem_free(udata); va_end(ap); return; } memset(dlg, 0, 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; void (*fn)(void *); int flags; m = va_arg(ap, unsigned char *); fn = va_arg(ap, void *); 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].udata = 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 history *h, unsigned char *t) { struct history_item *hi, *hs; int l; if (!h || !t || !*t) return; l = strlen(t) + 1; if (!(hi = mem_alloc(sizeof(struct history_item) + l))) return; memcpy(hi->d, t, l); foreach(hs, h->items) if (!strcmp(hs->d, t)) { struct history_item *hd = hs; hs = hs->prev; del_from_list(hd); mem_free(hd); h->n--; } add_to_list(h->items, hi); h->n++; while (h->n > MAX_HISTORY_ITEMS) { struct history_item *hd = h->items.prev; if ((void *)hd == &h->items) { internal("history is empty"); h->n = 0; return; } del_from_list(hd); mem_free(hd); h->n--; } } int input_field_cancel(struct dialog_data *dlg, struct dialog_item_data *di) { void (*fn)(void *) = di->item->udata; void *data = dlg->dlg->udata2; if (fn) fn(data); cancel_dialog(dlg, di); return 0; } int input_field_ok(struct dialog_data *dlg, struct dialog_item_data *di) { void (*fn)(void *, unsigned char *) = di->item->udata; void *data = dlg->dlg->udata2; unsigned char *text = dlg->items->cdata; if (check_dialog(dlg)) return 1; add_to_history(dlg->dlg->items->history, text); if (fn) fn(data, text); ok_dialog(dlg, di); return 0; } 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); 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, 2, &max); min_buttons_width(term, dlg->items + 1, 2, &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(dlg, NULL, dlg->dlg->udata, 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT); dlg_format_field(dlg, NULL, dlg->items, 0, &y, w, &rw, AL_LEFT); y += LL; dlg_format_buttons(dlg, NULL, dlg->items + 1, 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; dlg_format_text(dlg, term, dlg->dlg->udata, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT); dlg_format_field(dlg, term, dlg->items, dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT); y += LL; dlg_format_buttons(dlg, term, dlg->items + 1, 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER); } void input_field(struct terminal *term, struct memory_list *ml, unsigned char *title, unsigned char *text, unsigned char *okbutton, unsigned char *cancelbutton, void *data, struct history *history, int l, unsigned char *def, int min, int max, int (*check)(struct dialog_data *, struct dialog_item_data *), void (*fn)(void *, unsigned char *), void (*cancelfn)(void *)) { struct dialog *dlg; unsigned char *field; if (!(dlg = mem_alloc(sizeof(struct dialog) + 4 * sizeof(struct dialog_item) + l))) return; memset(dlg, 0, sizeof(struct dialog) + 4 * sizeof(struct dialog_item) + l); *(field = (unsigned char *)dlg + sizeof(struct dialog) + 4 * sizeof(struct dialog_item)) = 0; if (def) { if (strlen(def) + 1 > l) memcpy(field, def, l - 1); else strcpy(field, 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; dlg->items[1].type = D_BUTTON; dlg->items[1].gid = B_ENTER; dlg->items[1].fn = input_field_ok; dlg->items[1].dlen = 0; dlg->items[1].text = okbutton; dlg->items[1].udata = fn; dlg->items[2].type = D_BUTTON; dlg->items[2].gid = B_ESC; dlg->items[2].fn = input_field_cancel; dlg->items[2].dlen = 0; dlg->items[2].text = cancelbutton; dlg->items[2].udata = cancelfn; dlg->items[3].type = D_END; add_to_ml(&ml, dlg, NULL); do_dialog(term, dlg, ml); }