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.17 2005/03/20 20:15:32 demailly 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 <stdlib.h>
30 #include <math.h>
31 #ifdef __EMX__
32 #include <float.h>
33 #endif
34 #include <X11/IntrinsicP.h>
35 #include <X11/StringDefs.h>
36 #include <X11/cursorfont.h>
37 #include <X11/Xatom.h>
38
39 #include "xaw_incdir/Grip.h"
40
41 #include "xpaint.h"
42 #include "PaintP.h"
43 #include "image.h"
44 #include "protocol.h"
45
46 #define SHAPE
47
48 #ifdef SHAPE
49 #include <X11/extensions/shape.h>
50 #endif
51
52 extern void motionExtern(Widget, XEvent *, int x, int y, int flag);
53
54 #define regionRedraw(pw) PwRegionExpose(pw->paint.region.child, pw, NULL, NULL)
55
56 #define BoolStr(flg) ((flg) ? "True" : "False")
57
58 #undef INTERACTIVE
59
60 /*
61 ** Border Width of child widget
62 */
63 #define BW 0
64
65 /*
66 ** 2x2 matrix stuff
67 **
68 */
69
70 #define XFORM(x,y,mat,nx,ny) nx = mat[0][0] * x + mat[0][1] * y; \
71 ny = mat[1][0] * x + mat[1][1] * y
72 #define COPY_MAT(s,d) d[0][0] = s[0][0]; d[0][1] = s[0][1]; \
73 d[1][0] = s[1][0]; d[1][1] = s[1][1]
74
75 #define INVERT_MAT(mat, inv) { \
76 double _d = 1.0 / (mat[0][0] * mat[1][1] \
77 - mat[0][1] * mat[1][0]); \
78 (inv)[0][0] = (mat)[1][1] * _d; \
79 (inv)[1][1] = (mat)[0][0] * _d; \
80 (inv)[0][1] = -(mat)[0][1] * _d; \
81 (inv)[1][0] = -(mat)[1][0] * _d; \
82 }
83
84 #define ZERO(v) (((v) > -1e-5) && ((v) < 1e-5))
85
86 #ifndef MIN
87 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
88 #endif
89 #ifndef MAX
90 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
91 #endif
92 #ifndef SIGN
93 #define SIGN(a) (((a) < 0) ? -1 : 1)
94 #endif
95 #ifndef ABS
96 #define ABS(a) ((a > 0) ? (a) : 0 - (a))
97 #endif
98
99 #define MKMAT(pw) do { \
100 pwMatrix m; \
101 m[0][0] = pw->paint.region.scaleX; \
102 m[1][1] = pw->paint.region.scaleY; \
103 m[0][1] = m[1][0] = 0.0; \
104 mm(pw->paint.region.rotMat, m, pw->paint.region.mat); \
105 } while (0)
106
107 extern Pixmap lastpix;
108
109 static pwMatrix matIdentity =
110 {
111 {1, 0},
112 {0, 1}
113 };
114
115 int alpha_special_mode = 0;
116
117 void
XXsync(Display * dpy,Boolean flag)118 XXsync(Display *dpy, Boolean flag)
119 {
120 }
121
122 static void
doCallbacks(PaintWidget pw,int flag)123 doCallbacks(PaintWidget pw, int flag)
124 {
125 PaintWidget tpw = (pw->paint.paint)? (PaintWidget) pw->paint.paint : pw;
126 int i;
127
128 XtCallCallbackList((Widget) tpw, tpw->paint.regionCalls,
129 (XtPointer)(long)flag);
130 for (i = 0; i < tpw->paint.paintChildrenSize; i++) {
131 PaintWidget p = (PaintWidget) tpw->paint.paintChildren[i];
132 XtCallCallbackList((Widget) p, p->paint.regionCalls,
133 (XtPointer)(long)flag);
134 }
135 }
136
137 /*
138 * Multiply matrices a and b and store result in r.
139 */
140 static void
mm(pwMatrix a,pwMatrix b,pwMatrix r)141 mm(pwMatrix a, pwMatrix b, pwMatrix r)
142 {
143 double t00, t01, t10, t11;
144 t00 = a[0][0] * b[0][0] + a[0][1] * b[1][0];
145 t01 = a[0][0] * b[0][1] + a[0][1] * b[1][1];
146 t10 = a[1][0] * b[0][0] + a[1][1] * b[1][0];
147 t11 = a[1][0] * b[0][1] + a[1][1] * b[1][1];
148 r[0][0] = t00;
149 r[0][1] = t01;
150 r[1][0] = t10;
151 r[1][1] = t11;
152 }
153
154 /*
155 ** PwRegionSet -- set the active image region
156 ** add handles and other useful things
157 ** if the pix == None, use the current paint info in rect
158 ** else use the pixmap.
159 **
160 */
161 static void
buildSources(PaintWidget pw)162 buildSources(PaintWidget pw)
163 {
164 if (pw->paint.region.source == None) return;
165
166 if (pw->paint.region.sourceImg == NULL) {
167 pw->paint.region.sourceImg = XGetImage(XtDisplay(pw),
168 pw->paint.region.source, 0, 0,
169 pw->paint.region.orig.width,
170 pw->paint.region.orig.height,
171 AllPlanes, ZPixmap);
172 }
173
174 if (pw->paint.region.mask == None)
175 return;
176
177 if (pw->paint.region.maskImg == NULL) {
178 pw->paint.region.maskImg = XGetImage(XtDisplay(pw),
179 pw->paint.region.mask, 0, 0,
180 pw->paint.region.orig.width,
181 pw->paint.region.orig.height, AllPlanes, ZPixmap);
182 }
183 }
184
185 void
RegionTransparency(PaintWidget pw)186 RegionTransparency(PaintWidget pw)
187 {
188 PaintWidget tpw;
189 Widget w;
190 XImage *src1, *src2, *src3 = NULL;
191 Pixel pix;
192 GC gc;
193 int rwidth, rheight, widthp, heightp, zoom, skip;
194 int px, py, rx, ry, x, y, i, j, bytes_per_pixel, zoom_bytes_per_pixel;
195 char bg[4];
196 int opaque, transparent;
197
198 if (pw->paint.region.source == None) return;
199 tpw = (pw->paint.paint)? (PaintWidget)pw->paint.paint : pw;
200
201 XtVaGetValues((Widget)pw, XtNtransparent, &transparent, NULL);
202 if (transparent==0) return;
203
204 /* transparent=2 is transitional state - things should be redrawn once */
205 if (transparent&2)
206 XtVaSetValues((Widget)pw, XtNtransparent, transparent-2, NULL);
207
208 opaque = 1-(transparent&1);
209 zoom = GET_ZOOM(pw);
210
211 w = pw->paint.region.child;
212 if (!pw->paint.region.source || !w) {
213 return;
214 }
215
216 px = pw->paint.region.rect.x;
217 py = pw->paint.region.rect.y;
218
219 if (px<0) {
220 rx = -px;
221 px = 0;
222 } else
223 rx = 0;
224 if (py<0) {
225 ry = -py;
226 py = 0;
227 } else
228 ry = 0;
229
230 if (zoom==1) {
231 rwidth = w->core.width - rx;
232 rheight = w->core.height - ry;
233 } else {
234 rwidth = w->core.width;
235 rheight = w->core.height;
236 }
237
238 if (zoom>0) {
239 widthp = (rwidth+zoom-1)/zoom;
240 heightp = (rheight+zoom-1)/zoom;
241 } else {
242 widthp = rwidth*(-zoom);
243 heightp = rheight*(-zoom);
244 }
245
246 i = pw->paint.drawWidth - px;
247 j = pw->paint.drawHeight - py;
248
249 if (widthp>i) widthp = i;
250 if (heightp>j) heightp = j;
251 if (widthp<=0 || heightp<=0)
252 return;
253
254 gc = (pw->paint.region.fg_gc == None)?
255 pw->paint.tgc : pw->paint.region.fg_gc;
256
257 src1 = XGetImage(XtDisplay(pw), pw->paint.region.source,
258 (zoom==1)?rx:0, (zoom==1)?ry:0, widthp, heightp,
259 AllPlanes, ZPixmap);
260
261 if (tpw->paint.alpha_mode && tpw->paint.region.alpha)
262 AlphaTwistImage(tpw, src1, tpw->paint.region.alpha,
263 src1->width,
264 0, 0,
265 pw->paint.region.orig.x, pw->paint.region.orig.y);
266
267 if (!src1) return;
268
269 if ((zoom==1) && opaque) {
270 src2 = src1;
271 bytes_per_pixel = src2->bits_per_pixel/8;
272 } else {
273 src2 = XGetImage(XtDisplay(pw), GET_PIXMAP(pw),
274 px, py, widthp, heightp,
275 AllPlanes, ZPixmap);
276 if (src2) {
277 if (tpw->paint.alpha_mode && tpw->paint.current.alpha)
278 AlphaTwistImage(tpw, src2, tpw->paint.current.alpha,
279 tpw->paint.drawWidth,
280 px, py,
281 px, py);
282 bytes_per_pixel = src2->bits_per_pixel/8;
283 if (zoom>0)
284 for (y=0; y<heightp; y++) {
285 i = src2->bytes_per_line * y;
286 for (x=0; x<widthp; x++) {
287 if (opaque || (x+y)&1)
288 memcpy(&src2->data[i], &src1->data[i], bytes_per_pixel);
289 i += bytes_per_pixel;
290 }
291 } else
292 for (y=0; y<heightp; y++) {
293 i = src1->bytes_per_line * y;
294 for (x=0; x<widthp; x++) {
295 if (opaque || (x/(-zoom)+y/(-zoom))&1)
296 memcpy(&src2->data[i], &src1->data[i], bytes_per_pixel);
297 i += bytes_per_pixel;
298 }
299 }
300 }
301 XDestroyImage(src1);
302 if (!src2) return;
303 }
304
305 if (zoom == 1) {
306 XPutImage(XtDisplay(pw), XtWindow(w), gc,
307 src2, 0, 0, rx, ry, rwidth, rheight);
308 XDestroyImage(src2);
309 } else {
310 src3 = XCreateImage(XtDisplay(pw), pw->paint.visual,
311 src2->depth, ZPixmap, 0, NULL,
312 rwidth, rheight,
313 32, 0);
314 if (!src3) {
315 XDestroyImage(src2);
316 return;
317 }
318 src3->data = (char *) XtMalloc(rheight * src3->bytes_per_line);
319 if (!src3->data) {
320 XDestroyImage(src2);
321 XDestroyImage(src3);
322 return;
323 }
324 bytes_per_pixel = src3->bits_per_pixel/8;
325 XtVaGetValues((Widget)pw, XtNbackground, &pix, NULL);
326 xxPutPixel(src3, 0, 0, pix);
327 memcpy(bg, src3->data, bytes_per_pixel);
328 if (zoom>0) {
329 skip = -(zoom<=ZOOM_THRESH);
330 px = MIN(rwidth, widthp*zoom);
331 py = MIN(rheight, heightp*zoom);
332 for (y=0; y<py; y++) {
333 j = src3->bytes_per_line * y;
334 if ((y+1)%zoom == skip) {
335 for (x=0; x<rwidth; x++) {
336 memcpy(&src3->data[j], bg, bytes_per_pixel);
337 j += bytes_per_pixel;
338 }
339 } else {
340 i = src2->bytes_per_line * (y/zoom);
341 for (x=0; x<px; x++) {
342 if ((x+1)%zoom == skip)
343 memcpy(&src3->data[j], bg, bytes_per_pixel);
344 else
345 memcpy(&src3->data[j], &src2->data[i], bytes_per_pixel);
346 j += bytes_per_pixel;
347 if ((x+1)%zoom == 0)
348 i += bytes_per_pixel;
349 }
350 }
351 }
352 } else {
353 zoom_bytes_per_pixel = bytes_per_pixel * (-zoom);
354 px = MIN(rwidth, widthp/(-zoom));
355 py = MIN(rheight, heightp/(-zoom));
356 for (y = 0; y < py; y++) {
357 i = src2->bytes_per_line * y * (-zoom);
358 j = src3->bytes_per_line * y;
359 for (x = 0; x < px; x++) {
360 memcpy(&src3->data[j], &src2->data[i], bytes_per_pixel);
361 i += zoom_bytes_per_pixel;
362 j += bytes_per_pixel;
363 }
364 }
365 }
366
367 XDestroyImage(src2);
368
369 if (zoom!=1 && pw->paint.region.mask != None) {
370 XImage * dstMask, *srcMask;
371 Pixmap mask;
372 GC gcbw;
373 if (zoom>0) {
374 px = MIN(rwidth, widthp*zoom);
375 py = MIN(rheight, heightp*zoom);
376 } else {
377 px = MIN(rwidth, widthp/(-zoom));
378 py = MIN(rheight, heightp/(-zoom));
379 }
380 srcMask = XGetImage(XtDisplay(pw), pw->paint.region.mask,
381 0, 0, widthp, heightp,
382 AllPlanes, ZPixmap);
383 dstMask = XCreateImage(XtDisplay(pw), pw->paint.visual,
384 1, ZPixmap, 0, NULL, px, py, 32, 0);
385 dstMask->data = (char *) XtMalloc(py*dstMask->bytes_per_line);
386 memset(dstMask->data, 0, py*dstMask->bytes_per_line);
387 if (zoom>0) {
388 for (y=0; y<py; y++) {
389 for (x=0; x<px; x++) {
390 if (XGetPixel(srcMask, x/zoom, y/zoom))
391 XPutPixel(dstMask, x, y, True);
392 }
393 }
394 } else {
395 for (y=0; y<py; y++) {
396 for (x=0; x<px; x++) {
397 if (XGetPixel(srcMask, x*(-zoom), y*(-zoom)))
398 XPutPixel(dstMask, x, y, True);
399 }
400 }
401 }
402 XDestroyImage(srcMask);
403 mask = XCreatePixmap(XtDisplay(w), XtWindow(w), px, py, 1);
404 gcbw = XCreateGC(XtDisplay(w), mask, 0, 0);
405 XPutImage(XtDisplay(w), mask, gcbw, dstMask, 0, 0, 0, 0, px, py);
406 XSetClipOrigin(XtDisplay(w), gc, 0, 0);
407 XSetClipMask(XtDisplay(w), gc, mask);
408 XPutImage(XtDisplay(w), XtWindow(w), gc, src3, 0, 0, 0, 0, px, py);
409 XSync(XtDisplay(w), False);
410 XDestroyImage(dstMask);
411 XDestroyImage(src3);
412 XFreePixmap(XtDisplay(w), mask);
413 XFreeGC(XtDisplay(w), gcbw);
414 XSetClipOrigin(XtDisplay(w), gc, 0, 0);
415 XSetClipMask(XtDisplay(w), gc, pw->paint.region.mask);
416 return;
417 }
418
419 XPutImage(XtDisplay(w), XtWindow(w), gc,
420 src3, 0, 0, (zoom==1)?rx:0, (zoom==1)?ry:0, rwidth, rheight);
421 XDestroyImage(src3);
422 }
423 }
424
425 static void
resizeImg(PaintWidget pw,pwMatrix inv,Pixmap * pix,XImage * pixSrc,Pixmap * mask,XImage * maskSrc,Pixmap * shape)426 resizeImg(PaintWidget pw, pwMatrix inv, Pixmap * pix, XImage * pixSrc,
427 Pixmap * mask, XImage * maskSrc, Pixmap * shape)
428 {
429 int width, height, depth;
430 int x, y, zoom;
431 XImage *pixDst, *maskDst = NULL, *shapeDst = NULL;
432 Pixel pixel;
433 int sourceW, sourceH;
434 int ix, iy, fx, fy, cx, cy;
435 double dx, dy, sx, sy;
436
437 if (pixSrc == NULL || pix == NULL)
438 return;
439 if (pw->paint.region.rect.width == 0 || pw->paint.region.rect.height == 0)
440 return;
441
442 /*
443 ** Construct the dest pixmap.
444 */
445
446 if (*pix != None)
447 XFreePixmap(XtDisplay(pw), *pix);
448 if (*mask != None && maskSrc != NULL)
449 XFreePixmap(XtDisplay(pw), *mask);
450
451 depth = pixSrc->depth;
452 zoom = GET_ZOOM(pw);
453
454 if (zoom>0) {
455 width = pw->paint.region.rect.width / zoom;
456 height = pw->paint.region.rect.height / zoom;
457 } else {
458 width = pw->paint.region.rect.width * (-zoom);
459 height = pw->paint.region.rect.height * (-zoom);
460 }
461
462 *pix = XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, depth);
463 XtVaGetValues((Widget) pw, XtNbackground, &pixel, NULL);
464
465 pixDst = XCreateImage(XtDisplay(pw), pw->paint.visual,
466 depth, ZPixmap, 0, NULL, width, height, 32, 0);
467 XSetForeground(XtDisplay(pw), pw->paint.tgc, WhitePixelOfScreen(XtScreen(pw)));
468 pixDst->data = (char *) XtMalloc(height * pixDst->bytes_per_line);
469
470 if (maskSrc != NULL) {
471 *mask = XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, 1);
472 maskDst = XCreateImage(XtDisplay(pw), pw->paint.visual,
473 1, ZPixmap, 0, NULL, width, height, 32, 0);
474 maskDst->data = (char *) XtMalloc(height * maskDst->bytes_per_line);
475 #ifdef SHAPE
476 if (shape != NULL) {
477 *shape = XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, 1);
478 shapeDst = XCreateImage(XtDisplay(pw), pw->paint.visual,
479 1, ZPixmap, 0, NULL, width, height, 32, 0);
480 shapeDst->data = (char *) XtMalloc(height * shapeDst->bytes_per_line);
481 }
482 #endif
483 }
484
485 cx = pw->paint.region.orig.width / 2;
486 cy = pw->paint.region.orig.height / 2;
487 fx = (int) (-width / 2);
488 fy = (int) (-height / 2);
489 sourceW = pixSrc->width;
490 sourceH = pixSrc->height;
491
492 for (y = 0, dy = fy; y < height; y++, dy++) {
493 for (x = 0, dx = fx; x < width; x++, dx++) {
494 XFORM(dx, dy, inv, sx, sy);
495 ix = (sx + cx + 0.5);
496 iy = (sy + cy + 0.5);
497 if (ix >= 0 && ix < sourceW && iy >= 0 && iy < sourceH) {
498 xxPutPixel(pixDst, x, y, xxGetPixel(pixSrc, ix, iy));
499 if (maskSrc != NULL)
500 XPutPixel(maskDst, x, y, XGetPixel(maskSrc, ix, iy));
501 #ifdef SHAPE
502 if (shapeDst != NULL)
503 XPutPixel(shapeDst, x, y, True);
504 #endif
505 } else {
506 xxPutPixel(pixDst, x, y, pixel);
507 if (maskSrc != NULL)
508 XPutPixel(maskDst, x, y, False);
509 #ifdef SHAPE
510 if (shapeDst != NULL)
511 XPutPixel(shapeDst, x, y, False);
512 #endif
513 }
514 }
515 }
516
517 XPutImage(XtDisplay(pw), *pix, pw->paint.tgc, pixDst,
518 0, 0, 0, 0, width, height);
519 XDestroyImage(pixDst);
520
521 if (maskSrc != NULL) {
522 XPutImage(XtDisplay(pw), *mask, pw->paint.mgc, maskDst,
523 0, 0, 0, 0, width, height);
524 XDestroyImage(maskDst);
525 }
526 #ifdef SHAPE
527 if (shapeDst != NULL) {
528 XPutImage(XtDisplay(pw), *shape, pw->paint.mgc, shapeDst,
529 0, 0, 0, 0, width, height);
530 XDestroyImage(shapeDst);
531 }
532 #endif
533 }
534
535 void
regionCreateNotMask(PaintWidget pw)536 regionCreateNotMask(PaintWidget pw)
537 {
538 int width, height, zoom;
539
540 if (pw->paint.region.rect.width == 0 || pw->paint.region.rect.height == 0)
541 return;
542
543 if (pw->paint.region.mask == None)
544 return;
545
546 if (pw->paint.region.notMask != None)
547 XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
548
549 XtVaGetValues((Widget)pw, XtNzoom, &zoom, NULL);
550
551 width = pw->paint.region.rect.width;
552 height = pw->paint.region.rect.height;
553 if (zoom<0) {
554 width *= (-zoom);
555 height *= (-zoom);
556 }
557
558 pw->paint.region.notMask = XCreatePixmap(XtDisplay(pw), XtWindow(pw),
559 width, height, 1);
560 XSetFunction(XtDisplay(pw), pw->paint.mgc, GXcopyInverted);
561 XCopyArea(XtDisplay(pw), pw->paint.region.mask, pw->paint.region.notMask,
562 pw->paint.mgc, 0, 0,
563 width, height, 0, 0);
564 XSetFunction(XtDisplay(pw), pw->paint.mgc, GXcopy);
565
566 XSetClipOrigin(XtDisplay(pw), pw->paint.region.bg_gc, 0, 0);
567 XSetClipMask(XtDisplay(pw), pw->paint.region.bg_gc,
568 pw->paint.region.notMask);
569 XSetClipOrigin(XtDisplay(pw), pw->paint.region.fg_gc, 0, 0);
570 XSetClipMask(XtDisplay(pw), pw->paint.region.fg_gc, pw->paint.region.mask);
571 }
572
573 static void
createVtxPts(PaintWidget pw,double vtx[9][2],Boolean flag,Boolean useZoom)574 createVtxPts(PaintWidget pw, double vtx[9][2], Boolean flag, Boolean useZoom)
575 {
576 int zoom;
577 int i;
578 int x0, x1, y0, y1;
579 int width = pw->paint.region.orig.width;
580 int height = pw->paint.region.orig.height;
581
582 if (useZoom)
583 zoom = GET_ZOOM(pw);
584 else
585 zoom = 1;
586
587 x0 = (-width / 2);
588 x1 = (width + x0);
589 y0 = (-height / 2);
590 y1 = (height + y0);
591 if (zoom>0) {
592 x0 *= zoom;
593 x1 *= zoom;
594 y0 *= zoom;
595 y1 *= zoom;
596 } else {
597 x0 /= -zoom;
598 x1 /= -zoom;
599 y0 /= -zoom;
600 y1 /= -zoom;
601 }
602
603 /*
604 ** Watch out, these are points 0,1, and _3__
605 */
606 XFORM(x0, y0, pw->paint.region.mat, vtx[0][0], vtx[0][1]);
607 XFORM(x1, y0, pw->paint.region.mat, vtx[1][0], vtx[1][1]);
608 XFORM(x0, y1, pw->paint.region.mat, vtx[3][0], vtx[3][1]);
609
610 if (flag) {
611 XFORM(x1, y1, pw->paint.region.mat, vtx[2][0], vtx[2][1]);
612 if (zoom>0)
613 for (i = 0; i < 4; i++) {
614 vtx[i][0] += pw->paint.region.centerX * zoom;
615 vtx[i][1] += pw->paint.region.centerY * zoom;
616 } else
617 for (i = 0; i < 4; i++) {
618 vtx[i][0] += pw->paint.region.centerX / (-zoom);
619 vtx[i][1] += pw->paint.region.centerY / (-zoom);
620 }
621 } else {
622 /*
623 ** sort the points, so that point 0,0 is top left corner
624 */
625 if (vtx[0][0] > vtx[1][0]) {
626 double t = x0;
627 x0 = x1;
628 x1 = t;
629 }
630 if (vtx[0][1] > vtx[3][1]) {
631 double t = y0;
632 y0 = y1;
633 y1 = t;
634 }
635 XFORM(x0, y0, pw->paint.region.mat, vtx[0][0], vtx[0][1]);
636 XFORM(0, y0, pw->paint.region.mat, vtx[1][0], vtx[1][1]);
637 XFORM(x1, y0, pw->paint.region.mat, vtx[2][0], vtx[2][1]);
638
639 XFORM(x0, 0, pw->paint.region.mat, vtx[3][0], vtx[3][1]);
640 XFORM(0, 0, pw->paint.region.mat, vtx[4][0], vtx[4][1]);
641 XFORM(x1, 0, pw->paint.region.mat, vtx[5][0], vtx[5][1]);
642
643 XFORM(x0, y1, pw->paint.region.mat, vtx[6][0], vtx[6][1]);
644 XFORM(0, y1, pw->paint.region.mat, vtx[7][0], vtx[7][1]);
645 XFORM(x1, y1, pw->paint.region.mat, vtx[8][0], vtx[8][1]);
646 }
647 }
648
649 static void
doResize(PaintWidget pw)650 doResize(PaintWidget pw)
651 {
652 pwMatrix inv;
653 Pixmap shape, *shp = &shape;
654
655 buildSources(pw);
656
657 /*
658 ** First find out the bounding extent of the transformed
659 ** area, then scale it to fit inside of the "region box"
660 */
661
662 if (pw->paint.region.maskImg == NULL) {
663 Boolean needMask = False;
664 double vtx[9][2];
665 double minX, minY, maxX, maxY;
666 int x, cmin, cmax;
667
668 createVtxPts(pw, vtx, True, False);
669
670 minX = MIN(vtx[0][0], MIN(vtx[1][0], MIN(vtx[2][0], vtx[3][0])));
671 minY = MIN(vtx[0][1], MIN(vtx[1][1], MIN(vtx[2][1], vtx[3][1])));
672 maxX = MAX(vtx[0][0], MAX(vtx[1][0], MAX(vtx[2][0], vtx[3][0])));
673 maxY = MAX(vtx[0][1], MAX(vtx[1][1], MAX(vtx[2][1], vtx[3][1])));
674
675 /*
676 ** After computing min, max see if there are points
677 ** on all vertices, if so then set the correct return code
678 */
679 for (cmin = cmax = x = 0; x < 4; x++) {
680 if ((int) vtx[x][0] == (int) minX)
681 cmin++;
682 else if ((int) vtx[x][0] == (int) maxX)
683 cmax++;
684 }
685 needMask |= (cmin != 2 || cmax != 2);
686 for (cmin = cmax = x = 0; x < 4; x++) {
687 if ((int) vtx[x][1] == (int) minY)
688 cmin++;
689 else if ((int) vtx[x][1] == (int) maxY)
690 cmax++;
691 }
692
693 needMask |= (cmin != 2 || cmax != 2);
694
695 if (needMask) {
696 Pixmap mask;
697 GC mgc;
698 int width, height, zoom;
699 /*
700 ** If the image we just transformed needs a mask
701 ** and one doesn't exist, construct one.
702 */
703 width = pw->paint.region.orig.width;
704 height = pw->paint.region.orig.height;
705 XtVaGetValues((Widget)pw, XtNzoom, &zoom, NULL);
706 if (zoom<0) {
707 width *= (-zoom);
708 height *= (-zoom);
709 }
710 mask = pw->paint.region.mask =
711 XCreatePixmap(XtDisplay(pw), XtWindow(pw), width, height, 1);
712 mgc = GET_MGC(pw, mask);
713 XSetFunction(XtDisplay(pw), mgc, GXset);
714 XFillRectangle(XtDisplay(pw), mask, mgc, 0, 0, width, height);
715 XSetFunction(XtDisplay(pw), mgc, GXcopy);
716
717 buildSources(pw);
718
719 if (pw->paint.region.fg_gc == None) {
720 pw->paint.region.fg_gc = XCreateGC(XtDisplay(pw), XtWindow(pw),
721 0, 0);
722 pw->paint.region.bg_gc = XCreateGC(XtDisplay(pw), XtWindow(pw),
723 0, 0);
724 }
725 }
726 }
727 INVERT_MAT(pw->paint.region.mat, inv);
728 #ifdef SHAPE
729 if (pw->paint.region.maskImg == NULL || GET_ZOOM(pw) != 1)
730 shp = NULL;
731 #else
732 shp = NULL;
733 #endif
734
735 resizeImg(pw, inv, &pw->paint.region.source, pw->paint.region.sourceImg,
736 &pw->paint.region.mask, pw->paint.region.maskImg, shp);
737 regionCreateNotMask(pw);
738
739 #ifdef SHAPE
740 if (shp != NULL) {
741 XShapeCombineMask(XtDisplay(pw), XtWindow(pw->paint.region.child),
742 ShapeBounding, 0, 0, shape, ShapeSet);
743 XFreePixmap(XtDisplay(pw), shape);
744 }
745 #endif
746
747 pw->paint.region.needResize = False;
748 }
749
750 static void
drawRegionBox(PaintWidget pw,Boolean flag)751 drawRegionBox(PaintWidget pw, Boolean flag)
752 {
753 static XPoint xvtxLast[5];
754 XPoint xvtx[5];
755 double vtx[9][2];
756 Window window = XtWindow(pw);
757 int i;
758
759 createVtxPts(pw, vtx, True, True);
760
761 xvtx[0].x = vtx[0][0];
762 xvtx[0].y = vtx[0][1];
763 xvtx[1].x = vtx[1][0];
764 xvtx[1].y = vtx[1][1];
765 xvtx[2].x = vtx[2][0];
766 xvtx[2].y = vtx[2][1];
767 xvtx[3].x = vtx[3][0];
768 xvtx[3].y = vtx[3][1];
769 xvtx[4].x = vtx[0][0];
770 xvtx[4].y = vtx[0][1];
771
772 for (i = 0; i < 5; i++) {
773 xvtx[i].x += pw->paint.region.child->core.x;
774 xvtx[i].y += pw->paint.region.child->core.y;
775 }
776
777 if (pw->paint.region.isDrawn) {
778 XDrawLines(XtDisplay(pw), window, pw->paint.xgc, xvtxLast, 5,
779 CoordModeOrigin);
780 pw->paint.region.isDrawn = False;
781 }
782 if (flag) {
783 XDrawLines(XtDisplay(pw), window, pw->paint.xgc, xvtx, 5, CoordModeOrigin);
784 memcpy(xvtxLast, xvtx, sizeof(xvtxLast));
785 pw->paint.region.isDrawn = True;
786 }
787 }
788
789 /*
790 **
791 */
792
793 static void
regionResizeWindow(PaintWidget pw,Boolean sameCenter)794 regionResizeWindow(PaintWidget pw, Boolean sameCenter)
795 {
796 int zoom = GET_ZOOM(pw);
797 int minX, minY, maxX, maxY;
798 int width, height, dx, dy, nx, ny;
799 int newX, newY;
800 int i;
801 double vtx[9][2];
802
803 #ifndef INTERACTIVE
804 if (pw->paint.region.isTracking)
805 return;
806 #endif
807
808 createVtxPts(pw, vtx, False, False);
809
810 minX = MIN(vtx[0][0], vtx[6][0]);
811 maxX = MAX(vtx[2][0], vtx[8][0]);
812 minY = MIN(vtx[0][1], vtx[2][1]);
813 maxY = MAX(vtx[6][1], vtx[8][1]);
814
815 width = maxX - minX + 0.5;
816 height = maxY - minY + 0.5;
817
818 newX = pw->paint.region.centerX - (width / 2);
819 newY = pw->paint.region.centerY - (height / 2);
820
821 newX += pw->paint.region.rect.x;
822 newY += pw->paint.region.rect.y;
823 if (!sameCenter) {
824 pw->paint.region.centerX = width / 2;
825 pw->paint.region.centerY = height / 2;
826 } else {
827 pw->paint.region.centerX = width / 2;
828 pw->paint.region.centerY = height / 2;
829 }
830
831 if (zoom>0) {
832 if ((width *= zoom) < 10)
833 width = 10;
834 if ((height *= zoom) < 10)
835 height = 10;
836 XtResizeWidget(pw->paint.region.child, width, height, BW);
837 nx = (newX - pw->paint.zoomX) * zoom;
838 ny = (newY - pw->paint.zoomY) * zoom;
839 } else {
840 if ((width /= (-zoom)) < 10)
841 width = 10;
842 if ((height /= (-zoom)) < 10)
843 height = 10;
844 XtResizeWidget(pw->paint.region.child, width, height, BW);
845 nx = (newX - pw->paint.zoomX) / (-zoom);
846 ny = (newY - pw->paint.zoomY) / (-zoom);
847 }
848 XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
849
850 pw->paint.region.rect.x = newX;
851 pw->paint.region.rect.y = newY;
852 pw->paint.region.rect.width = width;
853 pw->paint.region.rect.height = height;
854
855 /*
856 ** Now place all the grips.
857 */
858 createVtxPts(pw, vtx, False, True);
859 width = pw->paint.region.grip[0]->core.width;
860 height = pw->paint.region.grip[0]->core.height;
861 if (zoom>0) {
862 dx = pw->paint.region.centerX * zoom - width / 2;
863 dy = pw->paint.region.centerY * zoom - height / 2;
864 } else {
865 dx = pw->paint.region.centerX / (-zoom) - width / 2;
866 dy = pw->paint.region.centerY / (-zoom) - height / 2;
867 }
868 for (i = 0; i < 9; i++) {
869 int x, y;
870
871 if (i == 4)
872 continue;
873
874 x = vtx[i][0] + dx;
875 y = vtx[i][1] + dy;
876
877 if (x < 0)
878 x = 0;
879 if (y < 0)
880 y = 0;
881 if (x + width > pw->paint.region.rect.width)
882 x = pw->paint.region.rect.width - width;
883 if (y + height > pw->paint.region.rect.height)
884 y = pw->paint.region.rect.height - height;
885
886 XtMoveWidget(pw->paint.region.grip[i], x, y);
887 }
888 }
889
890 /*
891 **
892 */
893
894 static void
moveGrips(PaintWidget pw)895 moveGrips(PaintWidget pw)
896 {
897 int width, height;
898 int i, gx=0, gy=0;
899 Dimension w, h;
900 Widget widget = pw->paint.region.grip[0];
901
902 w = widget->core.width;
903 h = widget->core.height;
904 width = widget->core.parent->core.width;
905 height = widget->core.parent->core.height;
906
907 for (i = 0; i < 9; i++) {
908 if (i == 4)
909 continue;
910
911 switch (i % 3) {
912 case 0:
913 gx = 0;
914 break;
915 case 1:
916 gx = width / 2 - w / 2;
917 break;
918 case 2:
919 gx = width - w;
920 break;
921 }
922 switch (i / 3) {
923 case 0:
924 gy = 0;
925 break;
926 case 1:
927 gy = height / 2 - h / 2;
928 break;
929 case 2:
930 gy = height - h;
931 break;
932 }
933
934 XtMoveWidget(pw->paint.region.grip[i], gx, gy);
935 }
936 }
937
938 static void
gripPress(Widget w,PaintWidget pw,XButtonEvent * event,Boolean * junk)939 gripPress(Widget w, PaintWidget pw, XButtonEvent * event, Boolean * junk)
940 {
941 static int fixedPoint[] =
942 {8, 8, 6, 8, -1, 6, 2, 2, 0};
943 double vtx[9][2], fvtx[9][2];
944 double x0, x1, x2, y0, y1, y2, t1, t2, l;
945 int index, i;
946
947 pw->paint.region.offX = event->x;
948 pw->paint.region.offY = event->y;
949 pw->paint.region.baseX = event->x_root - w->core.x;
950 pw->paint.region.baseY = event->y_root - w->core.y;
951
952 pw->paint.region.isTracking = True;
953
954 /*
955 ** Compute which grip was grabbed, to determine constrain line.
956 */
957 for (index = 0; index < 9 && pw->paint.region.grip[index] != w; index++);
958
959 createVtxPts(pw, vtx, False, False);
960 createVtxPts(pw, fvtx, True, False);
961
962 x0 = vtx[0][0];
963 y0 = vtx[0][1];
964 x1 = vtx[2][0];
965 y1 = vtx[2][1];
966 x2 = vtx[6][0];
967 y2 = vtx[6][1];
968
969 pw->paint.region.lineBase[0] = 0;
970 pw->paint.region.lineBase[1] = 0;
971
972 t1 = x1 - x0;
973 t2 = y1 - y0;
974 l = sqrt(t1 * t1 + t2 * t2);
975 pw->paint.region.lineDelta[0] = t1 / l;
976 pw->paint.region.lineDelta[1] = t2 / l;
977
978 t1 = x2 - x0;
979 t2 = y2 - y0;
980 l = sqrt(t1 * t1 + t2 * t2);
981 pw->paint.region.lineDelta[2] = t1 / l;
982 pw->paint.region.lineDelta[3] = t2 / l;
983
984 pw->paint.region.startScaleX = pw->paint.region.scaleX;
985 pw->paint.region.startScaleY = pw->paint.region.scaleY;
986
987 /*
988 ** Now compute which corner of the 4 cornered box doesn't move
989 ** as the object is resized.
990 */
991 for (i = 0; i < 4; i++) {
992 double fx = vtx[fixedPoint[index]][0];
993 double fy = vtx[fixedPoint[index]][1];
994 double px = fvtx[i][0] - pw->paint.region.centerX;
995 double py = fvtx[i][1] - pw->paint.region.centerY;
996
997 if (ZERO(fx - px) && ZERO(fy - py))
998 break;
999 }
1000 pw->paint.region.fixedPoint = i;
1001 }
1002
1003 static void
regionButtonPress(Widget w,PaintWidget pw,XButtonEvent * event,Boolean * junk)1004 regionButtonPress(Widget w, PaintWidget pw, XButtonEvent * event, Boolean * junk)
1005 {
1006 int zoom = GET_ZOOM(pw);
1007 static long prev_time = 0;
1008 Boolean value;
1009
1010 pw->paint.region.isRotate = (event->button == Button2);
1011
1012 pw->paint.region.offX = event->x;
1013 pw->paint.region.offY = event->y;
1014 pw->paint.region.baseX = event->x_root - w->core.x;
1015 pw->paint.region.baseY = event->y_root - w->core.y;
1016
1017 if (event->button == Button1 && Global.transparent) {
1018 if (abs(event->time-prev_time) > 300) {
1019 XtVaGetValues((Widget)pw, XtNtransparent, &value, NULL);
1020 value = 3 - (value&1);
1021 XtVaSetValues((Widget)pw, XtNtransparent, value, NULL);
1022 PwRegionTear((Widget)pw);
1023 RegionTransparency(pw);
1024 } else {
1025 prev_time = event->time;
1026 return;
1027 }
1028 prev_time = event->time;
1029 }
1030
1031 if (zoom>0)
1032 motionExtern((Widget)pw, (XEvent *) event,
1033 pw->paint.region.rect.x,
1034 pw->paint.region.rect.y + pw->paint.region.rect.height/zoom - 1, 1);
1035 else
1036 motionExtern((Widget)pw, (XEvent *) event,
1037 pw->paint.region.rect.x,
1038 pw->paint.region.rect.y + pw->paint.region.rect.height*(-zoom)- 1, 1);
1039
1040 pw->paint.region.lastX = event->x_root;
1041 pw->paint.region.lastY = event->y_root;
1042
1043 if (pw->paint.region.isRotate) {
1044 XDefineCursor(XtDisplay(w), XtWindow(pw->paint.region.child),
1045 XCreateFontCursor(XtDisplay(w), XC_exchange));
1046 pw->paint.region.lastAngle = 0.0;
1047 }
1048 /*
1049 ** Only draw the interactive box when we are rotating.
1050 */
1051 pw->paint.region.isTracking = pw->paint.region.isRotate;
1052 }
1053
1054 static void
gripRelease(Widget w,PaintWidget pw,XButtonEvent * event,Boolean * junk)1055 gripRelease(Widget w, PaintWidget pw, XButtonEvent * event, Boolean * junk)
1056 {
1057 pw->paint.region.isTracking = False;
1058 drawRegionBox(pw, False);
1059 #ifndef INTERACTIVE
1060 if (pw->paint.region.needResize) {
1061 regionResizeWindow(pw, False);
1062 regionRedraw(pw);
1063 }
1064 #endif
1065 }
1066
1067 static void
regionButtonRelease(Widget w,PaintWidget pw,XButtonEvent * event,Boolean * junk)1068 regionButtonRelease(Widget w, PaintWidget pw, XButtonEvent * event,
1069 Boolean * junk)
1070 {
1071 int value;
1072
1073 if (event->button == Button1 && Global.transparent) {
1074 XtVaGetValues((Widget)pw, XtNtransparent, &value, NULL);
1075 value = 3 -(value&1);
1076 XtVaSetValues((Widget)pw, XtNtransparent, value, NULL);
1077 PwRegionTear((Widget)pw);
1078 RegionTransparency(pw);
1079 }
1080
1081 pw->paint.region.isTracking = False;
1082 drawRegionBox(pw, False);
1083
1084 if (!pw->paint.region.isRotate)
1085 return;
1086
1087 #ifndef INTERACTIVE
1088 if (pw->paint.region.needResize) {
1089 regionResizeWindow(pw, False);
1090 regionRedraw(pw);
1091 }
1092 #endif
1093
1094 XDefineCursor(XtDisplay(w), XtWindow(pw->paint.region.child),
1095 XCreateFontCursor(XtDisplay(w), XC_fleur));
1096 }
1097 static void
regionGrab(Widget w,PaintWidget pw,XMotionEvent * event,Boolean * junk)1098 regionGrab(Widget w, PaintWidget pw, XMotionEvent * event, Boolean * junk)
1099 {
1100 int dx, dy, nx, ny;
1101
1102 while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w),
1103 MotionNotify, (XEvent *) event));
1104
1105 PwRegionTear((Widget) pw);
1106
1107 if (pw->paint.region.isRotate) {
1108 double da, na;
1109 pwMatrix m;
1110
1111 dx = event->x - pw->paint.region.rect.width / 2;
1112 dy = event->y - pw->paint.region.rect.height / 2;
1113 na = atan2((double) dy, (double) dx);
1114 /*
1115 * If Shift is pressed, constrain rotation to multiples of 15 degrees.
1116 */
1117 if (event->state & ShiftMask)
1118 na = ((int) (na / (15.0 / 180.0 * M_PI))) * (15.0 / 180.0 * M_PI);
1119 da = na - pw->paint.region.lastAngle;
1120 pw->paint.region.lastAngle = na;
1121
1122 m[0][0] = cos(da);
1123 m[0][1] = -sin(da);
1124 m[1][0] = sin(da);
1125 m[1][1] = cos(da);
1126
1127 PwRegionAppendMatrix((Widget) pw, m);
1128 } else {
1129 int zoom = GET_ZOOM(pw);
1130
1131 nx = event->x_root - pw->paint.region.baseX;
1132 ny = event->y_root - pw->paint.region.baseY;
1133
1134 /*
1135 * If Shift is pressed, constrain movement to horizontal or vertical
1136 */
1137 if (event->state & ShiftMask) {
1138 if (ABS(event->x_root - pw->paint.region.lastX) >
1139 ABS(event->y_root - pw->paint.region.lastY))
1140 ny = pw->paint.region.lastY - pw->paint.region.baseY;
1141 else
1142 nx = pw->paint.region.lastX - pw->paint.region.baseX;
1143 }
1144
1145 if (zoom>0) {
1146 dx = (nx - w->core.x) / zoom;
1147 dy = (ny - w->core.y) / zoom;
1148 } else {
1149 dx = (nx - w->core.x) * (-zoom);
1150 dy = (ny - w->core.y) * (-zoom);
1151 }
1152
1153 if (dx == 0 && dy == 0)
1154 return;
1155
1156 pw->paint.region.rect.x += dx;
1157 pw->paint.region.rect.y += dy;
1158
1159 if (zoom>0) {
1160 nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
1161 ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
1162 } else {
1163 nx = (pw->paint.region.rect.x - pw->paint.zoomX) / (-zoom);
1164 ny = (pw->paint.region.rect.y - pw->paint.zoomY) / (-zoom);
1165 }
1166
1167 XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
1168 if (zoom>0)
1169 motionExtern((Widget)pw, (XEvent *) event,
1170 pw->paint.region.rect.x,
1171 pw->paint.region.rect.y + pw->paint.region.rect.height/zoom - 1, 0);
1172 else
1173 motionExtern((Widget)pw, (XEvent *) event,
1174 pw->paint.region.rect.x,
1175 pw->paint.region.rect.y+pw->paint.region.rect.height*(-zoom)- 1, 0);
1176 RegionTransparency(pw);
1177 }
1178 }
1179
1180 void
PwDrawVisibleGrid(PaintWidget pw,Widget w,Boolean flag,int sx,int sy,int ex,int ey)1181 PwDrawVisibleGrid(PaintWidget pw, Widget w, Boolean flag,
1182 int sx, int sy, int ex, int ey)
1183 {
1184 GC gc;
1185 Display *dpy = XtDisplay(w);
1186 Window win = XtWindow(w);
1187 XGCValues values;
1188 Pixel gridcolor;
1189 int i, j, snap_x, snap_y, zoom, zx, zy;
1190 int gridmode;
1191
1192 zoom = GET_ZOOM(pw);
1193 XtVaGetValues((Widget)pw,
1194 XtNgridmode, &gridmode,
1195 XtNgridcolor, &gridcolor, NULL);
1196
1197 if ((gridmode>>31)&1) {
1198 if (pw->paint.snapOn) {
1199 snap_x = pw->paint.snap_x;
1200 snap_y = pw->paint.snap_y;
1201 if (snap_x < 1) snap_x = 1;
1202 if (snap_y < 1) snap_y = 1;
1203 } else
1204 snap_x = snap_y = 1;
1205 if (zoom>0) {
1206 zx = zoom*snap_x;
1207 zy = zoom*snap_y;
1208 } else {
1209 zx = snap_x/(-zoom);
1210 zy = snap_y/(-zoom);
1211 }
1212 if (zx <= ZOOM_THRESH/2 || zy <= ZOOM_THRESH/2) return;
1213 } else {
1214 if (zoom <= ZOOM_THRESH) return;
1215 snap_x = snap_y = 1;
1216 zx = zy = zoom;
1217 }
1218
1219 sx = (sx/snap_x)*zx;
1220 sy = (sy/snap_y)*zy;
1221 if (zoom>0) {
1222 ex = ex*zoom;
1223 ey = ey*zoom;
1224 } else {
1225 ex = ex/(-zoom);
1226 ey = ey/(-zoom);
1227 }
1228
1229 if (flag) {
1230 values.foreground = gridcolor;
1231 values.background = WhitePixelOfScreen(XtScreen(w));
1232 gc = XCreateGC(dpy, XtWindow(w), GCBackground|GCForeground, &values);
1233 } else {
1234 /*
1235 ** Turning off visible grid, and we need to clear
1236 ** to no space between pixels...
1237 */
1238 if (zx <= ZOOM_THRESH || zy <= ZOOM_THRESH) {
1239 if ((gridmode&3) >= 2) {
1240 if (sx>0) sx -= 1;
1241 if (sy>0) sy -= 1;
1242 ex += 2;
1243 ey += 2;
1244 }
1245 XClearArea(dpy, win, sx, sy, ex - sx, ey - sy, True);
1246 return;
1247 }
1248 values.background = BlackPixelOfScreen(XtScreen(w));
1249 values.foreground = WhitePixelOfScreen(XtScreen(w));
1250 gc = XCreateGC(dpy, XtWindow(w), GCBackground|GCForeground, &values);
1251 }
1252
1253 switch(gridmode&3) {
1254 case 0:
1255 for (i = sx-1; i <ex; i += zx)
1256 XDrawLine(dpy, win, gc, i, sy, i, ey);
1257 for (i = sy-1; i <ey; i += zy)
1258 XDrawLine(dpy, win, gc, sx, i, ex, i);
1259 break;
1260 case 1:
1261 for (i = sx-1; i < ex; i += zx)
1262 for (j = sy-1; j < ey; j += zy)
1263 XDrawPoint(dpy, win, gc, i, j);
1264 break;
1265 case 2:
1266 for (i = sx-1; i < ex; i += zx)
1267 for (j = sy-1; j < ey; j += zy) {
1268 XDrawLine(dpy, win, gc, i-1, j, i+1, j);
1269 XDrawLine(dpy, win, gc, i, j-1, i, j+1);
1270 }
1271 break;
1272 case 3:
1273 for (i = sx-1; i < ex; i += zx)
1274 for (j = sy-1; j < ey; j += zy)
1275 XDrawRectangle(dpy, win, gc, i-1, j-1, 2, 2);
1276 break;
1277 }
1278 XFreeGC(dpy, gc);
1279 }
1280
1281 void
PwRegionExpose(Widget w,PaintWidget pw,XEvent * event,Boolean * junk)1282 PwRegionExpose(Widget w, PaintWidget pw, XEvent * event, Boolean * junk)
1283 {
1284 PaintWidget tpw;
1285 XImage *xim, *src, *mask;
1286 XRectangle rect, nrect, tr;
1287 int isExpose;
1288 int width=0, height=0;
1289 int zoom = GET_ZOOM(pw);
1290 int pixW, pixH;
1291 int dx, dy;
1292
1293 if (!pw->paint.region.isVisible)
1294 return;
1295
1296 if (event == NULL) {
1297 isExpose = True;
1298 rect.x = 0;
1299 rect.y = 0;
1300 rect.width = w->core.width;
1301 rect.height = w->core.height;
1302 } else if (event->xany.type == Expose) {
1303 rect.x = event->xexpose.x;
1304 rect.y = event->xexpose.y;
1305 rect.width = event->xexpose.width;
1306 rect.height = event->xexpose.height;
1307 isExpose = True;
1308 } else if (event->xany.type == ConfigureNotify) {
1309 isExpose = False;
1310 rect.x = 0;
1311 rect.y = 0;
1312 rect.width = w->core.width;
1313 rect.height = w->core.height;
1314 } else
1315 return;
1316
1317 #ifndef INTERACTIVE
1318 if (pw->paint.region.isTracking) {
1319 drawRegionBox(pw, True);
1320 return;
1321 }
1322 #endif
1323 if (pw->paint.region.needResize)
1324 doResize(pw);
1325
1326 if (zoom != 1) {
1327 if (zoom>0) {
1328 nrect.x = rect.x / zoom;
1329 nrect.y = rect.y / zoom;
1330 width = (rect.width + zoom - 1) / zoom;
1331 height = (rect.height + zoom - 1) / zoom;
1332 pixW = pw->paint.region.rect.width / zoom;
1333 pixH = pw->paint.region.rect.height / zoom;
1334 } else {
1335 nrect.x = rect.x * (-zoom);
1336 nrect.y = rect.y * (-zoom);
1337 width = rect.width * (-zoom);
1338 height = rect.height * (-zoom);
1339 pixW = pw->paint.region.rect.width * (-zoom);
1340 pixH = pw->paint.region.rect.height * (-zoom);
1341 }
1342 /*
1343 ** It is possible for this to happen, when resizes and
1344 ** redraws are slightly out of sync.
1345 */
1346 if (width + nrect.x > pixW)
1347 width = pixW - nrect.x;
1348 if (height + nrect.y > pixH)
1349 height = pixH - nrect.y;
1350 if (width <= 0 || height <= 0)
1351 return;
1352 nrect.width = width;
1353 nrect.height = height;
1354 } else
1355 nrect = rect;
1356
1357 if (isExpose) {
1358 if (zoom == 1) {
1359 if (pw->paint.region.alpha && pw->paint.alpha_mode) {
1360 src = XGetImage(XtDisplay(pw), pw->paint.region.source,
1361 rect.x, rect.y, rect.width, rect.height,
1362 AllPlanes, ZPixmap);
1363 AlphaTwistImage(pw, src, pw->paint.region.alpha,
1364 pw->paint.region.rect.width,
1365 rect.x, rect.y,
1366 rect.x+pw->paint.region.orig.x,
1367 rect.y+pw->paint.region.orig.y);
1368 XPutImage(XtDisplay(w), XtWindow(w),
1369 pw->paint.region.fg_gc == None ?
1370 pw->paint.tgc : pw->paint.region.fg_gc, src,
1371 0, 0, rect.x, rect.y, rect.width, rect.height);
1372 XDestroyImage(src);
1373 } else
1374 XCopyArea(XtDisplay(w), pw->paint.region.source, XtWindow(w),
1375 pw->paint.region.fg_gc == None ?
1376 pw->paint.tgc : pw->paint.region.fg_gc,
1377 rect.x, rect.y, rect.width, rect.height,
1378 rect.x, rect.y);
1379 if (pw->paint.grid)
1380 PwDrawVisibleGrid(pw, w, True, rect.x, rect.y,
1381 rect.x+rect.width, rect.y+rect.height);
1382 } else {
1383 mask = NULL;
1384 tr.x = 0;
1385 tr.y = 0;
1386 tr.width = width;
1387 tr.height = height;
1388 src = XGetImage(XtDisplay(pw), pw->paint.region.source,
1389 nrect.x, nrect.y, nrect.width, nrect.height,
1390 AllPlanes, ZPixmap);
1391 tpw = (pw->paint.paint) ? (PaintWidget) pw->paint.paint : pw;
1392 if (tpw->paint.region.alpha && tpw->paint.alpha_mode)
1393 AlphaTwistImage(pw, src, tpw->paint.region.alpha,
1394 pw->paint.region.orig.width,
1395 nrect.x, nrect.y,
1396 nrect.x + pw->paint.region.orig.x,
1397 nrect.y + pw->paint.region.orig.y);
1398 if (pw->paint.region.mask != None)
1399 mask = XGetImage(XtDisplay(pw), pw->paint.region.mask,
1400 nrect.x, nrect.y, nrect.width, nrect.height,
1401 AllPlanes, ZPixmap);
1402 dx = tpw->paint.alpha_mode;
1403 tpw->paint.alpha_mode = 0;
1404 PwZoomDraw(pw, w, pw->paint.tgc, src, mask,
1405 False, nrect.x, nrect.y, zoom, &tr);
1406 XSync(XtDisplay(pw), False);
1407 tpw->paint.alpha_mode = dx;
1408 XDestroyImage(src);
1409 if (mask != NULL)
1410 XDestroyImage(mask);
1411 }
1412 }
1413
1414 /*
1415 ** XXX -- This should merge, and do fun things.. but.
1416 */
1417 if (isExpose && (event != NULL && event->xexpose.count != 0))
1418 return;
1419
1420
1421 if (pw->paint.region.mask != None) {
1422 int x = w->core.x + w->core.border_width;
1423 int y = w->core.y + w->core.border_width;
1424
1425 /*
1426 ** Copy in the background picture
1427 */
1428 if (zoom != 1 || pw->paint.current.alpha) {
1429 tpw = (pw->paint.paint) ? (PaintWidget) pw->paint.paint : pw;
1430
1431 if (zoom>0) {
1432 tr.x = (nrect.x + x) / zoom + pw->paint.zoomX;
1433 tr.y = (nrect.y + y) / zoom + pw->paint.zoomY;
1434 } else {
1435 tr.x = (nrect.x + x) * (-zoom) + pw->paint.zoomX;
1436 tr.y = (nrect.y + y) * (-zoom) + pw->paint.zoomY;
1437 }
1438 width = nrect.width;
1439 height = nrect.height;
1440
1441 /*
1442 ** We could use PwGetImage, but it returns
1443 ** the original image, not the sub-region
1444 */
1445 dx = 0;
1446 dy = 0;
1447 if (tr.x < 0) {
1448 width += tr.x;
1449 dx = -tr.x;
1450 tr.x = 0;
1451 }
1452 if (tr.y < 0) {
1453 height += tr.y;
1454 dy = -tr.y;
1455 tr.y = 0;
1456 }
1457 if (tr.x + width > tpw->paint.drawWidth)
1458 width = tpw->paint.drawWidth - tr.x;
1459 if (tr.y + height > tpw->paint.drawHeight)
1460 height = tpw->paint.drawHeight - tr.y;
1461 if (width > 0 && height > 0 && !isExpose &&
1462 pw->paint.region.notMask) {
1463 tr.width = width;
1464 tr.height = height;
1465 mask = XGetImage(XtDisplay(pw), pw->paint.region.notMask,
1466 nrect.x + dx, nrect.y + dy, tr.width, tr.height,
1467 AllPlanes, ZPixmap);
1468 if (mask) {
1469 xim = XGetImage(XtDisplay(w), GET_PIXMAP(pw),
1470 tr.x, tr.y, tr.width, tr.height,
1471 AllPlanes, ZPixmap);
1472 alpha_special_mode = 1;
1473 PwZoomDraw(pw, w, pw->paint.tgc, xim, mask, False,
1474 dx, dy, zoom, &tr);
1475 alpha_special_mode = 0;
1476 XSync(XtDisplay(pw), False);
1477 XDestroyImage(mask);
1478 XDestroyImage(xim);
1479 }
1480 }
1481 } else {
1482 XCopyArea(XtDisplay(w), GET_PIXMAP(pw), XtWindow(w),
1483 pw->paint.region.bg_gc,
1484 x, y, w->core.width, w->core.height, 0, 0);
1485 if (pw->paint.grid)
1486 PwDrawVisibleGrid(pw, w, True, x, y,
1487 x+w->core.width, y+w->core.height);
1488 }
1489 }
1490 }
1491
1492 static void
regionMove(Widget w,PaintWidget pw,XEvent * event,Boolean * junk)1493 regionMove(Widget w, PaintWidget pw, XEvent * event, Boolean * junk)
1494 {
1495 if (pw->paint.region.mask == None)
1496 return;
1497 /*
1498 ** For some reason, I had to generate an extra function..
1499 */
1500 PwRegionExpose(w, pw, event, junk);
1501 }
1502
1503
1504 static void
regionSetGripCursors(PaintWidget pw)1505 regionSetGripCursors(PaintWidget pw)
1506 {
1507 static int cursors[9] =
1508 {
1509 XC_top_left_corner,
1510 XC_top_side,
1511 XC_top_right_corner,
1512 XC_left_side,
1513 0,
1514 XC_right_side,
1515 XC_bottom_left_corner,
1516 XC_bottom_side,
1517 XC_bottom_right_corner
1518 };
1519 static int list[9] =
1520 {None, None, None, None, None, None, None, None, None};
1521 int i;
1522
1523 if (list[0] == None) {
1524 for (i = 0; i < 9; i++) {
1525 if (i != 4)
1526 list[i] = XCreateFontCursor(XtDisplay(pw), cursors[i]);
1527 }
1528 }
1529 for (i = 0; i < 9; i++)
1530 if (i != 4)
1531 XDefineCursor(XtDisplay(pw), XtWindow(pw->paint.region.grip[i]), list[i]);
1532 }
1533
1534 static void
gripGrab(Widget w,PaintWidget pw,XMotionEvent * event,Boolean * junk)1535 gripGrab(Widget w, PaintWidget pw, XMotionEvent * event, Boolean * junk)
1536 {
1537 static Boolean isLeftEdge[] =
1538 {True, False, False,
1539 True, False, False,
1540 True, False, False};
1541 static Boolean isTopEdge[] =
1542 {True, True, True,
1543 False, False, False,
1544 False, False, False};
1545 static Boolean isMiddle[] =
1546 {False, True, False,
1547 True, False, True,
1548 False, True, False};
1549 Boolean sameScale;
1550 int index, i, fp;
1551 int zoom = GET_ZOOM(pw);
1552 double v[2];
1553 int width, height;
1554 double ovtx[9][2], nvtx[9][2];
1555 double dx, dy;
1556
1557 for (index = 0; index < 9 && pw->paint.region.grip[index] != w; index++);
1558
1559 /*
1560 ** Find the intersection point
1561 */
1562 for (i = 0; i < 2; i++) {
1563 double x0 = pw->paint.region.lineBase[0];
1564 double y0 = pw->paint.region.lineBase[1];
1565 double xm = event->x;
1566 double ym = event->y;
1567
1568 dx = pw->paint.region.lineDelta[0 + i * 2];
1569 dy = pw->paint.region.lineDelta[1 + i * 2];
1570 v[i] = dx * (xm - x0) - dy * (y0 - ym);
1571 }
1572
1573 if (pw->paint.region.startScaleX < 0)
1574 v[0] = -v[0];
1575 if (pw->paint.region.startScaleY < 0)
1576 v[1] = -v[1];
1577 if (isLeftEdge[index])
1578 v[0] = -v[0];
1579 if (isTopEdge[index])
1580 v[1] = -v[1];
1581
1582 if (zoom>0) {
1583 v[0] /= (double) zoom;
1584 v[1] /= (double) zoom;
1585 } else {
1586 v[0] *= (double)(-zoom);
1587 v[1] *= (double)(-zoom);
1588 }
1589
1590 PwRegionTear((Widget) pw);
1591
1592 sameScale = False;
1593 if (isMiddle[index] || (event->state & ShiftMask) != 0) {
1594 /*
1595 ** Apply the constraint
1596 */
1597 if (index == 1 || index == 7)
1598 v[0] = 0;
1599 else if (index == 3 || index == 5)
1600 v[1] = 0;
1601 else
1602 sameScale = True;
1603 }
1604 width = pw->paint.region.startScaleX * pw->paint.region.orig.width;
1605 height = pw->paint.region.startScaleY * pw->paint.region.orig.height;
1606
1607 createVtxPts(pw, ovtx, True, False);
1608
1609 pw->paint.region.scaleX =
1610 (double) ((int) (width + v[0])) / pw->paint.region.orig.width;
1611 pw->paint.region.scaleY =
1612 (double) ((int) (height + v[1])) / pw->paint.region.orig.height;
1613
1614 if (sameScale) {
1615 double sx = ABS(pw->paint.region.scaleX);
1616 double sy = ABS(pw->paint.region.scaleY);
1617
1618 sx = MIN(sx, sy);
1619
1620 pw->paint.region.scaleX = SIGN(pw->paint.region.scaleX) * sx;
1621 pw->paint.region.scaleY = SIGN(pw->paint.region.scaleY) * sx;
1622 }
1623 MKMAT(pw);
1624 createVtxPts(pw, nvtx, True, False);
1625
1626 fp = pw->paint.region.fixedPoint;
1627 dx = ovtx[fp][0] - nvtx[fp][0];
1628 dy = ovtx[fp][1] - nvtx[fp][1];
1629
1630 pw->paint.region.centerX += dx;
1631 pw->paint.region.centerY += dy;
1632
1633 pw->paint.region.needResize = True;
1634 regionRedraw(pw);
1635 }
1636
1637 /*
1638 * Copy alpha channel of region to paint canvas, taking mask into account
1639 * Create alpha channel of region, if non existent and needed by canvas.
1640 */
1641 static void
writeRegionAlphaChannel(PaintWidget pw)1642 writeRegionAlphaChannel(PaintWidget pw)
1643 {
1644 int i, j, x, y, x0, x1, y0, y1;
1645 pwMatrix inv;
1646 double sx, sy, dx, dy, cx, cy;
1647 PaintWidget tpw = (pw->paint.paint) ? (PaintWidget)pw->paint.paint : pw;
1648
1649 if (!tpw->paint.current.alpha && !tpw->paint.region.alpha) return;
1650
1651 if (!tpw->paint.region.alpha) {
1652 i = pw->paint.region.orig.width * pw->paint.region.orig.height;
1653 tpw->paint.region.alpha = (unsigned char *) XtMalloc(i);
1654 memset(tpw->paint.region.alpha, (unsigned char)Global.alpha_bg, i);
1655 }
1656
1657 if (!tpw->paint.current.alpha) {
1658 i = tpw->paint.drawWidth * tpw->paint.drawHeight;
1659 tpw->paint.current.alpha = (unsigned char *) XtMalloc(i);
1660 memset(tpw->paint.current.alpha, (unsigned char)Global.alpha_bg, i);
1661 }
1662
1663 if (pw->paint.region.mask != None && pw->paint.region.maskImg == NULL) {
1664 pw->paint.region.maskImg = XGetImage(XtDisplay(pw),
1665 pw->paint.region.mask, 0, 0,
1666 pw->paint.region.orig.width,
1667 pw->paint.region.orig.height, AllPlanes, ZPixmap);
1668 }
1669
1670 INVERT_MAT(pw->paint.region.mat, inv);
1671
1672 cx = (pw->paint.region.orig.width+1) * 0.5;
1673 cy = (pw->paint.region.orig.height+1) * 0.5;
1674 dx = pw->paint.region.rect.x + pw->paint.region.orig.width * 0.5;
1675 dy = pw->paint.region.rect.y + pw->paint.region.orig.height * 0.5;
1676
1677 XFORM(-cx, -cy, pw->paint.region.mat, sx, sy);
1678 x1 = x0 = (int)(sx + dx + 0.5);
1679 y1 = y0 = (int)(sy + dy + 0.5);
1680 XFORM(cx, -cy, pw->paint.region.mat, sx, sy);
1681 i = (int)(sx + dx + 0.5);
1682 j = (int)(sy + dy + 0.5);
1683 if (i<x0) x0 = i; if (i>x1) x1 = i;
1684 if (j<y0) y0 = j; if (j>y1) y1 = j;
1685 XFORM(-cx, cy, pw->paint.region.mat, sx, sy);
1686 i = (int)(sx + dx + 0.5);
1687 j = (int)(sy + dy + 0.5);
1688 if (i<x0) x0 = i; if (i>x1) x1 = i;
1689 if (j<y0) y0 = j; if (j>y1) y1 = j;
1690 XFORM(cx, cy, pw->paint.region.mat, sx, sy);
1691 i = (int)(sx + dx + 0.5);
1692 j = (int)(sy + dy + 0.5);
1693 if (i<x0) x0 = i; if (i>x1) x1 = i;
1694 if (j<y0) y0 = j; if (j>y1) y1 = j;
1695 if (x0>=pw->paint.drawWidth || y0>=pw->paint.drawHeight) return;
1696 if (x1<0 || y1<0) return;
1697 if (x0<0) x0 = 0;
1698 if (y0<0) y0 = 0;
1699 if (x1>=pw->paint.drawWidth) x1 = pw->paint.drawWidth-1;
1700 if (y1>=pw->paint.drawHeight) y1 = pw->paint.drawHeight-1;
1701
1702 for (y=y0; y<=y1; y++)
1703 for (x=x0; x<=x1; x++) {
1704 XFORM((x-dx), (y-dy), inv, sx, sy);
1705 i = (int)(sx + cx);
1706 j = (int)(sy + cy);
1707 if (i>=0 && i<pw->paint.region.orig.width &&
1708 j>=0 && j<pw->paint.region.orig.height) {
1709 if (pw->paint.region.mask == None ||
1710 XGetPixel(pw->paint.region.maskImg, i, j)) {
1711 tpw->paint.current.alpha[x+y*tpw->paint.drawWidth] =
1712 tpw->paint.region.alpha[i+j*pw->paint.region.orig.width];
1713 }
1714 }
1715 }
1716 }
1717
1718 /*
1719 **
1720 **
1721 */
1722 static void
writeRegion(PaintWidget pw)1723 writeRegion(PaintWidget pw)
1724 {
1725 GC gc;
1726 AlphaPixmap pix;
1727 Pixmap src;
1728 XRectangle nr;
1729 int zoom = GET_ZOOM(pw);
1730
1731 if (!pw->paint.region.isVisible)
1732 return;
1733
1734 /* Write alpha channel first, if any */
1735 writeRegionAlphaChannel(pw);
1736
1737 /*
1738 ** No need to write it, it's still on the drawable.
1739 */
1740 if (pw->paint.region.isAttached)
1741 return;
1742
1743 nr.x = pw->paint.region.rect.x;
1744 nr.y = pw->paint.region.rect.y;
1745 if (zoom>0) {
1746 nr.width = pw->paint.region.rect.width / zoom;
1747 nr.height = pw->paint.region.rect.height / zoom;
1748 } else {
1749 nr.width = pw->paint.region.rect.width * (-zoom);
1750 nr.height = pw->paint.region.rect.height * (-zoom);
1751 }
1752
1753 /*
1754 ** If we've already modified the background (aka ripped the
1755 ** image up) then don't get a new undo buffer.
1756 ** The second case of the if is if you've done an undo in between.
1757 */
1758 if (pw->paint.region.undo_alphapix.pixmap == None ||
1759 pw->paint.region.undo_alphapix.pixmap != GET_PIXMAP(pw))
1760 pix = PwUndoStart((Widget) pw, &nr);
1761 else
1762 pix = pw->paint.region.undo_alphapix;
1763
1764 PwUndoAddRectangle((Widget) pw, &nr);
1765
1766 if (pw->paint.region.fg_gc != None) {
1767 gc = pw->paint.region.fg_gc;
1768 XSetClipOrigin(XtDisplay(pw), gc, nr.x, nr.y);
1769 } else {
1770 gc = pw->paint.tgc;
1771 }
1772
1773 if (pw->paint.region.proc != NULL) {
1774 XImage *sim = pw->paint.region.sourceImg;
1775 Boolean made = False;
1776
1777 if (sim == NULL) {
1778 sim = XGetImage(XtDisplay(pw),
1779 pw->paint.region.source, 0, 0,
1780 pw->paint.region.orig.width,
1781 pw->paint.region.orig.height, AllPlanes, ZPixmap);
1782 made = True;
1783 }
1784
1785 src = (*pw->paint.region.proc) ((Widget) pw, sim, pw->paint.region.mat);
1786 if (made)
1787 XDestroyImage(sim);
1788 } else {
1789 src = pw->paint.region.source;
1790 }
1791
1792 XCopyArea(XtDisplay(pw), src, pix.pixmap, gc,
1793 0, 0,
1794 nr.width, nr.height,
1795 nr.x, nr.y);
1796
1797 if (pw->paint.region.fg_gc != None)
1798 XSetClipOrigin(XtDisplay(pw), gc, 0, 0);
1799
1800 PwUpdate((Widget) pw, &nr, False);
1801 }
1802
1803 /*
1804 ** Called when the parent widgets zoom factor changes
1805 */
1806 static int
zoomScaling(int val,int z1,int z2)1807 zoomScaling(int val, int z1, int z2)
1808 {
1809 if (z2>0) val *= z2;
1810 if (z1<0) val *= -z1;
1811 if (z2<0) val = (val-z2-1)/(-z2);
1812 if (z1>0) val = (val+z1-1)/z1;
1813 return val;
1814 }
1815
1816 static void
zoomValueChanged(Widget w,XtPointer junk1,XtPointer junk2)1817 zoomValueChanged(Widget w, XtPointer junk1, XtPointer junk2)
1818 {
1819 PaintWidget pw = (PaintWidget) w;
1820 int zoom, curZoom;
1821 int nx, ny;
1822 int nw, nh;
1823
1824 zoom = GET_ZOOM(pw);
1825 curZoom = pw->paint.region.curZoom;
1826
1827 if (zoom == curZoom)
1828 return;
1829
1830 if (!pw->paint.region.isVisible)
1831 return;
1832
1833 if (zoom>0) {
1834 nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
1835 ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
1836 } else {
1837 nx = (pw->paint.region.rect.x - pw->paint.zoomX) / (-zoom);
1838 ny = (pw->paint.region.rect.y - pw->paint.zoomY) / (-zoom);
1839 }
1840 nw = zoomScaling(pw->paint.region.rect.width, curZoom, zoom);
1841 pw->paint.region.rect.width = nw;
1842 nh = zoomScaling(pw->paint.region.rect.height, curZoom, zoom);
1843 pw->paint.region.rect.height = nh;
1844
1845 pw->paint.region.curZoom = zoom;
1846
1847 XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
1848 XtResizeWidget(pw->paint.region.child, nw, nh, BW);
1849
1850 pw->paint.region.needResize = True;
1851 moveGrips(pw);
1852 regionRedraw(pw);
1853 }
1854
1855 void
PwRegionZoomPosChanged(PaintWidget pw)1856 PwRegionZoomPosChanged(PaintWidget pw)
1857 {
1858 int nx, ny;
1859 int zoom;
1860
1861 if (!pw->paint.region.isVisible)
1862 return;
1863
1864 zoom = GET_ZOOM(pw);
1865
1866 if (zoom>0) {
1867 nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
1868 ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
1869 } else {
1870 nx = (pw->paint.region.rect.x - pw->paint.zoomX) / (-zoom);
1871 ny = (pw->paint.region.rect.y - pw->paint.zoomY) / (-zoom);
1872 }
1873
1874 XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
1875 }
1876
1877
1878 static void
writeCleanRegion(PaintWidget pw,Boolean flag,Boolean write)1879 writeCleanRegion(PaintWidget pw, Boolean flag, Boolean write)
1880 {
1881 if (!pw->paint.region.isVisible)
1882 return;
1883
1884 if (write)
1885 writeRegion(pw);
1886
1887 /*
1888 ** Free up temporary images
1889 */
1890 if (pw->paint.region.sourceImg != NULL)
1891 XDestroyImage(pw->paint.region.sourceImg);
1892 if (pw->paint.region.maskImg != NULL)
1893 XDestroyImage(pw->paint.region.maskImg);
1894 if (pw->paint.region.alpha != NULL)
1895 free(pw->paint.region.alpha);
1896
1897 pw->paint.region.sourceImg = NULL;
1898 pw->paint.region.maskImg = NULL;
1899 pw->paint.region.alpha = NULL;
1900
1901 if (pw->paint.region.source != None) {
1902 XFreePixmap(XtDisplay(pw), pw->paint.region.source);
1903 pw->paint.region.source = None;
1904 }
1905 if (pw->paint.region.mask != None) {
1906 XFreePixmap(XtDisplay(pw), pw->paint.region.mask);
1907 pw->paint.region.mask = None;
1908 }
1909 if (pw->paint.region.notMask != None) {
1910 XFreePixmap(XtDisplay(pw), pw->paint.region.notMask);
1911 pw->paint.region.notMask = None;
1912 }
1913 if (pw->paint.region.unfilterPixmap != None) {
1914 XFreePixmap(XtDisplay(pw), pw->paint.region.unfilterPixmap);
1915 pw->paint.region.unfilterPixmap = None;
1916 }
1917
1918 pw->paint.region.undo_alphapix.pixmap = None;
1919 pw->paint.region.undo_alphapix.alpha = NULL;
1920
1921 if (flag) {
1922 if (pw->paint.region.child != None)
1923 XtUnmapWidget(pw->paint.region.child);
1924 pw->paint.region.isVisible = False;
1925 }
1926 }
1927
1928 /* Turn off the selected region after writing it to the background.
1929 * flag == True for all widgets
1930 */
1931 void
PwRegionFinish(Widget w,Boolean flag)1932 PwRegionFinish(Widget w, Boolean flag)
1933 {
1934 PaintWidget pw = (PaintWidget) w;
1935 PaintWidget pp = (PaintWidget) pw->paint.paint;
1936 PaintWidget tpw;
1937 int i;
1938
1939 if (flag) {
1940 tpw = (pp) ? pp : pw;
1941 writeCleanRegion(tpw, True, True);
1942 for (i = 0; i < tpw->paint.paintChildrenSize; i++)
1943 writeCleanRegion((PaintWidget) tpw->paint.paintChildren[i], True, True);
1944 doCallbacks(pw, False);
1945 } else {
1946 writeCleanRegion(pw, True, True);
1947 }
1948 }
1949
1950 /*
1951 * Turn off the selected region, but do not write it to the background.
1952 * Return False if no region, else True.
1953 * flag == True for all widgets
1954 */
1955 Boolean
PwRegionOff(Widget w,Boolean flag)1956 PwRegionOff(Widget w, Boolean flag)
1957 {
1958 PaintWidget pw = (PaintWidget) w;
1959 PaintWidget pp = (PaintWidget) pw->paint.paint;
1960 PaintWidget tpw;
1961 int i;
1962
1963 tpw = pw;
1964 if (flag)
1965 tpw = (pp) ? pp : pw;
1966
1967 if (!tpw->paint.region.isVisible)
1968 return False;
1969
1970 writeCleanRegion(tpw, True, False);
1971 if (flag) {
1972 for (i = 0; i < tpw->paint.paintChildrenSize; i++)
1973 writeCleanRegion((PaintWidget) tpw->paint.paintChildren[i], True, False);
1974 doCallbacks(pw, False);
1975 }
1976 return True;
1977 }
1978
1979 /* Set the region pixmap, and mask */
1980 void
PwRegionSet(Widget w,XRectangle * rect,Pixmap pix,Pixmap mask)1981 PwRegionSet(Widget w, XRectangle * rect, Pixmap pix, Pixmap mask)
1982 {
1983 PaintWidget pw = (PaintWidget) w;
1984 PaintWidget tpw = (pw->paint.paint)? (PaintWidget)pw->paint.paint : pw;
1985 int i, j, k1, k2, l1, l2;
1986 int nx, ny, x, y, width, height;
1987 int zoom = GET_ZOOM(pw);
1988 Boolean setIsAttached = False;
1989
1990
1991 /*
1992 ** If there is an image, write it
1993 ** rect == NULL, then this is just a "write" & "unmap" request
1994 */
1995 PwRegionFinish(w, True);
1996
1997 if (pw->paint.region.sourceImg) {
1998 XDestroyImage(pw->paint.region.sourceImg);
1999 pw->paint.region.sourceImg = NULL;
2000 }
2001 if (rect == NULL)
2002 return;
2003
2004 pw->paint.region.curZoom = zoom;
2005 XtVaSetValues(w, XtNtransparent, 0, NULL);
2006
2007 if (zoom>0) {
2008 x = (rect->x + pw->paint.zoomX) * zoom;
2009 y = (rect->y + pw->paint.zoomY) * zoom;
2010 width = rect->width * zoom;
2011 height = rect->height * zoom;
2012 } else {
2013 x = (rect->x + pw->paint.zoomX) / (-zoom);
2014 y = (rect->y + pw->paint.zoomY) / (-zoom);
2015 width = rect->width / (-zoom);
2016 height = rect->height / (-zoom);
2017 }
2018
2019 /*
2020 ** A little "initializing"
2021 */
2022 pw->paint.region.isDrawn = False;
2023 pw->paint.region.isTracking = False;
2024 pw->paint.region.needResize = False;
2025 pw->paint.region.unfilterPixmap = None;
2026
2027 pw->paint.region.rect = *rect;
2028
2029 if (pix == None) {
2030 setIsAttached = True;
2031
2032 if (rect->x < 0) {
2033 rect->width += rect->x;
2034 rect->x = 0;
2035 }
2036 if (rect->y < 0) {
2037 rect->height += rect->y;
2038 rect->y = 0;
2039 }
2040 if (rect->x+rect->width > pw->paint.drawWidth)
2041 rect->width = pw->paint.drawWidth-rect->x;
2042 if (rect->y+rect->height > pw->paint.drawHeight)
2043 rect->height = pw->paint.drawHeight-rect->y;
2044
2045 pw->paint.region.source = XCreatePixmap(XtDisplay(pw), XtWindow(pw),
2046 rect->width, rect->height,
2047 pw->core.depth);
2048 XCopyArea(XtDisplay(pw), GET_PIXMAP(pw), pw->paint.region.source,
2049 pw->paint.gc,
2050 rect->x, rect->y,
2051 rect->width, rect->height,
2052 0, 0);
2053 } else {
2054 pw->paint.region.source = pix;
2055 }
2056
2057 PwUndoStart((Widget) pw, rect);
2058 PwUndoAddRectangle((Widget) pw, rect);
2059
2060 pw->paint.region.mask = mask;
2061 pw->paint.region.orig = *rect;
2062
2063 /*
2064 * import alpha channel from PaintWidget
2065 */
2066 if (setIsAttached && tpw->paint.current.alpha) {
2067 if (pw->paint.region.mask == None)
2068 pw->paint.region.maskImg = NULL;
2069 else
2070 pw->paint.region.maskImg = XGetImage(XtDisplay(pw),
2071 pw->paint.region.mask, 0, 0,
2072 pw->paint.region.orig.width,
2073 pw->paint.region.orig.height, AllPlanes, ZPixmap);
2074 i = rect->width * rect->height;
2075 tpw->paint.region.alpha = (unsigned char *) XtMalloc(i);
2076 memset(tpw->paint.region.alpha, (unsigned char)Global.alpha_bg, i);
2077 k1 = -pw->paint.region.rect.x;
2078 if (k1<0) k1 = 0;
2079 k2 = pw->paint.region.orig.width;
2080 if (k2>(i=pw->paint.drawWidth-pw->paint.region.rect.x)) k2 = i;
2081 l1 = -pw->paint.region.rect.y;
2082 if (l1<0) l1 = 0;
2083 l2 = pw->paint.region.orig.height;
2084 if (l2>(i=pw->paint.drawHeight-pw->paint.region.rect.y)) l2 = i;
2085 if (k1<k2 && l1<l2)
2086 for (y=l1; y<l2; y++) {
2087 i = y * pw->paint.region.orig.width;
2088 j = pw->paint.region.rect.x +
2089 pw->paint.drawWidth*(y+pw->paint.region.rect.y);
2090 if (pw->paint.region.mask != None) {
2091 for (x=k1; x<k2; x++) {
2092 if (XGetPixel(pw->paint.region.maskImg, x, y)) {
2093 tpw->paint.region.alpha[x+i] = tpw->paint.current.alpha[x+j];
2094 if (setIsAttached)
2095 tpw->paint.current.alpha[x+j] =
2096 (unsigned char) Global.alpha_bg;
2097 }
2098 }
2099 } else {
2100 memcpy(tpw->paint.region.alpha+i+k1, tpw->paint.current.alpha+j+k1, k2-k1);
2101 if (setIsAttached)
2102 memset(tpw->paint.current.alpha+j+k1,
2103 (unsigned char) Global.alpha_bg, k2-k1);
2104 }
2105 }
2106 }
2107
2108 /*
2109 ** If there is a clipping mask, create a fg and bg GC with clip-masks
2110 ** to draw through.
2111 */
2112 if (mask != None) {
2113
2114 if (pw->paint.region.fg_gc == None) {
2115 pw->paint.region.fg_gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
2116 pw->paint.region.bg_gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, 0);
2117 }
2118 /*
2119 ** Make sure the Mask GC is built.
2120 */
2121 GET_MGC(pw, mask);
2122 regionCreateNotMask(pw);
2123 } else {
2124 /*
2125 ** No clip mask, make sure we aren't using one.
2126 */
2127 if (pw->paint.region.fg_gc != None) {
2128 XSetClipMask(XtDisplay(w), pw->paint.region.fg_gc, None);
2129 XSetClipMask(XtDisplay(w), pw->paint.region.bg_gc, None);
2130 }
2131 }
2132
2133 if (pw->paint.region.child == None) {
2134 pw->paint.region.child = XtVaCreateWidget("region",
2135 compositeWidgetClass, w,
2136 XtNborderWidth, BW,
2137 NULL);
2138 XtAddEventHandler(pw->paint.region.child, ButtonPressMask,
2139 False,
2140 (XtEventHandler) regionButtonPress,
2141 (XtPointer) pw);
2142 XtAddEventHandler(pw->paint.region.child, ButtonReleaseMask,
2143 False,
2144 (XtEventHandler) regionButtonRelease,
2145 (XtPointer) pw);
2146 XtAddEventHandler(pw->paint.region.child, ButtonMotionMask,
2147 False,
2148 (XtEventHandler) regionGrab,
2149 (XtPointer) pw);
2150 XtAddEventHandler(pw->paint.region.child, ExposureMask,
2151 False,
2152 (XtEventHandler) PwRegionExpose,
2153 (XtPointer) pw);
2154 XtAddEventHandler(pw->paint.region.child, StructureNotifyMask,
2155 False,
2156 (XtEventHandler) regionMove,
2157 (XtPointer) pw);
2158 XtAddCallback((Widget) pw, XtNsizeChanged,
2159 (XtCallbackProc) zoomValueChanged, (XtPointer) NULL);
2160 XtVaSetValues(pw->paint.region.child, XtNx, x, XtNy, y,
2161 XtNwidth, width, XtNheight, height, NULL);
2162 XtManageChild(pw->paint.region.child);
2163 XDefineCursor(XtDisplay(w), XtWindow(pw->paint.region.child),
2164 XCreateFontCursor(XtDisplay(w), XC_fleur));
2165
2166 for (i = 0; i < 9; i++) {
2167 if (i == 4)
2168 continue;
2169
2170 pw->paint.region.grip[i] =
2171 XtVaCreateManagedWidget("grip",
2172 gripWidgetClass, pw->paint.region.child,
2173 XtNwidth, 6, XtNheight, 6, NULL);
2174
2175 XtAddEventHandler(pw->paint.region.grip[i], ButtonPressMask,
2176 False,
2177 (XtEventHandler) gripPress,
2178 (XtPointer) pw);
2179 XtAddEventHandler(pw->paint.region.grip[i], ButtonMotionMask,
2180 False,
2181 (XtEventHandler) gripGrab,
2182 (XtPointer) pw);
2183 XtAddEventHandler(pw->paint.region.grip[i], ButtonReleaseMask,
2184 False,
2185 (XtEventHandler) gripRelease,
2186 (XtPointer) pw);
2187 }
2188 regionSetGripCursors(pw);
2189 pw->paint.region.isVisible = True;
2190 } else {
2191 XClearArea(XtDisplay(pw), XtWindow(pw->paint.region.child),
2192 0, 0, 0, 0, True);
2193 }
2194
2195 if (setIsAttached) {
2196 nx = rect->x;
2197 ny = rect->y;
2198 } else {
2199 nx = pw->paint.downX;
2200 ny = pw->paint.downY;
2201 }
2202 pw->paint.region.rect.x = nx;
2203 pw->paint.region.rect.y = ny;
2204 nx -= pw->paint.zoomX;
2205 ny -= pw->paint.zoomY;
2206 if (zoom>0)
2207 XtVaSetValues(pw->paint.region.child, XtNx, nx * zoom - BW,
2208 XtNy, ny * zoom - BW,
2209 XtNwidth, width,
2210 XtNheight, height,
2211 NULL);
2212 else
2213 XtVaSetValues(pw->paint.region.child, XtNx, nx / (-zoom) - BW,
2214 XtNy, ny / (-zoom) - BW,
2215 XtNwidth, width,
2216 XtNheight, height,
2217 NULL);
2218
2219 pw->paint.region.scaleX = 1.0;
2220 pw->paint.region.scaleY = 1.0;
2221 pw->paint.region.centerX = pw->paint.region.orig.width / 2;
2222 pw->paint.region.centerY = pw->paint.region.orig.height / 2;
2223 COPY_MAT(matIdentity, pw->paint.region.rotMat);
2224 MKMAT(pw);
2225
2226 if (zoom > 1) {
2227 pw->paint.region.rect.width *= zoom;
2228 pw->paint.region.rect.height *= zoom;
2229 }
2230 if (zoom < -1) {
2231 pw->paint.region.rect.width =
2232 (pw->paint.region.rect.width-zoom-1) / (-zoom);
2233 pw->paint.region.rect.height =
2234 (pw->paint.region.rect.height-zoom-1) / (-zoom);
2235 }
2236 moveGrips(pw);
2237
2238 if (!pw->paint.region.isVisible) {
2239 XtMapWidget(pw->paint.region.child);
2240 XSync(XtDisplay(pw), False);
2241 pw->paint.region.isVisible = True;
2242 }
2243 #ifdef SHAPE
2244 XShapeCombineMask(XtDisplay(pw), XtWindow(pw->paint.region.child),
2245 ShapeBounding, 0, 0, None, ShapeSet);
2246 #endif
2247
2248 pw->paint.region.isAttached = setIsAttached;
2249 doCallbacks(pw, True);
2250 }
2251
2252 static PaintWidget
getActiveRegion(PaintWidget pw)2253 getActiveRegion(PaintWidget pw)
2254 {
2255 PaintWidget tpw = (pw->paint.paint) ? (PaintWidget) pw->paint.paint : pw;
2256 int i;
2257
2258 if (pw->paint.region.isVisible && pw->paint.region.source != None)
2259 return pw;
2260
2261 if (tpw->paint.region.isVisible && tpw->paint.region.source != None)
2262 return tpw;
2263
2264 for (i = 0; i < tpw->paint.paintChildrenSize; i++) {
2265 PaintWidget p = (PaintWidget) tpw->paint.paintChildren[i];
2266 if (p->paint.region.source != None)
2267 return p;
2268 }
2269
2270 return None;
2271 }
2272
2273 /* Set the foreground pixmap, changing it in place */
2274 void
PwRegionSetRawPixmap(Widget w,Pixmap pix)2275 PwRegionSetRawPixmap(Widget w, Pixmap pix)
2276 {
2277 PaintWidget pw = getActiveRegion((PaintWidget) w);
2278
2279 if (pw == None)
2280 return;
2281
2282 XFreePixmap(XtDisplay(pw), pw->paint.region.source);
2283
2284 if (pw->paint.region.sourceImg != NULL) {
2285 XDestroyImage(pw->paint.region.sourceImg);
2286 pw->paint.region.sourceImg = NULL;
2287 }
2288 pw->paint.region.source = pix;
2289
2290 doResize(pw);
2291 regionRedraw(pw);
2292 }
2293
2294 /* Get a copy of the current image & mask, True if exist */
2295 Boolean
PwRegionGet(Widget w,Pixmap * pix,Pixmap * mask)2296 PwRegionGet(Widget w, Pixmap * pix, Pixmap * mask)
2297 {
2298 Display *dpy = XtDisplay(w);
2299 Window win = XtWindow(w);
2300 PaintWidget pw = getActiveRegion((PaintWidget) w);
2301 Pixmap myMask = None, notMask = None;
2302 int zoom;
2303 int width, height;
2304
2305 if (pw == None)
2306 return False;
2307 zoom = GET_ZOOM(pw);
2308 width = pw->paint.region.orig.width;
2309 height = pw->paint.region.orig.height;
2310
2311 if (pix) *pix = None;
2312 if (mask) *mask = None;
2313
2314 if (pw->paint.region.source != None && pix != NULL) {
2315 *pix = XCreatePixmap(dpy, win, width, height, pw->core.depth);
2316 if (pw->paint.region.sourceImg != NULL) {
2317 XPutImage(dpy, *pix, pw->paint.tgc,
2318 pw->paint.region.sourceImg,
2319 0, 0, 0, 0, width, height);
2320 } else {
2321 XCopyArea(dpy, pw->paint.region.source,
2322 *pix, pw->paint.tgc,
2323 0, 0, width, height, 0, 0);
2324 }
2325 }
2326 if (pw->paint.region.mask != None) {
2327 myMask = XCreatePixmap(dpy, win, width, height, 1);
2328 notMask = XCreatePixmap(dpy, win, width, height, 1);
2329
2330 if (pw->paint.region.maskImg != NULL) {
2331 XPutImage(dpy, myMask, pw->paint.mgc,
2332 pw->paint.region.maskImg,
2333 0, 0, 0, 0, width, height);
2334 } else {
2335 XCopyArea(dpy, pw->paint.region.mask,
2336 myMask, pw->paint.mgc,
2337 0, 0, width, height, 0, 0);
2338 }
2339
2340 XSetFunction(dpy, pw->paint.mgc, GXcopyInverted);
2341 XCopyArea(dpy, myMask, notMask, pw->paint.mgc, 0, 0,
2342 width, height, 0, 0);
2343 XSetFunction(dpy, pw->paint.mgc, GXcopy);
2344
2345 if (mask == NULL)
2346 XFreePixmap(dpy, myMask);
2347 else
2348 *mask = myMask;
2349 }
2350 if (notMask != None && pix != NULL) {
2351 XSetClipOrigin(dpy, pw->paint.igc, 0, 0);
2352 XSetClipMask(XtDisplay(pw), pw->paint.igc, notMask);
2353 XFillRectangle(XtDisplay(pw), *pix, pw->paint.igc, 0, 0,
2354 width, height);
2355 XSync(XtDisplay(w), False);
2356 XSetClipMask(XtDisplay(pw), pw->paint.igc, None);
2357
2358 }
2359 if (notMask != None)
2360 XFreePixmap(dpy, notMask);
2361
2362 return True;
2363 }
2364
2365 /* Clear the region to the current background color */
2366 void
PwRegionClear(Widget w)2367 PwRegionClear(Widget w)
2368 {
2369 PaintWidget pw = getActiveRegion((PaintWidget) w);
2370
2371 if (pw == None)
2372 return;
2373
2374 PwRegionTear(w);
2375
2376 pw->paint.region.isVisible = False;
2377 if (pw->paint.region.child != None)
2378 XtUnmapWidget(pw->paint.region.child);
2379 doCallbacks(pw, False);
2380 }
2381
2382 void
PwRegionTear(Widget w)2383 PwRegionTear(Widget w)
2384 {
2385 PaintWidget pw;
2386 XRectangle nr;
2387 int zoom;
2388
2389 pw = getActiveRegion((PaintWidget) w);
2390
2391 if (pw == None)
2392 return;
2393 if (!pw->paint.region.isAttached || !pw->paint.region.isVisible)
2394 return;
2395
2396 zoom = GET_ZOOM(pw);
2397 nr = pw->paint.region.rect;
2398
2399 if (zoom>0) {
2400 nr.width = (nr.width+zoom-1)/zoom;
2401 nr.height = (nr.height+zoom-1)/zoom;
2402 } else {
2403 nr.width *= (-zoom);
2404 nr.height *= (-zoom);
2405 }
2406
2407 pw->paint.region.undo_alphapix = PwUndoStart((Widget) pw, &nr);
2408
2409 if (pw->paint.region.mask != None) {
2410 XSetClipOrigin(XtDisplay(pw), pw->paint.igc, nr.x, nr.y);
2411 XSetClipMask(XtDisplay(pw), pw->paint.igc, pw->paint.region.mask);
2412 }
2413
2414 XFillRectangles(XtDisplay(pw), pw->paint.region.undo_alphapix.pixmap,
2415 pw->paint.igc, &nr, 1);
2416
2417 PwUpdate((Widget) pw, &nr, True);
2418
2419 if (pw->paint.region.mask != None) {
2420 XSetClipOrigin(XtDisplay(pw), pw->paint.igc, 0, 0);
2421 XSetClipMask(XtDisplay(pw), pw->paint.igc, None);
2422 }
2423
2424 pw->paint.region.isAttached = False;
2425 }
2426
2427 /* Append a transformation matrix to the current transform */
2428 void
PwRegionAppendMatrix(Widget w,pwMatrix mat)2429 PwRegionAppendMatrix(Widget w, pwMatrix mat)
2430 {
2431 PaintWidget pw = getActiveRegion((PaintWidget) w);
2432
2433 if (pw == None)
2434 return;
2435
2436 PwRegionTear((Widget) pw);
2437
2438 mm(pw->paint.region.rotMat, mat, pw->paint.region.rotMat);
2439 MKMAT(pw);
2440
2441 pw->paint.region.needResize = True;
2442 regionResizeWindow(pw, False);
2443 regionRedraw(pw);
2444 }
2445
2446 /* Set the current transformation matrix */
2447 void
PwRegionSetMatrix(Widget w,pwMatrix mat)2448 PwRegionSetMatrix(Widget w, pwMatrix mat)
2449 {
2450 PaintWidget pw = getActiveRegion((PaintWidget) w);
2451
2452 if (pw == None)
2453 return;
2454
2455 PwRegionTear((Widget) pw);
2456
2457 COPY_MAT(mat, pw->paint.region.rotMat);
2458 MKMAT(pw);
2459
2460 pw->paint.region.needResize = True;
2461 regionResizeWindow(pw, False);
2462 regionRedraw(pw);
2463 }
2464
2465 /* Append the current values to the scale */
2466 void
PwRegionAddScale(Widget w,double * xs,double * ys)2467 PwRegionAddScale(Widget w, double *xs, double *ys)
2468 {
2469 PaintWidget pw = getActiveRegion((PaintWidget) w);
2470
2471 if (pw == None)
2472 return;
2473
2474 PwRegionTear((Widget) pw);
2475
2476 if (xs != NULL)
2477 pw->paint.region.scaleX *= *xs;
2478 if (ys != NULL)
2479 pw->paint.region.scaleY *= *ys;
2480
2481 MKMAT(pw);
2482
2483 pw->paint.region.needResize = True;
2484 regionResizeWindow(pw, False);
2485 regionRedraw(pw);
2486 }
2487
2488 /* Set the current X & Y scale values */
2489 void
PwRegionSetScale(Widget w,double * xs,double * ys)2490 PwRegionSetScale(Widget w, double *xs, double *ys)
2491 {
2492 PaintWidget pw = getActiveRegion((PaintWidget) w);
2493
2494 if (pw == None)
2495 return;
2496
2497 if (xs != NULL)
2498 pw->paint.region.scaleX = *xs;
2499 if (ys != NULL)
2500 pw->paint.region.scaleY = *ys;
2501
2502 MKMAT(pw);
2503
2504 pw->paint.region.needResize = True;
2505 regionResizeWindow(pw, False);
2506 regionRedraw(pw);
2507 }
2508
2509 /* Reset both the rotation and scale back to identity */
2510 void
PwRegionReset(Widget w,Boolean flag)2511 PwRegionReset(Widget w, Boolean flag)
2512 {
2513 PaintWidget pw = getActiveRegion((PaintWidget) w);
2514 pwMatrix mat;
2515
2516 if (pw == None)
2517 return;
2518
2519 PwRegionTear((Widget) pw);
2520
2521 mat[0][0] = mat[1][1] = 1;
2522 mat[1][0] = mat[0][1] = 0;
2523
2524 COPY_MAT(mat, pw->paint.region.rotMat);
2525 pw->paint.region.scaleY = 1.0;
2526 pw->paint.region.scaleX = 1.0;
2527 MKMAT(pw);
2528
2529 pw->paint.region.needResize = True;
2530 regionResizeWindow(pw, False);
2531 regionRedraw(pw);
2532
2533 /* XXX flag should reset X & Y position as well */
2534 }
2535
2536 /*
2537 * Crop to region: replaces the image with the region.
2538 */
2539 void
RegionCrop(PaintWidget paint)2540 RegionCrop(PaintWidget paint)
2541 {
2542 PaintWidget pw = getActiveRegion(paint);
2543 Pixmap pix;
2544
2545
2546 StateSetBusy(True);
2547
2548 if (!PwRegionGet((Widget) paint, &pix, None)) {
2549 StateSetBusy(False);
2550 return; /* No region selected */
2551 }
2552 pw->paint.dirty = True;
2553
2554 /* Make the region inactive */
2555 PwRegionFinish((Widget) paint, True);
2556
2557 XtVaSetValues((Widget) paint,
2558 XtNpixmap, pix,
2559 XtNdrawWidth, pw->paint.region.orig.width,
2560 XtNdrawHeight, pw->paint.region.orig.height,
2561 NULL);
2562
2563 PwUpdateDrawable((Widget) paint, XtWindow(paint), NULL);
2564 StateSetBusy(False);
2565 }
2566
2567 void
RegionMove(PaintWidget pw,int dx,int dy)2568 RegionMove(PaintWidget pw, int dx, int dy)
2569 {
2570 int nx, ny;
2571 int zoom = GET_ZOOM(pw);
2572
2573 if (getActiveRegion(pw) == None)
2574 return;
2575
2576 PwRegionTear((Widget) pw);
2577
2578 pw->paint.region.rect.x += dx;
2579 pw->paint.region.rect.y += dy;
2580 if (zoom>0) {
2581 nx = (pw->paint.region.rect.x - pw->paint.zoomX) * zoom;
2582 ny = (pw->paint.region.rect.y - pw->paint.zoomY) * zoom;
2583 } else {
2584 nx = (pw->paint.region.rect.x - pw->paint.zoomX) / (-zoom);
2585 ny = (pw->paint.region.rect.y - pw->paint.zoomY) / (-zoom);
2586 }
2587
2588 XtMoveWidget(pw->paint.region.child, nx - BW, ny - BW);
2589 drawRegionBox(pw, False);
2590 }
2591