The R Project SVN R

Rev

Rev 27357 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 27357 Rev 27686
1
/*
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1998--2001  Guido Masarotto and Brian Ripley
3
 *  Copyright (C) 1998--2001  Guido Masarotto and Brian Ripley
4
 *
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
8
 *  (at your option) any later version.
9
 *
9
 *
10
 *  This program is distributed in the hope that it will be useful,
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
13
 *  GNU General Public License for more details.
14
 *
14
 *
15
 *  You should have received a copy of the GNU General Public License
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
18
 */
19
 
19
 
20
/*
20
/*
21
   A version of drawing.c without current/state.
21
   A version of drawing.c without current/state.
22
   More safe in case of multiple redrawing
22
   More safe in case of multiple redrawing
23
 */
23
 */
24
 
24
 
25
#include "internal.h"
25
#include "internal.h"
26
#include <winbase.h>
26
#include <winbase.h>
27
 
27
 
28
static HDC GETHDC(drawing d)
28
static HDC GETHDC(drawing d)
29
{
29
{
30
  if (!d)
30
  if (!d)
31
  {
31
  {
32
      DebugBreak();
32
      DebugBreak();
33
      return (HDC) 0; /* We should never get here, but we do? */
33
      return (HDC) 0; /* We should never get here, but we do? */
34
  }
34
  }
35
  if ( (d->kind == PrinterObject)|| (d->kind == MetafileObject))
35
  if ( (d->kind == PrinterObject)|| (d->kind == MetafileObject))
36
  {
36
  {
37
     HDC dc = (HDC) d->handle ;
37
     HDC dc = (HDC) d->handle ;
38
     SelectObject(dc, GetStockObject(NULL_PEN));
38
     SelectObject(dc, GetStockObject(NULL_PEN));
39
     SelectObject(dc, GetStockObject(NULL_BRUSH));
39
     SelectObject(dc, GetStockObject(NULL_BRUSH));
40
     return dc ;
40
     return dc ;
41
  }
41
  }
42
  else
42
  else
43
     return get_context(d);
43
     return get_context(d);
44
}
44
}
45
 
45
 
46
 
46
 
47
/*
47
/*
48
 *  Some clipping functions.
48
 *  Some clipping functions.
49
 */
49
 */
50
rect ggetcliprect(drawing d)
50
rect ggetcliprect(drawing d)
51
{
51
{
52
    RECT R;
52
    RECT R;
53
    rect r;
53
    rect r;
54
    HDC dc = GETHDC(d);
54
    HDC dc = GETHDC(d);
55
    GetClipBox(dc, &R);
55
    GetClipBox(dc, &R);
56
    r.x = R.left;
56
    r.x = R.left;
57
    r.y = R.top;
57
    r.y = R.top;
58
    r.width = R.right - R.left;
58
    r.width = R.right - R.left;
59
    r.height = R.bottom - R.top;
59
    r.height = R.bottom - R.top;
60
    return r;
60
    return r;
61
}
61
}
62
 
62
 
63
void gsetcliprect(drawing d, rect r)
63
void gsetcliprect(drawing d, rect r)
64
{
64
{
65
    HRGN rgn;
65
    HRGN rgn;
66
    HDC dc = GETHDC(d);
66
    HDC dc = GETHDC(d);
67
    rgn = CreateRectRgn(r.x, r.y, r.x + r.width, r.y + r.height);
67
    rgn = CreateRectRgn(r.x, r.y, r.x + r.width, r.y + r.height);
68
    SelectClipRgn(dc, rgn);
68
    SelectClipRgn(dc, rgn);
69
    DeleteObject(rgn);
69
    DeleteObject(rgn);
70
}
70
}
71
 
71
 
72
 
72
 
73
void gbitblt(drawing db, drawing sb, point p, rect r)
73
void gbitblt(drawing db, drawing sb, point p, rect r)
74
{
74
{
75
    HDC src;
75
    HDC src;
76
    HDC dst;
76
    HDC dst;
77
 
77
 
78
    dst = GETHDC(db);
78
    dst = GETHDC(db);
79
    src = GETHDC(sb);
79
    src = GETHDC(sb);
80
    BitBlt(dst, p.x, p.y, r.width, r.height, src, r.x, r.y, SRCCOPY);
80
    BitBlt(dst, p.x, p.y, r.width, r.height, src, r.x, r.y, SRCCOPY);
81
}
81
}
82
 
82
 
83
 
83
 
84
 
84
 
85
/* dp gives the amount to scroll; r the full rectangle to scroll */
85
/* dp gives the amount to scroll; r the full rectangle to scroll */
86
void gscroll(drawing d, point dp, rect r)
86
void gscroll(drawing d, point dp, rect r)
87
{
87
{
88
    HDC dc = GETHDC(d);
88
    HDC dc = GETHDC(d);
89
    RECT rr ;
89
    RECT rr ;
90
    rr.left = r.x;
90
    rr.left = r.x;
91
    rr.top = r.y;
91
    rr.top = r.y;
92
    rr.right = r.x + r.width;
92
    rr.right = r.x + r.width;
93
    rr.bottom = r.y + r.height;
93
    rr.bottom = r.y + r.height;
94
    ScrollDC(dc, dp.x , dp.y , &rr, &rr, 0, NULL);
94
    ScrollDC(dc, dp.x , dp.y , &rr, &rr, 0, NULL);
95
}
95
}
96
 
96
 
97
void ginvert(drawing d, rect r)
97
void ginvert(drawing d, rect r)
98
{
98
{
99
    HDC dc = GETHDC(d);
99
    HDC dc = GETHDC(d);
100
 
100
 
101
    PatBlt(dc, r.x, r.y, r.width, r.height, DSTINVERT);
101
    PatBlt(dc, r.x, r.y, r.width, r.height, DSTINVERT);
102
}
102
}
103
 
103
 
104
rgb ggetpixel(drawing d, point p)
104
rgb ggetpixel(drawing d, point p)
105
{
105
{
106
    rgb c;
106
    rgb c;
107
    HDC dc = GETHDC(d);
107
    HDC dc = GETHDC(d);
108
 
108
 
109
    c = GetPixel(dc, p.x, p.y);
109
    c = GetPixel(dc, p.x, p.y);
110
    c = ((c&0x000000FFL)<<16) | (c&0x0000FF00L) |
110
    c = ((c&0x000000FFL)<<16) | (c&0x0000FF00L) |
111
	((c&0x00FF0000L)>>16);
111
	((c&0x00FF0000L)>>16);
112
    return c;
112
    return c;
113
}
113
}
114
 
114
 
