fixed color dragging from colorwell
[wmaker-crm.git] / WINGs / wcolorwell.c
blob7e9e0df8e4579b7a02db30fa0e60aed5fe6d4f4b
5 #include "WINGsP.h"
8 char *WMColorWellDidChangeNotification = "WMColorWellDidChangeNotification";
11 typedef struct W_ColorWell {
12 W_Class widgetClass;
13 WMView *view;
15 WMView *colorView;
17 WMColor *color;
19 WMAction *action;
20 void *clientData;
22 WMPoint ipoint;
24 struct {
25 unsigned int active:1;
26 unsigned int bordered:1;
27 } flags;
28 } ColorWell;
30 static char *_ColorWellActivatedNotification = "_ColorWellActivatedNotification";
34 static void destroyColorWell(ColorWell *cPtr);
35 static void paintColorWell(ColorWell *cPtr);
37 static void handleEvents(XEvent *event, void *data);
39 static void handleDragEvents(XEvent *event, void *data);
41 static void handleActionEvents(XEvent *event, void *data);
43 static void willResizeColorWell();
47 W_ViewDelegate _ColorWellViewDelegate = {
48 NULL,
49 NULL,
50 NULL,
51 NULL,
52 willResizeColorWell
56 #if 0
57 static WMDragSourceProcs dragProcs = {
60 #endif
62 #define DEFAULT_WIDTH 60
63 #define DEFAULT_HEIGHT 30
64 #define DEFAULT_BORDER_WIDTH 6
66 #define MIN_WIDTH 16
67 #define MIN_HEIGHT 8
71 static void
72 colorChangedObserver(void *data, WMNotification *notification)
74 WMColorPanel *panel = (WMColorPanel*)WMGetNotificationObject(notification);
75 WMColorWell *cPtr = (WMColorWell*)data;
76 WMColor *color;
78 if (!cPtr->flags.active)
79 return;
81 color = WMGetColorPanelColor(panel);
83 WMSetColorWellColor(cPtr, color);
84 WMPostNotificationName(WMColorWellDidChangeNotification, cPtr, NULL);
88 static void
89 updateColorCallback(void *self, void *data)
91 WMColorPanel *panel = (WMColorPanel*)self;
92 WMColorWell *cPtr = (ColorWell*)data;
93 WMColor *color;
95 color = WMGetColorPanelColor(panel);
96 WMSetColorWellColor(cPtr, color);
97 WMPostNotificationName(WMColorWellDidChangeNotification, cPtr, NULL);
102 static void
103 activatedObserver(void *data, WMNotification *notification)
106 WMColorWell *cPtr = (WMColorWell*)data;
108 if (!cPtr->flags.active || WMGetNotificationObject(notification) == cPtr)
109 return;
111 W_SetViewBackgroundColor(cPtr->view, WMWidgetScreen(cPtr)->gray);
112 paintColorWell(cPtr);
114 cPtr->flags.active = 0;
120 WMColorWell*
121 WMCreateColorWell(WMWidget *parent)
123 ColorWell *cPtr;
125 cPtr = wmalloc(sizeof(ColorWell));
126 memset(cPtr, 0, sizeof(ColorWell));
128 cPtr->widgetClass = WC_ColorWell;
130 cPtr->view = W_CreateView(W_VIEW(parent));
131 if (!cPtr->view) {
132 wfree(cPtr);
133 return NULL;
135 cPtr->view->self = cPtr;
137 cPtr->view->delegate = &_ColorWellViewDelegate;
139 cPtr->colorView = W_CreateView(cPtr->view);
140 if (!cPtr->colorView) {
141 W_DestroyView(cPtr->view);
142 wfree(cPtr);
143 return NULL;
145 cPtr->colorView->self = cPtr;
147 WMCreateEventHandler(cPtr->view, ExposureMask|StructureNotifyMask
148 |ClientMessageMask, handleEvents, cPtr);
150 WMCreateEventHandler(cPtr->colorView, ExposureMask, handleEvents, cPtr);
152 WMCreateEventHandler(cPtr->colorView, ButtonPressMask|ButtonMotionMask
153 |EnterWindowMask, handleDragEvents, cPtr);
155 WMCreateEventHandler(cPtr->view, ButtonPressMask, handleActionEvents,
156 cPtr);
158 cPtr->colorView->flags.mapWhenRealized = 1;
160 cPtr->flags.bordered = 1;
162 W_ResizeView(cPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
164 WMAddNotificationObserver(activatedObserver, cPtr,
165 _ColorWellActivatedNotification, NULL);
167 cPtr->color = WMBlackColor(WMWidgetScreen(cPtr));
169 WMAddNotificationObserver(colorChangedObserver, cPtr,
170 WMColorPanelColorChangedNotification, NULL);
172 return cPtr;
176 void
177 WMSetColorWellColor(WMColorWell *cPtr, WMColor *color)
179 if (cPtr->color)
180 WMReleaseColor(cPtr->color);
182 cPtr->color = WMRetainColor(color);
184 if (cPtr->colorView->flags.realized && cPtr->colorView->flags.mapped)
185 paintColorWell(cPtr);
189 WMColor*
190 WMGetColorWellColor(WMColorWell *cPtr)
192 return cPtr->color;
196 void
197 WSetColorWellBordered(WMColorWell *cPtr, Bool flag)
199 if (cPtr->flags.bordered != flag) {
200 cPtr->flags.bordered = flag;
201 W_ResizeView(cPtr->view, cPtr->view->size.width, cPtr->view->size.height);
206 #define MIN(a,b) ((a) > (b) ? (b) : (a))
208 static void
209 willResizeColorWell(W_ViewDelegate *self, WMView *view,
210 unsigned int *width, unsigned int *height)
212 WMColorWell *cPtr = (WMColorWell*)view->self;
213 int bw;
215 if (cPtr->flags.bordered) {
217 if (*width < MIN_WIDTH)
218 *width = MIN_WIDTH;
219 if (*height < MIN_HEIGHT)
220 *height = MIN_HEIGHT;
222 bw = (int)((float)MIN(*width, *height)*0.24);
224 W_ResizeView(cPtr->colorView, *width-2*bw, *height-2*bw);
226 if (cPtr->colorView->pos.x!=bw || cPtr->colorView->pos.y!=bw)
227 W_MoveView(cPtr->colorView, bw, bw);
228 } else {
229 W_ResizeView(cPtr->colorView, *width, *height);
231 W_MoveView(cPtr->colorView, 0, 0);
236 static void
237 paintColorWell(ColorWell *cPtr)
239 W_Screen *scr = cPtr->view->screen;
241 W_DrawRelief(scr, cPtr->view->window, 0, 0, cPtr->view->size.width,
242 cPtr->view->size.height, WRRaised);
244 W_DrawRelief(scr, cPtr->colorView->window, 0, 0,
245 cPtr->colorView->size.width, cPtr->colorView->size.height,
246 WRSunken);
248 if (cPtr->color)
249 WMPaintColorSwatch(cPtr->color, cPtr->colorView->window,
250 2, 2, cPtr->colorView->size.width-4,
251 cPtr->colorView->size.height-4);
256 static void
257 handleEvents(XEvent *event, void *data)
259 ColorWell *cPtr = (ColorWell*)data;
261 CHECK_CLASS(data, WC_ColorWell);
264 switch (event->type) {
265 case Expose:
266 if (event->xexpose.count!=0)
267 break;
268 paintColorWell(cPtr);
269 break;
271 case DestroyNotify:
272 destroyColorWell(cPtr);
273 break;
279 static WMPixmap*
280 makeDragPixmap(WMColorWell *cPtr)
282 WMScreen *scr = cPtr->view->screen;
283 Pixmap pix;
285 pix = XCreatePixmap(scr->display, W_DRAWABLE(scr), 16, 16, scr->depth);
287 XFillRectangle(scr->display, pix, WMColorGC(cPtr->color), 0, 0, 15, 15);
289 XDrawRectangle(scr->display, pix, WMColorGC(scr->black), 0, 0, 15, 15);
291 return WMCreatePixmapFromXPixmaps(scr, pix, None, 16, 16, scr->depth);
295 static void
296 slideView(WMView *view, int srcX, int srcY, int dstX, int dstY)
298 double x, y, dx, dy;
299 int i;
301 srcX -= 8;
302 srcY -= 8;
303 dstX -= 8;
304 dstY -= 8;
306 x = srcX;
307 y = srcY;
309 dx = (double)(dstX-srcX)/20.0;
310 dy = (double)(dstY-srcY)/20.0;
312 for (i = 0; i < 20; i++) {
313 W_MoveView(view, x, y);
314 XFlush(view->screen->display);
316 x += dx;
317 y += dy;
323 static Window
324 findChildInWindow(Display *dpy, Window toplevel, int x, int y)
326 Window foo, bar;
327 Window *children;
328 unsigned nchildren;
329 int i;
331 if (!XQueryTree(dpy, toplevel, &foo, &bar,
332 &children, &nchildren) || children == NULL) {
333 return None;
336 /* first window that contains the point is the one */
337 for (i = nchildren-1; i >= 0; i--) {
338 XWindowAttributes attr;
340 if (XGetWindowAttributes(dpy, children[i], &attr)
341 && attr.map_state == IsViewable
342 && x >= attr.x && y >= attr.y
343 && x < attr.x + attr.width && y < attr.y + attr.height) {
344 Window child;
346 child = findChildInWindow(dpy, children[i],
347 x - attr.x, y - attr.y);
349 XFree(children);
351 if (!child)
352 return toplevel;
353 else
354 return child;
358 XFree(children);
359 return None;
363 static Window
364 findWindowUnderDragPointer(WMScreen *scr, int x, int y, Window iconWindow)
366 Window foo, bar;
367 Window *children;
368 unsigned nchildren;
369 int i;
371 if (!XQueryTree(scr->display, scr->rootWin, &foo, &bar,
372 &children, &nchildren) || children == NULL) {
373 return None;
376 /* try to find the window below the iconWindow by traversing
377 * the whole window list */
379 /* first find the position of the iconWindow */
380 for (i = nchildren-1; i >= 0; i--) {
381 if (children[i] == iconWindow) {
382 i--;
383 break;
386 if (i <= 0) {
387 XFree(children);
388 return scr->rootWin;
391 /* first window that contains the point is the one */
392 for (; i >= 0; i--) {
393 XWindowAttributes attr;
394 Window child;
396 if (XGetWindowAttributes(scr->display, children[i], &attr)
397 && attr.map_state == IsViewable
398 && x >= attr.x && y >= attr.y
399 && x < attr.x + attr.width && y < attr.y + attr.height
400 && (child = findChildInWindow(scr->display, children[i],
401 x - attr.x, y - attr.y))) {
402 XFree(children);
403 return child;
407 XFree(children);
408 return None;
413 static void
414 dragColor(ColorWell *cPtr, XEvent *event, WMPixmap *image)
416 WMView *dragView;
417 WMScreen *scr = cPtr->view->screen;
418 Display *dpy = scr->display;
419 XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue};
420 XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue};
421 XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue};
422 Bool done = False;
423 WMColorWell *activeWell = NULL;
425 dragView = W_CreateTopView(scr);
427 W_ResizeView(dragView, 16, 16);
428 dragView->attribFlags |= CWOverrideRedirect | CWSaveUnder;
429 dragView->attribs.event_mask = StructureNotifyMask;
430 dragView->attribs.override_redirect = True;
431 dragView->attribs.save_under = True;
433 W_MoveView(dragView, event->xmotion.x_root-8, event->xmotion.y_root-8);
435 W_RealizeView(dragView);
437 W_MapView(dragView);
439 XSetWindowBackgroundPixmap(dpy, dragView->window, WMGetPixmapXID(image));
440 XClearWindow(dpy, dragView->window);
443 XGrabPointer(dpy, scr->rootWin, True,
444 ButtonMotionMask|ButtonReleaseMask,
445 GrabModeSync, GrabModeAsync,
446 scr->rootWin, scr->defaultCursor, CurrentTime);
448 while (!done) {
449 XEvent ev;
450 WMView *view;
451 Window win;
453 XAllowEvents(dpy, SyncPointer, CurrentTime);
454 WMNextEvent(dpy, &ev);
456 switch (ev.type) {
457 case ButtonRelease:
458 if (activeWell != NULL) {
459 WMSetColorWellColor(activeWell, cPtr->color);
460 WMPostNotificationName(WMColorWellDidChangeNotification,
461 activeWell, NULL);
462 } else {
463 slideView(dragView, ev.xbutton.x_root, ev.xbutton.y_root,
464 event->xmotion.x_root, event->xmotion.y_root);
467 done = True;
468 break;
470 case MotionNotify:
471 while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ;
473 W_MoveView(dragView, ev.xmotion.x_root-8, ev.xmotion.y_root-8);
475 win = findWindowUnderDragPointer(scr, ev.xmotion.x_root,
476 ev.xmotion.y_root,
477 dragView->window);
479 if (win != None && win != scr->rootWin) {
480 view = W_GetViewForXWindow(dpy, win);
481 } else {
482 view = NULL;
485 if (view && view->self && W_CLASS(view->self) == WC_ColorWell
486 && view->self != activeWell && view->self != cPtr) {
488 activeWell = view->self;
489 XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
491 } else if (!view || view->self != activeWell) {
493 XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
494 activeWell = NULL;
496 break;
498 default:
499 WMHandleEvent(&ev);
500 break;
503 XUngrabPointer(dpy, CurrentTime);
504 XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
506 W_DestroyView(dragView);
510 static void
511 handleDragEvents(XEvent *event, void *data)
513 WMColorWell *cPtr = (ColorWell*)data;
515 switch (event->type) {
516 case ButtonPress:
517 if (event->xbutton.button == Button1) {
518 cPtr->ipoint.x = event->xbutton.x;
519 cPtr->ipoint.y = event->xbutton.y;
521 break;
523 case MotionNotify:
524 if (event->xmotion.state & Button1Mask) {
525 if (abs(cPtr->ipoint.x - event->xmotion.x) > 4
526 || abs(cPtr->ipoint.y - event->xmotion.y) > 4) {
527 WMSize offs;
528 WMPixmap *pixmap;
530 offs.width = 2;
531 offs.height = 2;
532 pixmap = makeDragPixmap(cPtr);
535 WMDragImageFromView(cPtr->view, pixmap, cPtr->view->pos,
536 offs, event, True);
537 * */
539 dragColor(cPtr, event, pixmap);
541 WMReleasePixmap(pixmap);
544 break;
549 static void
550 handleActionEvents(XEvent *event, void *data)
552 WMColorWell *cPtr = (ColorWell*)data;
553 WMScreen *scr = WMWidgetScreen(cPtr);
554 WMColorPanel *cpanel;
556 if (cPtr->flags.active)
557 W_SetViewBackgroundColor(cPtr->view, scr->gray);
558 else
559 W_SetViewBackgroundColor(cPtr->view, scr->white);
560 paintColorWell(cPtr);
562 cPtr->flags.active ^= 1;
564 if (cPtr->flags.active) {
565 WMPostNotificationName(_ColorWellActivatedNotification, cPtr, NULL);
567 cpanel = WMGetColorPanel(scr);
569 WMSetColorPanelAction(cpanel, updateColorCallback, cPtr);
571 if (cPtr->color)
572 WMSetColorPanelColor(cpanel, cPtr->color);
573 WMShowColorPanel(cpanel);
577 static void
578 destroyColorWell(ColorWell *cPtr)
580 WMRemoveNotificationObserver(cPtr);
582 if (cPtr->color)
583 WMReleaseColor(cPtr->color);
585 wfree(cPtr);