The R Project SVN R

Rev

Rev 42585 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 42585 Rev 45017
Line 24... Line 24...
24
   WITHOUT ANY WARRANTY.
24
   WITHOUT ANY WARRANTY.
25
 
25
 
26
   See the file COPYLIB.TXT for details.
26
   See the file COPYLIB.TXT for details.
27
*/
27
*/
28
 
28
 
29
/*  Copyright (C) 2004 	The R Foundation
29
/*  Copyright (C) 2004	The R Foundation
30
 
30
 
31
    Changes for R:
31
    Changes for R:
32
 
32
 
33
    Remove assumption of current->dest being non-NULL
33
    Remove assumption of current->dest being non-NULL
34
 
34
 
Line 36... Line 36...
36
 
36
 
37
#include "internal.h"
37
#include "internal.h"
38
 
38
 
39
#if (WINVER < 0x030a)
39
#if (WINVER < 0x030a)
40
 
40
 
41
	#define MoveToEx move_to_ex
41
#define MoveToEx move_to_ex
42
	#define GetCurrentPositionEx get_current_position_ex
42
#define GetCurrentPositionEx get_current_position_ex
43
	#define GetTextExtentPoint get_text_extent_point
43
#define GetTextExtentPoint get_text_extent_point
44
 
44
 
45
	int move_to_ex(HDC hdc, int x, int y, POINT *p);
45
int move_to_ex(HDC hdc, int x, int y, POINT *p);
46
	int get_current_position_ex(HDC hdc, POINT *p);
46
int get_current_position_ex(HDC hdc, POINT *p);
47
	int get_text_extent_point(HDC hdc, const char *str, int len, SIZE *s);
47
int get_text_extent_point(HDC hdc, const char *str, int len, SIZE *s);
48
 
48
 
49
static int move_to_ex(HDC hdc, int x, int y, POINT *p)
49
static int move_to_ex(HDC hdc, int x, int y, POINT *p)
50
{
50
{
51
	DWORD result = MoveTo(hdc, x, y);
51
    DWORD result = MoveTo(hdc, x, y);
52
	if (p) {
52
    if (p) {
53
		p->x = LOWORD(result);
53
	p->x = LOWORD(result);
54
		p->y = HIWORD(result);
54
	p->y = HIWORD(result);
55
	}
55
    }
56
	return 1;
56
    return 1;
57
}
57
}
58
 
58
 
59
static int get_current_position_ex(HDC hdc, POINT *p)
59
static int get_current_position_ex(HDC hdc, POINT *p)
60
{
60
{
61
	DWORD result = GetCurrentPosition(hdc);
61
    DWORD result = GetCurrentPosition(hdc);
62
	if (p) {
62
    if (p) {
63
		p->x = LOWORD(result);
63
	p->x = LOWORD(result);
64
		p->y = HIWORD(result);
64
	p->y = HIWORD(result);
65
	}
65
    }
66
	return 1;
66
    return 1;
67
}
67
}
68
 
68
 
69
static int get_text_extent_point(HDC hdc, const char *str, int len, SIZE *s)
69
static int get_text_extent_point(HDC hdc, const char *str, int len, SIZE *s)
70
{
70
{
71
	DWORD result = GetTextExtent(hdc, str, len);
71
    DWORD result = GetTextExtent(hdc, str, len);
72
	if (s) {
72
    if (s) {
73
		s->cx = LOWORD(result);
73
	s->cx = LOWORD(result);
74
		s->cy = HIWORD(result);
74
	s->cy = HIWORD(result);
75
	}
75
    }
76
	return 1;
76
    return 1;
77
}
77
}
78
 
78
 
79
#endif  /* WINVER < 0x030a */
79
#endif  /* WINVER < 0x030a */
80
 
80
 
81
/*
81
/*
82
 *  Windows transfer modes corresponding to bitblt operations.
82
 *  Windows transfer modes corresponding to bitblt operations.
83
 */
83
 */
84
static long copy_mode[16] = {
84
static long copy_mode[16] = {
85
	BLACKNESS,	/* Zeros */
85
    BLACKNESS,	/* Zeros */
86
	NOTSRCERASE,	/* DnorS */
86
    NOTSRCERASE,	/* DnorS */
87
	0x00220326L,	/* DandnotS */
87
    0x00220326L,	/* DandnotS */
88
	NOTSRCCOPY,	/* notS */
88
    NOTSRCCOPY,	/* notS */
89
	SRCERASE,	/* notDandS */
89
    SRCERASE,	/* notDandS */
90
	DSTINVERT,	/* notD */
90
    DSTINVERT,	/* notD */
91
	SRCINVERT,	/* DxorS */
91
    SRCINVERT,	/* DxorS */
92
	0x007700E6L,	/* DnandS */
92
    0x007700E6L,	/* DnandS */
93
	SRCAND,		/* DandS */
93
    SRCAND,		/* DandS */
94
	0x00990066L,	/* DxnorS */
94
    0x00990066L,	/* DxnorS */
95
	0x00AA0029L,	/* D */			/* = no-op */
95
    0x00AA0029L,	/* D */			/* = no-op */
96
	MERGEPAINT,	/* DornotS */
96
    MERGEPAINT,	/* DornotS */
97
	SRCCOPY,	/* S */
97
    SRCCOPY,	/* S */
98
	0x00DD0228L,	/* notDorS */
98
    0x00DD0228L,	/* notDorS */
99
	SRCPAINT,	/* DorS */
99
    SRCPAINT,	/* DorS */
100
	WHITENESS	/* Ones */
100
    WHITENESS	/* Ones */
101
};
101
};
102
 
102
 
103
/*
103
/*
104
 *  Windows transfer modes corresponding to patblt operations.
104
 *  Windows transfer modes corresponding to patblt operations.
105
 */
105
 */
