home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / fatbitsedit.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  20KB  |  822 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: fatBitsEdit.c,v 1.15 1996/10/25 13:20:32 torsten Exp $ */
  17.  
  18. #include <X11/Intrinsic.h>
  19. #include <X11/IntrinsicP.h>    /* for XtResizeWidget() */
  20. #include <X11/StringDefs.h>
  21. #ifndef VMS
  22. #include <X11/Xaw/Command.h>
  23. #include <X11/Xaw/Toggle.h>
  24. #include <X11/Xaw/Viewport.h>
  25. #include <X11/Xaw/Box.h>
  26. #include <X11/Xaw/Form.h>
  27. #include <X11/Xaw/Scrollbar.h>
  28. #else
  29. #include <X11Xaw/Command.h>
  30. #include <X11Xaw/Toggle.h>
  31. #include <X11Xaw/Viewport.h>
  32. #include <X11Xaw/Box.h>
  33. #include <X11Xaw/Form.h>
  34. #include <X11Xaw/Scrollbar.h>
  35. #endif
  36. #include <X11/Shell.h>
  37. #include <X11/cursorfont.h>
  38. #include <stdio.h>
  39. #ifndef NOSTDHDRS
  40. #include <stdlib.h>
  41. #include <unistd.h>
  42. #endif
  43. #include "Paint.h"
  44. #include "PaintP.h"
  45. #include "xpaint.h"
  46. #include "palette.h"
  47. #include "menu.h"
  48. #include "misc.h"
  49. #include "cutCopyPaste.h"
  50. #include "protocol.h"
  51. #include "graphic.h"
  52. #include "ops.h"
  53.  
  54. #define PADDING    4
  55. #define BW    1
  56.  
  57. typedef struct LocalInfo_s {
  58.     int curX, curY;
  59.     int offX, offY, baseX, baseY;
  60.     Widget cursor;        /* The Box widget */
  61.     Widget subpaint;        /* the paint widget inside the box */
  62.     Widget view;        /* the widget in the popup window */
  63.     Widget paint;        /* The source of this zoom */
  64.     Widget shell;
  65.  
  66.     int zoom;            /* paint widget (parent) zoom value */
  67.     Position spX, spY;        /* subpaint x, y (relative to Box widget) */
  68.     Dimension spBW;        /* subpaint borderwidth */
  69.     struct LocalInfo_s *next;
  70. } LocalInfo;
  71.  
  72. static LocalInfo *head = NULL;
  73.  
  74. typedef struct {
  75.     int size;            /* Max # of line segments */
  76.     int nsegs;            /* Current # of line segments */
  77.     XSegment *segs;        /* The segments */
  78. } FatLineCursor;
  79.  
  80. /*
  81.  * Segments are allocated in chunks this size. The smallest brush
  82.  * in the current brush palette uses 9 segments.
  83.  */
  84. #define FATCHUNK 16
  85.  
  86. /*
  87.  * Info passed to FatCursorDraw().
  88.  */
  89. typedef struct fcinfo {
  90.     Widget w;
  91.     Boolean drawn;
  92.     int lastX, lastY;
  93.     GC gcx;
  94.     int zoom;
  95.     struct fcinfo *next;
  96. } FatCursorInfo;
  97.  
  98. typedef struct {
  99.     FatCursorInfo *info;
  100.     Pixmap pixmap;        /* Pixmap used for building master */
  101.     FatLineCursor cursor;
  102. } FatMasterInfo;
  103.  
  104. static FatMasterInfo master =
  105. {NULL};
  106.  
  107. /*
  108.  * Add a line segment to fc.
  109.  * Reallocs if necessary.
  110.  */
  111. static void 
  112. AddSegment(FatLineCursor * fc, int x1, int y1, int x2, int y2)
  113. {
  114.     XSegment *p;
  115.  
  116.     if (fc->nsegs >= fc->size) {
  117.     fc->size += FATCHUNK;
  118.     fc->segs = realloc(fc->segs, fc->size * sizeof(XSegment));
  119.     }
  120.     p = &fc->segs[fc->nsegs++];
  121.     p->x1 = x1;
  122.     p->y1 = y1;
  123.     p->x2 = x2;
  124.     p->y2 = y2;
  125. }
  126.  
  127. /*
  128.  * Given a pixmap, create a master vector cursor.
  129.  */
  130. static void 
  131. CreateFatCursor(Widget paint, Pixmap cursor, FatLineCursor * fc)
  132. {
  133.     XImage *src;
  134.     int w, h, x, y, xoff, yoff;
  135.     Display *dpy = XtDisplay(paint);
  136.  
  137.     fc->nsegs = 0;
  138.     fc->size = FATCHUNK;
  139.     fc->segs = malloc(FATCHUNK * sizeof(XSegment));
  140.  
  141.     GetPixmapWHD(dpy, cursor, &w, &h, NULL);
  142.     src = XGetImage(dpy, cursor, 0, 0, w, h, AllPlanes, ZPixmap);
  143.     xoff = w / 2;
  144.     yoff = h / 2;
  145.     for (y = 0; y < h; ++y)
  146.     for (x = 0; x < w; ++x)
  147.         /*
  148.          * If we find a black pixel, check the four neighbours and
  149.          * place a line segment between the pixel and each white neighbour.
  150.          */
  151.         if (XGetPixel(src, x, y)) {
  152.         /* If at the edge, always add a line */
  153.         if ((x == 0) || (XGetPixel(src, x - 1, y) == 0))
  154.             AddSegment(fc, x - xoff, y - yoff, x - xoff, y - yoff + 1);
  155.         if ((y == 0) || (XGetPixel(src, x, y - 1) == 0))
  156.             AddSegment(fc, x - xoff, y - yoff, x - xoff + 1, y - yoff);
  157.         if ((x == w - 1) || (XGetPixel(src, x + 1, y) == 0))
  158.             AddSegment(fc, x - xoff + 1, y - yoff, x - xoff + 1, y - yoff + 1);
  159.         if ((y == h - 1) || (XGetPixel(src, x, y + 1) == 0))
  160.             AddSegment(fc, x - xoff, y - yoff + 1, x - xoff + 1, y - yoff + 1);
  161.         }
  162. }
  163.  
  164.  
  165. static void 
  166. FatCursorDraw(Widget w, FatCursorInfo * l, XMotionEvent * event)
  167. {
  168.     int x, y, i, n, z;
  169.     XSegment *s;
  170.     Display *dpy = XtDisplay(w);
  171.     Window win = XtWindow(w);
  172.     static int drawing = 0;
  173.  
  174.     /*
  175.      * If someone is still drawing on the canvas, return
  176.      */
  177.     if (drawing) {
  178.     if (event->type == ButtonRelease) {
  179.         drawing = 0;
  180.         l->drawn = 0;    /* Don't draw at old position */
  181.     } else
  182.         return;
  183.     }
  184.     n = master.cursor.nsegs;
  185.     z = l->zoom;
  186.  
  187.     /*
  188.      * Erase the old cursor (if any)
  189.      */
  190.     if (l->drawn) {
  191.     x = l->lastX;
  192.     y = l->lastY;
  193.     s = master.cursor.segs;
  194.     for (i = 0; i < n; ++i, ++s)
  195.         XDrawLine(dpy, win, l->gcx,
  196.               x + z * s->x1, y + z * s->y1,
  197.               x + z * s->x2, y + z * s->y2);
  198.     }
  199.     /*
  200.      * If a button is pressed, leave the cursor undrawn
  201.      */
  202.     if (event->type == ButtonPress) {
  203.     drawing = 1;
  204.     return;
  205.     }
  206.     /*
  207.      * If we're leaving the window, only draw the cursor once
  208.      * when we enter again
  209.      */
  210.     if (event->type == LeaveNotify) {
  211.     l->drawn = 0;
  212.     return;
  213.     }
  214.     l->drawn = 1;
  215.     x = event->x;
  216.     y = event->y;
  217.     /* Snap to zoom grid */
  218.     x = x / z * z;
  219.     y = y / z * z;
  220. #ifndef TRUNC_SNAP
  221.     if (event->x - x > z / 2)
  222.     x += z;
  223.     if (event->y - y > z / 2)
  224.     y += z;
  225. #endif
  226.     s = master.cursor.segs;
  227.     for (i = 0; i < n; ++i, ++s)
  228.     XDrawLine(dpy, win, l->gcx,
  229.           x + z * s->x1, y + z * s->y1,
  230.           x + z * s->x2, y + z * s->y2);
  231.  
  232.     l->lastX = x;
  233.     l->lastY = y;
  234. }
  235.  
  236. /*
  237.  * Register a fat cursor for the specified widget.
  238.  * If a fat cursor is already active, just update the zoom.
  239.  */
  240. void 
  241. FatCursorAddZoom(int zoom, Widget winwid)
  242. {
  243.     FatCursorInfo *new, *p;
  244.  
  245.     for (p = master.info; p != NULL; p = p->next)
  246.     if (p->w == winwid) {
  247.         p->zoom = zoom;
  248.         XtInsertEventHandler(winwid,
  249.                  PointerMotionMask | ButtonPressMask |
  250.                  ButtonReleaseMask | LeaveWindowMask,
  251.                  False, (XtEventHandler) FatCursorDraw,
  252.                  (XtPointer) p, XtListHead);
  253.         return;
  254.     }
  255.     new = XtNew(FatCursorInfo);
  256.     new->next = master.info;
  257.     master.info = new;
  258.     new->zoom = zoom;
  259.     new->w = winwid;
  260.     new->gcx = GetGCX(winwid);
  261.     new->drawn = False;
  262.  
  263.     /*
  264.      * FatCursorDraw must be called before the drawing routine so that
  265.      * it can remove the cursor in time.
  266.      */
  267.     XtInsertEventHandler(winwid,
  268.              PointerMotionMask | ButtonPressMask | ButtonReleaseMask | LeaveWindowMask,
  269.           False, (XtEventHandler) FatCursorDraw, (XtPointer) new,
  270.              XtListHead);
  271. }
  272.  
  273. /*
  274.  * Unregister a fat cursor for the specified widget's window.
  275.  */
  276. void 
  277. FatCursorRemoveZoom(Widget winwid)
  278. {
  279.     FatCursorInfo *p, *pp;
  280.  
  281.     for (p = pp = master.info; p != NULL; pp = p, p = p->next)
  282.     if (p->w == winwid)
  283.         break;
  284.  
  285.     if (p == NULL)        /* not found */
  286.     return;
  287.  
  288.     XtRemoveEventHandler(winwid, PointerMotionMask | ButtonPressMask |
  289.              ButtonReleaseMask | LeaveWindowMask,
  290.              False, (XtEventHandler) FatCursorDraw, (XtPointer) p);
  291.     if (pp == p)
  292.     master.info = p->next;
  293.     else
  294.     pp->next = p->next;
  295.     XtFree((XtPointer) p);
  296. }
  297.  
  298. void 
  299. FatCursorDestroyCallback(Widget w, XtPointer arg, XtPointer junk)
  300. {
  301.     FatCursorRemoveZoom((Widget) arg);
  302. }
  303.  
  304. /*
  305.  * Rebuild the master vector cursor corresponding to the specified pixmap.
  306.  */
  307. void 
  308. FatCursorSet(Widget w, Pixmap cursor)
  309. {
  310.     if (master.pixmap != cursor) {    /* Avoid setting cursor more than once */
  311.     master.pixmap = cursor;
  312.     if (master.cursor.segs != NULL)
  313.         free(master.cursor.segs);
  314.     CreateFatCursor(w, cursor, &master.cursor);
  315.     }
  316. }
  317.  
  318. /*
  319.  * If the specified widget has a FatCursor, remove its event handler.
  320.  */
  321. void 
  322. FatCursorOff(Widget w)
  323. {
  324.     FatCursorInfo *p;
  325.  
  326.     for (p = master.info; p != NULL; p = p->next)
  327.     if (p->w == w) {
  328.         XtRemoveEventHandler(p->w,
  329.                  PointerMotionMask | ButtonPressMask |
  330.                  ButtonReleaseMask | LeaveWindowMask,
  331.                  False, (XtEventHandler) FatCursorDraw,
  332.                  (XtPointer) p);
  333.         XtRemoveCallback(p->w, XtNdestroyCallback,
  334.                  FatCursorDestroyCallback, p->w);
  335.         return;
  336.     }
  337. }
  338.  
  339. /*
  340. **  When the popup window is gone, free the storage
  341.  */
  342. static void 
  343. destroyCallback(Widget w, XtPointer larg, void *junk2)
  344. {
  345.     LocalInfo *l = (LocalInfo *) larg;
  346.     LocalInfo *c = head, **p = &head;
  347.  
  348.     while (c != NULL && c != l) {
  349.     p = &c->next;
  350.     c = c->next;
  351.     }
  352.  
  353.     if (c != NULL)
  354.     *p = l->next;
  355.  
  356.     XtFree((XtPointer) l);
  357. }
  358.  
  359. /*
  360. **  Done or WM-Close pressed, destroy widgets
  361.  */
  362. static void 
  363. doneCallback(Widget w, XtPointer larg, void *junk2)
  364. {
  365.     LocalInfo *l = (LocalInfo *) larg;
  366.  
  367.     FatCursorRemoveZoom(l->view);
  368.  
  369.     /*
  370.     **    Destroy both the cursor and the popup window
  371.      */
  372.     XtDestroyWidget(l->cursor);
  373.     XtDestroyWidget(GetShell(w));
  374. }
  375.  
  376. /*
  377. **  Move the cursor and the view window to the position
  378. **   specified by x,y
  379. **  w, h are dimensions of the zoomed area
  380.  */
  381. static void 
  382. moveCursor(LocalInfo * l, int x, int y, int w, int h)
  383. {
  384.     int dw, dh;
  385.     int rx, ry;
  386.     int z;
  387.  
  388.     if (w == -1 || h == -1) {
  389.     Dimension wt, ht;
  390.  
  391.     XtVaGetValues(l->view, XtNzoom, &z,
  392.               XtNwidth, &wt,
  393.               XtNheight, &ht,
  394.               NULL);
  395.     w = (wt + z - 1) / z;
  396.     h = (ht + z - 1) / z;
  397.     }
  398.     XtVaGetValues(l->paint, XtNdrawWidth, &dw, XtNdrawHeight, &dh, NULL);
  399.  
  400.     z = l->zoom;
  401.     h *= z;
  402.     w *= z;
  403.     dh *= z;
  404.     dw *= z;
  405.     if (x < 0)
  406.     x = 0;
  407.     if (y < 0)
  408.     y = 0;
  409.     if (x + w > dw)
  410.     x = dw - w;
  411.     if (y + h > dh)
  412.     y = dh - h;
  413.     if (x < 0 || y < 0)
  414.     return;
  415.  
  416.     rx = x / z;        /* correct for parent's zoom factor */
  417.     ry = y / z;
  418.     x = rx * z;        /* snap view origin to zoom grid */
  419.     y = ry * z;
  420.  
  421.     XtVaSetValues(l->view, XtNzoomX, rx, XtNzoomY, ry, NULL);
  422.     XtVaSetValues(l->cursor, XtNx, x - l->spX - l->spBW - 1,
  423.           XtNy, y - l->spY - l->spBW - 1, NULL);
  424.     XtVaSetValues(l->subpaint, XtNzoomX, rx, XtNzoomY, ry, NULL);
  425. }
  426.  
  427. /*
  428. **  Given the popup dimensions, set the "cursor" view to the correct size
  429.  */
  430. static void 
  431. resizeCursor(LocalInfo * l)
  432. {
  433.     Dimension width, height;
  434.     int zoom;
  435.     int pw, ph;
  436.     int dw, dh;
  437.     int zx, zy;
  438.  
  439.     XtVaGetValues(l->view, XtNwidth, &width,
  440.           XtNheight, &height,
  441.           XtNzoom, &zoom,
  442.           NULL);
  443.     XtVaGetValues(l->paint, XtNdrawWidth, &dw,
  444.           XtNdrawHeight, &dh,
  445.           XtNzoom, &l->zoom,
  446.           NULL);
  447.     XtVaGetValues(l->subpaint, XtNzoomX, &zx,
  448.           XtNzoomY, &zy,
  449.           NULL);
  450.  
  451.     pw = (width + zoom - 1) / zoom;
  452.     ph = (height + zoom - 1) / zoom;
  453.     if ((pw + zx > dw) || (ph + zy > dh)) {
  454.     int nx, ny;
  455.  
  456.     nx = (pw + zx > dw) ? dw - pw : zx;
  457.     ny = (ph + zy > dh) ? dh - ph : zy;
  458.  
  459.     /*
  460.     **  If the new x or y value off the screen, set it back.
  461.     **    and resize view
  462.      */
  463.     if (nx < 0 || ny < 0) {
  464.         if (nx < 0) {
  465.         pw += nx;
  466.         nx = 0;
  467.         }
  468.         if (ny < 0) {
  469.         ph += ny;
  470.         ny = 0;
  471.         }
  472.         /* XXX -- this really should be SetValues(width,height)
  473.         **          but that doesn't work..?/
  474.          */
  475.         XtResizeWidget(l->view, pw * zoom, ph * zoom, 1);
  476.     }
  477.     moveCursor(l, nx, ny, pw, ph);
  478.     }
  479.     pw *= l->zoom;
  480.     ph *= l->zoom;
  481.  
  482.     XtVaSetValues(l->cursor, XtNwidth, pw + 2 * (PADDING + BW),
  483.           XtNheight, ph + 2 * (PADDING + BW),
  484.           NULL);
  485.     XtVaSetValues(l->subpaint, XtNwidth, pw, XtNheight, ph, NULL);
  486. }
  487.  
  488. /*
  489. **  Button down in the cursor window
  490.  */
  491. static void 
  492. press(Widget w, LocalInfo * l, XButtonEvent * event, Boolean * flg)
  493. {
  494.     Position x, y;
  495.  
  496.     XtVaGetValues(w, XtNx, &x, XtNy, &y, NULL);
  497.  
  498.     l->offX = event->x;
  499.     l->offY = event->y;
  500.     l->baseX = event->x_root - x;
  501.     l->baseY = event->y_root - y;
  502.     XtVaGetValues(l->paint, XtNzoom, &l->zoom, NULL);
  503. }
  504.  
  505. static void 
  506. motion(Widget w, LocalInfo * l, XMotionEvent * event, Boolean * flg)
  507. {
  508.     int nx, ny;
  509.     int px, py;
  510.  
  511.     /*
  512.     **    Compress motion events.
  513.      */
  514.     while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w),
  515.                   MotionNotify, (XEvent *) event));
  516.  
  517.     nx = event->x_root - l->baseX;
  518.     ny = event->y_root - l->baseY;
  519.  
  520.     px = nx + l->spX + l->spBW + 1;
  521.     py = ny + l->spY + l->spBW + 1;
  522.  
  523.     moveCursor(l, px, py, -1, -1);
  524. }
  525.  
  526. /*
  527. **  If the paint view size changes, update the parent paint window cursor size
  528.  */
  529. static void 
  530. sizeChanged(Widget w, XtPointer l, XtPointer junk)
  531. {
  532.     resizeCursor((LocalInfo *) l);
  533. }
  534.  
  535. /*
  536. **  The parent box widget changed size, resize to fit.
  537.  */
  538. static void 
  539. boxChanged(Widget w, LocalInfo * l, XConfigureEvent * event, Boolean * flg)
  540. {
  541.     Dimension width, height;
  542.     Dimension hpad, vpad, bw;
  543.     int zoom;
  544.  
  545.     XtVaGetValues(l->view, XtNzoom, &zoom, XtNborderWidth, &bw,
  546.           NULL);
  547.     XtVaGetValues(XtParent(l->view), XtNwidth, &width,
  548.           XtNheight, &height,
  549.           XtNhSpace, &hpad,
  550.           XtNvSpace, &vpad,
  551.           NULL);
  552.     width -= (hpad + bw) * 2;
  553.     height -= (vpad + bw) * 2;
  554.  
  555.     /* XXX -- this really should be SetValues(width,height)
  556.     **          but that doesn't work..?/
  557.      */
  558.     XtResizeWidget(l->view, width, height, 1);
  559.  
  560.     resizeCursor(l);
  561. }
  562.  
  563. /*
  564. **  One of the zoom percentage buttons pressed
  565.  */
  566. static void 
  567. buttonCallback(Widget w, XtPointer lArg, void *junk2)
  568. {
  569.     LocalInfo *l = (LocalInfo *) lArg;
  570.     char *lbl;
  571.     int nz;
  572.     int cx, cy, zx, zy, z, nw, nh;
  573.     int x, y;
  574.     Dimension width, height;
  575.     Boolean state;
  576.  
  577.     XtVaGetValues(w, XtNstate, &state, XtNlabel, &lbl, NULL);
  578.  
  579.     if (state == False)
  580.     return;
  581.  
  582.     nz = 0;
  583.     sscanf(lbl, "%*d:%d", &nz);
  584.     if (nz == 0)
  585.     return;
  586.  
  587.     XtVaGetValues(l->view, XtNzoomX, &zx,
  588.           XtNzoomY, &zy,
  589.           XtNzoom, &z,
  590.           XtNwidth, &width,
  591.           XtNheight, &height,
  592.           NULL);
  593.  
  594.     if ((CurrentOp->add == BrushAdd) || (CurrentOp->add == EraseAdd) ||
  595.     (CurrentOp->add == SmearAdd))
  596.     FatCursorAddZoom(nz, l->view);
  597.  
  598.     cx = zx + ((width + z - 1) / z) / 2;
  599.     cy = zy + ((height + z - 1) / z) / 2;
  600.     nw = (width + nz - 1) / nz;
  601.     nh = (height + nz - 1) / nz;
  602.  
  603.     XtVaSetValues(l->view, XtNzoom, nz, NULL);
  604.     /*    center on image center */
  605.     x = cx - nw / 2;
  606.     y = cy - nh / 2;
  607.  
  608.     moveCursor(l, x, y, width / nz, height / nz);
  609. }
  610.  
  611. /*
  612.  * Called when the zoom factor or size of the canvas is changed,
  613.  * so that the FatBits cursor window can be resized.
  614.  * If zoom is -1, don't change zoom factor, just redisplay
  615.  * cursor window.
  616.  */
  617. void 
  618. FatbitsUpdate(Widget w, int zoom)
  619. {
  620.     LocalInfo *l;
  621.     int x, y, vw, vh, dw, dh;
  622.  
  623.  
  624.     /* find fatbits info structure for this popup */
  625.     for (l = head; l != NULL; l = l->next)
  626.     if (l->paint == w) {
  627.         if (zoom > 0)
  628.         l->zoom = zoom;    /* new parent zoom factor */
  629.         else
  630.         zoom = l->zoom;
  631.  
  632.         resizeCursor(l);    /* correct cursor window size */
  633.  
  634.         /* reposition cursor window in parent paint window */
  635.         XtVaGetValues(l->view, XtNzoomX, &x, XtNzoomY, &y, NULL);
  636.         XtVaSetValues(l->cursor, XtNx, x * zoom - l->spX - l->spBW - 1,
  637.               XtNy, y * zoom - l->spY - l->spBW - 1, NULL);
  638.  
  639.         XtVaGetValues(w, XtNdrawWidth, &dw, XtNdrawHeight, &dh, NULL);
  640.         /* The Viewport is grandparent of the paint widget */
  641.         vw = vh = 0;
  642.         XtVaGetValues(XtParent(XtParent(w)),
  643.               XtNwidth, &vw, XtNheight, &vh, NULL);
  644.         if ((dw * zoom > vw) || (dh * zoom > vh))
  645.         /*
  646.          * The zoomed canvas is larger than the viewport.
  647.          * Reposition view on canvas so cursor window remains visible.
  648.          * This solution is not perfect: the cursor window is simply
  649.          * positioned at (0,0) in the viewport window.
  650.          * Still, it's better than having a non-visible cursor window.
  651.          */
  652.         XawViewportSetCoordinates(XtParent(XtParent(w)), x * zoom, y * zoom);
  653.  
  654.         return;        /* there can only be one fatbits popup */
  655.     }
  656. }
  657.  
  658.  
  659. /*
  660. **  Construct the fatbits popup.
  661.  */
  662. void 
  663. FatbitsEdit(Widget paint)
  664. {
  665.     Widget shell, form, fat;
  666.     Widget button, box;
  667.     int i, zoom;
  668.     Colormap cmap;
  669.     Position x, y, lx, ly;
  670.     Dimension width = 48, height = 48;
  671.     LocalInfo *l;
  672.     static char *zoomList[] =
  673.     {
  674.     "zoomButton1",
  675.     "zoomButton2",
  676.     "zoomButton3",
  677.     "zoomButton4",
  678.     "zoomButton5",
  679.     };
  680.     XtTranslations trans =
  681.     XtParseTranslationTable("<BtnDown>,<BtnUp>: set() notify()");
  682.     Widget first = None;
  683.  
  684.     /* If a popup for this paint widget exists, raise it */
  685.     for (l = head; l != NULL && l->paint != paint; l = l->next);
  686.  
  687.     if (l != NULL) {
  688.     XMapRaised(XtDisplay(l->shell), XtWindow(l->shell));
  689.     return;
  690.     }
  691.     /* Construct a new fatbits popup */
  692.  
  693.     l = XtNew(LocalInfo);
  694.  
  695.     l->paint = paint;
  696.     l->next = head;
  697.     head = l;
  698.  
  699.     XtVaGetValues(paint, XtNcolormap, &cmap, XtNzoom, &l->zoom,
  700.           XtNdownX, &lx, XtNdownY, &ly, NULL);
  701.  
  702.     shell = XtVaCreatePopupShell("fatbits", topLevelShellWidgetClass,
  703.                  GetShell(paint), XtNcolormap, cmap,
  704.                  NULL);
  705.     l->shell = shell;
  706.  
  707.     PaletteAddUser(PaletteFind(shell, cmap), shell);
  708.     form = XtVaCreateManagedWidget("form", formWidgetClass, shell, NULL);
  709.  
  710.     box = XtVaCreateManagedWidget("fatBox", boxWidgetClass, form,
  711.               XtNbackgroundPixmap, GetBackgroundPixmap(form),
  712.                   NULL);
  713.     XtAddEventHandler(box, StructureNotifyMask, False,
  714.               (XtEventHandler) boxChanged, (XtPointer) l);
  715.  
  716.  
  717.     fat = XtVaCreateManagedWidget("paint", paintWidgetClass, box,
  718.                   XtNpaint, paint,
  719.                   XtNbottom, XtChainBottom,
  720.                   NULL);
  721.     l->view = fat;
  722.     XtVaGetValues(fat, XtNzoom, &zoom, NULL);
  723.  
  724.     XtVaSetValues(fat, XtNwidth, width * zoom, XtNheight, height * zoom, NULL);
  725.  
  726.     button = XtVaCreateManagedWidget("done", commandWidgetClass, form,
  727.                      XtNfromVert, box,
  728.                      XtNtop, XtChainBottom,
  729.                      XtNbottom, XtChainBottom,
  730.                      XtNleft, XtChainLeft,
  731.                      XtNright, XtChainLeft,
  732.                      NULL);
  733.  
  734.     XtAddCallback(button, XtNcallback, doneCallback, (XtPointer) l);
  735.  
  736.     ccpAddStdPopup(fat);
  737.  
  738.     first = None;
  739.     for (i = 0; i < XtNumber(zoomList); i++) {
  740.     button = XtVaCreateManagedWidget(zoomList[i],
  741.                      toggleWidgetClass, form,
  742.                      XtNfromHoriz, button,
  743.                      XtNfromVert, box,
  744.                      XtNtop, XtChainBottom,
  745.                      XtNbottom, XtChainBottom,
  746.                      XtNleft, XtChainRight,
  747.                      XtNright, XtChainRight,
  748.                      XtNradioGroup, first,
  749.                      XtNtranslations, trans,
  750.                      NULL);
  751.     first = button;
  752.     XtAddCallback(button, XtNcallback, buttonCallback, (XtPointer) l);
  753.  
  754.     if (i == XtNumber(zoomList) / 2) {
  755.         XtVaSetValues(button, XtNstate, True, NULL);
  756.     }
  757.     }
  758.  
  759.     XtAddCallback(shell, XtNdestroyCallback, destroyCallback, (XtPointer) l);
  760.     AddDestroyCallback(shell, (DestroyCallbackFunc) doneCallback, (XtPointer) l);
  761.  
  762.     XtAddCallback(fat, XtNdestroyCallback, FatCursorDestroyCallback, fat);
  763.  
  764.     XtPopup(shell, XtGrabNone);
  765.  
  766.     lx -= width / 2;
  767.     ly -= height / 2;
  768.     if (lx < 0)
  769.     lx = 0;
  770.     if (ly < 0)
  771.     ly = 0;
  772.  
  773.     x = lx - (PADDING + 2);
  774.     y = ly - (PADDING + 2);
  775.  
  776.     box = XtVaCreateManagedWidget("fatBox", boxWidgetClass, paint,
  777.                   XtNx, x,
  778.                   XtNy, y,
  779.                   XtNwidth, width + 2 * (PADDING + 1),
  780.                   XtNheight, height + 2 * (PADDING + 1),
  781.                   XtNborderWidth, 1,
  782.              XtNbackgroundPixmap, GetBackgroundPixmap(paint),
  783.                   NULL);
  784.  
  785.     l->cursor = box;
  786.  
  787.     XtAddEventHandler(box, ButtonPressMask, False,
  788.               (XtEventHandler) press, (XtPointer) l);
  789.     XtAddEventHandler(box, ButtonMotionMask, False,
  790.               (XtEventHandler) motion, (XtPointer) l);
  791.  
  792.     l->subpaint = XtVaCreateManagedWidget("fatPaint", paintWidgetClass, box,
  793.                       XtNpaint, paint,
  794.                       XtNzoom, PwZoomParent,
  795.                       XtNx, PADDING,
  796.                       XtNy, PADDING,
  797.                       XtNborderWidth, 1,
  798.                       XtNwidth, width,
  799.                       XtNheight, height,
  800.                       XtVaTypedArg, XtNcursor,
  801.                       XtRString, "fleur", sizeof(Cursor),
  802.                       NULL);
  803.  
  804.     XtAddCallback(l->view, XtNsizeChanged, sizeChanged, (XtPointer) l);
  805.  
  806.     XtVaGetValues(l->subpaint, XtNx, &l->spX,
  807.           XtNy, &l->spY,
  808.           XtNborderWidth, &l->spBW,
  809.           NULL);
  810.  
  811.     XtVaSetValues(l->subpaint, XtNzoomX, lx, XtNzoomY, ly, NULL);
  812.     XtVaSetValues(l->view, XtNzoomX, lx, XtNzoomY, ly, NULL);
  813.  
  814.     /*
  815.     **    Set the current operator
  816.      */
  817.     GraphicAdd(fat);
  818.     StateAddParent(shell, paint);
  819.  
  820.     return;
  821. }
  822.