The R Project SVN R

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4394 ripley 1
/*
2
 * GraphApp - Cross-Platform Graphics Programming Library.
3
 *
4
 * File: context.c -- internal functions for manipulating DCs.
5
 * Platform: Windows  Version: 2.35  Date: 1998/04/04
6
 *
7
 * Version: 1.00  Changes: Original version by Lachlan Patrick.
8
 * Version: 1.05  Changes: Added drawstate information.
9
 * Version: 1.50  Changes: New colour system, dithered grey.
10
 * Version: 2.00  Changes: New object class and context sub-system.
11
 * Version: 2.01  Changes: get_context is now more bulletproof.
12
 * Version: 2.02  Changes: drawto and setwinrgb have been updated.
13
 * Version: 2.20  Changes: Added currentrgb, currentfont etc.
14
 * Version: 2.35  Changes: New reference count technique.
15
 */
16
 
17
/* Copyright (C) 1993-1998 Lachlan Patrick
18
 
19
   This file is part of GraphApp, a cross-platform C graphics library.
20
 
21
   GraphApp is free software; you can redistribute it and/or modify it
22
   under the terms of the GNU Library General Public License.
23
   GraphApp is distributed in the hope that it will be useful, but
24
   WITHOUT ANY WARRANTY.
25
 
26
   See the file COPYLIB.TXT for details.
27
*/
28
 
9184 ripley 29
/* Changes for R:  allow 32 contexts not 4 */
30
 
4394 ripley 31
#include "internal.h"
32
 
33
/*
34
 *  Private library variables.
35
 */
36
 
37
	PROTECTED drawstruct app_drawstate =
38
		{
39
			NULL,	/* drawing destination */
40
			Black,	/* colour */
41
			S,  	/* drawing mode */
42
			{0,0},	/* point */
43
			1,  	/* line width */
44
			NULL,	/* font */
45
			NULL,	/* cursor */
46
		};
47
 
48
	PROTECTED drawstate current = & app_drawstate;
49
	PROTECTED HDC       dc;	/* shared DC variable */
50
	PROTECTED HPEN      the_pen   = 0;
51
	PROTECTED HBRUSH    the_brush = 0;
52
 
53
	PROTECTED COLORREF win_rgb  = 0L;
54
 
55
/*
56
 *  Private drawing context variables.
57
 */
58
 
59
	static	rgb 	prev_pixval	= Black;
60
	static	int 	prev_width	= 1;
61
 
62
	static	bitmap	grey_bitmap	= NULL;
63
 
64
	static rgb grey_cmap [] = {
65
		0x00000000UL,
66
		0x00FFFFFFUL,
67
	};
68
	static byte grey_pixels [] = {
69
	  0, 1, 0, 1, 0, 1, 0, 1,
70
	  1, 0, 1, 0, 1, 0, 1, 0,
71
	  0, 1, 0, 1, 0, 1, 0, 1,
72
	  1, 0, 1, 0, 1, 0, 1, 0,
73
	  0, 1, 0, 1, 0, 1, 0, 1,
74
	  1, 0, 1, 0, 1, 0, 1, 0,
75
	  0, 1, 0, 1, 0, 1, 0, 1,
76
	  1, 0, 1, 0, 1, 0, 1, 0,
77
	};
78
	static imagedata grey_imagedata = {
79
		8,	/* depth */
80
		8,	/* width */
81
		8,	/* height */
82
		2,	/* cmapsize */
83
		grey_cmap,
84
		grey_pixels
85
	};
86
	static image grey_image = & grey_imagedata;
87
 
88
/*
89
 *  Private context list structure
90
 */
91
	typedef struct contextinfo  contextinfo;
92
 
93
	struct contextinfo
94
	{
95
		object	obj;	/* back pointer to drawing object */
96
		HDC 	dc; 	/* handle to DC used when drawing */
97
		HGDIOBJ old_bitmap; /* bitmap returned by SelectObject() */
98
	};
99
 
100
/*
101
 *  The constant MAX_CONTEXTS controls how large the
102
 *  circular array of contexts is, and thus how many
103
 *  concurrently active contexts there can be.  This
104
 *  number should be at least 2,  since bitblt needs
105
 *  two contexts for source and destination bitmaps.
106
 */
