home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / color.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  21KB  |  900 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)               | */
  3. /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
  4. /* |                                       | */
  5. /* | Permission to use, copy, modify, and to distribute this software  | */
  6. /* | and its documentation for any purpose is hereby granted without   | */
  7. /* | fee, provided that the above copyright notice appear in all       | */
  8. /* | copies and that both that copyright notice and this permission    | */
  9. /* | notice appear in supporting documentation.     There is no           | */
  10. /* | representations about the suitability of this software for           | */
  11. /* | any purpose.  this software is provided "as is" without express   | */
  12. /* | or implied warranty.                           | */
  13. /* |                                       | */
  14. /* +-------------------------------------------------------------------+ */
  15.  
  16. /* $Id: color.c,v 1.10 1996/05/28 09:15:19 torsten Exp $ */
  17.  
  18. #include <stdio.h>
  19. #include <X11/Intrinsic.h>
  20. #include <X11/Shell.h>
  21. #ifndef VMS
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/Label.h>
  24. #include <X11/Xaw/Scrollbar.h>
  25. #include <X11/Xaw/AsciiText.h>
  26. #include <X11/Xaw/Command.h>
  27. #include <X11/Xaw/Text.h>
  28. #else
  29. #include <X11Xaw/Form.h>
  30. #include <X11Xaw/Label.h>
  31. #include <X11Xaw/Scrollbar.h>
  32. #include <X11Xaw/AsciiText.h>
  33. #include <X11Xaw/Command.h>
  34. #include <X11Xaw/Text.h>
  35. #endif
  36. #include <X11/StringDefs.h>
  37. #include <X11/cursorfont.h>
  38.  
  39. #ifndef NOSTDHDRS
  40. #include <stdlib.h>
  41. #include <unistd.h>
  42. #endif
  43.  
  44. #include "palette.h"
  45. #include "protocol.h"
  46. #include "color.h"
  47.  
  48. #include <math.h>
  49.  
  50. #include "xpaint.h"
  51. #include "misc.h"
  52. #include "image.h"
  53.  
  54. #ifndef M_PI
  55. #define M_PI        3.14159265358979323846
  56. #endif
  57.  
  58. #define PIXMAP_WIDTH  120
  59. #define PIXMAP_HEIGHT 120
  60. #define RADIUS          50
  61.  
  62. #define RECOMPUTE(l)                    \
  63.     if (l->isRGB)                    \
  64.       rgbTOhsv(l->r,l->g,l->b,&l->h,&l->s,&l->v);    \
  65.     else                        \
  66.       hsvTOrgb(l->h,l->s,l->v,&l->r,&l->g,&l->b);
  67.  
  68. typedef void (*cbFunc_t) (Widget, XtPointer, Pixel);
  69.  
  70. typedef struct LocalInfo_s {
  71.     Boolean initing, inCallback;
  72.     Widget form;
  73.  
  74.     Widget valueBar, redBar, greenBar, blueBar;
  75.  
  76.     /*
  77.     **    Color image picker widget, and delta x, y;
  78.     **     also a copy gc, and the image
  79.      */
  80.     GC gc, xgc;
  81.     Pixmap pixmap;
  82.     Widget picker;
  83.     int dx, dy;
  84.     Pixel bg;
  85.  
  86.     /*
  87.     **    Static current view
  88.      */
  89.     Widget view;
  90.     Pixel pixel;
  91.     Colormap cmap;
  92.  
  93.     /*
  94.     **
  95.      */
  96.     Widget valueText, redText, greenText, blueText;
  97.  
  98.     Boolean isRGB;
  99.     float h, s, v;
  100.     float r, g, b;
  101.  
  102.     Palette *map;
  103.     cbFunc_t func;
  104.     XtPointer data;
  105.  
  106.     struct LocalInfo_s *next;
  107. } LocalInfo;
  108.  
  109. static LocalInfo *head = NULL;
  110.  
  111. static void 
  112. rgbTOhsv(float r, float g, float b, float *h, float *s, float *v)
  113. {
  114.     float max = MAX(r, MAX(g, b));
  115.     float min = MIN(r, MIN(g, b));
  116.     float delta;
  117.  
  118.     *v = max;
  119.     if (max != 0.0)
  120.     *s = (max - min) / max;
  121.     else
  122.     *s = 0.0;
  123.  
  124.     if (*s == 0.0) {
  125.     *h = 0.0;
  126.     } else {
  127.     delta = max - min;
  128.     if (r == max)
  129.         *h = (g - b) / delta;
  130.     else if (g == max)
  131.         *h = 2.0 + (b - r) / delta;
  132.     else            /* if (b == max) */
  133.         *h = 4.0 + (r - g) / delta;
  134.     *h *= 60.0;
  135.     if (*h < 0.0)
  136.         *h += 360.0;
  137.     }
  138. }
  139.  
  140. static void 
  141. hsvTOrgb(float h, float s, float v, float *r, float *g, float *b)
  142. {
  143.     int i;
  144.     float f, p, q, t;
  145.  
  146.     if (s == 0 && h == 0) {
  147.     *r = *g = *b = v;
  148.     } else {
  149.     if (h >= 360.0)
  150.         h = 0.0;
  151.     h /= 60.0;
  152.  
  153.     i = h;
  154.     f = h - i;
  155.     p = v * (1 - s);
  156.     q = v * (1 - (s * f));
  157.     t = v * (1 - (s * (1 - f)));
  158.     switch (i) {
  159.     case 0:
  160.         *r = v;
  161.         *g = t;
  162.         *b = p;
  163.         break;
  164.     case 1:
  165.         *r = q;
  166.         *g = v;
  167.         *b = p;
  168.         break;
  169.     case 2:
  170.         *r = p;
  171.         *g = v;
  172.         *b = t;
  173.         break;
  174.     case 3:
  175.         *r = p;
  176.         *g = q;
  177.         *b = v;
  178.         break;
  179.     case 4:
  180.         *r = t;
  181.         *g = p;
  182.         *b = v;
  183.         break;
  184.     case 5:
  185.         *r = v;
  186.         *g = p;
  187.         *b = q;
  188.         break;
  189.     }
  190.     }
  191. }
  192.  
  193. /*
  194. **  Event callback routines
  195.  */
  196. static void 
  197. drawCursor(LocalInfo * l, Boolean flag)
  198. {
  199.     Dimension width, height;
  200.     int sx, sy;
  201.  
  202.     if (!XtIsRealized(l->picker))
  203.     return;
  204.  
  205.     XtVaGetValues(l->picker, XtNwidth, &width, XtNheight, &height, NULL);
  206.  
  207.     sx = -l->dx - 3 + width / 2;
  208.     sy = -l->dy - 3 + height / 2;
  209.  
  210.     if (flag) {
  211.     XDrawArc(XtDisplay(l->picker), XtWindow(l->picker), l->xgc,
  212.          sx, sy, 6, 6, 0, 360 * 64);
  213.     } else {
  214.     int cx, cy;
  215.     cx = PIXMAP_WIDTH / 2;
  216.     cy = PIXMAP_HEIGHT / 2;
  217.  
  218.     XCopyArea(XtDisplay(l->picker), l->pixmap, XtWindow(l->picker), l->gc,
  219.           -l->dx + cx - 4, -l->dy + cy - 4,
  220.           8, 8, sx - 1, sy - 1);
  221.     }
  222. }
  223.  
  224. static void 
  225. update(LocalInfo * l, Boolean doSB, Boolean doText, Boolean doCursor)
  226. {
  227.     XColor col;
  228.     Pixel p;
  229.  
  230.     if (doSB) {
  231.     XawScrollbarSetThumb(l->valueBar, l->v, -1.0);
  232.     XawScrollbarSetThumb(l->redBar, l->r, -1.0);
  233.     XawScrollbarSetThumb(l->greenBar, l->g, -1.0);
  234.     XawScrollbarSetThumb(l->blueBar, l->b, -1.0);
  235.     }
  236.     if (doText) {
  237.     char buf[20];
  238.  
  239.     sprintf(buf, "%5.3f", l->v);
  240.     XtVaSetValues(l->valueText, XtNstring, buf, NULL);
  241.     sprintf(buf, "%d", (int) (l->r * 255));
  242.     XtVaSetValues(l->redText, XtNstring, buf, NULL);
  243.     sprintf(buf, "%d", (int) (l->g * 255));
  244.     XtVaSetValues(l->greenText, XtNstring, buf, NULL);
  245.     sprintf(buf, "%d", (int) (l->b * 255));
  246.     XtVaSetValues(l->blueText, XtNstring, buf, NULL);
  247.     }
  248.     if (doCursor) {
  249.     drawCursor(l, False);
  250.  
  251.     l->dx = sin(l->h * M_PI / 180.0) * l->s * RADIUS;
  252.     l->dy = cos(l->h * M_PI / 180.0) * l->s * RADIUS;
  253.  
  254.     drawCursor(l, True);
  255.     }
  256.     if (l->initing)
  257.     return;
  258.  
  259.     col.flags = DoRed | DoGreen | DoBlue;
  260.     col.red = l->r * 0xffff;
  261.     col.green = l->g * 0xffff;
  262.     col.blue = l->b * 0xffff;
  263.     col.pixel = l->pixel;
  264.     p = l->pixel;
  265.  
  266. #if 0
  267.     if ((l->map != NULL) &&
  268. #ifndef VMS
  269.     (l->map->readonly ||
  270. #else
  271.     (l->map->Readonly ||
  272. #endif /* VMS */
  273.      ((DefaultVisualOfScreen(XtScreen(l->view))->class & 1) == 0)))
  274. #endif
  275.     XtVaSetValues(l->view, XtNbackground,
  276.               p = PaletteAlloc(l->map, &col), NULL);
  277. #if 0
  278.     else
  279.     XStoreColor(XtDisplay(l->view), l->cmap, &col);
  280. #endif
  281.  
  282.     if (l->func != NULL) {
  283.     l->inCallback = True;
  284.     l->func(l->form, l->data, p);
  285.     l->inCallback = False;
  286.     }
  287. }
  288.  
  289. static void 
  290. expose(Widget w, LocalInfo * l, XExposeEvent * event, Boolean * flg)
  291. {
  292.     Dimension width, height;
  293.     int dx, dy;
  294.  
  295.     XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL);
  296.  
  297.     dx = (PIXMAP_WIDTH - width) / 2;
  298.     dy = (PIXMAP_HEIGHT - height) / 2;
  299.  
  300.     XCopyArea(XtDisplay(w), l->pixmap, XtWindow(w), l->gc,
  301.           event->x + dx, event->y + dy,
  302.           event->width, event->height,
  303.           event->x, event->y);
  304.     drawCursor(l, True);
  305. }
  306.  
  307. static void 
  308. motion(Widget w, LocalInfo * l, XEvent * event, Boolean * flg)
  309. {
  310.     Dimension width, height;
  311.     int cx, cy;
  312.     int dx, dy, dx2, dy2;
  313.  
  314.     while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w),
  315.                   MotionNotify, (XEvent *) event));
  316.  
  317.     XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL);
  318.  
  319.     cx = width / 2;
  320.     cy = height / 2;
  321.  
  322.     if (event->type == ButtonPress) {
  323.     dx = cx - event->xbutton.x;
  324.     dy = cy - event->xbutton.y;
  325.     } else {
  326.     dx = cx - event->xmotion.x;
  327.     dy = cy - event->xmotion.y;
  328.     }
  329.     dx2 = dx * dx;
  330.     dy2 = dy * dy;
  331.  
  332.  
  333.     if (dx == 0 && dy == 0)
  334.     l->h = 0;
  335.     else if ((l->h = atan2((double) dx, (double) dy)) < 0.0)
  336.     l->h += 2 * M_PI;
  337.     l->s = sqrt((double) (dx2 + dy2)) / RADIUS;
  338.     l->h *= 360.0 / (2 * M_PI);
  339.  
  340.     if (l->s > 1.0) {
  341.     l->s = 1.0;
  342.     dx = sin(l->h * M_PI / 180.0) * RADIUS;
  343.     dy = cos(l->h * M_PI / 180.0) * RADIUS;
  344.     }
  345.     drawCursor(l, False);
  346.     l->dx = dx;
  347.     l->dy = dy;
  348.     drawCursor(l, True);
  349.  
  350.     l->isRGB = False;
  351.     RECOMPUTE(l);
  352.     update(l, True, True, False);
  353. }
  354.  
  355. static void 
  356. barCB(Widget w, LocalInfo * l, float *percent)
  357. {
  358.     l->isRGB = True;
  359.  
  360.     if (l->redBar == w)
  361.     l->r = *percent;
  362.     else if (l->greenBar == w)
  363.     l->g = *percent;
  364.     else if (l->blueBar == w)
  365.     l->b = *percent;
  366.     else if (l->valueBar == w) {
  367.     l->v = *percent;
  368.     l->isRGB = False;
  369.     }
  370.     RECOMPUTE(l);
  371.     update(l, True, True, l->isRGB);
  372. }
  373.  
  374. static void 
  375. textExitCB(Widget w, LocalInfo * l, XtPointer junk)
  376. {
  377.     String val;
  378.     int v;
  379.  
  380.  
  381.     XtVaGetValues(w, XtNstring, &val, NULL);
  382.     if (w != l->valueText) {
  383.     v = atoi(val);
  384.     if (v > 255) {
  385.         v = 255;
  386.         XtVaSetValues(w, XtNstring, "255", NULL);
  387.     }
  388.     if (v < 0) {
  389.         v = 0;
  390.         XtVaSetValues(w, XtNstring, "0", NULL);
  391.     }
  392.     if (w == l->redText) {
  393.         if ((int) (l->r * 255.0) == v)
  394.         return;
  395.         l->r = v / 255.0;
  396.         l->isRGB = True;
  397.         RECOMPUTE(l);
  398.     }
  399.     if (w == l->greenText) {
  400.         if ((int) (l->g * 255.0) == v)
  401.         return;
  402.         l->g = v / 255.0;
  403.         l->isRGB = True;
  404.         RECOMPUTE(l);
  405.     }
  406.     if (w == l->blueText) {
  407.         if ((int) (l->b * 255.0) == v)
  408.         return;
  409.         l->b = v / 255.0;
  410.         l->isRGB = True;
  411.         RECOMPUTE(l);
  412.     }
  413.     } else {
  414.     float f = atof(val);
  415.  
  416.     /*
  417.     **  Same to 3 decimal places?
  418.      */
  419.     if ((int) (f * 1000) == (int) (l->v * 1000))
  420.         return;
  421.  
  422.     l->v = f;
  423.     l->isRGB = False;
  424.     RECOMPUTE(l);
  425.     }
  426.  
  427.     update(l, True, True, l->isRGB);
  428. }
  429.  
  430. static void 
  431. textAction(Widget w, XEvent * event, String * prms, Cardinal * nprms)
  432. {
  433.     Widget cpick;
  434.     LocalInfo *l = head;
  435.  
  436.     cpick = w;
  437.     while (cpick != None && strcmp(XtName(cpick), "colorPicker") != 0)
  438.     cpick = XtParent(cpick);
  439.  
  440.     if (cpick == None)
  441.     return;
  442.  
  443.     for (; l != NULL && l->form != cpick; l = l->next);
  444.  
  445.     textExitCB(w, l, NULL);
  446. }
  447.  
  448.  
  449. static void 
  450. grabCB(Widget w, LocalInfo * l, XtPointer junk)
  451. {
  452.     XColor *xcol = DoGrabColor(w);
  453.  
  454.     l->isRGB = True;
  455.     l->r = (float) ((xcol->red >> 8) & 0xff) / (float) 0xff;
  456.     l->g = (float) ((xcol->green >> 8) & 0xff) / (float) 0xff;
  457.     l->b = (float) ((xcol->blue >> 8) & 0xff) / (float) 0xff;
  458.  
  459.     RECOMPUTE(l);
  460.     update(l, True, True, True);
  461. }
  462.  
  463. /*
  464. **  Create a nice little color wheel that we can pick colors from.
  465. **  Create it as an Image so that we can compress it down to the
  466. **  supported number of colors, after we've allocated "perfect" ones.
  467. **
  468.  */
  469. static void 
  470. drawInPixmap(Widget w, Palette * map, Colormap cmap,
  471.          Pixel bg, Pixmap pix, GC gc)
  472. {
  473.     XImage *xim = XGetImage(XtDisplay(w), pix, 0, 0,
  474.                 PIXMAP_WIDTH, PIXMAP_HEIGHT,
  475.                 AllPlanes, ZPixmap);
  476.     int offX = PIXMAP_WIDTH / 2 - RADIUS;
  477.     int offY = PIXMAP_HEIGHT / 2 - RADIUS;
  478.     float r, g, b;
  479.     float h, s;
  480.     int x, y;
  481.     static Image *image = NULL;
  482.     unsigned char *ip;
  483.     int i;
  484.     XColor xcol[64];
  485.     Pixel pval[XtNumber(xcol)];
  486.     int backgroundIndex = 0;
  487.     Boolean isTrue = (map != NULL && !map->isMapped);
  488.  
  489.     StateSetBusyWatch(True);
  490.  
  491.     if (image == NULL || isTrue) {
  492.     image = ImageNew(2 * RADIUS, 2 * RADIUS);
  493.     ip = image->data;
  494.  
  495.     for (y = 0; y < 2 * RADIUS; y++)
  496.         for (x = 0; x < 2 * RADIUS; x++) {
  497.         int dx, dy, dx2, dy2;
  498.  
  499.         dx = RADIUS - x;
  500.         dx2 = dx * dx;
  501.         dy = RADIUS - y;
  502.         dy2 = dy * dy;
  503.  
  504.         if (dx2 + dy2 > RADIUS * RADIUS) {
  505.             *ip++ = 0;
  506.             *ip++ = 0;
  507.             *ip++ = 0;
  508.             continue;
  509.         }
  510.         if (dx == 0 && dy == 0)
  511.             h = 0;
  512.         else if ((h = atan2((double) dx, (double) dy)) < 0.0)
  513.             h += 2 * M_PI;
  514.         s = sqrt((double) (dx2 + dy2)) / RADIUS;
  515.  
  516.         h *= 360.0 / (2 * M_PI);
  517.  
  518.         hsvTOrgb(h, s, 1.0, &r, &g, &b);
  519.  
  520.         *ip++ = r * 255;
  521.         *ip++ = g * 255;
  522.         *ip++ = b * 255;
  523.         if (isTrue) {
  524.             XColor c;
  525.             c.red = r * 0xffff;
  526.             c.green = g * 0xffff;
  527.             c.blue = b * 0xffff;
  528.             XPutPixel(xim, offX + x, offY + y,
  529.                   PaletteAlloc(map, &c));
  530.         }
  531.         }
  532.     if (isTrue) {
  533.         ImageDelete(image);
  534.         image = NULL;
  535.     } else
  536.         image = ImageCompress(image, XtNumber(xcol), 0);
  537.     }
  538.     if (!isTrue) {
  539.     for (i = 0; i < image->cmapSize; i++) {
  540.         xcol[i].flags = DoRed | DoGreen | DoBlue;
  541.         xcol[i].red = image->cmapData[i * 3 + 0] * 256;
  542.         xcol[i].green = image->cmapData[i * 3 + 1] * 256;
  543.         xcol[i].blue = image->cmapData[i * 3 + 2] * 256;
  544.         if (xcol[i].green == 0 && xcol[i].blue == 0 && xcol[i].red == 0) {
  545.         backgroundIndex = i;
  546.         continue;
  547.         }
  548.         if (map == NULL) {
  549.         XAllocColor(XtDisplay(w), cmap, &xcol[i]);
  550.         pval[i] = xcol[i].pixel;
  551.         }
  552.     }
  553.  
  554.     if (map != NULL)
  555.         PaletteAllocN(map, xcol, image->cmapSize, pval);
  556.  
  557.     for (ip = image->data, y = 0; y < 2 * RADIUS; y++)
  558.         for (x = 0; x < 2 * RADIUS; x++, ip++)
  559.         if (*ip == backgroundIndex)
  560.             XPutPixel(xim, offX + x, offY + y, bg);
  561.         else
  562.             XPutPixel(xim, offX + x, offY + y, pval[*ip]);
  563.     }
  564.     XPutImage(XtDisplay(w), pix, gc, xim, 0, 0, 0, 0,
  565.           PIXMAP_WIDTH, PIXMAP_HEIGHT);
  566.     XDestroyImage(xim);
  567.  
  568.     StateSetBusyWatch(False);
  569. }
  570.  
  571. static Widget
  572. createBarText(Widget parent, Widget above, String msg,
  573.           Widget * bar, Widget * text)
  574. {
  575.     static String textTranslations =
  576.     "#override\n\
  577. <Key>Return: color-text-ok()\n\
  578. <Key>Linefeed: color-text-ok()\n\
  579. Ctrl<Key>M: color-text-ok()\n\
  580. Ctrl<Key>J: color-text-ok()\n";
  581.     static XtTranslations trans = None;
  582.     Widget subform, label;
  583.  
  584.     if (trans == None) {
  585.     static XtActionsRec act =
  586.     {"color-text-ok", (XtActionProc) textAction};
  587.  
  588.     XtAppAddActions(XtWidgetToApplicationContext(parent), &act, 1);
  589.  
  590.     trans = XtParseTranslationTable(textTranslations);
  591.     }
  592.     subform = XtVaCreateManagedWidget("form", formWidgetClass, parent,
  593.                       XtNborderWidth, 0,
  594.                       XtNfromVert, above,
  595.                       NULL);
  596.     label = XtVaCreateManagedWidget("valueLabel", labelWidgetClass, subform,
  597.                     XtNlabel, msg,
  598.                     XtNborderWidth, 0,
  599.                     XtNright, XtChainLeft,
  600.                     XtNleft, XtChainLeft,
  601.                     NULL);
  602.     *bar = XtVaCreateManagedWidget("valueBar", scrollbarWidgetClass, subform,
  603.                    XtNorientation, XtorientHorizontal,
  604.                    XtNwidth, 50,
  605.                    XtNfromHoriz, label,
  606.                    XtNleft, XtChainLeft,
  607.                    NULL);
  608.     *text = XtVaCreateManagedWidget("valueText", asciiTextWidgetClass, subform,
  609.                     XtNfromHoriz, *bar,
  610.                     XtNeditType, XawtextEdit,
  611.                     XtNwrap, XawtextWrapNever,
  612.                     XtNresize, XawtextResizeWidth,
  613.                     XtNtranslations, trans,
  614.                     XtNwidth, 50,
  615.                     XtNlength, 5,
  616.                     NULL);
  617.     return subform;
  618. }
  619.  
  620. static void 
  621. freePixel(Widget w, LocalInfo * l)
  622. {
  623.     XFreeColors(XtDisplay(w), l->cmap, &l->pixel, 1, 0);
  624. }
  625.  
  626. static LocalInfo *
  627. colorPicker(Widget parent, Colormap cmap, Pixel * pixval)
  628. {
  629.     Widget top = GetToplevel(parent);
  630.     Widget form, picker, subform;
  631.     Widget button;
  632.     LocalInfo *l = (LocalInfo *) XtNew(LocalInfo);
  633.     XGCValues gcvalues;
  634.  
  635.     if (cmap == None)
  636.     cmap = DefaultColormapOfScreen(XtScreen(parent));
  637.  
  638.     l->initing = True;
  639.     l->inCallback = False;
  640.     l->func = NULL;
  641.  
  642.     l->cmap = cmap;
  643.  
  644.     form = XtVaCreateManagedWidget("colorPicker", formWidgetClass, parent, NULL);
  645.  
  646.     /*
  647.     **    The HS space image
  648.      */
  649.     picker = XtVaCreateManagedWidget("palette", coreWidgetClass, form,
  650.                      XtNwidth, PIXMAP_WIDTH,
  651.                      XtNheight, PIXMAP_WIDTH,
  652.                      NULL);
  653.     l->picker = picker;
  654.  
  655.     XtAddEventHandler(picker, ExposureMask, False,
  656.               (XtEventHandler) expose, (XtPointer) l);
  657.     XtAddEventHandler(picker, ButtonPressMask, False,
  658.               (XtEventHandler) motion, (XtPointer) l);
  659.     XtAddEventHandler(picker, ButtonMotionMask, False,
  660.               (XtEventHandler) motion, (XtPointer) l);
  661.  
  662.     gcvalues.foreground = BlackPixel(XtDisplay(top),
  663.                      DefaultScreen(XtDisplay(top)));
  664.     l->xgc = XtGetGC(picker, GCForeground, &gcvalues);
  665.  
  666.     /*
  667.     **    The color "view"
  668.      */
  669.     l->pixel = None;
  670.     if (pixval == NULL) {
  671.     if (XAllocColorCells(XtDisplay(top), cmap, False, NULL, 0, &l->pixel, 1)) {
  672.         XColor col;
  673.         col.pixel = l->pixel;
  674.         col.flags = DoRed | DoGreen | DoBlue;
  675.         col.red = 0xffff;
  676.         col.green = 0xffff;
  677.         col.blue = 0xffff;
  678.         XStoreColor(XtDisplay(top), cmap, &col);
  679.  
  680.         XtAddCallback(form, XtNdestroyCallback,
  681.               (XtCallbackProc) freePixel, (XtPointer) l);
  682.     }
  683.     } else {
  684.     l->pixel = *pixval;
  685.     }
  686.     l->view = XtVaCreateManagedWidget("view", coreWidgetClass, form,
  687.                       XtNwidth, 40,
  688.                       XtNheight, 40,
  689.                       XtNfromHoriz, picker,
  690.                       XtNbackground, l->pixel,
  691.                       NULL);
  692.  
  693.     button = XtVaCreateManagedWidget("match", commandWidgetClass, form,
  694.                      XtNfromVert, l->view,
  695.                      XtNfromHoriz, picker,
  696.                      NULL);
  697.     XtAddCallback(button, XtNcallback, (XtCallbackProc) grabCB, (XtPointer) l);
  698.  
  699.     /*
  700.     **    Now create the scroll bars
  701.      */
  702.     subform = createBarText(form, picker, "Value", &l->valueBar, &l->valueText);
  703.     subform = createBarText(form, subform, "Red", &l->redBar, &l->redText);
  704.     subform = createBarText(form, subform, "Green", &l->greenBar, &l->greenText);
  705.     subform = createBarText(form, subform, "Blue", &l->blueBar, &l->blueText);
  706.  
  707.     XtAddCallback(l->valueBar, XtNjumpProc,
  708.           (XtCallbackProc) barCB, (XtPointer) l);
  709.     XtAddCallback(l->redBar, XtNjumpProc,
  710.           (XtCallbackProc) barCB, (XtPointer) l);
  711.     XtAddCallback(l->greenBar, XtNjumpProc,
  712.           (XtCallbackProc) barCB, (XtPointer) l);
  713.     XtAddCallback(l->blueBar, XtNjumpProc,
  714.           (XtCallbackProc) barCB, (XtPointer) l);
  715.  
  716.     l->isRGB = True;
  717.     l->r = l->g = l->b = 1.0;
  718.     RECOMPUTE(l);
  719.     update(l, True, True, True);
  720.  
  721.     l->form = form;
  722.     l->next = head;
  723.     head = l;
  724.  
  725.     return l;
  726. }
  727.  
  728. Widget
  729. ColorPickerPalette(Widget parent, Palette * map, Pixel * pixval)
  730. {
  731.     LocalInfo *l = colorPicker(parent, map->cmap, pixval);
  732.     XGCValues gcvalues;
  733.     Cardinal depth;
  734.  
  735.     XtVaGetValues(l->picker, XtNbackground, &gcvalues.foreground,
  736.           XtNdepth, &depth, NULL);
  737.     l->pixmap = XCreatePixmap(XtDisplay(l->picker),
  738.                   DefaultRootWindow(XtDisplay(l->picker)),
  739.                   PIXMAP_WIDTH, PIXMAP_HEIGHT, depth);
  740.     l->gc = XtGetGC(l->picker, GCForeground, &gcvalues);
  741.     XFillRectangle(XtDisplay(l->picker), l->pixmap, l->gc,
  742.            0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
  743.     l->map = map;
  744.     l->bg = gcvalues.foreground;
  745.     drawInPixmap(l->picker, map, l->cmap, l->bg, l->pixmap, l->gc);
  746.  
  747.     l->initing = False;
  748.     return l->form;
  749. }
  750.  
  751. Widget
  752. ColorPicker(Widget parent, Colormap cmap, Pixel * pixval)
  753. {
  754.     LocalInfo *l = colorPicker(parent, cmap, pixval);
  755.     XGCValues gcvalues;
  756.     Cardinal depth;
  757.  
  758.     l->map = NULL;
  759.  
  760.     XtVaGetValues(l->picker, XtNbackground, &gcvalues.foreground,
  761.           XtNdepth, &depth, NULL);
  762.     l->pixmap = XCreatePixmap(XtDisplay(l->picker),
  763.                   DefaultRootWindow(XtDisplay(l->picker)),
  764.                   PIXMAP_WIDTH, PIXMAP_HEIGHT, depth);
  765.     l->gc = XtGetGC(l->picker, GCForeground, &gcvalues);
  766.     XFillRectangle(XtDisplay(l->picker), l->pixmap, l->gc,
  767.            0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
  768.  
  769.     l->bg = gcvalues.foreground;
  770.     drawInPixmap(l->picker, NULL, l->cmap, l->bg,
  771.          l->pixmap, l->gc);
  772.  
  773.     l->initing = False;
  774.     return l->form;
  775. }
  776.  
  777. void 
  778. ColorPickerShell(Widget w)
  779. {
  780.     Widget top = GetToplevel(w);
  781.     Widget shell;
  782.  
  783.     shell = XtVaCreatePopupShell("color", transientShellWidgetClass,
  784.                  GetShell(w), NULL);
  785.  
  786.     ColorPicker(shell, DefaultColormapOfScreen(XtScreen(top)), NULL);
  787.  
  788.     XtPopup(shell, XtGrabNone);
  789. }
  790.  
  791. void 
  792. ColorPickerSetXColor(Widget w, XColor * xcol)
  793. {
  794.     LocalInfo *l = head;
  795.  
  796.     for (; l != NULL && l->form != w; l = l->next);
  797.  
  798.     if (l == NULL || l->inCallback)
  799.     return;
  800.  
  801.     l->isRGB = True;
  802.     l->r = (float) ((xcol->red >> 8) & 0xff) / (float) 0xff;
  803.     l->g = (float) ((xcol->green >> 8) & 0xff) / (float) 0xff;
  804.     l->b = (float) ((xcol->blue >> 8) & 0xff) / (float) 0xff;
  805.  
  806.     RECOMPUTE(l);
  807.     update(l, True, True, True);
  808. }
  809.  
  810. void 
  811. ColorPickerSetPixel(Widget w, Pixel pix)
  812. {
  813.     LocalInfo *l = head;
  814.     XColor xcol;
  815.  
  816.     for (; l != NULL && l->form != w; l = l->next);
  817.  
  818.     if (l == NULL || l->inCallback)
  819.     return;
  820.  
  821.     XtVaSetValues(l->view, XtNbackground, pix, NULL);
  822.  
  823.     xcol.pixel = pix;
  824.     XQueryColor(XtDisplay(w), l->cmap, &xcol);
  825.  
  826.     l->isRGB = True;
  827.     l->r = (float) ((xcol.red >> 8) & 0xff) / (float) 0xff;
  828.     l->g = (float) ((xcol.green >> 8) & 0xff) / (float) 0xff;
  829.     l->b = (float) ((xcol.blue >> 8) & 0xff) / (float) 0xff;
  830.     l->pixel = pix;
  831.  
  832.     RECOMPUTE(l);
  833.     update(l, True, True, True);
  834. }
  835.  
  836. void 
  837. ColorPickerSetFunction(Widget w, XtCallbackProc func, XtPointer data)
  838. {
  839.     LocalInfo *l = head;
  840.  
  841.     for (; l != NULL && l->form != w; l = l->next);
  842.  
  843.     if (l == NULL)
  844.     return;
  845.  
  846.     l->func = (cbFunc_t) func;
  847.     l->data = data;
  848. }
  849.  
  850. Pixel
  851. ColorPickerGetPixel(Widget w)
  852. {
  853.     LocalInfo *l = head;
  854.  
  855.     for (; l != NULL && l->form != w; l = l->next);
  856.  
  857.     if (l == NULL)
  858.     return None;
  859.     return l->pixel;
  860. }
  861.  
  862. XColor *
  863. ColorPickerGetXColor(Widget w)
  864. {
  865.     static XColor xcol;
  866.     LocalInfo *l = head;
  867.  
  868.     for (; l != NULL && l->form != w; l = l->next);
  869.  
  870.     if (l == NULL)
  871.     return NULL;
  872.     xcol.pixel = l->pixel;
  873.     xcol.red = l->r * 0xffff;
  874.     xcol.green = l->g * 0xffff;
  875.     xcol.blue = l->b * 0xffff;
  876.  
  877.     return &xcol;
  878. }
  879.  
  880. /*
  881.  * Update the colour map for the specified ColorPicker.
  882.  */
  883. void 
  884. ColorPickerUpdateMap(Widget w, Palette * map)
  885. {
  886.     LocalInfo *l = head;
  887.  
  888.  
  889.     for (; l != NULL && l->form != w; l = l->next);
  890.  
  891.     if (l == NULL)
  892.     return;
  893.  
  894.     l->map = map;
  895.     l->cmap = map->cmap;
  896.  
  897.     drawInPixmap(l->picker, map, l->cmap, l->bg, l->pixmap, l->gc);
  898.     XClearArea(XtDisplay(w), XtWindow(l->picker), 0, 0, 0, 0, True);
  899. }
  900.