From 1030dc837b10a03a02a85d5504cbeec168ce49e2 Mon Sep 17 00:00:00 2001 From: Bernie Innocenti Date: Mon, 03 May 2010 21:53:47 +0000 Subject: Import XaoS r489 (trunk after version 3.5) --- (limited to 'src/ui/dialog.c') diff --git a/src/ui/dialog.c b/src/ui/dialog.c new file mode 100644 index 0000000..d5c6aae --- /dev/null +++ b/src/ui/dialog.c @@ -0,0 +1,1521 @@ +/* + * XaoS, a fast portable realtime fractal zoomer + * Copyright (C) 1996 by + * + * Jan Hubicka (hubicka@paru.cas.cz) + * Thomas Marsh (tmarsh@austin.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#undef _EFENCE_ +#include +#ifdef _plan9_ +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#ifndef _MAC +#include +#endif +#endif +#include +#ifndef _plan9_ +#include +#endif +#include +#include +#include +#include +#include +#include +#include "uiint.h" +#include +#include + +#ifdef HAVE_GETTEXT +#include +#else +#define gettext(STRING) STRING +#endif + +struct dialogitem; +struct dialogtype { + void (*build) (struct dialogitem * item, CONST menudialog * entry); + int (*key) (struct dialogitem * item, int key); + void (*mouse) (struct dialogitem * item, int x, int y, int buttons, + int flags); + void (*destroy) (struct dialogitem * item, dialogparam * param); + void (*draw) (struct dialogitem * item); + void (*unselect) (struct dialogitem * item); +}; +struct dialogitem { + int y; + int width, width1, height; + CONST menudialog *dialog; + void *data; + CONST struct dialogtype *type; +}; +static struct opendialog { + int x, y, width, height; + int half; + int nitems; + CONST menudialog *dialog; + int mousereleased; + int mousegrab; + CONST menuitem *item; + int current; + struct dialogitem *items; + struct uih_window *window; +} dialog; + +static dialogparam *qparam; +static CONST menuitem *qitem; + +int dialogvisible; + +int yesnodialogvisible; +static struct yesnodialog { + int width; + int questionwidth; + int mousereleased; + char *question; + void (*handler) (int yes); + int selected; + int pressed; + struct uih_window *window; +} yesnodialog; + +// These 3 definitions are no longer used: +static CONST char *CONST oktext = "OK"; +static CONST char *CONST canceltext = "Cancel"; +static CONST char *CONST helptext = "Help"; + +static int okwidth; +static int cancelwidth; +#define SELECTED(item) ((item-dialog.items)==dialog.current) +static void NEXT(void) +{ + dialog.items[dialog.current].type->unselect(dialog.items + + dialog.current); + dialog.current = (dialog.current + 1) % dialog.nitems; + uih->display = 1; +} + +static void PREV(void) +{ + dialog.items[dialog.current].type->unselect(dialog.items + + dialog.current); + dialog.current = + dialog.current ? (dialog.current - 1) : dialog.nitems - 1; + uih->display = 1; +} + +struct okdata { + int pressed; + int selected; +}; + +CONST char *CONST yestext = "Yes"; +CONST char *CONST notext = "No"; +#define YESNOX ((uih->image->width-yesnodialog.width)/2) +#define YESNOHEIGHT (2*BUTTONHEIGHT+2*BORDERHEIGHT) +#define YESNOY ((uih->image->height-YESNOHEIGHT)/2) +void +ui_drawbutton(CONST char *text, int pressed, int selected, int x1, int x2, + int y) +{ + int width = xtextwidth(uih->font, text); + /*printf("%s %i %i\n",text,pressed,selected); */ + if (uih->palette->type & BITMAPS) { + uih_drawborder(uih, x1, y, x2 - x1, BUTTONHEIGHT, + (pressed != 0 + || selected != 0) * BORDER_PRESSED | BORDER_LIGHT); + xprint(uih->image, uih->font, (x1 + x2 - width) / 2 + pressed, + y + BORDERHEIGHT + pressed, text, selected + || pressed ? BGCOLOR(uih) : FGCOLOR(uih), BGCOLOR(uih), + TEXT_PRESSED); + } else { + uih_drawborder(uih, x1, y, x2 - x1, BUTTONHEIGHT, + (pressed != 0) * BORDER_PRESSED | BORDER_LIGHT); + xprint(uih->image, uih->font, (x1 + x2 - width) / 2 + pressed, + y + BORDERHEIGHT + pressed, text, + selected ? SELCOLOR(uih) : FGCOLOR(uih), BGCOLOR(uih), + /*TEXT_PRESSED */ 0); + } +} + +static void +ui_yesnopos(struct uih_context *c, int *x, int *y, int *w, int *h, + void *data) +{ +#ifdef _plan9_ +#define filevisible 0 +#endif + if (filevisible || helpvisible) { + *x = *y = *w = *h = 0; + return; + } + *w = yesnodialog.width; + *h = YESNOHEIGHT; + *x = YESNOX; + *y = YESNOY; +} + +static void ui_drawyesno(struct uih_context *c, void *data) +{ + xprint(uih->image, uih->font, + YESNOX + (yesnodialog.width - yesnodialog.questionwidth) / 2, + YESNOY + BORDERHEIGHT, yesnodialog.question, + FGCOLOR(uih), BGCOLOR(uih), 0); + ui_drawbutton(yestext, yesnodialog.pressed == 0, + yesnodialog.selected == 0, YESNOX + BORDERWIDTH + 1, + YESNOX + (yesnodialog.width) / 2 - 1, + YESNOY + BUTTONHEIGHT + BORDERHEIGHT); + ui_drawbutton(notext, yesnodialog.pressed == 1, + yesnodialog.selected == 1, + YESNOX + (yesnodialog.width) / 2 + 1, + YESNOX + yesnodialog.width - BORDERWIDTH - 1, + YESNOY + BUTTONHEIGHT + BORDERHEIGHT); +} + +static void ui_closeyesno(int success) +{ + if (!yesnodialogvisible) + return; + free(yesnodialog.question); + yesnodialog.handler(success); + yesnodialogvisible = 0; + uih_removew(uih, yesnodialog.window); + uih->display = 1; +} + +void ui_buildyesno(CONST char *question, void (*handler) (int yes)) +{ + if (yesnodialogvisible) + ui_closeyesno(0); + yesnodialogvisible = 1; + yesnodialog.questionwidth = xtextwidth(uih->font, question); + yesnodialog.question = mystrdup(question); + yesnodialog.mousereleased = 0; + yesnodialog.width = + xtextwidth(uih->font, yestext) + xtextwidth(uih->font, + notext) + + 8 * BORDERWIDTH + 2; + if (yesnodialog.width < yesnodialog.questionwidth) + yesnodialog.width = yesnodialog.questionwidth; + yesnodialog.width += 2 * BORDERWIDTH; + yesnodialog.handler = handler; + yesnodialog.selected = 0; + yesnodialog.pressed = -1; + yesnodialog.window = + uih_registerw(uih, ui_yesnopos, ui_drawyesno, NULL, DRAWBORDER); + uih->display = 1; +} + +static int ui_keyyesno(int key) +{ + if (!yesnodialogvisible) + return 0; + switch (key) { + case UIKEY_LEFT: + yesnodialog.selected ^= 1; + uih->display = 1; + return 1; + case UIKEY_UP: + return 1; + case UIKEY_RIGHT: + case UIKEY_TAB: + yesnodialog.selected ^= 1; + uih->display = 1; + return 1; + case UIKEY_DOWN: + return 1; + case 13: + case '\n': + ui_closeyesno(!yesnodialog.selected); + return 1; + case UIKEY_ESC: + ui_closeyesno(0); + return 1; + } + return 1; +} + +static int ui_mouseyesno(int x, int y, int buttons, int flags) +{ + int mouseat = 0; + if (!yesnodialogvisible) + return 0; + if (!yesnodialog.mousereleased && (flags & MOUSE_RELEASE)) { + yesnodialog.mousereleased = 1; + return 1; + } + if (!yesnodialog.mousereleased && (flags & MOUSE_DRAG)) { + return 1; + } + yesnodialog.mousereleased = 1; + if (x < YESNOX || y < YESNOY || x > YESNOX + yesnodialog.width + || y > YESNOY + YESNOHEIGHT) { + if (flags & MOUSE_PRESS) { + ui_closeyesno(0); + } else { + if (yesnodialog.pressed != -1) + uih->display = 1; + yesnodialog.pressed = -1; + } + return 1; + } + if (x > YESNOX + yesnodialog.width / 2) + mouseat = 1; + if (flags & MOUSE_DRAG) { + if (yesnodialog.pressed != mouseat) + uih->display = 1; + if (yesnodialog.selected != mouseat) + uih->display = 1; + yesnodialog.selected = mouseat; + yesnodialog.pressed = mouseat; + } else { + if ((flags & MOUSE_MOVE) && yesnodialog.selected != mouseat) + uih->display = 1, yesnodialog.selected = mouseat; + if (yesnodialog.pressed != -1) + uih->display = 1; + yesnodialog.pressed = -1; + } + if (flags & MOUSE_RELEASE) { + ui_closeyesno(!mouseat); + } + return 1; +} + +static void ui_buildok(struct dialogitem *item, CONST menudialog * entry) +{ + struct okdata *ok; + item->height = BUTTONHEIGHT; + okwidth = xtextwidth(uih->font, gettext("OK")); + cancelwidth = xtextwidth(uih->font, gettext("Cancel")); + item->width = okwidth + 2 * BORDERWIDTH + 2; + item->width1 = cancelwidth + 2 * BORDERWIDTH + 2; + if (item->width < item->width1) + item->width = item->width1; + if (item->width > item->width1) + item->width1 = item->width; + item->data = ok = (struct okdata *) malloc(sizeof(struct okdata)); + ok->pressed = -1; + ok->selected = 0; +} + +static void ui_destroyok(struct dialogitem *item, dialogparam * param) +{ + free(item->data); +} + +static int ui_keyok(struct dialogitem *item, int key) +{ + struct okdata *ok = (struct okdata *) item->data; + switch (key) { + case UIKEY_LEFT: + if (ok->selected >= 1) { + ok->selected--; + uih->display = 1; + return 1; + } + case UIKEY_UP: + PREV(); + return 1; + case UIKEY_RIGHT: + case UIKEY_TAB: + if (ok->selected < 2) { + ok->selected++; + uih->display = 1; + return 1; + } + case UIKEY_DOWN: + NEXT(); + return 1; + case 13: + case '\n': + if (ok->selected <= 1) + ui_closedialog(!ok->selected); + else + ui_help(dialog.item->shortname); + return 1; + } + return 0; +} + +static void +ui_mouseok(struct dialogitem *item, int x, int y, int buttons, int flags) +{ + struct okdata *ok = (struct okdata *) item->data; + int mouseat = 0; + if (x > dialog.x + dialog.width / 3) + mouseat = 1; + if (x > dialog.x + 2 * dialog.width / 3) + mouseat = 2; + if (flags & MOUSE_DRAG) { + if (ok->pressed != mouseat) + uih->display = 1; + if (ok->selected != mouseat) + uih->display = 1; + ok->selected = mouseat; + ok->pressed = mouseat; + } else { + if ((flags & MOUSE_MOVE) && ok->selected != mouseat) + uih->display = 1, ok->selected = mouseat; + if (ok->pressed != -1) + uih->display = 1; + ok->pressed = -1; + } + if (flags & MOUSE_RELEASE) { + if (mouseat < 2) + ui_closedialog(!mouseat); + else + ui_help(dialog.item->shortname); + } +} + +static void ui_drawok(struct dialogitem *item) +{ + struct okdata *ok = (struct okdata *) item->data; + ui_drawbutton(gettext("OK"), ok->pressed == 0, SELECTED(item) + && ok->selected == 0, dialog.x + BORDERWIDTH + 1, + dialog.x + (dialog.width) / 3 - 1, item->y); + ui_drawbutton(gettext("Cancel"), ok->pressed == 1, SELECTED(item) + && ok->selected == 1, dialog.x + (dialog.width) / 3 + 1, + dialog.x + 2 * dialog.width / 3 - BORDERWIDTH, item->y); + ui_drawbutton(gettext("Help"), ok->pressed == 2, SELECTED(item) + && ok->selected == 2, dialog.x + 2 * (dialog.width) / 3, + dialog.x + dialog.width - BORDERWIDTH - 1, item->y); +} + +static void ui_unselectok(struct dialogitem *item) +{ + struct okdata *ok = (struct okdata *) item->data; + ok->pressed = -1; + ok->selected = 0; + uih->display = 1; +} + +CONST static struct dialogtype okdialog = { + ui_buildok, + ui_keyok, + ui_mouseok, + ui_destroyok, + ui_drawok, + ui_unselectok +}; + +void ui_updatetext(struct ui_textdata *d) +{ + int again = 1; + int i; + int wi; + int len = (int) strlen(d->text); + if (d->start >= len) + d->start = 0; + if (d->cursor > len) + d->cursor = len; + if (d->cursor < d->start) + d->start = d->cursor; + do { + wi = 0; + for (i = 0; d->text[d->start + i]; i++) { + if (d->start + i == d->cursor) + d->cursorpos = wi; + wi += xtextcharw(uih->font, d->text[d->start + i]); + if (wi >= d->width) { + break; + } + } + if (d->start + i == d->cursor && wi < d->width) + d->cursorpos = wi; + if (d->start + i < d->cursor) + d->start++; + else + again = 0; + } + while (again); + d->ndisplayed = i; + while (again); +} + +struct ui_textdata *ui_opentext(int x, int y, int width, CONST char *def) +{ + struct ui_textdata *d = (struct ui_textdata *) malloc(sizeof(*d)); + char *text; + int size = 100; + if ((int) strlen(def) > size) + size = (int) strlen(def) * 2; + d->x = x; + d->y = y; + d->width = width; + text = (char *) malloc(size); + strcpy(text, def); + d->text = text; + d->cursor = 0; + d->cursorpos = 0; + d->start = 0; + d->ndisplayed = 0; + d->clear = 1; + d->size = size; + ui_updatetext(d); + return (d); +} + +void ui_drawtext(struct ui_textdata *d, int active) +{ + char *c = (char *) malloc(d->ndisplayed + 2); + strncpy(c, d->text + d->start, d->ndisplayed); + c[d->ndisplayed] = 0; + xprint(uih->image, uih->font, d->x, d->y, c, + (uih->palette->type & BITMAPS) ? BGCOLOR(uih) : ((active + && d->clear) ? + SELCOLOR(uih) : + FGCOLOR(uih)), + BGCOLOR(uih), + (uih->palette->type & BITMAPS) ? TEXT_PRESSED : 0); + if (active) { + xdrawcursor(uih->image, d->x + d->cursorpos, d->y, + (uih->palette-> + type & BITMAPS) ? BGCOLOR(uih) : SELCOLOR(uih), + xtextheight(uih->font)); + } + free(c); +} + +void ui_textmouse(struct ui_textdata *d, int x, int y) +{ + if (y > d->y && y < d->y + xtextheight(uih->font) && x > d->x) { + int w = 0; + int i; + int xp = d->x; + for (i = 0; i < d->ndisplayed + 1 && xp - w / 2 < x; i++) { + w = xtextcharw(uih->font, d->text[i + d->start]); + xp += w; + } + d->cursor = i + d->start - 1; + if (d->cursor < 0) + d->cursor = 0; + d->clear = 0; + ui_updatetext(d); + uih->display = 1; + } +} + +void ui_closetext(struct ui_textdata *d) +{ + free(d->text); + free(d); +} + +int ui_textkey(struct ui_textdata *d, int key) +{ + switch (key) { + case UIKEY_LEFT: + if (d->clear) + d->clear = 0; + if (d->cursor) + d->cursor--; + else + return 0; + ui_updatetext(d); + uih->display = 1; + return 1; + case UIKEY_RIGHT: + if (d->clear) + d->clear = 0; + if (d->cursor < (int) strlen(d->text)) + d->cursor++; + else + return 0; + ui_updatetext(d); + uih->display = 1; + return 1; + case UIKEY_HOME: + if (d->clear) + d->clear = 0; + d->cursor = 0; + ui_updatetext(d); + uih->display = 1; + return 1; + case UIKEY_END: + if (d->clear) + d->clear = 0; + d->cursor = (int) strlen(d->text); + ui_updatetext(d); + uih->display = 1; + return 1; + case UIKEY_BACKSPACE: + if (d->clear) + d->text[0] = 0, d->clear = 0; + else if (d->cursor) { + int len, i; + len = (int) strlen(d->text); + for (i = d->cursor; i <= len; i++) { + d->text[i - 1] = d->text[i]; + } + d->cursor--; + } + ui_updatetext(d); + uih->display = 1; + return 1; + } + if (isprint(key)) { + int i; + int len; + if (d->clear) + d->text[0] = 0, d->clear = 0; + if ((len = (int) strlen(d->text)) > d->size - 2) { + d->text = (char *) realloc(d->text, d->size * 2); + } + for (i = len; i >= d->cursor; i--) { + d->text[i + 1] = d->text[i]; + } + d->text[d->cursor] = key; + d->cursor++; + ui_updatetext(d); + uih->display = 1; + return 1; + } + return 0; +} + +static void +ui_buildstring(struct dialogitem *item, CONST menudialog * entry) +{ + item->height = BUTTONHEIGHT; + item->width = xtextwidth(uih->font, item->dialog->question); + item->width1 = xtextcharw(uih->font, 'w') * 20; + item->data = ui_opentext(0, 0, 2043, item->dialog->defstr); +} + +static void ui_destroystring(struct dialogitem *item, dialogparam * param) +{ + struct ui_textdata *text = (struct ui_textdata *) item->data; + param->dstring = mystrdup(text->text); + ui_closetext(text); +} + +static void ui_drawquestion(struct dialogitem *item) +{ + if (uih->palette->type & BITMAPS) { + if (SELECTED(item)) + xrectangle(uih->image, dialog.x + BORDERWIDTH, item->y, + dialog.half - dialog.x - 2 * BORDERWIDTH, + BUTTONHEIGHT, FGCOLOR(uih)); + xprint(uih->image, uih->font, dialog.half - item->width, + item->y + BORDERHEIGHT, item->dialog->question, + SELECTED(item) ? BGCOLOR(uih) : FGCOLOR(uih), + BGCOLOR(uih), TEXT_PRESSED); + } else { + xprint(uih->image, uih->font, dialog.half - item->width, + item->y + BORDERHEIGHT, item->dialog->question, + SELECTED(item) ? SELCOLOR(uih) : FGCOLOR(uih), BGCOLOR(uih), + 0); + } +} + +static void ui_drawstring(struct dialogitem *item) +{ + struct ui_textdata *text = (struct ui_textdata *) item->data; + if (text->width == 2043) + text->x = dialog.half + BORDERWIDTH, text->width = + dialog.width + dialog.x - dialog.half - 2 * BORDERWIDTH, + text->y = item->y + BORDERHEIGHT, ui_updatetext(text); + uih_drawborder(uih, dialog.half, item->y, + dialog.width - dialog.half + dialog.x - BORDERWIDTH, + BUTTONHEIGHT, BORDER_PRESSED | BORDER_LIGHT); + ui_drawtext(text, SELECTED(item)); + ui_drawquestion(item); +} + +static int ui_keystring(struct dialogitem *item, int key) +{ + struct ui_textdata *text = (struct ui_textdata *) item->data; + return (ui_textkey(text, key)); +} + +static void +ui_mousestring(struct dialogitem *item, int x, int y, int buttons, + int flags) +{ + struct ui_textdata *text = (struct ui_textdata *) item->data; + if (flags & MOUSE_DRAG) { + ui_textmouse(text, x, y); + } +} + +static void ui_unselectstring(struct dialogitem *item) +{ +} + +CONST static struct dialogtype stringdialog = { + ui_buildstring, + ui_keystring, + ui_mousestring, + ui_destroystring, + ui_drawstring, + ui_unselectstring +}; + +static void ui_buildint(struct dialogitem *item, CONST menudialog * entry) +{ + char s[50]; + item->height = BUTTONHEIGHT; + item->width = xtextwidth(uih->font, item->dialog->question); + item->width1 = xtextcharw(uih->font, 'w') * 5; + sprintf(s, "%i", item->dialog->defint); + item->data = ui_opentext(0, 0, 2043, s); +} + +static void ui_destroyint(struct dialogitem *item, dialogparam * param) +{ + struct ui_textdata *text = (struct ui_textdata *) item->data; + param->dint = (int) atol(text->text); + ui_closetext(text); +} + +CONST static struct dialogtype intdialog = { + ui_buildint, + ui_keystring, + ui_mousestring, + ui_destroyint, + ui_drawstring, + ui_unselectstring +}; + +static CONST char *ui_getextension(CONST char *ch) +{ + int i = 0; + while (ch[i]) { + if (ch[i] == '*') + return (ch + i + 1); + i++; + } + return ch + i; +} + +number_t ui_getfloat(CONST char *c) +{ +#ifdef HAVE_LONG_DOUBLE + long double param; +#else + double param; +#endif +#ifdef HAVE_LONG_DOUBLE +#ifndef USE_ATOLD +#ifdef USE_XLDIO + param = x_strtold(c, NULL); + if (0) +#else + if (sscanf(c, "%LG", ¶m) == 0) +#endif +#else + param = _atold(c); + if (0) +#endif + { +#else + if (sscanf(c, "%lG", ¶m) == 0) { +#endif + return 0; + } + return (param); +} + +#define BROWSEWIDTH /*(2*BORDERWIDTH+xtextcharw(uih->font,'B'))*/BUTTONHEIGHT +struct ui_filedata { + struct ui_textdata *text; + int active; + int pressed; +}; + +static struct dialogitem *curritem; +static void filecallback(CONST char *name, int succ) +{ + struct ui_filedata *text = (struct ui_filedata *) curritem->data; + if (succ) { + ui_closetext(text->text); + uih->display = 1; + text->text = ui_opentext(0, 0, 2043, name); + dialog.mousereleased = 0; + } + if (dialog.nitems == 2) + ui_closedialog(succ); +} + +static void ui_buildfile(struct dialogitem *item, CONST menudialog * entry) +{ + char str[256]; + struct ui_filedata *data = + (struct ui_filedata *) malloc(sizeof(*data)); + int i = 0; + item->height = BUTTONHEIGHT; + item->width = xtextwidth(uih->font, item->dialog->question); + item->width1 = xtextcharw(uih->font, 'w') * 20; + while (item->dialog->defstr[i] != '*' && item->dialog->defstr[i] != 0) + str[i] = item->dialog->defstr[i], i++; + str[i] = 0; + item->data = data; + if (entry->type == DIALOG_OFILE) + data->text = + ui_opentext(0, 0, 2043, + ui_getfile(str, + ui_getextension(item->dialog->defstr))); + else + data->text = ui_opentext(0, 0, 2043, item->dialog->defstr); + data->active = 0; + data->pressed = 0; +#ifndef _plan9_ + if (dialog.nitems == 2) { + curritem = item; + ui_buildfilesel(data->text->text, "", filecallback); + } +#endif +} + +static void ui_destroyfile(struct dialogitem *item, dialogparam * param) +{ + struct ui_filedata *text = (struct ui_filedata *) item->data; +#ifndef _plan9_ + if (filevisible) + ui_closefilesel(0); +#endif + param->dpath = mystrdup(text->text->text); + ui_closetext(text->text); + free(text); +} + +static void ui_drawfile(struct dialogitem *item) +{ + struct ui_filedata *data = (struct ui_filedata *) item->data; + int wholesize = + dialog.width + dialog.x - dialog.half - 2 * BORDERWIDTH; + if (data->text->width == 2043) { + data->text->x = dialog.half + BORDERWIDTH, + data->text->width = wholesize - BROWSEWIDTH - 2 * BORDERWIDTH, + data->text->y = item->y + BORDERHEIGHT; + ui_updatetext(data->text); + } + uih_drawborder(uih, dialog.half, item->y, wholesize - BROWSEWIDTH, + BUTTONHEIGHT, BORDER_PRESSED | BORDER_LIGHT); + ui_drawtext(data->text, SELECTED(item) && !data->active); + xprint(uih->image, uih->font, dialog.half - item->width, + item->y + BORDERHEIGHT, item->dialog->question, + SELECTED(item) ? SELCOLOR(uih) : FGCOLOR(uih), BGCOLOR(uih), 0); + ui_drawquestion(item); + ui_drawbutton("B", data->pressed && SELECTED(item), SELECTED(item) + && data->active, + dialog.x + dialog.width - BROWSEWIDTH - BORDERWIDTH, + dialog.x + dialog.width - BORDERWIDTH, item->y); +} + +static int ui_keyfile(struct dialogitem *item, int key) +{ + struct ui_filedata *text = (struct ui_filedata *) item->data; + int i = 0; + if (!text->active) + i = ui_textkey(text->text, key); + if (!i) { + if (key == '\t' || key == UIKEY_RIGHT) { + text->active++; + if (text->active > 1) { + text->active = 0; + return 0; + } + uih->display = 1; + return 1; + } + if (key == UIKEY_LEFT) { + text->active--; + if (text->active < 0) { + text->active = 1; + return 0; + } + return 1; + } +#ifndef _plan9_ + if ((key == 13 || key == '\n') && text->active) { + curritem = item; + ui_buildfilesel(text->text->text, "", filecallback); + return 1; + } +#endif + } + return (i); +} + +static void +ui_mousefile(struct dialogitem *item, int x, int y, int buttons, int flags) +{ + struct ui_filedata *text = (struct ui_filedata *) item->data; + int i; + if (flags & MOUSE_MOVE) { + if (x < dialog.x + dialog.width - BORDERWIDTH - BROWSEWIDTH) + i = 0; + else + i = 1; + if (text->active != i) + text->active = i, uih->display = 1; + } +#ifndef _plan9_ + if ((flags & MOUSE_RELEASE) && text->pressed) { + text->pressed = 0; + uih->display = 1; + curritem = item; + ui_buildfilesel(text->text->text, "", filecallback); + return; + } +#endif + if (flags & MOUSE_DRAG) { + if (x < dialog.x + dialog.width - BORDERWIDTH - BROWSEWIDTH) { + text->active = 0, ui_textmouse(text->text, x, y); + if (text->pressed) + text->pressed = 0, uih->display = 1; + } else if (!text->pressed) { + text->pressed = 1; + uih->display = 1; + } + } +} + +static void ui_unselectfile(struct dialogitem *item) +{ + struct ui_filedata *text = (struct ui_filedata *) item->data; + if (text->active) + text->active = 0, uih->display = 1; + if (text->pressed) + text->pressed = 0, uih->display = 1; +} + +CONST static struct dialogtype filedialog = { + ui_buildfile, + ui_keyfile, + ui_mousefile, + ui_destroyfile, + ui_drawfile, + ui_unselectfile +}; + +static void +ui_buildfloat(struct dialogitem *item, CONST menudialog * entry) +{ + char s[50]; + item->height = BUTTONHEIGHT; + item->width = xtextwidth(uih->font, item->dialog->question); + item->width1 = xtextcharw(uih->font, 'w') * 10; + sprintf(s, "%g", (double) item->dialog->deffloat); + item->data = ui_opentext(0, 0, 2043, s); +} + +static void ui_destroyfloat(struct dialogitem *item, dialogparam * param) +{ + struct ui_textdata *text = (struct ui_textdata *) item->data; + param->number = ui_getfloat(text->text); + ui_closetext(text); +} + +CONST static struct dialogtype floatdialog = { + ui_buildfloat, + ui_keystring, + ui_mousestring, + ui_destroyfloat, + ui_drawstring, + ui_unselectstring +}; + +struct ui_coorddata { + struct ui_textdata *text[2]; + int active; +}; +static void +ui_buildcoord(struct dialogitem *item, CONST menudialog * entry) +{ + char s[50]; + struct ui_coorddata *data = + (struct ui_coorddata *) malloc(sizeof(*data)); + item->height = BUTTONHEIGHT; + item->width = xtextwidth(uih->font, item->dialog->question); + item->width1 = xtextcharw(uih->font, 'w') * 20; + item->data = data; + data->active = 0; + sprintf(s, "%g", (double) item->dialog->deffloat); + data->text[0] = ui_opentext(0, 0, 2043, s); + sprintf(s, "%g", (double) item->dialog->deffloat2); + data->text[1] = ui_opentext(0, 0, 2043, s); +} + +static void ui_destroycoord(struct dialogitem *item, dialogparam * param) +{ + struct ui_coorddata *data = (struct ui_coorddata *) item->data; + param->dcoord[0] = ui_getfloat(data->text[0]->text); + param->dcoord[1] = ui_getfloat(data->text[1]->text); + ui_closetext(data->text[0]); + ui_closetext(data->text[1]); + free(data); +} + +#define SPACESIZE xtextwidth(uih->font,"+") +#define ENDSIZE xtextwidth(uih->font,"i") +static void ui_drawcoord(struct dialogitem *item) +{ + struct ui_coorddata *data = (struct ui_coorddata *) item->data; + int wholesize = + dialog.width + dialog.x - dialog.half - 2 * BORDERWIDTH - ENDSIZE; + int half = (wholesize - SPACESIZE) / 2; + if (data->text[0]->width == 2043) { + data->text[0]->x = dialog.half + BORDERWIDTH, + data->text[0]->width = half - BORDERWIDTH, + data->text[0]->y = item->y + BORDERHEIGHT; + data->text[1]->x = dialog.half + half + SPACESIZE + BORDERWIDTH, + data->text[1]->width = half - BORDERWIDTH, + data->text[1]->y = item->y + BORDERHEIGHT; + ui_updatetext(data->text[0]); + ui_updatetext(data->text[1]); + } + uih_drawborder(uih, dialog.half, item->y, half, BUTTONHEIGHT, + BORDER_PRESSED | BORDER_LIGHT); + uih_drawborder(uih, dialog.half + half + SPACESIZE, item->y, half, + BUTTONHEIGHT, BORDER_PRESSED | BORDER_LIGHT); + ui_drawtext(data->text[0], SELECTED(item) && !data->active); + ui_drawtext(data->text[1], SELECTED(item) && data->active); + xprint(uih->image, uih->font, dialog.half + half, + item->y + BORDERHEIGHT, "+", FGCOLOR(uih), + BGCOLOR(uih), 0); + xprint(uih->image, uih->font, + dialog.x + dialog.width - BORDERWIDTH - ENDSIZE, + item->y + BORDERHEIGHT, "i", FGCOLOR(uih), + BGCOLOR(uih), 0); + ui_drawquestion(item); +} + +static int ui_keycoord(struct dialogitem *item, int key) +{ + struct ui_coorddata *text = (struct ui_coorddata *) item->data; + int i = ui_textkey(text->text[text->active], key); + if (!i) { + if (key == '\t' || key == UIKEY_RIGHT) { + text->active++; + if (text->active > 1) { + text->active = 0; + return 0; + } + uih->display = 1; + if (key == UIKEY_RIGHT) { + text->text[1]->cursor = 0; + ui_updatetext(text->text[1]); + uih->display = 1; + } + return 1; + } + if (key == UIKEY_LEFT) { + text->active--; + if (text->active < 0) { + text->active = 1; + return 0; + } + text->text[0]->cursor = (int) strlen(text->text[0]->text); + ui_updatetext(text->text[0]); + uih->display = 1; + return 1; + } + } + return (i); +} + +static void +ui_mousecoord(struct dialogitem *item, int x, int y, int buttons, + int flags) +{ + struct ui_coorddata *text = (struct ui_coorddata *) item->data; + int i; + if (flags & MOUSE_MOVE) { + if (x < text->text[1]->x) + i = 0; + else + i = 1; + if (text->active != i) + text->active = i, uih->display = 1; + } + if (flags & MOUSE_DRAG) { + if (x < text->text[1]->x) + text->active = 0, ui_textmouse(text->text[0], x, y); + else + text->active = 1, ui_textmouse(text->text[1], x, y); + } +} + +static void ui_unselectcoord(struct dialogitem *item) +{ + struct ui_coorddata *text = (struct ui_coorddata *) item->data; + text->active = 0; +} + +CONST static struct dialogtype coorddialog = { + ui_buildcoord, + ui_keycoord, + ui_mousecoord, + ui_destroycoord, + ui_drawcoord, + ui_unselectcoord +}; + +struct ui_choicedata { + CONST char **texts; + int selected; + int n; + + struct uih_window *menu; + int x, y, width, height; + int active; +}; +static void +ui_choicemenupos(struct uih_context *uih, int *x, int *y, int *width, + int *height, void *data) +{ + struct ui_choicedata *choice = (struct ui_choicedata *) data; + if (filevisible || helpvisible) { + *x = *y = *width = *height = 0; + return; + } + *x = choice->x; + *y = choice->y; + *width = choice->width; + *height = choice->height; +} + +static void ui_drawchoicemenu(uih_context * uih, void *data) +{ + struct ui_choicedata *choice = (struct ui_choicedata *) data; + int i; + for (i = 0; i < choice->n; i++) { + xprint(uih->image, uih->font, choice->x + BORDERWIDTH, + choice->y + BORDERHEIGHT + i * xtextheight(uih->font), + choice->texts[i], + i == choice->active ? SELCOLOR(uih) : FGCOLOR(uih), + BGCOLOR(uih), 0); + } +} + +static void +ui_buildchoicemenu(struct uih_context *uih, struct ui_choicedata *choice, + int x, int y, int width) +{ + if (choice->menu != NULL) + return; + choice->width = width + 2 * BORDERWIDTH; + choice->x = x; + choice->height = xtextheight(uih->font) * choice->n + 2 * BORDERHEIGHT; + choice->active = choice->selected; + choice->y = y - choice->active * xtextheight(uih->font); + dialog.mousegrab = 1; + if (choice->x + choice->width > uih->image->width) + choice->x = uih->image->width - choice->width; + if (choice->y + choice->height > uih->image->height) + choice->y = uih->image->height - choice->height; + if (choice->x < 0) + choice->x = 0; + if (choice->y < 0) + choice->y = 0; + choice->menu = + uih_registerw(uih, ui_choicemenupos, ui_drawchoicemenu, choice, + DRAWBORDER); + uih->display = 1; +} + +static void +ui_closechoicemenu(struct uih_context *uih, struct ui_choicedata *choice) +{ + if (choice->menu == NULL) + return; + uih_removew(uih, choice->menu); + choice->menu = NULL; + uih->display = 1; + dialog.mousegrab = 0; + dialog.mousereleased = 0; +} + +static void +ui_buildchoice(struct dialogitem *item, CONST menudialog * entry) +{ + int i; + struct ui_choicedata *data = + (struct ui_choicedata *) malloc(sizeof(*data)); + item->height = BUTTONHEIGHT; + item->width = xtextwidth(uih->font, item->dialog->question); + item->width1 = 0; + data->menu = NULL; + + data->texts = (CONST char **) entry->defstr; + for (i = 0; data->texts[i] != NULL; i++) { + int w = xtextwidth(uih->font, data->texts[i]); + if (w > item->width1) + item->width1 = w; + } + item->width1 += 2 * BORDERWIDTH; + data->n = i; + data->selected = entry->defint; + item->data = data; +} + +static void ui_destroychoice(struct dialogitem *item, dialogparam * param) +{ + struct ui_choicedata *data = (struct ui_choicedata *) item->data; + param->dint = data->selected; + ui_closechoicemenu(uih, data); + free(data); +} + +static void ui_drawchoice(struct dialogitem *item) +{ + struct ui_choicedata *data = (struct ui_choicedata *) item->data; + uih_drawborder(uih, dialog.half, item->y, item->width1, + BUTTONHEIGHT | BORDER_LIGHT, 0); + xprint(uih->image, uih->font, dialog.half + BORDERWIDTH, + item->y + BORDERHEIGHT, data->texts[data->selected], + SELECTED(item) ? SELCOLOR(uih) : FGCOLOR(uih), + BGCOLOR(uih), 0); + ui_drawquestion(item); +} + +static int ui_keychoice(struct dialogitem *item, int key) +{ + struct ui_choicedata *data = (struct ui_choicedata *) item->data; + if (!data->menu) { + switch (key) { + case ' ': + case '\n': + case 13: + case UIKEY_UP: + case UIKEY_DOWN: + case UIKEY_RIGHT: + ui_buildchoicemenu(uih, data, dialog.half, item->y, + item->width1); + return (1); + } + } else { + switch (key) { + case ' ': + case 13: + case '\n': + data->selected = data->active; + ui_closechoicemenu(uih, data); + return (1); + case UIKEY_DOWN: + data->active++; + data->active %= data->n; + uih->display = 1; + return (1); + case UIKEY_UP: + data->active--; + if (data->active < 0) + data->active = data->n - 1; + uih->display = 1; + return (1); + case UIKEY_ESC: + ui_closechoicemenu(uih, data); + return (1); + } + } + return 0; +} + +static void +ui_mousechoice(struct dialogitem *item, int x, int y, int buttons, + int flags) +{ + struct ui_choicedata *data = (struct ui_choicedata *) item->data; + int in; + if (data->menu != NULL) { + in = 0; + if (x > data->x && y > data->y && x < data->x + data->width + && y < data->y + data->height) + in = 1; + if ((flags & MOUSE_PRESS) && !in) { + ui_closechoicemenu(uih, data); + return; + } + if ((flags & MOUSE_MOVE) && in) { + in = (y - data->y) / xtextheight(uih->font); + if (in < 0) + in = 0; + if (in >= data->n) + in = data->n - 1; + if (data->active != in) + data->active = in, uih->display = 1; + } + if (flags & MOUSE_RELEASE) { + data->selected = data->active; + ui_closechoicemenu(uih, data); + return; + } + } else { + if (flags & MOUSE_PRESS && x > dialog.half) + ui_buildchoicemenu(uih, data, dialog.half, item->y, + item->width1); + } +} + +static void ui_unselectchoice(struct dialogitem *item) +{ + struct ui_choicedata *data = (struct ui_choicedata *) item->data; + ui_closechoicemenu(uih, data); +} + +CONST static struct dialogtype choicedialog = { + ui_buildchoice, + ui_keychoice, + ui_mousechoice, + ui_destroychoice, + ui_drawchoice, + ui_unselectchoice +}; + +static void +ui_dialogpos(struct uih_context *c, int *x, int *y, int *width, + int *height, void *data) +{ + *x = dialog.x; + *y = dialog.y; + if (filevisible || helpvisible) { + *x = *y = *width = *height = 0; + return; + } + *width = dialog.width; + *height = dialog.height; +} + +static void ui_dialogdraw(struct uih_context *c, void *data) +{ + int n; + for (n = 0; n < dialog.nitems; n++) + dialog.items[n].type->draw(dialog.items + n); +} + +#define YSKIP 2 +void ui_builddialog(CONST menuitem * item) +{ + int n = 2; + int ypos; + int width1 = 0; + if (ui_nogui) { + printf("dialog \"%s\"\n", item->shortname); + return; + } + if (driver->gui_driver && driver->gui_driver->dialog) { + driver->gui_driver->dialog(uih, item->shortname); + return; + } + dialogvisible = 1; + dialog.width = 0; + dialog.height = 0; + dialog.dialog = menu_getdialog(uih, item); + dialog.item = item; + for (n = 0; dialog.dialog[n].question != NULL; n++); + n++; + dialog.nitems = n; + dialog.items = + (struct dialogitem *) malloc(sizeof(struct dialogitem) * + dialog.nitems); + dialog.mousereleased = 0; + dialog.items[dialog.nitems - 1].type = &okdialog; + for (n = 0; n < dialog.nitems; n++) { + if (n < dialog.nitems - 1) { + switch (dialog.dialog[n].type) { + case DIALOG_STRING: + case DIALOG_KEYSTRING: + dialog.items[n].type = &stringdialog; + break; + case DIALOG_INT: + dialog.items[n].type = &intdialog; + break; + case DIALOG_IFILE: + case DIALOG_OFILE: + dialog.items[n].type = &filedialog; + break; + case DIALOG_FLOAT: + dialog.items[n].type = &floatdialog; + break; + case DIALOG_COORD: + dialog.items[n].type = &coorddialog; + break; + case DIALOG_CHOICE: + dialog.items[n].type = &choicedialog; + break; + default: + printf("uidialog:unknown type!\n"); + exit(1); + } + } + dialog.items[n].dialog = dialog.dialog + n; + dialog.items[n].type->build(dialog.items + n, dialog.dialog + n); + dialog.height += dialog.items[n].height; + if (width1 < dialog.items[n].width1) + width1 = dialog.items[n].width1; + if (dialog.width < dialog.items[n].width) + dialog.width = dialog.items[n].width; + } + dialog.height += YSKIP * (n - 1); + n = xtextwidth(uih->font, gettext("OK")) + xtextwidth(uih->font, + gettext + ("Cancel")) + + xtextwidth(uih->font, gettext("Help")) + 10; + if (dialog.width < n) + dialog.width = n; + dialog.half = dialog.width + 2 * BORDERWIDTH; + dialog.width += 2 * BORDERWIDTH + width1; + dialog.height += 2 * BORDERHEIGHT; + dialog.current = 0; + dialog.x = (uih->image->width - dialog.width) / 2; + dialog.half += dialog.x; + dialog.y = (uih->image->height - dialog.height) / 2; + ypos = dialog.y + BORDERHEIGHT; + for (n = 0; n < dialog.nitems; n++) { + dialog.items[n].y = ypos; + ypos += dialog.items[n].height + YSKIP; + } + dialog.window = + uih_registerw(uih, ui_dialogpos, ui_dialogdraw, NULL, DRAWBORDER); + uih->display = 1; +} + +static void ui_dialogquestion(int succesfull) +{ + if (succesfull) + ui_menuactivate(qitem, qparam); + else + menu_destroydialog(qitem, qparam, uih); +} + +void ui_closedialog(int succesfull) +{ + int n = 2; + if (dialogvisible) { + dialogparam *param = + (dialogparam *) malloc(sizeof(dialogparam) * (dialog.nitems)); + dialogvisible = 0; + uih_removew(uih, dialog.window); + uih->display = 1; + for (n = 0; n < dialog.nitems; n++) { + dialog.items[n].type->destroy(dialog.items + n, param + n); + } + free(dialog.items); + if (succesfull) { + for (n = 0; n < dialog.nitems - 1; n++) + if (dialog.dialog[n].type == DIALOG_OFILE + && xio_exist(param[n].dpath)) { + qparam = param; + qitem = dialog.item; + ui_buildyesno("File exist. Overwrite?", + ui_dialogquestion); + return; + } + ui_menuactivate(dialog.item, param); + } else + menu_destroydialog(dialog.item, param, uih); + } +} + +int ui_dialogmouse(int x, int y, int mousebuttons, int flags) +{ + int i; + if (ui_mouseyesno(x, y, mousebuttons, flags)) + return 1; + if (!dialogvisible) + return 0; + if (!dialog.mousereleased && (flags & MOUSE_RELEASE)) { + dialog.mousereleased = 1; + return 1; + } + if (!dialog.mousereleased && (flags & MOUSE_DRAG)) { + return 1; + } + dialog.mousereleased = 1; + if (dialog.mousegrab) { + dialog.items[dialog.current].type->mouse(dialog.items + + dialog.current, x, y, + mousebuttons, flags); + return 1; + } + if (dialog.x > x || dialog.y > y || dialog.x + dialog.width < x + || dialog.y + dialog.height < y) { + if (flags & MOUSE_PRESS) { + ui_closedialog(0); + return 1; + } + dialog.items[dialog.current].type->mouse(dialog.items + + dialog.current, x, y, 0, + 0); + return 1; + } + for (i = dialog.nitems - 1; i >= 0; i--) + if (dialog.items[i].y < y) + break; + if (i == -1) { + dialog.items[dialog.current].type->mouse(dialog.items + + dialog.current, x, y, 0, + 0); + return 1; + } + if (((flags & MOUSE_PRESS) || (flags & MOUSE_MOVE)) + && dialog.current != i) { + dialog.items[dialog.current].type->unselect(dialog.items + + dialog.current); + dialog.current = i; + uih->display = 1; + } + dialog.items[i].type->mouse(dialog.items + i, x, y, mousebuttons, + flags); + return 1; +} + +int ui_dialogkeys(int key) +{ + if (ui_keyyesno(key)) + return 1; + if (!dialogvisible) + return 0; + if (key == UIKEY_ESC) { + ui_closedialog(0); + return 1; + } + if (!dialog.items[dialog.current].type-> + key(dialog.items + dialog.current, key)) { + switch (key) { + case 'h': + ui_help(dialog.item->shortname); + return 1; + case UIKEY_TAB: + case UIKEY_DOWN: + case UIKEY_RIGHT: + NEXT(); + break; + case UIKEY_UP: + case UIKEY_LEFT: + PREV(); + break; + case 13: + case '\n': + ui_closedialog(1); + } + } + return 1; +} -- cgit v0.9.1