107
	#define MAX_CONTEXTS 32
108
 
109
	static contextinfo context[MAX_CONTEXTS];
110
	static int num_contexts = 0;
111
	static int empty_slot = 0;
112
 
113
/*
114
 *  Create a pen and a brush for use in drawing.
115
 */
116
static void create_pen_and_brush(rgb c, unsigned long winrgb,
117
		int width, int depth)
118
{
119
	the_pen = CreatePen(PS_INSIDEFRAME, width, winrgb);
120
 
121
	if ((depth == 1) && (c == Grey))
122
		the_brush = CreatePatternBrush(grey_bitmap->handle);
123
	else
124
		the_brush = CreateSolidBrush(winrgb);
125
}
126
 
127
/*
128
 *  Delete any created pens and brushes.
129
 *  Assumes they are not selected into any valid DC.
130
 */
131
static void delete_pen_and_brush(void)
132
{
133
	DeleteObject(the_pen);
134
	DeleteObject(the_brush);
135
}
136
 
137
/*
138
 *  Set Windows drawing globals up.
139
 */
140
PROTECTED
141
void init_contexts(void)
142
{
143
	grey_bitmap = imagetobitmap(grey_image);
144
	grey_bitmap->text = new_string("grey_bitmap");
145
 
146
	current = & app_drawstate;
147
	app_drawstate.fnt = SystemFont;
148
	app_drawstate.crsr = ArrowCursor;
149
 
150
	create_pen_and_brush(Black, Black, 1, 0);
151
}
152
 
153
static void free_context(contextinfo *c)
154
{
155
	if (! c->dc)
156
		return; /* already been deleted */
157
 
158
	SelectObject(c->dc, GetStockObject(NULL_PEN));
159
	SelectObject(c->dc, GetStockObject(NULL_BRUSH));
160
 
161
	if (c->obj->kind & ControlObject)
162
		ReleaseDC(c->obj->handle, c->dc);
163
	else if (c->obj->kind == BitmapObject) {
164
		SelectObject(c->dc, c->old_bitmap);
165
		DeleteDC(c->dc);
166
	}
167
 
168
	if (dc == c->dc)
169
		dc = 0;
170
 
171
	c->dc = 0;
172
	c->obj = NULL;
173
	c->old_bitmap = 0;
174
}
175
 
176
/*
177
 *  Add a new DC into our list of DCs.
178
 */
179
PROTECTED
180
void add_context(object obj, HDC dc, HGDIOBJ old)
181
{
182
	contextinfo *c;
183
 
184
	/* Clear a spot for the new DC if the array is full. */
185
	if (num_contexts == MAX_CONTEXTS) {
186
		c = & context[empty_slot];
187
		free_context(c);
188
		empty_slot = (empty_slot+1) % MAX_CONTEXTS;
189
	} else {
190
		c = & context[num_contexts];
191
		num_contexts++;
192
	}
193
	/* Add this context to the list. */
194
	c->obj = obj;
195
	c->dc = dc;
196
	c->old_bitmap = old;
197
}
198
 
199
/*
200
 *  Find and return a DC for a window or a bitmap.
201
 *  Also keep track of which DCs have been created.
202
 */
203
PROTECTED
204
HDC get_context(object obj)
205
{
206
	int i;
207
	HDC dc;
208
	HGDIOBJ old;
209
 
210
	/* Determine if a DC for this object already exists. */
211
	for (i = 0; i < num_contexts; i++) {
212
		if (context[i].obj == obj)
213
			return context[i].dc;
214
	}
215
 
216
	/* Use GetDC or CreateCompatibleDC to return a DC. */
217
	if (obj->kind & ControlObject) {
218
		dc = GetDC(obj->handle);
219
		add_context(obj, dc, 0);
220
	}
221
	else if (obj->kind == BitmapObject) {
222
		dc = CreateCompatibleDC(0);
223
		old = SelectObject(dc, obj->handle);
224
		add_context(obj, dc, old);
225
	}
226
	else {
227
		return NULL;
228
	/* apperror("Cannot find DC for non-drawable object."); */
229
	}
230
 
231
	/* We only select in the brush or pen we need, when we
232
	 * need it. Thus at all other times, they are NULL.
233
	 * This ensures we can delete objects when we want, and
234
	 * also makes correct context possible. */
235
	SelectObject(dc, GetStockObject(NULL_PEN));
236
	SelectObject(dc, GetStockObject(NULL_BRUSH));
237
 
238
	return dc;
239
}
240
 