115
static COLORREF getwinrgb(drawing d, rgb c)
115
static COLORREF getwinrgb(drawing d, rgb c)
116
{
116
{
117
    int r, g, b;
117
    int r, g, b;
118
    long luminance;
118
    long luminance;
119
    int depth;
119
    int depth;
120
 
120
 
121
    r = (int) ((c >> 16) & 0x000000FFL);
121
    r = (int) ((c >> 16) & 0x000000FFL);
122
    g = (int) ((c >>  8) & 0x000000FFL);
122
    g = (int) ((c >>  8) & 0x000000FFL);
123
    b = (int) ((c >>  0) & 0x000000FFL);
123
    b = (int) ((c >>  0) & 0x000000FFL);
124
    depth = getdepth(d);
124
    depth = getdepth(d);
125
    if (depth <= 2)	/* map to black or white, or grey if c == Grey */
125
    if (depth <= 2)	/* map to black or white, or grey if c == Grey */
126
    {
126
    {
127
	luminance = (r*3 + g*5 + b) / 9;
127
	luminance = (r*3 + g*5 + b) / 9;
128
	if (luminance > 0x0087)		r = g = b = 0x00FF;
128
	if (luminance > 0x0087)		r = g = b = 0x00FF;
129
	else if (luminance <= 0x0077)	r = g = b = 0x0000;
129
	else if (luminance <= 0x0077)	r = g = b = 0x0000;
130
	else				r = g = b = 0x0080;
130
	else				r = g = b = 0x0080;
131
	c = rgb(r, g, b);
131
	c = rgb(r, g, b);
132
    }
132
    }
133
    return RGB(r, g, b);
133
    return RGB(r, g, b);
134
}
134
}
135
 
135
 
136
void gsetpixel(drawing d, point p, rgb c)
136
void gsetpixel(drawing d, point p, rgb c)
137
{
137
{
138
    HDC dc = GETHDC(d);
138
    HDC dc = GETHDC(d);
139
    HBRUSH br = CreateSolidBrush(getwinrgb(d, c));
139
    HBRUSH br = CreateSolidBrush(getwinrgb(d, c));
140
 
140
 
141
    fix_brush(dc, d, br);
141
    fix_brush(dc, d, br);
142
    SelectObject(dc, br);
142
    SelectObject(dc, br);
143
    PatBlt(dc, p.x, p.y, 1, 1, PATCOPY);
143
    PatBlt(dc, p.x, p.y, 1, 1, PATCOPY);
144
    SelectObject(dc, GetStockObject(NULL_BRUSH));
144
    SelectObject(dc, GetStockObject(NULL_BRUSH));
145
    DeleteObject(br);
145
    DeleteObject(br);
146
}
146
}
147
 
147
 
148
typedef struct {
148
typedef struct {
149
    HDC dc;
149
    HDC dc;
150
    int len2; /* squared length of current dash */
150
    int len2; /* squared length of current dash */
151
    int curseg, on; /* current dash (0-7), on/off flag */
151
    int curseg, on; /* current dash (0-7), on/off flag */
152
    int style, width;
152
    int style, width;
153
    int curx, cury; /* start of current dash */
153
    int curx, cury; /* start of current dash */
154
} DashStruct;
154
} DashStruct;
155
 
155
 
156
static int npieces;
156
static int npieces;
157
 
157
 
158
static void CALLBACK  gLineHelper(int x, int y, LPARAM aa)
158
static void CALLBACK  gLineHelper(int x, int y, LPARAM aa)
159
{
159
{
160
    DashStruct *a = (DashStruct *) aa;
160
    DashStruct *a = (DashStruct *) aa;
161
    int distx, disty;
161
    int distx, disty;
162
 
162
 
163
    npieces++;
163
    npieces++;
164
    distx = x - (a->curx);
164
    distx = x - (a->curx);
165
    disty = y - (a->cury);
165
    disty = y - (a->cury);
166
    if (distx*distx + disty*disty >= (a->len2)) {
166
    if (distx*distx + disty*disty >= (a->len2)) {
167
	if (a->on)
167
	if (a->on)
168
	    LineTo(a->dc, x, y);
168
	    LineTo(a->dc, x, y);
169
	else
169
	else
170
	    MoveToEx(a->dc, x, y, NULL);
170
	    MoveToEx(a->dc, x, y, NULL);
171
	a->curx = x;
171
	a->curx = x;
172
	a->cury = y;
172
	a->cury = y;
173
	a->len2 = 0;
173
	a->len2 = 0;
174
	while (!a->len2) {
174
	while (!a->len2) {
175
	    a->curseg = (a->curseg + 4) % 32;
175
	    a->curseg = (a->curseg + 4) % 32;
176
	    a->len2 = (((a->style) >> (a->curseg)) & 15) * (a->width);
176
	    a->len2 = (((a->style) >> (a->curseg)) & 15) * (a->width);
177
	    a->len2 = (a->len2) * (a->len2);
177
	    a->len2 = (a->len2) * (a->len2);
178
	    a->on = (a->on) ? 0 : 1;
178
	    a->on = (a->on) ? 0 : 1;
179
	}
179
	}
180
    }
180
    }
181
}
181
}
182
 
182
 
183
void gdrawline(drawing d, int width, int style, rgb c, point p1, point p2,
183
void gdrawline(drawing d, int width, int style, rgb c, point p1, point p2,
184
	       int fast)
184
	       int fast)
185
{
185
{
186
   point p[2];
186
   point p[2];
187
   p[0] = p1;
187
   p[0] = p1;
188
   p[1] = p2;
188
   p[1] = p2;
189
   gdrawpolyline( d, width, style, c, p, 2, 0, fast);
189
   gdrawpolyline( d, width, style, c, p, 2, 0, fast);
190
}
190
}
191
 
191
 
192
void gdrawpolyline(drawing d, int width, int style, rgb c,
192
void gdrawpolyline(drawing d, int width, int style, rgb c,
193
                   point p[], int n, int closepath, int fast)
193
                   point p[], int n, int closepath, int fast)