106
static long pat_mode[16] = {
106
static long pat_mode[16] = {
107
	BLACKNESS,	/* Zeros */
107
    BLACKNESS,	/* Zeros */
108
	0x000500A9L,	/* DnorP */
108
    0x000500A9L,	/* DnorP */
109
	0x000A0329L,	/* DandnotP */
109
    0x000A0329L,	/* DandnotP */
110
	0x000F0001L,	/* notP */
110
    0x000F0001L,	/* notP */
111
	0x00500325L,	/* notDandP */
111
    0x00500325L,	/* notDandP */
112
	DSTINVERT,	/* notD */
112
    DSTINVERT,	/* notD */
113
	PATINVERT,	/* DxorP */
113
    PATINVERT,	/* DxorP */
114
	0x005F00E9L,	/* DnandP */
114
    0x005F00E9L,	/* DnandP */
115
	0x00A000C9L,	/* DandP */
115
    0x00A000C9L,	/* DandP */
116
	0x00A50065L,	/* DxnorP */
116
    0x00A50065L,	/* DxnorP */
117
	0x00AA0029L,	/* D */			/* = no-op */
117
    0x00AA0029L,	/* D */			/* = no-op */
118
	0x00AF0229L,	/* DornotP */
118
    0x00AF0229L,	/* DornotP */
119
	PATCOPY,	/* P */
119
    PATCOPY,	/* P */
120
	0x00F50225L,	/* notDorP */
120
    0x00F50225L,	/* notDorP */
121
	0x00FA0089L,	/* DorP */
121
    0x00FA0089L,	/* DorP */
122
	WHITENESS	/* Ones */
122
    WHITENESS	/* Ones */
123
};
123
};
124
 
124
 
125
/*
125
/*
126
 *  Windows transfer modes corresponding to pen drawing.
126
 *  Windows transfer modes corresponding to pen drawing.
127
 */
127
 */
128
static int pen_mode[16] = {
128
static int pen_mode[16] = {
129
	R2_BLACK,	/* Zeros */
129
    R2_BLACK,	/* Zeros */
130
	R2_NOTMERGEPEN,	/* DnorS */
130
    R2_NOTMERGEPEN,	/* DnorS */
131
	R2_MASKNOTPEN,	/* DandnotS */
131
    R2_MASKNOTPEN,	/* DandnotS */
132
	R2_NOTCOPYPEN,	/* notS */
132
    R2_NOTCOPYPEN,	/* notS */
133
	R2_MASKPENNOT,	/* notDandS */
133
    R2_MASKPENNOT,	/* notDandS */
134
	R2_NOT,		/* notD */
134
    R2_NOT,		/* notD */
135
	R2_XORPEN,	/* DxorS */
135
    R2_XORPEN,	/* DxorS */
136
	R2_NOTMASKPEN,	/* DnandS */
136
    R2_NOTMASKPEN,	/* DnandS */
137
	R2_MASKPEN,	/* DandS */
137
    R2_MASKPEN,	/* DandS */
138
	R2_NOTXORPEN,	/* DxnorS */
138
    R2_NOTXORPEN,	/* DxnorS */
139
	R2_NOP,		/* D */			/* = no-op */
139
    R2_NOP,		/* D */			/* = no-op */
140
	R2_MERGENOTPEN,	/* DornotS */
140
    R2_MERGENOTPEN,	/* DornotS */
141
	R2_COPYPEN,	/* S */
141
    R2_COPYPEN,	/* S */
142
	R2_MERGEPENNOT,	/* notDorS */
142
    R2_MERGEPENNOT,	/* notDorS */
143
	R2_MERGEPEN,	/* DorS */
143
    R2_MERGEPEN,	/* DorS */
144
	R2_WHITE	/* Ones */
144
    R2_WHITE	/* Ones */
145
};
145
};
146
 
146
 
147
/*
147
/*
148
 *  Some clipping functions.
148
 *  Some clipping functions.
149
 */
149
 */
150
rect getcliprect(void)
150
rect getcliprect(void)
151
{
151
{
152
	RECT R;
152
    RECT R;
153
	rect r;
153
    rect r;
154
 
154
 
155
	GetClipBox(dc, &R);
155
    GetClipBox(dc, &R);
156
	r.x = R.left;
156
    r.x = R.left;
157
	r.y = R.top;
157
    r.y = R.top;
158
	r.width = R.right - R.left;
158
    r.width = R.right - R.left;
159
	r.height = R.bottom - R.top;
159
    r.height = R.bottom - R.top;
160
	return r;
160
    return r;
161
}
161
}
162
 
162
 
163
void setcliprect(rect r)
163
void setcliprect(rect r)
164
{
164
{
165
	HRGN rgn;
165
    HRGN rgn;
166
 
166
 
167
	rgn = CreateRectRgn(r.x, r.y, r.x+r.width, r.y+r.height);
167
    rgn = CreateRectRgn(r.x, r.y, r.x+r.width, r.y+r.height);
168
	SelectClipRgn(dc, rgn);
168
    SelectClipRgn(dc, rgn);
169
	DeleteObject(rgn);
169
    DeleteObject(rgn);
170
}
170
}
171
 
171
 
172
/*
172
/*
173
 *  Ensure that drawing is possible by creating DCs and windows
173
 *  Ensure that drawing is possible by creating DCs and windows
174
 *  as necessary.
174
 *  as necessary.
175
 */
175
 */
176
PROTECTED
176
PROTECTED
177
window simple_window(void)
177
window simple_window(void)
178
{
178
{
179
	window w;
179
    window w;
180
	w = newwindow("Graphics", rect(0,0,0,0), StandardWindow);
180
    w = newwindow("Graphics", rect(0,0,0,0), StandardWindow);
181
	show(w);
181
    show(w);
182
	return w;
182
    return w;
183
}
183
}
184
 
184
 
185
/*
185
/*
186
 *  Fix brush origins.
186
 *  Fix brush origins.
187
 */
187
 */