241
/*
242
 *  Remove the context from the list by blanking its fields.
243
 *  It is assumed that the DC has previously been released,
244
 *  for example by EndPaint() in the events.c file.
245
 */
246
PROTECTED
247
void remove_context(object obj)
248
{
249
	int i;
250
	contextinfo *c;
251
 
252
	for (i = 0; i < num_contexts; i++) {
253
		c = & context[i];
254
		if (c->obj == obj) {
255
			c->obj = NULL;
256
			c->dc = 0;
257
			c->old_bitmap = 0;
258
			empty_slot = i;
259
		}
260
	}
261
}
262
 
263
/*
264
 *  Free the DC associated with a given object.
265
 */
266
PROTECTED
267
void del_context(object obj)
268
{
269
	int i;
270
	contextinfo *c;
271
 
272
	for (i = 0; i < num_contexts; i++) {
273
		c = & context[i];
274
		if (c->obj == obj) {
275
			free_context(c);
276
			c->obj = NULL;
277
			c->dc = 0;
278
			c->old_bitmap = 0;
279
			empty_slot = i;
280
		}
281
	}
282
}
283
 
284
/*
285
 *  Get rid of all DCs.
286
 */
287
PROTECTED
288
void del_all_contexts(void)
289
{
290
	int i;
291
	contextinfo *c;
292
 
293
	for (i = 0; i < num_contexts; i++) {
294
		c = & context[i];
295
		free_context(c);
296
		c->obj = NULL;
297
		c->dc = 0;
298
		c->old_bitmap = 0;
299
	}
300
	num_contexts = 0;
301
	empty_slot = 0;
302
}
303
 
304
/*
305
 *  De-initialise drawing variables.
306
 */
307
PROTECTED
308
void finish_contexts(void)
309
{
310
	del_all_contexts();
311
	DeleteObject(the_pen);
312
	DeleteObject(the_brush);
313
}
314
 
315
/*
316
 *  Set up a pen and a brush for use in colouring things, and return
317
 *  the Windows RGB value equivalent to the library rgb value.
318
 */
319
static unsigned long set_win_rgb(rgb c, int width)
320
{
321
	int r, g, b;
322
	long luminance;
323
	int depth;
324
	unsigned long winrgb;
325
 
326
	if (current->mode == Ones)
327
		c = White;
328
	else if (current->mode == Zeros)
329
		c = Black;
330
 
331
	r = (int) ((c >> 16) & 0x000000FFL);
332
	g = (int) ((c >>  8) & 0x000000FFL);
333
	b = (int) ((c >>  0) & 0x000000FFL);
334
 
335
	depth = getdepth(current->dest);
336
 
337
	if (depth <= 2)	/* map to black or white, or grey if c == Grey */
338
	{
339
		luminance = (r*3 + g*5 + b) / 9;
340
		if (luminance > 0x0087)		r = g = b = 0x00FF;
341
		else if (luminance <= 0x0077)	r = g = b = 0x0000;
342
		else				r = g = b = 0x0080;
343
		c = rgb(r,g,b);
344
	}
345
 
346
	winrgb = RGB(r, g, b);
347
 
348
	/* Has a colour or width change occured? */
349
	if ((c != prev_pixval) || (width != prev_width))
350
	{
351
		prev_pixval = c;
352
		prev_width = width;
353
 
354
		/* delete any old objects */
355
		delete_pen_and_brush();
356
 
357
		/* set up new objects */
358
		create_pen_and_brush(c, winrgb, width, depth);
359
	}
360
	return winrgb;
361
}
362
 
