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

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 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: brushOp.c,v 1.11 1996/11/01 09:37:12 torsten Exp $ */
  17.  
  18. #include <X11/Intrinsic.h>
  19. #include <X11/StringDefs.h>
  20. #include <X11/Shell.h>
  21. #ifndef VMS
  22. #include <X11/Xaw/Box.h>
  23. #include <X11/Xaw/Form.h>
  24. #include <X11/Xaw/Command.h>
  25. #include <X11/Xaw/Toggle.h>
  26. #else
  27. #include <X11Xaw/Box.h>
  28. #include <X11Xaw/Form.h>
  29. #include <X11Xaw/Command.h>
  30. #include <X11Xaw/Toggle.h>
  31. #endif
  32. #include <stdlib.h>
  33. #include <xpm.h>
  34.  
  35. #include "xpaint.h"
  36. #include "misc.h"
  37. #include "Paint.h"
  38. #include "PaintP.h"
  39. #include "palette.h"
  40. #include "graphic.h"
  41. #include "protocol.h"
  42. #include "image.h"
  43. #include "ops.h"
  44.  
  45. #include "bitmaps/paintA.xpm"
  46. #include "bitmaps/paintB.xpm"
  47. #include "bitmaps/paintC.xpm"
  48. #include "bitmaps/paintD.xpm"
  49. #include "bitmaps/paintE.xpm"
  50. #include "bitmaps/paintF.xpm"
  51. #include "bitmaps/paintG.xpm"
  52. #include "bitmaps/paintH.xpm"
  53. #include "bitmaps/paintI.xpm"
  54. #include "bitmaps/paintJ.xpm"
  55. #include "bitmaps/paintK.xpm"
  56. #include "bitmaps/paintL.xpm"
  57. #include "bitmaps/paintM.xpm"
  58. #include "bitmaps/paintN.xpm"
  59. #include "bitmaps/paintO.xpm"
  60. #include "bitmaps/paintP.xpm"
  61. #include "bitmaps/paintQ.xpm"
  62. #include "bitmaps/paintR.xpm"
  63. #include "bitmaps/paintS.xpm"
  64. #include "bitmaps/paintT.xpm"
  65.  
  66. #define BRUSH(name) (char **) CONCAT(name, _xpm)
  67.  
  68. #define BLEND(a, b, x)    ((x)*(b) + (1.0-(x))*(a))
  69.  
  70. typedef struct {
  71.     Pixmap pixmap;
  72.     Cursor cursor;
  73.     char **bits;
  74.     int width, height;
  75.     char *brushbits;
  76.     int numpixels;        /* Total number of set pixels */
  77. } BrushItem;
  78.  
  79. static BrushItem brushList[] =
  80. {
  81.     {None, None, BRUSH(paintA)},
  82.     {None, None, BRUSH(paintB)},
  83.     {None, None, BRUSH(paintC)},
  84.     {None, None, BRUSH(paintD)},
  85.     {None, None, BRUSH(paintE)},
  86.     {None, None, BRUSH(paintF)},
  87.     {None, None, BRUSH(paintG)},
  88.     {None, None, BRUSH(paintH)},
  89.     {None, None, BRUSH(paintI)},
  90.     {None, None, BRUSH(paintJ)},
  91.     {None, None, BRUSH(paintK)},
  92.     {None, None, BRUSH(paintL)},
  93.     {None, None, BRUSH(paintM)},
  94.     {None, None, BRUSH(paintN)},
  95.     {None, None, BRUSH(paintO)},
  96.     {None, None, BRUSH(paintP)},
  97.     {None, None, BRUSH(paintQ)},
  98.     {None, None, BRUSH(paintR)},
  99.     {None, None, BRUSH(paintS)},
  100.     {None, None, BRUSH(paintT)}
  101. };
  102.  
  103. static XpmColorSymbol monoColorSymbols[5] =
  104. {
  105.     {"A", NULL, 0},
  106.     {"B", NULL, 1},
  107.     {"C", NULL, 1},
  108.     {"D", NULL, 1},
  109.     {"E", NULL, 1}
  110. };
  111.  
  112. typedef enum {
  113.     ERASE, SMEAR, PLAIN
  114. } BrushType;
  115.  
  116. typedef struct {
  117.     Boolean useSecond;
  118.     BrushType brushtype;
  119.     Pixmap pixmap;
  120.     int width, height;
  121.     Palette *brushPalette;
  122. } LocalInfo;
  123.  
  124. static BrushItem *currentBrush = NULL;
  125. static Boolean eraseMode = True;
  126. static Boolean transparentMode = False;
  127. static float brushOpacity = 0.2;
  128. static XImage *brushImage;
  129.  
  130. static void smear(Widget w, OpInfo * info, GC gc, LocalInfo * l, int sx, int sy);
  131. static void wbrush(Widget w, OpInfo * info, GC gc,
  132.            LocalInfo * l, int sx, int sy);
  133.  
  134. static void 
  135. draw(Widget w, OpInfo * info, LocalInfo * l, int x, int y)
  136. {
  137.     XRectangle undo;
  138.     int sx = x - l->width / 2;
  139.     int sy = y - l->height / 2;
  140.     GC gc;
  141.  
  142.     if (l->brushtype == ERASE)
  143.     gc = info->base_gc;
  144.     else
  145.     gc = l->useSecond ? info->second_gc : info->first_gc;
  146.  
  147.     XSetClipOrigin(XtDisplay(w), gc, sx, sy);
  148.  
  149.     if ((l->brushtype == ERASE) && eraseMode && (info->base != None)) {
  150.     XCopyArea(XtDisplay(w), info->base, info->drawable,
  151.           gc, sx, sy, l->width, l->height, sx, sy);
  152.     } else if (l->brushtype == SMEAR) {
  153.     smear(w, info, gc, l, sx, sy);
  154.     } else if (transparentMode) {
  155.     wbrush(w, info, gc, l, sx, sy);
  156.     } else {            /* plain opaque brush */
  157.     XFillRectangle(XtDisplay(w), info->drawable,
  158.                gc, sx, sy, l->width, l->height);
  159.     }
  160.  
  161.     if (info->surface == opPixmap) {
  162.     XYtoRECT(sx, sy, sx + l->width, sy + l->height, &undo);
  163.     UndoGrow(w, sx, sy);
  164.     UndoGrow(w, sx + l->width, sy + l->height);
  165.     PwUpdate(w, &undo, False);
  166.     }
  167. }
  168.  
  169. static void 
  170. press(Widget w, LocalInfo * l, XButtonEvent * event, OpInfo * info)
  171. {
  172.     /*
  173.     **  Check to make sure all buttons are up, before doing this
  174.      */
  175.     if ((event->state & (Button1Mask | Button2Mask | Button3Mask |
  176.              Button4Mask | Button5Mask)) != 0)
  177.     return;
  178.  
  179.     if (info->surface == opWindow && info->isFat)
  180.     return;
  181.  
  182.     l->useSecond = event->button == Button2;
  183.     l->width = currentBrush->width;
  184.     l->height = currentBrush->height;
  185.  
  186.     XSetClipMask(XtDisplay(w), info->first_gc, l->pixmap);
  187.     XSetClipMask(XtDisplay(w), info->second_gc, l->pixmap);
  188.     XSetClipMask(XtDisplay(w), info->base_gc, l->pixmap);
  189.  
  190.     UndoStart(w, info);
  191.  
  192.     draw(w, info, l, event->x, event->y);
  193. }
  194.  
  195. static void 
  196. motion(Widget w, LocalInfo * l, XMotionEvent * event, OpInfo * info)
  197. {
  198.     if (!event->state || ((info->surface == opWindow) && info->isFat))
  199.     return;
  200.     draw(w, info, l, event->x, event->y);
  201. }
  202.  
  203. static void 
  204. release(Widget w, LocalInfo * l, XButtonEvent * event, OpInfo * info)
  205. {
  206.     int mask;
  207.     /*
  208.     **  Check to make sure all buttons are up, before doing this
  209.      */
  210.     mask = AllButtonsMask;
  211.     switch (event->button) {
  212.     case Button1:
  213.     mask ^= Button1Mask;
  214.     break;
  215.     case Button2:
  216.     mask ^= Button2Mask;
  217.     break;
  218.     case Button3:
  219.     mask ^= Button3Mask;
  220.     break;
  221.     case Button4:
  222.     mask ^= Button4Mask;
  223.     break;
  224.     case Button5:
  225.     mask ^= Button5Mask;
  226.     break;
  227.     }
  228.     if ((event->state & mask) != 0)
  229.     return;
  230.  
  231.     XSetClipMask(XtDisplay(w), info->first_gc, None);
  232.     XSetClipMask(XtDisplay(w), info->second_gc, None);
  233.     XSetClipMask(XtDisplay(w), info->base_gc, None);
  234. }
  235.  
  236. /*
  237. ** drawing routine for smear operator
  238.  */
  239. static void 
  240. smear(Widget wid, OpInfo * info, GC gc, LocalInfo * l, int sx, int sy)
  241. {
  242.     int x, y, n, xx, yy, w, h, d, m;
  243.     unsigned long r, g, b;
  244.     unsigned char *brushbits;
  245.     Pixel p;
  246.     Display *dpy = XtDisplay(wid);
  247.     XColor *col, newcol;
  248.  
  249.     /*
  250.      * Perform manual clipping to avoid XPutImage crashing on us
  251.      */
  252.     xx = yy = 0;
  253.     w = l->width;
  254.     h = l->height;
  255.     if (sx < 0) {
  256.     xx = -sx;
  257.     w += sx;
  258.     sx = 0;
  259.     } else if ((d = (sx + w - ((PaintWidget) wid)->paint.drawWidth)) > 0)
  260.     w -= d;
  261.     if (sy < 0) {
  262.     yy = -sy;
  263.     h += sy;
  264.     sy = 0;
  265.     } else if ((d = (sy + h - ((PaintWidget) wid)->paint.drawHeight)) > 0)
  266.     h -= d;
  267.     if ((w <= 0) || (h <= 0))
  268.     return;
  269.  
  270.  
  271.     /* copy portion of image under brush into brushImage */
  272.     XGetSubImage(dpy, info->drawable, sx, sy, w, h,
  273.          AllPlanes, ZPixmap, brushImage, xx, yy);
  274.  
  275.     /* compute average of pixels inside brush */
  276.     r = g = b = 0;
  277.     brushbits = (unsigned char *) currentBrush->brushbits;
  278.     for (y = 0; y < l->height; ++y)
  279.     for (x = 0; x < l->width; ++x)
  280.         if (*brushbits++) {
  281.         p = XGetPixel(brushImage, x, y);
  282.         col = PaletteLookup(l->brushPalette, p);
  283.         r += col->red;
  284.         g += col->green;
  285.         b += col->blue;
  286.         }
  287.     n = currentBrush->numpixels;
  288.     r = r / 256 / n;
  289.     g = g / 256 / n;
  290.     b = b / 256 / n;
  291.  
  292.     /* now blend each surface pixel with average */
  293.     brushbits = (unsigned char *) currentBrush->brushbits;
  294.     for (y = 0; y < l->height; ++y)
  295.     for (x = 0; x < l->width; ++x) {
  296.         if ((m = *brushbits++) != 0) {
  297.         float mix = m / 5.0;
  298.  
  299.         p = XGetPixel(brushImage, x, y);
  300.         col = PaletteLookup(l->brushPalette, p);
  301.         newcol.red = 256 * BLEND(col->red / 256, r, mix);
  302.         newcol.green = 256 * BLEND(col->green / 256, g, mix);
  303.         newcol.blue = 256 * BLEND(col->blue / 256, b, mix);
  304.         p = PaletteAlloc(l->brushPalette, &newcol);
  305.         XPutPixel(brushImage, x, y, p);
  306.         }
  307.     }
  308.     XPutImage(dpy, info->drawable, gc, brushImage, xx, yy, sx, sy, w, h);
  309. }
  310.  
  311.  
  312. /*
  313. ** drawing routine for transparent brush
  314.  */
  315. static void 
  316. wbrush(Widget wid, OpInfo * info, GC gc, LocalInfo * l, int sx, int sy)
  317. {
  318.     int x, y, xx, yy, m, w, h, d;
  319.     unsigned long r, g, b;
  320.     unsigned char *brushbits;
  321.     Pixel p;
  322.     Display *dpy = XtDisplay(wid);
  323.     XColor *col, newcol;
  324.     XGCValues gcval;
  325.  
  326.  
  327.     /*
  328.      * Perform manual clipping to avoid XPutImage crashing on us
  329.      */
  330.     xx = yy = 0;
  331.     w = l->width;
  332.     h = l->height;
  333.     if (sx < 0) {
  334.     xx = -sx;
  335.     w += sx;
  336.     sx = 0;
  337.     } else if ((d = (sx + w - ((PaintWidget) wid)->paint.drawWidth)) > 0)
  338.     w -= d;
  339.     if (sy < 0) {
  340.     yy = -sy;
  341.     h += sy;
  342.     sy = 0;
  343.     } else if ((d = (sy + h - ((PaintWidget) wid)->paint.drawHeight)) > 0)
  344.     h -= d;
  345.     if ((w <= 0) || (h <= 0))
  346.     return;
  347.  
  348.     /* copy portion of image under brush into brushImage */
  349.     XGetSubImage(dpy, info->drawable, sx, sy, w, h,
  350.          AllPlanes, ZPixmap, brushImage, xx, yy);
  351.  
  352.     /* get current colour */
  353.     XGetGCValues(dpy, gc, GCForeground, &gcval);
  354.     col = PaletteLookup(l->brushPalette, gcval.foreground);
  355.     r = col->red / 256;
  356.     g = col->green / 256;
  357.     b = col->blue / 256;
  358.     brushbits = (unsigned char *) currentBrush->brushbits;
  359.     for (y = 0; y < l->height; ++y)
  360.     for (x = 0; x < l->width; ++x)
  361.         if ((m = *brushbits++) != 0) {
  362.         float mix = m / 5.0 * brushOpacity;
  363.  
  364.         p = XGetPixel(brushImage, x, y);
  365.         col = PaletteLookup(l->brushPalette, p);
  366.         newcol.red = 256 * BLEND(col->red / 256, r, mix);
  367.         newcol.green = 256 * BLEND(col->green / 256, g, mix);
  368.         newcol.blue = 256 * BLEND(col->blue / 256, b, mix);
  369.         p = PaletteAlloc(l->brushPalette, &newcol);
  370.         XPutPixel(brushImage, x, y, p);
  371.         }
  372.     XPutImage(dpy, info->drawable, gc, brushImage, xx, yy, sx, sy, w, h);
  373. }
  374.  
  375.  
  376. static void 
  377. setPixmap(Widget w, void *brushArg)
  378. {
  379.     BrushItem *brush = (BrushItem *) brushArg;
  380.     LocalInfo *l = (LocalInfo *) GraphicGetData(w);
  381.  
  382.     l->pixmap = brush->pixmap;
  383. }
  384.  
  385. static void 
  386. setCursor(Widget wid, void *brushArg)
  387. {
  388.     static Boolean inited = False;
  389.     static XColor xcols[2];
  390.     BrushItem *brush = (BrushItem *) brushArg;
  391.     Display *dpy = XtDisplay(wid);
  392.     PaintWidget paint = (PaintWidget) wid;
  393.  
  394.     if (!inited) {
  395.     Colormap map;
  396.     Screen *screen = XtScreen(wid);
  397.  
  398.     inited = True;
  399.     xcols[0].pixel = WhitePixelOfScreen(screen);
  400.     xcols[1].pixel = BlackPixelOfScreen(screen);
  401.  
  402.     XtVaGetValues(wid, XtNcolormap, &map, NULL);
  403.  
  404.     XQueryColors(dpy, map, xcols, XtNumber(xcols));
  405.     }
  406.     if (brush->cursor == None) {
  407.     Pixmap source, mask;
  408.     XImage *src, *msk;
  409.     GC gc;
  410.     int x, y, w, h, ow, oh, n;
  411.     unsigned char *brushbits;
  412.     XpmAttributes xpmAttr;
  413.     static XpmColorSymbol colorsymbols[5] =
  414.     {
  415.         {"A", NULL, 0},
  416.         {"B", NULL, 1},
  417.         {"C", NULL, 2},
  418.         {"D", NULL, 3},
  419.         {"E", NULL, 4}
  420.     };
  421.  
  422.     ow = brush->width;
  423.     oh = brush->height;
  424.     w = ow + 2;
  425.     h = oh + 2;        /* add 1 pixel border for mask */
  426.  
  427.     /* get full depth pixmap */
  428.     xpmAttr.valuemask = XpmColorSymbols;
  429.     xpmAttr.numsymbols = 5;
  430.     xpmAttr.colorsymbols = colorsymbols;
  431.     XpmCreatePixmapFromData(dpy, RootWindowOfScreen(XtScreen(wid)),
  432.                 brush->bits, &source, NULL, &xpmAttr);
  433.     GetPixmapWHD(dpy, source, NULL, NULL, (int *) &xpmAttr.depth);
  434.     src = NewXImage(dpy, NULL, xpmAttr.depth, w, h);
  435.     memset(src->data, 0, src->bytes_per_line * h);
  436.  
  437.     /* copy colour pixmap to center of XImage */
  438.     XGetSubImage(dpy, source, 0, 0, ow, oh, AllPlanes, ZPixmap, src, 1, 1);
  439.     msk = NewXImage(dpy, NULL, 1, w, h);
  440.     brushbits = (unsigned char *) xmalloc(ow * oh);
  441.     brush->brushbits = (char *) brushbits;
  442.     
  443.     n = 0;
  444.     for (y = 0; y < h; y++)
  445.         for (x = 0; x < w; x++) {
  446.         Pixel p = XGetPixel(src, x, y);
  447.  
  448.         if ((y != 0) && (y != h - 1) && (x != 0) && (x != w - 1))
  449.             *brushbits++ = p;
  450.  
  451.         if (p)
  452.             ++n;
  453.  
  454.         if (!p && x > 0)
  455.             p = XGetPixel(src, x - 1, y);
  456.         if (!p && x < w - 1)
  457.             p = XGetPixel(src, x + 1, y);
  458.         if (!p && y > 0)
  459.             p = XGetPixel(src, x, y - 1);
  460.         if (!p && y < h - 1)
  461.             p = XGetPixel(src, x, y + 1);
  462.         XPutPixel(msk, x, y, p ? 1 : 0);
  463.         }
  464.     XFreePixmap(dpy, source);
  465.     XDestroyImage(src);
  466.     brush->numpixels = n;
  467.  
  468.     source = XCreatePixmap(dpy, brush->pixmap, w, h, 1);
  469.     mask = XCreatePixmap(dpy, brush->pixmap, w, h, 1);
  470.     gc = XCreateGC(dpy, mask, 0, 0);
  471.     XSetForeground(dpy, gc, 0);
  472.     XFillRectangle(dpy, source, gc, 0, 0, w, h);
  473.     XCopyArea(dpy, brush->pixmap, source, gc, 0, 0, ow, oh, 1, 1);
  474.     XPutImage(dpy, mask, gc, msk, 0, 0, 0, 0, w, h);
  475.     XDestroyImage(msk);
  476.     XFreeGC(dpy, gc);
  477.  
  478.     brush->cursor = XCreatePixmapCursor(dpy, source, mask,
  479.                         &xcols[1], &xcols[0],
  480.                         w / 2, h / 2);
  481.     XFreePixmap(dpy, source);
  482.     XFreePixmap(dpy, mask);
  483.     }
  484.     FatCursorSet(wid, brush->pixmap);
  485.  
  486.     /* don't set cursor to brush shape if zoom is larger than 1 */
  487.     if (paint->paint.zoom <= 1)
  488.     XtVaSetValues(wid, XtNcursor, brush->cursor, NULL);
  489.     else {
  490.     SetCrossHairCursor(wid);
  491.     FatCursorAddZoom(paint->paint.zoom, wid);
  492.     XtAddCallback(wid, XtNdestroyCallback, FatCursorDestroyCallback, wid);
  493.     }
  494. }
  495.  
  496. /*
  497. **  Those public functions
  498.  */
  499.  
  500. Boolean
  501. EraseGetMode(void)
  502. {
  503.     return eraseMode;
  504. }
  505.  
  506. void
  507. EraseSetMode(Boolean mode)
  508. {
  509.     eraseMode = mode;
  510. }
  511.  
  512. void
  513. BrushSetMode(Boolean mode)
  514. {
  515.     transparentMode = mode;
  516. }
  517.  
  518. void
  519. BrushSetParameters(float opacity)
  520. {
  521.     brushOpacity = opacity;
  522. }
  523.  
  524. void *
  525. BrushAdd(Widget w)
  526. {
  527.     static LocalInfo *l;
  528.     Colormap cmap;
  529.  
  530.     l = XtNew(LocalInfo);
  531.  
  532.     XtVaSetValues(w, XtNcompress, False, NULL);
  533.  
  534.     l->brushtype = PLAIN;
  535.     l->pixmap = currentBrush->pixmap;
  536.     XtVaGetValues(w, XtNcolormap, &cmap, NULL);
  537.     l->brushPalette = PaletteFind(w, cmap);
  538.  
  539.     OpAddEventHandler(w, opWindow | opPixmap, ButtonPressMask,
  540.               FALSE, (OpEventProc) press, (XtPointer) l);
  541.     OpAddEventHandler(w, opWindow | opPixmap, ButtonMotionMask,
  542.               FALSE, (OpEventProc) motion, (XtPointer) l);
  543.     OpAddEventHandler(w, opWindow | opPixmap, ButtonReleaseMask,
  544.               FALSE, (OpEventProc) release, (XtPointer) l);
  545.  
  546.     setCursor(w, (void *) currentBrush);
  547.  
  548.     return l;
  549. }
  550.  
  551. void
  552. BrushRemove(Widget w, void *l)
  553. {
  554.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonPressMask,
  555.              FALSE, (OpEventProc) press, (XtPointer) l);
  556.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonMotionMask,
  557.              FALSE, (OpEventProc) motion, (XtPointer) l);
  558.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonReleaseMask,
  559.              FALSE, (OpEventProc) release, (XtPointer) l);
  560.  
  561.     XtFree((XtPointer) l);
  562.     FatCursorOff(w);
  563. }
  564.  
  565. void *
  566. EraseAdd(Widget w)
  567. {
  568.     LocalInfo *l = XtNew(LocalInfo);
  569.  
  570.     XtVaSetValues(w, XtNcompress, False, NULL);
  571.  
  572.     l->brushtype = ERASE;
  573.     l->pixmap = currentBrush->pixmap;
  574.  
  575.     OpAddEventHandler(w, opWindow | opPixmap, ButtonPressMask,
  576.               FALSE, (OpEventProc) press, (XtPointer) l);
  577.     OpAddEventHandler(w, opWindow | opPixmap, ButtonMotionMask,
  578.               FALSE, (OpEventProc) motion, (XtPointer) l);
  579.     OpAddEventHandler(w, opWindow | opPixmap, ButtonReleaseMask,
  580.               FALSE, (OpEventProc) release, (XtPointer) l);
  581.  
  582.     setCursor(w, (void *) currentBrush);
  583.  
  584.     return l;
  585. }
  586.  
  587. void
  588. EraseRemove(Widget w, void *l)
  589. {
  590.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonPressMask,
  591.              FALSE, (OpEventProc) press, (XtPointer) l);
  592.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonMotionMask,
  593.              FALSE, (OpEventProc) motion, (XtPointer) l);
  594.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonReleaseMask,
  595.              FALSE, (OpEventProc) release, (XtPointer) l);
  596.  
  597.     XtFree((XtPointer) l);
  598.     FatCursorOff(w);
  599. }
  600.  
  601. void *
  602. SmearAdd(Widget w)
  603. {
  604.     LocalInfo *l = XtNew(LocalInfo);
  605.     Colormap cmap;
  606.  
  607.  
  608.     XtVaSetValues(w, XtNcompress, False, NULL);
  609.  
  610.     l->brushtype = SMEAR;
  611.     l->pixmap = currentBrush->pixmap;
  612.     XtVaGetValues(w, XtNcolormap, &cmap, NULL);
  613.     l->brushPalette = PaletteFind(w, cmap);
  614.  
  615.     OpAddEventHandler(w, opWindow | opPixmap, ButtonPressMask,
  616.               FALSE, (OpEventProc) press, (XtPointer) l);
  617.     OpAddEventHandler(w, opWindow | opPixmap, ButtonMotionMask,
  618.               FALSE, (OpEventProc) motion, (XtPointer) l);
  619.     OpAddEventHandler(w, opWindow | opPixmap, ButtonReleaseMask,
  620.               FALSE, (OpEventProc) release, (XtPointer) l);
  621.  
  622.     setCursor(w, (void *) currentBrush);
  623.  
  624.     return l;
  625. }
  626.  
  627. void
  628. SmearRemove(Widget w, void *l)
  629. {
  630.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonPressMask,
  631.              FALSE, (OpEventProc) press, (XtPointer) l);
  632.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonMotionMask,
  633.              FALSE, (OpEventProc) motion, (XtPointer) l);
  634.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonReleaseMask,
  635.              FALSE, (OpEventProc) release, (XtPointer) l);
  636.  
  637.     XtFree((XtPointer) l);
  638.     FatCursorOff(w);
  639. }
  640.  
  641. /*
  642. **  Initializer to create a default brush
  643.  */
  644. void
  645. BrushInit(Widget toplevel)
  646. {
  647.     XpmAttributes xpmAttr;
  648.  
  649.     currentBrush = &brushList[0];
  650.  
  651.     /* force depth of one */
  652.     xpmAttr.depth = 1;
  653.     xpmAttr.colorsymbols = monoColorSymbols;
  654.     xpmAttr.valuemask = XpmDepth | XpmColorSymbols;
  655.     XpmCreatePixmapFromData(XtDisplay(toplevel),
  656.                 RootWindowOfScreen(XtScreen(toplevel)),
  657.                 currentBrush->bits, ¤tBrush->pixmap,
  658.                 NULL, &xpmAttr);
  659.     currentBrush->width = xpmAttr.width;
  660.     currentBrush->height = xpmAttr.height;
  661.  
  662.     brushImage = NewXImage(XtDisplay(toplevel), NULL,
  663.                DefaultDepthOfScreen(XtScreen(toplevel)),
  664.                currentBrush->width, currentBrush->height);
  665. }
  666.  
  667. /*
  668. **  The brush selection dialog
  669.  */
  670.  
  671. static void
  672. closePopup(Widget button, Widget shell)
  673. {
  674.     XtPopdown(shell);
  675. }
  676.  
  677. static void
  678. selectBrush(Widget shell, BrushItem * nc)
  679. {
  680.     currentBrush = nc;
  681.  
  682.     if ((CurrentOp->add == BrushAdd) ||
  683.     (CurrentOp->add == EraseAdd) ||
  684.     (CurrentOp->add == SmearAdd)) {
  685.     GraphicAll(setCursor, (void *) currentBrush);
  686.     GraphicAll(setPixmap, (void *) currentBrush);
  687.     }
  688.     if (brushImage != NULL)
  689.     XDestroyImage(brushImage);
  690.     brushImage = NewXImage(XtDisplay(shell), NULL,
  691.                DefaultDepthOfScreen(XtScreen(shell)),
  692.                currentBrush->width, currentBrush->height);
  693. }
  694.  
  695. static Widget
  696. createDialog(Widget w)
  697. {
  698.     Widget shell, form, box, icon, firstIcon = 0, close;
  699.     GC gc;
  700.     XGCValues values;
  701.     int i;
  702.     Pixel fg, bg;
  703.     Pixmap pix;
  704.     int nw, nh, ox, oy;
  705.     XpmAttributes xpmAttr;
  706.  
  707.     shell = XtVaCreatePopupShell("brush",
  708.                  topLevelShellWidgetClass, w,
  709.                  NULL);
  710.  
  711.     form = XtVaCreateManagedWidget(NULL,
  712.                    formWidgetClass, shell,
  713.                    NULL);
  714.  
  715.     box = XtVaCreateManagedWidget("box",
  716.                   boxWidgetClass, form,
  717.                   NULL);
  718.  
  719.     values.foreground = WhitePixelOfScreen(XtScreen(w));
  720.     values.background = BlackPixelOfScreen(XtScreen(w));
  721.  
  722.     gc = XCreateGC(XtDisplay(w),
  723.            RootWindowOfScreen(XtScreen(w)),
  724.            GCForeground | GCBackground, &values);
  725.  
  726.     values.background = WhitePixelOfScreen(XtScreen(w));
  727.     values.foreground = BlackPixelOfScreen(XtScreen(w));
  728.  
  729.     for (i = 0; i < XtNumber(brushList); i++) {
  730.     if (brushList[i].pixmap == None) {
  731.         /* force depth of one */
  732.         xpmAttr.depth = 1;
  733.         xpmAttr.colorsymbols = monoColorSymbols;
  734.         xpmAttr.valuemask = XpmDepth | XpmColorSymbols;
  735.         XpmCreatePixmapFromData(XtDisplay(box),
  736.                     RootWindowOfScreen(XtScreen(box)),
  737.                  brushList[i].bits, &brushList[i].pixmap,
  738.                     NULL, &xpmAttr);
  739.         brushList[i].width = xpmAttr.width;
  740.         brushList[i].height = xpmAttr.height;
  741.     }
  742.     icon = XtVaCreateManagedWidget("icon",
  743.                        toggleWidgetClass, box,
  744.                        XtNradioGroup, firstIcon,
  745.                        NULL);
  746.     nw = brushList[i].width;
  747.     nh = brushList[i].height;
  748.     ox = oy = 0;
  749.     if (nw < 16) {
  750.         ox = (16 - nw) / 2;
  751.         nw = 16;
  752.     }
  753.     if (nh < 16) {
  754.         oy = (16 - nh) / 2;
  755.         nh = 16;
  756.     }
  757.     pix = XCreatePixmap(XtDisplay(box),
  758.                 RootWindowOfScreen(XtScreen(box)),
  759.                 nw, nh,
  760.                 DefaultDepthOfScreen(XtScreen(box)));
  761.  
  762.     XtVaGetValues(icon, XtNforeground, &fg, XtNbackground, &bg,
  763.               NULL);
  764.     /*
  765.     **  Clear then draw the clipped rectangle in
  766.      */
  767.     XSetClipMask(XtDisplay(w), gc, None);
  768.     XSetForeground(XtDisplay(w), gc, bg);
  769.     XFillRectangle(XtDisplay(w), pix, gc, 0, 0, nw, nh);
  770.     XSetClipMask(XtDisplay(w), gc, brushList[i].pixmap);
  771.     XSetClipOrigin(XtDisplay(w), gc, ox, oy);
  772.     XSetForeground(XtDisplay(w), gc, fg);
  773.     XFillRectangle(XtDisplay(w), pix, gc, 0, 0, nw, nh);
  774.  
  775.     XtVaSetValues(icon, XtNbitmap, pix, NULL);
  776.  
  777.     if (firstIcon == NULL) {
  778.         XtVaSetValues(icon, XtNstate, True, NULL);
  779.         firstIcon = icon;
  780.     }
  781.     XtAddCallback(icon, XtNcallback,
  782.            (XtCallbackProc) selectBrush, (XtPointer) & brushList[i]);
  783.     }
  784.  
  785.     close = XtVaCreateManagedWidget("close",
  786.                     commandWidgetClass, form,
  787.                     XtNfromVert, box,
  788.                     XtNtop, XtChainBottom,
  789.                     NULL);
  790.  
  791.     XtAddCallback(close, XtNcallback, (XtCallbackProc) closePopup,
  792.           (XtPointer) shell);
  793.  
  794.     XFreeGC(XtDisplay(w), gc);
  795.  
  796.     AddDestroyCallback(shell, (DestroyCallbackFunc) closePopup, shell);
  797.  
  798.     return shell;
  799. }
  800.  
  801. void 
  802. BrushSelect(Widget w)
  803. {
  804.     static Widget popup = NULL;
  805.  
  806.     if (popup == NULL)
  807.     popup = createDialog(GetToplevel(w));
  808.  
  809.     XtPopup(popup, XtGrabNone);
  810.     XMapRaised(XtDisplay(popup), XtWindow(popup));
  811. }
  812.