188
PROTECTED
188
PROTECTED
189
void fix_brush(HDC dc, drawing obj, HBRUSH brush)
189
void fix_brush(HDC dc, drawing obj, HBRUSH brush)
190
{
190
{
191
	POINT p;
191
    POINT p;
192
	HWND hwnd;
192
    HWND hwnd;
193
	drawing parent;
193
    drawing parent;
194
 
194
 
195
	parent = parentwindow(obj);
195
    parent = parentwindow(obj);
196
	if (! parent)
196
    if (! parent)
197
		return;
197
	return;
198
	hwnd = parent->handle;
198
    hwnd = parent->handle;
199
	p.x = p.y = 0;
199
    p.x = p.y = 0;
200
	ClientToScreen(hwnd, &p);
200
    ClientToScreen(hwnd, &p);
201
	if (brush)
201
    if (brush)
202
		UnrealizeObject(brush);
202
	UnrealizeObject(brush);
203
#if (WINVER <= 0x030a)
203
#if (WINVER <= 0x030a)
204
	/* Microsoft keeps changing which functions they include in GDI.DLL */
204
    /* Microsoft keeps changing which functions they include in GDI.DLL */
205
	/* But this function should work on systems before Win 95 */
205
    /* But this function should work on systems before Win 95 */
206
	SetBrushOrg(dc, p.x, p.y);
206
    SetBrushOrg(dc, p.x, p.y);
207
#else
207
#else
208
	/* And this function should work on Win 95 and NT */
208
    /* And this function should work on Win 95 and NT */
209
	SetBrushOrgEx(dc, p.x, p.y, &p);
209
    SetBrushOrgEx(dc, p.x, p.y, &p);
210
#endif
210
#endif
211
}
211
}
212
 
212
 
213
/*
213
/*
214
 *  All drawing functions call enabledrawing.
214
 *  All drawing functions call enabledrawing.
215
 */
215
 */
216
static void enable_drawing(void)
216
static void enable_drawing(void)
217
{
217
{
218
	if (! current->dest) {
218
    if (! current->dest) {
219
		if (! current_window)
219
	if (! current_window)
220
			current_window = simple_window();
220
	    current_window = simple_window();
221
		show(current_window);
221
	show(current_window);
222
		drawto(current_window);
222
	drawto(current_window);
223
	}
223
    }
224
	if (! dc)
224
    if (! dc)
225
		dc = get_context(current->dest);
225
	dc = get_context(current->dest);
226
 
226
 
227
	fix_brush(dc, current->dest, the_brush);
227
    fix_brush(dc, current->dest, the_brush);
228
}
228
}
229
 
229
 
230
/*
230
/*
231
 *  Drawing functions begin here.
231
 *  Drawing functions begin here.
232
 */
232
 */
233
void bitblt(bitmap db, bitmap sb, point p, rect r, int mode)
233
void bitblt(bitmap db, bitmap sb, point p, rect r, int mode)
234
{
234
{
235
	HDC src;
235
    HDC src;
236
	HDC dst;
236
    HDC dst;
237
 
237
 
238
	dst = get_context((object)db);
238
    dst = get_context((object)db);
239
	src = get_context((object)sb);
239
    src = get_context((object)sb);
240
 
240
 
241
	BitBlt(dst, p.x, p.y, r.width, r.height, src, r.x, r.y,
241
    BitBlt(dst, p.x, p.y, r.width, r.height, src, r.x, r.y,
242
		copy_mode[mode&0x0F]);
242
	   copy_mode[mode&0x0F]);
243
}
243
}
244
 
244
 
245
void scrollrect(point dp, rect r)
245
void scrollrect(point dp, rect r)
246
{
246
{
247
	rect cliprect;
247
    rect cliprect;
248
	if (current->dest) cliprect = getrect(current->dest);
248
    if (current->dest) cliprect = getrect(current->dest);
249
	else return;
249
    else return;
250
 
250
 
251
	enable_drawing();
251
    enable_drawing();
252
	ScrollDC(dc, dp.x-r.x, dp.y-r.y,
252
    ScrollDC(dc, dp.x-r.x, dp.y-r.y,
253
		 rect2RECT(&r), rect2RECT(&cliprect), 0, NULL);
253
	     rect2RECT(&r), rect2RECT(&cliprect), 0, NULL);
254
}
254
}
255
 
255
 
256
void copyrect(bitmap sb, point p, rect r)
256
void copyrect(bitmap sb, point p, rect r)
257
{
257
{
258
	enable_drawing();
258
    enable_drawing();
259
	if (current->dest) bitblt(current->dest, sb, p, r, S);
259
    if (current->dest) bitblt(current->dest, sb, p, r, S);
260
}
260
}
261
 
261
 
262
void texturerect(bitmap sb, rect dr)
262
void texturerect(bitmap sb, rect dr)
263
{
263
{
264
	long x, y, sw, sh, sdx, sdy;
264
    long x, y, sw, sh, sdx, sdy;
265
	long right, bottom;
265
    long right, bottom;
266
	rect sr,r;
266
    rect sr,r;
267
 
267
 
268
	enable_drawing();
268
    enable_drawing();
269
	sr = getrect(sb);
269
    sr = getrect(sb);
270
	sw = sr.width;
270
    sw = sr.width;
271
	sh = sr.height;
271
    sh = sr.height;
272
	right = dr.x + dr.width;
272
    right = dr.x + dr.width;
273
	bottom = dr.y + dr.height;
273
    bottom = dr.y + dr.height;
274
 
274
 
275
	for (y = dr.y; y <= bottom; y += sh)
275
    for (y = dr.y; y <= bottom; y += sh)
276
		for (x = dr.x; x <= right; x += sw) {
276
	for (x = dr.x; x <= right; x += sw) {
277
 
277
 
278
			/* reduce size of source rectangle for clipping */
278
	    /* reduce size of source rectangle for clipping */
279
			if (x+sw > right)	sdx = right - x;
279
	    if (x+sw > right)	sdx = right - x;
280
			else			sdx = sw;
280
	    else			sdx = sw;
281
			if (y+sh > bottom)	sdy = bottom - y;
281
	    if (y+sh > bottom)	sdy = bottom - y;
282
			else			sdy = sh;
282
	    else			sdy = sh;
283
 
283
 
284
			r = rect(sr.x, sr.y, sdx, sdy);
284
	    r = rect(sr.x, sr.y, sdx, sdy);
285
			copyrect(sb, pt(x,y), r);
285
	    copyrect(sb, pt(x,y), r);
286
		}
286
	}
287
}
287
}
288
 