363
void setcursor(cursor c)
364
{
365
	decrease_refcount(current->crsr);
366
	current->crsr = c;
367
	if (c) SetCursor((HCURSOR) c->handle);
368
	increase_refcount(c);
369
}
370
 
371
void setfont(font f)
372
{
373
	decrease_refcount(current->fnt);
374
	current->fnt = f;
375
	increase_refcount(f);
376
}
377
 
378
/*
379
 *  Set the way that source and destination pixels are combined
380
 *  when drawing.
381
 */
382
void setdrawmode(int mode)
383
{
384
	current->mode = mode & 0x0F; /* must be between 0x00 and 0x0F */
385
}
386
 
387
/*
388
 *  Set the colour.
389
 */
390
void setrgb(rgb hue)
391
{
392
	current->hue = hue;
393
	win_rgb = set_win_rgb(hue, current->linewidth);
394
}
395
 
396
/*
397
 *  Set the line width.
398
 */
399
void setlinewidth(int width)
400
{
401
	if (width < 1)
402
		width = 1;
403
	current->linewidth = width;
404
	win_rgb = set_win_rgb(current->hue, current->linewidth);
405
}
406
 
407
/*
408
 *  Set which window/menubar/menu to add new objects too.
409
 */
410
void addto(object obj)
411
{
412
	if (! obj)
413
		return;
414
	switch (obj->kind) {
415
		case WindowObject:	current_window = obj;	break;
416
		case MenubarObject:	current_menubar = obj;	break;
417
		case MenuObject:	current_menu = obj;	break;
418
	}
419
}
420
 
421
/*
422
 *  Set which bitmap or window to draw to; allocate a DC too.
423
 */
424
void drawto(drawing d)
425
{
426
	if (! d) {
427
		current = & app_drawstate;
428
		current->dest = NULL;
429
		return;
430
	}
431
 
432
	dc = get_context(d);
433
 
434
	if (d->drawstate) {
435
		/* Change the current drawing state to this one. */
436
		current = d->drawstate;
437
		current->dest = d;
438
		win_rgb = set_win_rgb(current->hue, current->linewidth);
439
	}
440
	else {
441
		/* Otherwise just use the current drawing state. */
442
		current->dest = d;
443
	}
444
}
445
 
446
/*
447
 *  Ensure drawing variables are set up.
448
 */
449
void setdrawstate(drawstate s)
450
{
451
	if (! s)
452
		return;
453
	moveto(s->p);
454
	setdrawmode(s->mode);
455
	setcursor(s->crsr);
456
	setfont(s->fnt);
457
	setlinewidth(s->linewidth);
458
	setrgb(s->hue);
459
}
460
 
461
/*
462
 *  Change the current drawstate to the specified one.
463
 */
464
void restoredrawstate(drawstate s)
465
{
466
	if (! s)
467
		return;
468
	setdrawstate(s);
469
	discard(s);
470
}
471
 
472
/*
473
 *  Reset drawing variables to initial values.
474
 */
475
void resetdrawstate(void)
476
{
477
	setrgb(Black);
478
	setlinewidth(1);
479
	setcursor(ArrowCursor);
480
	moveto(pt(0,0));
481
	setfont(SystemFont);
482
	setdrawmode(S);
483
}
484
 
485
/*
486
 *  Return a new copy of the current drawing state.
487
 */
488
drawstate copydrawstate(void)
489
{
490
	drawstate s = NULL;
491
 
492
	if (current) {
493
		s = create(drawstruct);
494
		if (s)
495
			*s = *current;
496
	}
497
	return s;
498
}
499
 
500
/*
501
 *  Return drawing state information.
502
 */
503
 
504
drawing	currentdrawing(void)    { return current->dest; }
505
rgb 	currentrgb(void)        { return current->hue; }
506
int 	currentmode(void)       { return current->mode; }
507
point	currentpoint(void)      { return current->p; }
508
int 	currentlinewidth(void)  { return current->linewidth; }
509
font	currentfont(void)       { return current->fnt; }
510
cursor	currentcursor(void)     { return current->crsr; }
511
 
512
int 	getkeystate(void)       { return keystate; }