194
{
194
{
195
    int tmpx, tmpy, tmp;
195
    int tmpx, tmpy, tmp;
196
    HDC dc = GETHDC(d);
196
    HDC dc = GETHDC(d);
197
    COLORREF winrgb = getwinrgb(d, c);
197
    COLORREF winrgb = getwinrgb(d, c);
198
    LOGBRUSH lb;
198
    LOGBRUSH lb;
199
    HPEN gpen;
199
    HPEN gpen;
200
    int i;
200
    int i;
201
 
201
 
202
    if (n < 2) return;
202
    if (n < 2) return;
203
    lb.lbStyle = BS_SOLID;
203
    lb.lbStyle = BS_SOLID;
204
    lb.lbColor = winrgb;
204
    lb.lbColor = winrgb;
205
    lb.lbHatch = 0;
205
    lb.lbHatch = 0;
206
    if (!style) {
206
    if (!style) {
207
	if (fast)
207
	if (fast)
208
	    gpen = CreatePen(PS_INSIDEFRAME, width, winrgb);
208
	    gpen = CreatePen(PS_INSIDEFRAME, width, winrgb);
209
	else
209
	else
210
	    gpen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_ROUND,
210
	    gpen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_ROUND,
211
				width, &lb, 0, NULL);
211
				width, &lb, 0, NULL);
212
	SelectObject(dc, gpen);
212
	SelectObject(dc, gpen);
213
	SetROP2(dc, R2_COPYPEN);
213
	SetROP2(dc, R2_COPYPEN);
214
        MoveToEx(dc, p[0].x, p[0].y, NULL);
214
        MoveToEx(dc, p[0].x, p[0].y, NULL);
215
        for (i = 1; i < n ; i++)
215
        for (i = 1; i < n ; i++)
216
	      LineTo(dc, p[i].x, p[i].y);
216
	      LineTo(dc, p[i].x, p[i].y);
217
        if (closepath) LineTo(dc, p[0].x, p[0].y);
217
        if (closepath) LineTo(dc, p[0].x, p[0].y);
218
	SelectObject(dc, GetStockObject(NULL_PEN));
218
	SelectObject(dc, GetStockObject(NULL_PEN));
219
	DeleteObject(gpen);
219
	DeleteObject(gpen);
220
    }
220
    }
221
     else {
221
     else {
222
	DashStruct a;
222
	DashStruct a;
223
	gpen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_ROUND,
223
	gpen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_ROUND,
224
			    width, &lb, 0, NULL);
224
			    width, &lb, 0, NULL);
225
	SelectObject(dc, gpen);
225
	SelectObject(dc, gpen);
226
	SetROP2(dc, R2_COPYPEN);
226
	SetROP2(dc, R2_COPYPEN);
227
	a.on = 1;
227
	a.on = 1;
228
	a.dc = dc;
228
	a.dc = dc;
229
	a.len2 = (style & 15) * width;
229
	a.len2 = (style & 15) * width;
230
	a.len2 = (a.len2) * (a.len2);
230
	a.len2 = (a.len2) * (a.len2);
231
	a.curseg = 0;
231
	a.curseg = 0;
232
	a.style = style;
232
	a.style = style;
233
	a.width = width;
233
	a.width = width;
234
	a.curx = p[0].x;
234
	a.curx = p[0].x;
235
	a.cury = p[0].y;
235
	a.cury = p[0].y;
236
	MoveToEx(dc, p[0].x, p[0].y, NULL);
236
	MoveToEx(dc, p[0].x, p[0].y, NULL);
237
	npieces = 0;
237
	npieces = 0;
238
	BeginPath(dc);
238
	BeginPath(dc);
239
        for (i = 1; i < n; i++) {
239
        for (i = 1; i < n; i++) {
240
 	  LineDDA(p[i-1].x, p[i-1].y, p[i].x, p[i].y, gLineHelper,
240
 	  LineDDA(p[i-1].x, p[i-1].y, p[i].x, p[i].y, gLineHelper,
241
		  (LPARAM) &a);
241
		  (LPARAM) &a);
242
	  if ((p[i].x != a.curx) || (p[i].y != a.cury)) {
242
	  if ((p[i].x != a.curx) || (p[i].y != a.cury)) {
243
	      if (a.on) LineTo(dc, p[i].x, p[i].y);
243
	      if (a.on) LineTo(dc, p[i].x, p[i].y);
244
	      else MoveToEx(dc, p[i].x, p[i].y, NULL);
244
	      else MoveToEx(dc, p[i].x, p[i].y, NULL);
245
	      tmpx = (a.curx-p[i].x);
245
	      tmpx = (a.curx-p[i].x);
246
	      tmpy = (a.cury-p[i].y);
246
	      tmpy = (a.cury-p[i].y);
247
	      tmp = tmpx*tmpx + tmpy*tmpy;
247
	      tmp = tmpx*tmpx + tmpy*tmpy;
248
	      a.len2 = a.len2 + tmp - 2*sqrt((double)(tmp*a.len2));
248
	      a.len2 = a.len2 + tmp - 2*sqrt((double)(tmp*a.len2));
249
	      a.curx = p[i].x;
249
	      a.curx = p[i].x;
250
	      a.cury = p[i].y;
250
	      a.cury = p[i].y;
251
	  }
251
	  }
252
	  if(npieces > 5000) {
252
	  if(npieces > 5000) {
253
	      EndPath(dc);
253
	      EndPath(dc);
254
	      StrokePath(dc);
254
	      StrokePath(dc);
255
	      npieces = 0;
255
	      npieces = 0;
256
	      BeginPath(dc);
256
	      BeginPath(dc);
257
	  }
257
	  }
258
        }
258
        }
259
        if (closepath) {
259
        if (closepath) {
260
          LineDDA(p[n-1].x, p[n-1].y, p[0].x, p[0].y, gLineHelper,
260
          LineDDA(p[n-1].x, p[n-1].y, p[0].x, p[0].y, gLineHelper,
261
		  (LPARAM) &a);
261
		  (LPARAM) &a);
262
	  if (a.on) LineTo(dc,p[0].x,p[0].y);
262
	  if (a.on) LineTo(dc,p[0].x,p[0].y);
263
        }
263
        }
264
	EndPath(dc);
264
	EndPath(dc);
265
	StrokePath(dc);
265
	StrokePath(dc);
266
	SelectObject(dc, GetStockObject(NULL_PEN));
266
	SelectObject(dc, GetStockObject(NULL_PEN));
267
	DeleteObject(gpen);
267
	DeleteObject(gpen);
268
    }
268
    }
269
}
269
}
270
 
270
 
271
void gdrawrect(drawing d, int width, int style, rgb c, rect r, int fast)
271
void gdrawrect(drawing d, int width, int style, rgb c, rect r, int fast)
272
{
272
{
273
    int x0 = r.x;
273
    int x0 = r.x;
274
    int y0 = r.y;
274
    int y0 = r.y;
275
    int x1 = r.x + r.width;
275
    int x1 = r.x + r.width;
276
    int y1 = r.y + r.height;
276
    int y1 = r.y + r.height;
277
    point p[4];
277
    point p[4];
278
    p[0] = pt(x0,y0);
278
    p[0] = pt(x0,y0);
279
    p[1] = pt(x1,y0);
279
    p[1] = pt(x1,y0);
280
    p[2] = pt(x1,y1);
280
    p[2] = pt(x1,y1);
281
    p[3] = pt(x0,y1);
281
    p[3] = pt(x0,y1);
282
    gdrawpolyline(d, width, style, c, p, 4, 1, fast);
282
    gdrawpolyline(d, width, style, c, p, 4, 1, fast);
283
}
283
}
284
 