288
 
289
void invertrect(rect r)
289
void invertrect(rect r)
290
{
290
{
291
	enable_drawing();
291
    enable_drawing();
292
	PatBlt(dc, r.x, r.y, r.width, r.height, DSTINVERT);
292
    PatBlt(dc, r.x, r.y, r.width, r.height, DSTINVERT);
293
}
293
}
294
 
294
 
295
rgb getpixel(point p)
295
rgb getpixel(point p)
296
{
296
{
297
	rgb c;
297
    rgb c;
298
 
298
 
299
	enable_drawing();
299
    enable_drawing();
300
	c = GetPixel(dc, p.x, p.y);
300
    c = GetPixel(dc, p.x, p.y);
301
	c = ((c&0x000000FFL)<<16) | (c&0x0000FF00L) |
301
    c = ((c&0x000000FFL)<<16) | (c&0x0000FF00L) |
302
		((c&0x00FF0000L)>>16);
302
	((c&0x00FF0000L)>>16);
303
	return c;
303
    return c;
304
}
304
}
305
 
305
 
306
void setpixel(point p, rgb c)
306
void setpixel(point p, rgb c)
307
{
307
{
308
	rgb old = current->hue;
308
    rgb old = current->hue;
309
 
309
 
310
	enable_drawing();
310
    enable_drawing();
311
	setrgb(c);
311
    setrgb(c);
312
	SelectObject(dc, the_brush);
312
    SelectObject(dc, the_brush);
313
	PatBlt(dc, p.x, p.y, 1, 1, pat_mode[current->mode]);
313
    PatBlt(dc, p.x, p.y, 1, 1, pat_mode[current->mode]);
314
	SelectObject(dc, GetStockObject(NULL_BRUSH));
314
    SelectObject(dc, GetStockObject(NULL_BRUSH));
315
	setrgb(old);
315
    setrgb(old);
316
}
316
}
317
 
317
 
318
void moveto(point p)
318
void moveto(point p)
319
{
319
{
320
	current->p = p;
320
    current->p = p;
321
}
321
}
322
 
322
 
323
void lineto(point p)
323
void lineto(point p)
324
{
324
{
325
	drawline(current->p, p);
325
    drawline(current->p, p);
326
	moveto(p);
326
    moveto(p);
327
}
327
}
328
 
328
 
329
void drawpoint(point p)
329
void drawpoint(point p)
330
{
330
{
331
	setpixel(p, current->hue);
331
    setpixel(p, current->hue);
332
}
332
}
333
 
333
 
334
void drawline(point p1, point p2)
334
void drawline(point p1, point p2)
335
{
335
{
336
	if ((p1.x == p2.x) && (p1.y == p2.y))
336
    if ((p1.x == p2.x) && (p1.y == p2.y))
337
		return; /* same point so draw nothing */
337
	return; /* same point so draw nothing */
338
 
338
 
339
	enable_drawing();
339
    enable_drawing();
340
	SelectObject(dc, the_pen);
340
    SelectObject(dc, the_pen);
341
	SetROP2(dc, pen_mode[current->mode]);
341
    SetROP2(dc, pen_mode[current->mode]);
342
	MoveToEx(dc, p1.x, p1.y, NULL);
342
    MoveToEx(dc, p1.x, p1.y, NULL);
343
	LineTo(dc, p2.x, p2.y);
343
    LineTo(dc, p2.x, p2.y);
344
	SelectObject(dc, GetStockObject(NULL_PEN));
344
    SelectObject(dc, GetStockObject(NULL_PEN));
345
}
345
}
346
 
346
 
347
void drawrect(rect r)
347
void drawrect(rect r)
348
{
348
{
349
	enable_drawing();
349
    enable_drawing();
350
	SelectObject(dc, the_pen);
350
    SelectObject(dc, the_pen);
351
	SetROP2(dc, pen_mode[current->mode]);
351
    SetROP2(dc, pen_mode[current->mode]);
352
	Rectangle(dc, r.x, r.y, r.x+r.width, r.y+r.height);
352
    Rectangle(dc, r.x, r.y, r.x+r.width, r.y+r.height);
353
	SelectObject(dc, GetStockObject(NULL_PEN));
353
    SelectObject(dc, GetStockObject(NULL_PEN));
354
}
354
}
355
 
355
 
356
void fillrect(rect r)
356
void fillrect(rect r)
357
{
357
{
358
	enable_drawing();
358
    enable_drawing();
359
	SelectObject(dc, the_brush);
359
    SelectObject(dc, the_brush);
360
	PatBlt(dc, r.x, r.y, r.width, r.height, pat_mode[current->mode]);
360
    PatBlt(dc, r.x, r.y, r.width, r.height, pat_mode[current->mode]);
361
	SelectObject(dc, GetStockObject(NULL_BRUSH));
361
    SelectObject(dc, GetStockObject(NULL_BRUSH));
362
}
362
}
363
 
363
 
364
#define deg2rad(deg) ((deg)*2*Pi/360)
364
#define deg2rad(deg) ((deg)*2*Pi/360)
365
 
365
 
