home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / paintregion.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  49KB  |  1,853 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. /* Portions copyright 1995, 1995 Torsten Martinsen */
  17.  
  18. /* $Id: PaintRegion.c,v 1.6 1996/05/12 08:17:01 torsten Exp $ */
  19.  
  20. /*
  21. ** PaintRegion.c -- Hopefully all of the routines to get, set and  
  22. **   manipulate the selection region.
  23. **
  24. **  Not part of the "selection" operation, since this really
  25. **   need to know lots of hidden information (why?)
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include <X11/IntrinsicP.h>
  31. #include <X11/StringDefs.h>
  32. #include <X11/cursorfont.h>
  33. #include <X11/Xatom.h>
  34. #ifndef VMS
  35. #include <X11/Xaw/Grip.h>
  36. #else
  37. #include <X11Xaw/Grip.h>
  38. #endif
  39. #include "PaintP.h"
  40. #include "protocol.h"
  41.  
  42. #ifndef M_PI
  43. #define M_PI            3.14159265358979323846
  44. #endif
  45.  
  46. #define SHAPE
  47.  
  48. #ifdef SHAPE
  49. #ifndef VMS
  50. #include <X11/extensions/shape.h>
  51. #else
  52. #include "decw$include:shape.h"
  53. #endif /* VMS */
  54. #endif
  55.  
  56. static void regionExpose(Widget, PaintWidget, XEvent *, Boolean *);
  57.  
  58. #define regionRedraw(pw)  regionExpose(pw->paint.region.child, pw, NULL, NULL)
  59.  
  60. #define BoolStr(flg)    ((flg) ? "True" : "False")
  61.  
  62. #undef INTERACTIVE
  63.  
  64. /*
  65. **  Border Width of child widget
  66.  */
  67. #define BW    0
  68.  
  69. /*
  70. **  2x2 matrix stuff
  71. **
  72.  */
  73.  
  74. #define XFORM(x,y,mat,nx,ny)    nx = mat[0][0] * x + mat[0][1] * y; \
  75.                 ny = mat[1][0] * x + mat[1][1] * y
  76. #define COPY_MAT(s,d)    d[0][0] = s[0][0]; d[0][1] = s[0][1]; \
  77.             d[1][0] = s[1][0]; d[1][1] = s[1][1]
  78.  
  79. #define INVERT_MAT(mat, inv) do {            \
  80.         float _d = 1.0 / (mat[0][0] * mat[1][1] \
  81.                   - mat[0][1] * mat[1][0]);    \
  82.         (inv)[0][0] =  (mat)[1][1] * _d;    \
  83.         (inv)[1][1] =  (mat)[0][0] * _d;    \
  84.         (inv)[0][1] = -(mat)[0][1] * _d;    \
  85.         (inv)[1][0] = -(mat)[1][0] * _d;    \
  86.     } while (0)
  87.  
  88. #define ZERO(v)        (((v) > -1e-5) && ((v) < 1e-5))
  89.  
  90. #ifndef MIN
  91. #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
  92. #endif
  93. #ifndef MAX
  94. #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
  95. #endif
  96. #ifndef SIGN
  97. #define SIGN(a)        (((a) < 0) ? -1 : 1)
  98. #endif
  99. #ifndef ABS
  100. #define ABS(a)          ((a > 0) ? (a) : 0 - (a))
  101. #endif
  102.  
  103. #define MKMAT(pw) do {                            \
  104.         pwMatrix    m;                    \
  105.         m[0][0] = pw->paint.region.scaleX;            \
  106.         m[1][1] = pw->paint.region.scaleY;            \
  107.         m[0][1] = m[1][0] = 0.0;                \
  108.         mm(pw->paint.region.rotMat, m, pw->paint.region.mat);    \
  109.     } while (0)
  110.  
  111. static pwMatrix matIdentity =
  112. {
  113.     {1, 0},
  114.     {0, 1}
  115. };
  116.  
  117. static void 
  118. doCallbacks(PaintWidget pw, int flag)
  119. {
  120.     PaintWidget tpw = (pw->paint.paint == None) ?
  121.     pw : (PaintWidget) pw->paint.paint;
  122.     int i;
  123.  
  124.     XtCallCallbackList((Widget) tpw, tpw->paint.regionCalls, (XtPointer) flag);
  125.     for (i = 0; i < tpw->paint.paintChildrenSize; i++) {
  126.     PaintWidget p = (PaintWidget) tpw->paint.paintChildren[i];
  127.     XtCallCallbackList((Widget) p, p->paint.regionCalls, (XtPointer) flag);
  128.     }
  129. }
  130.  
  131. /*
  132.  * Multiply matrices a and b and store result in r.
  133.  */
  134. static void 
  135. mm(pwMatrix a, pwMatrix b, pwMatrix r)
  136. {
  137.     float t00, t10, t01, t11;
  138.  
  139.     t00 = a[0][0] * b[0][0] + a[0][1] * b[1][0];
  140.     t01 = a[0][0] * b[0][1] + a[0][1] * b[1][1];
  141.     t10 = a[1][0] * b[0][0] + a[1][1] * b[1][0];
  142.     t11 = a[1][0] * b[0][1] + a[1][1] * b[1][1];
  143.  
  144.     r[0][0] = t00;
  145.     r[1][0] = t10;
  146.     r[0][1] = t01;
  147.     r[1][1] = t11;
  148. }
  149.  
  150. /*
  151. **   PwRegionSet -- set the active image region
  152. **     add handles and other useful things
  153. **     if the pix == None, use the current paint info in rect
  154. **     else use the pixmap.
  155. **
  156.  */
  157. static void 
  158. buildSources(PaintWidget pw)
  159. {
  160.     if (pw->paint.region.sourceImg == NULL) {
  161.     pw->paint.region.sourceImg = XGetImage(XtDisplay(pw),
  162.                        pw->paint.region.source, 0, 0,
  163.                          pw->paint.region.orig.width,
  164.                pw->paint.region.orig.height, AllPlanes, ZPixmap);
  165.     }
  166.     if (pw->paint.region.mask == None)
  167.     return;
  168.  
  169.     if (pw->paint.region.maskImg == NULL) {
  170.     pw->paint.region.maskImg = XGetImage(XtDisplay(pw),
  171.                          pw->paint.region.mask, 0, 0,
  172.                          pw->paint.region.orig.width,
  173.                pw->paint.region.orig.height, AllPlanes, ZPixmap);
  174.     }
  175. }
  176.  
  177. static void 
  178. resizeImg(PaintWidget pw, pwMatrix inv, Pixmap * pix, XImage * pixSrc,
  179.       Pixmap * msk, XImage * mskSrc, Pixmap * shape)
  180. {
  181.     int width, height, depth;
  182.     int x, y;
  183.     XImage *pixDst, *mskDst, *shapeDst = NULL;
  184.     int sourceW, sourceH;
  185.     int ix, iy, fx, fy, cx, cy;
  186.     float dx, dy, sx, sy;
  187.  
  188.     if (pixSrc == NULL || pix == NULL)
  189.     return;
  190.     if (pw->paint.region.rect.width == 0 || pw->paint.region.rect.height == 0)
  191.     return;
  192.  
  193.     /*
  194.     **  Construct the dest pixmap.
  195.      */
  196.  
  197.     if (*pix != None)
  198.     XFreePixmap(XtDisplay(pw), *pix);
  199.     if (*msk != None && mskSrc != NULL)
  200.     XFreePixmap(XtDisplay(pw), *msk);
  201.  
  202.     depth = pixSrc->depth;
  203.  
  204.     width = pw->paint.region.rect.width / GET_ZOOM(pw);
  205.     height = pw->paint.region.rect.height / GET_ZOOM(pw);
  206.  
  207.     *pix = XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, depth);
  208.     pixDst = XCreateImage(XtDisplay(pw), pw->paint.visual,
  209.               depth, ZPixmap, 0, NULL, width, height, 32, 0);
  210.     pixDst->data = (char *) XtMalloc(height * pixDst->bytes_per_line);
  211.  
  212.     if (mskSrc != NULL) {
  213.     *msk = XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, 1);
  214.     mskDst = XCreateImage(XtDisplay(pw), pw->paint.visual,
  215.                   1, ZPixmap, 0, NULL, width, height, 32, 0);
  216.     mskDst->data = (char *) XtMalloc(height * mskDst->bytes_per_line);
  217. #ifdef SHAPE
  218.     if (shape != NULL) {
  219.         *shape = XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, 1);
  220.         shapeDst = XCreateImage(XtDisplay(pw), pw->paint.visual,
  221.                   1, ZPixmap, 0, NULL, width, height, 32, 0);
  222.         shapeDst->data = (char *) XtMalloc(height * shapeDst->bytes_per_line);
  223.     }
  224. #endif
  225.     }
  226.     cx = pw->paint.region.orig.width / 2;
  227.     cy = pw->paint.region.orig.height / 2;
  228.     fx = (int) (-width / 2);
  229.     fy = (int) (-height / 2);
  230.     sourceW = pixSrc->width;
  231.     sourceH = pixSrc->height;
  232.     for (y = 0, dy = fy; y < height; y++, dy++) {
  233.     for (x = 0, dx = fx; x < width; x++, dx++) {
  234.         XFORM(dx, dy, inv, sx, sy);
  235.         ix = (sx + cx);
  236.         iy = (sy + cy);
  237.         if (ix >= 0 && ix < sourceW && iy >= 0 && iy < sourceH) {
  238.         xxPutPixel(pixDst, x, y, xxGetPixel(pixSrc, ix, iy));
  239.         if (mskSrc != NULL)
  240.             XPutPixel(mskDst, x, y, XGetPixel(mskSrc, ix, iy));
  241. #ifdef SHAPE
  242.         if (shapeDst != NULL)
  243.             XPutPixel(shapeDst, x, y, True);
  244. #endif
  245.         } else if (mskSrc != NULL) {
  246.         XPutPixel(mskDst, x, y, False);
  247. #ifdef SHAPE
  248.         if (shapeDst != NULL)
  249.             XPutPixel(shapeDst, x, y, False);
  250. #endif
  251.         }
  252.     }
  253.     }
  254.  
  255.     XPutImage(XtDisplay(pw), *pix, pw->paint.tgc, pixDst,
  256.           0, 0, 0, 0, width, height);
  257.     XDestroyImage(pixDst);
  258.  
  259.     if (mskSrc != NULL) {
  260.     XPutImage(XtDisplay(pw), *msk, pw->paint.mgc, mskDst,
  261.           0, 0, 0, 0, width, height);
  262.     XDestroyImage(mskDst);
  263.     }
  264. #ifdef SHAPE
  265.     if (shapeDst != NULL) {
  266.     XPutImage(XtDisplay(pw), *shape, pw->paint.mgc, shapeDst,
  267.           0, 0, 0, 0, width, height);
  268.     XDestroyImage(shapeDst);
  269.     }
  270. #endif
  271. }
  272.  
  273. static void 
  274. regionCreateNotMask(PaintWidget pw)
  275. {
  276.     if (pw->paint.region.rect.width == 0 || pw->paint.region.rect.height == 0)
  277.     return;
  278.  
  279.     if (pw->paint.region.mask == None)
  280.     return;
  281.  
  282.     if (pw->paint.region.notMask != None)
  283.     XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
  284.  
  285.     pw->paint.region.notMask = XCreatePixmap(XtDisplay(pw), XtWindow(pw),
  286.        pw->paint.region.rect.width, pw->paint.region.rect.height, 1);
  287.     XSetFunction(XtDisplay(pw), pw->paint.mgc, GXcopyInverted);
  288.     XCopyArea(XtDisplay(pw), pw->paint.region.mask, pw->paint.region.notMask,
  289.           pw->paint.mgc, 0, 0,
  290.     pw->paint.region.rect.width, pw->paint.region.rect.height, 0, 0);
  291.     XSetFunction(XtDisplay(pw), pw->paint.mgc, GXcopy);
  292.  
  293.     XSetClipMask(XtDisplay(pw), pw->paint.region.bg_gc,
  294.          pw->paint.region.notMask);
  295.     XSetClipMask(XtDisplay(pw), pw->paint.region.fg_gc, pw->paint.region.mask);
  296. }
  297.  
  298. static void 
  299. createVtxPts(PaintWidget pw, float vtx[9][2], Boolean flag, Boolean useZoom)
  300. {
  301.     int zoom;
  302.     int i;
  303.     int x0, x1, y0, y1;
  304.     int width = pw->paint.region.orig.width;
  305.     int height = pw->paint.region.orig.height;
  306.  
  307.     if (useZoom)
  308.     zoom = GET_ZOOM(pw);
  309.     else
  310.     zoom = 1;
  311.  
  312.     x0 = (-width / 2);
  313.     x1 = (width + x0);
  314.     y0 = (-height / 2);
  315.     y1 = (height + y0);
  316.     x0 *= zoom;
  317.     x1 *= zoom;
  318.     y0 *= zoom;
  319.     y1 *= zoom;
  320.  
  321.     /*
  322.     **  Watch out, these are points 0,1, and _3__
  323.      */
  324.     XFORM(x0, y0, pw->paint.region.mat, vtx[0][0], vtx[0][1]);
  325.     XFORM(x1, y0, pw->paint.region.mat, vtx[1][0], vtx[1][1]);
  326.     XFORM(x0, y1, pw->paint.region.mat, vtx[3][0], vtx[3][1]);
  327.  
  328.     if (flag) {
  329.     XFORM(x1, y1, pw->paint.region.mat, vtx[2][0], vtx[2][1]);
  330.  
  331.     for (i = 0; i < 4; i++) {
  332.         vtx[i][0] += pw->paint.region.centerX * zoom;
  333.         vtx[i][1] += pw->paint.region.centerY * zoom;
  334.     }
  335.     } else {
  336.     /*
  337.     **  sort the points, so that point 0,0 is top left corner
  338.      */
  339.     if (vtx[0][0] > vtx[1][0]) {
  340.         float t = x0;
  341.         x0 = x1;
  342.         x1 = t;
  343.     }
  344.     if (vtx[0][1] > vtx[3][1]) {
  345.         float t = y0;
  346.         y0 = y1;
  347.         y1 = t;
  348.     }
  349.     XFORM(x0, y0, pw->paint.region.mat, vtx[0][0], vtx[0][1]);
  350.     XFORM(0, y0, pw->paint.region.mat, vtx[1][0], vtx[1][1]);
  351.     XFORM(x1, y0, pw->paint.region.mat, vtx[2][0], vtx[2][1]);
  352.  
  353.     XFORM(x0, 0, pw->paint.region.mat, vtx[3][0], vtx[3][1]);
  354.     XFORM(0, 0, pw->paint.region.mat, vtx[4][0], vtx[4][1]);
  355.     XFORM(x1, 0, pw->paint.region.mat, vtx[5][0], vtx[5][1]);
  356.  
  357.     XFORM(x0, y1, pw->paint.region.mat, vtx[6][0], vtx[6][1]);
  358.     XFORM(0, y1, pw->paint.region.mat, vtx[7][0], vtx[7][1]);
  359.     XFORM(x1, y1, pw->paint.region.mat, vtx[8][0], vtx[8][1]);
  360.     }
  361. }
  362.  
  363. static void 
  364. doResize(PaintWidget pw)
  365. {
  366.     pwMatrix inv;
  367.     Pixmap shape, *shp = &shape;
  368.  
  369.     buildSources(pw);
  370.  
  371.     /*
  372.     **  First find out the bounding extent of the transformed
  373.     **   area, then scale it to fit inside of the "region box"
  374.      */
  375.  
  376.     if (pw->paint.region.maskImg == NULL) {
  377.     Boolean needMask = False;
  378.     float vtx[9][2];
  379.     float minX, minY, maxX, maxY;
  380.     int x, cmin, cmax;
  381.  
  382.     createVtxPts(pw, vtx, True, False);
  383.  
  384.     minX = MIN(vtx[0][0], MIN(vtx[1][0], MIN(vtx[2][0], vtx[3][0])));
  385.     minY = MIN(vtx[0][1], MIN(vtx[1][1], MIN(vtx[2][1], vtx[3][1])));
  386.     maxX = MAX(vtx[0][0], MAX(vtx[1][0], MAX(vtx[2][0], vtx[3][0])));
  387.     maxY = MAX(vtx[0][1], MAX(vtx[1][1], MAX(vtx[2][1], vtx[3][1])));
  388.  
  389.     /*
  390.     **  After computing min, max see if there are points
  391.     **   on all vertices, if so then set the correct return code
  392.      */
  393.     for (cmin = cmax = x = 0; x < 4; x++) {
  394.         if ((int) vtx[x][0] == (int) minX)
  395.         cmin++;
  396.         else if ((int) vtx[x][0] == (int) maxX)
  397.         cmax++;
  398.     }
  399.     needMask |= (cmin != 2 || cmax != 2);
  400.     for (cmin = cmax = x = 0; x < 4; x++) {
  401.         if ((int) vtx[x][1] == (int) minY)
  402.         cmin++;
  403.         else if ((int) vtx[x][1] == (int) maxY)
  404.         cmax++;
  405.     }
  406.     needMask |= (cmin != 2 || cmax != 2);
  407.  
  408.     if (needMask) {
  409.         Pixmap mask;
  410.         GC mgc;
  411.  
  412.         /*
  413.         **  If the image we just transformed needs a mask
  414.         **  and one doesn't exist, construct one.
  415.          */
  416.         mask = pw->paint.region.mask =
  417.         XCreatePixmap(XtDisplay(pw), XtWindow(pw),
  418.                   pw->paint.region.orig.width,
  419.                   pw->paint.region.orig.height, 1);
  420.         mgc = GET_MGC(pw, mask);
  421.         XSetFunction(XtDisplay(pw), mgc, GXset);
  422.         XFillRectangle(XtDisplay(pw), mask, mgc, 0, 0,
  423.                pw->paint.region.orig.width,
  424.                pw->paint.region.orig.height);
  425.         XSetFunction(XtDisplay(pw), mgc, GXcopy);
  426.  
  427.         buildSources(pw);
  428.  
  429.         if (pw->paint.region.fg_gc == None) {
  430.         pw->paint.region.fg_gc = XCreateGC(XtDisplay(pw), XtWindow(pw),
  431.                            0, 0);
  432.         pw->paint.region.bg_gc = XCreateGC(XtDisplay(pw), XtWindow(pw),
  433.                            0, 0);
  434.         }
  435.     }
  436.     }
  437.     INVERT_MAT(pw->paint.region.mat, inv);
  438. #ifdef SHAPE
  439.     if (pw->paint.region.maskImg == NULL || GET_ZOOM(pw) != 1)
  440.     shp = NULL;
  441. #else
  442.     shp = NULL;
  443. #endif
  444.     resizeImg(pw, inv, &pw->paint.region.source, pw->paint.region.sourceImg,
  445.           &pw->paint.region.mask, pw->paint.region.maskImg, shp);
  446.     regionCreateNotMask(pw);
  447.  
  448. #ifdef SHAPE
  449.     if (shp != NULL) {
  450.     XShapeCombineMask(XtDisplay(pw), XtWindow(pw->paint.region.child),
  451.               ShapeBounding, 0, 0, shape, ShapeSet);
  452.     XFreePixmap(XtDisplay(pw), shape);
  453.     }
  454. #endif
  455.  
  456.     pw->paint.region.needResize = False;
  457. }
  458.  
  459. static void 
  460. drawRegionBox(PaintWidget pw, Boolean flag)
  461. {
  462.     static XPoint xvtxLast[5];
  463.     XPoint xvtx[5];
  464.     float vtx[9][2];
  465.     Window window = XtWindow(pw);
  466.     int i;
  467.  
  468.     createVtxPts(pw, vtx, True, True);
  469.  
  470.     xvtx[0].x = vtx[0][0];
  471.     xvtx[0].y = vtx[0][1];
  472.     xvtx[1].x = vtx[1][0];
  473.     xvtx[1].y = vtx[1][1];
  474.     xvtx[2].x = vtx[2][0];
  475.     xvtx[2].y = vtx[2][1];
  476.     xvtx[3].x = vtx[3][0];
  477.     xvtx[3].y = vtx[3][1];
  478.     xvtx[4].x = vtx[0][0];
  479.     xvtx[4].y = vtx[0][1];
  480.  
  481.     for (i = 0; i < 5; i++) {
  482.     xvtx[i].x += pw->paint.region.child->core.x;
  483.     xvtx[i].y += pw->paint.region.child->core.y;
  484.     }
  485.  
  486.     if (pw->paint.region.isDrawn) {
  487.     XDrawLines(XtDisplay(pw), window, pw->paint.xgc, xvtxLast, 5,
  488.            CoordModeOrigin);
  489.     pw->paint.region.isDrawn = False;
  490.     }
  491.     if (flag) {
  492.     XDrawLines(XtDisplay(pw), window, pw->paint.xgc, xvtx, 5, CoordModeOrigin);
  493.     memcpy(xvtxLast, xvtx, sizeof(xvtxLast));
  494.     pw->paint.region.isDrawn = True;
  495.     }
  496. }
  497.  
  498. /*
  499. **
  500.  */
  501.  
  502. static void 
  503. regionResizeWindow(PaintWidget pw, Boolean sameCenter)
  504. {
  505.     int zoom = GET_ZOOM(pw);
  506.     int minX, minY, maxX, maxY;
  507.     int width, height, dx, dy, nx, ny;
  508.     int newX, newY;
  509.     int i;
  510.     float vtx[9][2];
  511.  
  512. #ifndef INTERACTIVE
  513.     if (pw->paint.region.isTracking)
  514.     return;
  515. #endif
  516.  
  517.     createVtxPts(pw, vtx, False, False);
  518.  
  519.     minX = MIN(vtx[0][0], vtx[6][0]);
  520.     maxX = MAX(vtx[2][0], vtx[8][0]);
  521.     minY = MIN(vtx[0][1], vtx[2][1]);
  522.     maxY = MAX(vtx[6][1], vtx[8][1]);
  523.  
  524.     width = maxX - minX + 0.5;
  525.     height = maxY - minY + 0.5;
  526.  
  527.     newX = pw->paint.region.centerX - (width / 2);
  528.     newY = pw->paint.region.centerY - (height / 2);
  529.  
  530.     newX += pw->paint.region.rect.x;
  531.     newY += pw->paint.region.rect.y;
  532.     if (!sameCenter) {
  533.     pw->paint.region.centerX = width / 2;
  534.     pw->paint.region.centerY = height / 2;
  535.     } else {
  536.     pw->paint.region.centerX = width / 2;
  537.     pw->paint.region.centerY = height / 2;
  538.     }
  539.  
  540.     if ((width *= zoom) < 10)
  541.     width = 10;
  542.     if ((height *= zoom) < 10)
  543.     height = 10;
  544.     XtResizeWidget(pw->paint.region.child, width, height, BW);
  545.     nx = (newX - pw->paint.zoomX) * zoom;
  546.     ny = (newY - pw->paint.zoomY) * zoom;
  547.     XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
  548.  
  549.     pw->paint.region.rect.x = newX;
  550.     pw->paint.region.rect.y = newY;
  551.     pw->paint.region.rect.width = width;
  552.     pw->paint.region.rect.height = height;
  553.  
  554.     /*
  555.     **  Now place all the grips.
  556.      */
  557.     createVtxPts(pw, vtx, False, True);
  558.     width = pw->paint.region.grip[0]->core.width;
  559.     height = pw->paint.region.grip[0]->core.height;
  560.     dx = pw->paint.region.centerX * zoom - width / 2;
  561.     dy = pw->paint.region.centerY * zoom - height / 2;
  562.     for (i = 0; i < 9; i++) {
  563.     int x, y;
  564.  
  565.     if (i == 4)
  566.         continue;
  567.  
  568.     x = vtx[i][0] + dx;
  569.     y = vtx[i][1] + dy;
  570.  
  571.     if (x < 0)
  572.         x = 0;
  573.     if (y < 0)
  574.         y = 0;
  575.     if (x + width > pw->paint.region.rect.width)
  576.         x = pw->paint.region.rect.width - width;
  577.     if (y + height > pw->paint.region.rect.height)
  578.         y = pw->paint.region.rect.height - height;
  579.  
  580.     XtMoveWidget(pw->paint.region.grip[i], x, y);
  581.     }
  582. }
  583.  
  584. /*
  585. **
  586.  */
  587.  
  588. static void 
  589. moveGrips(PaintWidget pw)
  590. {
  591.     int width, height;
  592.     int i, gx, gy;
  593.     Dimension w, h;
  594.     Widget widget = pw->paint.region.grip[0];
  595.  
  596.     w = widget->core.width;
  597.     h = widget->core.height;
  598.     width = widget->core.parent->core.width;
  599.     height = widget->core.parent->core.height;
  600.  
  601.     for (i = 0; i < 9; i++) {
  602.     if (i == 4)
  603.         continue;
  604.  
  605.     switch (i % 3) {
  606.     case 0:
  607.         gx = 0;
  608.         break;
  609.     case 1:
  610.         gx = width / 2 - w / 2;
  611.         break;
  612.     case 2:
  613.         gx = width - w;
  614.         break;
  615.     }
  616.     switch (i / 3) {
  617.     case 0:
  618.         gy = 0;
  619.         break;
  620.     case 1:
  621.         gy = height / 2 - h / 2;
  622.         break;
  623.     case 2:
  624.         gy = height - h;
  625.         break;
  626.     }
  627.  
  628.     XtMoveWidget(pw->paint.region.grip[i], gx, gy);
  629.     }
  630. }
  631.  
  632. static void 
  633. gripPress(Widget w, PaintWidget pw, XButtonEvent * event, Boolean * junk)
  634. {
  635.     static int fixedPoint[] =
  636.     {8, 8, 6, 8, -1, 6, 2, 2, 0};
  637.     float vtx[9][2], fvtx[9][2];
  638.     float x0, x1, x2, y0, y1, y2, t1, t2, l;
  639.     int index, i;
  640.  
  641.     pw->paint.region.offX = event->x;
  642.     pw->paint.region.offY = event->y;
  643.     pw->paint.region.baseX = event->x_root - w->core.x;
  644.     pw->paint.region.baseY = event->y_root - w->core.y;
  645.  
  646.     pw->paint.region.isTracking = True;
  647.  
  648.     /*
  649.     **  Compute which grip was grabbed, to determine constrain line.
  650.      */
  651.     for (index = 0; index < 9 && pw->paint.region.grip[index] != w; index++);
  652.  
  653.     createVtxPts(pw, vtx, False, False);
  654.     createVtxPts(pw, fvtx, True, False);
  655.  
  656.     x0 = vtx[0][0];
  657.     y0 = vtx[0][1];
  658.     x1 = vtx[2][0];
  659.     y1 = vtx[2][1];
  660.     x2 = vtx[6][0];
  661.     y2 = vtx[6][1];
  662.  
  663.     pw->paint.region.lineBase[0] = 0;
  664.     pw->paint.region.lineBase[1] = 0;
  665.  
  666.     t1 = x1 - x0;
  667.     t2 = y1 - y0;
  668.     l = sqrt(t1 * t1 + t2 * t2);
  669.     pw->paint.region.lineDelta[0] = t1 / l;
  670.     pw->paint.region.lineDelta[1] = t2 / l;
  671.  
  672.     t1 = x2 - x0;
  673.     t2 = y2 - y0;
  674.     l = sqrt(t1 * t1 + t2 * t2);
  675.     pw->paint.region.lineDelta[2] = t1 / l;
  676.     pw->paint.region.lineDelta[3] = t2 / l;
  677.  
  678.     pw->paint.region.startScaleX = pw->paint.region.scaleX;
  679.     pw->paint.region.startScaleY = pw->paint.region.scaleY;
  680.  
  681.     /*
  682.     **  Now compute which corner of the 4 cornered box doesn't move
  683.     **    as the object is resized.
  684.      */
  685.     for (i = 0; i < 4; i++) {
  686.     float fx = vtx[fixedPoint[index]][0];
  687.     float fy = vtx[fixedPoint[index]][1];
  688.     float px = fvtx[i][0] - pw->paint.region.centerX;
  689.     float py = fvtx[i][1] - pw->paint.region.centerY;
  690.  
  691.     if (ZERO(fx - px) && ZERO(fy - py))
  692.         break;
  693.     }
  694.     pw->paint.region.fixedPoint = i;
  695. }
  696.  
  697. static void 
  698. regionButtonPress(Widget w, PaintWidget pw, XButtonEvent * event, Boolean * junk)
  699. {
  700.     pw->paint.region.isRotate = event->button == Button2;
  701.  
  702.     pw->paint.region.offX = event->x;
  703.     pw->paint.region.offY = event->y;
  704.     pw->paint.region.baseX = event->x_root - w->core.x;
  705.     pw->paint.region.baseY = event->y_root - w->core.y;
  706.  
  707.     pw->paint.region.lastX = event->x_root;
  708.     pw->paint.region.lastY = event->y_root;
  709.  
  710.     if (pw->paint.region.isRotate) {
  711.     XDefineCursor(XtDisplay(w), XtWindow(pw->paint.region.child),
  712.               XCreateFontCursor(XtDisplay(w), XC_exchange));
  713.     pw->paint.region.lastAngle = 0.0;
  714.     }
  715.     /*
  716.     **  Only draw the interactive box when we are rotating.
  717.      */
  718.     pw->paint.region.isTracking = pw->paint.region.isRotate;
  719. }
  720. static void 
  721. gripRelease(Widget w, PaintWidget pw, XButtonEvent * event, Boolean * junk)
  722. {
  723.     pw->paint.region.isTracking = False;
  724.     drawRegionBox(pw, False);
  725. #ifndef INTERACTIVE
  726.     if (pw->paint.region.needResize) {
  727.     regionResizeWindow(pw, False);
  728.     regionRedraw(pw);
  729.     }
  730. #endif
  731. }
  732. static void 
  733. regionButtonRelease(Widget w, PaintWidget pw, XButtonEvent * event,
  734.             Boolean * junk)
  735. {
  736.     pw->paint.region.isTracking = False;
  737.     drawRegionBox(pw, False);
  738.  
  739.     if (!pw->paint.region.isRotate)
  740.     return;
  741.  
  742. #ifndef INTERACTIVE
  743.     if (pw->paint.region.needResize) {
  744.     regionResizeWindow(pw, False);
  745.     regionRedraw(pw);
  746.     }
  747. #endif
  748.  
  749.     XDefineCursor(XtDisplay(w), XtWindow(pw->paint.region.child),
  750.           XCreateFontCursor(XtDisplay(w), XC_fleur));
  751. }
  752. static void 
  753. regionGrab(Widget w, PaintWidget pw, XMotionEvent * event, Boolean * junk)
  754. {
  755.     int dx, dy, nx, ny;
  756.  
  757.     while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w),
  758.                   MotionNotify, (XEvent *) event));
  759.  
  760.     PwRegionTear((Widget) pw);
  761.  
  762.     if (pw->paint.region.isRotate) {
  763.     double da, na;
  764.     pwMatrix m;
  765.  
  766.     dx = event->x - pw->paint.region.rect.width / 2;
  767.     dy = event->y - pw->paint.region.rect.height / 2;
  768.     na = atan2((double) dy, (double) dx);
  769.     /*
  770.      * If Shift is pressed, constrain rotation to multiples of 15 degrees.
  771.      */
  772.     if (event->state & ShiftMask)
  773.         na = ((int) (na / (15.0 / 180.0 * M_PI))) * (15.0 / 180.0 * M_PI);
  774.     da = na - pw->paint.region.lastAngle;
  775.     pw->paint.region.lastAngle = na;
  776.  
  777.     m[0][0] = cos(da);
  778.     m[0][1] = -sin(da);
  779.     m[1][0] = sin(da);
  780.     m[1][1] = cos(da);
  781.  
  782.     PwRegionAppendMatrix((Widget) pw, m);
  783.     } else {
  784.     int zoom = GET_ZOOM(pw);
  785.  
  786.     nx = event->x_root - pw->paint.region.baseX;
  787.     ny = event->y_root - pw->paint.region.baseY;
  788.  
  789.     /*
  790.      * If Shift is pressed, constrain movement to horizontal or vertical
  791.      */
  792.     if (event->state & ShiftMask)
  793.         if (ABS(event->x_root - pw->paint.region.lastX) >
  794.         ABS(event->y_root - pw->paint.region.lastY))
  795.         ny = pw->paint.region.lastY - pw->paint.region.baseY;
  796.         else
  797.         nx = pw->paint.region.lastX - pw->paint.region.baseX;
  798.  
  799.     dx = (nx - w->core.x) / zoom;
  800.     dy = (ny - w->core.y) / zoom;
  801.  
  802.     if (dx == 0 && dy == 0)
  803.         return;
  804.  
  805.  
  806.     pw->paint.region.rect.x += dx;
  807.     pw->paint.region.rect.y += dy;
  808.  
  809.     nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
  810.     ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
  811.  
  812.     XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
  813.     }
  814. }
  815.  
  816. static void 
  817. regionExpose(Widget w, PaintWidget pw, XEvent * event, Boolean * junk)
  818. {
  819.     XImage *xim = NULL;
  820.     XRectangle rect, nrect;
  821.     int isExpose;
  822.     int zoom = GET_ZOOM(pw);
  823.  
  824.     if (!pw->paint.region.isVisible)
  825.     return;
  826.  
  827.     if (event == NULL) {
  828.     isExpose = True;
  829.     rect.x = 0;
  830.     rect.y = 0;
  831.     rect.width = w->core.width;
  832.     rect.height = w->core.height;
  833.     } else if (event->xany.type == Expose) {
  834.     rect.x = event->xexpose.x;
  835.     rect.y = event->xexpose.y;
  836.     rect.width = event->xexpose.width;
  837.     rect.height = event->xexpose.height;
  838.     isExpose = True;
  839.     } else if (event->xany.type == ConfigureNotify) {
  840.     isExpose = False;
  841.     rect.x = 0;
  842.     rect.y = 0;
  843.     rect.width = w->core.width;
  844.     rect.height = w->core.height;
  845.     } else {
  846.     return;
  847.     }
  848.  
  849. #ifndef INTERACTIVE
  850.     if (pw->paint.region.isTracking) {
  851.     drawRegionBox(pw, True);
  852.     return;
  853.     }
  854. #endif
  855.     if (pw->paint.region.needResize)
  856.     doResize(pw);
  857.  
  858.     if (zoom != 1) {
  859.     int width, height;
  860.     int pixW, pixH;
  861.  
  862.     nrect.x = rect.x / zoom;
  863.     nrect.y = rect.y / zoom;
  864.     width = (rect.width + zoom - 1) / zoom;
  865.     height = (rect.height + zoom - 1) / zoom;
  866.     /*
  867.     **  It is possible for this to happen, when resizes and 
  868.     **    redraws are slightly out of sync.
  869.      */
  870.     pixW = pw->paint.region.rect.width / zoom;
  871.     pixH = pw->paint.region.rect.height / zoom;
  872.     if (width + nrect.x > pixW)
  873.         width = pixW - nrect.x;
  874.     if (height + nrect.y > pixH)
  875.         height = pixH - nrect.y;
  876.     if (width <= 0 || height <= 0)
  877.         return;
  878.     nrect.width = width;
  879.     nrect.height = height;
  880.     }
  881.     if (isExpose) {
  882.     if (zoom == 1) {
  883.         XCopyArea(XtDisplay(w), pw->paint.region.source, XtWindow(w),
  884.               pw->paint.region.fg_gc == None ?
  885.               pw->paint.tgc : pw->paint.region.fg_gc,
  886.         rect.x, rect.y, rect.width, rect.height, rect.x, rect.y);
  887.     } else {
  888.         XImage *src, *msk = NULL;
  889.         XRectangle tr;
  890.  
  891.         tr = nrect;
  892.         tr.x = 0;
  893.         tr.y = 0;
  894.  
  895.         src = XGetImage(XtDisplay(pw), pw->paint.region.source,
  896.                 nrect.x, nrect.y, nrect.width, nrect.height,
  897.                 AllPlanes, ZPixmap);
  898.         if (pw->paint.region.mask != None)
  899.         msk = XGetImage(XtDisplay(pw), pw->paint.region.mask,
  900.                  nrect.x, nrect.y, nrect.width, nrect.height,
  901.                 AllPlanes, ZPixmap);
  902.         _PwZoomDraw(pw, w, pw->paint.tgc, src, msk,
  903.             False, nrect.x, nrect.y, zoom, &tr);
  904.         XDestroyImage(src);
  905.         if (msk != NULL)
  906.         XDestroyImage(msk);
  907.     }
  908.     }
  909.     /*
  910.     **  XXX -- This should merge, and do fun things.. but.
  911.      */
  912.     if (isExpose && (event != NULL && event->xexpose.count != 0))
  913.     return;
  914.  
  915.     if (pw->paint.region.mask != None) {
  916.     int x = w->core.x + w->core.border_width;
  917.     int y = w->core.y + w->core.border_width;
  918.  
  919.     /*
  920.     **  Copy in the background picture
  921.      */
  922.     if (GET_ZOOM(pw) != 1) {
  923.         XRectangle tr;
  924.         XImage *nmsk;
  925.         int dx = 0, dy = 0;
  926.         PaintWidget tpw = (pw->paint.paint == None) ?
  927.         pw : (PaintWidget) pw->paint.paint;
  928.         int width, height;
  929.  
  930.         tr.x = (nrect.x + x) / zoom + pw->paint.zoomX;
  931.         tr.y = (nrect.y + y) / zoom + pw->paint.zoomY;
  932.         width = nrect.width;
  933.         height = nrect.height;
  934.  
  935.         /*
  936.         **  We could use PwGetImage, but it returns
  937.         **    the original image, not the sub-region
  938.          */
  939.         if (tr.x < 0) {
  940.         width += tr.x;
  941.         dx = -tr.x;
  942.         tr.x = 0;
  943.         }
  944.         if (tr.y < 0) {
  945.         height += tr.y;
  946.         dy = -tr.y;
  947.         tr.y = 0;
  948.         }
  949.         if (tr.x + width > tpw->paint.drawWidth)
  950.         width = tpw->paint.drawWidth - tr.x;
  951.         if (tr.y + height > tpw->paint.drawHeight)
  952.         height = tpw->paint.drawHeight - tr.y;
  953.         if (width > 0 && height > 0) {
  954.         tr.width = width;
  955.         tr.height = height;
  956.         xim = XGetImage(XtDisplay(w), GET_PIXMAP(pw),
  957.                 tr.x, tr.y, tr.width, tr.height,
  958.                 AllPlanes, ZPixmap);
  959.         tr.x = tr.y = 0;
  960.         nmsk = XGetImage(XtDisplay(pw), pw->paint.region.notMask,
  961.              nrect.x + dx, nrect.y + dy, tr.width, tr.height,
  962.                  AllPlanes, ZPixmap);
  963.  
  964.         _PwZoomDraw(pw, w, pw->paint.tgc, xim, nmsk, False,
  965.                 dx, dy, zoom, &tr);
  966.         XDestroyImage(nmsk);
  967.         XDestroyImage(xim);
  968.         }
  969.     } else {
  970.         XCopyArea(XtDisplay(w), GET_PIXMAP(pw), XtWindow(w),
  971.               pw->paint.region.bg_gc,
  972.               x, y, w->core.width, w->core.height, 0, 0);
  973.     }
  974.     }
  975. }
  976. static void 
  977. regionMove(Widget w, PaintWidget pw, XEvent * event, Boolean * junk)
  978. {
  979.     if (pw->paint.region.mask == None)
  980.     return;
  981.     /*
  982.     **  For some reason, I had to generate an extra function.. 
  983.      */
  984.     regionExpose(w, pw, event, junk);
  985. }
  986.  
  987.  
  988. static void 
  989. regionSetGripCursors(PaintWidget pw)
  990. {
  991.     static int cursors[9] =
  992.     {
  993.     XC_top_left_corner,
  994.     XC_top_side,
  995.     XC_top_right_corner,
  996.     XC_left_side,
  997.     0,
  998.     XC_right_side,
  999.     XC_bottom_left_corner,
  1000.     XC_bottom_side,
  1001.     XC_bottom_right_corner
  1002.     };
  1003.     static int list[9] =
  1004.     {None, None, None, None, None, None, None, None, None};
  1005.     int i;
  1006.  
  1007.     if (list[0] == None) {
  1008.     for (i = 0; i < 9; i++) {
  1009.         if (i != 4)
  1010.         list[i] = XCreateFontCursor(XtDisplay(pw), cursors[i]);
  1011.     }
  1012.     }
  1013.     for (i = 0; i < 9; i++)
  1014.     if (i != 4)
  1015.         XDefineCursor(XtDisplay(pw), XtWindow(pw->paint.region.grip[i]), list[i]);
  1016. }
  1017.  
  1018. static void 
  1019. gripGrab(Widget w, PaintWidget pw, XMotionEvent * event, Boolean * junk)
  1020. {
  1021.     static Boolean isLeftEdge[] =
  1022.     {True, False, False,
  1023.      True, False, False,
  1024.      True, False, False};
  1025.     static Boolean isTopEdge[] =
  1026.     {True, True, True,
  1027.      False, False, False,
  1028.      False, False, False};
  1029.     static Boolean isMiddle[] =
  1030.     {False, True, False,
  1031.      True, False, True,
  1032.      False, True, False};
  1033.     Boolean sameScale;
  1034.     int index, i, fp;
  1035.     int zoom = GET_ZOOM(pw);
  1036.     float v[2];
  1037.     int width, height;
  1038.     float ovtx[9][2], nvtx[9][2];
  1039.     float dx, dy;
  1040.  
  1041.     for (index = 0; index < 9 && pw->paint.region.grip[index] != w; index++);
  1042.  
  1043.     /*
  1044.     **  Find the intersection point
  1045.      */
  1046.     for (i = 0; i < 2; i++) {
  1047.     float x0 = pw->paint.region.lineBase[0];
  1048.     float y0 = pw->paint.region.lineBase[1];
  1049.     float xm = event->x;
  1050.     float ym = event->y;
  1051.  
  1052.     dx = pw->paint.region.lineDelta[0 + i * 2];
  1053.     dy = pw->paint.region.lineDelta[1 + i * 2];
  1054.     v[i] = dx * (xm - x0) - dy * (y0 - ym);
  1055.     }
  1056.  
  1057.     if (pw->paint.region.startScaleX < 0)
  1058.     v[0] = -v[0];
  1059.     if (pw->paint.region.startScaleY < 0)
  1060.     v[1] = -v[1];
  1061.     if (isLeftEdge[index])
  1062.     v[0] = -v[0];
  1063.     if (isTopEdge[index])
  1064.     v[1] = -v[1];
  1065.  
  1066.     v[0] /= (float) zoom;
  1067.     v[1] /= (float) zoom;
  1068.  
  1069.     PwRegionTear((Widget) pw);
  1070.  
  1071.     sameScale = False;
  1072.     if (isMiddle[index] || (event->state & ShiftMask) != 0) {
  1073.     /*
  1074.     **  Apply the constraint
  1075.      */
  1076.     if (index == 1 || index == 7)
  1077.         v[0] = 0;
  1078.     else if (index == 3 || index == 5)
  1079.         v[1] = 0;
  1080.     else
  1081.         sameScale = True;
  1082.     }
  1083.     width = pw->paint.region.startScaleX * pw->paint.region.orig.width;
  1084.     height = pw->paint.region.startScaleY * pw->paint.region.orig.height;
  1085.  
  1086.     createVtxPts(pw, ovtx, True, False);
  1087.  
  1088.     pw->paint.region.scaleX =
  1089.     (float) ((int) (width + v[0])) / pw->paint.region.orig.width;
  1090.     pw->paint.region.scaleY =
  1091.     (float) ((int) (height + v[1])) / pw->paint.region.orig.height;
  1092.  
  1093.     if (sameScale) {
  1094.     float sx = ABS(pw->paint.region.scaleX);
  1095.     float sy = ABS(pw->paint.region.scaleY);
  1096.  
  1097.     sx = MIN(sx, sy);
  1098.  
  1099.     pw->paint.region.scaleX = SIGN(pw->paint.region.scaleX) * sx;
  1100.     pw->paint.region.scaleY = SIGN(pw->paint.region.scaleY) * sx;
  1101.     }
  1102.     MKMAT(pw);
  1103.     createVtxPts(pw, nvtx, True, False);
  1104.  
  1105.     fp = pw->paint.region.fixedPoint;
  1106.     dx = ovtx[fp][0] - nvtx[fp][0];
  1107.     dy = ovtx[fp][1] - nvtx[fp][1];
  1108.  
  1109.     pw->paint.region.centerX += dx;
  1110.     pw->paint.region.centerY += dy;
  1111.  
  1112.     pw->paint.region.needResize = True;
  1113.     regionRedraw(pw);
  1114. }
  1115.  
  1116. /*
  1117. **
  1118. **
  1119.  */
  1120. static void 
  1121. writeRegion(PaintWidget pw)
  1122. {
  1123.     GC gc;
  1124.     Pixmap pix, src;
  1125.     XRectangle nr;
  1126.     int zoom = GET_ZOOM(pw);
  1127.  
  1128.     if (!pw->paint.region.isVisible)
  1129.     return;
  1130.     /*
  1131.     **  No need to write it, it's still on the drawable.
  1132.      */
  1133.     if (pw->paint.region.isAttached)
  1134.     return;
  1135.  
  1136.     nr.x = pw->paint.region.rect.x;
  1137.     nr.y = pw->paint.region.rect.y;
  1138.     nr.width = pw->paint.region.rect.width / zoom;
  1139.     nr.height = pw->paint.region.rect.height / zoom;
  1140.  
  1141.     /*
  1142.     **  If we've already modified the background (aka ripped the
  1143.     **    image up)  then don't get a new undo buffer.
  1144.     **    The second case of the if is if you've done an undo inbetween.
  1145.      */
  1146.     if (pw->paint.region.undoPixmap == None ||
  1147.     pw->paint.region.undoPixmap != GET_PIXMAP(pw))
  1148.     pix = PwUndoStart((Widget) pw, &nr);
  1149.     else
  1150.     pix = pw->paint.region.undoPixmap;
  1151.  
  1152.     PwUndoAddRectangle((Widget) pw, &nr);
  1153.  
  1154.     if (pw->paint.region.fg_gc != None) {
  1155.     gc = pw->paint.region.fg_gc;
  1156.     XSetClipOrigin(XtDisplay(pw), gc, nr.x, nr.y);
  1157.     } else {
  1158.     gc = pw->paint.tgc;
  1159.     }
  1160.  
  1161.     if (pw->paint.region.proc != NULL) {
  1162.     XImage *sim = pw->paint.region.sourceImg;
  1163.     Boolean made = False;
  1164.  
  1165.     if (sim == NULL) {
  1166.         sim = XGetImage(XtDisplay(pw),
  1167.                 pw->paint.region.source, 0, 0,
  1168.                 pw->paint.region.orig.width,
  1169.                pw->paint.region.orig.height, AllPlanes, ZPixmap);
  1170.         made = True;
  1171.     }
  1172.     src = (*pw->paint.region.proc) ((Widget) pw, sim, pw->paint.region.mat);
  1173.     if (made)
  1174.         XDestroyImage(sim);
  1175.     } else {
  1176.     src = pw->paint.region.source;
  1177.     }
  1178.  
  1179.     XCopyArea(XtDisplay(pw), src, pix, gc,
  1180.           0, 0,
  1181.           nr.width, nr.height,
  1182.           nr.x, nr.y);
  1183.  
  1184.     if (pw->paint.region.fg_gc != None)
  1185.     XSetClipOrigin(XtDisplay(pw), gc, 0, 0);
  1186.  
  1187.     PwUpdate((Widget) pw, &nr, False);
  1188. }
  1189.  
  1190. /*
  1191. **  Called when the parent widgets zoom factor changes
  1192.  */
  1193. static void 
  1194. zoomValueChanged(Widget w, XtPointer junk1, XtPointer junk2)
  1195. {
  1196.     PaintWidget pw = (PaintWidget) w;
  1197.     int zoom = GET_ZOOM(pw);
  1198.     int nx, ny;
  1199.     int nw, nh;
  1200.  
  1201.     if (zoom == pw->paint.region.curZoom)
  1202.     return;
  1203.  
  1204.     if (!pw->paint.region.isVisible)
  1205.     return;
  1206.  
  1207.     nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
  1208.     ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
  1209.     nw = (pw->paint.region.rect.width / pw->paint.region.curZoom) * zoom;
  1210.     pw->paint.region.rect.width = nw;
  1211.     nh = (pw->paint.region.rect.height / pw->paint.region.curZoom) * zoom;
  1212.     pw->paint.region.rect.height = nh;
  1213.     pw->paint.region.curZoom = zoom;
  1214.  
  1215.     XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
  1216.     XtResizeWidget(pw->paint.region.child, nw, nh, BW);
  1217.  
  1218.     pw->paint.region.needResize = True;
  1219.     moveGrips(pw);
  1220.     regionRedraw(pw);
  1221. }
  1222.  
  1223. void 
  1224. pwRegionZoomPosChanged(PaintWidget pw)
  1225. {
  1226.     int nx, ny;
  1227.     int zoom;
  1228.  
  1229.     if (!pw->paint.region.isVisible)
  1230.     return;
  1231.  
  1232.     zoom = GET_ZOOM(pw);
  1233.  
  1234.     nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
  1235.     ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
  1236.  
  1237.     XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
  1238. }
  1239.  
  1240.  
  1241. static void 
  1242. writeCleanRegion(PaintWidget pw, Boolean flag, Boolean write)
  1243. {
  1244.     if (!pw->paint.region.isVisible)
  1245.     return;
  1246.  
  1247.     if (write)
  1248.     writeRegion(pw);
  1249.  
  1250.     /*
  1251.     **  Free up temporary images
  1252.      */
  1253.     if (pw->paint.region.sourceImg != NULL)
  1254.     XDestroyImage(pw->paint.region.sourceImg);
  1255.     if (pw->paint.region.maskImg != NULL)
  1256.     XDestroyImage(pw->paint.region.maskImg);
  1257.  
  1258.     pw->paint.region.sourceImg = NULL;
  1259.     pw->paint.region.maskImg = NULL;
  1260.     if (pw->paint.region.source != None) {
  1261.     XFreePixmap(XtDisplay(pw), pw->paint.region.source);
  1262.     pw->paint.region.source = None;
  1263.     }
  1264.     if (pw->paint.region.mask != None) {
  1265.     XFreePixmap(XtDisplay(pw), pw->paint.region.mask);
  1266.     pw->paint.region.mask = None;
  1267.     }
  1268.     if (pw->paint.region.notMask != None) {
  1269.     XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
  1270.     pw->paint.region.notMask = None;
  1271.     }
  1272.     pw->paint.region.undoPixmap = None;
  1273.  
  1274.     if (flag) {
  1275.     if (pw->paint.region.child != None)
  1276.         XtUnmapWidget(pw->paint.region.child);
  1277.     pw->paint.region.isVisible = False;
  1278.     }
  1279. }
  1280.  
  1281. /*  Turn off the selected region after writing it to the background.
  1282.  *  flag == True for all widgets
  1283.  */
  1284. void 
  1285. PwRegionFinish(Widget w, Boolean flag)
  1286. {
  1287.     PaintWidget pw = (PaintWidget) w;
  1288.     PaintWidget pp = (PaintWidget) pw->paint.paint;
  1289.     PaintWidget tpw;
  1290.     int i;
  1291.  
  1292.     if (flag) {
  1293.     tpw = (pp == None) ? pw : pp;
  1294.     writeCleanRegion(tpw, True, True);
  1295.     for (i = 0; i < tpw->paint.paintChildrenSize; i++)
  1296.         writeCleanRegion((PaintWidget) tpw->paint.paintChildren[i], True, True);
  1297.     doCallbacks(pw, False);
  1298.     } else {
  1299.     writeCleanRegion(pw, True, True);
  1300.     }
  1301. }
  1302.  
  1303. /*
  1304.  * Turn off the selected region, but do not write it to the background.
  1305.  * Return False if no region, else True.
  1306.  *  flag == True for all widgets
  1307.  */
  1308. Boolean
  1309. PwRegionOff(Widget w, Boolean flag)
  1310. {
  1311.     PaintWidget pw = (PaintWidget) w;
  1312.     PaintWidget pp = (PaintWidget) pw->paint.paint;
  1313.     PaintWidget tpw;
  1314.     int i;
  1315.  
  1316.     tpw = pw;
  1317.     if (flag)
  1318.     tpw = (pp == None) ? pw : pp;
  1319.  
  1320.     if (!tpw->paint.region.isVisible)
  1321.     return False;
  1322.  
  1323.     writeCleanRegion(tpw, True, False);
  1324.     if (flag) {
  1325.     for (i = 0; i < tpw->paint.paintChildrenSize; i++)
  1326.         writeCleanRegion((PaintWidget) tpw->paint.paintChildren[i], True, False);
  1327.     doCallbacks(pw, False);
  1328.     }
  1329.     return True;
  1330. }
  1331.  
  1332. /*  Set the region pixmap, and mask */
  1333. void 
  1334. PwRegionSet(Widget w, XRectangle * rect, Pixmap pix, Pixmap mask)
  1335. {
  1336.     PaintWidget pw = (PaintWidget) w;
  1337.     int i;
  1338.     int nx, ny, x, y, width, height;
  1339.     int zoom = GET_ZOOM(pw);
  1340.     Boolean setIsAttached = False;
  1341.  
  1342.     /*
  1343.     **  If there is an image, write it
  1344.     **     rect == NULL, then this is just a "write" & "unmap" request
  1345.      */
  1346.     PwRegionFinish(w, True);
  1347.     if (rect == NULL)
  1348.     return;
  1349.  
  1350.     pw->paint.region.curZoom = zoom;
  1351.  
  1352.     x = (rect->x + pw->paint.zoomX) * zoom;
  1353.     y = (rect->y + pw->paint.zoomY) * zoom;
  1354.     width = rect->width * zoom;
  1355.     height = rect->height * zoom;
  1356.  
  1357.     /*
  1358.     **  A little "initializing"
  1359.      */
  1360.     pw->paint.region.isDrawn = False;
  1361.     pw->paint.region.isTracking = False;
  1362.     pw->paint.region.needResize = False;
  1363.  
  1364.     pw->paint.region.rect = *rect;
  1365.  
  1366.     if (pix == None) {
  1367.     setIsAttached = True;
  1368.  
  1369.     if (rect->x < 0) {
  1370.         rect->width += rect->x;
  1371.         rect->x = 0;
  1372.     }
  1373.     if (rect->y < 0) {
  1374.         rect->height += rect->y;
  1375.         rect->y = 0;
  1376.     }
  1377.     if (rect->width > pw->paint.drawWidth)
  1378.         rect->width = pw->paint.drawWidth;
  1379.     if (rect->height > pw->paint.drawHeight)
  1380.         rect->height = pw->paint.drawHeight;
  1381.  
  1382.     pw->paint.region.source = XCreatePixmap(XtDisplay(pw), XtWindow(pw),
  1383.                         rect->width, rect->height,
  1384.                         pw->core.depth);
  1385.     XCopyArea(XtDisplay(pw), GET_PIXMAP(pw), pw->paint.region.source,
  1386.           pw->paint.gc,
  1387.           rect->x, rect->y,
  1388.           rect->width, rect->height,
  1389.           0, 0);
  1390.     } else {
  1391.     pw->paint.region.source = pix;
  1392.     }
  1393.  
  1394.     pw->paint.region.mask = mask;
  1395.     pw->paint.region.orig = *rect;
  1396.  
  1397.     /*
  1398.     **  If there is a clipping mask, create a fg and bg GC with clip-masks
  1399.     **    to draw through.
  1400.      */
  1401.     if (mask != None) {
  1402.  
  1403.     if (pw->paint.region.fg_gc == None) {
  1404.         pw->paint.region.fg_gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  1405.         pw->paint.region.bg_gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
  1406.     }
  1407.     /*
  1408.     **  Make sure the Mask GC is built.
  1409.      */
  1410.     GET_MGC(pw, mask);
  1411.     regionCreateNotMask(pw);
  1412.     } else {
  1413.     /*
  1414.     **  No clip mask, make sure we aren't using one.
  1415.      */
  1416.     if (pw->paint.region.fg_gc != None) {
  1417.         XSetClipMask(XtDisplay(w), pw->paint.region.fg_gc, None);
  1418.         XSetClipMask(XtDisplay(w), pw->paint.region.bg_gc, None);
  1419.     }
  1420.     }
  1421.  
  1422.     if (pw->paint.region.child == None) {
  1423.     pw->paint.region.child = XtVaCreateWidget("region",
  1424.                           compositeWidgetClass, w,
  1425.                           XtNborderWidth, BW,
  1426.                           NULL);
  1427.     XtAddEventHandler(pw->paint.region.child, ButtonPressMask,
  1428.               False,
  1429.               (XtEventHandler) regionButtonPress,
  1430.               (XtPointer) pw);
  1431.     XtAddEventHandler(pw->paint.region.child, ButtonReleaseMask,
  1432.               False,
  1433.               (XtEventHandler) regionButtonRelease,
  1434.               (XtPointer) pw);
  1435.     XtAddEventHandler(pw->paint.region.child, ButtonMotionMask,
  1436.               False,
  1437.               (XtEventHandler) regionGrab,
  1438.               (XtPointer) pw);
  1439.     XtAddEventHandler(pw->paint.region.child, ExposureMask,
  1440.               False,
  1441.               (XtEventHandler) regionExpose,
  1442.               (XtPointer) pw);
  1443.     XtAddEventHandler(pw->paint.region.child, StructureNotifyMask,
  1444.               False,
  1445.               (XtEventHandler) regionMove,
  1446.               (XtPointer) pw);
  1447.     XtAddCallback((Widget) pw, XtNsizeChanged,
  1448.             (XtCallbackProc) zoomValueChanged, (XtPointer) NULL);
  1449.     XtVaSetValues(pw->paint.region.child, XtNx, x, XtNy, y,
  1450.               XtNwidth, width, XtNheight, height, NULL);
  1451.     XtManageChild(pw->paint.region.child);
  1452.     XDefineCursor(XtDisplay(w), XtWindow(pw->paint.region.child),
  1453.               XCreateFontCursor(XtDisplay(w), XC_fleur));
  1454.  
  1455.     for (i = 0; i < 9; i++) {
  1456.         if (i == 4)
  1457.         continue;
  1458.  
  1459.         pw->paint.region.grip[i] =
  1460.         XtVaCreateManagedWidget("grip",
  1461.                  gripWidgetClass, pw->paint.region.child,
  1462.                     XtNwidth, 6, XtNheight, 6, NULL);
  1463.  
  1464.         XtAddEventHandler(pw->paint.region.grip[i], ButtonPressMask,
  1465.                   False,
  1466.                   (XtEventHandler) gripPress,
  1467.                   (XtPointer) pw);
  1468.         XtAddEventHandler(pw->paint.region.grip[i], ButtonMotionMask,
  1469.                   False,
  1470.                   (XtEventHandler) gripGrab,
  1471.                   (XtPointer) pw);
  1472.         XtAddEventHandler(pw->paint.region.grip[i], ButtonReleaseMask,
  1473.                   False,
  1474.                   (XtEventHandler) gripRelease,
  1475.                   (XtPointer) pw);
  1476.     }
  1477.     regionSetGripCursors(pw);
  1478.     pw->paint.region.isVisible = True;
  1479.     } else {
  1480.     XClearArea(XtDisplay(pw), XtWindow(pw->paint.region.child),
  1481.            0, 0, 0, 0, True);
  1482.     }
  1483.  
  1484.     if (setIsAttached) {
  1485.     nx = rect->x;
  1486.     ny = rect->y;
  1487.     } else {
  1488.     nx = pw->paint.downX;
  1489.     ny = pw->paint.downY;
  1490.     }
  1491.     pw->paint.region.rect.x = nx;
  1492.     pw->paint.region.rect.y = ny;
  1493.     nx -= pw->paint.zoomX;
  1494.     ny -= pw->paint.zoomY;
  1495.     XtVaSetValues(pw->paint.region.child, XtNx, nx * zoom - BW,
  1496.           XtNy, ny * zoom - BW,
  1497.           XtNwidth, width,
  1498.           XtNheight, height,
  1499.           NULL);
  1500.  
  1501.     pw->paint.region.scaleX = 1.0;
  1502.     pw->paint.region.scaleY = 1.0;
  1503.     pw->paint.region.centerX = pw->paint.region.orig.width / 2;
  1504.     pw->paint.region.centerY = pw->paint.region.orig.height / 2;
  1505.     COPY_MAT(matIdentity, pw->paint.region.rotMat);
  1506.     MKMAT(pw);
  1507.  
  1508.     if (zoom != 1) {
  1509.     pw->paint.region.rect.width *= zoom;
  1510.     pw->paint.region.rect.height *= zoom;
  1511.     }
  1512.     moveGrips(pw);
  1513.  
  1514.     if (!pw->paint.region.isVisible) {
  1515.     XtMapWidget(pw->paint.region.child);
  1516.     pw->paint.region.isVisible = True;
  1517.     }
  1518. #ifdef SHAPE
  1519.     XShapeCombineMask(XtDisplay(pw), XtWindow(pw->paint.region.child),
  1520.               ShapeBounding, 0, 0, None, ShapeSet);
  1521. #endif
  1522.  
  1523.     pw->paint.region.isAttached = setIsAttached;
  1524.     doCallbacks(pw, True);
  1525. }
  1526.  
  1527. static PaintWidget
  1528. getActiveRegion(PaintWidget pw)
  1529. {
  1530.     PaintWidget pp = (PaintWidget) pw->paint.paint;
  1531.     PaintWidget tpw = (pp == None) ? pw : pp;
  1532.     int i;
  1533.  
  1534.     if (pw->paint.region.isVisible && pw->paint.region.source != None)
  1535.     return pw;
  1536.  
  1537.     if (tpw->paint.region.isVisible && tpw->paint.region.source != None)
  1538.     return tpw;
  1539.  
  1540.     for (i = 0; i < tpw->paint.paintChildrenSize; i++) {
  1541.     PaintWidget p = (PaintWidget) tpw->paint.paintChildren[i];
  1542.     if (p->paint.region.source != None)
  1543.         return p;
  1544.     }
  1545.  
  1546.     return None;
  1547. }
  1548.  
  1549. /*  Set the foreground pixmap, changing it in place */
  1550. void 
  1551. PwRegionSetRawPixmap(Widget w, Pixmap pix)
  1552. {
  1553.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1554.  
  1555.     if (pw == None)
  1556.     return;
  1557.  
  1558.     XFreePixmap(XtDisplay(pw), pw->paint.region.source);
  1559.  
  1560.     if (pw->paint.region.sourceImg != NULL) {
  1561.     XDestroyImage(pw->paint.region.sourceImg);
  1562.     pw->paint.region.sourceImg = NULL;
  1563.     }
  1564.     pw->paint.region.source = pix;
  1565.  
  1566.     doResize(pw);
  1567.     regionRedraw(pw);
  1568. }
  1569.  
  1570. /*  Get a copy of the current image & mask, True if exist */
  1571. Boolean
  1572. PwRegionGet(Widget w, Pixmap * pix, Pixmap * mask)
  1573. {
  1574.     Display *dpy = XtDisplay(w);
  1575.     Window win = XtWindow(w);
  1576.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1577.     Pixmap myMask = None, notMask = None;
  1578.     int zoom;
  1579.     int width, height;
  1580.  
  1581.     if (pw == None)
  1582.     return False;
  1583.     zoom = GET_ZOOM(pw);
  1584.     width = pw->paint.region.orig.width;
  1585.     height = pw->paint.region.orig.height;
  1586.  
  1587.     if (pix)
  1588.     *pix = None;
  1589.     if (mask)
  1590.     *mask = None;
  1591.  
  1592.     if (pw->paint.region.source != None && pix != NULL) {
  1593.     *pix = XCreatePixmap(dpy, win, width, height, pw->core.depth);
  1594.     if (pw->paint.region.sourceImg != NULL) {
  1595.         XPutImage(dpy, *pix, pw->paint.tgc,
  1596.               pw->paint.region.sourceImg,
  1597.               0, 0, 0, 0, width, height);
  1598.     } else {
  1599.         XCopyArea(dpy, pw->paint.region.source,
  1600.               *pix, pw->paint.tgc,
  1601.               0, 0, width, height, 0, 0);
  1602.     }
  1603.     }
  1604.     if (pw->paint.region.mask != None) {
  1605.     myMask = XCreatePixmap(dpy, win, width, height, 1);
  1606.     notMask = XCreatePixmap(dpy, win, width, height, 1);
  1607.  
  1608.     if (pw->paint.region.maskImg != NULL) {
  1609.         XPutImage(dpy, myMask, pw->paint.mgc,
  1610.               pw->paint.region.maskImg,
  1611.               0, 0, 0, 0, width, height);
  1612.     } else {
  1613.         XCopyArea(dpy, pw->paint.region.mask,
  1614.               myMask, pw->paint.mgc,
  1615.               0, 0, width, height, 0, 0);
  1616.     }
  1617.  
  1618.     XSetFunction(dpy, pw->paint.mgc, GXcopyInverted);
  1619.     XCopyArea(dpy, myMask, notMask, pw->paint.mgc, 0, 0,
  1620.           width, height, 0, 0);
  1621.     XSetFunction(dpy, pw->paint.mgc, GXcopy);
  1622.  
  1623.     if (mask == NULL)
  1624.         XFreePixmap(dpy, myMask);
  1625.     else
  1626.         *mask = myMask;
  1627.     }
  1628.     if (notMask != None && pix != NULL) {
  1629.     XSetClipOrigin(dpy, pw->paint.igc, 0, 0);
  1630.     XSetClipMask(XtDisplay(pw), pw->paint.igc, notMask);
  1631.     XFillRectangle(XtDisplay(pw), *pix, pw->paint.igc, 0, 0,
  1632.                width, height);
  1633.     XSetClipMask(XtDisplay(pw), pw->paint.igc, None);
  1634.  
  1635.     }
  1636.     if (notMask != None)
  1637.     XFreePixmap(dpy, notMask);
  1638.  
  1639.     return True;
  1640. }
  1641.  
  1642. /*  Clear the region to the current background color */
  1643. void 
  1644. PwRegionClear(Widget w)
  1645. {
  1646.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1647.  
  1648.     if (pw == None)
  1649.     return;
  1650.  
  1651.     PwRegionTear(w);
  1652.  
  1653.     pw->paint.region.isVisible = False;
  1654.     if (pw->paint.region.child != None)
  1655.     XtUnmapWidget(pw->paint.region.child);
  1656.     doCallbacks(pw, False);
  1657. }
  1658.  
  1659. /*
  1660. **  Make sure that the current region is not connected to the
  1661. **    source pixmap.
  1662.  */
  1663. void 
  1664. PwRegionTear(Widget w)
  1665. {
  1666.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1667.     XRectangle nr;
  1668.  
  1669.     if (pw == None)
  1670.     return;
  1671.     if (!pw->paint.region.isAttached || !pw->paint.region.isVisible)
  1672.     return;
  1673.  
  1674.     nr = pw->paint.region.rect;
  1675.     nr.width /= GET_ZOOM(pw);
  1676.     nr.height /= GET_ZOOM(pw);
  1677.  
  1678.     pw->paint.region.undoPixmap = PwUndoStart((Widget) pw, &nr);
  1679.  
  1680.     if (pw->paint.region.mask != None) {
  1681.     XSetClipOrigin(XtDisplay(pw), pw->paint.igc, nr.x, nr.y);
  1682.     XSetClipMask(XtDisplay(pw), pw->paint.igc, pw->paint.region.mask);
  1683.     }
  1684.     XFillRectangles(XtDisplay(pw), pw->paint.region.undoPixmap,
  1685.             pw->paint.igc, &nr, 1);
  1686.     PwUpdate((Widget) pw, &nr, False);
  1687.     if (pw->paint.region.mask != None) {
  1688.     XSetClipOrigin(XtDisplay(pw), pw->paint.igc, 0, 0);
  1689.     XSetClipMask(XtDisplay(pw), pw->paint.igc, None);
  1690.     }
  1691.     pw->paint.region.isAttached = False;
  1692. }
  1693.  
  1694. /*  Append a transformation matrix to the current transform */
  1695. void 
  1696. PwRegionAppendMatrix(Widget w, pwMatrix mat)
  1697. {
  1698.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1699.  
  1700.     if (pw == None)
  1701.     return;
  1702.  
  1703.     PwRegionTear((Widget) pw);
  1704.  
  1705.     mm(pw->paint.region.rotMat, mat, pw->paint.region.rotMat);
  1706.     MKMAT(pw);
  1707.  
  1708.     pw->paint.region.needResize = True;
  1709.     regionResizeWindow(pw, False);
  1710.     regionRedraw(pw);
  1711. }
  1712.  
  1713. /*  Set the current transformation matrix */
  1714. void 
  1715. PwRegionSetMatrix(Widget w, pwMatrix mat)
  1716. {
  1717.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1718.  
  1719.     if (pw == None)
  1720.     return;
  1721.  
  1722.     PwRegionTear((Widget) pw);
  1723.  
  1724.     COPY_MAT(mat, pw->paint.region.rotMat);
  1725.     MKMAT(pw);
  1726.  
  1727.     pw->paint.region.needResize = True;
  1728.     regionResizeWindow(pw, False);
  1729.     regionRedraw(pw);
  1730. }
  1731.  
  1732. /* Append the current values to the scale */
  1733. void 
  1734. PwRegionAddScale(Widget w, float *xs, float *ys)
  1735. {
  1736.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1737.  
  1738.     if (pw == None)
  1739.     return;
  1740.  
  1741.     PwRegionTear((Widget) pw);
  1742.  
  1743.     if (xs != NULL)
  1744.     pw->paint.region.scaleX *= *xs;
  1745.     if (ys != NULL)
  1746.     pw->paint.region.scaleY *= *ys;
  1747.  
  1748.     MKMAT(pw);
  1749.  
  1750.     pw->paint.region.needResize = True;
  1751.     regionResizeWindow(pw, False);
  1752.     regionRedraw(pw);
  1753. }
  1754.  
  1755. /* Set the current X & Y scale values */
  1756. void 
  1757. PwRegionSetScale(Widget w, float *xs, float *ys)
  1758. {
  1759.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1760.  
  1761.     if (pw == None)
  1762.     return;
  1763.  
  1764.     if (xs != NULL)
  1765.     pw->paint.region.scaleX = *xs;
  1766.     if (ys != NULL)
  1767.     pw->paint.region.scaleY = *ys;
  1768.  
  1769.     MKMAT(pw);
  1770.  
  1771.     pw->paint.region.needResize = True;
  1772.     regionResizeWindow(pw, False);
  1773.     regionRedraw(pw);
  1774. }
  1775.  
  1776. /* Reset both the rotation and scale back to identity */
  1777. void 
  1778. PwRegionReset(Widget w, Boolean flag)
  1779. {
  1780.     PaintWidget pw = getActiveRegion((PaintWidget) w);
  1781.     pwMatrix mat;
  1782.  
  1783.     if (pw == None)
  1784.     return;
  1785.  
  1786.     PwRegionTear((Widget) pw);
  1787.  
  1788.     mat[0][0] = mat[1][1] = 1;
  1789.     mat[1][0] = mat[0][1] = 0;
  1790.  
  1791.     COPY_MAT(mat, pw->paint.region.rotMat);
  1792.     pw->paint.region.scaleY = 1.0;
  1793.     pw->paint.region.scaleX = 1.0;
  1794.     MKMAT(pw);
  1795.  
  1796.     pw->paint.region.needResize = True;
  1797.     regionResizeWindow(pw, False);
  1798.     regionRedraw(pw);
  1799.  
  1800.     /* XXX flag should reset X & Y position as well */
  1801. }
  1802.  
  1803. /*
  1804.  * Crop to region: replaces the image with the region.
  1805.  */
  1806. void 
  1807. RegionCrop(PaintWidget paint)
  1808. {
  1809.     PaintWidget pw = getActiveRegion(paint);
  1810.     Pixmap pix;
  1811.  
  1812.  
  1813.     StateSetBusy(True);
  1814.  
  1815.     if (!PwRegionGet((Widget) paint, &pix, None)) {
  1816.     StateSetBusy(False);
  1817.     return;            /* No region selected */
  1818.     }
  1819.     pw->paint.dirty = True;
  1820.  
  1821.     /* Make the region inactive */
  1822.     PwRegionFinish((Widget) paint, True);
  1823.  
  1824.     XtVaSetValues((Widget) paint,
  1825.           XtNpixmap, pix,
  1826.           XtNdrawWidth, pw->paint.region.orig.width,
  1827.           XtNdrawHeight, pw->paint.region.orig.height,
  1828.           NULL);
  1829.  
  1830.     PwUpdateDrawable((Widget) paint, XtWindow(paint), NULL);
  1831.     StateSetBusy(False);
  1832. }
  1833.  
  1834. void 
  1835. RegionMove(PaintWidget pw, int dx, int dy)
  1836. {
  1837.     int nx, ny;
  1838.     int zoom = GET_ZOOM(pw);
  1839.  
  1840.     if (getActiveRegion(pw) == None)
  1841.     return;
  1842.     PwRegionTear((Widget) pw);
  1843.  
  1844.     pw->paint.region.rect.x += dx;
  1845.     pw->paint.region.rect.y += dy;
  1846.     nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
  1847.     ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
  1848.  
  1849.     XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
  1850.  
  1851.     drawRegionBox(pw, False);
  1852. }