Graphics.c revision cbc4e2be
1/*
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * Author:  Davor Matic, MIT X Consortium
31 */
32
33#ifdef HAVE_CONFIG_H
34# include "config.h"
35#endif
36
37#include <X11/IntrinsicP.h>
38#include <X11/StringDefs.h>
39#include <X11/Xfuncs.h>
40#include "BitmapP.h"
41#include "Bitmap.h"
42#include "Requests.h"
43
44#include <stdio.h>
45#include <math.h>
46
47#ifndef abs
48#define abs(x)                        (((x) > 0) ? (x) : -(x))
49#endif
50#define min(x, y)                     (((int)(x) < (int)(y)) ? (x) : (y))
51#define max(x, y)                     (((int)(x) > (int)(y)) ? (x) : (y))
52#ifndef rint
53# if HAVE_LRINT
54#  define rint(x)                     lrint(x)
55# else
56#  define rint(x)                     floor(x + 0.5)
57# endif
58#endif
59
60/*****************************************************************************\
61 *                                   Graphics                                *
62\*****************************************************************************/
63
64#define GetBit(image, x, y)\
65    ((bit)((*(image->data + (x) / 8 + (y) * image->bytes_per_line) &\
66	    (1 << ((x) % 8))) ? 1 : 0))
67
68#if 0
69bit
70BWGetBit(Widget w, Position x, Position y)
71{
72    BitmapWidget BW = (BitmapWidget) w;
73
74    if (QueryInBitmap(BW, x, y))
75	return GetBit(BW->bitmap.image, x, y);
76    else
77	return NotSet;
78}
79#endif
80
81#define InvertBit(image, x, y)\
82    (*(image->data + (x) / 8 + (y) * image->bytes_per_line) ^=\
83     (bit) (1 << ((x) % 8)))
84
85
86#define SetBit(image, x, y)\
87    (*(image->data + (x) / 8 + (y) * image->bytes_per_line) |=\
88     (bit) (1 << ((x) % 8)))
89
90#define ClearBit(image, x, y)\
91    (*(image->data + (x) / 8 + (y) * image->bytes_per_line) &=\
92     (bit)~(1 << ((x) % 8)))
93
94
95#define HighlightSquare(BW, x, y)\
96    XFillRectangle(XtDisplay(BW), XtWindow(BW),\
97                   BW->bitmap.highlighting_gc,\
98		   InWindowX(BW, x), InWindowY(BW, y),\
99                   BW->bitmap.squareW, BW->bitmap.squareH)
100/*
101void
102HighlightSquare(BitmapWidget BW, Position x, Position y)
103{
104    XFillRectangle(XtDisplay(BW), XtWindow(BW),
105                   BW->bitmap.highlighting_gc,
106		   InWindowX(BW, x), InWindowY(BW, y),
107                   BW->bitmap.squareW, BW->bitmap.squareH);
108}
109*/
110
111#define DrawSquare(BW, x, y)\
112    XFillRectangle(XtDisplay(BW), XtWindow(BW),\
113                   BW->bitmap.drawing_gc,\
114		   InWindowX(BW, x), InWindowY(BW, y),\
115                   BW->bitmap.squareW, BW->bitmap.squareH)
116
117/*
118void
119DrawSquare(BitmapWidget BW, Position x, Position y)
120{
121    XFillRectangle(XtDisplay(BW), XtWindow(BW),
122                   BW->bitmap.drawing_gc,
123		   InWindowX(BW, x), InWindowY(BW, y),
124                   BW->bitmap.squareW, BW->bitmap.squareH);
125}
126*/
127
128#define InvertPoint(BW, x, y)\
129    {InvertBit(BW->bitmap.image, x, y); DrawSquare(BW, x, y);}
130
131#define DrawPoint(BW, x, y, value)\
132    if (GetBit(BW->bitmap.image, x, y) != value)\
133       InvertPoint(BW, x, y)
134
135void
136BWDrawPoint(Widget w, Position x, Position y, bit value)
137{
138    BitmapWidget BW = (BitmapWidget) w;
139
140    if (QueryInBitmap(BW, x, y)) {
141	if (value == Highlight)
142	    HighlightSquare(BW, x, y);
143	else
144	    DrawPoint(BW, x, y, value);
145    }
146}
147
148static XPoint *
149HotSpotShape(BitmapWidget BW, Position x, Position y)
150{
151    static XPoint points[5];
152
153    points[0].x = InWindowX(BW, x);
154    points[0].y = InWindowY(BW, y + 1.0/2);
155    points[1].x = InWindowX(BW, x + 1.0/2);
156    points[1].y = InWindowY(BW, y + 1);
157    points[2].x = InWindowX(BW, x + 1);
158    points[2].y = InWindowY(BW, y + 1.0/2);
159    points[3].x = InWindowX(BW, x + 1.0/2);
160    points[3].y = InWindowY(BW, y);
161    points[4].x = InWindowX(BW, x);
162    points[4].y = InWindowY(BW, y + 1.0/2);
163
164    return points;
165}
166
167#define DrawHotSpot(BW, x, y)\
168  XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.drawing_gc,\
169	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
170
171#define HighlightHotSpot(BW, x, y)\
172  XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,\
173	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
174
175/*
176XImage *CreateBitmapImage();
177void DestroyBitmapImage();
178*/
179
180void
181BWRedrawHotSpot(Widget w)
182{
183    BitmapWidget BW = (BitmapWidget) w;
184
185    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
186	DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
187}
188
189void
190BWClearHotSpot(Widget w)
191{
192    BitmapWidget BW = (BitmapWidget) w;
193
194    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
195      DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
196      BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
197    }
198}
199
200void
201BWDrawHotSpot(Widget w, Position x, Position y, int value)
202{
203    BitmapWidget BW = (BitmapWidget) w;
204
205    if (QueryInBitmap(BW, x, y)) {
206	if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y) &&
207	    ((BW->bitmap.hot.x == x) && (BW->bitmap.hot.y == y))) {
208	    if ((value == Clear) || (value == Invert)) {
209		BWClearHotSpot(w);
210	    }
211	}
212	else
213	    if ((value == Set) || (value == Invert)) {
214		BWClearHotSpot(w);
215		DrawHotSpot(BW, x, y);
216		BW->bitmap.hot.x = x;
217		BW->bitmap.hot.y = y;
218	    }
219
220	if (value == Highlight)
221	    HighlightHotSpot(BW, x, y);
222    }
223}
224
225void
226BWSetHotSpot(Widget w, Position x, Position y)
227{
228    if (QuerySet(x, y))
229	BWDrawHotSpot(w, x, y, Set);
230    else
231	BWClearHotSpot(w);
232}
233
234/* high level procedures */
235
236void
237BWRedrawSquares(Widget w,
238		Position x, Position y,
239		Dimension width, Dimension height)
240{
241    BitmapWidget BW = (BitmapWidget) w;
242    Position from_x = InBitmapX(BW, x);
243    Position from_y = InBitmapY(BW, y);
244    Position to_x = InBitmapX(BW, x + width);
245    Position to_y = InBitmapY(BW, y + height);
246
247    QuerySwap(from_x, to_x);
248    QuerySwap(from_y, to_y);
249    from_x = max(0, from_x);
250    from_y = max(0, from_y);
251    to_x = min(BW->bitmap.image->width - 1, to_x);
252    to_y = min(BW->bitmap.image->height - 1, to_y);
253
254    for (x = from_x; x <= to_x; x++)
255	for (y = from_y; y <= to_y; y++)
256	    if (GetBit(BW->bitmap.image, x, y)) DrawSquare(BW, x, y);
257}
258
259void
260BWDrawGrid(Widget w,
261	   Position from_x, Position from_y,
262	   Position to_x, Position to_y)
263{
264    BitmapWidget BW = (BitmapWidget) w;
265    int i;
266
267    QuerySwap(from_x, to_x);
268    QuerySwap(from_y, to_y);
269    from_x = max(0, from_x);
270    from_y = max(0, from_y);
271    to_x = min(BW->bitmap.image->width - 1, to_x);
272    to_y = min(BW->bitmap.image->height - 1, to_y);
273
274    for(i = from_x + (from_x == 0); i <= to_x; i++)
275	XDrawLine(XtDisplay(BW), XtWindow(BW),
276		  BW->bitmap.frame_gc,
277		  InWindowX(BW, i), InWindowY(BW, from_y),
278		  InWindowX(BW, i), InWindowY(BW, to_y + 1));
279
280    for(i = from_y + (from_y == 0); i <= to_y; i++)
281	XDrawLine(XtDisplay(BW), XtWindow(BW),
282		  BW->bitmap.frame_gc,
283		  InWindowX(BW, from_x), InWindowY(BW, i),
284		  InWindowX(BW, to_x + 1), InWindowY(BW, i));
285}
286
287
288void
289BWRedrawGrid(Widget w,
290	     Position x, Position y,
291	     Dimension width, Dimension height)
292{
293    BitmapWidget BW = (BitmapWidget) w;
294    Position from_x = InBitmapX(BW, x);
295    Position from_y = InBitmapY(BW, y);
296    Position to_x = InBitmapX(BW, x + width);
297    Position to_y = InBitmapY(BW, y + height);
298
299    if (BW->bitmap.grid)
300	BWDrawGrid(w, from_x, from_y, to_x, to_y);
301}
302
303void
304BWDrawLine(Widget w,
305	   Position from_x, Position from_y,
306	   Position to_x, Position to_y, int value)
307{
308    Position i;
309    register double x, y;
310    double dx, dy, delta;
311
312    dx = to_x - from_x;
313    dy = to_y - from_y;
314    x = from_x + 0.5;
315    y = from_y + 0.5;
316    delta = max(abs(dx), abs(dy));
317    if (delta > 0) {
318	dx /= delta;
319	dy /= delta;
320	for(i = 0; i <= delta; i++) {
321	    BWDrawPoint(w, (Position) x, (Position) y, value);
322	    x += dx;
323	    y += dy;
324	}
325    }
326    else
327	BWDrawPoint(w, from_x, from_y, value);
328}
329
330void
331BWBlindLine(Widget w,
332	    Position from_x, Position from_y,
333	    Position to_x, Position to_y, int value)
334{
335    Position i;
336    register double x, y;
337    double dx, dy, delta;
338
339    dx = to_x - from_x;
340    dy = to_y - from_y;
341    x = from_x + 0.5;
342    y = from_y + 0.5;
343    delta = max(abs(dx), abs(dy));
344    if (delta > 0) {
345	dx /= delta;
346	dy /= delta;
347	x += dx;
348	y += dy;
349	for(i = 1; i <= delta; i++) {
350	    BWDrawPoint(w, (Position) x, (Position) y, value);
351	    x += dx;
352	    y += dy;
353	}
354    }
355    else
356	BWDrawPoint(w, from_x, from_y, value);
357}
358
359void
360BWDrawRectangle(Widget w,
361		Position from_x, Position from_y,
362		Position to_x, Position to_y, int value)
363{
364    register Position i;
365    Dimension delta, width, height;
366
367    QuerySwap(from_x, to_x);
368    QuerySwap(from_y, to_y);
369
370    width = to_x - from_x;
371    height = to_y - from_y;
372
373    delta = max(width, height);
374
375    if (!QueryZero(width, height)) {
376	for (i = 0; (int)i < (int)delta; i++) {
377	    if ((int)i < (int)width) {
378		BWDrawPoint(w, from_x + i, from_y, value);
379		BWDrawPoint(w, to_x - i, to_y, value);
380	    }
381	    if ((int)i < (int)height) {
382		BWDrawPoint(w, from_x, to_y - i, value);
383		BWDrawPoint(w, to_x, from_y + i, value);
384	    }
385	}
386    }
387    else
388	BWDrawLine(w,
389		   from_x, from_y,
390		   to_x, to_y, value);
391}
392
393void
394BWDrawFilledRectangle(Widget w,
395		      Position from_x, Position from_y,
396		      Position to_x, Position to_y, int value)
397{
398    register Position x, y;
399
400    QuerySwap(from_x, to_x);
401    QuerySwap(from_y, to_y);
402
403    for (x = from_x; x <= to_x; x++)
404	for (y = from_y; y <= to_y; y++)
405	    BWDrawPoint(w, x, y, value);
406}
407
408void
409BWDrawCircle(Widget w,
410	     Position origin_x, Position origin_y,
411	     Position point_x, Position point_y, int value)
412{
413    register Position i, delta;
414    Dimension dx, dy, half;
415    double radius;
416
417    dx = abs(point_x - origin_x);
418    dy = abs(point_y - origin_y);
419    radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
420    if (radius < 1.0) {
421	BWDrawPoint(w, origin_x, origin_y, value);
422    }
423    else {
424	BWDrawPoint(w, origin_x - (Position) floor(radius), origin_y, value);
425	BWDrawPoint(w, origin_x + (Position) floor(radius), origin_y, value);
426	BWDrawPoint(w, origin_x, origin_y - (Position) floor(radius), value);
427	BWDrawPoint(w, origin_x, origin_y + (Position) floor(radius), value);
428    }
429    half = radius / sqrt(2.0);
430    for(i = 1; (int)i <= (int)half; i++) {
431	delta = sqrt(radius * radius - i * i);
432	BWDrawPoint(w, origin_x - delta, origin_y - i, value);
433	BWDrawPoint(w, origin_x - delta, origin_y + i, value);
434	BWDrawPoint(w, origin_x + delta, origin_y - i, value);
435	BWDrawPoint(w, origin_x + delta, origin_y + i, value);
436	if (i != delta) {
437	    BWDrawPoint(w, origin_x - i, origin_y - delta, value);
438	    BWDrawPoint(w, origin_x - i, origin_y + delta, value);
439	    BWDrawPoint(w, origin_x + i, origin_y - delta, value);
440	    BWDrawPoint(w, origin_x + i, origin_y + delta, value);
441	}
442    }
443}
444
445void
446BWDrawFilledCircle(Widget w,
447		   Position origin_x, Position origin_y,
448		   Position point_x, Position point_y, int value)
449{
450    register Position i, j, delta;
451    Dimension dx, dy;
452    double radius;
453
454    dx = abs(point_x - origin_x);
455    dy = abs(point_y - origin_y);
456    radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
457    for(j = origin_x - (Position) floor(radius);
458	j <= origin_x + (Position) floor(radius); j++)
459	BWDrawPoint(w, j, origin_y, value);
460    for(i = 1; i <= (Position) floor(radius); i++) {
461	delta = sqrt(radius * radius - i * i);
462	for(j = origin_x - delta; j <= origin_x + delta; j++) {
463	    BWDrawPoint(w, j, origin_y - i, value);
464	    BWDrawPoint(w, j, origin_y + i, value);
465	}
466    }
467}
468
469#define QueryFlood(BW, x, y, value)\
470    ((GetBit(BW->bitmap.image, x, y) !=\
471      (value & 1)) && QueryInBitmap(BW, x, y))
472
473#define Flood(BW, x, y, value)\
474    {if (value == Highlight) HighlightSquare(BW, x, y);\
475     else InvertPoint(BW, x, y);}
476
477/*
478static void
479FloodLoop(BitmapWidget BW, Position x, Position y, int value)
480{
481    if (QueryFlood(BW, x, y, value)) {
482	Flood(BW, x, y, value);
483	FloodLoop(BW, x, y - 1, value);
484	FloodLoop(BW, x - 1, y, value);
485	FloodLoop(BW, x, y + 1, value);
486	FloodLoop(BW, x + 1, y, value);
487    }
488}
489*/
490
491static void
492FloodLoop(BitmapWidget BW, Position x, Position y, int value)
493{
494    Position save_x, save_y, x_left, x_right;
495
496    if (QueryFlood(BW, x, y, value))
497	Flood(BW, x, y, value)
498
499
500    save_x = x;
501    save_y = y;
502
503    x++;
504    while (QueryFlood(BW, x, y, value)) {
505	Flood(BW, x, y, value);
506	x++;
507    }
508    x_right = --x;
509
510    x = save_x;
511    x--;
512    while (QueryFlood(BW, x, y, value)) {
513	Flood(BW, x, y, value);
514	x--;
515    }
516    x_left = ++x;
517
518
519    x = x_left;
520    y = save_y;
521    y++;
522
523    while (x <= x_right) {
524	Boolean flag = False;
525	Position x_enter;
526
527	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
528	    flag = True;
529	    x++;
530	}
531
532	if (flag) {
533	    if ((x == x_right) && QueryFlood(BW, x, y, value))
534		FloodLoop(BW, x, y, value);
535	    else
536		FloodLoop(BW, x - 1, y, value);
537	}
538
539	x_enter = x;
540
541	while (!QueryFlood(BW, x, y, value) && (x < x_right))
542	    x++;
543
544	if (x == x_enter) x++;
545    }
546
547    x = x_left;
548    y = save_y;
549    y--;
550
551    while (x <= x_right) {
552	Boolean flag = False;
553	Position x_enter;
554
555	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
556	    flag = True;
557	    x++;
558	}
559
560	if (flag) {
561	    if ((x == x_right) && QueryFlood(BW, x, y, value))
562		FloodLoop(BW, x, y, value);
563	    else
564		FloodLoop(BW, x - 1, y, value);
565	}
566
567	x_enter = x;
568
569	while (!QueryFlood(BW, x, y, value) && (x < x_right))
570	    x++;
571
572	if (x == x_enter) x++;
573    }
574}
575
576void
577BWFloodFill(Widget w, Position x, Position y, int value)
578{
579    BitmapWidget BW = (BitmapWidget) w;
580    int pixel;
581
582    pixel = GetBit(BW->bitmap.image, x, y);
583
584    if (value == Invert)
585	FloodLoop(BW, x, y, (pixel ? Clear : Set));
586    else if (value != pixel)
587	FloodLoop(BW, x, y, value);
588}
589
590#define QueryHotInMark(BW)\
591    ((BW->bitmap.hot.x == max(BW->bitmap.mark.from_x,\
592			      min(BW->bitmap.hot.x, BW->bitmap.mark.to_x)))\
593     &&\
594     (BW->bitmap.hot.y == max(BW->bitmap.mark.from_y,\
595			      min(BW->bitmap.hot.y, BW->bitmap.mark.to_y))))
596
597void
598BWUp(Widget w)
599{
600    BitmapWidget BW = (BitmapWidget) w;
601    register Position x, y;
602    bit first, up, down=0;
603    Position from_x, from_y, to_x, to_y;
604
605    if (BWQueryMarked(w)) {
606	from_x = BW->bitmap.mark.from_x;
607	from_y = BW->bitmap.mark.from_y;
608	to_x = BW->bitmap.mark.to_x;
609	to_y = BW->bitmap.mark.to_y;
610    }
611    else {
612	from_x = 0;
613	from_y = 0;
614	to_x = BW->bitmap.width - 1;
615	to_y = BW->bitmap.height - 1;
616    }
617
618    if ((to_y - from_y) == 0)
619	return;
620
621    for(x = from_x; x <= to_x; x++) {
622	first = up = GetBit(BW->bitmap.image, x, to_y);
623	for(y = to_y - 1; y >= from_y; y--) {
624	    down = GetBit(BW->bitmap.image, x, y);
625	    if (up != down)
626		InvertPoint(BW, x, y);
627	    up =down;
628	}
629	if(first != down)
630	    InvertPoint(BW, x, to_y);
631    }
632
633    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
634	&&
635	!BWQueryMarked(w))
636	BWSetHotSpot(w,
637		     BW->bitmap.hot.x,
638		     (BW->bitmap.hot.y - 1 + BW->bitmap.image->height) %
639		     BW->bitmap.image->height);
640
641}
642
643void
644BWDown(Widget w)
645{
646    BitmapWidget BW = (BitmapWidget) w;
647    register Position x, y;
648    bit first, down, up=0;
649    Position from_x, from_y, to_x, to_y;
650
651    if (BWQueryMarked(w)) {
652	from_x = BW->bitmap.mark.from_x;
653	from_y = BW->bitmap.mark.from_y;
654	to_x = BW->bitmap.mark.to_x;
655	to_y = BW->bitmap.mark.to_y;
656    }
657    else {
658	from_x = 0;
659	from_y = 0;
660	to_x = BW->bitmap.width - 1;
661	to_y = BW->bitmap.height - 1;
662    }
663
664    if ((to_y - from_y) == 0)
665	return;
666
667    for(x = from_x; x <= to_x; x++) {
668	first = down = GetBit(BW->bitmap.image, x, from_y);
669	for(y = from_y + 1; y <= to_y; y++) {
670	    up = GetBit(BW->bitmap.image, x, y);
671	    if (down != up)
672		InvertPoint(BW, x, y);
673	    down = up;
674	}
675	if(first != up)
676	    InvertPoint(BW, x, from_y);
677    }
678
679    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
680	&&
681	!BWQueryMarked(w))
682	BWSetHotSpot(w,
683		     BW->bitmap.hot.x,
684		     (BW->bitmap.hot.y + 1) % BW->bitmap.image->height);
685}
686
687void
688BWLeft(Widget w)
689{
690    BitmapWidget BW = (BitmapWidget) w;
691    register Position x, y;
692    bit first, left, right=0;
693    Position from_x, from_y, to_x, to_y;
694
695    if (BWQueryMarked(w)) {
696	from_x = BW->bitmap.mark.from_x;
697	from_y = BW->bitmap.mark.from_y;
698	to_x = BW->bitmap.mark.to_x;
699	to_y = BW->bitmap.mark.to_y;
700    }
701    else {
702	from_x = 0;
703	from_y = 0;
704	to_x = BW->bitmap.width - 1;
705	to_y = BW->bitmap.height - 1;
706    }
707
708    if ((to_x - from_x) == 0)
709	return;
710
711    for(y = from_y; y <= to_y; y++) {
712	first = left = GetBit(BW->bitmap.image, to_x, y);
713	for(x = to_x - 1; x >= from_x; x--) {
714	    right = GetBit(BW->bitmap.image, x, y);
715	    if (left != right)
716		InvertPoint(BW, x, y);
717	    left = right;
718	}
719	if(first != right)
720	    InvertPoint(BW, to_x, y);
721    }
722
723    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
724	&&
725	!BWQueryMarked(w))
726	BWSetHotSpot(w,
727		     (BW->bitmap.hot.x - 1 + BW->bitmap.image->width) %
728		     BW->bitmap.image->width,
729		     BW->bitmap.hot.y);
730}
731
732void
733BWRight(Widget w)
734{
735    BitmapWidget BW = (BitmapWidget) w;
736    register Position x, y;
737    bit first, right, left=0;
738    Position from_x, from_y, to_x, to_y;
739
740    if (BWQueryMarked(w)) {
741	from_x = BW->bitmap.mark.from_x;
742	from_y = BW->bitmap.mark.from_y;
743	to_x = BW->bitmap.mark.to_x;
744	to_y = BW->bitmap.mark.to_y;
745    }
746    else {
747	from_x = 0;
748	from_y = 0;
749	to_x = BW->bitmap.width - 1;
750	to_y = BW->bitmap.height - 1;
751    }
752
753    if ((to_x - from_x) == 0)
754	return;
755
756    for(y = from_y; y <= to_y; y++) {
757	first = right = GetBit(BW->bitmap.image, from_x, y);
758	for(x = from_x + 1; x <= to_x; x++) {
759	    left = GetBit(BW->bitmap.image, x, y);
760	    if (right != left)
761		InvertPoint(BW, x, y);
762	    right = left;
763	}
764	if(first != left)
765	    InvertPoint(BW, from_x, y);
766    }
767
768    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
769	&&
770	!BWQueryMarked(w))
771	BWSetHotSpot(w,
772		     (BW->bitmap.hot.x + 1) % BW->bitmap.image->width,
773		     BW->bitmap.hot.y);
774}
775
776/* void TransferImageData(); */
777
778void
779BWFold(Widget w)
780{
781    BitmapWidget BW = (BitmapWidget) w;
782    Position x, y, new_x, new_y;
783    Dimension horiz, vert;
784    char *storage_data;
785    XImage *storage;
786
787    storage_data = CreateCleanData(Length(BW->bitmap.image->width,
788					  BW->bitmap.image->height));
789
790    storage = CreateBitmapImage(BW, storage_data,
791				(Dimension) BW->bitmap.image->width,
792				(Dimension) BW->bitmap.image->height);
793
794    TransferImageData(BW->bitmap.image, storage);
795
796    BW->bitmap.fold ^= True;
797    horiz = (BW->bitmap.image->width + BW->bitmap.fold) / 2;
798    vert = (BW->bitmap.image->height + BW->bitmap.fold) / 2;
799
800    for (x = 0; x < BW->bitmap.image->width; x++)
801	for (y = 0; y < BW->bitmap.image->height; y++) {
802	    new_x = (int)(x + horiz) % (int)BW->bitmap.image->width;
803	    new_y = (int)(y + vert) % (int)BW->bitmap.image->height;
804	    if(GetBit(BW->bitmap.image, new_x, new_y) !=
805	       GetBit(storage, x, y))
806		InvertPoint(BW, new_x, new_y);
807	}
808
809    DestroyBitmapImage(&storage);
810
811    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
812      BWSetHotSpot(w,
813		   (Position)
814		   ((int)(BW->bitmap.hot.x+horiz)
815		    %(int)BW->bitmap.image->width),
816		   (Position)
817		   ((int)(BW->bitmap.hot.y+vert)
818		    %(int)BW->bitmap.image->height)
819		   );
820}
821
822
823void
824BWClear(Widget w)
825{
826    BitmapWidget BW = (BitmapWidget) w;
827    register Position x, y;
828    int i, length;
829
830    length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
831
832    for (x = 0; x < BW->bitmap.image->width; x++)
833	for (y = 0; y < BW->bitmap.image->height; y++)
834	    if (GetBit(BW->bitmap.image, x, y))
835		DrawSquare(BW, x, y);
836
837    for (i = 0; i < length; i++)
838	BW->bitmap.image->data[i] = 0;
839
840}
841
842void
843BWSet(Widget w)
844{
845    BitmapWidget BW = (BitmapWidget) w;
846    register Position x, y;
847    int i, length;
848
849    length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
850
851    for (x = 0; x < BW->bitmap.image->width; x++)
852	for (y = 0; y < BW->bitmap.image->height; y++)
853	    if (!GetBit(BW->bitmap.image, x, y))
854		DrawSquare(BW, x, y);
855
856    for (i = 0; i < length; i++)
857	BW->bitmap.image->data[i] = (char)255;
858
859}
860
861void
862BWRedraw(Widget w)
863{
864    BitmapWidget BW = (BitmapWidget) w;
865
866    XClearArea(XtDisplay(BW), XtWindow(BW),
867	       0, 0, BW->core.width, BW->core.height,
868	       True);
869}
870
871void
872BWInvert(Widget w)
873{
874    BitmapWidget BW = (BitmapWidget) w;
875    int i, length;
876
877    length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
878
879    XFillRectangle(XtDisplay(BW), XtWindow(BW),
880		   BW->bitmap.drawing_gc,
881		   InWindowX(BW, 0), InWindowY(BW, 0),
882		   InWindowX(BW, BW->bitmap.image->width) - InWindowX(BW, 0),
883		   InWindowY(BW, BW->bitmap.image->height) - InWindowY(BW, 0));
884
885    for (i = 0; i < length; i++)
886	BW->bitmap.image->data[i] ^= 255;
887}
888
889void
890BWFlipHoriz(Widget w)
891{
892    BitmapWidget BW = (BitmapWidget) w;
893    register Position x, y;
894    Position from_x, from_y, to_x, to_y;
895    float half;
896
897    if (BWQueryMarked(w)) {
898	from_x = BW->bitmap.mark.from_x;
899	from_y = BW->bitmap.mark.from_y;
900	to_x = BW->bitmap.mark.to_x;
901	to_y = BW->bitmap.mark.to_y;
902    }
903    else {
904	from_x = 0;
905	from_y = 0;
906	to_x = BW->bitmap.width - 1;
907	to_y = BW->bitmap.height - 1;
908    }
909    half = (float) (to_y - from_y) / 2.0 + 0.5;
910
911    if (half == 0.0)
912	return;
913
914    for (x = from_x; x <= to_x; x++)
915	for (y = 0; y <  half; y++)
916	    if (GetBit(BW->bitmap.image, x, from_y + y) !=
917		GetBit(BW->bitmap.image, x, to_y - y)) {
918		InvertPoint(BW, x, from_y + y);
919		InvertPoint(BW, x, to_y - y);
920	    }
921
922    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
923	&&
924	!BWQueryMarked(w))
925	BWSetHotSpot(w,
926		     BW->bitmap.hot.x,
927		     BW->bitmap.image->height - 1 - BW->bitmap.hot.y);
928}
929
930void
931BWFlipVert(Widget w)
932{
933    BitmapWidget BW = (BitmapWidget) w;
934    register Position x, y;
935    Position from_x, from_y, to_x, to_y;
936    float half;
937
938    if (BWQueryMarked(w)) {
939	from_x = BW->bitmap.mark.from_x;
940	from_y = BW->bitmap.mark.from_y;
941	to_x = BW->bitmap.mark.to_x;
942	to_y = BW->bitmap.mark.to_y;
943    }
944    else {
945	from_x = 0;
946	from_y = 0;
947	to_x = BW->bitmap.width - 1;
948	to_y = BW->bitmap.height - 1;
949    }
950    half = (float) (to_x - from_x) / 2.0 + 0.5;
951
952    if (half == 0)
953	return;
954
955    for (y = from_y; y <= to_y; y++)
956	for (x = 0; x < half; x++)
957	    if (GetBit(BW->bitmap.image, from_x + x, y) !=
958		GetBit(BW->bitmap.image, to_x - x, y)) {
959		InvertPoint(BW, from_x + x, y);
960		InvertPoint(BW, to_x - x, y);
961	    }
962
963    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
964	&&
965	!BWQueryMarked(w))
966	BWSetHotSpot(w,
967		     BW->bitmap.image->width - 1 - BW->bitmap.hot.x,
968		     BW->bitmap.hot.y);
969}
970
971
972void
973BWRotateRight(Widget w)
974{
975    BitmapWidget BW = (BitmapWidget) w;
976    Position x, y, delta, shift, tmp;
977    Position half_width, half_height;
978    XPoint hot;
979    bit quad1, quad2, quad3, quad4;
980    Position from_x, from_y, to_x, to_y;
981
982    if (BWQueryMarked(w)) {
983	from_x = BW->bitmap.mark.from_x;
984	from_y = BW->bitmap.mark.from_y;
985	to_x = BW->bitmap.mark.to_x;
986	to_y = BW->bitmap.mark.to_y;
987    }
988    else {
989	from_x = 0;
990	from_y = 0;
991	to_x = BW->bitmap.width - 1;
992	to_y = BW->bitmap.height - 1;
993    }
994
995    half_width = floor((to_x - from_x) / 2.0 + 0.5);
996    half_height = floor((to_y - from_y ) / 2.0 + 0.5);
997    shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
998    delta = min((Position) half_width, (Position) half_height) - shift;
999
1000    for (x = 0; x <= delta; x++) {
1001	for (y = 1 - shift; y <= delta; y++) {
1002	    quad1 = GetBit(BW->bitmap.image,
1003			   from_x + (Position)half_width + x,
1004			   from_y + (Position)half_height + y);
1005	    quad2 = GetBit(BW->bitmap.image,
1006			   from_x + (Position)half_width + y,
1007			   from_y + (Position)half_height - shift - x);
1008	    quad3 = GetBit(BW->bitmap.image,
1009			   from_x + (Position)half_width - shift - x,
1010			   from_y + (Position)half_height - shift - y);
1011	    quad4 = GetBit(BW->bitmap.image,
1012			   from_x + (Position)half_width - shift - y,
1013			   from_y + (Position)half_height + x);
1014
1015	    if (quad1 != quad2)
1016		InvertPoint(BW,
1017			    from_x + (Position)half_width + x,
1018			    from_y + (Position)half_height + y);
1019	    if (quad2 != quad3)
1020		InvertPoint(BW,
1021			    from_x + (Position)half_width + y,
1022			    from_y + (Position)half_height - shift - x);
1023	    if (quad3 != quad4)
1024		InvertPoint(BW,
1025			    from_x + (Position)half_width - shift - x,
1026			    from_y + (Position)half_height - shift - y);
1027	    if (quad4 != quad1)
1028		InvertPoint(BW,
1029			    from_x + (Position)half_width - shift - y,
1030			    from_y + (Position)half_height + x);
1031	}
1032    }
1033
1034    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
1035	&&
1036	!BWQueryMarked(w)) {
1037	hot.x = BW->bitmap.hot.x - half_width;
1038	hot.y = BW->bitmap.hot.y - half_height;
1039	if (hot.x >= 0) hot.x += shift;
1040	if (hot.y >= 0) hot.y += shift;
1041	tmp = hot.x;
1042	hot.x = - hot.y;
1043	hot.y = tmp;
1044	if (hot.x > 0) hot.x -= shift;
1045	if (hot.y > 0) hot.y -= shift;
1046	hot.x += half_width;
1047	hot.y += half_height;
1048	if (QueryInBitmap(BW, hot.x, hot.y))
1049	    BWSetHotSpot(w, hot.x, hot.y);
1050    }
1051
1052}
1053
1054void
1055BWRotateLeft(Widget w)
1056{
1057    BitmapWidget BW = (BitmapWidget) w;
1058    Position x, y,delta, shift, tmp;
1059    Position half_width, half_height;
1060    XPoint hot;
1061    bit quad1, quad2, quad3, quad4;
1062    Position from_x, from_y, to_x, to_y;
1063
1064    if (BWQueryMarked(w)) {
1065	from_x = BW->bitmap.mark.from_x;
1066	from_y = BW->bitmap.mark.from_y;
1067	to_x = BW->bitmap.mark.to_x;
1068	to_y = BW->bitmap.mark.to_y;
1069    }
1070    else {
1071	from_x = 0;
1072	from_y = 0;
1073	to_x = BW->bitmap.width - 1;
1074	to_y = BW->bitmap.height - 1;
1075    }
1076
1077    half_width = floor((to_x - from_x) / 2.0 + 0.5);
1078    half_height = floor((to_y - from_y ) / 2.0 + 0.5);
1079    shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
1080    delta = min((Position) half_width, (Position) half_height) - shift;
1081
1082    for (x = 0; x <= delta; x++) {
1083	for (y = 1 - shift; y <= delta; y++) {
1084	    quad1 = GetBit(BW->bitmap.image,
1085			   from_x + (Position)half_width + x,
1086			   from_y + (Position)half_height + y);
1087	    quad2 = GetBit(BW->bitmap.image,
1088			   from_x + (Position)half_width + y,
1089			   from_y + (Position)half_height - shift - x);
1090	    quad3 = GetBit(BW->bitmap.image,
1091			   from_x + (Position)half_width - shift - x,
1092			   from_y + (Position)half_height - shift - y);
1093	    quad4 = GetBit(BW->bitmap.image,
1094			   from_x + (Position)half_width - shift - y,
1095			   from_y + (Position)half_height + x);
1096
1097	    if (quad1 != quad4)
1098		InvertPoint(BW,
1099			    from_x + (Position)half_width + x,
1100			    from_y + (Position)half_height + y);
1101	    if (quad2 != quad1)
1102		InvertPoint(BW,
1103			    from_x + (Position)half_width + y,
1104			    from_y + (Position)half_height - shift - x);
1105	    if (quad3 != quad2)
1106		InvertPoint(BW,
1107			    from_x + (Position)half_width - shift - x,
1108			    from_y + (Position)half_height - shift - y);
1109	    if (quad4 != quad3)
1110		InvertPoint(BW,
1111			    from_x + (Position)half_width - shift - y,
1112			    from_y + (Position)half_height + x);
1113	}
1114    }
1115
1116    if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
1117	&&
1118	!BWQueryMarked(w)) {
1119	hot.x = BW->bitmap.hot.x - half_width;
1120	hot.y = BW->bitmap.hot.y - half_height;
1121	if (hot.x >= 0) hot.x += shift;
1122	if (hot.y >= 0) hot.y += shift;
1123	tmp = hot.x;
1124	hot.x = hot.y;
1125	hot.y = - tmp;
1126	if (hot.x > 0) hot.x -= shift;
1127	if (hot.y > 0) hot.y -= shift;
1128	hot.x += half_width;
1129	hot.y += half_height;
1130	if (QueryInBitmap(BW, hot.x, hot.y))
1131	    BWSetHotSpot(w, hot.x, hot.y);
1132    }
1133}
1134
1135
1136void
1137CopyImageData(XImage *source, XImage *destination,
1138	      Position from_x, Position from_y,
1139	      Position to_x, Position to_y,
1140	      Position at_x, Position at_y)
1141{
1142    Position x, y, delta_x, delta_y;
1143
1144    delta_x = to_x - from_x + 1;
1145    delta_y = to_y - from_y + 1;
1146
1147    for (x = 0; x < delta_x; x++)
1148	for (y = 0; y < delta_y; y++)
1149	    if (GetBit(source, from_x + x, from_y + y))
1150		SetBit(destination, at_x + x, at_y + y);
1151	    else
1152		ClearBit(destination, at_x + x, at_y + y);
1153}
1154
1155XImage *
1156ConvertToBitmapImage(BitmapWidget BW, XImage *image)
1157{
1158    XImage *bitmap_image;
1159    char   *data;
1160    Position x, y;
1161
1162    data = CreateCleanData(Length(image->width, image->height));
1163    bitmap_image = CreateBitmapImage(BW, data,
1164				     (Dimension) image->width,
1165				     (Dimension) image->height);
1166
1167    for (x = 0; x < min(image->width, bitmap_image->width); x++)
1168	for (y = 0; y < min(image->height, bitmap_image->height); y++)
1169	    if ((XGetPixel(image, x, y) != 0) != GetBit(bitmap_image, x, y))
1170		InvertBit(bitmap_image, x, y);
1171
1172    return bitmap_image;
1173}
1174
1175void
1176TransferImageData(XImage *source, XImage *destination)
1177{
1178    Position x, y;
1179
1180    for (x = 0; x < min(source->width, destination->width); x++)
1181	for (y = 0; y < min(source->height, destination->height); y++)
1182	    if (GetBit(source, x, y) != GetBit(destination, x, y))
1183		InvertBit(destination, x, y);
1184}
1185
1186void
1187BWStore(Widget w)
1188{
1189    BitmapWidget BW = (BitmapWidget) w;
1190    Dimension width, height;
1191    char *storage_data;
1192
1193    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1194
1195	DestroyBitmapImage(&BW->bitmap.storage);
1196
1197	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
1198	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
1199
1200	storage_data = CreateCleanData(Length(width, height));
1201
1202	BW->bitmap.storage = CreateBitmapImage(BW,
1203					       storage_data,
1204					       width, height);
1205
1206	CopyImageData(BW->bitmap.image, BW->bitmap.storage,
1207		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
1208		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
1209		      0, 0);
1210    }
1211}
1212
1213void
1214BWClearMarked(Widget w)
1215{
1216    BitmapWidget BW = (BitmapWidget) w;
1217
1218    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
1219	BWDrawFilledRectangle(w,
1220			      BW->bitmap.mark.from_x,
1221			      BW->bitmap.mark.from_y,
1222			      BW->bitmap.mark.to_x,
1223			      BW->bitmap.mark.to_y,
1224			      Clear);
1225}
1226
1227
1228void
1229BWDragMarked(Widget w, Position at_x, Position at_y)
1230{
1231    BitmapWidget BW = (BitmapWidget) w;
1232
1233    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
1234	BWDrawRectangle(w,
1235			at_x, at_y,
1236			at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
1237			at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y,
1238			Highlight);
1239}
1240
1241void
1242BWDragStored(Widget w, Position at_x, Position at_y)
1243{
1244    BitmapWidget BW = (BitmapWidget) w;
1245
1246    if (BW->bitmap.storage)
1247	BWDrawRectangle(w,
1248			at_x, at_y,
1249			at_x + BW->bitmap.storage->width - 1,
1250			at_y + BW->bitmap.storage->height - 1,
1251			Highlight);
1252}
1253
1254static void
1255DrawImageData(BitmapWidget BW, XImage *image,
1256	      Position at_x, Position at_y, int value)
1257{
1258    Position x, y;
1259    Boolean  C, S, I, H;
1260    bit      A, B;
1261
1262    C = value == Clear;
1263    S = value == Set;
1264    I = value == Invert;
1265    H = value == Highlight;
1266
1267    for (x = 0; x < image->width; x++)
1268	for (y = 0; y < image->height; y++) {
1269	    A = GetBit(image, x, y);
1270	    B = GetBit(BW->bitmap.image, at_x + x, at_y + y);
1271	    if ((A & C) | ((A | B) & S) | ((A ^ B) & I) | ((A | B) & H))
1272		value = (A & H) ? Highlight : Set;
1273	    else
1274		value = Clear;
1275	    BWDrawPoint((Widget) BW,
1276			 at_x + x, at_y + y,
1277			 value);
1278	}
1279}
1280
1281void
1282BWRestore(Widget w, Position at_x, Position at_y, int value)
1283{
1284    BitmapWidget BW = (BitmapWidget) w;
1285
1286    if (BW->bitmap.storage) {
1287      DrawImageData(BW, BW->bitmap.storage, at_x, at_y, value);
1288      /*DestroyBitmapImage(&BW->bitmap.storage);*/
1289    }
1290}
1291
1292void
1293BWCopy(Widget w, Position at_x, Position at_y, int value)
1294{
1295    BitmapWidget BW = (BitmapWidget) w;
1296    XImage *storage;
1297    char *storage_data;
1298    Dimension width, height;
1299
1300    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1301
1302	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
1303	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
1304
1305	storage_data = CreateCleanData(Length(width, height));
1306
1307	storage = CreateBitmapImage(BW, storage_data, width, height);
1308
1309	CopyImageData(BW->bitmap.image, storage,
1310		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
1311		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
1312		      0, 0);
1313
1314	DrawImageData(BW, storage, at_x, at_y, value);
1315
1316	DestroyBitmapImage(&storage);
1317    }
1318}
1319
1320/* void BWMark(); */
1321
1322void
1323BWMove(Widget w, Position at_x, Position at_y, int value)
1324{
1325    BitmapWidget BW = (BitmapWidget) w;
1326    XImage *storage;
1327    char *storage_data;
1328    Dimension width, height;
1329
1330    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1331
1332	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
1333	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
1334
1335	storage_data = CreateCleanData(Length(width, height));
1336
1337	storage = CreateBitmapImage(BW, storage_data, width, height);
1338
1339	CopyImageData(BW->bitmap.image, storage,
1340		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
1341		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
1342		      0, 0);
1343
1344	BWDrawFilledRectangle(w,
1345			      BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
1346			      BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
1347			      Clear);
1348
1349	DrawImageData(BW, storage, at_x, at_y, value);
1350
1351	BWMark(w, at_x, at_y,
1352	     at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
1353	     at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y);
1354
1355	DestroyBitmapImage(&storage);
1356    }
1357}
1358
1359void
1360BWRedrawMark(Widget w)
1361{
1362    BitmapWidget BW = (BitmapWidget) w;
1363
1364    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
1365	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
1366		       InWindowX(BW, BW->bitmap.mark.from_x),
1367		       InWindowY(BW, BW->bitmap.mark.from_y),
1368		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
1369		       InWindowX(BW, BW->bitmap.mark.from_x),
1370		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
1371		       InWindowY(BW, BW->bitmap.mark.from_y));
1372}
1373
1374void
1375BWStoreToBuffer(Widget w)
1376{
1377    BitmapWidget BW = (BitmapWidget) w;
1378
1379    memmove( BW->bitmap.buffer->data, BW->bitmap.image->data,
1380	  Length(BW->bitmap.image->width, BW->bitmap.image->height));
1381
1382    BW->bitmap.buffer_hot = BW->bitmap.hot;
1383    BW->bitmap.buffer_mark = BW->bitmap.mark;
1384}
1385
1386void
1387BWUnmark(Widget w)
1388{
1389    BitmapWidget BW = (BitmapWidget) w;
1390
1391    BW->bitmap.buffer_mark = BW->bitmap.mark;
1392
1393    if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1394	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
1395		       InWindowX(BW, BW->bitmap.mark.from_x),
1396		       InWindowY(BW, BW->bitmap.mark.from_y),
1397		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
1398		       InWindowX(BW, BW->bitmap.mark.from_x),
1399		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
1400		       InWindowY(BW, BW->bitmap.mark.from_y));
1401
1402	BW->bitmap.mark.from_x = BW->bitmap.mark.from_y = NotSet;
1403	BW->bitmap.mark.to_x = BW->bitmap.mark.to_y = NotSet;
1404    }
1405}
1406
1407void
1408BWMark(Widget w, Position from_x, Position from_y,
1409       Position to_x, Position to_y)
1410{
1411    BitmapWidget BW = (BitmapWidget) w;
1412
1413    BWUnmark(w);
1414
1415    if (QuerySet(from_x, from_y)) {
1416	if ((from_x == to_x) && (from_y == to_y)) {
1417	    /*
1418	      BW->bitmap.mark.from_x = 0;
1419	      BW->bitmap.mark.from_y = 0;
1420	      BW->bitmap.mark.to_x = BW->bitmap.image->width - 1;
1421	      BW->bitmap.mark.to_y = BW->bitmap.image->height - 1;
1422	      */
1423	    return;
1424	}
1425	else {
1426	    QuerySwap(from_x, to_x);
1427	    QuerySwap(from_y, to_y);
1428	    from_x = max(0, from_x);
1429	    from_y = max(0, from_y);
1430	    to_x = min(BW->bitmap.image->width - 1, to_x);
1431	    to_y = min(BW->bitmap.image->height - 1, to_y);
1432
1433	    BW->bitmap.mark.from_x = from_x;
1434	    BW->bitmap.mark.from_y = from_y;
1435	    BW->bitmap.mark.to_x = to_x;
1436	    BW->bitmap.mark.to_y = to_y;
1437	}
1438
1439	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
1440		       InWindowX(BW, BW->bitmap.mark.from_x),
1441		       InWindowY(BW, BW->bitmap.mark.from_y),
1442		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
1443		       InWindowX(BW, BW->bitmap.mark.from_x),
1444		       InWindowY(BW, BW->bitmap.mark.to_y +1) -
1445		       InWindowY(BW, BW->bitmap.mark.from_y));
1446    }
1447}
1448
1449void
1450BWMarkAll(Widget w)
1451{
1452  BitmapWidget BW = (BitmapWidget) w;
1453
1454  BWMark(w, 0, 0, BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
1455}
1456
1457void
1458BWUndo(Widget w)
1459{
1460    BitmapWidget BW = (BitmapWidget) w;
1461    Position x, y;
1462    char *tmp_data;
1463    XPoint tmp_hot;
1464    BWArea tmp_mark;
1465
1466    tmp_data = BW->bitmap.image->data;
1467    BW->bitmap.image->data = BW->bitmap.buffer->data;
1468    BW->bitmap.buffer->data = tmp_data;
1469
1470    tmp_hot = BW->bitmap.hot;
1471    tmp_mark = BW->bitmap.mark;
1472
1473    for (x = 0; x < BW->bitmap.image->width; x++)
1474	for (y = 0; y < BW->bitmap.image->height; y++)
1475	 if (GetBit(BW->bitmap.image, x, y) != GetBit(BW->bitmap.buffer, x, y))
1476	     DrawSquare(BW, x, y);
1477
1478    BWSetHotSpot(w, BW->bitmap.buffer_hot.x, BW->bitmap.buffer_hot.y);
1479/*
1480    BWMark(w, BW->bitmap.buffer_mark.from_x, BW->bitmap.buffer_mark.from_y,
1481	   BW->bitmap.buffer_mark.to_x, BW->bitmap.buffer_mark.to_y);
1482*/
1483    BW->bitmap.buffer_hot = tmp_hot;
1484    BW->bitmap.buffer_mark= tmp_mark;
1485
1486}
1487
1488void
1489BWHighlightAxes(Widget w)
1490{
1491    BitmapWidget BW = (BitmapWidget) w;
1492
1493    XDrawLine(XtDisplay(BW), XtWindow(BW),
1494	      BW->bitmap.axes_gc,
1495	      InWindowX(BW, 0),
1496	      InWindowY(BW, 0),
1497	      InWindowX(BW, BW->bitmap.width),
1498	      InWindowY(BW, BW->bitmap.height));
1499    XDrawLine(XtDisplay(BW), XtWindow(BW),
1500	      BW->bitmap.axes_gc,
1501	      InWindowX(BW, BW->bitmap.width),
1502	      InWindowY(BW, 0),
1503	      InWindowX(BW, 0),
1504	      InWindowY(BW, BW->bitmap.height));
1505    XDrawLine(XtDisplay(BW), XtWindow(BW),
1506	      BW->bitmap.axes_gc,
1507	      InWindowX(BW, 0),
1508	      InWindowY(BW, (float)BW->bitmap.height / 2.0),
1509	      InWindowX(BW, BW->bitmap.width),
1510	      InWindowY(BW, (float)BW->bitmap.height / 2.0));
1511    XDrawLine(XtDisplay(BW), XtWindow(BW),
1512	      BW->bitmap.axes_gc,
1513	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
1514	      InWindowY(BW, 0),
1515	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
1516	      InWindowY(BW, BW->bitmap.height));
1517}
1518
1519typedef struct {
1520    Position *x, *y;
1521    Dimension *width, *height;
1522} Table;
1523
1524XImage *
1525ScaleBitmapImage(BitmapWidget BW, XImage *src,
1526		 double scale_x, double scale_y)
1527{
1528    char *data;
1529    XImage *dst;
1530    Table table;
1531    Position x, y, w, h;
1532    Dimension width, height;
1533    bit pixel;
1534
1535    width = max(rint(scale_x * src->width), 1);
1536    height = max(rint(scale_y * src->height), 1);
1537
1538    data = CreateCleanData(Length(width, height));
1539    dst = CreateBitmapImage(BW, data, width, height);
1540
1541    /*
1542     * It would be nice to check if width or height < 1.0 and
1543     * average the skipped pixels. But, it is slow as it is now.
1544     */
1545    if (scale_x == 1.0 && scale_y == 1.0)
1546	memmove( dst->data, src->data, Length(width, height));
1547    else {
1548	table.x = (Position *) XtMalloc(sizeof(Position) * src->width);
1549	table.y = (Position *) XtMalloc(sizeof(Position) * src->height);
1550	table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src->width);
1551	table.height = (Dimension *) XtMalloc(sizeof(Dimension) * src->height);
1552
1553	for (x = 0; x < src->width; x++) {
1554	    table.x[x] = rint(scale_x * x);
1555	    table.width[x] = rint(scale_x * (x + 1)) - rint(scale_x * x);
1556	}
1557	for (y = 0; y < src->height; y++) {
1558	    table.y[y] = rint(scale_y * y);
1559	    table.height[y] = rint(scale_y * (y + 1)) - rint(scale_y * y);
1560	}
1561
1562	for (x = 0; x < src->width; x++)
1563	    for (y = 0; y < src->height; y++) {
1564	        pixel = GetBit(src, x, y);
1565		for (w = 0; (int)w < (int)table.width[x]; w++)
1566		    for (h = 0; (int)h < (int)table.height[y]; h++)
1567			if (pixel) SetBit(dst,
1568					table.x[x] + w,
1569					table.y[y] + h);
1570	    }
1571
1572	XtFree((char *)table.x);
1573	XtFree((char *)table.y);
1574	XtFree((char *)table.width);
1575	XtFree((char *)table.height);
1576    }
1577
1578    return (dst);
1579}
1580
1581/*****************************************************************************/
1582