366
void drawarc(rect r, int start_angle, int end_angle)
366
void drawarc(rect r, int start_angle, int end_angle)
367
{
367
{
368
	point p0, p1, p2;
368
    point p0, p1, p2;
369
	double start, end;
369
    double start, end;
370
	int fudge;
370
    int fudge;
371
 
371
 
372
	enable_drawing();
372
    enable_drawing();
373
 
373
 
374
	if (start_angle == end_angle)
374
    if (start_angle == end_angle)
375
		return;
375
	return;
376
	if (((end_angle - start_angle) % 360) == 0) {
376
    if (((end_angle - start_angle) % 360) == 0) {
377
		drawarc(r, 0, 180);
377
	drawarc(r, 0, 180);
378
		drawarc(r, 180, 360);
378
	drawarc(r, 180, 360);
379
		return;
379
	return;
380
	}
380
    }
381
 
381
 
382
	start = deg2rad(start_angle);
382
    start = deg2rad(start_angle);
383
	end = deg2rad(end_angle);
383
    end = deg2rad(end_angle);
384
	p0 = midpt(topleft(r), bottomright(r));
384
    p0 = midpt(topleft(r), bottomright(r));
385
	p1.x = p0.x + (int)(cos(start) * 512); /* arbitrary hypotenuse */
385
    p1.x = p0.x + (int)(cos(start) * 512); /* arbitrary hypotenuse */
386
	p1.y = p0.y - (int)(sin(start) * 512);
386
    p1.y = p0.y - (int)(sin(start) * 512);
387
	p2.x = p0.x + (int)(cos(end) * 512);
387
    p2.x = p0.x + (int)(cos(end) * 512);
388
	p2.y = p0.y - (int)(sin(end) * 512);
388
    p2.y = p0.y - (int)(sin(end) * 512);
389
 
389
 
390
	SelectObject(dc, the_pen);
390
    SelectObject(dc, the_pen);
391
	SetROP2(dc, pen_mode[current->mode]);
391
    SetROP2(dc, pen_mode[current->mode]);
392
	if (current->linewidth % 2) /* Ask Bill Gates why we need this */
392
    if (current->linewidth % 2) /* Ask Bill Gates why we need this */
393
		fudge = 0;
393
	fudge = 0;
394
	else
394
    else
395
		fudge = 1;
395
	fudge = 1;
396
	Arc(dc, r.x, r.y, r.x+r.width+fudge, r.y+r.height+fudge,
396
    Arc(dc, r.x, r.y, r.x+r.width+fudge, r.y+r.height+fudge,
397
		p1.x, p1.y, p2.x, p2.y);
397
	p1.x, p1.y, p2.x, p2.y);
398
	SelectObject(dc, GetStockObject(NULL_PEN));
398
    SelectObject(dc, GetStockObject(NULL_PEN));
399
}
399
}
400
 
400
 
401
void fillarc(rect r, int start_angle, int end_angle)
401
void fillarc(rect r, int start_angle, int end_angle)
402
{
402
{
403
	point p0, p1, p2;
403
    point p0, p1, p2;
404
	double start, end;
404
    double start, end;
405
 
405
 
406
	enable_drawing();
406
    enable_drawing();
407
 
-
 
408
	if (start_angle == end_angle)
-
 
409
		return;
-
 
410
	if (((end_angle - start_angle) % 360) == 0) {
-
 
411
		fillellipse(r);
-
 
412
		return;
-
 
413
	}
-
 
414
 
407
 
-
 
408
    if (start_angle == end_angle)
-
 
409
	return;
-
 
410
    if (((end_angle - start_angle) % 360) == 0) {
-
 
411
	fillellipse(r);
-
 
412
	return;
-
 
413
    }
-
 
414
 
415
	start = deg2rad(start_angle);
415
    start = deg2rad(start_angle);
416
	end = deg2rad(end_angle);
416
    end = deg2rad(end_angle);
417
	p0 = midpt(topleft(r), bottomright(r));
417
    p0 = midpt(topleft(r), bottomright(r));
418
	p1.x = p0.x + (int)(cos(start) * 512); /* arbitrary hypotenuse */
418
    p1.x = p0.x + (int)(cos(start) * 512); /* arbitrary hypotenuse */
419
	p1.y = p0.y - (int)(sin(start) * 512);
419
    p1.y = p0.y - (int)(sin(start) * 512);
420
	p2.x = p0.x + (int)(cos(end) * 512);
420
    p2.x = p0.x + (int)(cos(end) * 512);
421
	p2.y = p0.y - (int)(sin(end) * 512);
421
    p2.y = p0.y - (int)(sin(end) * 512);
422
 
422
 
423
	SelectObject(dc, the_brush);
423
    SelectObject(dc, the_brush);
424
	SetROP2(dc, pen_mode[current->mode]);
424
    SetROP2(dc, pen_mode[current->mode]);
425
	Pie(dc, r.x, r.y, r.x+r.width+1, r.y+r.height+1,
425
    Pie(dc, r.x, r.y, r.x+r.width+1, r.y+r.height+1,
426
		p1.x, p1.y, p2.x, p2.y);
426
	p1.x, p1.y, p2.x, p2.y);
427
	SelectObject(dc, GetStockObject(NULL_BRUSH));
427
    SelectObject(dc, GetStockObject(NULL_BRUSH));
428
}
428
}
429
 
429
 
430
void drawellipse(rect r)
430
void drawellipse(rect r)
431
{
431
{
432
	enable_drawing();
432
    enable_drawing();
433
	SelectObject(dc, the_pen);
433
    SelectObject(dc, the_pen);
434
	SetROP2(dc, pen_mode[current->mode]);
434
    SetROP2(dc, pen_mode[current->mode]);
435
	Ellipse(dc, r.x, r.y, r.x+r.width, r.y+r.height);
435
    Ellipse(dc, r.x, r.y, r.x+r.width, r.y+r.height);
436
	SelectObject(dc, GetStockObject(NULL_PEN));
436
    SelectObject(dc, GetStockObject(NULL_PEN));
437
}
437
}
438
 
438
 
439
/*
439
/*
440
 *  The old fillellipse function.
440
 *  The old fillellipse function.
441
 *
441
 *
Line 443... Line 443...
443
 *  which is not symmetric and also produces strange results
443
 *  which is not symmetric and also produces strange results
444
 *  at low sizes (the 'ellipses' look egg-shaped).
444
 *  at low sizes (the 'ellipses' look egg-shaped).
445
 */
445
 */
