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