e16/src/dialog.c

2627 lines
64 KiB
C

/*
* Copyright (C) 2000-2004 Carsten Haitzler, Geoff Harrison and various contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "E.h"
typedef struct
{
char horizontal;
char numeric;
char numeric_side;
int upper;
int lower;
int unit;
int jump;
int val;
int *val_ptr;
int min_length;
int base_orig_w, base_orig_h;
int knob_orig_w, knob_orig_h;
int border_orig_w, border_orig_h;
int base_x, base_y, base_w, base_h;
int knob_x, knob_y, knob_w, knob_h;
int border_x, border_y, border_w, border_h;
int numeric_x, numeric_y, numeric_w, numeric_h;
ImageClass *ic_base;
ImageClass *ic_knob;
ImageClass *ic_border;
char in_drag;
int wanted_val;
Window base_win;
Window knob_win;
Window border_win;
} DItemSlider;
typedef struct
{
Window area_win;
int w, h;
void (*event_func) (int val, void *data);
} DItemArea;
typedef struct
{
char *text;
} DItemButton;
typedef struct
{
char *text;
Window check_win;
int check_orig_w, check_orig_h;
char onoff;
char *onoff_ptr;
} DItemCheckButton;
typedef struct
{
char *text;
} DItemText;
typedef struct
{
char *image;
} DItemImage;
typedef struct
{
char horizontal;
} DItemSeparator;
typedef struct
{
int num_columns;
char border;
char homogenous_h;
char homogenous_v;
int num_items;
DItem **items;
} DItemTable;
typedef struct
{
char *text;
Window radio_win;
int radio_orig_w, radio_orig_h;
char onoff;
int val;
int *val_ptr;
DItem *next;
DItem *first;
void (*event_func) (int val, void *data);
} DItemRadioButton;
struct _ditem
{
int type;
void (*func) (int val, void *data);
int val;
void *data;
ImageClass *iclass;
TextClass *tclass;
Imlib_Border padding;
char fill_h;
char fill_v;
int align_h;
int align_v;
int row_span;
int col_span;
int x, y, w, h;
char hilited;
char clicked;
Window win;
union
{
DItemButton button;
DItemCheckButton check_button;
DItemText text;
DItemTable table;
DItemImage image;
DItemSeparator separator;
DItemRadioButton radio_button;
DItemSlider slider;
DItemArea area;
}
item;
};
typedef struct _dbutton
{
char *text;
void (*func) (int val, void *data);
Window win;
int x, y, w, h;
char hilited;
char clicked;
char close;
TextClass *tclass;
ImageClass *iclass;
}
DButton;
typedef struct _Dkeybind
{
KeyCode key;
int val;
void *data;
void (*func) (int val, void *data);
}
DKeyBind;
struct _dialog
{
char *name;
char *title;
char *text;
int num_buttons;
Window win;
DButton **button;
TextClass *tclass;
ImageClass *iclass;
int w, h;
DItem *item;
void (*exit_func) (int val, void *data);
int exit_val;
void *exit_data;
int num_bindings;
DKeyBind *keybindings;
};
static void MoveTableBy(Dialog * d, DItem * di, int dx, int dy);
static void DialogItemsRealize(Dialog * d);
static ImageClass *d_ic_default = NULL;
static TextClass *d_tc_default = NULL;
static void DialogRealizeTClassDefault(void);
static void DialogRealizeIClassDefault(void);
static void
DialogRealizeTClassDefault(void)
{
if (!d_tc_default)
{
d_tc_default = CreateTclass();
d_tc_default->norm.normal = CreateTextState();
d_tc_default->norm.normal->fontname =
Estrdup("-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*");
ESetColor(&(d_tc_default->norm.normal->fg_col), 0, 0, 0);
}
}
static void
DialogRealizeIClassDefault(void)
{
if (!d_ic_default)
{
d_ic_default = CreateIclass();
d_ic_default->name = NULL;
d_ic_default->norm.normal = CreateImageState();
ESetColor(&(d_ic_default->norm.normal->hihi), 255, 255, 255);
ESetColor(&(d_ic_default->norm.normal->hi), 220, 220, 220);
ESetColor(&(d_ic_default->norm.normal->bg), 160, 160, 160);
ESetColor(&(d_ic_default->norm.normal->lo), 100, 100, 100);
ESetColor(&(d_ic_default->norm.normal->lolo), 0, 0, 0);
d_ic_default->norm.normal->bevelstyle = BEVEL_NEXT;
d_ic_default->norm.hilited = CreateImageState();
ESetColor(&(d_ic_default->norm.hilited->hihi), 255, 255, 255);
ESetColor(&(d_ic_default->norm.hilited->hi), 240, 240, 240);
ESetColor(&(d_ic_default->norm.hilited->bg), 200, 200, 200);
ESetColor(&(d_ic_default->norm.hilited->lo), 160, 160, 160);
ESetColor(&(d_ic_default->norm.hilited->lolo), 0, 0, 0);
d_ic_default->norm.hilited->bevelstyle = BEVEL_NEXT;
d_ic_default->norm.clicked = CreateImageState();
ESetColor(&(d_ic_default->norm.clicked->hihi), 0, 0, 0);
ESetColor(&(d_ic_default->norm.clicked->hi), 100, 100, 100);
ESetColor(&(d_ic_default->norm.clicked->bg), 160, 160, 160);
ESetColor(&(d_ic_default->norm.clicked->lo), 220, 220, 220);
ESetColor(&(d_ic_default->norm.clicked->lolo), 255, 255, 255);
d_ic_default->norm.clicked->bevelstyle = BEVEL_NEXT;
d_ic_default->active.normal = CreateImageState();
ESetColor(&(d_ic_default->active.normal->hihi), 0, 0, 0);
ESetColor(&(d_ic_default->active.normal->hi), 100, 100, 100);
ESetColor(&(d_ic_default->active.normal->bg), 160, 160, 160);
ESetColor(&(d_ic_default->active.normal->lo), 220, 220, 220);
ESetColor(&(d_ic_default->active.normal->lolo), 255, 255, 255);
d_ic_default->active.normal->bevelstyle = BEVEL_NEXT;
d_ic_default->active.hilited = CreateImageState();
ESetColor(&(d_ic_default->active.hilited->hihi), 0, 0, 0);
ESetColor(&(d_ic_default->active.hilited->hi), 100, 100, 100);
ESetColor(&(d_ic_default->active.hilited->bg), 160, 160, 160);
ESetColor(&(d_ic_default->active.hilited->lo), 220, 220, 220);
ESetColor(&(d_ic_default->active.hilited->lolo), 255, 255, 255);
d_ic_default->active.hilited->bevelstyle = BEVEL_NEXT;
d_ic_default->active.clicked = CreateImageState();
ESetColor(&(d_ic_default->active.clicked->hihi), 0, 0, 0);
ESetColor(&(d_ic_default->active.clicked->hi), 100, 100, 100);
ESetColor(&(d_ic_default->active.clicked->bg), 160, 160, 160);
ESetColor(&(d_ic_default->active.clicked->lo), 220, 220, 220);
ESetColor(&(d_ic_default->active.clicked->lolo), 255, 255, 255);
d_ic_default->active.clicked->bevelstyle = BEVEL_NEXT;
d_ic_default->padding.left = 8;
d_ic_default->padding.right = 8;
d_ic_default->padding.top = 8;
d_ic_default->padding.bottom = 8;
}
IclassPopulate(d_ic_default);
}
void
DialogBindKey(Dialog * d, char *key, void (*func) (int val, void *data),
int val, void *data)
{
d->num_bindings++;
if (!d->keybindings)
d->keybindings = Emalloc(sizeof(DKeyBind) * d->num_bindings);
else
d->keybindings =
Erealloc(d->keybindings, sizeof(DKeyBind) * d->num_bindings);
d->keybindings[d->num_bindings - 1].val = val;
d->keybindings[d->num_bindings - 1].data = data;
d->keybindings[d->num_bindings - 1].func = func;
d->keybindings[d->num_bindings - 1].key =
XKeysymToKeycode(disp, XStringToKeysym(key));;
}
Dialog *
DialogCreate(char *name)
{
Dialog *d;
d = Emalloc(sizeof(Dialog));
d->name = Estrdup(name);
d->title = NULL;
d->text = NULL;
d->num_buttons = 0;
d->win = 0;
d->button = NULL;
d->win = ECreateWindow(root.win, -20, -20, 2, 2, 0);
d->item = NULL;
d->exit_func = NULL;
d->exit_val = 0;
d->exit_data = NULL;
d->tclass = FindItem("DIALOG", 0, LIST_FINDBY_NAME, LIST_TYPE_TCLASS);
if (!d->tclass)
{
DialogRealizeTClassDefault();
d->tclass = d_tc_default;
}
if (d->tclass)
d->tclass->ref_count++;
d->iclass = FindItem("DIALOG", 0, LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
if (!d->iclass)
{
DialogRealizeIClassDefault();
d->iclass = d_ic_default;
}
if (d->iclass)
d->iclass->ref_count++;
d->num_bindings = 0;
d->keybindings = NULL;
return d;
}
static void
FreeDButton(DButton * db)
{
if (db->text)
Efree(db->text);
if (db->iclass)
db->iclass->ref_count--;
if (db->tclass)
db->tclass->ref_count--;
Efree(db);
}
void
DialogDestroy(Dialog * d)
{
int i;
if (d->name)
Efree(d->name);
if (d->title)
Efree(d->title);
if (d->text)
Efree(d->text);
for (i = 0; i < d->num_buttons; i++)
FreeDButton(d->button[i]);
if (d->button)
Efree(d->button);
if (d->item)
DialogFreeItem(d->item);
if (d->iclass)
d->iclass->ref_count--;
if (d->tclass)
d->tclass->ref_count--;
if (d->keybindings)
Efree(d->keybindings);
Efree(d);
}
void
DialogSetText(Dialog * d, const char *text)
{
int w, h;
if (d->text)
Efree(d->text);
d->text = Estrdup(text);
if ((!d->tclass) || (!d->iclass))
return;
TextSize(d->tclass, 0, 0, STATE_NORMAL, text, &w, &h, 17);
d->w = w + d->iclass->padding.left + d->iclass->padding.right;
d->h = h + d->iclass->padding.top + d->iclass->padding.bottom;
}
void
DialogSetTitle(Dialog * d, const char *title)
{
if (d->title)
Efree(d->title);
d->title = Estrdup(title);
}
void
DialogSetExitFunction(Dialog * d, void (*func) (int val, void *data), int val,
void *data)
{
d->exit_func = func;
d->exit_val = val;
d->exit_data = data;
}
void
DialogAddButton(Dialog * d, char *text, void (*func) (int val, void *data),
char close)
{
DButton *db;
int w, h;
db = Emalloc(sizeof(DButton));
d->num_buttons++;
d->button = Erealloc(d->button, d->num_buttons * (sizeof(DButton *)));
d->button[d->num_buttons - 1] = db;
db->text = Estrdup(text);
db->func = func;
db->win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, db->win);
db->x = -1;
db->y = -1;
db->w = -1;
db->h = -1;
db->hilited = 0;
db->clicked = 0;
db->close = close;
db->tclass =
FindItem("DIALOG_BUTTON", 0, LIST_FINDBY_NAME, LIST_TYPE_TCLASS);
if (!db->tclass)
{
DialogRealizeTClassDefault();
db->tclass = d_tc_default;
}
if (db->tclass)
db->tclass->ref_count++;
db->iclass =
FindItem("DIALOG_BUTTON", 0, LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
if (!db->iclass)
{
DialogRealizeTClassDefault();
db->iclass = d_ic_default;
}
if (db->iclass)
db->iclass->ref_count++;
TextSize(db->tclass, 0, 0, STATE_NORMAL, text, &w, &h, 17);
db->w = w + db->iclass->padding.left + db->iclass->padding.right;
db->h = h + db->iclass->padding.top + db->iclass->padding.bottom;
XSelectInput(disp, db->win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask |
ButtonReleaseMask | ExposureMask);
}
static void
DialogDrawButton(Dialog * d, int bnum)
{
int state;
state = STATE_NORMAL;
if ((d->button[bnum]->hilited) && (d->button[bnum]->clicked))
{
state = STATE_CLICKED;
}
else if ((d->button[bnum]->hilited) && (!d->button[bnum]->clicked))
{
state = STATE_HILITED;
}
else if (!(d->button[bnum]->hilited) && (d->button[bnum]->clicked))
{
state = STATE_CLICKED;
}
IclassApply(d->button[bnum]->iclass, d->button[bnum]->win,
d->button[bnum]->w, d->button[bnum]->h, 0, 0, state, 0);
TclassApply(d->button[bnum]->iclass, d->button[bnum]->win,
d->button[bnum]->w, d->button[bnum]->h, 0, 0, state, 1,
d->button[bnum]->tclass, d->button[bnum]->text);
}
static void
DialogActivateButton(Window win, int inclick)
{
Dialog *d;
int bnum;
char doact = 0;
d = FindDialogButton(win, &bnum);
if (!d)
return;
if ((d->button[bnum]->hilited) && (d->button[bnum]->clicked)
&& (inclick == 3))
doact = 1;
if (inclick == 0)
d->button[bnum]->hilited = 1;
if (inclick == 1)
d->button[bnum]->hilited = 0;
if (inclick == 2)
d->button[bnum]->clicked = 1;
if (inclick == 3)
d->button[bnum]->clicked = 0;
DialogDrawButton(d, bnum);
if ((doact) && (d->button[bnum]->func))
(d->button[bnum]->func) (bnum, d);
if ((doact) && (d->button[bnum]->close))
DialogClose(d);
}
static void
DialogDraw(Dialog * d)
{
if ((!d->tclass) || (!d->iclass))
return;
if (d->text)
{
TclassApply(d->iclass, d->win, d->w, d->h, 0, 0, STATE_NORMAL, 1,
d->tclass, d->text);
}
else if (d->item)
{
DialogDrawItems(d, d->item, 0, 0, 99999, 99999);
}
}
static void
DialogDrawArea(Dialog * d, int x, int y, int w, int h)
{
if ((!d->tclass) || (!d->iclass))
return;
if (d->text)
{
TclassApply(d->iclass, d->win, d->w, d->h, 0, 0, STATE_NORMAL, 1,
d->tclass, d->text);
}
else if (d->item)
{
DialogDrawItems(d, d->item, x, y, w, h);
}
}
void
DialogRedraw(Dialog * d)
{
int i;
if ((!d->tclass) || (!d->iclass))
return;
IclassApply(d->iclass, d->win, d->w, d->h, 0, 0, STATE_NORMAL, 0);
for (i = 0; i < d->num_buttons; i++)
DialogDrawButton(d, i);
DialogDraw(d);
}
static void
DialogMoveResize(EWin * ewin, int resize)
{
Dialog *d = ewin->dialog;
if (!d)
return;
if (conf.theme.transparency || IclassIsTransparent(d->iclass))
DialogRedraw(d);
return;
resize = 0;
}
static void
DialogRefresh(EWin * ewin)
{
DialogMoveResize(ewin, 0);
}
static void
DialogEwinInit(EWin * ewin, void *ptr)
{
ewin->dialog = (Dialog *) ptr;
ewin->MoveResize = DialogMoveResize;
ewin->Refresh = DialogRefresh;
}
void
ShowDialog(Dialog * d)
{
char pq;
int i, w, h, mw, mh;
EWin *ewin;
XTextProperty xtp;
XClassHint *xch;
Snapshot *sn;
if (d->title)
{
xtp.encoding = XA_STRING;
xtp.format = 8;
xtp.value = (unsigned char *)(d->title);
xtp.nitems = strlen((char *)(xtp.value));
XSetWMName(disp, d->win, &xtp);
xch = XAllocClassHint();
xch->res_name = d->name;
xch->res_class = "Enlightenment_Dialog";
XSetClassHint(disp, d->win, xch);
XFree(xch);
}
ewin = FindEwinByDialog(d);
if (ewin)
{
if (ewin->desktop != desks.current)
MoveEwinToDesktopAt(ewin, desks.current, ewin->x, ewin->y);
RaiseEwin(ewin);
ShowEwin(ewin);
return;
}
if (d->item)
DialogItemsRealize(d);
w = d->w;
h = d->h;
mw = 0;
mh = 0;
for (i = 0; i < d->num_buttons; i++)
{
if (d->button[i]->w > mw)
mw = d->button[i]->w;
if (d->button[i]->h > mh)
mh = d->button[i]->h;
}
h += d->iclass->padding.top + d->iclass->padding.bottom + mh;
if ((d->iclass->padding.left + d->iclass->padding.right +
(d->num_buttons *
(mw + d->iclass->padding.left + d->iclass->padding.right))) > w)
w = d->iclass->padding.left + d->iclass->padding.right +
(d->num_buttons *
(mw + d->iclass->padding.left + d->iclass->padding.right));
for (i = 0; i < d->num_buttons; i++)
{
d->button[i]->x =
(((w
- (d->iclass->padding.left + d->iclass->padding.right)) -
(d->num_buttons *
(mw + d->iclass->padding.left +
d->iclass->padding.right))) / 2) + d->iclass->padding.left +
(i * (mw + d->iclass->padding.left + d->iclass->padding.right)) +
d->iclass->padding.left;
d->button[i]->y =
d->h - d->iclass->padding.bottom + d->iclass->padding.top;
d->button[i]->w = mw;
d->button[i]->h = mh;
EMoveResizeWindow(disp, d->button[i]->win, d->button[i]->x,
d->button[i]->y, d->button[i]->w, d->button[i]->h);
}
d->w = w;
d->h = h;
EResizeWindow(disp, d->win, w, h);
pq = queue_up;
queue_up = 0;
ewin = AddInternalToFamily(d->win, NULL, EWIN_TYPE_DIALOG, d,
DialogEwinInit);
XSelectInput(disp, d->win,
ExposureMask | PointerMotionMask | EnterWindowMask |
LeaveWindowMask | FocusChangeMask | KeyPressMask);
if (ewin)
{
sn = FindSnapshot(ewin);
/* get the size right damnit! */
if (sn && sn->use_wh)
ResizeEwin(ewin, sn->w, sn->h);
if (sn && sn->use_xy)
{
MoveEwin(ewin, sn->x, sn->y);
}
else
{
if (FindADialog() > 1)
ArrangeEwin(ewin);
else
ArrangeEwinCentered(ewin, 0);
}
ShowEwin(ewin);
}
if (!FindDialog(d->win))
AddItem(d, d->name, d->win, LIST_TYPE_DIALOG);
XSync(disp, False);
DialogRedraw(d);
queue_up = pq;
}
void
DialogClose(Dialog * d)
{
EWin *ewin;
XEvent ev;
if (!d)
return;
ewin = FindEwinByDialog(d);
EDestroyWindow(disp, d->win);
if (ewin)
{
HideEwin(ewin);
ev.xunmap.window = d->win;
HandleUnmap(&ev);
}
if (d->exit_func)
(d->exit_func) (d->exit_val, d->exit_data);
RemoveItem(NULL, d->win, LIST_FINDBY_ID, LIST_TYPE_DIALOG);
DialogDestroy(d);
}
DItem *
DialogInitItem(Dialog * d)
{
if (!d->item)
{
DItem *di;
di = Emalloc(sizeof(DItem));
d->item = di;
di->type = DITEM_TABLE;
di->func = NULL;
di->val = 0;
di->data = NULL;
di->iclass = NULL;
di->tclass = NULL;
di->padding.left = 0;
di->padding.right = 0;
di->padding.top = 0;
di->padding.bottom = 0;
di->fill_h = 0;
di->fill_v = 0;
di->align_h = 512;
di->align_v = 512;
di->row_span = 1;
di->col_span = 1;
di->x = 0;
di->y = 0;
di->w = 0;
di->h = 0;
di->hilited = 0;
di->clicked = 0;
di->win = 0;
di->item.table.num_columns = 1;
di->item.table.border = 0;
di->item.table.homogenous_h = 0;
di->item.table.homogenous_v = 0;
di->item.table.num_items = 0;
di->item.table.items = NULL;
return di;
}
return NULL;
}
DItem *
DialogAddItem(DItem * dii, int type)
{
DItem *di;
di = Emalloc(sizeof(DItem));
di->type = type;
di->func = NULL;
di->val = 0;
di->data = NULL;
di->iclass = NULL;
di->tclass = NULL;
di->padding.left = 0;
di->padding.right = 0;
di->padding.top = 0;
di->padding.bottom = 0;
di->fill_h = 1;
di->fill_v = 1;
di->align_h = 512;
di->align_v = 512;
di->row_span = 1;
di->col_span = 1;
di->x = 0;
di->y = 0;
di->w = 0;
di->h = 0;
di->hilited = 0;
di->clicked = 0;
di->win = 0;
switch (di->type)
{
case DITEM_NONE:
break;
case DITEM_AREA:
di->item.area.area_win = 0;
di->item.area.w = 32;
di->item.area.h = 32;
di->item.area.event_func = NULL;
break;
case DITEM_BUTTON:
di->item.button.text = NULL;
break;
case DITEM_CHECKBUTTON:
di->item.check_button.text = NULL;
di->item.check_button.check_win = 0;
di->item.check_button.onoff = 0;
di->item.check_button.onoff_ptr = NULL;
di->item.check_button.check_orig_w = 10;
di->item.check_button.check_orig_h = 10;
break;
case DITEM_TEXT:
di->item.text.text = NULL;
break;
case DITEM_TABLE:
di->item.table.num_columns = 1;
di->item.table.border = 0;
di->item.table.homogenous_h = 0;
di->item.table.homogenous_v = 0;
di->item.table.num_items = 0;
di->item.table.items = NULL;
break;
case DITEM_IMAGE:
di->item.image.image = NULL;
break;
case DITEM_SEPARATOR:
di->item.separator.horizontal = 0;
break;
case DITEM_RADIOBUTTON:
di->item.radio_button.text = NULL;
di->item.radio_button.radio_win = 0;
di->item.radio_button.onoff = 0;
di->item.radio_button.val = 0;
di->item.radio_button.val_ptr = 0;
di->item.radio_button.next = NULL;
di->item.radio_button.first = NULL;
di->item.radio_button.radio_orig_w = 10;
di->item.radio_button.radio_orig_h = 10;
di->item.radio_button.event_func = NULL;
break;
case DITEM_SLIDER:
di->item.slider.horizontal = 1;
di->item.slider.numeric = 0;
di->item.slider.numeric_side = 0;
di->item.slider.upper = 100;
di->item.slider.lower = 0;
di->item.slider.unit = 10;
di->item.slider.jump = 20;
di->item.slider.val = 0;
di->item.slider.val_ptr = NULL;
di->item.slider.min_length = 64;
di->item.slider.ic_base = NULL;
di->item.slider.ic_knob = NULL;
di->item.slider.ic_border = NULL;
di->item.slider.base_win = 0;
di->item.slider.knob_win = 0;
di->item.slider.border_win = 0;
di->item.slider.base_orig_w = 10;
di->item.slider.base_orig_h = 10;
di->item.slider.knob_orig_w = 6;
di->item.slider.knob_orig_h = 6;
di->item.slider.border_orig_w = 14;
di->item.slider.border_orig_h = 14;
di->item.slider.base_x = 0;
di->item.slider.base_y = 0;
di->item.slider.base_w = 0;
di->item.slider.base_h = 0;
di->item.slider.knob_x = 0;
di->item.slider.knob_y = 0;
di->item.slider.knob_w = 0;
di->item.slider.knob_h = 0;
di->item.slider.border_x = 0;
di->item.slider.border_y = 0;
di->item.slider.border_w = 0;
di->item.slider.border_h = 0;
di->item.slider.numeric_x = 0;
di->item.slider.numeric_y = 0;
di->item.slider.numeric_w = 0;
di->item.slider.numeric_h = 0;
di->item.slider.in_drag = 0;
di->item.slider.wanted_val = 0;
break;
default:
break;
}
if (dii)
{
dii->item.table.num_items++;
dii->item.table.items =
Erealloc(dii->item.table.items,
sizeof(DItem *) * dii->item.table.num_items);
dii->item.table.items[dii->item.table.num_items - 1] = di;
}
return di;
}
void
DialogItemSetCallback(DItem * di, void (*func) (int val, void *data), int val,
char *data)
{
di->func = func;
di->val = val;
di->data = data;
}
void
DialogItemSetClass(DItem * di, ImageClass * iclass, TextClass * tclass)
{
if (di->iclass)
di->iclass->ref_count--;
di->iclass = iclass;
if (di->iclass)
di->iclass->ref_count++;
if (di->tclass)
di->tclass->ref_count--;
di->tclass = tclass;
if (di->tclass)
di->tclass->ref_count++;
}
void
DialogItemSetPadding(DItem * di, int left, int right, int top, int bottom)
{
di->padding.left = left;
di->padding.right = right;
di->padding.top = top;
di->padding.bottom = bottom;
}
void
DialogItemSetFill(DItem * di, char fill_h, char fill_v)
{
di->fill_h = fill_h;
di->fill_v = fill_v;
}
void
DialogItemSetAlign(DItem * di, int align_h, int align_v)
{
di->align_h = align_h;
di->align_v = align_v;
}
void
DialogItemSetRowSpan(DItem * di, int row_span)
{
di->row_span = row_span;
}
void
DialogItemSetColSpan(DItem * di, int col_span)
{
di->col_span = col_span;
}
void
DialogItemCallCallback(DItem * di)
{
if (di->func)
di->func(di->val, di->data);
}
static void
DialogRealizeItem(Dialog * d, DItem * di)
{
char *def = NULL;
int iw = 0, ih = 0;
if (di->type == DITEM_BUTTON)
{
def = "DIALOG_WIDGET_BUTTON";
}
else if (di->type == DITEM_CHECKBUTTON)
{
def = "DIALOG_WIDGET_CHECK_BUTTON";
}
else if (di->type == DITEM_TEXT)
{
def = "DIALOG_WIDGET_TEXT";
}
else if (di->type == DITEM_SEPARATOR)
{
def = "DIALOG_WIDGET_SEPARATOR";
}
else if (di->type == DITEM_TABLE)
{
def = "DIALOG_WIDGET_TABLE";
}
else if (di->type == DITEM_RADIOBUTTON)
{
def = "DIALOG_WIDGET_RADIO_BUTTON";
}
else if (di->type == DITEM_AREA)
{
def = "DIALOG_WIDGET_AREA";
}
else
{
def = "DIALOG_WIDGET_BUTTON";
}
if (def)
{
if (!di->tclass)
di->tclass = FindItem(def, 0, LIST_FINDBY_NAME, LIST_TYPE_TCLASS);
if (!di->iclass)
di->iclass = FindItem(def, 0, LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
if (!di->tclass)
{
DialogRealizeTClassDefault();
di->tclass = d_tc_default;
}
if (di->tclass)
di->tclass->ref_count++;
if (!di->iclass)
{
DialogRealizeIClassDefault();
di->iclass = d_ic_default;
}
if (di->iclass)
di->iclass->ref_count++;
if (di->type == DITEM_TABLE)
{
int i;
for (i = 0; i < di->item.table.num_items; i++)
DialogRealizeItem(d, di->item.table.items[i]);
}
switch (di->type)
{
case DITEM_SLIDER:
if (di->item.slider.numeric)
{
di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->win);
XSelectInput(disp, di->win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask
| ButtonReleaseMask);
}
di->item.slider.base_win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->item.slider.base_win);
di->item.slider.knob_win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->item.slider.knob_win);
XSelectInput(disp, di->item.slider.base_win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask |
ButtonReleaseMask);
XSelectInput(disp, di->item.slider.knob_win,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
if (!di->item.slider.ic_base)
{
if (di->item.slider.horizontal)
{
di->item.slider.ic_base =
FindItem("DIALOG_WIDGET_SLIDER_BASE_HORIZONTAL", 0,
LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
else
{
di->item.slider.ic_base =
FindItem("DIALOG_WIDGET_SLIDER_BASE_VERTICAL", 0,
LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
}
if (!di->item.slider.ic_base)
{
DialogRealizeIClassDefault();
di->item.slider.ic_base = d_ic_default;
}
if (di->item.slider.ic_base->norm.normal->im_file)
{
Imlib_Image *im;
im = ELoadImage(di->item.slider.ic_base->norm.normal->im_file);
if (im)
{
imlib_context_set_image(im);
di->item.slider.base_orig_w = imlib_image_get_width();
di->item.slider.base_orig_h = imlib_image_get_height();
imlib_free_image();
}
}
if (di->item.slider.ic_base)
di->item.slider.ic_base->ref_count++;
if (!di->item.slider.ic_knob)
{
if (di->item.slider.horizontal)
{
di->item.slider.ic_knob =
FindItem("DIALOG_WIDGET_SLIDER_KNOB_HORIZONTAL", 0,
LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
else
{
di->item.slider.ic_knob =
FindItem("DIALOG_WIDGET_SLIDER_KNOB_VERTICAL", 0,
LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
}
if (!di->item.slider.ic_knob)
{
DialogRealizeIClassDefault();
di->item.slider.ic_knob = d_ic_default;
}
if (di->item.slider.ic_knob)
di->item.slider.ic_knob->ref_count++;
if (di->item.slider.ic_knob->norm.normal->im_file)
{
Imlib_Image *im;
im = ELoadImage(di->item.slider.ic_knob->norm.normal->im_file);
if (im)
{
imlib_context_set_image(im);
di->item.slider.knob_orig_w = imlib_image_get_width();
di->item.slider.knob_orig_h = imlib_image_get_height();
imlib_free_image();
}
}
if (!di->item.slider.ic_border)
{
if (di->item.slider.horizontal)
{
di->item.slider.ic_border =
FindItem("DIALOG_WIDGET_SLIDER_BORDER_HORIZONTAL", 0,
LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
else
{
di->item.slider.ic_border =
FindItem("DIALOG_WIDGET_SLIDER_BORDER_VERTICAL", 0,
LIST_FINDBY_NAME, LIST_TYPE_ICLASS);
}
}
if (di->item.slider.ic_border)
{
if (di->item.slider.ic_border->norm.normal->im_file)
{
Imlib_Image *im;
im = ELoadImage(di->item.slider.ic_border->norm.
normal->im_file);
if (im)
{
imlib_context_set_image(im);
di->item.slider.border_orig_w = imlib_image_get_width();
di->item.slider.border_orig_h = imlib_image_get_height();
imlib_free_image();
di->item.slider.border_win =
ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->item.slider.border_win);
}
}
di->item.slider.ic_border->ref_count++;
}
if (di->item.slider.horizontal)
{
iw = di->item.slider.min_length +
di->item.slider.ic_base->padding.left +
di->item.slider.ic_base->padding.right;
ih = di->item.slider.base_orig_h;
}
else
{
iw = di->item.slider.base_orig_w;
ih = di->item.slider.min_length +
di->item.slider.ic_base->padding.top +
di->item.slider.ic_base->padding.bottom;
}
di->w = iw;
di->h = ih;
break;
case DITEM_BUTTON:
TextSize(di->tclass, 0, 0, STATE_NORMAL, di->item.button.text, &iw,
&ih, 17);
iw += di->iclass->padding.left + di->iclass->padding.right;
ih += di->iclass->padding.top + di->iclass->padding.bottom;
di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->win);
XSelectInput(disp, di->win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask |
ButtonReleaseMask | ExposureMask);
di->w = iw;
di->h = ih;
break;
case DITEM_AREA:
iw = di->item.area.w;
ih = di->item.area.h;
iw += di->iclass->padding.left + di->iclass->padding.right;
ih += di->iclass->padding.top + di->iclass->padding.bottom;
di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->win);
XSelectInput(disp, di->win, ExposureMask);
di->item.area.area_win = ECreateWindow(di->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->item.area.area_win);
XSelectInput(disp, di->item.area.area_win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask |
ButtonReleaseMask | ExposureMask | PointerMotionMask);
di->w = iw;
di->h = ih;
break;
case DITEM_CHECKBUTTON:
if (di->iclass->norm.normal->im_file)
{
Imlib_Image *im;
im = ELoadImage(di->iclass->norm.normal->im_file);
if (im)
{
imlib_context_set_image(im);
di->item.check_button.check_orig_w = imlib_image_get_width();
di->item.check_button.check_orig_h = imlib_image_get_height();
imlib_free_image();
}
}
TextSize(di->tclass, 0, 0, STATE_NORMAL, di->item.check_button.text,
&iw, &ih, 17);
if (ih < di->item.check_button.check_orig_h)
ih = di->item.check_button.check_orig_h;
iw += di->item.check_button.check_orig_w + di->iclass->padding.left;
di->item.check_button.check_win =
ECreateWindow(d->win, -20, -20, 2, 2, 0);
di->win = ECreateEventWindow(d->win, -20, -20, 2, 2);
EMapWindow(disp, di->item.check_button.check_win);
EMapWindow(disp, di->win);
XSelectInput(disp, di->win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask |
ButtonReleaseMask | ExposureMask);
di->w = iw;
di->h = ih;
break;
case DITEM_TEXT:
TextSize(di->tclass, 0, 0, STATE_NORMAL, di->item.text.text, &iw, &ih,
17);
di->w = iw;
di->h = ih;
break;
case DITEM_IMAGE:
{
Imlib_Image *im;
im = ELoadImage(di->item.image.image);
if (im)
{
Pixmap pmap = 0, mask = 0;
imlib_context_set_image(im);
iw = imlib_image_get_width();
ih = imlib_image_get_height();
di->win = ECreateWindow(d->win, 0, 0, iw, ih, 0);
EMapWindow(disp, di->win);
imlib_render_pixmaps_for_whole_image(&pmap, &mask);
ESetWindowBackgroundPixmap(disp, di->win, pmap);
EShapeCombineMask(disp, di->win, ShapeBounding, 0,
0, mask, ShapeSet);
IMLIB_FREE_PIXMAP_AND_MASK(pmap, mask);
imlib_free_image();
}
}
di->w = iw;
di->h = ih;
break;
case DITEM_SEPARATOR:
iw = di->iclass->padding.left + di->iclass->padding.right;
ih = di->iclass->padding.top + di->iclass->padding.bottom;
di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0);
EMapWindow(disp, di->win);
di->w = iw;
di->h = ih;
break;
case DITEM_RADIOBUTTON:
if (di->iclass->norm.normal->im_file)
{
Imlib_Image *im;
im = ELoadImage(di->iclass->norm.normal->im_file);
if (im)
{
imlib_context_set_image(im);
di->item.radio_button.radio_orig_w = imlib_image_get_width();
di->item.radio_button.radio_orig_h = imlib_image_get_height();
imlib_free_image();
}
}
TextSize(di->tclass, 0, 0, STATE_NORMAL, di->item.radio_button.text,
&iw, &ih, 17);
if (ih < di->item.radio_button.radio_orig_h)
ih = di->item.radio_button.radio_orig_h;
iw += di->item.radio_button.radio_orig_w + di->iclass->padding.left;
di->item.radio_button.radio_win =
ECreateWindow(d->win, -20, -20, 2, 2, 0);
di->win = ECreateEventWindow(d->win, -20, -20, 2, 2);
EMapWindow(disp, di->item.radio_button.radio_win);
EMapWindow(disp, di->win);
XSelectInput(disp, di->win,
EnterWindowMask | LeaveWindowMask | ButtonPressMask |
ButtonReleaseMask | ExposureMask);
di->w = iw;
di->h = ih;
break;
case DITEM_TABLE:
{
int cols, rows;
cols = di->item.table.num_columns;
rows = 1;
if ((cols > 0) && (rows > 0))
{
int i, *col_size, *row_size = NULL, r = 0, c =
0, x = 0, y = 0;
col_size = Emalloc(sizeof(int) * cols);
row_size = Erealloc(row_size, sizeof(int));
row_size[0] = 0;
for (i = 0; i < cols; i++)
col_size[i] = 0;
for (i = 0; i < di->item.table.num_items; i++)
{
DItem *dii;
int w, h, j, csum = 0;
dii = di->item.table.items[i];
w = dii->w + (dii->padding.left + dii->padding.right);
h = dii->h + (dii->padding.top + dii->padding.bottom);
for (j = 0; j < dii->col_span; j++)
csum += col_size[c + j];
if (w > csum)
col_size[c + di->col_span - 1] += (w - csum);
if (h > row_size[r])
row_size[r] = h;
c += dii->col_span;
if (c >= cols)
{
c = 0;
r++;
rows++;
row_size = Erealloc(row_size, sizeof(int) * rows);
row_size[rows - 1] = 0;
}
}
if (di->item.table.homogenous_h)
{
int max = 0;
for (i = 0; i < cols; i++)
{
if (col_size[i] > max)
max = col_size[i];
}
for (i = 0; i < cols; i++)
col_size[i] = max;
}
if (di->item.table.homogenous_v)
{
int max = 0;
for (i = 0; i < rows; i++)
{
if (row_size[i] > max)
max = row_size[i];
}
for (i = 0; i < rows; i++)
row_size[i] = max;
}
iw = 0;
ih = 0;
for (i = 0; i < cols; i++)
iw += col_size[i];
for (i = 0; i < rows; i++)
ih += row_size[i];
di->w = iw;
di->h = ih;
r = 0;
c = 0;
for (i = 0; i < di->item.table.num_items; i++)
{
DItem *dii;
int j, sw = 0, sh = 0;
dii = di->item.table.items[i];
for (j = 0; j < dii->col_span; j++)
sw += col_size[c + j];
for (j = 0; j < dii->row_span; j++)
sh += row_size[r + j];
if (dii->fill_h)
dii->w = sw - (dii->padding.left + dii->padding.right);
if (dii->fill_v)
dii->h = sh - (dii->padding.top + dii->padding.bottom);
if (dii->type == DITEM_TABLE)
{
int dx, dy, newx, newy;
newx =
di->x + x + d->iclass->padding.left +
dii->padding.left +
(((sw
- (dii->padding.left + dii->padding.right) -
dii->w) * dii->align_h) >> 10);
newy =
di->y + y + d->iclass->padding.top +
dii->padding.top +
(((sh
- (dii->padding.top + dii->padding.bottom) -
dii->h) * dii->align_v) >> 10);
dx = newx - dii->x - d->iclass->padding.left;
dy = newy - dii->y - d->iclass->padding.top;
MoveTableBy(d, dii, dx, dy);
}
else
{
dii->x =
di->x + x + d->iclass->padding.left +
dii->padding.left +
(((sw
- (dii->padding.left + dii->padding.right) -
dii->w) * dii->align_h) >> 10);
dii->y =
di->y + y + d->iclass->padding.top +
dii->padding.top +
(((sh
- (dii->padding.top + dii->padding.bottom) -
dii->h) * dii->align_v) >> 10);
if (dii->win)
EMoveResizeWindow(disp, dii->win, dii->x, dii->y,
dii->w, dii->h);
if (dii->type == DITEM_CHECKBUTTON)
EMoveResizeWindow(disp,
dii->item.check_button.
check_win, dii->x,
dii->y +
((dii->h -
dii->item.check_button.
check_orig_h) / 2),
dii->item.check_button.
check_orig_w,
dii->item.check_button.
check_orig_h);
if (dii->type == DITEM_RADIOBUTTON)
EMoveResizeWindow(disp,
dii->item.radio_button.
radio_win, dii->x,
dii->y +
((dii->h -
dii->item.radio_button.
radio_orig_h) / 2),
dii->item.radio_button.
radio_orig_w,
dii->item.radio_button.
radio_orig_h);
if (dii->type == DITEM_AREA)
{
dii->item.area.w =
dii->w - (dii->iclass->padding.left +
dii->iclass->padding.right);
dii->item.area.h =
dii->h - (dii->iclass->padding.top +
dii->iclass->padding.bottom);
EMoveResizeWindow(disp,
dii->item.area.area_win,
dii->iclass->padding.left,
dii->iclass->padding.top,
dii->item.area.w,
dii->item.area.h);
}
if (dii->type == DITEM_SLIDER)
{
dii->item.slider.base_x = 0;
dii->item.slider.base_y = 0;
dii->item.slider.base_w = dii->w;
dii->item.slider.base_h = dii->h;
dii->item.slider.border_x = 0;
dii->item.slider.border_y = 0;
dii->item.slider.border_w = dii->w;
dii->item.slider.border_h = dii->h;
dii->item.slider.knob_w =
dii->item.slider.knob_orig_w;
dii->item.slider.knob_h =
dii->item.slider.knob_orig_h;
if (dii->item.slider.base_win)
EMoveResizeWindow(disp,
dii->item.slider.base_win,
dii->x +
dii->item.slider.base_x,
dii->y +
dii->item.slider.base_y,
dii->item.slider.base_w,
dii->item.slider.base_h);
if (dii->item.slider.border_win)
EMoveResizeWindow(disp,
dii->item.slider.
border_win,
dii->x +
dii->item.slider.border_x,
dii->y +
dii->item.slider.border_y,
dii->item.slider.border_w,
dii->item.slider.border_h);
if (dii->win)
EMoveResizeWindow(disp, dii->win,
dii->x +
dii->item.slider.
numeric_x,
dii->y +
dii->item.slider.
numeric_y,
dii->item.slider.
numeric_w,
dii->item.slider.numeric_h);
}
}
x += sw;
c += dii->col_span;
if (c >= cols)
{
x = 0;
y += row_size[r];
c = 0;
r++;
}
}
if (col_size)
Efree(col_size);
if (row_size)
Efree(row_size);
}
}
break;
case DITEM_NONE:
default:
di->w = 0;
di->h = 0;
break;
}
}
static void
MoveTableBy(Dialog * d, DItem * di, int dx, int dy)
{
int i;
di->x += dx;
di->y += dy;
for (i = 0; i < di->item.table.num_items; i++)
{
DItem *dii;
dii = di->item.table.items[i];
dii->x += dx;
dii->y += dy;
if (dii->type == DITEM_TABLE)
MoveTableBy(d, dii, dx, dy);
if (dii->win)
EMoveWindow(disp, dii->win, dii->x, dii->y);
if (dii->type == DITEM_CHECKBUTTON)
EMoveWindow(disp, dii->item.check_button.check_win, dii->x,
dii->y +
((dii->h - dii->item.check_button.check_orig_h) / 2));
if (dii->type == DITEM_RADIOBUTTON)
EMoveWindow(disp, dii->item.radio_button.radio_win, dii->x,
dii->y +
((dii->h - dii->item.radio_button.radio_orig_h) / 2));
if (dii->type == DITEM_SLIDER)
{
if (dii->item.slider.base_win)
EMoveResizeWindow(disp, dii->item.slider.base_win,
dii->x + dii->item.slider.base_x,
dii->y + dii->item.slider.base_y,
dii->item.slider.base_w,
dii->item.slider.base_h);
if (dii->item.slider.knob_win)
EMoveResizeWindow(disp, dii->item.slider.knob_win,
dii->x + dii->item.slider.knob_x,
dii->y + dii->item.slider.knob_y,
dii->item.slider.knob_w,
dii->item.slider.knob_h);
if (dii->item.slider.border_win)
EMoveResizeWindow(disp, dii->item.slider.border_win,
dii->x + dii->item.slider.border_x,
dii->y + dii->item.slider.border_y,
dii->item.slider.border_w,
dii->item.slider.border_h);
if (dii->win)
EMoveResizeWindow(disp, dii->win,
dii->x + dii->item.slider.numeric_x,
dii->y + dii->item.slider.numeric_y,
dii->item.slider.numeric_w,
dii->item.slider.numeric_h);
}
}
}
#define INTERSECTS(x, y, w, h, xx, yy, ww, hh) \
((x < (xx + ww)) && \
(y < (yy + hh)) && \
((x + w) > xx) && \
((y + h) > yy))
void
DialogDrawItems(Dialog * d, DItem * di, int x, int y, int w, int h)
{
int state;
if (queue_up)
{
DrawQueue *dq;
dq = Emalloc(sizeof(DrawQueue));
dq->win = 0;
dq->iclass = NULL;
dq->w = w;
dq->h = h;
dq->active = 0;
dq->sticky = 0;
dq->state = 0;
dq->expose = 0;
dq->tclass = NULL;
dq->text = NULL;
dq->shape_propagate = 0;
dq->pager = NULL;
dq->redraw_pager = NULL;
dq->d = d;
dq->di = di;
dq->x = x;
dq->y = y;
AddItem(dq, "DRAW", 0, LIST_TYPE_DRAW);
EDBUG_RETURN_;
}
if (di->type == DITEM_TABLE)
{
int i;
if (INTERSECTS(x, y, w, h, di->x, di->y, di->w, di->h))
{
for (i = 0; i < di->item.table.num_items; i++)
DialogDrawItems(d, di->item.table.items[i], x, y, w, h);
}
return;
}
if (INTERSECTS(x, y, w, h, di->x, di->y, di->w, di->h))
{
switch (di->type)
{
case DITEM_SLIDER:
if (di->item.slider.horizontal)
{
di->item.slider.knob_x =
di->item.slider.base_x +
(((di->item.slider.base_w -
di->item.slider.knob_w) * (di->item.slider.val -
di->item.slider.lower)) /
(di->item.slider.upper - di->item.slider.lower));
di->item.slider.knob_y =
di->item.slider.base_y +
((di->item.slider.base_h - di->item.slider.knob_h) / 2);
}
else
{
di->item.slider.knob_y =
(di->item.slider.base_y + di->item.slider.base_h -
di->item.slider.knob_h) -
(((di->item.slider.base_h -
di->item.slider.knob_h) * (di->item.slider.val -
di->item.slider.lower)) /
(di->item.slider.upper - di->item.slider.lower));
di->item.slider.knob_x =
di->item.slider.base_x +
((di->item.slider.base_w - di->item.slider.knob_w) / 2);
}
if (di->item.slider.knob_win)
EMoveResizeWindow(disp, di->item.slider.knob_win,
di->x + di->item.slider.knob_x,
di->y + di->item.slider.knob_y,
di->item.slider.knob_w,
di->item.slider.knob_h);
if (di->item.slider.base_win)
IclassApply(di->item.slider.ic_base, di->item.slider.base_win,
di->item.slider.base_w, di->item.slider.base_h, 0,
0, STATE_NORMAL, 0);
if (di->item.slider.border_win)
IclassApply(di->item.slider.ic_border,
di->item.slider.border_win,
di->item.slider.border_w,
di->item.slider.border_h, 0, 0, STATE_NORMAL, 0);
state = STATE_NORMAL;
if ((di->hilited) && (di->clicked))
state = STATE_CLICKED;
else if ((di->hilited) && (!di->clicked))
state = STATE_HILITED;
else if (!(di->hilited) && (di->clicked))
state = STATE_CLICKED;
if (di->item.slider.knob_win)
IclassApply(di->item.slider.ic_knob, di->item.slider.knob_win,
di->item.slider.knob_w, di->item.slider.knob_h, 0,
0, state, 0);
break;
case DITEM_BUTTON:
state = STATE_NORMAL;
if ((di->hilited) && (di->clicked))
state = STATE_CLICKED;
else if ((di->hilited) && (!di->clicked))
state = STATE_HILITED;
else if (!(di->hilited) && (di->clicked))
state = STATE_CLICKED;
IclassApply(di->iclass, di->win, di->w, di->h, 0, 0, state, 0);
TclassApply(di->iclass, di->win, di->w, di->h, 0, 0, state, 1,
di->tclass, di->item.button.text);
break;
case DITEM_AREA:
IclassApply(di->iclass, di->win, di->w, di->h, 0, 0,
STATE_NORMAL, 0);
break;
case DITEM_CHECKBUTTON:
state = STATE_NORMAL;
if ((di->hilited) && (di->clicked))
state = STATE_CLICKED;
else if ((di->hilited) && (!di->clicked))
state = STATE_HILITED;
else if (!(di->hilited) && (di->clicked))
state = STATE_CLICKED;
if (di->item.check_button.onoff)
IclassApply(di->iclass, di->item.check_button.check_win,
di->item.check_button.check_orig_w,
di->item.check_button.check_orig_h, 1, 0, state, 0);
else
IclassApply(di->iclass, di->item.check_button.check_win,
di->item.check_button.check_orig_w,
di->item.check_button.check_orig_h, 0, 0, state, 0);
XClearArea(disp, d->win, di->x, di->y, di->w, di->h, False);
TextDraw(di->tclass, d->win, 0, 0, STATE_NORMAL,
di->item.check_button.text,
di->x + di->item.check_button.check_orig_w +
di->iclass->padding.left, di->y,
di->w - di->item.check_button.check_orig_w -
di->iclass->padding.left, 99999, 17,
di->tclass->justification);
break;
case DITEM_TEXT:
XClearArea(disp, d->win, di->x, di->y, di->w, di->h, False);
TextDraw(di->tclass, d->win, 0, 0, STATE_NORMAL,
di->item.text.text, di->x, di->y, di->w, 99999, 17,
di->tclass->justification);
break;
case DITEM_IMAGE:
break;
case DITEM_SEPARATOR:
if (di->item.separator.horizontal)
IclassApply(di->iclass, di->win, di->w, di->h, 0, 0,
STATE_NORMAL, 0);
else
IclassApply(di->iclass, di->win, di->w, di->h, 0, 0,
STATE_CLICKED, 0);
break;
case DITEM_RADIOBUTTON:
state = STATE_NORMAL;
if ((di->hilited) && (di->clicked))
state = STATE_CLICKED;
else if ((di->hilited) && (!di->clicked))
state = STATE_HILITED;
else if (!(di->hilited) && (di->clicked))
state = STATE_CLICKED;
if (di->item.radio_button.onoff)
IclassApply(di->iclass, di->item.radio_button.radio_win,
di->item.radio_button.radio_orig_w,
di->item.radio_button.radio_orig_h, 1, 0, state, 0);
else
IclassApply(di->iclass, di->item.radio_button.radio_win,
di->item.radio_button.radio_orig_w,
di->item.radio_button.radio_orig_w, 0, 0, state, 0);
XClearArea(disp, d->win, di->x, di->y, di->w, di->h, False);
TextDraw(di->tclass, d->win, 0, 0, STATE_NORMAL,
di->item.radio_button.text,
di->x + di->item.radio_button.radio_orig_w +
di->iclass->padding.left, di->y,
di->w - di->item.radio_button.radio_orig_w -
di->iclass->padding.left, 99999, 17,
di->tclass->justification);
break;
default:
break;
}
}
}
static void
DialogItemsRealize(Dialog * d)
{
char pq;
if (!d->item)
return;
DialogRealizeItem(d, d->item);
pq = queue_up;
queue_up = 0;
DialogDrawItems(d, d->item, 0, 0, 99999, 99999);
queue_up = pq;
d->w = d->item->w + d->iclass->padding.left + d->iclass->padding.right;
d->h = d->item->h + d->iclass->padding.top + d->iclass->padding.bottom;
}
void
DialogItemButtonSetText(DItem * di, char *text)
{
if (di->item.button.text)
Efree(di->item.button.text);
di->item.button.text = Estrdup(text);
}
void
DialogItemCheckButtonSetText(DItem * di, char *text)
{
if (di->item.check_button.text)
Efree(di->item.check_button.text);
di->item.check_button.text = Estrdup(text);
}
void
DialogItemTextSetText(DItem * di, char *text)
{
if (di->item.text.text)
Efree(di->item.text.text);
di->item.text.text = Estrdup(text);
}
void
DialogItemRadioButtonSetEventFunc(DItem * di,
void (*func) (int val, void *data))
{
di->item.radio_button.event_func = func;
}
void
DialogItemRadioButtonSetText(DItem * di, char *text)
{
if (di->item.radio_button.text)
Efree(di->item.radio_button.text);
di->item.radio_button.text = Estrdup(text);
}
void
DialogItemRadioButtonSetFirst(DItem * di, DItem * first)
{
di->item.radio_button.first = first;
if (di == first)
return;
while (first->item.radio_button.next)
first = first->item.radio_button.next;
first->item.radio_button.next = di;
}
void
DialogItemRadioButtonGroupSetValPtr(DItem * di, int *val_ptr)
{
while (di)
{
di->item.radio_button.val_ptr = val_ptr;
if (*val_ptr == di->item.radio_button.val)
di->item.check_button.onoff = 1;
di = di->item.radio_button.next;
}
}
void
DialogItemRadioButtonGroupSetVal(DItem * di, int val)
{
di->item.radio_button.val = val;
}
void
DialogItemCheckButtonSetState(DItem * di, char onoff)
{
di->item.check_button.onoff = onoff;
}
void
DialogItemCheckButtonSetPtr(DItem * di, char *onoff_ptr)
{
di->item.check_button.onoff_ptr = onoff_ptr;
}
void
DialogItemTableSetOptions(DItem * di, int num_columns, char border,
char homogenous_h, char homogenous_v)
{
di->item.table.num_columns = num_columns;
di->item.table.border = border;
di->item.table.homogenous_h = homogenous_h;
di->item.table.homogenous_v = homogenous_v;
}
void
DialogItemSeparatorSetOrientation(DItem * di, char horizontal)
{
di->item.separator.horizontal = horizontal;
}
void
DialogItemImageSetFile(DItem * di, char *image)
{
if (di->item.image.image)
Efree(di->item.image.image);
di->item.image.image = Estrdup(image);
di->fill_h = 0;
di->fill_v = 0;
}
void
DialogItemSliderSetVal(DItem * di, int val)
{
if (val < di->item.slider.lower)
val = di->item.slider.lower;
else if (val > di->item.slider.upper)
val = di->item.slider.upper;
di->item.slider.val = val;
if (di->item.slider.val_ptr)
*di->item.slider.val_ptr = val;
}
void
DialogItemSliderSetBounds(DItem * di, int lower, int upper)
{
if (lower < upper)
{
di->item.slider.lower = lower;
di->item.slider.upper = upper;
}
else
{
di->item.slider.lower = upper;
di->item.slider.upper = lower;
}
if (di->item.slider.upper <= di->item.slider.lower)
di->item.slider.upper = di->item.slider.lower + 1;
}
void
DialogItemSliderSetUnits(DItem * di, int units)
{
di->item.slider.unit = units;
}
void
DialogItemSliderSetJump(DItem * di, int jump)
{
di->item.slider.jump = jump;
}
void
DialogItemSliderSetMinLength(DItem * di, int min)
{
di->item.slider.min_length = min;
}
void
DialogItemSliderSetValPtr(DItem * di, int *val_ptr)
{
di->item.slider.val_ptr = val_ptr;
}
void
DialogItemSliderSetOrientation(DItem * di, char horizontal)
{
di->item.slider.horizontal = horizontal;
}
int
DialogItemSliderGetVal(DItem * di)
{
return di->item.slider.val;
}
void
DialogItemSliderGetBounds(DItem * di, int *lower, int *upper)
{
if (lower)
*lower = di->item.slider.lower;
if (upper)
*upper = di->item.slider.upper;
}
void
DialogItemAreaSetSize(DItem * di, int w, int h)
{
di->item.area.w = w;
di->item.area.h = h;
}
Window
DialogItemAreaGetWindow(DItem * di)
{
return di->item.area.area_win;
}
void
DialogItemAreaGetSize(DItem * di, int *w, int *h)
{
*w = di->item.area.w;
*h = di->item.area.h;
}
void
DialogItemAreaSetEventFunc(DItem * di, void (*func) (int val, void *data))
{
di->item.area.event_func = func;
}
void
DialogFreeItem(DItem * di)
{
if (di->type == DITEM_TABLE)
{
int i;
for (i = 0; i < di->item.table.num_items; i++)
DialogFreeItem(di->item.table.items[i]);
}
switch (di->type)
{
case DITEM_BUTTON:
if (di->item.button.text)
Efree(di->item.button.text);
break;
case DITEM_CHECKBUTTON:
if (di->item.check_button.text)
Efree(di->item.check_button.text);
break;
case DITEM_TEXT:
if (di->item.text.text)
Efree(di->item.text.text);
break;
case DITEM_IMAGE:
if (di->item.image.image)
Efree(di->item.image.image);
break;
case DITEM_RADIOBUTTON:
if (di->item.radio_button.text)
Efree(di->item.radio_button.text);
break;
case DITEM_SLIDER:
if (di->item.slider.ic_base)
di->item.slider.ic_base->ref_count--;
if (di->item.slider.ic_knob)
di->item.slider.ic_knob->ref_count--;
if (di->item.slider.ic_border)
di->item.slider.ic_border->ref_count--;
break;
case DITEM_SEPARATOR:
break;
case DITEM_TABLE:
if (di->item.table.items)
Efree(di->item.table.items);
break;
default:
break;
}
if (di->iclass)
di->iclass->ref_count--;
if (di->tclass)
di->tclass->ref_count--;
Efree(di);
}
static DItem *
DialogItemFindWindow(DItem * di, Window win)
{
DItem *dii = NULL;
if (di->type == DITEM_TABLE)
{
int i;
for (i = 0; i < di->item.table.num_items; i++)
{
if ((dii = DialogItemFindWindow(di->item.table.items[i], win)))
return dii;
}
}
else if ((di->win == win)
|| ((di->type == DITEM_SLIDER)
&& ((di->item.slider.base_win == win)
|| (di->item.slider.knob_win == win)))
|| ((di->type == DITEM_AREA) && (di->item.area.area_win == win)))
{
return di;
}
return NULL;
}
DItem *
DialogItem(Dialog * d)
{
return d->item;
}
/*
* Predefined dialogs
*/
void
DialogOK(const char *title, const char *fmt, ...)
{
char text[10240];
va_list ap;
va_start(ap, fmt);
Evsnprintf(text, sizeof(text), fmt, ap);
va_end(ap);
DialogOKstr(title, text);
}
void
DialogOKstr(const char *title, const char *txt)
{
Dialog *d;
d = DialogCreate("DIALOG");
DialogSetTitle(d, title);
DialogSetText(d, txt);
DialogAddButton(d, _("OK"), NULL, 1);
ShowDialog(d);
}
void
DialogRestart(int val, void *data)
{
SessionExit("restart");
val = 0;
data = NULL;
}
void
DialogQuit(int val, void *data)
{
SessionExit("error");
val = 0;
data = NULL;
}
void
DialogAlert(const char *fmt, ...)
{
char text[10240];
va_list ap;
va_start(ap, fmt);
Evsnprintf(text, 10240, fmt, ap);
va_end(ap);
Alert(text);
}
void
DialogAlertOK(const char *fmt, ...)
{
char text[10240];
va_list ap;
va_start(ap, fmt);
Evsnprintf(text, 10240, fmt, ap);
va_end(ap);
AlertX(_("Attention !!!"), _("OK"), " ", " ", text);
}
/*
* Dialog event handlers
*/
int
DialogEventKeyPress(XEvent * ev)
{
Dialog *d;
int i;
d = FindDialog(ev->xkey.window);
if (d == NULL)
return 0;
for (i = 0; i < d->num_bindings; i++)
{
if (ev->xkey.keycode == d->keybindings[i].key)
(d->keybindings[i].func) (d->keybindings[i].val,
d->keybindings[i].data);
}
return 1;
}
int
DialogEventMotion(XEvent * ev)
{
Dialog *d;
DItem *di;
int dx, dy;
di = FindDialogItem(ev->xmotion.window, &d);
if (d == NULL)
return 0;
if (di == NULL)
goto exit;
if (di->type == DITEM_AREA)
{
if (di->item.area.event_func)
(di->item.area.event_func) (0, ev);
}
else if ((di->type == DITEM_SLIDER) && (di->item.slider.in_drag))
{
if (ev->xmotion.window == di->item.slider.knob_win)
{
dx = mode.x - mode.px;
dy = mode.y - mode.py;
if (di->item.slider.horizontal)
{
di->item.slider.wanted_val += dx;
di->item.slider.val =
di->item.slider.lower +
(((di->item.slider.wanted_val *
(di->item.slider.upper -
di->item.slider.lower)) /
(di->item.slider.base_w -
di->item.slider.knob_w)) /
di->item.slider.unit) * di->item.slider.unit;
}
else
{
di->item.slider.wanted_val += dy;
di->item.slider.val =
di->item.slider.lower +
((((di->item.
slider.base_h - di->item.slider.knob_h -
di->item.slider.wanted_val) *
(di->item.slider.upper -
di->item.slider.lower)) /
(di->item.slider.base_h -
di->item.slider.knob_h)) /
di->item.slider.unit) * di->item.slider.unit;
}
if (di->item.slider.val < di->item.slider.lower)
di->item.slider.val = di->item.slider.lower;
if (di->item.slider.val > di->item.slider.upper)
di->item.slider.val = di->item.slider.upper;
if (di->item.slider.val_ptr)
*di->item.slider.val_ptr = di->item.slider.val;
if (di->func)
(di->func) (di->val, di->data);
}
DialogDrawItems(d, di, 0, 0, 99999, 99999);
}
exit:
return 1;
}
int
DialogEventExpose(XEvent * ev)
{
Window win = ev->xexpose.window;
Dialog *d;
int bnum;
DItem *di;
int x, y, w, h;
d = FindDialog(win);
if (d)
{
DialogDrawArea(d, ev->xexpose.x, ev->xexpose.y,
ev->xexpose.width, ev->xexpose.height);
goto exit;
}
d = FindDialogButton(win, &bnum);
if (d)
{
DialogDrawButton(d, bnum);
goto exit;
}
di = FindDialogItem(win, &d);
if (d == NULL)
return 0;
GetWinXY(win, &x, &y);
GetWinWH(win, (unsigned int *)&w, (unsigned int *)&h);
DialogDrawArea(d, x, y, w, h);
if (di == NULL)
goto exit;
if (di->type == DITEM_AREA)
{
if (di->func)
(di->func) (di->val, di->data);
}
exit:
return 1;
}
int
DialogEventMouseDown(XEvent * ev)
{
Window win = ev->xbutton.window;
Dialog *d;
int bnum;
DItem *di;
d = FindDialogButton(win, &bnum);
if (d)
{
DialogActivateButton(win, 2);
goto exit;
}
di = FindDialogItem(win, &d);
if (d == NULL)
return 0;
if (di == NULL)
goto exit;
if (di->type == DITEM_AREA)
{
if (di->item.area.event_func)
(di->item.area.event_func) (0, ev);
}
else if (di->type == DITEM_SLIDER)
{
if (win == di->item.slider.base_win)
{
if (di->item.slider.horizontal)
{
if (ev->xbutton.x >
(di->item.slider.knob_x + (di->item.slider.knob_w / 2)))
di->item.slider.val += di->item.slider.jump;
else
di->item.slider.val -= di->item.slider.jump;
}
else
{
if (ev->xbutton.y >
(di->item.slider.knob_y + (di->item.slider.knob_h / 2)))
di->item.slider.val -= di->item.slider.jump;
else
di->item.slider.val += di->item.slider.jump;
}
if (di->item.slider.val < di->item.slider.lower)
di->item.slider.val = di->item.slider.lower;
if (di->item.slider.val > di->item.slider.upper)
di->item.slider.val = di->item.slider.upper;
if (di->item.slider.val_ptr)
*di->item.slider.val_ptr = di->item.slider.val;
if (di->func)
(di->func) (di->val, di->data);
}
else if (win == di->item.slider.knob_win)
{
di->item.slider.in_drag = 1;
if (di->item.slider.horizontal)
di->item.slider.wanted_val = di->item.slider.knob_x;
else
di->item.slider.wanted_val = di->item.slider.knob_y;
}
}
di->clicked = 1;
DialogDrawItems(d, di, 0, 0, 99999, 99999);
exit:
return 1;
}
int
DialogEventMouseUp(XEvent * ev)
{
Window win = mode.context_win;
Dialog *d;
int bnum;
DItem *di;
d = FindDialogButton(win, &bnum);
if (d)
{
DialogActivateButton(win, 3);
goto exit;
}
di = FindDialogItem(win, &d);
if (d == NULL)
return 0;
if (di == NULL)
goto exit;
di->clicked = 0;
if (win)
{
if (di->type == DITEM_AREA)
{
if (di->item.area.event_func)
(di->item.area.event_func) (0, ev);
}
else if (di->type == DITEM_CHECKBUTTON)
{
if (di->item.check_button.onoff)
di->item.check_button.onoff = 0;
else
di->item.check_button.onoff = 1;
if (di->item.check_button.onoff_ptr)
*di->item.check_button.onoff_ptr = di->item.check_button.onoff;
}
else if (di->type == DITEM_RADIOBUTTON)
{
DItem *dii;
dii = di->item.radio_button.first;
while (dii)
{
if (dii->item.radio_button.onoff)
{
dii->item.radio_button.onoff = 0;
DialogDrawItems(d, dii, 0, 0, 99999, 99999);
}
dii = dii->item.radio_button.next;
}
di->item.radio_button.onoff = 1;
if (di->item.radio_button.val_ptr)
*di->item.radio_button.val_ptr = di->item.radio_button.val;
}
else if (di->type == DITEM_SLIDER)
{
if (win == di->item.slider.knob_win)
di->item.slider.in_drag = 0;
}
}
DialogDrawItems(d, di, 0, 0, 99999, 99999);
if (win)
{
if (di->func)
(di->func) (di->val, di->data);
}
exit:
return 1;
}
int
DialogEventMouseIn(XEvent * ev)
{
Window win = ev->xcrossing.window;
Dialog *d;
int bnum;
DItem *di;
d = FindDialogButton(win, &bnum);
if (d)
{
DialogActivateButton(win, 0);
goto exit;
}
di = FindDialogItem(win, &d);
if (d == NULL)
return 0;
if (di == NULL)
goto exit;
if (di->type == DITEM_AREA)
{
if (di->item.area.event_func)
(di->item.area.event_func) (0, ev);
}
else if (di->type == DITEM_RADIOBUTTON)
{
if (di->item.radio_button.event_func)
(di->item.radio_button.event_func) (di->item.radio_button.val, ev);
}
di->hilited = 1;
DialogDrawItems(d, di, 0, 0, 99999, 99999);
exit:
return 1;
}
int
DialogEventMouseOut(XEvent * ev)
{
Window win = ev->xcrossing.window;
Dialog *d;
int bnum;
DItem *di;
d = FindDialogButton(win, &bnum);
if (d)
{
DialogActivateButton(win, 1);
goto exit;
}
di = FindDialogItem(win, &d);
if (d == NULL)
return 0;
if (di == NULL)
goto exit;
if (di->type == DITEM_AREA)
{
if (di->item.area.event_func)
(di->item.area.event_func) (0, ev);
}
else if (di->type == DITEM_RADIOBUTTON)
{
if (di->item.radio_button.event_func)
(di->item.radio_button.event_func) (di->item.radio_button.val, NULL);
}
di->hilited = 0;
DialogDrawItems(d, di, 0, 0, 99999, 99999);
exit:
return 1;
}
/*
* Finders
*/
Dialog *
FindDialogButton(Window win, int *bnum)
{
Dialog **ds, *d = NULL;
int i, j, num, b = 0;
EDBUG(6, "FindDialogButton");
ds = (Dialog **) ListItemType(&num, LIST_TYPE_DIALOG);
for (i = 0; i < num; i++)
{
for (j = 0; j < ds[i]->num_buttons; j++)
{
if (win != ds[i]->button[j]->win)
continue;
d = ds[i];
b = j;
goto done;
}
}
done:
if (ds)
Efree(ds);
*bnum = b;
EDBUG_RETURN(d);
}
DItem *
FindDialogItem(Window win, Dialog ** dret)
{
Dialog **ds, *d = NULL;
DItem *di = NULL;
int i, num;
EDBUG(6, "FindDialogButton");
ds = (Dialog **) ListItemType(&num, LIST_TYPE_DIALOG);
for (i = 0; i < num; i++)
{
if (!ds[i]->item)
continue;
di = DialogItemFindWindow(ds[i]->item, win);
if (di == NULL)
continue;
d = ds[i];
break;
}
if (ds)
Efree(ds);
*dret = d;
EDBUG_RETURN(di);
}
Dialog *
FindDialog(Window win)
{
Dialog **ds, *d = NULL;
int i, num;
EDBUG(6, "FindDialog");
ds = (Dialog **) ListItemType(&num, LIST_TYPE_DIALOG);
for (i = 0; i < num; i++)
{
if (ds[i]->win != win)
continue;
d = ds[i];
break;
}
if (ds)
Efree(ds);
EDBUG_RETURN(d);
}