446
void oldfillellipse(rect r)
446
void oldfillellipse(rect r)
447
{
447
{
448
	enable_drawing();
448
    enable_drawing();
449
	SelectObject(dc, the_brush);
449
    SelectObject(dc, the_brush);
450
	SetROP2(dc, pen_mode[current->mode]);
450
    SetROP2(dc, pen_mode[current->mode]);
451
	Ellipse(dc, r.x, r.y, r.x+r.width+1, r.y+r.height+1);
451
    Ellipse(dc, r.x, r.y, r.x+r.width+1, r.y+r.height+1);
452
	SelectObject(dc, GetStockObject(NULL_BRUSH));
452
    SelectObject(dc, GetStockObject(NULL_BRUSH));
453
}
453
}
454
 
454
 
455
/*
455
/*
456
 *  Fill an ellipse using a stored rectangle algorithm.
456
 *  Fill an ellipse using a stored rectangle algorithm.
457
 *
457
 *
Line 461... Line 461...
461
 */
461
 */
462
#define fastfillrect(x,y,w,h) PatBlt(dc,(x),(y),(w),(h),mode)
462
#define fastfillrect(x,y,w,h) PatBlt(dc,(x),(y),(w),(h),mode)
463
 
463
 
464
void fillellipse(rect r)
464
void fillellipse(rect r)
465
{			/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
465
{			/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
466
	register long mode = pat_mode[current->mode];
466
    register long mode = pat_mode[current->mode];
467
 
467
 
468
	int w_odd = (r.width & 0x0001);
468
    int w_odd = (r.width & 0x0001);
469
	int h_odd = (r.height & 0x0001);
469
    int h_odd = (r.height & 0x0001);
470
	int a = r.width >> 1;
470
    int a = r.width >> 1;
471
	int b = r.height >> 1;
471
    int b = r.height >> 1;
472
	point c = pt(r.x+a,r.y+b);
472
    point c = pt(r.x+a,r.y+b);
473
	int x = 0;
473
    int x = 0;
474
	int y = b;
474
    int y = b;
475
	long a2 = a*a;
475
    long a2 = a*a;
476
	long b2 = b*b;
476
    long b2 = b*b;
477
	long xcrit = ((a2+a2+a2) >> 2) + 1;
477
    long xcrit = ((a2+a2+a2) >> 2) + 1;
478
	long ycrit = ((b2+b2+b2) >> 2) + 1;
478
    long ycrit = ((b2+b2+b2) >> 2) + 1;
479
	long t = b2 + a2 - (a2+a2)*b;	/* t = e(x+1,y-1) */
479
    long t = b2 + a2 - (a2+a2)*b;	/* t = e(x+1,y-1) */
480
	long dxt = b2*(3+x+x);
480
    long dxt = b2*(3+x+x);
481
	long dyt = a2*(3-y-y);
481
    long dyt = a2*(3-y-y);
482
	int d2xt = b2+b2;
482
    int d2xt = b2+b2;
483
	int d2yt = a2+a2;
483
    int d2yt = a2+a2;
484
	int stored = 0;
484
    int stored = 0;
485
	int sx = 0, sy = 0, sh = 0; /* stored values of x, y, height */
485
    int sx = 0, sy = 0, sh = 0; /* stored values of x, y, height */
486
 
486
 
487
	if ((r.width > 31) && (r.height > 31)) {
487
    if ((r.width > 31) && (r.height > 31)) {
488
		oldfillellipse(r);
488
	oldfillellipse(r);
489
		return;
489
	return;
490
	}
490
    }
491
	if ((r.width < 3) || (r.height < 3)) {
491
    if ((r.width < 3) || (r.height < 3)) {
492
		fillrect(r);
492
	fillrect(r);
493
		return;
493
	return;
494
	}
494
    }
495
 
495
 
496
	enable_drawing();
496
    enable_drawing();
497
	SelectObject(dc, the_brush);
497
    SelectObject(dc, the_brush);
498
 
498
 
499
	if (w_odd == 0) {
499
    if (w_odd == 0) {
500
		fastfillrect(c.x-1,c.y-b,2,r.height);
500
	fastfillrect(c.x-1,c.y-b,2,r.height);
501
	}
501
    }
502
 
502
 
503
	while (y > 0) {
503
    while (y > 0) {
504
 
504
 
505
		if (stored) {
505
	if (stored) {
506
			if (sx != x) { /* output stored rect */
506
	    if (sx != x) { /* output stored rect */
507
				fastfillrect(c.x-sx,c.y-sy,
507
		fastfillrect(c.x-sx,c.y-sy,
508
					sx+sx+w_odd,sh);
508
			     sx+sx+w_odd,sh);
509
				fastfillrect(c.x-sx,c.y+sy+h_odd-sh,
509
		fastfillrect(c.x-sx,c.y+sy+h_odd-sh,
510
					sx+sx+w_odd,sh);
510
			     sx+sx+w_odd,sh);
511
				stored = 0;
-
 
512
			}
-
 
513
			else /* increment height of stored rect */
-
 
514
				sh++;
-
 
515
		}
-
 
516
 
-
 
517
		if (t + a2*y < xcrit) { /* e(x+1,y-1/2) <= 0 */
-
 
518
			/* move left and right to encounter edge */
-
 
519
			x += 1;
-
 
520
			t += dxt;
-
 
521
			dxt += d2xt;
-
 
522
		} else if (t - b2*x >= ycrit) { /* e(x+1/2,y-1) > 0 */
-
 
523
			/* drop down one line */
-
 
524
			if (!stored) {
-
 
525
				sx = x;
-
 
526
				sy = y;
-
 
527
				sh = 1;
-
 
528
				stored = 1;
-
 
529
			}
-
 
530
			y -= 1;
-
 
531
			t += dyt;
-
 
532
			dyt += d2yt;
-
 
533
		} else {
-
 
534
			/* drop diagonally down and out */
-
 
535
			if (!stored) {
-
 
536
				sx = x;
-
 
537
				sy = y;
-
 
538
				sh = 1;
-
 
539
				stored = 1;
-
 
540
			}
-
 
541
 
-
 
542
			x += 1;
-
 
543
			y -= 1;
-
 
544
			t += dxt + dyt;
-
 
545
			dxt += d2xt;
-
 
546
			dyt += d2yt;
-
 
547
		}
-
 
548
	}
-
 
549
	if (stored) { /* output stored rectangle */
-
 
550
		fastfillrect(c.x-sx,c.y-sy,sx+sx+w_odd,sh);
-
 
551
		fastfillrect(c.x-sx,c.y+sy+h_odd-sh,sx+sx+w_odd,sh);
-
 
552
		stored = 0;
511
		stored = 0;
-
 
512
	    }
-
 
513
	    else /* increment height of stored rect */
-
 
514
		sh++;
-
 
515
	}
-
 
516
 
-
 
517
	if (t + a2*y < xcrit) { /* e(x+1,y-1/2) <= 0 */
-
 
518
	    /* move left and right to encounter edge */
-
 
519
	    x += 1;
-
 
520
	    t += dxt;
-
 
521
	    dxt += d2xt;
-
 
522
	} else if (t - b2*x >= ycrit) { /* e(x+1/2,y-1) > 0 */
-
 
523
	    /* drop down one line */
-
 
524
	    if (!stored) {
-
 
525
		sx = x;
-
 
526
		sy = y;
-
 
527
		sh = 1;
-
 
528
		stored = 1;
-
 
529
	    }
-
 
530
	    y -= 1;
-
 
531
	    t += dyt;
-
 
532
	    dyt += d2yt;
-
 
533
	} else {
-
 
534
	    /* drop diagonally down and out */
-
 
535
	    if (!stored) {
-
 
536
		sx = x;
-
 
537
		sy = y;
-
 
538
		sh = 1;
-
 
539
		stored = 1;
-
 
540
	    }
-
 
541
 
-
 
542
	    x += 1;
-
 
543
	    y -= 1;
-
 
544
	    t += dxt + dyt;
-
 
545
	    dxt += d2xt;
-
 
546
	    dyt += d2yt;
553
	}
547
	}
-
 
548
    }
-
 
549
    if (stored) { /* output stored rectangle */
-
 
550
	fastfillrect(c.x-sx,c.y-sy,sx+sx+w_odd,sh);
-
 
551
	fastfillrect(c.x-sx,c.y+sy+h_odd-sh,sx+sx+w_odd,sh);
-
 
552
	stored = 0;
-
 
553
    }
554
	if (x <= a){
554
    if (x <= a){
555
		fastfillrect(c.x-a,c.y-y,a+a+w_odd,1);
555
	fastfillrect(c.x-a,c.y-y,a+a+w_odd,1);
556
		fastfillrect(c.x-a,c.y+y-1+h_odd,a+a+w_odd,1);
556
	fastfillrect(c.x-a,c.y+y-1+h_odd,a+a+w_odd,1);
557
	}
557
    }
558
 
558
 
559
	SelectObject(dc, GetStockObject(NULL_BRUSH));
559
    SelectObject(dc, GetStockObject(NULL_BRUSH));
560
}
560
}
561
 