284
 
285
void gfillrect(drawing d, rgb fill, rect r)
285
void gfillrect(drawing d, rgb fill, rect r)
286
{
286
{
287
    HDC dc = GETHDC(d);
287
    HDC dc = GETHDC(d);
288
    HBRUSH br = CreateSolidBrush(getwinrgb(d, fill));
288
    HBRUSH br = CreateSolidBrush(getwinrgb(d, fill));
289
    fix_brush(dc, d, br);
289
    fix_brush(dc, d, br);
290
    SelectObject(dc, br);
290
    SelectObject(dc, br);
291
    PatBlt(dc, r.x, r.y, r.width, r.height, PATCOPY);
291
    PatBlt(dc, r.x, r.y, r.width, r.height, PATCOPY);
292
    SelectObject(dc, GetStockObject(NULL_BRUSH));
292
    SelectObject(dc, GetStockObject(NULL_BRUSH));
293
    DeleteObject(br);
293
    DeleteObject(br);
294
}
294
}
295
 
295
 
296
void gdrawellipse(drawing d, int width, rgb border, rect r, int fast)
296
void gdrawellipse(drawing d, int width, rgb border, rect r, int fast)
297
{
297
{
298
    HDC dc = GETHDC(d);
298
    HDC dc = GETHDC(d);
299
    LOGBRUSH lb;
299
    LOGBRUSH lb;
300
    HPEN gpen;
300
    HPEN gpen;
301
    if (fast)
301
    if (fast)
302
	gpen = CreatePen(PS_INSIDEFRAME, width, getwinrgb(d, border));
302
	gpen = CreatePen(PS_INSIDEFRAME, width, getwinrgb(d, border));
303
    else {
303
    else {
304
	lb.lbStyle = BS_SOLID;
304
	lb.lbStyle = BS_SOLID;
305
	lb.lbColor = getwinrgb(d, border);
305
	lb.lbColor = getwinrgb(d, border);
306
	lb.lbHatch = 0;
306
	lb.lbHatch = 0;
307
	gpen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_ROUND,
307
	gpen = ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_ROUND,
308
			    width, &lb, 0, NULL);
308
			    width, &lb, 0, NULL);
309
    }
309
    }
310
    SelectObject(dc, gpen);
310
    SelectObject(dc, gpen);
311
    SetROP2(dc, R2_COPYPEN);
311
    SetROP2(dc, R2_COPYPEN);
312
    Ellipse(dc, r.x, r.y, r.x+r.width, r.y+r.height);
312
    Ellipse(dc, r.x, r.y, r.x+r.width, r.y+r.height);
313
    SelectObject(dc, GetStockObject(NULL_PEN));
313
    SelectObject(dc, GetStockObject(NULL_PEN));
314
    DeleteObject(gpen);
314
    DeleteObject(gpen);
315
}
315
}
316
 
316
 
317
void goldfillellipse(drawing d, rgb fill, rect r)
317
void goldfillellipse(drawing d, rgb fill, rect r)
318
{
318
{
319
    HDC dc = GETHDC(d);
319
    HDC dc = GETHDC(d);
320
    HBRUSH br = CreateSolidBrush(getwinrgb(d, fill));
320
    HBRUSH br = CreateSolidBrush(getwinrgb(d, fill));
321
    fix_brush(dc, d, br);
321
    fix_brush(dc, d, br);
322
    SelectObject(dc, br);
322
    SelectObject(dc, br);
323
    Ellipse(dc, r.x, r.y, r.x+r.width, r.y+r.height);
323
    Ellipse(dc, r.x, r.y, r.x+r.width, r.y+r.height);
324
    SelectObject(dc, GetStockObject(NULL_BRUSH));
324
    SelectObject(dc, GetStockObject(NULL_BRUSH));
325
    DeleteObject(br);
325
    DeleteObject(br);
326
}
326
}
327
 
327
 
328
 
328
 
329
#ifndef fastfillrect
329
#ifndef fastfillrect
330
#define fastfillrect(x, y, w, h) PatBlt(dc, (x), (y), (w), (h), mode)
330
#define fastfillrect(x, y, w, h) PatBlt(dc, (x), (y), (w), (h), mode)
331
#endif
331
#endif
332
 
332
 
