/* * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors * Copyright (C) 2004-2007 Kim Woelders * * 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" #include "dialog.h" #include "e16-ecore_list.h" #include "eimage.h" #include "ewins.h" #include "hints.h" #include "iclass.h" #include "tclass.h" #include "timers.h" #include "xwin.h" #define DEBUG_DIALOGS 0 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; Win base_win; Win knob_win; Win border_win; } DItemSlider; typedef struct { Win area_win; int w, h; DialogItemCallbackFunc *init_func; DialogItemCallbackFunc *event_func; } DItemArea; typedef struct { Win check_win; int check_orig_w, check_orig_h; char onoff; char *onoff_ptr; } DItemCheckButton; 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 { Win radio_win; int radio_orig_w, radio_orig_h; char onoff; int val; int *val_ptr; DItem *next; DItem *first; DialogItemCallbackFunc *event_func; } DItemRadioButton; struct _ditem { int type; Dialog *dlg; DialogCallbackFunc *func; int val; void *data; ImageClass *iclass; TextClass *tclass; EImageBorder padding; char fill_h; char fill_v; char do_close; int align_h; int align_v; int row_span; int col_span; int x, y, w, h; Win win; char *text; union { DItemCheckButton check_button; DItemTable table; DItemImage image; DItemSeparator separator; DItemRadioButton radio_button; DItemSlider slider; DItemArea area; } item; char realized; char update; char state; char hilited; char clicked; }; typedef struct { KeyCode key; DialogCallbackFunc *func; int val; void *data; } DKeyBind; struct _dialog { EWin *ewin; Win win; Pixmap pmap; int w, h; char *name; char *title; PmapMask pmm_bg; TextClass *tclass; ImageClass *iclass; DItem *item; DialogCallbackFunc *exit_func; int exit_val; int num_bindings; DKeyBind *keybindings; void *data; char redraw; char update; char resize; char close; int xu1, yu1, xu2, yu2; }; static EWin *FindEwinByDialog(Dialog * d); static int FindADialog(void); static void DialogHandleEvents(Win win, XEvent * ev, void *prm); static void DItemHandleEvents(Win win, XEvent * ev, void *prm); static void MoveTableBy(Dialog * d, DItem * di, int dx, int dy); static void DialogItemsRealize(Dialog * d); static void DialogItemDestroy(DItem * di, int clean); static int DialogItemCheckButtonGetState(DItem * di); static void DialogUpdate(Dialog * d); static void DialogAddFooter(Dialog * d, DItem * parent, int flags, DialogCallbackFunc * cb); static void DialogAddHeader(Dialog * d, DItem * parent, const char *img, const char *txt); static Ecore_List *dialog_list = NULL; static char dialog_update_pending = 0; void DialogBindKey(Dialog * d, const char *key, DialogCallbackFunc * func, 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].func = func; d->keybindings[d->num_bindings - 1].data = data; d->keybindings[d->num_bindings - 1].key = XKeysymToKeycode(disp, XStringToKeysym(key)); } void DialogKeybindingsDestroy(Dialog * d) { _EFREE(d->keybindings); d->num_bindings = 0; } Dialog * DialogCreate(const char *name) { Dialog *d; d = Ecalloc(1, sizeof(Dialog)); if (!d) return NULL; if (!dialog_list) dialog_list = ecore_list_new(); ecore_list_append(dialog_list, d); d->name = Estrdup(name); d->win = ECreateClientWindow(VRoot.win, -20, -20, 2, 2); EventCallbackRegister(d->win, 0, DialogHandleEvents, d); d->tclass = TextclassFind("DIALOG", 1); if (d->tclass) TextclassIncRefcount(d->tclass); d->iclass = ImageclassFind("DIALOG", 1); if (d->iclass) ImageclassIncRefcount(d->iclass); d->xu1 = d->yu1 = 99999; d->xu2 = d->yu2 = 0; return d; } static void DialogDestroy(Dialog * d) { ecore_list_remove_node(dialog_list, d); if (d->name) Efree(d->name); if (d->title) Efree(d->title); DialogKeybindingsDestroy(d); if (d->item) DialogItemDestroy(d->item, 0); if (d->iclass) ImageclassDecRefcount(d->iclass); if (d->tclass) TextclassDecRefcount(d->tclass); FreePmapMask(&(d->pmm_bg)); EFreePixmap(d->pmap); EDestroyWindow(d->win); Efree(d); } static int _DialogMatchName(const void *data, const void *match) { return strcmp(((const Dialog *)data)->name, match); } Dialog * DialogFind(const char *name) { return ecore_list_find(dialog_list, _DialogMatchName, name); } void DialogSetTitle(Dialog * d, const char *title) { if (d->title) Efree(d->title); d->title = Estrdup(title); HintsSetWindowName(d->win, d->title); } void DialogSetExitFunction(Dialog * d, DialogCallbackFunc * func, int val) { d->exit_func = func; d->exit_val = val; } void DialogCallExitFunction(Dialog * d) { if (d->exit_func) d->exit_func(d, d->exit_val, NULL); } void DialogSetData(Dialog * d, void *data) { d->data = data; } void * DialogGetData(Dialog * d) { return d->data; } #if 0 /* FIXME - Merge/remove */ void DialogAddButton(Dialog * d, const char *text, DialogCallbackFunc * func, char doclose, int image) { DButton *db; int w, h; EImageBorder *pad; 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->parent = d; db->text = Estrdup(text); db->func = func; db->image = image; db->win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EventCallbackRegister(db->win, 0, DButtonHandleEvents, db); EMapWindow(db->win); db->x = -1; db->y = -1; db->w = -1; db->h = -1; db->hilited = 0; db->clicked = 0; db->close = doclose; db->tclass = TextclassFind("DIALOG_BUTTON", 1); if (db->tclass) TextclassIncRefcount(db->tclass); db->iclass = ImageclassFind("DIALOG_BUTTON", 1); if (db->iclass) ImageclassIncRefcount(db->iclass); TextSize(db->tclass, 0, 0, STATE_NORMAL, text, &w, &h, 17); pad = ImageclassGetPadding(db->iclass); db->h = h + pad->top + pad->bottom; db->w = w + pad->left + pad->right; if (Conf.dialogs.button_image && db->image) db->w += h + 2; ESelectInput(db->win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); } static void DialogDrawButton(Dialog * d __UNUSED__, DButton * db) { int state; EImage *im; state = STATE_NORMAL; if ((db->hilited) && (db->clicked)) { state = STATE_CLICKED; } else if ((db->hilited) && (!db->clicked)) { state = STATE_HILITED; } else if (!(db->hilited) && (db->clicked)) { state = STATE_CLICKED; } im = NULL; if (Conf.dialogs.button_image) { switch (db->image) { case DLG_BUTTON_OK: im = ThemeImageLoad("pix/ok.png"); break; case DLG_BUTTON_CANCEL: im = ThemeImageLoad("pix/cancel.png"); break; case DLG_BUTTON_APPLY: im = ThemeImageLoad("pix/apply.png"); break; case DLG_BUTTON_CLOSE: im = ThemeImageLoad("pix/close.png"); break; default: break; } } if (im) { ImageClass *ic = db->iclass; EImageBorder *pad; int h; ImageclassApply(db->iclass, db->win, db->w, db->h, 0, 0, state, ST_WIDGET); pad = ImageclassGetPadding(ic); h = db->h - (pad->top + pad->bottom); TextDraw(db->tclass, db->win, None, 0, 0, state, db->text, h + 2 + pad->left, pad->top, db->w - (h + 2 + pad->left + pad->right), h, h, TextclassGetJustification(db->tclass)); EImageRenderOnDrawable(im, db->win, None, pad->left, pad->top, h, h, 1); EImageFree(im); } else { ITApply(db->win, db->iclass, NULL, db->w, db->h, state, 0, 0, ST_WIDGET, db->tclass, NULL, db->text); } } #endif DItem * DialogItemAddButton(DItem * parent, const char *text, DialogCallbackFunc * func, int val, char doclose, int image __UNUSED__) { DItem *di; di = DialogAddItem(parent, DITEM_BUTTON); DialogItemSetText(di, text); DialogItemSetCallback(di, func, 0, NULL); di->val = val; di->do_close = doclose; return di; } void DialogRedraw(Dialog * d) { if ((!d->tclass) || (!d->iclass)) return; #if DEBUG_DIALOGS Eprintf("DialogRedraw win=%#lx pmap=%#lx\n", d->win, d->pmap); #endif FreePmapMask(&(d->pmm_bg)); ImageclassApplyCopy(d->iclass, d->win, d->w, d->h, 0, 0, STATE_NORMAL, &(d->pmm_bg), 0, ST_DIALOG); if (d->pmm_bg.pmap == None) return; if (d->resize || d->pmap == None) { if (d->pmap != None) EFreePixmap(d->pmap); d->pmap = ECreatePixmap(d->win, d->w, d->h, 0); ESetWindowBackgroundPixmap(d->win, d->pmap); } EXCopyArea(d->pmm_bg.pmap, d->pmap, 0, 0, d->w, d->h, 0, 0); d->redraw = 1; DialogDrawItems(d, d->item, 0, 0, 99999, 99999); } static void DialogEwinMoveResize(EWin * ewin, int resize __UNUSED__) { Dialog *d = ewin->data; if (!d || Mode.mode != MODE_NONE || !EoIsShown(ewin)) return; if (TransparencyUpdateNeeded() || ImageclassIsTransparent(d->iclass)) DialogRedraw(d); } static void DialogEwinClose(EWin * ewin) { DialogDestroy(ewin->data); ewin->client.win = NULL; ewin->data = NULL; } static const EWinOps DialogEwinOps = { NULL, DialogEwinMoveResize, DialogEwinClose, }; static void DialogEwinInit(EWin * ewin, void *ptr) { ewin->data = ptr; ewin->ops = &DialogEwinOps; ewin->props.focus_when_mapped = 1; EoSetLayer(ewin, 10); } void DialogArrange(Dialog * d, int resize) { if (resize) DialogItemsRealize(d); ICCCM_SetSizeConstraints(d->ewin, d->w, d->h, d->w, d->h, 0, 0, 1, 1, 0.0, 65535.0); if (resize) { EwinResize(d->ewin, d->w, d->h); d->resize = 1; DialogRedraw(d); DialogUpdate(d); d->resize = 0; ArrangeEwinCentered(d->ewin); } } static void DialogShowArranged(Dialog * d, int center) { EWin *ewin; ewin = FindEwinByDialog(d); if (ewin) { #if 0 /* Make dialogs sticky? */ if (EoGetDesk(ewin) != DesksGetCurrent()) EwinMoveToDesktop(ewin, DesksGetCurrent()); #endif EwinRaise(ewin); EwinShow(ewin); return; } DialogItemsRealize(d); HintsSetWindowClass(d->win, d->name, "Enlightenment_Dialog"); ewin = AddInternalToFamily(d->win, "DIALOG", EWIN_TYPE_DIALOG, d, DialogEwinInit); d->ewin = ewin; if (!ewin) return; DialogArrange(d, 0); ewin->client.event_mask |= KeyPressMask; ESelectInput(d->win, ewin->client.event_mask); EwinMoveToDesktop(ewin, EoGetDesk(ewin)); if (ewin->state.placed) { EwinMoveResize(ewin, EoGetX(ewin), EoGetY(ewin), d->w, d->h); } else { EwinResize(ewin, d->w, d->h); if (center || FindADialog() == 1) ArrangeEwinCentered(ewin); else ArrangeEwin(ewin); } DialogRedraw(d); DialogUpdate(d); EwinShow(ewin); } void DialogShow(Dialog * d) { DialogShowArranged(d, 0); } void DialogShowCentered(Dialog * d) { DialogShowArranged(d, 1); } void DialogClose(Dialog * d) { d->close = 1; } static void _DialogClose(Dialog * d) { if (!d) return; DialogCallExitFunction(d); EwinHide(d->ewin); } void DialogShowSimple(const DialogDef * dd, void *data) { DialogShowSimpleWithName(dd, dd->name, data); } void DialogFill(Dialog * d, DItem * parent, const DialogDef * dd, void *data) { DItem *content; if (Conf.dialogs.headers && (dd->header_image || dd->header_text)) DialogAddHeader(d, parent, dd->header_image, _(dd->header_text)); content = DialogAddItem(parent, DITEM_TABLE); if (!content) return; dd->fill(d, content, data); if (dd->func) DialogAddFooter(d, parent, dd->flags, dd->func); } void DialogShowSimpleWithName(const DialogDef * dd, const char *name, void *data) { Dialog *d; DItem *table; d = DialogFind(name); if (d) { SoundPlay("SOUND_SETTINGS_ACTIVE"); DialogShow(d); return; } SoundPlay(dd->sound); d = DialogCreate(name); if (!d) return; DialogSetTitle(d, _(dd->title)); table = DialogInitItem(d); if (!table) return; DialogFill(d, table, dd, data); DialogShow(d); } static DItem * DialogItemCreate(int type) { DItem *di; di = Ecalloc(1, sizeof(DItem)); di->type = type; di->align_h = 512; di->align_v = 512; di->row_span = 1; di->col_span = 1; 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; DialogItemSetPadding(di, 2, 2, 2, 2); DialogItemSetFill(di, 1, 0); return di; } DItem * DialogInitItem(Dialog * d) { DItem *di; if (d->item) return NULL; di = DialogItemCreate(DITEM_TABLE); d->item = di; if (!di) return di; di->dlg = d; di->item.table.num_columns = 1; return di; } DItem * DialogAddItem(DItem * dii, int type) { DItem *di; di = DialogItemCreate(type); if (!di) return di; switch (di->type) { default: break; case DITEM_AREA: di->item.area.w = 32; di->item.area.h = 32; break; case DITEM_CHECKBUTTON: di->item.check_button.check_win = 0; di->item.check_button.onoff = 0; di->item.check_button.onoff_ptr = &(di->item.check_button.onoff); di->item.check_button.check_orig_w = 10; di->item.check_button.check_orig_h = 10; 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.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; } 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; di->dlg = dii->dlg; } return di; } static void DialogAddHeader(Dialog * d __UNUSED__, DItem * parent, const char *img, const char *txt) { DItem *table, *di; table = DialogAddItem(parent, DITEM_TABLE); DialogItemTableSetOptions(table, 2, 0, 0, 0); DialogItemSetAlign(table, 512, 0); DialogItemSetFill(table, 0, 0); di = DialogAddItem(table, DITEM_IMAGE); DialogItemImageSetFile(di, img); di = DialogAddItem(table, DITEM_TEXT); DialogItemSetText(di, txt); di = DialogAddItem(parent, DITEM_SEPARATOR); } static void DialogAddFooter(Dialog * d, DItem * parent, int flags, DialogCallbackFunc * cb) { DItem *table, *di; int n_buttons; if (!(flags & DLG_NO_SEPARATOR)) di = DialogAddItem(parent, DITEM_SEPARATOR); table = DialogAddItem(parent, DITEM_TABLE); DialogItemSetAlign(table, 512, 0); DialogItemSetFill(table, 0, 0); /* FIXME - The "real" dialog buttons are slightly different */ n_buttons = 0; if (flags & 1) { di = DialogItemAddButton(table, _("OK"), cb, 0, 1, DLG_BUTTON_OK); n_buttons++; } if (flags & 2) { di = DialogItemAddButton(table, _("Apply"), cb, 1, 0, DLG_BUTTON_APPLY); DialogBindKey(d, "Return", cb, 1, NULL); n_buttons++; } if (flags & 4) { di = DialogItemAddButton(table, _("Close"), NULL, 0, 1, DLG_BUTTON_CLOSE); DialogBindKey(d, "Escape", DialogCallbackClose, 0, NULL); n_buttons++; } DialogItemTableSetOptions(table, n_buttons, 0, 1, 0); DialogSetExitFunction(d, cb, 2); } Dialog * DialogItemGetDialog(DItem * di) { return di->dlg; } void DialogItemSetCallback(DItem * di, DialogCallbackFunc * func, int val, void *data) { di->func = func; di->val = val; di->data = data; } #if 0 /* Unused */ void DialogItemSetClass(DItem * di, ImageClass * iclass, TextClass * tclass) { if (di->iclass) ImageclassDecRefcount(di->iclass); di->iclass = iclass; if (di->iclass) ImageclassIncRefcount(di->iclass); if (di->tclass) TextclassDecRefcount(di->tclass); di->tclass = tclass; if (di->tclass) TextclassIncRefcount(di->tclass); } #endif 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(Dialog * d, DItem * di) { if (di->func) di->func(d, di->val, di->data); } static void DialogRealizeItem(Dialog * d, DItem * di) { const char *def = NULL; int iw = 0, ih = 0; int register_win_callback; EImage *im; EImageBorder *pad; if (di->realized && di->type != DITEM_TABLE) return; di->realized = 1; 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 (!di->tclass) di->tclass = TextclassFind(def, 1); if (!di->iclass) di->iclass = ImageclassFind(def, 1); if (di->tclass) TextclassIncRefcount(di->tclass); if (di->iclass) ImageclassIncRefcount(di->iclass); if (di->type == DITEM_TABLE) { int i; for (i = 0; i < di->item.table.num_items; i++) DialogRealizeItem(d, di->item.table.items[i]); } register_win_callback = 1; switch (di->type) { case DITEM_SLIDER: if (di->item.slider.numeric) { di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->win); ESelectInput(di->win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); } di->item.slider.base_win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->item.slider.base_win); di->item.slider.knob_win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->item.slider.knob_win); ESelectInput(di->item.slider.base_win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); EventCallbackRegister(di->item.slider.base_win, 0, DItemHandleEvents, di); ESelectInput(di->item.slider.knob_win, ButtonPressMask | ButtonReleaseMask | PointerMotionMask); EventCallbackRegister(di->item.slider.knob_win, 0, DItemHandleEvents, di); if (!di->item.slider.ic_base) { if (di->item.slider.horizontal) { di->item.slider.ic_base = ImageclassFind("DIALOG_WIDGET_SLIDER_BASE_HORIZONTAL", 1); } else { di->item.slider.ic_base = ImageclassFind("DIALOG_WIDGET_SLIDER_BASE_VERTICAL", 1); } } im = ImageclassGetImage(di->item.slider.ic_base, 0, 0, 0); if (im) { EImageGetSize(im, &di->item.slider.base_orig_w, &di->item.slider.base_orig_h); EImageFree(im); } if (di->item.slider.ic_base) ImageclassIncRefcount(di->item.slider.ic_base); if (!di->item.slider.ic_knob) { if (di->item.slider.horizontal) { di->item.slider.ic_knob = ImageclassFind("DIALOG_WIDGET_SLIDER_KNOB_HORIZONTAL", 1); } else { di->item.slider.ic_knob = ImageclassFind("DIALOG_WIDGET_SLIDER_KNOB_VERTICAL", 1); } } if (di->item.slider.ic_knob) ImageclassIncRefcount(di->item.slider.ic_knob); im = ImageclassGetImage(di->item.slider.ic_knob, 0, 0, 0); if (im) { EImageGetSize(im, &di->item.slider.knob_orig_w, &di->item.slider.knob_orig_h); EImageFree(im); } if (!di->item.slider.ic_border) { if (di->item.slider.horizontal) { di->item.slider.ic_border = ImageclassFind("DIALOG_WIDGET_SLIDER_BORDER_HORIZONTAL", 0); } else { di->item.slider.ic_border = ImageclassFind("DIALOG_WIDGET_SLIDER_BORDER_VERTICAL", 0); } } if (di->item.slider.ic_border) { im = ImageclassGetImage(di->item.slider.ic_border, 0, 0, 0); if (im) { EImageGetSize(im, &di->item.slider.border_orig_w, &di->item.slider.border_orig_h); EImageFree(im); di->item.slider.border_win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->item.slider.border_win); } ImageclassIncRefcount(di->item.slider.ic_border); } pad = ImageclassGetPadding(di->item.slider.ic_base); if (di->item.slider.horizontal) { iw = di->item.slider.min_length + pad->left + pad->right; ih = di->item.slider.base_orig_h; } else { iw = di->item.slider.base_orig_w; ih = di->item.slider.min_length + pad->top + pad->bottom; } di->w = iw; di->h = ih; break; case DITEM_BUTTON: pad = ImageclassGetPadding(di->iclass); TextSize(di->tclass, 0, 0, STATE_NORMAL, di->text, &iw, &ih, 17); iw += pad->left + pad->right; ih += pad->top + pad->bottom; di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->win); ESelectInput(di->win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); di->w = iw; di->h = ih; break; case DITEM_AREA: pad = ImageclassGetPadding(di->iclass); iw = di->item.area.w; ih = di->item.area.h; iw += pad->left + pad->right; ih += pad->top + pad->bottom; di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->win); di->item.area.area_win = ECreateWindow(di->win, -20, -20, 2, 2, 0); EMapWindow(di->item.area.area_win); ESelectInput(di->item.area.area_win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); EventCallbackRegister(di->item.area.area_win, 0, DItemHandleEvents, di); di->w = iw; di->h = ih; break; case DITEM_CHECKBUTTON: pad = ImageclassGetPadding(di->iclass); im = ImageclassGetImage(di->iclass, 0, 0, 0); if (im) { EImageGetSize(im, &di->item.check_button.check_orig_w, &di->item.check_button.check_orig_h); EImageFree(im); } TextSize(di->tclass, 0, 0, STATE_NORMAL, di->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 + pad->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(di->item.check_button.check_win); EMapWindow(di->win); ESelectInput(di->win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); di->w = iw; di->h = ih; break; case DITEM_TEXT: TextSize(di->tclass, 0, 0, STATE_NORMAL, di->text, &iw, &ih, 17); di->w = iw; di->h = ih; break; case DITEM_IMAGE: im = ThemeImageLoad(di->item.image.image); if (im) { Pixmap pmap = 0, mask = 0; EImageGetSize(im, &iw, &ih); di->win = ECreateWindow(d->win, 0, 0, iw, ih, 0); EMapWindow(di->win); EImageRenderPixmaps(im, di->win, &pmap, &mask, 0, 0); ESetWindowBackgroundPixmap(di->win, pmap); EShapeCombineMask(di->win, ShapeBounding, 0, 0, mask, ShapeSet); EClearWindow(di->win); EImagePixmapFree(pmap); EImageFree(im); } di->w = iw; di->h = ih; register_win_callback = 0; break; case DITEM_SEPARATOR: pad = ImageclassGetPadding(di->iclass); iw = pad->left + pad->right; ih = pad->top + pad->bottom; di->win = ECreateWindow(d->win, -20, -20, 2, 2, 0); EMapWindow(di->win); di->w = iw; di->h = ih; register_win_callback = 0; break; case DITEM_RADIOBUTTON: pad = ImageclassGetPadding(di->iclass); im = ImageclassGetImage(di->iclass, 0, 0, 0); if (im) { EImageGetSize(im, &di->item.radio_button.radio_orig_w, &di->item.radio_button.radio_orig_h); EImageFree(im); } TextSize(di->tclass, 0, 0, STATE_NORMAL, di->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 + pad->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(di->item.radio_button.radio_win); EMapWindow(di->win); ESelectInput(di->win, EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); di->w = iw; di->h = ih; break; case DITEM_TABLE: { int cols, rows; pad = ImageclassGetPadding(d->iclass); cols = di->item.table.num_columns; rows = 1; if (cols > 0) { int i, r, c, x, y; int *col_size, *row_size; col_size = Emalloc(sizeof(int) * cols); row_size = Emalloc(sizeof(int) * rows); row_size[0] = 0; for (i = 0; i < cols; i++) col_size[i] = 0; r = c = 0; for (i = 0; i < di->item.table.num_items; i++) { DItem *dii; int w, h, j, ww; dii = di->item.table.items[i]; w = dii->w + (dii->padding.left + dii->padding.right); h = dii->h + (dii->padding.top + dii->padding.bottom); ww = 0; for (j = 0; j < dii->col_span; j++) ww += col_size[c + j]; if (w > ww) { ww = (w + dii->col_span - 1) / dii->col_span; for (j = 0; j < dii->col_span; j++) if (col_size[c + j] < ww) col_size[c + j] = ww; } 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 = 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; x = y = 0; r = 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 + pad->left + dii->padding.left + (((sw - (dii->padding.left + dii->padding.right) - dii->w) * dii->align_h) >> 10); newy = di->y + y + pad->top + dii->padding.top + (((sh - (dii->padding.top + dii->padding.bottom) - dii->h) * dii->align_v) >> 10); dx = newx - dii->x - pad->left; dy = newy - dii->y - pad->top; MoveTableBy(d, dii, dx, dy); } else { dii->x = di->x + x + pad->left + dii->padding.left + (((sw - (dii->padding.left + dii->padding.right) - dii->w) * dii->align_h) >> 10); dii->y = di->y + y + pad->top + dii->padding.top + (((sh - (dii->padding.top + dii->padding.bottom) - dii->h) * dii->align_v) >> 10); if (dii->win) EMoveResizeWindow(dii->win, dii->x, dii->y, dii->w, dii->h); if (dii->type == DITEM_CHECKBUTTON) EMoveResizeWindow(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(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) { pad = ImageclassGetPadding(dii->iclass); dii->item.area.w = dii->w - (pad->left + pad->right); dii->item.area.h = dii->h - (pad->top + pad->bottom); EMoveResizeWindow(dii->item.area.area_win, pad->left, pad->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(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(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(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; } if (di->win && register_win_callback) EventCallbackRegister(di->win, 0, DItemHandleEvents, di); } 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]; if (dii->type == DITEM_TABLE) { MoveTableBy(d, dii, dx, dy); continue; } dii->x += dx; dii->y += dy; if (dii->win) EMoveWindow(dii->win, dii->x, dii->y); switch (dii->type) { case DITEM_CHECKBUTTON: EMoveWindow(dii->item.check_button.check_win, dii->x, dii->y + ((dii->h - dii->item.check_button.check_orig_h) / 2)); break; case DITEM_RADIOBUTTON: EMoveWindow(dii->item.radio_button.radio_win, dii->x, dii->y + ((dii->h - dii->item.radio_button.radio_orig_h) / 2)); break; case DITEM_SLIDER: { if (dii->item.slider.base_win) EMoveResizeWindow(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(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(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(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); break; } } } } void DialogDrawItems(Dialog * d, DItem * di, int x, int y, int w, int h) { d->update = 1; di->update = 1; if (d->xu1 > x) d->xu1 = x; if (d->yu1 > y) d->yu1 = y; x += w; y += h; if (d->xu2 < x) d->xu2 = x; if (d->yu2 < y) d->yu2 = y; dialog_update_pending = 1; #if DEBUG_DIALOGS Eprintf("DialogDrawItems t=%d u=%d - %d,%d -> %d,%d\n", di->type, di->update, d->xu1, d->yu1, d->xu2, d->yu2); #endif } static void DialogDrawItem(Dialog * d, DItem * di) { int state, x, w; EImageBorder *pad; if (!di->update && di->type != DITEM_TABLE) return; if (di->x > d->xu2 || di->y > d->yu2 || di->x + di->w <= d->xu1 || di->y + di->h <= d->yu1) goto done; #if DEBUG_DIALOGS Eprintf("DialogDrawItem t=%d u=%d - %d,%d -> %d,%d\n", di->type, di->update, d->xu1, d->yu1, d->xu2, d->yu2); #endif switch (di->type) { case DITEM_TABLE: { int i; DItem *dii; for (i = 0; i < di->item.table.num_items; i++) { dii = di->item.table.items[i]; if (di->update) dii->update = 1; DialogDrawItem(d, dii); } #if 0 /* Debug */ { XGCValues gcv; GC gc; pad = ImageclassGetPadding(d->iclass); gcv.subwindow_mode = IncludeInferiors; gc = EXCreateGC(d->pmap, GCSubwindowMode, &gcv); XSetForeground(disp, gc, BlackPixel(disp, VRoot.scr)); XDrawRectangle(disp, d->pmap, gc, pad->left + di->x, pad->top + di->y, di->w, di->h); EXFreeGC(gc); } #endif } break; 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(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) ImageclassApply(di->item.slider.ic_base, di->item.slider.base_win, di->item.slider.base_w, di->item.slider.base_h, 0, 0, STATE_NORMAL, ST_WIDGET); if (di->item.slider.border_win) ImageclassApply(di->item.slider.ic_border, di->item.slider.border_win, di->item.slider.border_w, di->item.slider.border_h, 0, 0, STATE_NORMAL, ST_WIDGET); 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) ImageclassApply(di->item.slider.ic_knob, di->item.slider.knob_win, di->item.slider.knob_w, di->item.slider.knob_h, 0, 0, state, ST_WIDGET); 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; ITApply(di->win, di->iclass, NULL, di->w, di->h, state, 0, 0, ST_WIDGET, di->tclass, NULL, di->text); break; case DITEM_AREA: if (!d->redraw) break; ImageclassApply(di->iclass, di->win, di->w, di->h, 0, 0, STATE_NORMAL, ST_DIALOG); if (di->item.area.init_func) di->item.area.init_func(di, 0, NULL); break; case DITEM_SEPARATOR: if (!d->redraw) break; if (di->item.separator.horizontal) ImageclassApply(di->iclass, di->win, di->w, di->h, 0, 0, STATE_NORMAL, ST_WIDGET); else ImageclassApply(di->iclass, di->win, di->w, di->h, 0, 0, STATE_CLICKED, ST_WIDGET); break; case DITEM_TEXT: state = STATE_NORMAL; x = di->x; w = di->w; goto draw_text; 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; ImageclassApply(di->iclass, di->item.check_button.check_win, di->item.check_button.check_orig_w, di->item.check_button.check_orig_h, DialogItemCheckButtonGetState(di), 0, state, ST_WIDGET); if (!d->redraw && (TextclassGetTextState(di->tclass, di->state, 0, 0) == TextclassGetTextState(di->tclass, state, 0, 0))) break; pad = ImageclassGetPadding(di->iclass); x = di->x + di->item.check_button.check_orig_w + pad->left; w = di->w - di->item.check_button.check_orig_w - pad->left; goto draw_text; 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; ImageclassApply(di->iclass, di->item.radio_button.radio_win, di->item.radio_button.radio_orig_w, di->item.radio_button.radio_orig_h, di->item.radio_button.onoff, 0, state, ST_WIDGET); if (!d->redraw && (TextclassGetTextState(di->tclass, di->state, 0, 0) == TextclassGetTextState(di->tclass, state, 0, 0))) break; pad = ImageclassGetPadding(di->iclass); x = di->x + di->item.radio_button.radio_orig_w + pad->left; w = di->w - di->item.radio_button.radio_orig_w - pad->left; goto draw_text; default: break; draw_text: di->state = state; if (!di->text) break; if (!d->redraw) EXCopyArea(d->pmm_bg.pmap, d->pmap, di->x, di->y, di->w, di->h, di->x, di->y); TextDraw(di->tclass, d->win, d->pmap, 0, 0, state, di->text, x, di->y, w, 99999, 17, TextclassGetJustification(di->tclass)); break; } done: di->update = 0; } static void DialogUpdate(Dialog * d) { if (d->item) DialogDrawItem(d, d->item); if (d->xu1 < d->xu2 && d->yu1 < d->yu2) EClearArea(d->win, d->xu1, d->yu1, d->xu2 - d->xu1, d->yu2 - d->yu1, False); d->update = 0; d->xu1 = d->yu1 = 99999; d->xu2 = d->yu2 = 0; } static void _DialogsCheckUpdate(void *data __UNUSED__) { Dialog *d; if (!dialog_update_pending) return; dialog_update_pending = 0; ECORE_LIST_FOR_EACH(dialog_list, d) { if (d->update) DialogUpdate(d); d->redraw = 0; } } void DialogsInit(void) { IdlerAdd(50, _DialogsCheckUpdate, NULL); } static void DialogItemsRealize(Dialog * d) { EImageBorder *pad; if (!d->item) return; DialogRealizeItem(d, d->item); DialogDrawItems(d, d->item, 0, 0, 99999, 99999); pad = ImageclassGetPadding(d->iclass); d->w = d->item->w + pad->left + pad->right; d->h = d->item->h + pad->top + pad->bottom; EResizeWindow(d->win, d->w, d->h); } void DialogItemSetText(DItem * di, const char *text) { if (di->text) Efree(di->text); di->text = Estrdup(text); } void DialogItemRadioButtonSetEventFunc(DItem * di, DialogItemCallbackFunc * func) { di->item.radio_button.event_func = func; } 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.radio_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_ptr) = onoff; } void DialogItemCheckButtonSetPtr(DItem * di, char *onoff_ptr) { di->item.check_button.onoff_ptr = onoff_ptr; } static int DialogItemCheckButtonGetState(DItem * di) { return *(di->item.check_button.onoff_ptr) ? 1 : 0; } 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, const 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 DialogItemSliderSetValPtr(DItem * di, int *val_ptr) { di->item.slider.val_ptr = val_ptr; DialogItemSliderSetVal(di, *val_ptr); } 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 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; } Win 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 DialogItemAreaSetInitFunc(DItem * di, DialogItemCallbackFunc * func) { di->item.area.init_func = func; } void DialogItemAreaSetEventFunc(DItem * di, DialogItemCallbackFunc * func) { di->item.area.event_func = func; } void DialogItemTableEmpty(DItem * di) { int i; if (di->type != DITEM_TABLE) return; for (i = 0; i < di->item.table.num_items; i++) DialogItemDestroy(di->item.table.items[i], 1); if (di->item.table.items) Efree(di->item.table.items); di->item.table.items = NULL; di->item.table.num_items = 0; } static void DialogItemDestroy(DItem * di, int clean) { if (di->type == DITEM_TABLE) DialogItemTableEmpty(di); if (di->text) Efree(di->text); switch (di->type) { default: break; case DITEM_CHECKBUTTON: if (!clean) break; EDestroyWindow(di->item.check_button.check_win); break; case DITEM_IMAGE: if (di->item.image.image) Efree(di->item.image.image); break; case DITEM_RADIOBUTTON: if (!clean) break; EDestroyWindow(di->item.radio_button.radio_win); break; case DITEM_SLIDER: if (di->item.slider.ic_base) ImageclassDecRefcount(di->item.slider.ic_base); if (di->item.slider.ic_knob) ImageclassDecRefcount(di->item.slider.ic_knob); if (di->item.slider.ic_border) ImageclassDecRefcount(di->item.slider.ic_border); if (!clean) break; EDestroyWindow(di->item.slider.base_win); EDestroyWindow(di->item.slider.knob_win); EDestroyWindow(di->item.slider.border_win); break; case DITEM_AREA: if (!clean) break; EDestroyWindow(di->item.area.area_win); break; } if (clean && di->win) EDestroyWindow(di->win); if (di->iclass) ImageclassDecRefcount(di->iclass); if (di->tclass) TextclassDecRefcount(di->tclass); Efree(di); } /* Convenience callback to close dialog */ void DialogCallbackClose(Dialog * d, int val __UNUSED__, void *data __UNUSED__) { DialogClose(d); } /* * Predefined dialogs */ void DialogOK(const char *title, const char *fmt, ...) { char text[10240]; va_list args; va_start(args, fmt); Evsnprintf(text, sizeof(text), fmt, args); va_end(args); DialogOKstr(title, text); } void DialogOKstr(const char *title, const char *txt) { Dialog *d; DItem *table, *di; d = DialogCreate("DIALOG"); table = DialogInitItem(d); DialogSetTitle(d, title); di = DialogAddItem(table, DITEM_TEXT); DialogItemSetText(di, txt); di = DialogItemAddButton(table, _("OK"), DialogCallbackClose, 0, 1, DLG_BUTTON_OK); DialogItemSetFill(di, 0, 0); DialogBindKey(d, "Return", DialogCallbackClose, 0, NULL); DialogBindKey(d, "Escape", DialogCallbackClose, 0, NULL); DialogShow(d); } void DialogAlert(const char *fmt, ...) { char text[10240]; va_list args; va_start(args, fmt); Evsnprintf(text, 10240, fmt, args); va_end(args); Alert(text); } void DialogAlertOK(const char *fmt, ...) { char text[10240]; va_list args; va_start(args, fmt); Evsnprintf(text, 10240, fmt, args); va_end(args); AlertX(_("Attention !!!"), _("OK"), NULL, NULL, text); } /* * Dialog event handlers */ static void DialogEventKeyPress(Dialog * d, XEvent * ev) { int i; for (i = 0; i < d->num_bindings; i++) { if (ev->xkey.keycode != d->keybindings[i].key) continue; d->keybindings[i].func(d, d->keybindings[i].val, d->keybindings[i].data); break; } } static void DialogHandleEvents(Win win __UNUSED__, XEvent * ev, void *prm) { Dialog *d = (Dialog *) prm; switch (ev->type) { case KeyPress: DialogEventKeyPress(d, ev); break; } if (d->close) _DialogClose(d); } static void DItemEventMotion(Win win __UNUSED__, DItem * di, XEvent * ev) { int dx, dy; switch (di->type) { case DITEM_AREA: if (di->item.area.event_func) di->item.area.event_func(di, 0, ev); break; case DITEM_SLIDER: if (!di->item.slider.in_drag) break; if (ev->xmotion.window == WinGetXwin(di->item.slider.knob_win)) { dx = Mode.events.x - Mode.events.px; dy = Mode.events.y - Mode.events.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->dlg, di->val, di->data); } DialogDrawItems(di->dlg, di, di->x, di->y, di->w, di->h); break; } } static void DItemEventMouseDown(Win win, DItem * di, XEvent * ev) { int x, y, wheel_jump; switch (di->type) { case DITEM_AREA: if (di->item.area.event_func) di->item.area.event_func(di, 0, ev); break; case DITEM_SLIDER: #if 0 /* Do any themes have this? */ if (win == di->item.slider.border_win) break; #endif if (ev->xbutton.window == WinGetXwin(di->item.slider.knob_win)) { if (ev->xbutton.button >= 1 && ev->xbutton.button <= 3) { 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; break; } } /* Coords -> item.slider.base_win */ ETranslateCoordinates(win, di->item.slider.base_win, ev->xbutton.x, ev->xbutton.y, &x, &y, NULL); switch (ev->xbutton.button) { case 1: case 3: 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; } break; case 2: if (di->item.slider.horizontal) di->item.slider.val = x * (di->item.slider.upper - di->item.slider.lower) / di->w; else di->item.slider.val = ((di->h - y) * (di->item.slider.upper - di->item.slider.lower) / di->h); break; case 4: case 5: wheel_jump = di->item.slider.jump / 2; if (!wheel_jump) wheel_jump++; if (ev->xbutton.button == 5) { di->item.slider.val -= wheel_jump; } else if (ev->xbutton.button == 4) { di->item.slider.val += wheel_jump; } break; } 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 0 /* Remove? */ if (di->func) (di->func) (d, di->val, di->data); #endif break; } di->clicked = 1; DialogDrawItems(di->dlg, di, di->x, di->y, di->w, di->h); } static void DItemEventMouseUp(Win win, DItem * di, XEvent * ev) { DItem *dii; if (ev->xbutton.window != Mode.events.last_bpress) return; switch (di->type) { case DITEM_AREA: if (di->item.area.event_func) di->item.area.event_func(di, 0, ev); break; case DITEM_CHECKBUTTON: DialogItemCheckButtonSetState(di, !DialogItemCheckButtonGetState(di)); break; case DITEM_RADIOBUTTON: dii = di->item.radio_button.first; while (dii) { if (dii->item.radio_button.onoff) { dii->item.radio_button.onoff = 0; DialogDrawItems(di->dlg, dii, dii->x, dii->y, dii->w, dii->h); } 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; break; case DITEM_SLIDER: if (win == di->item.slider.knob_win) di->item.slider.in_drag = 0; break; } if (di->hilited && di->clicked) { if (di->func) di->func(di->dlg, di->val, di->data); if (di->do_close) di->dlg->close = 1; } di->clicked = 0; DialogDrawItems(di->dlg, di, di->x, di->y, di->w, di->h); } static void DItemEventMouseIn(Win win __UNUSED__, DItem * di, XEvent * ev) { switch (di->type) { case DITEM_AREA: if (di->item.area.event_func) di->item.area.event_func(di, 0, ev); break; case DITEM_RADIOBUTTON: if (di->item.radio_button.event_func) di->item.radio_button.event_func(di, di->item.radio_button.val, ev); break; } di->hilited = 1; DialogDrawItems(di->dlg, di, di->x, di->y, di->w, di->h); } static void DItemEventMouseOut(Win win __UNUSED__, DItem * di, XEvent * ev) { switch (di->type) { case DITEM_AREA: if (di->item.area.event_func) di->item.area.event_func(di, 0, ev); break; case DITEM_RADIOBUTTON: if (di->item.radio_button.event_func) di->item.radio_button.event_func(di, di->item.radio_button.val, NULL); break; } di->hilited = 0; DialogDrawItems(di->dlg, di, di->x, di->y, di->w, di->h); } static void DItemHandleEvents(Win win, XEvent * ev, void *prm) { DItem *di = (DItem *) prm; switch (ev->type) { case ButtonPress: DItemEventMouseDown(win, di, ev); break; case ButtonRelease: DItemEventMouseUp(win, di, ev); break; case MotionNotify: DItemEventMotion(win, di, ev); break; case EnterNotify: DItemEventMouseIn(win, di, ev); break; case LeaveNotify: DItemEventMouseOut(win, di, ev); break; } if (di->dlg->close) _DialogClose(di->dlg); } /* * Finders */ static EWin * FindEwinByDialog(Dialog * d) { EWin *const *ewins; int i, num; ewins = EwinListGetAll(&num); for (i = 0; i < num; i++) { if ((Dialog *) (ewins[i]->data) == d) return ewins[i]; } return NULL; } static int FindADialog(void) { EWin *const *ewins; int i, num, n; ewins = EwinListGetAll(&num); for (i = n = 0; i < num; i++) { if (ewins[i]->type == EWIN_TYPE_DIALOG) n++; } return n; }