2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2009 Kim Woelders
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include "e16-ecore_list.h"
38 static Ecore_List *tt_list = NULL;
39 static Timer *tt_timer = NULL;
44 int delay; /* milliseconds */
49 char root_motion_mask_set;
50 CB_GetAclass *ac_func;
56 ImageClass *iclass[5];
62 ImageClass *tooltippic;
63 unsigned int ref_count;
67 #define TTICL iclass[4]
70 TooltipRealize(ToolTip * tt)
75 for (i = 0; i < 5; i++)
81 eo = EobjWindowCreate(EOBJ_TYPE_MISC, -50, -100, wh, wh, 1, tt->name);
82 eo->fade = eo->shadow = 1;
83 EobjChangeOpacity(eo, OpacityFromPercent(Conf.opacity.tooltips));
86 tt->iwin = ECreateWindow(EobjGetWin(tt->TTWIN), 0, 0, 1, 1, 0);
90 TooltipCreate(const char *name, const char *ic0, const char *ic1,
91 const char *ic2, const char *ic3, const char *ic4,
92 const char *tclass, int dist, const char *tooltippic)
97 if (ic0 == NULL || tclass == NULL)
100 ic = ImageclassAlloc(ic0, 0);
104 tt = ECALLOC(ToolTip, 1);
108 tt->name = Estrdup(name);
109 tt->iclass[0] = ImageclassAlloc(ic1, 0);
110 tt->iclass[1] = ImageclassAlloc(ic2, 0);
111 tt->iclass[2] = ImageclassAlloc(ic3, 0);
112 tt->iclass[3] = ImageclassAlloc(ic4, 0);
114 tt->tclass = TextclassAlloc(tclass, 1);
115 tt->tooltippic = ImageclassAlloc(tooltippic, 0);
120 tt_list = ecore_list_new();
121 ecore_list_prepend(tt_list, tt);
128 TooltipDestroy(ToolTip * tt)
133 if (tt->ref_count > 0)
135 DialogOK("ToolTip Error!", _("%u references remain\n"), tt->ref_count);
141 TooltipConfigLoad(FILE * fs)
144 char s[FILEPATH_LEN_MAX];
145 char s2[FILEPATH_LEN_MAX];
148 char bubble1[64], bubble2[64], bubble3[64], bubble4[64];
150 char tooltiphelppic[64];
154 name[0] = iclass[0] = tclass[0] = '\0';
155 bubble1[0] = bubble2[0] = bubble3[0] = bubble4[0] = '\0';
156 tooltiphelppic[0] = '\0';
158 while (GetLine(s, sizeof(s), fs))
160 i1 = ConfigParseline1(s, s2, NULL, NULL);
164 if (iclass[0] && tclass[0] && name[0])
165 TooltipCreate(name, iclass, bubble1, bubble2,
166 bubble3, bubble4, tclass, distance,
170 case CONFIG_CLASSNAME:
178 case TOOLTIP_DRAWICLASS:
179 case CONFIG_IMAGECLASS:
182 case TOOLTIP_BUBBLE1:
185 case TOOLTIP_BUBBLE2:
188 case TOOLTIP_BUBBLE3:
191 case TOOLTIP_BUBBLE4:
197 case TOOLTIP_DISTANCE:
200 case TOOLTIP_HELP_PIC:
201 STRCPY(tooltiphelppic, s2);
204 ConfigParseError("ToolTip", s);
215 TooltipCreateIclass(const char *name, const char *file, int *pw, int *ph)
221 ic = ImageclassFind(name, 0);
223 ic = ImageclassCreateSimple(name, file);
224 im = ImageclassGetImage(ic, 0, 0, 0);
228 EImageGetSize(im, &w, &h);
239 TooltipIclassPaste(ToolTip * tt, const char *ic_name, int x, int y, int *px)
245 ic = ImageclassFind(ic_name, 0);
246 im = ImageclassGetImage(ic, 0, 0, 0);
250 EImageGetSize(im, &w, &h);
251 EImageRenderOnDrawable(im, EobjGetWin(tt->TTWIN), None, EIMAGE_BLEND, x, y,
258 TooltipShow(ToolTip * tt, const char *text, ActionClass * ac, int x, int y)
260 int i, w, h, ix, iy, iw, ih, dx, dy, xx, yy;
261 int ww, hh, adx, ady, dist;
262 int headline_h = 0, headline_w = 0, icons_width =
263 0, labels_width = 0, double_w = 0;
268 int cols[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
274 if (!tt || Mode.mode != MODE_NONE)
284 /* if we get an actionclass, look for tooltip action texts */
288 num = ActionclassGetActionCount(ac);
289 heights = EMALLOC(int, num);
291 for (i = 0; i < num; i++)
298 aa = ActionclassGetAction(ac, i);
302 tts = ActionGetTooltipString(aa);
307 TextSize(tt->tclass, 0, 0, STATE_NORMAL, tts, &temp_w, &temp_h,
309 if (temp_w > labels_width)
310 labels_width = temp_w;
313 if (ActionGetEvent(aa) == EVENT_DOUBLE_DOWN)
315 TextSize(tt->tclass, 0, 0, STATE_NORMAL, "2x", &double_w,
317 if (cols[0] < double_w)
321 if (ActionGetAnybutton(aa))
323 TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_ANY",
324 "pix/mouse_any.png", &cols[1], &temp_h);
327 switch (ActionGetButton(aa))
330 ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_1",
331 "pix/mouse_1.png", &cols[1],
335 ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_2",
336 "pix/mouse_2.png", &cols[1],
340 ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_3",
341 "pix/mouse_3.png", &cols[1],
345 ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_4",
346 "pix/mouse_4.png", &cols[1],
350 ic = TooltipCreateIclass("TOOLTIP_MOUSEBUTTON_5",
351 "pix/mouse_5.png", &cols[1],
359 modifiers = ActionGetModifiers(aa);
362 if (modifiers & ShiftMask)
363 ic = TooltipCreateIclass("TOOLTIP_KEY_SHIFT",
366 if (modifiers & LockMask)
367 ic = TooltipCreateIclass("TOOLTIP_KEY_LOCK",
370 if (modifiers & ControlMask)
371 ic = TooltipCreateIclass("TOOLTIP_KEY_CTRL",
374 if (modifiers & Mod1Mask)
375 ic = TooltipCreateIclass("TOOLTIP_KEY_MOD1",
378 if (modifiers & Mod2Mask)
379 ic = TooltipCreateIclass("TOOLTIP_KEY_MOD2",
382 if (modifiers & Mod3Mask)
383 ic = TooltipCreateIclass("TOOLTIP_KEY_MOD3",
386 if (modifiers & Mod4Mask)
387 ic = TooltipCreateIclass("TOOLTIP_KEY_MOD4",
390 if (modifiers & Mod5Mask)
391 ic = TooltipCreateIclass("TOOLTIP_KEY_MOD5",
396 temp_w = cols[0] + cols[1] + cols[2] + cols[3] + cols[4] +
397 cols[5] + cols[6] + cols[7] + cols[8] + cols[9];
399 if (temp_w > icons_width)
400 icons_width = temp_w;
406 TextSize(tt->tclass, 0, 0, STATE_NORMAL, text, &headline_w, &headline_h, 17);
407 if (headline_w < icons_width + labels_width)
408 w = icons_width + labels_width;
414 pad = ImageclassGetPadding(ic);
419 im = ImageclassGetImage(tt->tooltippic, 0, 0, 0);
424 EImageGetSize(im, &iw, &ih);
431 w += pad->left + pad->right;
432 h += pad->top + pad->bottom;
434 if ((tt->tooltippic) && (iw > 0) && (ih > 0))
438 EMoveResizeWindow(tt->iwin, ix, iy, iw, ih);
439 EMapWindow(tt->iwin);
440 ImageclassApply(tt->tooltippic, tt->iwin, 0, 0, STATE_NORMAL, ST_SOLID);
443 EUnmapWindow(tt->iwin);
445 dx = x - WinGetW(VROOT) / 2;
446 dy = y - WinGetH(VROOT) / 2;
448 if ((dy == 0) && (dx == 0))
477 yy = y - ((ady * 10 * dist) / 100);
478 xx = x - (dist * 10 * dx) / (100 * WinGetW(VROOT) / 2);
479 EobjMove(tt->win[0], xx - 4, yy - 4);
484 yy = y - ((ady * 30 * dist) / 100);
485 xx = x - (dist * 30 * dx) / (100 * WinGetW(VROOT) / 2);
486 EobjMove(tt->win[1], xx - 8, yy - 8);
491 yy = y - ((ady * 50 * dist) / 100);
492 xx = x - (dist * 50 * dx) / (100 * WinGetW(VROOT) / 2);
493 EobjMove(tt->win[2], xx - 12, yy - 12);
498 yy = y - ((ady * 80 * dist) / 100);
499 xx = x - (dist * 80 * dx) / (100 * WinGetW(VROOT) / 2);
500 EobjMove(tt->win[3], xx - 16, yy - 16);
503 yy = y - ((ady * 100 * dist) / 100);
504 xx = x - (dist * 100 * dx) / (100 * WinGetW(VROOT) / 2);
509 ww = (w / 2) + ((dx * w) / (WinGetW(VROOT) / 2));
531 xx = x - ((adx * 10 * dist) / 100);
532 yy = y - (dist * 10 * dy) / (100 * WinGetH(VROOT) / 2);
533 EobjMove(tt->win[0], xx - 4, yy - 4);
538 xx = x - ((adx * 30 * dist) / 100);
539 yy = y - (dist * 30 * dy) / (100 * WinGetH(VROOT) / 2);
540 EobjMove(tt->win[1], xx - 8, yy - 8);
545 xx = x - ((adx * 50 * dist) / 100);
546 yy = y - (dist * 50 * dy) / (100 * WinGetH(VROOT) / 2);
547 EobjMove(tt->win[2], xx - 12, yy - 12);
552 xx = x - ((adx * 80 * dist) / 100);
553 yy = y - (dist * 80 * dy) / (100 * WinGetH(VROOT) / 2);
554 EobjMove(tt->win[3], xx - 16, yy - 16);
557 xx = x - ((adx * 100 * dist) / 100);
558 yy = y - (dist * 100 * dy) / (100 * WinGetH(VROOT) / 2);
563 hh = (h / 2) + ((dy * h) / (WinGetH(VROOT) / 2));
566 EobjMoveResize(tt->TTWIN, xx - ww, yy - hh, w, h);
568 for (i = 0; i < 5; i++)
573 ImageclassApply(tt->iclass[i], EobjGetWin(eo), 0, 0, STATE_NORMAL,
575 EobjShapeUpdate(eo, 0);
581 /* draw the ordinary tooltip text */
582 TextDraw(tt->tclass, EobjGetWin(tt->TTWIN), None, 0, 0, STATE_NORMAL, text,
583 xx, pad->top, headline_w, headline_h, 17, 512);
585 /* draw the icons and labels, if any */
588 num = ActionclassGetActionCount(ac);
589 y = pad->top + headline_h;
590 xx = pad->left + double_w;
592 for (i = 0; i < num; i++)
596 aa = ActionclassGetAction(ac, i);
600 tts = ActionGetTooltipString(aa);
605 if (ActionGetEvent(aa) == EVENT_DOUBLE_DOWN)
607 TextDraw(tt->tclass, EobjGetWin(tt->TTWIN), None, 0, 0,
608 STATE_NORMAL, "2x", xx + iw - double_w, y, double_w,
612 if (ActionGetAnybutton(aa))
614 TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_ANY", x, y, &x);
617 switch (ActionGetButton(aa))
620 TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_1", x, y, &x);
623 TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_2", x, y, &x);
626 TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_3", x, y, &x);
629 TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_4", x, y, &x);
632 TooltipIclassPaste(tt, "TOOLTIP_MOUSEBUTTON_5", x, y, &x);
638 modifiers = ActionGetModifiers(aa);
641 if (modifiers & ShiftMask)
642 TooltipIclassPaste(tt, "TOOLTIP_KEY_SHIFT", x, y, &x);
643 if (modifiers & LockMask)
644 TooltipIclassPaste(tt, "TOOLTIP_KEY_LOCK", x, y, &x);
645 if (modifiers & ControlMask)
646 TooltipIclassPaste(tt, "TOOLTIP_KEY_CTRL", x, y, &x);
647 if (modifiers & Mod1Mask)
648 TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD1", x, y, &x);
649 if (modifiers & Mod2Mask)
650 TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD2", x, y, &x);
651 if (modifiers & Mod3Mask)
652 TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD3", x, y, &x);
653 if (modifiers & Mod4Mask)
654 TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD4", x, y, &x);
655 if (modifiers & Mod5Mask)
656 TooltipIclassPaste(tt, "TOOLTIP_KEY_MOD5", x, y, &x);
659 TextDraw(tt->tclass, EobjGetWin(tt->TTWIN), None, 0, 0,
660 STATE_NORMAL, tts, pad->left + icons_width + iw, y,
661 labels_width, heights[i], 17, 0);
671 TooltipHide(ToolTip * tt)
675 if (!tt || !tt->TTWIN || !tt->TTWIN->shown)
678 for (i = 4; i >= 0; i--)
680 EobjUnmap(tt->win[i]);
684 _TooltipMatchName(const void *data, const void *match)
686 return strcmp(((const ToolTip *)data)->name, (const char *)match);
690 TooltipFind(const char *name)
692 return (ToolTip *) ecore_list_find(tt_list, _TooltipMatchName, name);
704 TooltipsSetPending(0, NULL, NULL);
706 ECORE_LIST_FOR_EACH(tt_list, tt) TooltipHide(tt);
710 TooltipsEnable(int enable)
714 if (Mode_tooltips.inhibit > 0)
715 Mode_tooltips.inhibit--;
719 Mode_tooltips.inhibit++;
724 static ToolTip *ttip = NULL;
727 ToolTipTimeout(void *data __UNUSED__)
735 ttip = TooltipFind("DEFAULT");
739 /* In the case of multiple screens, check to make sure
740 * the root window is still where the mouse is... */
741 if (!EQueryPointer(NULL, &x, &y, NULL, &mask))
744 /* In case this is a virtual root */
745 if (x < 0 || y < 0 || x >= WinGetW(VROOT) || y >= WinGetH(VROOT))
748 /* dont pop up tooltip is mouse button down */
750 (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask))
753 if (!Mode_tooltips.ac_func)
755 ac = Mode_tooltips.ac_func(Mode_tooltips.ac_data);
759 tts = ActionclassGetTooltipString(ac);
763 TooltipShow(ttip, _(tts), ac, x, y);
772 * ButtonPress, ButtonRelease, MotionNotify, EnterNotify, LeaveNotify
775 TooltipsSetPending(int type, CB_GetAclass * func, void *data)
777 if (!Mode_tooltips.ac_func && !func)
780 Mode_tooltips.ac_func = func;
781 Mode_tooltips.ac_data = data;
787 if (Conf_tooltips.showroottooltip)
789 if (!Mode_tooltips.root_motion_mask_set)
791 Mode_tooltips.root_motion_mask_set = 1;
792 ESelectInputChange(VROOT, PointerMotionMask, 0);
797 if (Mode_tooltips.root_motion_mask_set)
799 Mode_tooltips.root_motion_mask_set = 0;
800 ESelectInputChange(VROOT, 0, PointerMotionMask);
806 if (Mode_tooltips.inhibit || !Conf_tooltips.enable)
808 if (type && !Conf_tooltips.showroottooltip)
811 TIMER_ADD(tt_timer, 0.001 * Conf_tooltips.delay, ToolTipTimeout, NULL);
819 TooltipsSighan(int sig, void *prm __UNUSED__)
824 memset(&Mode_tooltips, 0, sizeof(Mode_tooltips));
826 case ESIGNAL_AREA_SWITCH_START:
827 case ESIGNAL_DESK_SWITCH_START:
828 case ESIGNAL_EWIN_CHANGE:
836 * Configuration dialog
838 static char tmp_tooltips;
839 static int tmp_tooltiptime;
840 static char tmp_roottip;
843 CB_ConfigureTooltips(Dialog * d __UNUSED__, int val, void *data __UNUSED__)
847 Conf_tooltips.enable = tmp_tooltips;
848 Conf_tooltips.delay = tmp_tooltiptime * 10;
849 Conf_tooltips.showroottooltip = tmp_roottip;
855 _DlgFillTooltips(Dialog * d __UNUSED__, DItem * table, void *data __UNUSED__)
859 tmp_tooltips = Conf_tooltips.enable;
860 tmp_tooltiptime = Conf_tooltips.delay / 10;
861 tmp_roottip = Conf_tooltips.showroottooltip;
863 DialogItemTableSetOptions(table, 2, 0, 0, 0);
865 di = DialogAddItem(table, DITEM_CHECKBUTTON);
866 DialogItemSetColSpan(di, 2);
867 DialogItemSetText(di, _("Display Tooltips"));
868 DialogItemCheckButtonSetPtr(di, &tmp_tooltips);
870 di = DialogAddItem(table, DITEM_CHECKBUTTON);
871 DialogItemSetColSpan(di, 2);
872 DialogItemSetText(di, _("Display Root Window Tips"));
873 DialogItemCheckButtonSetPtr(di, &tmp_roottip);
875 di = DialogAddItem(table, DITEM_TEXT);
876 DialogItemSetAlign(di, 0, 512);
877 DialogItemSetText(di, _("Tooltip Delay:\n"));
879 di = DialogAddItem(table, DITEM_SLIDER);
880 DialogItemSliderSetBounds(di, 0, 300);
881 DialogItemSliderSetUnits(di, 10);
882 DialogItemSliderSetJump(di, 25);
883 DialogItemSliderSetValPtr(di, &tmp_tooltiptime);
886 const DialogDef DlgTooltips = {
887 "CONFIGURE_TOOLTIPS",
889 N_("Tooltip Settings"),
890 SOUND_SETTINGS_TOOLTIPS,
892 N_("Enlightenment Tooltip\n" "Settings Dialog\n"),
894 DLG_OAC, CB_ConfigureTooltips,
896 #endif /* ENABLE_DIALOGS */
898 static const CfgItem TooltipsCfgItems[] = {
899 CFG_ITEM_BOOL(Conf_tooltips, enable, 1),
900 CFG_ITEM_BOOL(Conf_tooltips, showroottooltip, 1),
901 CFG_ITEM_INT(Conf_tooltips, delay, 1500),
903 #define N_CFG_ITEMS (sizeof(TooltipsCfgItems)/sizeof(CfgItem))
908 extern const EModule ModTooltips;
909 const EModule ModTooltips = {
913 {N_CFG_ITEMS, TooltipsCfgItems}