333
void gfillellipse(drawing d, rgb fill, rect r)
333
void gfillellipse(drawing d, rgb fill, rect r)
334
{			/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
334
{			/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
335
    register long mode = PATCOPY;
335
    register long mode = PATCOPY;
336
    int w_odd = (r.width & 0x0001);
336
    int w_odd = (r.width & 0x0001);
337
    int h_odd = (r.height & 0x0001);
337
    int h_odd = (r.height & 0x0001);
338
    int a = r.width >> 1;
338
    int a = r.width >> 1;
339
    int b = r.height >> 1;
339
    int b = r.height >> 1;
340
    point c = pt(r.x+a,r.y+b);
340
    point c = pt(r.x+a,r.y+b);
341
    int x = 0;
341
    int x = 0;
342
    int y = b;
342
    int y = b;
343
    long a2 = a*a;
343
    long a2 = a*a;
344
    long b2 = b*b;
344
    long b2 = b*b;
345
    long xcrit = ((a2+a2+a2) >> 2) + 1;
345
    long xcrit = ((a2+a2+a2) >> 2) + 1;
346
    long ycrit = ((b2+b2+b2) >> 2) + 1;
346
    long ycrit = ((b2+b2+b2) >> 2) + 1;
347
    long t = b2 + a2 - (a2+a2)*b;	/* t = e(x+1,y-1) */
347
    long t = b2 + a2 - (a2+a2)*b;	/* t = e(x+1,y-1) */
348
    long dxt = b2*(3+x+x);
348
    long dxt = b2*(3+x+x);
349
    long dyt = a2*(3-y-y);
349
    long dyt = a2*(3-y-y);
350
    int d2xt = b2+b2;
350
    int d2xt = b2+b2;
351
    int d2yt = a2+a2;
351
    int d2yt = a2+a2;
352
    int stored = 0;
352
    int stored = 0;
353
    int sx = 0, sy = 0, sh = 0; /* stored values of x, y, height */
353
    int sx = 0, sy = 0, sh = 0; /* stored values of x, y, height */
354
    HDC dc;
354
    HDC dc;
355
    HBRUSH br;
355
    HBRUSH br;
356
 
356
 
357
    if ((r.width > 31) && (r.height > 31)) {
357
    if ((r.width > 31) && (r.height > 31)) {
358
	goldfillellipse(d, fill, r);
358
	goldfillellipse(d, fill, r);
359
	return;
359
	return;
360
    }
360
    }
361
    if ((r.width < 3) || (r.height < 3)) {
361
    if ((r.width < 3) || (r.height < 3)) {
362
	gfillrect(d, fill, r);
362
	gfillrect(d, fill, r);
363
	return;
363
	return;
364
    }
364
    }
365
    dc = GETHDC(d);
365
    dc = GETHDC(d);
366
    br = CreateSolidBrush(getwinrgb(d, fill));
366
    br = CreateSolidBrush(getwinrgb(d, fill));
367
    fix_brush(dc, d, br);
367
    fix_brush(dc, d, br);
368
    SelectObject(dc, br);
368
    SelectObject(dc, br);
369
 
369
 
370
    if (w_odd == 0) {
370
    if (w_odd == 0) {
371
	fastfillrect(c.x-1,c.y-b,2,r.height);
371
	fastfillrect(c.x-1,c.y-b,2,r.height);
372
    }
372
    }
373
 
373
 
374
    while (y > 0) {
374
    while (y > 0) {
375
	if (stored) {
375
	if (stored) {
376
	    if (sx != x) { /* output stored rect */
376
	    if (sx != x) { /* output stored rect */
377
		fastfillrect(c.x-sx,c.y-sy, sx+sx+w_odd,sh);
377
		fastfillrect(c.x-sx,c.y-sy, sx+sx+w_odd,sh);
378
		fastfillrect(c.x-sx,c.y+sy+h_odd-sh, sx+sx+w_odd,sh);
378
		fastfillrect(c.x-sx,c.y+sy+h_odd-sh, sx+sx+w_odd,sh);
379
		stored = 0;
379
		stored = 0;
380
	    }
380
	    }
381
	    else /* increment height of stored rect */
381
	    else /* increment height of stored rect */
382
		sh++;
382
		sh++;
383
	}
383
	}
384
	if (t + a2*y < xcrit) { /* e(x+1,y-1/2) <= 0 */
384
	if (t + a2*y < xcrit) { /* e(x+1,y-1/2) <= 0 */
385
	    /* move left and right to encounter edge */
385
	    /* move left and right to encounter edge */
386
	    x += 1;
386
	    x += 1;
387
	    t += dxt;
387
	    t += dxt;
388
	    dxt += d2xt;
388
	    dxt += d2xt;
389
	} else if (t - b2*x >= ycrit) { /* e(x+1/2,y-1) > 0 */
389
	} else if (t - b2*x >= ycrit) { /* e(x+1/2,y-1) > 0 */
390
	    /* drop down one line */
390
	    /* drop down one line */
391
	    if (!stored) {
391
	    if (!stored) {
392
		sx = x;
392
		sx = x;
393
		sy = y;
393
		sy = y;
394
		sh = 1;
394
		sh = 1;
395
		stored = 1;
395
		stored = 1;
396
	    }
396
	    }
397
	    y -= 1;
397
	    y -= 1;
398
	    t += dyt;
398
	    t += dyt;
399
	    dyt += d2yt;
399
	    dyt += d2yt;
400
	} else {
400
	} else {
401
	    /* drop diagonally down and out */
401
	    /* drop diagonally down and out */
402
	    if (!stored) {
402
	    if (!stored) {
403
		sx = x;
403
		sx = x;
404
		sy = y;
404
		sy = y;
405
		sh = 1;
405
		sh = 1;
406
		stored = 1;
406
		stored = 1;
407
	    }
407
	    }
408
 
408
 
409
	    x += 1;
409
	    x += 1;
410
	    y -= 1;
410
	    y -= 1;
411
	    t += dxt + dyt;
411
	    t += dxt + dyt;
412
	    dxt += d2xt;
412
	    dxt += d2xt;
413
	    dyt += d2yt;
413
	    dyt += d2yt;
414
	}
414
	}
415
    }
415
    }
416
    if (stored) { /* output stored rectangle */
416
    if (stored) { /* output stored rectangle */
417
	fastfillrect(c.x-sx, c.y-sy, sx+sx+w_odd, sh);
417
	fastfillrect(c.x-sx, c.y-sy, sx+sx+w_odd, sh);
418
	fastfillrect(c.x-sx, c.y+sy+h_odd-sh, sx+sx+w_odd, sh);
418
	fastfillrect(c.x-sx, c.y+sy+h_odd-sh, sx+sx+w_odd, sh);
419
	stored = 0;
419
	stored = 0;
420
    }
420
    }
421
    if (x <= a){
421
    if (x <= a){
422
	fastfillrect(c.x-a, c.y-y, a+a+w_odd, 1);
422
	fastfillrect(c.x-a, c.y-y, a+a+w_odd, 1);
423
	fastfillrect(c.x-a, c.y+y-1+h_odd, a+a+w_odd, 1);
423
	fastfillrect(c.x-a, c.y+y-1+h_odd, a+a+w_odd, 1);
424
    }
424
    }
425
    SelectObject(dc, GetStockObject(NULL_BRUSH));
425
    SelectObject(dc, GetStockObject(NULL_BRUSH));
426
    DeleteObject(br);
426
    DeleteObject(br);
427
}
427
}
428
 
428
 
429
 
429
 
430
void gfillpolygon(drawing d, rgb fill, point *p, int n)
430
void gfillpolygon(drawing d, rgb fill, point *p, int n)
431
{
431
{
432
   HDC dc = GETHDC(d);
432
   HDC dc = GETHDC(d);
433
   HBRUSH br = CreateSolidBrush(getwinrgb(d,fill));
433
   HBRUSH br = CreateSolidBrush(getwinrgb(d,fill));
434
   fix_brush(dc, d, br);
434
   fix_brush(dc, d, br);
435
   SelectObject(dc, br);
435
   SelectObject(dc, br);
436
   Polygon(dc, (POINT FAR *) p, n);
436
   Polygon(dc, (POINT FAR *) p, n);
437
   SelectObject(dc, GetStockObject(NULL_BRUSH));
437
   SelectObject(dc, GetStockObject(NULL_BRUSH));
438
   DeleteObject(br);
438
   DeleteObject(br);
439
}
439
}
440
 
440
 
