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