Radio and Check buttons now work
[wmaker-crm.git] / WINGs / wballoon.c
blobee045e0edb272592f8f4a6db6bc82d0658ad1f50
2 #include "wconfig.h"
3 #include "WINGsP.h"
5 #ifdef SHAPE
6 #include <X11/extensions/shape.h>
7 #endif
9 typedef struct W_Balloon {
10 W_View *view;
12 WMHashTable *table; /* Table from view ptr to text */
14 WMColor *backColor;
15 WMColor *textColor;
16 WMFont *font;
18 WMHandlerID timer; /* timer for showing balloon */
20 WMHandlerID noDelayTimer;
22 int delay;
24 Window forWindow; /* window for which the balloon
25 * is being show in the moment */
27 struct {
28 WMAlignment alignment:2;
29 unsigned enabled:1;
31 unsigned noDelay:1;
32 } flags;
33 } Balloon;
35 #define DEFAULT_WIDTH 60
36 #define DEFAULT_HEIGHT 14
37 #define DEFAULT_ALIGNMENT WALeft
38 #define DEFAULT_DELAY 500
40 #define NO_DELAY_DELAY 150
42 static void destroyBalloon(Balloon * bPtr);
44 static void handleEvents(XEvent * event, void *data);
46 static void showText(Balloon * bPtr, int x, int y, int w, int h, char *text);
48 struct W_Balloon *W_CreateBalloon(WMScreen * scr)
50 Balloon *bPtr;
52 bPtr = wmalloc(sizeof(Balloon));
53 memset(bPtr, 0, sizeof(Balloon));
55 bPtr->view = W_CreateUnmanagedTopView(scr);
56 if (!bPtr->view) {
57 wfree(bPtr);
58 return NULL;
60 bPtr->view->self = bPtr;
62 //XXX bPtr->textColor = WMRetainColor(bPtr->view->screen->black);
64 WMCreateEventHandler(bPtr->view, StructureNotifyMask, handleEvents, bPtr);
66 W_ResizeView(bPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
67 bPtr->flags.alignment = DEFAULT_ALIGNMENT;
69 bPtr->table = WMCreateHashTable(WMIntHashCallbacks);
71 bPtr->delay = DEFAULT_DELAY;
73 bPtr->flags.enabled = 1;
75 return bPtr;
78 void WMSetBalloonTextAlignment(WMScreen * scr, WMAlignment alignment)
80 scr->balloon->flags.alignment = alignment;
84 void WMSetBalloonTextForView(char *text, WMView * view)
86 char *oldText = NULL;
87 WMScreen *scr = view->screen;
89 if (text) {
90 oldText = WMHashInsert(scr->balloon->table, view, wstrdup(text));
91 } else {
92 oldText = WMHashGet(scr->balloon->table, view);
94 WMHashRemove(scr->balloon->table, view);
97 if (oldText) {
98 wfree(oldText);
102 void WMSetBalloonFont(WMScreen * scr, WMFont * font)
104 Balloon *bPtr = scr->balloon;
106 if (bPtr->font != NULL)
107 WMReleaseFont(bPtr->font);
109 if (font)
110 bPtr->font = WMRetainFont(font);
111 else
112 bPtr->font = NULL;
115 void WMSetBalloonTextColor(WMScreen * scr, WMColor * color)
117 Balloon *bPtr = scr->balloon;
119 if (bPtr->textColor)
120 WMReleaseColor(bPtr->textColor);
122 bPtr->textColor = WMRetainColor(color);
125 void WMSetBalloonDelay(WMScreen * scr, int delay)
127 scr->balloon->delay = delay;
130 void WMSetBalloonEnabled(WMScreen * scr, Bool flag)
132 scr->balloon->flags.enabled = ((flag == 0) ? 0 : 1);
134 W_UnmapView(scr->balloon->view);
137 static void clearNoDelay(void *data)
139 Balloon *bPtr = (Balloon *) data;
141 bPtr->flags.noDelay = 0;
142 bPtr->noDelayTimer = NULL;
145 void W_BalloonHandleLeaveView(WMView * view)
147 Balloon *bPtr = view->screen->balloon;
149 if (bPtr->forWindow == view->window) {
150 if (bPtr->view->flags.mapped) {
151 W_UnmapView(bPtr->view);
152 bPtr->noDelayTimer = WMAddTimerHandler(NO_DELAY_DELAY, clearNoDelay, bPtr);
154 if (bPtr->timer)
155 WMDeleteTimerHandler(bPtr->timer);
157 bPtr->timer = NULL;
159 bPtr->forWindow = None;
164 * botar balao perto do cursor
165 * so mapear balao se o mouse ficar parado pelo delay
169 static void showBalloon(void *data)
171 char *text;
172 WMView *view = (WMView *) data;
173 Balloon *bPtr = view->screen->balloon;
174 int x, y;
175 Window foo;
177 bPtr->timer = NULL;
179 text = WMHashGet(bPtr->table, view);
180 if (!text)
181 return;
183 XTranslateCoordinates(view->screen->display, view->window, view->screen->rootWin, 0, 0, &x, &y, &foo);
185 if (!bPtr->view->flags.realized)
186 W_RealizeView(bPtr->view);
188 showText(bPtr, x, y, view->size.width, view->size.height, text);
190 bPtr->flags.noDelay = 1;
193 void W_BalloonHandleEnterView(WMView * view)
195 Balloon *bPtr = view->screen->balloon;
196 char *text;
198 if (!bPtr->flags.enabled)
199 return;
201 text = WMHashGet(bPtr->table, view);
202 if (!text) {
203 if (bPtr->view->flags.realized)
204 W_UnmapView(bPtr->view);
206 return;
209 if (bPtr->timer)
210 WMDeleteTimerHandler(bPtr->timer);
211 bPtr->timer = NULL;
213 if (bPtr->noDelayTimer)
214 WMDeleteTimerHandler(bPtr->noDelayTimer);
215 bPtr->noDelayTimer = NULL;
217 bPtr->forWindow = view->window;
219 if (bPtr->flags.noDelay) {
220 bPtr->timer = NULL;
222 showBalloon(view);
223 } else {
224 bPtr->timer = WMAddTimerHandler(bPtr->delay, showBalloon, view);
228 #define TOP 0
229 #define BOTTOM 1
230 #define LEFT 0
231 #define RIGHT 2
233 #define TLEFT (TOP|LEFT)
234 #define TRIGHT (TOP|RIGHT)
235 #define BLEFT (BOTTOM|LEFT)
236 #define BRIGHT (BOTTOM|RIGHT)
238 #define SPACE 12
240 static void drawBalloon(WMScreen * scr, Pixmap bitmap, Pixmap pix, int x, int y, int w, int h, int side)
242 Display *dpy = scr->display;
243 //XXXWMColor *white = WMWhiteColor(scr);
244 //XXXWMColor *black = WMBlackColor(scr);
245 GC bgc = scr->monoGC;
246 //XXXGC gc = WMColorGC(white);
247 GC gc = scr->monoGC;
248 int rad = h * 3 / 10;
249 XPoint pt[3], ipt[3];
250 int w1;
252 /* outline */
253 XSetForeground(dpy, bgc, 1);
255 XFillArc(dpy, bitmap, bgc, x, y, rad, rad, 90 * 64, 90 * 64);
256 XFillArc(dpy, bitmap, bgc, x, y + h - 1 - rad, rad, rad, 180 * 64, 90 * 64);
258 XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y, rad, rad, 0 * 64, 90 * 64);
259 XFillArc(dpy, bitmap, bgc, x + w - 1 - rad, y + h - 1 - rad, rad, rad, 270 * 64, 90 * 64);
261 XFillRectangle(dpy, bitmap, bgc, x, y + rad / 2, w, h - rad);
262 XFillRectangle(dpy, bitmap, bgc, x + rad / 2, y, w - rad, h);
264 /* interior */
265 XFillArc(dpy, pix, gc, x + 1, y + 1, rad, rad, 90 * 64, 90 * 64);
266 XFillArc(dpy, pix, gc, x + 1, y + h - 2 - rad, rad, rad, 180 * 64, 90 * 64);
268 XFillArc(dpy, pix, gc, x + w - 2 - rad, y + 1, rad, rad, 0 * 64, 90 * 64);
269 XFillArc(dpy, pix, gc, x + w - 2 - rad, y + h - 2 - rad, rad, rad, 270 * 64, 90 * 64);
271 XFillRectangle(dpy, pix, gc, x + 1, y + 1 + rad / 2, w - 2, h - 2 - rad);
272 XFillRectangle(dpy, pix, gc, x + 1 + rad / 2, y + 1, w - 2 - rad, h - 2);
274 if (side & BOTTOM) {
275 pt[0].y = y + h - 1;
276 pt[1].y = y + h - 1 + SPACE;
277 pt[2].y = y + h - 1;
278 ipt[0].y = pt[0].y - 1;
279 ipt[1].y = pt[1].y - 1;
280 ipt[2].y = pt[2].y - 1;
281 } else {
282 pt[0].y = y;
283 pt[1].y = y - SPACE;
284 pt[2].y = y;
285 ipt[0].y = pt[0].y + 1;
286 ipt[1].y = pt[1].y + 1;
287 ipt[2].y = pt[2].y + 1;
290 /*w1 = WMAX(h, 24); */
291 w1 = WMAX(h, 21);
293 if (side & RIGHT) {
294 pt[0].x = x + w - w1 + 2 * w1 / 16;
295 pt[1].x = x + w - w1 + 11 * w1 / 16;
296 pt[2].x = x + w - w1 + 7 * w1 / 16;
297 ipt[0].x = x + 1 + w - w1 + 2 * (w1 - 1) / 16;
298 ipt[1].x = x + 1 + w - w1 + 11 * (w1 - 1) / 16;
299 ipt[2].x = x + 1 + w - w1 + 7 * (w1 - 1) / 16;
300 /*ipt[0].x = pt[0].x+1;
301 ipt[1].x = pt[1].x;
302 ipt[2].x = pt[2].x; */
303 } else {
304 pt[0].x = x + w1 - 2 * w1 / 16;
305 pt[1].x = x + w1 - 11 * w1 / 16;
306 pt[2].x = x + w1 - 7 * w1 / 16;
307 ipt[0].x = x - 1 + w1 - 2 * (w1 - 1) / 16;
308 ipt[1].x = x - 1 + w1 - 11 * (w1 - 1) / 16;
309 ipt[2].x = x - 1 + w1 - 7 * (w1 - 1) / 16;
310 /*ipt[0].x = pt[0].x-1;
311 ipt[1].x = pt[1].x;
312 ipt[2].x = pt[2].x; */
315 XFillPolygon(dpy, bitmap, bgc, pt, 3, Convex, CoordModeOrigin);
316 XFillPolygon(dpy, pix, gc, ipt, 3, Convex, CoordModeOrigin);
318 /* fix outline */
319 //XDrawLines(dpy, pix, WMColorGC(black), pt, 3, CoordModeOrigin);
320 if (side & RIGHT) {
321 pt[0].x++;
322 pt[2].x--;
323 } else {
324 pt[0].x--;
325 pt[2].x++;
327 //XDrawLines(dpy, pix, WMColorGC(black), pt, 3, CoordModeOrigin);
329 //WMReleaseColor(white);
330 //WMReleaseColor(black);
333 static Pixmap makePixmap(WMScreen * scr, int width, int height, int side, Pixmap * mask)
335 Display *dpy = WMScreenDisplay(scr);
336 Pixmap bitmap;
337 Pixmap pixmap;
338 int x, y;
339 //WMColor *black = WMBlackColor(scr);
341 bitmap = XCreatePixmap(dpy, scr->rootWin, width + SPACE, height + SPACE, 1);
343 XSetForeground(dpy, scr->monoGC, 0);
344 XFillRectangle(dpy, bitmap, scr->monoGC, 0, 0, width + SPACE, height + SPACE);
346 pixmap = XCreatePixmap(dpy, scr->rootWin, width + SPACE, height + SPACE, scr->depth);
348 //XFillRectangle(dpy, pixmap, WMColorGC(black), 0, 0, width + SPACE, height + SPACE);
350 if (side & BOTTOM) {
351 y = 0;
352 } else {
353 y = SPACE;
355 x = 0;
357 drawBalloon(scr, bitmap, pixmap, x, y, width, height, side);
359 *mask = bitmap;
361 //WMReleaseColor(black);
363 return pixmap;
366 static void showText(Balloon * bPtr, int x, int y, int w, int h, char *text)
368 WMScreen *scr = bPtr->view->screen;
369 Display *dpy = WMScreenDisplay(scr);
370 int width;
371 int height;
372 Pixmap pixmap;
373 Pixmap mask;
374 WMFont *font = bPtr->font ? bPtr->font : scr->normalFont;
375 int textHeight;
376 int side = 0;
377 int ty;
378 int bx, by;
381 int w;
382 char *ptr, *ptr2;
384 ptr2 = ptr = text;
385 width = 0;
386 while (ptr && ptr2) {
387 ptr2 = strchr(ptr, '\n');
388 if (ptr2) {
389 //XXXw = WMWidthOfString(font, ptr, ptr2 - ptr);
390 } else {
391 //XXXw = WMWidthOfString(font, ptr, strlen(ptr));
393 if (w > width)
394 width = w;
395 ptr = ptr2 + 1;
399 width += 16;
401 //XXXtextHeight = W_GetTextHeight(font, text, width, False);
403 height = textHeight + 4;
405 if (height < 16)
406 height = 16;
407 if (width < height)
408 width = height;
410 if (x + width > scr->rootView->size.width) {
411 side = RIGHT;
412 bx = x - width + w / 2;
413 if (bx < 0)
414 bx = 0;
415 } else {
416 side = LEFT;
417 bx = x + w / 2;
419 if (bx + width > scr->rootView->size.width)
420 bx = scr->rootView->size.width - width;
422 if (y - (height + SPACE) < 0) {
423 side |= TOP;
424 by = y + h - 1;
425 ty = SPACE;
426 } else {
427 side |= BOTTOM;
428 by = y - (height + SPACE);
429 ty = 0;
431 pixmap = makePixmap(scr, width, height, side, &mask);
433 /*W_PaintText(bPtr->view, pixmap, font, 8, ty + (height - textHeight) / 2,
434 width, bPtr->flags.alignment,
435 bPtr->textColor ? bPtr->textColor : scr->black, False, text, strlen(text));
438 XSetWindowBackgroundPixmap(dpy, bPtr->view->window, pixmap);
440 W_ResizeView(bPtr->view, width, height + SPACE);
442 XFreePixmap(dpy, pixmap);
444 #ifdef SHAPE
445 XShapeCombineMask(dpy, bPtr->view->window, ShapeBounding, 0, 0, mask, ShapeSet);
446 #endif
447 XFreePixmap(dpy, mask);
449 W_MoveView(bPtr->view, bx, by);
451 W_MapView(bPtr->view);
454 static void handleEvents(XEvent * event, void *data)
456 Balloon *bPtr = (Balloon *) data;
458 switch (event->type) {
459 case DestroyNotify:
460 destroyBalloon(bPtr);
461 break;
465 static void destroyBalloon(Balloon * bPtr)
467 WMHashEnumerator e;
468 char *str;
470 e = WMEnumerateHashTable(bPtr->table);
472 while ((str = WMNextHashEnumeratorItem(&e))) {
473 wfree(str);
475 WMFreeHashTable(bPtr->table);
477 if (bPtr->textColor)
478 WMReleaseColor(bPtr->textColor);
480 if (bPtr->font)
481 WMReleaseFont(bPtr->font);
483 wfree(bPtr);