441
/* For ordinary text, e.g. in console */
441
/* For ordinary text, e.g. in console */
442
int gdrawstr(drawing d, font f, rgb c, point p, char *s)
442
int gdrawstr(drawing d, font f, rgb c, point p, char *s)
443
{
443
{
444
    POINT curr_pos;
444
    POINT curr_pos;
445
    int width;
445
    int width;
446
    HFONT old;
446
    HFONT old;
447
    HDC dc = GETHDC(d);
447
    HDC dc = GETHDC(d);
448
 
448
 
449
    SetTextColor(dc, getwinrgb(d,c));
449
    SetTextColor(dc, getwinrgb(d,c));
450
    old = SelectObject(dc, f->handle);
450
    old = SelectObject(dc, f->handle);
451
    MoveToEx(dc, p.x, p.y, NULL);
451
    MoveToEx(dc, p.x, p.y, NULL);
452
    SetBkMode(dc, TRANSPARENT);
452
    SetBkMode(dc, TRANSPARENT);
453
    SetTextAlign(dc, TA_TOP | TA_LEFT | TA_UPDATECP);
453
    SetTextAlign(dc, TA_TOP | TA_LEFT | TA_UPDATECP);
454
 
454
 
455
    TextOut(dc, p.x, p.y, s, strlen(s));
455
    TextOut(dc, p.x, p.y, s, strlen(s));
456
 
456
 
457
    GetCurrentPositionEx(dc, &curr_pos);
457
    GetCurrentPositionEx(dc, &curr_pos);
458
    width = curr_pos.x - p.x;
458
    width = curr_pos.x - p.x;
459
    SelectObject(dc, old);
459
    SelectObject(dc, old);
460
 
460
 
461
    return width;
461
    return width;
462
}
462
}
463
 
463
 
464
/* This version aligns on baseline, and allows hadj = 0, 0.5, 1 */
464
/* This version aligns on baseline, and allows hadj = 0, 0.5, 1 */
465
void gdrawstr1(drawing d, font f, rgb c, point p, char *s, double hadj)
465
void gdrawstr1(drawing d, font f, rgb c, point p, char *s, double hadj)
466
{
466
{
467
    HFONT old;
467
    HFONT old;
468
    HDC dc = GETHDC(d);
468
    HDC dc = GETHDC(d);
469
    UINT flags = TA_BASELINE | TA_UPDATECP;
469
    UINT flags = TA_BASELINE | TA_UPDATECP;
470
 
470
 
471
    SetTextColor(dc, getwinrgb(d,c));
471
    SetTextColor(dc, getwinrgb(d,c));
472
    old = SelectObject(dc, f->handle);
472
    old = SelectObject(dc, f->handle);
473
    MoveToEx(dc, p.x, p.y, NULL);
473
    MoveToEx(dc, p.x, p.y, NULL);
474
    SetBkMode(dc, TRANSPARENT);
474
    SetBkMode(dc, TRANSPARENT);
475
    if (hadj < 0.25) flags |= TA_LEFT;
475
    if (hadj < 0.25) flags |= TA_LEFT;
476
    else if (hadj < 0.75) flags |= TA_CENTER;
476
    else if (hadj < 0.75) flags |= TA_CENTER;
477
    else flags |= TA_RIGHT;
477
    else flags |= TA_RIGHT;
478
    SetTextAlign(dc, flags);
478
    SetTextAlign(dc, flags);
479
    TextOut(dc, p.x, p.y, s, strlen(s));
479
    TextOut(dc, p.x, p.y, s, strlen(s));
480
    SelectObject(dc, old);
480
    SelectObject(dc, old);
481
}
481
}
482
 
482
 
483
rect gstrrect(drawing d, font f, char *s)
483
rect gstrrect(drawing d, font f, char *s)
484
{
484
{
485
    SIZE size;
485
    SIZE size;
486
    HFONT old;
486
    HFONT old;
487
    HDC dc;
487
    HDC dc;
488
    if (! f)
488
    if (! f)
489
	f = SystemFont;
489
	f = SystemFont;
490
    if (d)
490
    if (d)
491
	dc = GETHDC(d);
491
	dc = GETHDC(d);
492
    else
492
    else
493
	dc = GetDC(0);
493
	dc = GetDC(0);
494
    old = SelectObject(dc, f->handle);
494
    old = SelectObject(dc, f->handle);
495
    GetTextExtentPoint32(dc, (LPSTR)s, strlen(s), &size);
495
    GetTextExtentPoint32(dc, (LPSTR)s, strlen(s), &size);
496
    SelectObject(dc, old);
496
    SelectObject(dc, old);
497
    if (!d) ReleaseDC(0,dc);
497
    if (!d) ReleaseDC(0,dc);
498
    return rect(0, 0, size.cx, size.cy);
498
    return rect(0, 0, size.cx, size.cy);
499
}
499
}
500
 
500
 
501
point gstrsize(drawing d, font f, char *s)
501
point gstrsize(drawing d, font f, char *s)
502
{
502
{
503
    rect r = gstrrect(d, f, s);
503
    rect r = gstrrect(d, f, s);
504
    return pt(r.width, r.height);
504
    return pt(r.width, r.height);
505
}
505
}
506
 
506
 
507
int gstrwidth(drawing d, font f, char *s)
507
int gstrwidth(drawing d, font f, char *s)
508
{
508
{
509
    rect r = gstrrect(d,f,s);
509
    rect r = gstrrect(d,f,s);
510
    return r.width;
510
    return r.width;
511
}
511
}
512
 
512
 
513
int ghasfixedwidth(font f)
513
int ghasfixedwidth(font f)
514
{
514
{
515
    TEXTMETRIC tm;
515
    TEXTMETRIC tm;
516
    HFONT old;
516
    HFONT old;
517
    HDC dc = GetDC(0);
517
    HDC dc = GetDC(0);
518
    old = SelectObject(dc, (HFONT)f->handle);
518
    old = SelectObject(dc, (HFONT)f->handle);
519
    GetTextMetrics(dc, &tm);
519
    GetTextMetrics(dc, &tm);
520
    SelectObject(dc, old);
520
    SelectObject(dc, old);
521
    ReleaseDC(0,dc);
521
    ReleaseDC(0,dc);
522
    return !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
522
    return !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
523
}
523
}
524
 
524
 
525
void gcharmetric(drawing d, font f, int c, int *ascent, int *descent,
525
void gcharmetric(drawing d, font f, int c, int *ascent, int *descent,
526
		 int *width)
526
		 int *width)
