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

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. /* Polygon selection code and other portions */
  16. /* Copyright 1995, 1996 Torsten Martinsen    */
  17.  
  18. /* $Id: selectOp.c,v 1.6 1996/05/31 06:24:05 torsten Exp $ */
  19.  
  20. #include <X11/Intrinsic.h>
  21. #include <X11/StringDefs.h>
  22. #include <X11/cursorfont.h>
  23. #ifndef VMS
  24. #include <X11/Xaw/Form.h>
  25. #include <X11/Xaw/AsciiText.h>
  26. #include <X11/Xaw/Toggle.h>
  27. #include <X11/Xaw/Scrollbar.h>
  28. #include <X11/Xaw/Command.h>
  29. #else
  30. #include <X11Xaw/Form.h>
  31. #include <X11Xaw/AsciiText.h>
  32. #include <X11Xaw/Toggle.h>
  33. #include <X11Xaw/Scrollbar.h>
  34. #include <X11Xaw/Command.h>
  35. #endif
  36. #include <X11/Shell.h>
  37. #include <X11/keysym.h>
  38. #include <stdio.h>
  39. #include "xpaint.h"
  40. #include "Paint.h"
  41. #include "protocol.h"
  42. #include "palette.h"
  43. #include "color.h"
  44. #include "misc.h"
  45. #include "operation.h"
  46. #include "ops.h"
  47.  
  48. /*
  49. **  It is now historical, that the Box and Area selection
  50. **    operations are contained in the same file.
  51.  */
  52.  
  53. static int cutMode = 0;
  54. static int shapeMode = 0;
  55.  
  56. typedef struct {
  57.     int areaType;        /* 0: box/ellipse, 1: lasso */
  58.     Boolean lastType;        /* True: square/circle */
  59.     Boolean tracking, first;
  60.  
  61.     Widget w;
  62.     Drawable drawable;
  63.  
  64.     Boolean drawn;
  65.  
  66.     int wx, wy;
  67.  
  68.     /*
  69.     **  The point region for lasso and polygon
  70.      */
  71.     int size, npoint;
  72.     XPoint *real_p, *window_p;
  73.  
  74.     /*
  75.      * Additional info for polygon
  76.      */
  77.     int startX, endX, startY, endY, button;
  78.  
  79.     /*
  80.     **  The rectangles for a box (also used for ellipse)
  81.      */
  82.     int lastX, lastY;
  83.     XRectangle rect;
  84.  
  85.     GC gcx;
  86.  
  87.     /*
  88.     **  The interesting stuff, for the active region
  89.     **    the important part of pixBox is the width, height
  90.     **    the x,y is where it is presently located on the screen.
  91.      */
  92.     XRectangle pixBox;
  93. } LocalInfo;
  94.  
  95. #define MKRECT(rect, sx, sy, ex, ey, typeFlag) do {            \
  96.     if (typeFlag) {        /* square */                \
  97.         (rect)->width  = MIN(ABS(sx - ex),ABS(sy - ey));    \
  98.         (rect)->height = (rect)->width;                \
  99.         (rect)->x = (ex - sx < 0) ? sx - (rect)->width : sx;    \
  100.         (rect)->y = (ey - sy < 0) ? sy - (rect)->height : sy;    \
  101.     } else {        /* no constraints */            \
  102.         (rect)->x      = MIN(sx, ex);                \
  103.         (rect)->y      = MIN(sy, ey);                \
  104.         (rect)->width  = MAX(sx, ex) - (rect)->x;        \
  105.         (rect)->height = MAX(sy, ey) - (rect)->y;        \
  106.     }                                \
  107. } while (0)
  108.  
  109. static Boolean chromaCut(Widget w, LocalInfo * l, Pixmap * mask);
  110.  
  111. /*
  112. **  press
  113.  */
  114. static void 
  115. press(Widget w, LocalInfo * l, XButtonEvent * event, OpInfo * info)
  116. {
  117.     /*
  118.     **  Check to make sure all buttons are up, before doing this
  119.      */
  120.     if ((event->state & AllButtonsMask) != 0)
  121.     return;
  122.  
  123.     if (info->surface == opWindow) {
  124.     l->w = w;
  125.  
  126.     l->wx = event->x;
  127.     l->wy = event->y;
  128.  
  129.     l->drawn = False;
  130.  
  131.     return;
  132.     }
  133.     /*
  134.     **  Must be on the surface == pixmap now
  135.      */
  136.  
  137.     l->drawable = info->drawable;
  138.  
  139.     l->real_p[0].x = info->x;
  140.     l->real_p[0].y = info->y;
  141.     l->window_p[0].x = l->wx - info->zoom / 2;
  142.     l->window_p[0].y = l->wy - info->zoom / 2;
  143.     l->npoint = 1;
  144. }
  145.  
  146. static void 
  147. keyPress(Widget w, LocalInfo * l, XKeyEvent * event, OpInfo * info)
  148. {
  149.     KeySym keysym;
  150.     int len, i, dx, dy;
  151.     char buf[21];
  152.  
  153.     len = XLookupString(event, buf, sizeof(buf) - 1, &keysym, NULL);
  154.  
  155.     dx = dy = 0;
  156.     switch (keysym) {
  157.     case XK_Up:
  158.     dy = -1;
  159.     break;
  160.     case XK_Down:
  161.     dy = 1;
  162.     break;
  163.     case XK_Left:
  164.     dx = -1;
  165.     break;
  166.     case XK_Right:
  167.     dx = 1;
  168.     break;
  169.     default:
  170.     break;
  171.     }
  172.     if (event->state & ControlMask) {
  173.     dx *= 5;
  174.     dy *= 5;
  175.     }
  176.     if (dx || dy) {
  177.     RegionMove((PaintWidget) w, dx, dy);
  178.     return;
  179.     }
  180.     /*
  181.     **  Look for either backspace or delete and remove region
  182.      */
  183.     for (i = 0; i < len; i++) {
  184.     if (buf[i] == 0x08 || buf[i] == 0x7f) {
  185.         PwRegionClear(w);
  186.         return;
  187.     }
  188.     }
  189. }
  190.  
  191. static void 
  192. finishPolyBand(Widget w, LocalInfo * l, OpInfo * info)
  193. {
  194.     int xmin, xmax, ymin, ymax, i, width, height;
  195.     Pixmap mask;
  196.     GC gc;
  197.     XPoint tmp;
  198.  
  199.     if (!l->tracking)
  200.     return;
  201.  
  202.     l->tracking = False;
  203.  
  204.     if (l->drawn)
  205.     XDrawLines(XtDisplay(w), XtWindow(w), l->gcx,
  206.            l->window_p, l->npoint, CoordModeOrigin);
  207.     PwUpdateDrawable(w, info->drawable, NULL);
  208.     if (l->npoint <= 2)
  209.     return;
  210.     l->window_p[l->npoint] = l->window_p[0];
  211.     l->real_p[l->npoint] = l->real_p[0];
  212.     l->npoint++;
  213.  
  214.     xmin = xmax = l->real_p[0].x;
  215.     ymin = ymax = l->real_p[0].y;
  216.     for (i = l->npoint - 1; i > 0; i--) {
  217.     xmin = MIN(xmin, l->real_p[i].x);
  218.     ymin = MIN(ymin, l->real_p[i].y);
  219.     xmax = MAX(xmax, l->real_p[i].x);
  220.     ymax = MAX(ymax, l->real_p[i].y);
  221.  
  222.     l->window_p[i].x = l->window_p[i].x - l->window_p[i - 1].x;
  223.     l->window_p[i].y = l->window_p[i].y - l->window_p[i - 1].y;
  224.     l->real_p[i].x = l->real_p[i].x - l->real_p[i - 1].x;
  225.     l->real_p[i].y = l->real_p[i].y - l->real_p[i - 1].y;
  226.     }
  227.  
  228.     XYtoRECT(xmin, ymin, xmax, ymax, &l->pixBox);
  229.     XtVaGetValues(w, XtNdrawWidth, &width, XtNdrawHeight, &height, NULL);
  230.     if (l->pixBox.x + l->pixBox.width > width)
  231.     l->pixBox.width = width - l->pixBox.x;
  232.     if (l->pixBox.y + l->pixBox.height > height)
  233.     l->pixBox.height = height - l->pixBox.y;
  234.     if (l->pixBox.x < 0) {
  235.     l->pixBox.width += l->pixBox.x;
  236.     l->pixBox.x = 0;
  237.     }
  238.     if (l->pixBox.y < 0) {
  239.     l->pixBox.height += l->pixBox.y;
  240.     l->pixBox.y = 0;
  241.     }
  242.     mask = XCreatePixmap(XtDisplay(w), XtWindow(w),
  243.              l->pixBox.width, l->pixBox.height, 1);
  244.     gc = XCreateGC(XtDisplay(w), mask, 0, 0);
  245.     XSetFunction(XtDisplay(w), gc, GXclear);
  246.     XFillRectangle(XtDisplay(w), mask, gc, 0, 0,
  247.            l->pixBox.width, l->pixBox.height);
  248.     XSetFunction(XtDisplay(w), gc, GXset);
  249.     tmp = l->real_p[0];
  250.     l->real_p[0].x = l->real_p[0].x - xmin;
  251.     l->real_p[0].y = l->real_p[0].y - ymin;
  252.     XFillPolygon(XtDisplay(w), mask, gc, l->real_p, l->npoint,
  253.          Complex, CoordModePrevious);
  254.     l->real_p[0] = tmp;
  255.  
  256.     XFreeGC(XtDisplay(w), gc);
  257.  
  258.     if (l->pixBox.width <= 1 || l->pixBox.height <= 1) {
  259.     PwRegionFinish(w, True);
  260.     return;
  261.     }
  262.     if (cutMode != 0 && !chromaCut(w, l, &mask)) {
  263.     PwRegionFinish(w, True);
  264.     return;
  265.     }
  266.     PwRegionSet(w, &l->pixBox, None, mask);
  267. }
  268.  
  269. static void 
  270. pressPolyBand(Widget w, LocalInfo * l, XButtonEvent * event, OpInfo * info)
  271. {
  272.     if (!l->tracking && (event->button == Button1)) {
  273.     l->endX = l->startX = event->x;
  274.     l->endY = l->startY = event->y;
  275.  
  276.     l->button = event->button;
  277.  
  278.     l->window_p[0].x = event->x;
  279.     l->window_p[0].y = event->y;
  280.     l->real_p[0].x = info->x;
  281.     l->real_p[0].y = info->y;
  282.     l->npoint = 1;
  283.  
  284.     l->drawn = False;
  285.     l->tracking = True;
  286.     l->first = True;
  287.     } else if ((event->button == Button2) && l->tracking) {
  288.     finishPolyBand(w, l, info);
  289.     return;
  290.     }
  291. }
  292.  
  293. /*
  294. **  motion
  295.  */
  296. static void 
  297. motionBoxBand(Widget w, LocalInfo * l, XMotionEvent * event, OpInfo * info)
  298. {
  299.     XRectangle rect;
  300.  
  301.     if (l->drawn) {
  302.     MKRECT(&rect, l->window_p[0].x, l->window_p[0].y,
  303.            l->lastX, l->lastY, l->lastType);
  304.     if (shapeMode == 0)
  305.         XDrawRectangles(XtDisplay(w), XtWindow(w), l->gcx, &rect, 1);
  306.     else
  307.         XDrawArc(XtDisplay(w), XtWindow(w), l->gcx, rect.x, rect.y,
  308.              rect.width, rect.height, 0, 360 * 64);
  309.     }
  310.     l->lastX = event->x - info->zoom / 2;
  311.     l->lastY = event->y - info->zoom / 2;
  312.     l->lastType = (event->state & ShiftMask);
  313.  
  314.     if ((l->drawn =
  315.        (l->window_p[0].x != l->lastX && l->window_p[0].y != l->lastY))) {
  316.     MKRECT(&rect, l->window_p[0].x, l->window_p[0].y,
  317.            l->lastX, l->lastY, l->lastType);
  318.     if (shapeMode == 0)
  319.         XDrawRectangles(XtDisplay(w), XtWindow(w), l->gcx, &rect, 1);
  320.     else
  321.         XDrawArc(XtDisplay(w), XtWindow(w), l->gcx, rect.x, rect.y,
  322.              rect.width, rect.height, 0, 360 * 64);
  323.     }
  324. }
  325.  
  326. static void 
  327. motionLassoBand(Widget w, LocalInfo * l, XMotionEvent * event, OpInfo * info)
  328. {
  329.     if (l->npoint != 0 && (l->real_p[l->npoint - 1].x == info->x) &&
  330.     (l->real_p[l->npoint - 1].y == info->y))
  331.     return;
  332.  
  333.     l->window_p[l->npoint].x = event->x;
  334.     l->window_p[l->npoint].y = event->y;
  335.     l->real_p[l->npoint].x = info->x;
  336.     l->real_p[l->npoint].y = info->y;
  337.  
  338.     XDrawLine(XtDisplay(w), XtWindow(w), l->gcx,
  339.           l->window_p[l->npoint - 1].x,
  340.           l->window_p[l->npoint - 1].y,
  341.           l->window_p[l->npoint].x,
  342.           l->window_p[l->npoint].y);
  343.     XDrawPoint(XtDisplay(w), XtWindow(w), l->gcx,
  344.            l->window_p[l->npoint].x,
  345.            l->window_p[l->npoint].y);
  346.  
  347.  
  348.     l->npoint++;
  349.  
  350.     if (l->npoint > l->size - 3) {
  351.     l->size += 256;
  352.     l->real_p = (XPoint *) XtRealloc((XtPointer) l->real_p,
  353.                      l->size * sizeof(XPoint));
  354.     l->window_p = (XPoint *) XtRealloc((XtPointer) l->window_p,
  355.                        l->size * sizeof(XPoint));
  356.     }
  357. }
  358.  
  359. static void 
  360. motionPolyBand(Widget w, LocalInfo * l, XMotionEvent * event, OpInfo * info)
  361. {
  362.     if (!l->tracking)
  363.     return;
  364.  
  365.     if (l->drawn)
  366.     XDrawLine(XtDisplay(w), info->drawable, l->gcx,
  367.           l->startX, l->startY, l->endX, l->endY);
  368.  
  369.     l->endX = event->x;
  370.     l->endY = event->y;
  371.  
  372.     if ((l->drawn = ((l->startX != l->endX) || (l->startY != l->endY))))
  373.     XDrawLine(XtDisplay(w), info->drawable, l->gcx,
  374.           l->startX, l->startY, l->endX, l->endY);
  375. }
  376.  
  377. static void 
  378. motion(Widget w, LocalInfo * l, XMotionEvent * event, OpInfo * info)
  379. {
  380.     if (!event->state)
  381.     return;
  382.  
  383.     if (l->areaType == 0)
  384.     motionBoxBand(w, l, event, info);
  385.     else
  386.     motionLassoBand(w, l, event, info);
  387. }
  388.  
  389. static Boolean
  390. chromaCut(Widget w, LocalInfo * l, Pixmap * mask)
  391. {
  392.     GC gc;
  393.     XImage *src, *mimg;
  394.     XRectangle *rect = PwScaleRectangle(w, &l->pixBox);
  395.     int x, y, count = 0;
  396.     Pixel p;
  397.     XColor *xcol;
  398.     int br, bg, bb;
  399.     int vr, vg, vb;
  400.     int pr, pg, pb;
  401.     Boolean mode = (cutMode == 1);
  402.     Palette *map;
  403.     Colormap cmap;
  404.     int step;
  405.  
  406.     src = PwGetImage(w, rect);
  407.     XtVaGetValues(GetShell(w), XtNcolormap, &cmap, NULL);
  408.     map = PaletteFind(w, cmap);
  409.  
  410.     if (*mask != None) {
  411.     mimg = XGetImage(XtDisplay(w), *mask, 0, 0,
  412.              rect->width, rect->height, AllPlanes, ZPixmap);
  413.     } else {
  414.     mimg = NewXImage(XtDisplay(w), DefaultVisualOfScreen(XtScreen(w)),
  415.              1, rect->width, rect->height);
  416.  
  417.     memset(mimg->data, ~0, rect->height * mimg->bytes_per_line);
  418.     }
  419.  
  420.     GetChromaBackground(&br, &bg, &bb);
  421.     GetChromaDelta(&vr, &vg, &vb);
  422.  
  423.     if (rect->height * rect->width > 2048)
  424.     StateSetBusy(True);
  425.     step = 256 * 64 / rect->width;
  426.  
  427.     for (y = 0; y < rect->height; y++) {
  428.     for (x = 0; x < rect->width; x++) {
  429.         if (!XGetPixel(mimg, x, y))
  430.         continue;
  431.  
  432.         p = XGetPixel(src, x + rect->x, y + rect->y);
  433.         xcol = PaletteLookup(map, p);
  434.         pr = (xcol->red >> 8) & 0xff;
  435.         pg = (xcol->green >> 8) & 0xff;
  436.         pb = (xcol->blue >> 8) & 0xff;
  437.  
  438.         if (((br - vr) <= pr && pr <= (br + vr) &&
  439.          (bg - vg) <= pg && pg <= (bg + vg) &&
  440.          (bb - vb) <= pb && pb <= (bb + vb)) == mode)
  441.         XPutPixel(mimg, x, y, False);
  442.         else
  443.         count++;
  444.     }
  445.     if (y % step == 0)
  446.         StateTimeStep();
  447.     }
  448.  
  449.     if (count != 0) {
  450.     /*
  451.     **  Not a solid region.
  452.      */
  453.  
  454.     if (*mask == None)
  455.         *mask = XCreatePixmap(XtDisplay(w), XtWindow(w),
  456.                   rect->width, rect->height, 1);
  457.     gc = XCreateGC(XtDisplay(w), *mask, 0, 0);
  458.     XPutImage(XtDisplay(w), *mask, gc, mimg, 0, 0, 0, 0,
  459.           rect->width, rect->height);
  460.     XFreeGC(XtDisplay(w), gc);
  461.     }
  462.     XDestroyImage(mimg);
  463.  
  464.     if (rect->height * rect->width > 2048)
  465.     StateSetBusy(False);
  466.  
  467.  
  468.     return count != 0;
  469. }
  470.  
  471. static void 
  472. releaseBoxBand(Widget w, LocalInfo * l, XButtonEvent * event,
  473.            OpInfo * info, Pixmap * mask)
  474. {
  475.     XRectangle rect;
  476.     int width, height;
  477.     GC gc;
  478.     if (l->drawn) {
  479.     MKRECT(&rect, l->window_p[0].x, l->window_p[0].y,
  480.            l->lastX, l->lastY, l->lastType);
  481.     if (shapeMode == 0)
  482.         XDrawRectangles(XtDisplay(w), XtWindow(w), l->gcx, &rect, 1);
  483.     else
  484.         XDrawArc(XtDisplay(w), XtWindow(w), l->gcx, rect.x, rect.y,
  485.              rect.width, rect.height, 0, 360 * 64);
  486.     }
  487.     MKRECT(&l->pixBox, l->real_p[0].x, l->real_p[0].y,
  488.        info->x, info->y, l->lastType);
  489.     XtVaGetValues(w, XtNdrawWidth, &width, XtNdrawHeight, &height, NULL);
  490.  
  491.     if (l->pixBox.x + l->pixBox.width > width)
  492.     l->pixBox.width = width - l->pixBox.x;
  493.     if (l->pixBox.y + l->pixBox.height > height)
  494.     l->pixBox.height = height - l->pixBox.y;
  495.     if (l->pixBox.x < 0) {
  496.     l->pixBox.width += l->pixBox.x;
  497.     l->pixBox.x = 0;
  498.     }
  499.     if (l->pixBox.y < 0) {
  500.     l->pixBox.height += l->pixBox.y;
  501.     l->pixBox.y = 0;
  502.     }
  503.     if (shapeMode == 0)
  504.     return;
  505.  
  506.     /* to avoid crash when selecting a single point as ellipse - ACZ */
  507.     if ((l->pixBox.width <= 1) || (l->pixBox.height <= 1))
  508.      return;
  509.  
  510.     *mask = XCreatePixmap(XtDisplay(w), XtWindow(w),
  511.               l->pixBox.width, l->pixBox.height, 1);
  512.     gc = XCreateGC(XtDisplay(w), *mask, 0, 0);
  513.     XSetFunction(XtDisplay(w), gc, GXclear);
  514.     XFillRectangle(XtDisplay(w), *mask, gc, 0, 0,
  515.            l->pixBox.width, l->pixBox.height);
  516.     XSetFunction(XtDisplay(w), gc, GXset);
  517.     XFillArc(XtDisplay(w), *mask, gc, 0, 0,
  518.          l->pixBox.width, l->pixBox.height, 0, 360 * 64);
  519.  
  520.     XFreeGC(XtDisplay(w), gc);
  521. }
  522.  
  523. static Boolean
  524. releaseLassoBand(Widget w, LocalInfo * l, XButtonEvent * event,
  525.          OpInfo * info, Pixmap * mask)
  526. {
  527.     int xmax, xmin, ymax, ymin;
  528.     int width, height, i;
  529.     GC gc;
  530.     XPoint tmp;
  531.  
  532.     XDrawLines(XtDisplay(w), XtWindow(w), l->gcx,
  533.            l->window_p, l->npoint, CoordModeOrigin);
  534.  
  535.     if (l->npoint <= 2)
  536.     return False;
  537.  
  538.     l->window_p[l->npoint] = l->window_p[0];
  539.     l->real_p[l->npoint] = l->real_p[0];
  540.     l->npoint++;
  541.  
  542.     xmin = xmax = l->real_p[0].x;
  543.     ymin = ymax = l->real_p[0].y;
  544.     for (i = l->npoint - 1; i > 0; i--) {
  545.     xmin = MIN(xmin, l->real_p[i].x);
  546.     ymin = MIN(ymin, l->real_p[i].y);
  547.     xmax = MAX(xmax, l->real_p[i].x);
  548.     ymax = MAX(ymax, l->real_p[i].y);
  549.  
  550.     l->window_p[i].x = l->window_p[i].x - l->window_p[i - 1].x;
  551.     l->window_p[i].y = l->window_p[i].y - l->window_p[i - 1].y;
  552.     l->real_p[i].x = l->real_p[i].x - l->real_p[i - 1].x;
  553.     l->real_p[i].y = l->real_p[i].y - l->real_p[i - 1].y;
  554.     }
  555.  
  556.     XYtoRECT(xmin, ymin, xmax, ymax, &l->pixBox);
  557.     XtVaGetValues(w, XtNdrawWidth, &width, XtNdrawHeight, &height, NULL);
  558.     if (l->pixBox.x + l->pixBox.width > width)
  559.     l->pixBox.width = width - l->pixBox.x;
  560.     if (l->pixBox.y + l->pixBox.height > height)
  561.     l->pixBox.height = height - l->pixBox.y;
  562.     if (l->pixBox.x < 0) {
  563.     l->pixBox.width += l->pixBox.x;
  564.     l->pixBox.x = 0;
  565.     }
  566.     if (l->pixBox.y < 0) {
  567.     l->pixBox.height += l->pixBox.y;
  568.     l->pixBox.y = 0;
  569.     }
  570.     *mask = XCreatePixmap(XtDisplay(w), XtWindow(w),
  571.               l->pixBox.width, l->pixBox.height, 1);
  572.     gc = XCreateGC(XtDisplay(w), *mask, 0, 0);
  573.     XSetFunction(XtDisplay(w), gc, GXclear);
  574.     XFillRectangle(XtDisplay(w), *mask, gc, 0, 0,
  575.            l->pixBox.width, l->pixBox.height);
  576.     XSetFunction(XtDisplay(w), gc, GXset);
  577.     tmp = l->real_p[0];
  578.     l->real_p[0].x = l->real_p[0].x - xmin;
  579.     l->real_p[0].y = l->real_p[0].y - ymin;
  580.     XFillPolygon(XtDisplay(w), *mask, gc, l->real_p, l->npoint,
  581.          Complex, CoordModePrevious);
  582.     l->real_p[0] = tmp;
  583.  
  584.     XFreeGC(XtDisplay(w), gc);
  585.  
  586.     return True;
  587. }
  588.  
  589. static void 
  590. releasePolyBand(Widget w, LocalInfo * l, XButtonEvent * event,
  591.         OpInfo * info, Pixmap * mask)
  592. {
  593.     if (l->first) {
  594.     l->first = False;
  595.     return;
  596.     } else {
  597.     l->endX = event->x;
  598.     l->endY = event->y;
  599.     l->startX = event->x;
  600.     l->startY = event->y;
  601.     }
  602.  
  603.     if (l->npoint > l->size - 3) {
  604.     l->size += 32;
  605.     l->real_p = (XPoint *) XtRealloc((XtPointer) l->real_p,
  606.                      l->size * sizeof(XPoint));
  607.     l->window_p = (XPoint *) XtRealloc((XtPointer) l->window_p,
  608.                        l->size * sizeof(XPoint));
  609.     }
  610.     l->window_p[l->npoint].x = event->x;
  611.     l->window_p[l->npoint].y = event->y;
  612.     l->real_p[l->npoint].x = info->x;
  613.     l->real_p[l->npoint].y = info->y;
  614.     l->npoint++;
  615. }
  616.  
  617.  
  618. static void 
  619. release(Widget w, LocalInfo * l, XButtonEvent * event, OpInfo * info)
  620. {
  621.     int mask;
  622.     Pixmap mpix;
  623.  
  624.     /*
  625.     **  Check to make sure all buttons are up, before doing this
  626.      */
  627.     mask = AllButtonsMask;
  628.     switch (event->button) {
  629.     case Button1:
  630.     mask ^= Button1Mask;
  631.     break;
  632.     case Button2:
  633.     mask ^= Button2Mask;
  634.     break;
  635.     case Button3:
  636.     mask ^= Button3Mask;
  637.     break;
  638.     case Button4:
  639.     mask ^= Button4Mask;
  640.     break;
  641.     case Button5:
  642.     mask ^= Button5Mask;
  643.     break;
  644.     }
  645.     if ((event->state & mask) != 0)
  646.     return;
  647.  
  648.     mpix = None;
  649.  
  650.     if (l->areaType == 0)
  651.     releaseBoxBand(w, l, event, info, &mpix);
  652.     else if (releaseLassoBand(w, l, event, info, &mpix) == False) {
  653.     PwRegionFinish(w, True);
  654.     return;
  655.     }
  656.     if (l->pixBox.width <= 1 || l->pixBox.height <= 1) {
  657.     PwRegionFinish(w, True);
  658.     return;
  659.     }
  660.     if (cutMode != 0 && !chromaCut(w, l, &mpix)) {
  661.     PwRegionFinish(w, True);
  662.     return;
  663.     }
  664.     PwRegionSet(w, &l->pixBox, None, mpix);
  665. }
  666.  
  667. /*
  668. **  Those public functions
  669.  */
  670. void *
  671. SelectBoxAdd(Widget w)
  672. {
  673.     LocalInfo *l = (LocalInfo *) XtMalloc(sizeof(LocalInfo));
  674.  
  675.     l->areaType = 0;
  676.     l->lastType = 0;
  677.     l->gcx = GetGCX(w);
  678.  
  679.     l->size = 8;
  680.     l->real_p = (XPoint *) XtCalloc(sizeof(XPoint), l->size);
  681.     l->window_p = (XPoint *) XtCalloc(sizeof(XPoint), l->size);
  682.  
  683.     XtVaSetValues(w, XtNcompress, True, NULL);
  684.  
  685.     OpAddEventHandler(w, opWindow | opPixmap, ButtonPressMask, FALSE,
  686.               (OpEventProc) press, l);
  687.     OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE,
  688.               (OpEventProc) motion, l);
  689.     OpAddEventHandler(w, opWindow, ButtonReleaseMask, FALSE,
  690.               (OpEventProc) release, l);
  691.     OpAddEventHandler(w, opWindow, KeyPressMask, FALSE,
  692.               (OpEventProc) keyPress, l);
  693.     SetCrossHairCursor(w);
  694.  
  695.     return l;
  696. }
  697.  
  698. void 
  699. SelectBoxRemove(Widget w, void *p)
  700. {
  701.     LocalInfo *l = (LocalInfo *) p;
  702.  
  703.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonPressMask, FALSE,
  704.              (OpEventProc) press, l);
  705.     OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE,
  706.              (OpEventProc) motion, l);
  707.     OpRemoveEventHandler(w, opWindow, ButtonReleaseMask, FALSE,
  708.              (OpEventProc) release, l);
  709.     OpRemoveEventHandler(w, opWindow, KeyPressMask, FALSE,
  710.              (OpEventProc) keyPress, l);
  711.     PwRegionFinish(w, False);
  712.  
  713.     XtFree((XtPointer) l->window_p);
  714.     XtFree((XtPointer) l->real_p);
  715.     XtFree((XtPointer) l);
  716. }
  717.  
  718. void *
  719. LassoAdd(Widget w)
  720. {
  721.     LocalInfo *l = (LocalInfo *) XtMalloc(sizeof(LocalInfo));
  722.  
  723.     l->areaType = 1;
  724.     l->gcx = GetGCX(w);
  725.  
  726.     XtVaSetValues(w, XtNcompress, False, NULL);
  727.  
  728.     l->size = 256;
  729.     l->real_p = (XPoint *) XtCalloc(sizeof(XPoint), l->size);
  730.     l->window_p = (XPoint *) XtCalloc(sizeof(XPoint), l->size);
  731.  
  732.     OpAddEventHandler(w, opWindow | opPixmap, ButtonPressMask, FALSE,
  733.               (OpEventProc) press, l);
  734.     OpAddEventHandler(w, opWindow, ButtonMotionMask, FALSE,
  735.               (OpEventProc) motion, l);
  736.     OpAddEventHandler(w, opWindow, ButtonReleaseMask, FALSE,
  737.               (OpEventProc) release, l);
  738.     OpAddEventHandler(w, opWindow, KeyPressMask, FALSE,
  739.               (OpEventProc) keyPress, l);
  740.  
  741.     SetPencilCursor(w);
  742.  
  743.     return l;
  744. }
  745.  
  746. void 
  747. LassoRemove(Widget w, void *p)
  748. {
  749.     LocalInfo *l = (LocalInfo *) p;
  750.  
  751.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonPressMask, FALSE,
  752.              (OpEventProc) press, l);
  753.     OpRemoveEventHandler(w, opWindow, ButtonMotionMask, FALSE,
  754.              (OpEventProc) motion, l);
  755.     OpRemoveEventHandler(w, opWindow, ButtonReleaseMask, FALSE,
  756.              (OpEventProc) release, l);
  757.     OpRemoveEventHandler(w, opWindow, KeyPressMask, FALSE,
  758.              (OpEventProc) keyPress, l);
  759.     PwRegionFinish(w, False);
  760.  
  761.     XtFree((XtPointer) l->window_p);
  762.     XtFree((XtPointer) l->real_p);
  763.     XtFree((XtPointer) l);
  764. }
  765.  
  766.  
  767. void *
  768. SelectPolyAdd(Widget w)
  769. {
  770.     LocalInfo *l = (LocalInfo *) XtMalloc(sizeof(LocalInfo));
  771.  
  772.     l->areaType = 2;
  773.     l->drawn = False;
  774.     l->first = True;
  775.     l->tracking = False;
  776.     l->gcx = GetGCX(w);
  777.  
  778.     XtVaSetValues(w, XtNcompress, False, NULL);
  779.  
  780.     l->size = 256;
  781.     l->real_p = (XPoint *) XtCalloc(sizeof(XPoint), l->size);
  782.     l->window_p = (XPoint *) XtCalloc(sizeof(XPoint), l->size);
  783.  
  784.     OpAddEventHandler(w, opWindow | opPixmap, ButtonPressMask, FALSE,
  785.               (OpEventProc) pressPolyBand, l);
  786.     OpAddEventHandler(w, opWindow, PointerMotionMask, FALSE,
  787.               (OpEventProc) motionPolyBand, l);
  788.     OpAddEventHandler(w, opWindow, ButtonReleaseMask, FALSE,
  789.               (OpEventProc) releasePolyBand, l);
  790.     OpAddEventHandler(w, opWindow, KeyPressMask, FALSE,
  791.               (OpEventProc) keyPress, l);
  792.  
  793.     SetPencilCursor(w);
  794.  
  795.     return l;
  796. }
  797.  
  798. void 
  799. SelectPolyRemove(Widget w, void *p)
  800. {
  801.     LocalInfo *l = (LocalInfo *) p;
  802.  
  803.     OpRemoveEventHandler(w, opWindow | opPixmap, ButtonPressMask, FALSE,
  804.              (OpEventProc) pressPolyBand, l);
  805.     OpRemoveEventHandler(w, opWindow, PointerMotionMask, FALSE,
  806.              (OpEventProc) motionPolyBand, l);
  807.     OpRemoveEventHandler(w, opWindow, ButtonReleaseMask, FALSE,
  808.              (OpEventProc) releasePolyBand, l);
  809.     OpRemoveEventHandler(w, opWindow, KeyPressMask, FALSE,
  810.              (OpEventProc) keyPress, l);
  811.     PwRegionFinish(w, False);
  812.  
  813.     XtFree((XtPointer) l->window_p);
  814.     XtFree((XtPointer) l->real_p);
  815.     XtFree((XtPointer) l);
  816. }
  817.  
  818. void 
  819. SelectSetShapeMode(int value)
  820. {
  821.     shapeMode = value;
  822. }
  823.  
  824. void 
  825. SelectSetCutMode(int value)
  826. {
  827.     cutMode = value;
  828. #if RANGEBUTTONS
  829.     ChromaSetCutMode(value);
  830. #endif
  831. }
  832.  
  833. int 
  834. SelectGetCutMode(void)
  835. {
  836.     return cutMode;
  837. }
  838.