561
 
562
void drawroundrect(rect r)
562
void drawroundrect(rect r)
563
{
563
{
564
	int minimum, radius;
564
    int minimum, radius;
565
 
565
 
566
	enable_drawing();
566
    enable_drawing();
567
	SelectObject(dc, the_pen);
567
    SelectObject(dc, the_pen);
568
	SetROP2(dc, pen_mode[current->mode]);
568
    SetROP2(dc, pen_mode[current->mode]);
569
	minimum = min(r.width, r.height);
569
    minimum = min(r.width, r.height);
570
	if ((radius = minimum/2) < 16)
570
    if ((radius = minimum/2) < 16)
571
		radius = 16;
571
	radius = 16;
572
	RoundRect(dc, r.x, r.y, r.x+r.width, r.y+r.height,
572
    RoundRect(dc, r.x, r.y, r.x+r.width, r.y+r.height,
573
		radius, radius);
573
	      radius, radius);
574
	SelectObject(dc, GetStockObject(NULL_PEN));
574
    SelectObject(dc, GetStockObject(NULL_PEN));
575
}
575
}
576
 
576
 
577
void fillroundrect(rect r)
577
void fillroundrect(rect r)
578
{
578
{
579
	int minimum, radius;
579
    int minimum, radius;
580
 
580
 
581
	enable_drawing();
581
    enable_drawing();
582
	SelectObject(dc, the_brush);
582
    SelectObject(dc, the_brush);
583
	SetROP2(dc, pen_mode[current->mode]);
583
    SetROP2(dc, pen_mode[current->mode]);
584
	minimum = min(r.width, r.height);
584
    minimum = min(r.width, r.height);
585
	if ((radius = minimum/2) < 16)
585
    if ((radius = minimum/2) < 16)
586
		radius = 16;
586
	radius = 16;
587
	RoundRect(dc, r.x, r.y, r.x+r.width+1, r.y+r.height+1,
587
    RoundRect(dc, r.x, r.y, r.x+r.width+1, r.y+r.height+1,
588
		radius, radius);
588
	      radius, radius);
589
	SelectObject(dc, GetStockObject(NULL_BRUSH));
589
    SelectObject(dc, GetStockObject(NULL_BRUSH));
590
}
590
}
591
 
591
 
592
void drawpolygon(point *p, int n)
592
void drawpolygon(point *p, int n)
593
{
593
{
594
	enable_drawing();
594
    enable_drawing();
595
	SelectObject(dc, the_pen);
595
    SelectObject(dc, the_pen);
596
	SetROP2(dc, pen_mode[current->mode]);
596
    SetROP2(dc, pen_mode[current->mode]);
597
	Polyline(dc, (POINT FAR *) p, n);
597
    Polyline(dc, (POINT FAR *) p, n);
598
	SelectObject(dc, GetStockObject(NULL_PEN));
598
    SelectObject(dc, GetStockObject(NULL_PEN));
599
}
599
}
600
 