527
{
527
{
528
    int first, last, extra;
528
    int first, last, extra;
529
    TEXTMETRIC tm;
529
    TEXTMETRIC tm;
530
    HFONT old;
530
    HFONT old;
531
    HDC dc = GETHDC(d);
531
    HDC dc = GETHDC(d);
532
    old = SelectObject(dc, (HFONT)f->handle);
532
    old = SelectObject(dc, (HFONT)f->handle);
533
    GetTextMetrics(dc, &tm);
533
    GetTextMetrics(dc, &tm);
534
    first = tm.tmFirstChar;
534
    first = tm.tmFirstChar;
535
    last = tm.tmLastChar;
535
    last = tm.tmLastChar;
536
    extra = tm.tmExternalLeading + tm.tmInternalLeading - 1;
536
    extra = tm.tmExternalLeading + tm.tmInternalLeading - 1;
537
    if(c < 0) { /* used for setting cra */
537
    if(c < 0) { /* used for setting cra */
538
      SIZE size;
538
      SIZE size;
539
      char* cc="M";
539
      char* cc="M";
540
      GetTextExtentPoint32(dc,(LPSTR) cc, 1, &size);
540
      GetTextExtentPoint32(dc,(LPSTR) cc, 1, &size);
541
      *descent = tm.tmDescent ;
541
      *descent = tm.tmDescent ;
542
      *ascent = size.cy - *descent;
542
      *ascent = size.cy - *descent;
543
      *width = size.cx;
543
      *width = size.cx;
544
      if(*width > size.cy) *width = size.cy;
544
      if(*width > size.cy) *width = size.cy;
545
    } else if(c == 0) {
545
    } else if(c == 0) {
546
	*descent = tm.tmDescent ;
546
	*descent = tm.tmDescent ;
547
        *ascent = tm.tmHeight - *descent - extra ;
547
        *ascent = tm.tmHeight - *descent - extra ;
548
	*width = tm.tmMaxCharWidth ;
548
	*width = tm.tmMaxCharWidth ;
549
    } else if((first <= c) && (c <= last)) {
549
    } else if((first <= c) && (c <= last)) {
550
      SIZE size;
550
      SIZE size;
551
      GetTextExtentPoint32(dc,(LPSTR) &c, 1, &size);
551
      GetTextExtentPoint32(dc,(LPSTR) &c, 1, &size);
552
      *descent = tm.tmDescent ;
552
      *descent = tm.tmDescent ;
553
      *ascent = size.cy - *descent - extra ;
553
      *ascent = size.cy - *descent - extra ;
554
      *width = size.cx;
554
      *width = size.cx;
555
      /*
555
      /*
556
	 Under NT, ' ' gives 0 ascent and descent, which seems
556
	 Under NT, ' ' gives 0 ascent and descent, which seems
557
	 correct but this : (i) makes R engine to center in random way;
557
	 correct but this : (i) makes R engine to center in random way;
558
	 (ii) doesn't correspond to what 98 and X do (' ' is there
558
	 (ii) doesn't correspond to what 98 and X do (' ' is there
559
	 high as the full font)
559
	 high as the full font)
560
      */
560
      */
561
      if ((c!=' ') && (tm.tmPitchAndFamily & TMPF_TRUETYPE)) {
561
      if ((c!=' ') && (tm.tmPitchAndFamily & TMPF_TRUETYPE)) {
562
        GLYPHMETRICS gm;
562
        GLYPHMETRICS gm;
563
        MAT2 m2;
563
        MAT2 m2;
564
	m2.eM11.value = m2.eM22.value = (WORD) 1 ;
564
	m2.eM11.value = m2.eM22.value = (WORD) 1 ;
565
	m2.eM21.value = m2.eM12.value = (WORD) 0 ;
565
	m2.eM21.value = m2.eM12.value = (WORD) 0 ;
566
	m2.eM11.fract = m2.eM12.fract =
566
	m2.eM11.fract = m2.eM12.fract =
567
	  m2.eM21.fract = m2.eM22.fract =  (short) 0 ;
567
	  m2.eM21.fract = m2.eM22.fract =  (short) 0 ;
568
        if (GetGlyphOutline(dc,c,GGO_METRICS,&gm,0,NULL,&m2) != GDI_ERROR) {
568
        if (GetGlyphOutline(dc,c,GGO_METRICS,&gm,0,NULL,&m2) != GDI_ERROR) {
569
	  *descent = gm.gmBlackBoxY - gm.gmptGlyphOrigin.y ;
569
	  *descent = gm.gmBlackBoxY - gm.gmptGlyphOrigin.y ;
570
	  *ascent  = gm.gmptGlyphOrigin.y + 1;
570
	  *ascent  = gm.gmptGlyphOrigin.y + 1;
571
        }
571
        }
572
      }
572
      }
573
    } else {
573
    } else {
574
	*ascent = 0;
574
	*ascent = 0;
575
	*descent = 0;
575
	*descent = 0;
576
	*width = 0;
576
	*width = 0;
577
    }
577
    }
578
    SelectObject(dc, old);
578
    SelectObject(dc, old);
579
}
579
}
580
 
580
 
