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