600
 
601
void fillpolygon(point *p, int n)
601
void fillpolygon(point *p, int n)
602
{
602
{
603
	enable_drawing();
603
    enable_drawing();
604
	SelectObject(dc, the_brush);
604
    SelectObject(dc, the_brush);
605
	SetROP2(dc, pen_mode[current->mode]);
605
    SetROP2(dc, pen_mode[current->mode]);
606
	Polygon(dc, (POINT FAR *) p, n);
606
    Polygon(dc, (POINT FAR *) p, n);
607
	SelectObject(dc, GetStockObject(NULL_BRUSH));
607
    SelectObject(dc, GetStockObject(NULL_BRUSH));
608
}
608
}
609
 
609
 
610
/*
610
/*
611
 *  String drawing functions.
611
 *  String drawing functions.
612
 */
612
 */
Line 614... Line 614...
614
/*
614
/*
615
 *  Drawstr returns the width of the string drawn.
615
 *  Drawstr returns the width of the string drawn.
616
 */
616
 */
617
int drawstr(point p, const char *s)
617
int drawstr(point p, const char *s)
618
{
618
{
619
	POINT curr_pos;
619
    POINT curr_pos;
620
	int width;
620
    int width;
621
	HFONT old;
621
    HFONT old;
622
 
622
 
623
	enable_drawing();
623
    enable_drawing();
624
	SetTextColor(dc, win_rgb); /* set colour */
624
    SetTextColor(dc, win_rgb); /* set colour */
625
	if (! current->fnt)
625
    if (! current->fnt)
626
		current->fnt = SystemFont;
626
	current->fnt = SystemFont;
627
	old = SelectObject(dc, current->fnt->handle);
627
    old = SelectObject(dc, current->fnt->handle);
628
	MoveToEx(dc, p.x, p.y, NULL);
628
    MoveToEx(dc, p.x, p.y, NULL);
629
	SetBkMode(dc, TRANSPARENT);
629
    SetBkMode(dc, TRANSPARENT);
630
	SetTextAlign(dc, TA_LEFT | TA_UPDATECP);
630
    SetTextAlign(dc, TA_LEFT | TA_UPDATECP);
631
 
631
 
632
	TextOut(dc, p.x, p.y, s, strlen(s));
632
    TextOut(dc, p.x, p.y, s, strlen(s));
633
 
633
 
634
	GetCurrentPositionEx(dc, &curr_pos);
634
    GetCurrentPositionEx(dc, &curr_pos);
635
	width = curr_pos.x - p.x;
635
    width = curr_pos.x - p.x;
636
	SelectObject(dc, old);
636
    SelectObject(dc, old);
637
	/* always leave a DC with no real font selected */
637
    /* always leave a DC with no real font selected */
638
 
638
 
639
	return width;
639
    return width;
640
}
640
}
641
 
641
 
642
rect strrect(font f, const char *s)
642
rect strrect(font f, const char *s)
643
{
643
{
644
	SIZE size;
644
    SIZE size;
645
	long h;
645
    long h;
646
	HFONT old;
646
    HFONT old;
647
	HDC dc;
647
    HDC dc;
648
 
648
 
649
	if (! f)
649
    if (! f)
650
		f = SystemFont;
650
	f = SystemFont;
651
 
651
 
652
	h = getheight(f);
652
    h = getheight(f);
653
 
653
 
654
	dc = GetDC(0); /* get screen dc */
654
    dc = GetDC(0); /* get screen dc */
655
	old = SelectObject(dc, f->handle);
655
    old = SelectObject(dc, f->handle);
656
	GetTextExtentPoint(dc, (LPSTR) s, strlen(s), &size);
656
    GetTextExtentPoint(dc, (LPSTR) s, strlen(s), &size);
657
	SelectObject(dc, old);
657
    SelectObject(dc, old);
658
	ReleaseDC(0, dc);
658
    ReleaseDC(0, dc);
659
 
659
 
660
	return rect(0,0,size.cx, h);
660
    return rect(0,0,size.cx, h);
661
}
661
}
662
 
662
 
663
point strsize(font f, const char *s)
663
point strsize(font f, const char *s)
664
{
664
{
665
	rect r = strrect(f,s);
665
    rect r = strrect(f,s);
666
	return pt(r.width, r.height);
666
    return pt(r.width, r.height);
667
}
667
}
668
 
668
 
669
int strwidth(font f, const char *s)
669
int strwidth(font f, const char *s)
670
{
670
{
671
	rect r = strrect(f,s);
671
    rect r = strrect(f,s);
672
	return r.width;
672
    return r.width;
673
}
673
}
674
 
674
 
675
/*
675
/*
676
 *  Draw an image:
676
 *  Draw an image:
677
 */
677
 */
678
void drawimage(image img, rect dr, rect sr)
678
void drawimage(image img, rect dr, rect sr)
679
{
679
{
680
	bitmap b;
680
    bitmap b;
681
	image i = img;
681
    image i = img;
682
 
682
 
683
	if (! img)
683
    if (! img)
684
		return;
684
	return;
685
	enable_drawing();
685
    enable_drawing();
686
	dr = rcanon(dr);
686
    dr = rcanon(dr);
687
	if ((dr.width != img->width) || (dr.height != img->height))
687
    if ((dr.width != img->width) || (dr.height != img->height))
688
		i = scaleimage(img, rect(0,0,dr.width,dr.height), sr);
688
	i = scaleimage(img, rect(0,0,dr.width,dr.height), sr);
689
	b = imagetobitmap(i);
689
    b = imagetobitmap(i);
690
	copyrect(b, pt(dr.x,dr.y), getrect(b));
690
    copyrect(b, pt(dr.x,dr.y), getrect(b));
691
	del(b);
691
    del(b);
692
	if (i != img)
692
    if (i != img)
693
		del(i);
693
	del(i);
694
}
694
}