581
font gnewfont(drawing d, char *face, int style, int size, double rot)
581
font gnewfont(drawing d, char *face, int style, int size, double rot)
582
{
582
{
583
    font obj;
583
    font obj;
584
    HFONT hf;
584
    HFONT hf;
585
    LOGFONT lf;
585
    LOGFONT lf;
586
 
586
 
587
    if ((rot <= 45.0) || ((rot > 135) && (rot <= 225)) || (rot > 315))
587
    if ((rot <= 45.0) || ((rot > 135) && (rot <= 225)) || (rot > 315))
588
	lf.lfHeight = -MulDiv(size, devicepixelsy(d), 72);
588
	lf.lfHeight = -MulDiv(size, devicepixelsy(d), 72);
589
    else
589
    else
590
	lf.lfHeight = -MulDiv(size, devicepixelsx(d), 72);
590
	lf.lfHeight = -MulDiv(size, devicepixelsx(d), 72);
591
 
591
 
592
    lf.lfWidth = 0 ;
592
    lf.lfWidth = 0 ;
593
    lf.lfEscapement = lf.lfOrientation = (int) 10*rot;
593
    lf.lfEscapement = lf.lfOrientation = (int) 10*rot;
594
    lf.lfWeight = FW_NORMAL;
594
    lf.lfWeight = FW_NORMAL;
595
    lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
595
    lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
596
    if ((! strcmp(face, "Symbol")) || (! strcmp(face, "Wingdings")))
596
    if ((! strcmp(face, "Symbol")) || (! strcmp(face, "Wingdings")))
597
	lf.lfCharSet = SYMBOL_CHARSET;
597
	lf.lfCharSet = SYMBOL_CHARSET;
598
    else
598
    else
599
	lf.lfCharSet = ANSI_CHARSET;
599
	lf.lfCharSet = ANSI_CHARSET;
600
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
600
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
601
    lf.lfQuality = DEFAULT_QUALITY;
601
    lf.lfQuality = DEFAULT_QUALITY;
602
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
602
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
603
    if ((strlen(face) > 1) && (face[0] == 'T') && (face[1] == 'T')) {
603
    if ((strlen(face) > 1) && (face[0] == 'T') && (face[1] == 'T')) {
604
        char *pf;
604
        char *pf;
605
        lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
605
        lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
606
        for (pf = &face[2]; isspace(*pf) ; pf++);
606
        for (pf = &face[2]; isspace(*pf) ; pf++);
607
        strncpy(lf.lfFaceName, pf, LF_FACESIZE-1);
607
        strncpy(lf.lfFaceName, pf, LF_FACESIZE-1);
608
    }
608
    }
609
    else {
609
    else {
610
        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
610
        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
611
        strncpy(lf.lfFaceName, face, LF_FACESIZE-1);
611
        strncpy(lf.lfFaceName, face, LF_FACESIZE-1);
612
    }
612
    }
613
    if (style & Italic)
613
    if (style & Italic)
614
	lf.lfItalic = 1;
614
	lf.lfItalic = 1;
615
    if (style & Bold)
615
    if (style & Bold)
616
	lf.lfWeight = FW_BOLD;
616
	lf.lfWeight = FW_BOLD;
617
    if (style & FixedWidth)
617
    if (style & FixedWidth)
618
	lf.lfPitchAndFamily |= FIXED_PITCH;
618
	lf.lfPitchAndFamily |= FIXED_PITCH;
619
    if (style & SansSerif)
619
    if (style & SansSerif)
620
	lf.lfPitchAndFamily |= FF_SWISS;
620
	lf.lfPitchAndFamily |= FF_SWISS;
621
 
621
 
622
    if ((hf = CreateFontIndirect(&lf)) == 0)
622
    if ((hf = CreateFontIndirect(&lf)) == 0)
623
	return NULL;
623
	return NULL;
624
 
624
 
625
    obj = new_font_object(hf);
625
    obj = new_font_object(hf);
626
    if (obj)
626
    if (obj)
627
	obj->text = new_string(face);
627
	obj->text = new_string(face);
628
    if (d && ((d->kind == PrinterObject) ||
628
    if (d && ((d->kind == PrinterObject) ||
629
	      (d->kind == MetafileObject))) {
629
	      (d->kind == MetafileObject))) {
630
	TEXTMETRIC tm;
630
	TEXTMETRIC tm;
631
	HFONT old = SelectObject((HDC)d->handle, hf);
631
	HFONT old = SelectObject((HDC)d->handle, hf);
632
	GetTextMetrics((HDC)d->handle, &tm);
632
	GetTextMetrics((HDC)d->handle, &tm);
633
	obj->rect.width = tm.tmAveCharWidth;
633
	obj->rect.width = tm.tmAveCharWidth;
634
	obj->rect.height = tm.tmHeight;
634
	obj->rect.height = tm.tmHeight;
635
	obj->rect.x = tm.tmAscent - tm.tmInternalLeading;
635
	obj->rect.x = tm.tmAscent - tm.tmInternalLeading;
636
	obj->rect.y = tm.tmDescent;
636
	obj->rect.y = tm.tmDescent;
637
	SelectObject((HDC)d->handle, old);
637
	SelectObject((HDC)d->handle, old);
638
    }
638
    }
639
 
639
 
640
    return (font) obj;
640
    return (font) obj;
641
}
641
}
642
 
642
 
643
 
643
 
644
static int measuredev(drawing dev, int what)
644
static int measuredev(drawing dev, int what)
645
{
645
{
646
    HDC hDC;
646
    HDC hDC;
647
    int n;
647
    int n;
648
    if (dev)
648
    if (dev)
649
	hDC = GETHDC(dev);
649
	hDC = GETHDC(dev);
650
    else
650
    else
651
	hDC = GetDC(NULL);
651
	hDC = GetDC(NULL);
652
    n = GetDeviceCaps(hDC, what);
652
    n = GetDeviceCaps(hDC, what);
653
    if (!dev) ReleaseDC(NULL, hDC);
653
    if (!dev) ReleaseDC(NULL, hDC);
654
    return n;
654
    return n;
655
}
655
}
656
 
656
 
657
#define MEASUREDEV(a) {return measuredev(dev,a);}
657
#define MEASUREDEV(a) {return measuredev(dev,a);}
658
 
658
 
659
int devicewidth(drawing dev) MEASUREDEV(HORZRES)
659
int devicewidth(drawing dev) MEASUREDEV(HORZRES)
660
int deviceheight(drawing dev) MEASUREDEV(VERTRES)
660
int deviceheight(drawing dev) MEASUREDEV(VERTRES)
661
int devicewidthmm(drawing dev) MEASUREDEV(HORZSIZE)
661
int devicewidthmm(drawing dev) MEASUREDEV(HORZSIZE)
662
int deviceheightmm(drawing dev) MEASUREDEV(VERTSIZE)
662
int deviceheightmm(drawing dev) MEASUREDEV(VERTSIZE)
663
int devicepixelsx(drawing dev) MEASUREDEV(LOGPIXELSX)
663
int devicepixelsx(drawing dev) MEASUREDEV(LOGPIXELSX)
664
int devicepixelsy(drawing dev) MEASUREDEV(LOGPIXELSY)
664
int devicepixelsy(drawing dev) MEASUREDEV(LOGPIXELSY)
665
 
665
 
666
void BringToTop(window c, int stay)
666
int isTopmost(window c)
-
 
667
{
-
 
668
    return GetWindowLong(c->handle, GWL_EXSTYLE) & WS_EX_TOPMOST;
-
 
669
}
-
 
670
 
-
 
671
void BringToTop(window c, int stay) /* stay=0 for regular, 1 for topmost, 2 for toggle */
667
{
672
{
668
    SetForegroundWindow(c->handle); /* needed in Rterm */
673
    SetForegroundWindow(c->handle); /* needed in Rterm */
669
    BringWindowToTop(c->handle);    /* needed in Rgui --mdi */
674
    BringWindowToTop(c->handle);    /* needed in Rgui --mdi */
-
 
675
 
-
 
676
    if (stay == 2) stay = !isTopmost(c);
-
 
677
 
670
    if (stay) SetWindowPos(c->handle, HWND_TOPMOST, 0, 0, 0, 0,
678
    if (stay) SetWindowPos(c->handle, HWND_TOPMOST, 0, 0, 0, 0,
671
    				SWP_NOMOVE | SWP_NOSIZE);
679
    				SWP_NOMOVE | SWP_NOSIZE);
672
    else SetWindowPos(c->handle, HWND_NOTOPMOST, 0, 0, 0, 0,
680
    else SetWindowPos(c->handle, HWND_NOTOPMOST, 0, 0, 0, 0,
673
    				SWP_NOMOVE | SWP_NOSIZE);
681
    				SWP_NOMOVE | SWP_NOSIZE);
674
}
682
}