1 |
/* $Header$ */ |
2 |
|
3 |
/* |
4 |
* tkWinDraw.c -- |
5 |
* |
6 |
* This file contains the Xlib emulation functions pertaining to |
7 |
* actually drawing objects on a window. |
8 |
* |
9 |
* Copyright (c) 1995 Sun Microsystems, Inc. |
10 |
* Copyright (c) 1994 Software Research Associates, Inc. |
11 |
* |
12 |
* See the file "license.terms" for information on usage and redistribution |
13 |
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
14 |
* |
15 |
* RCS: @(#) $Id: tkwindraw.c,v 1.1.1.1 2001/06/13 05:13:02 dtashley Exp $ |
16 |
*/ |
17 |
|
18 |
#include "tkWinInt.h" |
19 |
|
20 |
/* |
21 |
* These macros convert between X's bizarre angle units to radians. |
22 |
*/ |
23 |
|
24 |
#define PI 3.14159265358979 |
25 |
#define XAngleToRadians(a) ((double)(a) / 64 * PI / 180); |
26 |
|
27 |
/* |
28 |
* Translation table between X gc functions and Win32 raster op modes. |
29 |
*/ |
30 |
|
31 |
int tkpWinRopModes[] = { |
32 |
R2_BLACK, /* GXclear */ |
33 |
R2_MASKPEN, /* GXand */ |
34 |
R2_MASKPENNOT, /* GXandReverse */ |
35 |
R2_COPYPEN, /* GXcopy */ |
36 |
R2_MASKNOTPEN, /* GXandInverted */ |
37 |
R2_NOT, /* GXnoop */ |
38 |
R2_XORPEN, /* GXxor */ |
39 |
R2_MERGEPEN, /* GXor */ |
40 |
R2_NOTMERGEPEN, /* GXnor */ |
41 |
R2_NOTXORPEN, /* GXequiv */ |
42 |
R2_NOT, /* GXinvert */ |
43 |
R2_MERGEPENNOT, /* GXorReverse */ |
44 |
R2_NOTCOPYPEN, /* GXcopyInverted */ |
45 |
R2_MERGENOTPEN, /* GXorInverted */ |
46 |
R2_NOTMASKPEN, /* GXnand */ |
47 |
R2_WHITE /* GXset */ |
48 |
}; |
49 |
|
50 |
/* |
51 |
* Translation table between X gc functions and Win32 BitBlt op modes. Some |
52 |
* of the operations defined in X don't have names, so we have to construct |
53 |
* new opcodes for those functions. This is arcane and probably not all that |
54 |
* useful, but at least it's accurate. |
55 |
*/ |
56 |
|
57 |
#define NOTSRCAND (DWORD)0x00220326 /* dest = (NOT source) AND dest */ |
58 |
#define NOTSRCINVERT (DWORD)0x00990066 /* dest = (NOT source) XOR dest */ |
59 |
#define SRCORREVERSE (DWORD)0x00DD0228 /* dest = source OR (NOT dest) */ |
60 |
#define SRCNAND (DWORD)0x007700E6 /* dest = NOT (source AND dest) */ |
61 |
|
62 |
static int bltModes[] = { |
63 |
BLACKNESS, /* GXclear */ |
64 |
SRCAND, /* GXand */ |
65 |
SRCERASE, /* GXandReverse */ |
66 |
SRCCOPY, /* GXcopy */ |
67 |
NOTSRCAND, /* GXandInverted */ |
68 |
PATCOPY, /* GXnoop */ |
69 |
SRCINVERT, /* GXxor */ |
70 |
SRCPAINT, /* GXor */ |
71 |
NOTSRCERASE, /* GXnor */ |
72 |
NOTSRCINVERT, /* GXequiv */ |
73 |
DSTINVERT, /* GXinvert */ |
74 |
SRCORREVERSE, /* GXorReverse */ |
75 |
NOTSRCCOPY, /* GXcopyInverted */ |
76 |
MERGEPAINT, /* GXorInverted */ |
77 |
SRCNAND, /* GXnand */ |
78 |
WHITENESS /* GXset */ |
79 |
}; |
80 |
|
81 |
/* |
82 |
* The following raster op uses the source bitmap as a mask for the |
83 |
* pattern. This is used to draw in a foreground color but leave the |
84 |
* background color transparent. |
85 |
*/ |
86 |
|
87 |
#define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */ |
88 |
|
89 |
/* |
90 |
* The following two raster ops are used to copy the foreground and background |
91 |
* bits of a source pattern as defined by a stipple used as the pattern. |
92 |
*/ |
93 |
|
94 |
#define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */ |
95 |
#define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */ |
96 |
|
97 |
/* |
98 |
* Macros used later in the file. |
99 |
*/ |
100 |
|
101 |
#define MIN(a,b) ((a>b) ? b : a) |
102 |
#define MAX(a,b) ((a<b) ? b : a) |
103 |
|
104 |
/* |
105 |
* The followng typedef is used to pass Windows GDI drawing functions. |
106 |
*/ |
107 |
|
108 |
typedef BOOL (CALLBACK *WinDrawFunc) _ANSI_ARGS_((HDC dc, |
109 |
CONST POINT* points, int npoints)); |
110 |
|
111 |
typedef struct ThreadSpecificData { |
112 |
POINT *winPoints; /* Array of points that is reused. */ |
113 |
int nWinPoints; /* Current size of point array. */ |
114 |
} ThreadSpecificData; |
115 |
static Tcl_ThreadDataKey dataKey; |
116 |
|
117 |
/* |
118 |
* Forward declarations for procedures defined in this file: |
119 |
*/ |
120 |
|
121 |
static POINT * ConvertPoints _ANSI_ARGS_((XPoint *points, int npoints, |
122 |
int mode, RECT *bbox)); |
123 |
static void DrawOrFillArc _ANSI_ARGS_((Display *display, |
124 |
Drawable d, GC gc, int x, int y, |
125 |
unsigned int width, unsigned int height, |
126 |
int start, int extent, int fill)); |
127 |
static void RenderObject _ANSI_ARGS_((HDC dc, GC gc, |
128 |
XPoint* points, int npoints, int mode, HPEN pen, |
129 |
WinDrawFunc func)); |
130 |
static HPEN SetUpGraphicsPort _ANSI_ARGS_((GC gc)); |
131 |
|
132 |
/* |
133 |
*---------------------------------------------------------------------- |
134 |
* |
135 |
* TkWinGetDrawableDC -- |
136 |
* |
137 |
* Retrieve the DC from a drawable. |
138 |
* |
139 |
* Results: |
140 |
* Returns the window DC for windows. Returns a new memory DC |
141 |
* for pixmaps. |
142 |
* |
143 |
* Side effects: |
144 |
* Sets up the palette for the device context, and saves the old |
145 |
* device context state in the passed in TkWinDCState structure. |
146 |
* |
147 |
*---------------------------------------------------------------------- |
148 |
*/ |
149 |
|
150 |
HDC |
151 |
TkWinGetDrawableDC(display, d, state) |
152 |
Display *display; |
153 |
Drawable d; |
154 |
TkWinDCState* state; |
155 |
{ |
156 |
HDC dc; |
157 |
TkWinDrawable *twdPtr = (TkWinDrawable *)d; |
158 |
Colormap cmap; |
159 |
|
160 |
if (twdPtr->type == TWD_WINDOW) { |
161 |
TkWindow *winPtr = twdPtr->window.winPtr; |
162 |
|
163 |
dc = GetDC(twdPtr->window.handle); |
164 |
if (winPtr == NULL) { |
165 |
cmap = DefaultColormap(display, DefaultScreen(display)); |
166 |
} else { |
167 |
cmap = winPtr->atts.colormap; |
168 |
} |
169 |
} else if (twdPtr->type == TWD_WINDC) { |
170 |
dc = twdPtr->winDC.hdc; |
171 |
cmap = DefaultColormap(display, DefaultScreen(display)); |
172 |
} else { |
173 |
dc = CreateCompatibleDC(NULL); |
174 |
SelectObject(dc, twdPtr->bitmap.handle); |
175 |
cmap = twdPtr->bitmap.colormap; |
176 |
} |
177 |
state->palette = TkWinSelectPalette(dc, cmap); |
178 |
state->bkmode = GetBkMode(dc); |
179 |
return dc; |
180 |
} |
181 |
|
182 |
/* |
183 |
*---------------------------------------------------------------------- |
184 |
* |
185 |
* TkWinReleaseDrawableDC -- |
186 |
* |
187 |
* Frees the resources associated with a drawable's DC. |
188 |
* |
189 |
* Results: |
190 |
* None. |
191 |
* |
192 |
* Side effects: |
193 |
* Restores the old bitmap handle to the memory DC for pixmaps. |
194 |
* |
195 |
*---------------------------------------------------------------------- |
196 |
*/ |
197 |
|
198 |
void |
199 |
TkWinReleaseDrawableDC(d, dc, state) |
200 |
Drawable d; |
201 |
HDC dc; |
202 |
TkWinDCState *state; |
203 |
{ |
204 |
TkWinDrawable *twdPtr = (TkWinDrawable *)d; |
205 |
SetBkMode(dc, state->bkmode); |
206 |
SelectPalette(dc, state->palette, TRUE); |
207 |
RealizePalette(dc); |
208 |
if (twdPtr->type == TWD_WINDOW) { |
209 |
ReleaseDC(TkWinGetHWND(d), dc); |
210 |
} else if (twdPtr->type == TWD_BITMAP) { |
211 |
DeleteDC(dc); |
212 |
} |
213 |
} |
214 |
|
215 |
/* |
216 |
*---------------------------------------------------------------------- |
217 |
* |
218 |
* ConvertPoints -- |
219 |
* |
220 |
* Convert an array of X points to an array of Win32 points. |
221 |
* |
222 |
* Results: |
223 |
* Returns the converted array of POINTs. |
224 |
* |
225 |
* Side effects: |
226 |
* Allocates a block of memory in thread local storage that |
227 |
* should not be freed. |
228 |
* |
229 |
*---------------------------------------------------------------------- |
230 |
*/ |
231 |
|
232 |
static POINT * |
233 |
ConvertPoints(points, npoints, mode, bbox) |
234 |
XPoint *points; |
235 |
int npoints; |
236 |
int mode; /* CoordModeOrigin or CoordModePrevious. */ |
237 |
RECT *bbox; /* Bounding box of points. */ |
238 |
{ |
239 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
240 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
241 |
int i; |
242 |
|
243 |
/* |
244 |
* To avoid paying the cost of a malloc on every drawing routine, |
245 |
* we reuse the last array if it is large enough. |
246 |
*/ |
247 |
|
248 |
if (npoints > tsdPtr->nWinPoints) { |
249 |
if (tsdPtr->winPoints != NULL) { |
250 |
ckfree((char *) tsdPtr->winPoints); |
251 |
} |
252 |
tsdPtr->winPoints = (POINT *) ckalloc(sizeof(POINT) * npoints); |
253 |
if (tsdPtr->winPoints == NULL) { |
254 |
tsdPtr->nWinPoints = -1; |
255 |
return NULL; |
256 |
} |
257 |
tsdPtr->nWinPoints = npoints; |
258 |
} |
259 |
|
260 |
bbox->left = bbox->right = points[0].x; |
261 |
bbox->top = bbox->bottom = points[0].y; |
262 |
|
263 |
if (mode == CoordModeOrigin) { |
264 |
for (i = 0; i < npoints; i++) { |
265 |
tsdPtr->winPoints[i].x = points[i].x; |
266 |
tsdPtr->winPoints[i].y = points[i].y; |
267 |
bbox->left = MIN(bbox->left, tsdPtr->winPoints[i].x); |
268 |
bbox->right = MAX(bbox->right, tsdPtr->winPoints[i].x); |
269 |
bbox->top = MIN(bbox->top, tsdPtr->winPoints[i].y); |
270 |
bbox->bottom = MAX(bbox->bottom, tsdPtr->winPoints[i].y); |
271 |
} |
272 |
} else { |
273 |
tsdPtr->winPoints[0].x = points[0].x; |
274 |
tsdPtr->winPoints[0].y = points[0].y; |
275 |
for (i = 1; i < npoints; i++) { |
276 |
tsdPtr->winPoints[i].x = tsdPtr->winPoints[i-1].x + points[i].x; |
277 |
tsdPtr->winPoints[i].y = tsdPtr->winPoints[i-1].y + points[i].y; |
278 |
bbox->left = MIN(bbox->left, tsdPtr->winPoints[i].x); |
279 |
bbox->right = MAX(bbox->right, tsdPtr->winPoints[i].x); |
280 |
bbox->top = MIN(bbox->top, tsdPtr->winPoints[i].y); |
281 |
bbox->bottom = MAX(bbox->bottom, tsdPtr->winPoints[i].y); |
282 |
} |
283 |
} |
284 |
return tsdPtr->winPoints; |
285 |
} |
286 |
|
287 |
/* |
288 |
*---------------------------------------------------------------------- |
289 |
* |
290 |
* XCopyArea -- |
291 |
* |
292 |
* Copies data from one drawable to another using block transfer |
293 |
* routines. |
294 |
* |
295 |
* Results: |
296 |
* None. |
297 |
* |
298 |
* Side effects: |
299 |
* Data is moved from a window or bitmap to a second window or |
300 |
* bitmap. |
301 |
* |
302 |
*---------------------------------------------------------------------- |
303 |
*/ |
304 |
|
305 |
void |
306 |
XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y) |
307 |
Display* display; |
308 |
Drawable src; |
309 |
Drawable dest; |
310 |
GC gc; |
311 |
int src_x, src_y; |
312 |
unsigned int width, height; |
313 |
int dest_x, dest_y; |
314 |
{ |
315 |
HDC srcDC, destDC; |
316 |
TkWinDCState srcState, destState; |
317 |
TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask; |
318 |
|
319 |
srcDC = TkWinGetDrawableDC(display, src, &srcState); |
320 |
|
321 |
if (src != dest) { |
322 |
destDC = TkWinGetDrawableDC(display, dest, &destState); |
323 |
} else { |
324 |
destDC = srcDC; |
325 |
} |
326 |
|
327 |
if (clipPtr && clipPtr->type == TKP_CLIP_REGION) { |
328 |
SelectClipRgn(destDC, (HRGN) clipPtr->value.region); |
329 |
OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin); |
330 |
} |
331 |
|
332 |
BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y, |
333 |
bltModes[gc->function]); |
334 |
|
335 |
SelectClipRgn(destDC, NULL); |
336 |
|
337 |
if (src != dest) { |
338 |
TkWinReleaseDrawableDC(dest, destDC, &destState); |
339 |
} |
340 |
TkWinReleaseDrawableDC(src, srcDC, &srcState); |
341 |
} |
342 |
|
343 |
/* |
344 |
*---------------------------------------------------------------------- |
345 |
* |
346 |
* XCopyPlane -- |
347 |
* |
348 |
* Copies a bitmap from a source drawable to a destination |
349 |
* drawable. The plane argument specifies which bit plane of |
350 |
* the source contains the bitmap. Note that this implementation |
351 |
* ignores the gc->function. |
352 |
* |
353 |
* Results: |
354 |
* None. |
355 |
* |
356 |
* Side effects: |
357 |
* Changes the destination drawable. |
358 |
* |
359 |
*---------------------------------------------------------------------- |
360 |
*/ |
361 |
|
362 |
void |
363 |
XCopyPlane(display, src, dest, gc, src_x, src_y, width, height, dest_x, |
364 |
dest_y, plane) |
365 |
Display* display; |
366 |
Drawable src; |
367 |
Drawable dest; |
368 |
GC gc; |
369 |
int src_x, src_y; |
370 |
unsigned int width, height; |
371 |
int dest_x, dest_y; |
372 |
unsigned long plane; |
373 |
{ |
374 |
HDC srcDC, destDC; |
375 |
TkWinDCState srcState, destState; |
376 |
HBRUSH bgBrush, fgBrush, oldBrush; |
377 |
TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask; |
378 |
|
379 |
display->request++; |
380 |
|
381 |
if (plane != 1) { |
382 |
panic("Unexpected plane specified for XCopyPlane"); |
383 |
} |
384 |
|
385 |
srcDC = TkWinGetDrawableDC(display, src, &srcState); |
386 |
|
387 |
if (src != dest) { |
388 |
destDC = TkWinGetDrawableDC(display, dest, &destState); |
389 |
} else { |
390 |
destDC = srcDC; |
391 |
} |
392 |
|
393 |
if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) { |
394 |
|
395 |
/* |
396 |
* Case 1: opaque bitmaps. Windows handles the conversion |
397 |
* from one bit to multiple bits by setting 0 to the |
398 |
* foreground color, and 1 to the background color (seems |
399 |
* backwards, but there you are). |
400 |
*/ |
401 |
|
402 |
if (clipPtr && clipPtr->type == TKP_CLIP_REGION) { |
403 |
SelectClipRgn(destDC, (HRGN) clipPtr->value.region); |
404 |
OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin); |
405 |
} |
406 |
|
407 |
SetBkMode(destDC, OPAQUE); |
408 |
SetBkColor(destDC, gc->foreground); |
409 |
SetTextColor(destDC, gc->background); |
410 |
BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y, |
411 |
SRCCOPY); |
412 |
|
413 |
SelectClipRgn(destDC, NULL); |
414 |
} else if (clipPtr->type == TKP_CLIP_PIXMAP) { |
415 |
if (clipPtr->value.pixmap == src) { |
416 |
|
417 |
/* |
418 |
* Case 2: transparent bitmaps are handled by setting the |
419 |
* destination to the foreground color whenever the source |
420 |
* pixel is set. |
421 |
*/ |
422 |
|
423 |
fgBrush = CreateSolidBrush(gc->foreground); |
424 |
oldBrush = SelectObject(destDC, fgBrush); |
425 |
BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y, |
426 |
MASKPAT); |
427 |
SelectObject(destDC, oldBrush); |
428 |
DeleteObject(fgBrush); |
429 |
} else { |
430 |
|
431 |
/* |
432 |
* Case 3: two arbitrary bitmaps. Copy the source rectangle |
433 |
* into a color pixmap. Use the result as a brush when |
434 |
* copying the clip mask into the destination. |
435 |
*/ |
436 |
|
437 |
HDC memDC, maskDC; |
438 |
HBITMAP bitmap; |
439 |
TkWinDCState maskState; |
440 |
|
441 |
fgBrush = CreateSolidBrush(gc->foreground); |
442 |
bgBrush = CreateSolidBrush(gc->background); |
443 |
maskDC = TkWinGetDrawableDC(display, clipPtr->value.pixmap, |
444 |
&maskState); |
445 |
memDC = CreateCompatibleDC(destDC); |
446 |
bitmap = CreateBitmap(width, height, 1, 1, NULL); |
447 |
SelectObject(memDC, bitmap); |
448 |
|
449 |
/* |
450 |
* Set foreground bits. We create a new bitmap containing |
451 |
* (source AND mask), then use it to set the foreground color |
452 |
* into the destination. |
453 |
*/ |
454 |
|
455 |
BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, SRCCOPY); |
456 |
BitBlt(memDC, 0, 0, width, height, maskDC, |
457 |
dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin, |
458 |
SRCAND); |
459 |
oldBrush = SelectObject(destDC, fgBrush); |
460 |
BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0, |
461 |
MASKPAT); |
462 |
|
463 |
/* |
464 |
* Set background bits. Same as foreground, except we use |
465 |
* ((NOT source) AND mask) and the background brush. |
466 |
*/ |
467 |
|
468 |
BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, |
469 |
NOTSRCCOPY); |
470 |
BitBlt(memDC, 0, 0, width, height, maskDC, |
471 |
dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin, |
472 |
SRCAND); |
473 |
SelectObject(destDC, bgBrush); |
474 |
BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0, |
475 |
MASKPAT); |
476 |
|
477 |
TkWinReleaseDrawableDC(clipPtr->value.pixmap, maskDC, &maskState); |
478 |
SelectObject(destDC, oldBrush); |
479 |
DeleteDC(memDC); |
480 |
DeleteObject(bitmap); |
481 |
DeleteObject(fgBrush); |
482 |
DeleteObject(bgBrush); |
483 |
} |
484 |
} |
485 |
if (src != dest) { |
486 |
TkWinReleaseDrawableDC(dest, destDC, &destState); |
487 |
} |
488 |
TkWinReleaseDrawableDC(src, srcDC, &srcState); |
489 |
} |
490 |
|
491 |
/* |
492 |
*---------------------------------------------------------------------- |
493 |
* |
494 |
* TkPutImage -- |
495 |
* |
496 |
* Copies a subimage from an in-memory image to a rectangle of |
497 |
* of the specified drawable. |
498 |
* |
499 |
* Results: |
500 |
* None. |
501 |
* |
502 |
* Side effects: |
503 |
* Draws the image on the specified drawable. |
504 |
* |
505 |
*---------------------------------------------------------------------- |
506 |
*/ |
507 |
|
508 |
void |
509 |
TkPutImage(colors, ncolors, display, d, gc, image, src_x, src_y, dest_x, |
510 |
dest_y, width, height) |
511 |
unsigned long *colors; /* Array of pixel values used by this |
512 |
* image. May be NULL. */ |
513 |
int ncolors; /* Number of colors used, or 0. */ |
514 |
Display* display; |
515 |
Drawable d; /* Destination drawable. */ |
516 |
GC gc; |
517 |
XImage* image; /* Source image. */ |
518 |
int src_x, src_y; /* Offset of subimage. */ |
519 |
int dest_x, dest_y; /* Position of subimage origin in |
520 |
* drawable. */ |
521 |
unsigned int width, height; /* Dimensions of subimage. */ |
522 |
{ |
523 |
HDC dc, dcMem; |
524 |
TkWinDCState state; |
525 |
BITMAPINFO *infoPtr; |
526 |
HBITMAP bitmap; |
527 |
char *data; |
528 |
|
529 |
display->request++; |
530 |
|
531 |
dc = TkWinGetDrawableDC(display, d, &state); |
532 |
SetROP2(dc, tkpWinRopModes[gc->function]); |
533 |
dcMem = CreateCompatibleDC(dc); |
534 |
|
535 |
if (image->bits_per_pixel == 1) { |
536 |
/* |
537 |
* If the image isn't in the right format, we have to copy |
538 |
* it into a new buffer in MSBFirst and word-aligned format. |
539 |
*/ |
540 |
|
541 |
if ((image->bitmap_bit_order != MSBFirst) |
542 |
|| (image->bitmap_pad != sizeof(WORD))) { |
543 |
data = TkAlignImageData(image, sizeof(WORD), MSBFirst); |
544 |
bitmap = CreateBitmap(image->width, image->height, 1, 1, data); |
545 |
ckfree(data); |
546 |
} else { |
547 |
bitmap = CreateBitmap(image->width, image->height, 1, 1, |
548 |
image->data); |
549 |
} |
550 |
SetTextColor(dc, gc->foreground); |
551 |
SetBkColor(dc, gc->background); |
552 |
} else { |
553 |
int i, usePalette; |
554 |
|
555 |
/* |
556 |
* Do not use a palette for TrueColor images. |
557 |
*/ |
558 |
|
559 |
usePalette = (image->bits_per_pixel < 16); |
560 |
|
561 |
if (usePalette) { |
562 |
infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER) |
563 |
+ sizeof(RGBQUAD)*ncolors); |
564 |
} else { |
565 |
infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER)); |
566 |
} |
567 |
|
568 |
infoPtr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
569 |
infoPtr->bmiHeader.biWidth = image->width; |
570 |
infoPtr->bmiHeader.biHeight = -image->height; /* Top-down order */ |
571 |
infoPtr->bmiHeader.biPlanes = 1; |
572 |
infoPtr->bmiHeader.biBitCount = image->bits_per_pixel; |
573 |
infoPtr->bmiHeader.biCompression = BI_RGB; |
574 |
infoPtr->bmiHeader.biSizeImage = 0; |
575 |
infoPtr->bmiHeader.biXPelsPerMeter = 0; |
576 |
infoPtr->bmiHeader.biYPelsPerMeter = 0; |
577 |
infoPtr->bmiHeader.biClrImportant = 0; |
578 |
|
579 |
if (usePalette) { |
580 |
infoPtr->bmiHeader.biClrUsed = ncolors; |
581 |
for (i = 0; i < ncolors; i++) { |
582 |
infoPtr->bmiColors[i].rgbBlue = GetBValue(colors[i]); |
583 |
infoPtr->bmiColors[i].rgbGreen = GetGValue(colors[i]); |
584 |
infoPtr->bmiColors[i].rgbRed = GetRValue(colors[i]); |
585 |
infoPtr->bmiColors[i].rgbReserved = 0; |
586 |
} |
587 |
} else { |
588 |
infoPtr->bmiHeader.biClrUsed = 0; |
589 |
} |
590 |
bitmap = CreateDIBitmap(dc, &infoPtr->bmiHeader, CBM_INIT, |
591 |
image->data, infoPtr, DIB_RGB_COLORS); |
592 |
ckfree((char *) infoPtr); |
593 |
} |
594 |
bitmap = SelectObject(dcMem, bitmap); |
595 |
BitBlt(dc, dest_x, dest_y, width, height, dcMem, src_x, src_y, SRCCOPY); |
596 |
DeleteObject(SelectObject(dcMem, bitmap)); |
597 |
DeleteDC(dcMem); |
598 |
TkWinReleaseDrawableDC(d, dc, &state); |
599 |
} |
600 |
|
601 |
/* |
602 |
*---------------------------------------------------------------------- |
603 |
* |
604 |
* XFillRectangles -- |
605 |
* |
606 |
* Fill multiple rectangular areas in the given drawable. |
607 |
* |
608 |
* Results: |
609 |
* None. |
610 |
* |
611 |
* Side effects: |
612 |
* Draws onto the specified drawable. |
613 |
* |
614 |
*---------------------------------------------------------------------- |
615 |
*/ |
616 |
|
617 |
void |
618 |
XFillRectangles(display, d, gc, rectangles, nrectangles) |
619 |
Display* display; |
620 |
Drawable d; |
621 |
GC gc; |
622 |
XRectangle* rectangles; |
623 |
int nrectangles; |
624 |
{ |
625 |
HDC dc; |
626 |
int i; |
627 |
RECT rect; |
628 |
TkWinDCState state; |
629 |
HBRUSH brush; |
630 |
|
631 |
if (d == None) { |
632 |
return; |
633 |
} |
634 |
|
635 |
dc = TkWinGetDrawableDC(display, d, &state); |
636 |
SetROP2(dc, tkpWinRopModes[gc->function]); |
637 |
brush = CreateSolidBrush(gc->foreground); |
638 |
|
639 |
if ((gc->fill_style == FillStippled |
640 |
|| gc->fill_style == FillOpaqueStippled) |
641 |
&& gc->stipple != None) { |
642 |
TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple; |
643 |
HBRUSH oldBrush, stipple; |
644 |
HBITMAP oldBitmap, bitmap; |
645 |
HDC dcMem; |
646 |
HBRUSH bgBrush = CreateSolidBrush(gc->background); |
647 |
|
648 |
if (twdPtr->type != TWD_BITMAP) { |
649 |
panic("unexpected drawable type in stipple"); |
650 |
} |
651 |
|
652 |
/* |
653 |
* Select stipple pattern into destination dc. |
654 |
*/ |
655 |
|
656 |
stipple = CreatePatternBrush(twdPtr->bitmap.handle); |
657 |
SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL); |
658 |
oldBrush = SelectObject(dc, stipple); |
659 |
dcMem = CreateCompatibleDC(dc); |
660 |
|
661 |
/* |
662 |
* For each rectangle, create a drawing surface which is the size of |
663 |
* the rectangle and fill it with the background color. Then merge the |
664 |
* result with the stipple pattern. |
665 |
*/ |
666 |
|
667 |
for (i = 0; i < nrectangles; i++) { |
668 |
bitmap = CreateCompatibleBitmap(dc, rectangles[i].width, |
669 |
rectangles[i].height); |
670 |
oldBitmap = SelectObject(dcMem, bitmap); |
671 |
rect.left = 0; |
672 |
rect.top = 0; |
673 |
rect.right = rectangles[i].width; |
674 |
rect.bottom = rectangles[i].height; |
675 |
FillRect(dcMem, &rect, brush); |
676 |
BitBlt(dc, rectangles[i].x, rectangles[i].y, rectangles[i].width, |
677 |
rectangles[i].height, dcMem, 0, 0, COPYFG); |
678 |
if (gc->fill_style == FillOpaqueStippled) { |
679 |
FillRect(dcMem, &rect, bgBrush); |
680 |
BitBlt(dc, rectangles[i].x, rectangles[i].y, |
681 |
rectangles[i].width, rectangles[i].height, dcMem, |
682 |
0, 0, COPYBG); |
683 |
} |
684 |
SelectObject(dcMem, oldBitmap); |
685 |
DeleteObject(bitmap); |
686 |
} |
687 |
|
688 |
DeleteDC(dcMem); |
689 |
SelectObject(dc, oldBrush); |
690 |
DeleteObject(stipple); |
691 |
DeleteObject(bgBrush); |
692 |
} else { |
693 |
for (i = 0; i < nrectangles; i++) { |
694 |
TkWinFillRect(dc, rectangles[i].x, rectangles[i].y, |
695 |
rectangles[i].width, rectangles[i].height, gc->foreground); |
696 |
} |
697 |
} |
698 |
DeleteObject(brush); |
699 |
TkWinReleaseDrawableDC(d, dc, &state); |
700 |
} |
701 |
|
702 |
/* |
703 |
*---------------------------------------------------------------------- |
704 |
* |
705 |
* RenderObject -- |
706 |
* |
707 |
* This function draws a shape using a list of points, a |
708 |
* stipple pattern, and the specified drawing function. |
709 |
* |
710 |
* Results: |
711 |
* None. |
712 |
* |
713 |
* Side effects: |
714 |
* None. |
715 |
* |
716 |
*---------------------------------------------------------------------- |
717 |
*/ |
718 |
|
719 |
static void |
720 |
RenderObject(dc, gc, points, npoints, mode, pen, func) |
721 |
HDC dc; |
722 |
GC gc; |
723 |
XPoint* points; |
724 |
int npoints; |
725 |
int mode; |
726 |
HPEN pen; |
727 |
WinDrawFunc func; |
728 |
{ |
729 |
RECT rect; |
730 |
HPEN oldPen; |
731 |
HBRUSH oldBrush; |
732 |
POINT *winPoints = ConvertPoints(points, npoints, mode, &rect); |
733 |
|
734 |
if ((gc->fill_style == FillStippled |
735 |
|| gc->fill_style == FillOpaqueStippled) |
736 |
&& gc->stipple != None) { |
737 |
|
738 |
TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple; |
739 |
HDC dcMem; |
740 |
LONG width, height; |
741 |
HBITMAP oldBitmap; |
742 |
int i; |
743 |
HBRUSH oldMemBrush; |
744 |
|
745 |
if (twdPtr->type != TWD_BITMAP) { |
746 |
panic("unexpected drawable type in stipple"); |
747 |
} |
748 |
|
749 |
/* |
750 |
* Grow the bounding box enough to account for wide lines. |
751 |
*/ |
752 |
|
753 |
if (gc->line_width > 1) { |
754 |
rect.left -= gc->line_width; |
755 |
rect.top -= gc->line_width; |
756 |
rect.right += gc->line_width; |
757 |
rect.bottom += gc->line_width; |
758 |
} |
759 |
|
760 |
width = rect.right - rect.left; |
761 |
height = rect.bottom - rect.top; |
762 |
|
763 |
/* |
764 |
* Select stipple pattern into destination dc. |
765 |
*/ |
766 |
|
767 |
SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL); |
768 |
oldBrush = SelectObject(dc, CreatePatternBrush(twdPtr->bitmap.handle)); |
769 |
|
770 |
/* |
771 |
* Create temporary drawing surface containing a copy of the |
772 |
* destination equal in size to the bounding box of the object. |
773 |
*/ |
774 |
|
775 |
dcMem = CreateCompatibleDC(dc); |
776 |
oldBitmap = SelectObject(dcMem, CreateCompatibleBitmap(dc, width, |
777 |
height)); |
778 |
oldPen = SelectObject(dcMem, pen); |
779 |
BitBlt(dcMem, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY); |
780 |
|
781 |
/* |
782 |
* Translate the object for rendering in the temporary drawing |
783 |
* surface. |
784 |
*/ |
785 |
|
786 |
for (i = 0; i < npoints; i++) { |
787 |
winPoints[i].x -= rect.left; |
788 |
winPoints[i].y -= rect.top; |
789 |
} |
790 |
|
791 |
/* |
792 |
* Draw the object in the foreground color and copy it to the |
793 |
* destination wherever the pattern is set. |
794 |
*/ |
795 |
|
796 |
SetPolyFillMode(dcMem, (gc->fill_rule == EvenOddRule) ? ALTERNATE |
797 |
: WINDING); |
798 |
oldMemBrush = SelectObject(dcMem, CreateSolidBrush(gc->foreground)); |
799 |
(*func)(dcMem, winPoints, npoints); |
800 |
BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0, COPYFG); |
801 |
|
802 |
/* |
803 |
* If we are rendering an opaque stipple, then draw the polygon in the |
804 |
* background color and copy it to the destination wherever the pattern |
805 |
* is clear. |
806 |
*/ |
807 |
|
808 |
if (gc->fill_style == FillOpaqueStippled) { |
809 |
DeleteObject(SelectObject(dcMem, |
810 |
CreateSolidBrush(gc->background))); |
811 |
(*func)(dcMem, winPoints, npoints); |
812 |
BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0, |
813 |
COPYBG); |
814 |
} |
815 |
|
816 |
SelectObject(dcMem, oldPen); |
817 |
DeleteObject(SelectObject(dcMem, oldMemBrush)); |
818 |
DeleteObject(SelectObject(dcMem, oldBitmap)); |
819 |
DeleteDC(dcMem); |
820 |
} else { |
821 |
oldPen = SelectObject(dc, pen); |
822 |
oldBrush = SelectObject(dc, CreateSolidBrush(gc->foreground)); |
823 |
SetROP2(dc, tkpWinRopModes[gc->function]); |
824 |
|
825 |
SetPolyFillMode(dc, (gc->fill_rule == EvenOddRule) ? ALTERNATE |
826 |
: WINDING); |
827 |
|
828 |
(*func)(dc, winPoints, npoints); |
829 |
|
830 |
SelectObject(dc, oldPen); |
831 |
} |
832 |
DeleteObject(SelectObject(dc, oldBrush)); |
833 |
} |
834 |
|
835 |
/* |
836 |
*---------------------------------------------------------------------- |
837 |
* |
838 |
* XDrawLines -- |
839 |
* |
840 |
* Draw connected lines. |
841 |
* |
842 |
* Results: |
843 |
* None. |
844 |
* |
845 |
* Side effects: |
846 |
* Renders a series of connected lines. |
847 |
* |
848 |
*---------------------------------------------------------------------- |
849 |
*/ |
850 |
|
851 |
void |
852 |
XDrawLines(display, d, gc, points, npoints, mode) |
853 |
Display* display; |
854 |
Drawable d; |
855 |
GC gc; |
856 |
XPoint* points; |
857 |
int npoints; |
858 |
int mode; |
859 |
{ |
860 |
HPEN pen; |
861 |
TkWinDCState state; |
862 |
HDC dc; |
863 |
|
864 |
if (d == None) { |
865 |
return; |
866 |
} |
867 |
|
868 |
dc = TkWinGetDrawableDC(display, d, &state); |
869 |
|
870 |
pen = SetUpGraphicsPort(gc); |
871 |
SetBkMode(dc, TRANSPARENT); |
872 |
RenderObject(dc, gc, points, npoints, mode, pen, Polyline); |
873 |
DeleteObject(pen); |
874 |
|
875 |
TkWinReleaseDrawableDC(d, dc, &state); |
876 |
} |
877 |
|
878 |
/* |
879 |
*---------------------------------------------------------------------- |
880 |
* |
881 |
* XFillPolygon -- |
882 |
* |
883 |
* Draws a filled polygon. |
884 |
* |
885 |
* Results: |
886 |
* None. |
887 |
* |
888 |
* Side effects: |
889 |
* Draws a filled polygon on the specified drawable. |
890 |
* |
891 |
*---------------------------------------------------------------------- |
892 |
*/ |
893 |
|
894 |
void |
895 |
XFillPolygon(display, d, gc, points, npoints, shape, mode) |
896 |
Display* display; |
897 |
Drawable d; |
898 |
GC gc; |
899 |
XPoint* points; |
900 |
int npoints; |
901 |
int shape; |
902 |
int mode; |
903 |
{ |
904 |
HPEN pen; |
905 |
TkWinDCState state; |
906 |
HDC dc; |
907 |
|
908 |
if (d == None) { |
909 |
return; |
910 |
} |
911 |
|
912 |
dc = TkWinGetDrawableDC(display, d, &state); |
913 |
|
914 |
pen = GetStockObject(NULL_PEN); |
915 |
RenderObject(dc, gc, points, npoints, mode, pen, Polygon); |
916 |
|
917 |
TkWinReleaseDrawableDC(d, dc, &state); |
918 |
} |
919 |
|
920 |
/* |
921 |
*---------------------------------------------------------------------- |
922 |
* |
923 |
* XDrawRectangle -- |
924 |
* |
925 |
* Draws a rectangle. |
926 |
* |
927 |
* Results: |
928 |
* None. |
929 |
* |
930 |
* Side effects: |
931 |
* Draws a rectangle on the specified drawable. |
932 |
* |
933 |
*---------------------------------------------------------------------- |
934 |
*/ |
935 |
|
936 |
void |
937 |
XDrawRectangle(display, d, gc, x, y, width, height) |
938 |
Display* display; |
939 |
Drawable d; |
940 |
GC gc; |
941 |
int x; |
942 |
int y; |
943 |
unsigned int width; |
944 |
unsigned int height; |
945 |
{ |
946 |
HPEN pen, oldPen; |
947 |
TkWinDCState state; |
948 |
HBRUSH oldBrush; |
949 |
HDC dc; |
950 |
|
951 |
if (d == None) { |
952 |
return; |
953 |
} |
954 |
|
955 |
dc = TkWinGetDrawableDC(display, d, &state); |
956 |
|
957 |
pen = SetUpGraphicsPort(gc); |
958 |
SetBkMode(dc, TRANSPARENT); |
959 |
oldPen = SelectObject(dc, pen); |
960 |
oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); |
961 |
SetROP2(dc, tkpWinRopModes[gc->function]); |
962 |
|
963 |
Rectangle(dc, x, y, x+width+1, y+height+1); |
964 |
|
965 |
DeleteObject(SelectObject(dc, oldPen)); |
966 |
SelectObject(dc, oldBrush); |
967 |
TkWinReleaseDrawableDC(d, dc, &state); |
968 |
} |
969 |
|
970 |
/* |
971 |
*---------------------------------------------------------------------- |
972 |
* |
973 |
* XDrawArc -- |
974 |
* |
975 |
* Draw an arc. |
976 |
* |
977 |
* Results: |
978 |
* None. |
979 |
* |
980 |
* Side effects: |
981 |
* Draws an arc on the specified drawable. |
982 |
* |
983 |
*---------------------------------------------------------------------- |
984 |
*/ |
985 |
|
986 |
void |
987 |
XDrawArc(display, d, gc, x, y, width, height, start, extent) |
988 |
Display* display; |
989 |
Drawable d; |
990 |
GC gc; |
991 |
int x; |
992 |
int y; |
993 |
unsigned int width; |
994 |
unsigned int height; |
995 |
int start; |
996 |
int extent; |
997 |
{ |
998 |
display->request++; |
999 |
|
1000 |
DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 0); |
1001 |
} |
1002 |
|
1003 |
/* |
1004 |
*---------------------------------------------------------------------- |
1005 |
* |
1006 |
* XFillArc -- |
1007 |
* |
1008 |
* Draw a filled arc. |
1009 |
* |
1010 |
* Results: |
1011 |
* None. |
1012 |
* |
1013 |
* Side effects: |
1014 |
* Draws a filled arc on the specified drawable. |
1015 |
* |
1016 |
*---------------------------------------------------------------------- |
1017 |
*/ |
1018 |
|
1019 |
void |
1020 |
XFillArc(display, d, gc, x, y, width, height, start, extent) |
1021 |
Display* display; |
1022 |
Drawable d; |
1023 |
GC gc; |
1024 |
int x; |
1025 |
int y; |
1026 |
unsigned int width; |
1027 |
unsigned int height; |
1028 |
int start; |
1029 |
int extent; |
1030 |
{ |
1031 |
display->request++; |
1032 |
|
1033 |
DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 1); |
1034 |
} |
1035 |
|
1036 |
/* |
1037 |
*---------------------------------------------------------------------- |
1038 |
* |
1039 |
* DrawOrFillArc -- |
1040 |
* |
1041 |
* This procedure handles the rendering of drawn or filled |
1042 |
* arcs and chords. |
1043 |
* |
1044 |
* Results: |
1045 |
* None. |
1046 |
* |
1047 |
* Side effects: |
1048 |
* Renders the requested arc. |
1049 |
* |
1050 |
*---------------------------------------------------------------------- |
1051 |
*/ |
1052 |
|
1053 |
static void |
1054 |
DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, fill) |
1055 |
Display *display; |
1056 |
Drawable d; |
1057 |
GC gc; |
1058 |
int x, y; /* left top */ |
1059 |
unsigned int width, height; |
1060 |
int start; /* start: three-o'clock (deg*64) */ |
1061 |
int extent; /* extent: relative (deg*64) */ |
1062 |
int fill; /* ==0 draw, !=0 fill */ |
1063 |
{ |
1064 |
HDC dc; |
1065 |
HBRUSH brush, oldBrush; |
1066 |
HPEN pen, oldPen; |
1067 |
TkWinDCState state; |
1068 |
int clockwise = (extent < 0); /* non-zero if clockwise */ |
1069 |
int xstart, ystart, xend, yend; |
1070 |
double radian_start, radian_end, xr, yr; |
1071 |
|
1072 |
if (d == None) { |
1073 |
return; |
1074 |
} |
1075 |
|
1076 |
dc = TkWinGetDrawableDC(display, d, &state); |
1077 |
|
1078 |
SetROP2(dc, tkpWinRopModes[gc->function]); |
1079 |
|
1080 |
/* |
1081 |
* Compute the absolute starting and ending angles in normalized radians. |
1082 |
* Swap the start and end if drawing clockwise. |
1083 |
*/ |
1084 |
|
1085 |
start = start % (64*360); |
1086 |
if (start < 0) { |
1087 |
start += (64*360); |
1088 |
} |
1089 |
extent = (start+extent) % (64*360); |
1090 |
if (extent < 0) { |
1091 |
extent += (64*360); |
1092 |
} |
1093 |
if (clockwise) { |
1094 |
int tmp = start; |
1095 |
start = extent; |
1096 |
extent = tmp; |
1097 |
} |
1098 |
radian_start = XAngleToRadians(start); |
1099 |
radian_end = XAngleToRadians(extent); |
1100 |
|
1101 |
/* |
1102 |
* Now compute points on the radial lines that define the starting and |
1103 |
* ending angles. Be sure to take into account that the y-coordinate |
1104 |
* system is inverted. |
1105 |
*/ |
1106 |
|
1107 |
xr = x + width / 2.0; |
1108 |
yr = y + height / 2.0; |
1109 |
xstart = (int)((xr + cos(radian_start)*width/2.0) + 0.5); |
1110 |
ystart = (int)((yr + sin(-radian_start)*height/2.0) + 0.5); |
1111 |
xend = (int)((xr + cos(radian_end)*width/2.0) + 0.5); |
1112 |
yend = (int)((yr + sin(-radian_end)*height/2.0) + 0.5); |
1113 |
|
1114 |
/* |
1115 |
* Now draw a filled or open figure. Note that we have to |
1116 |
* increase the size of the bounding box by one to account for the |
1117 |
* difference in pixel definitions between X and Windows. |
1118 |
*/ |
1119 |
|
1120 |
pen = SetUpGraphicsPort(gc); |
1121 |
oldPen = SelectObject(dc, pen); |
1122 |
if (!fill) { |
1123 |
/* |
1124 |
* Note that this call will leave a gap of one pixel at the |
1125 |
* end of the arc for thin arcs. We can't use ArcTo because |
1126 |
* it's only supported under Windows NT. |
1127 |
*/ |
1128 |
|
1129 |
SetBkMode(dc, TRANSPARENT); |
1130 |
Arc(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend); |
1131 |
} else { |
1132 |
brush = CreateSolidBrush(gc->foreground); |
1133 |
oldBrush = SelectObject(dc, brush); |
1134 |
if (gc->arc_mode == ArcChord) { |
1135 |
Chord(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend); |
1136 |
} else if ( gc->arc_mode == ArcPieSlice ) { |
1137 |
Pie(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend); |
1138 |
} |
1139 |
DeleteObject(SelectObject(dc, oldBrush)); |
1140 |
} |
1141 |
DeleteObject(SelectObject(dc, oldPen)); |
1142 |
TkWinReleaseDrawableDC(d, dc, &state); |
1143 |
} |
1144 |
|
1145 |
/* |
1146 |
*---------------------------------------------------------------------- |
1147 |
* |
1148 |
* SetUpGraphicsPort -- |
1149 |
* |
1150 |
* Set up the graphics port from the given GC. |
1151 |
* |
1152 |
* Results: |
1153 |
* None. |
1154 |
* |
1155 |
* Side effects: |
1156 |
* The current port is adjusted. |
1157 |
* |
1158 |
*---------------------------------------------------------------------- |
1159 |
*/ |
1160 |
|
1161 |
static HPEN |
1162 |
SetUpGraphicsPort(gc) |
1163 |
GC gc; |
1164 |
{ |
1165 |
DWORD style; |
1166 |
|
1167 |
if (gc->line_style == LineOnOffDash) { |
1168 |
unsigned char *p = (unsigned char *) &(gc->dashes); |
1169 |
/* pointer to the dash-list */ |
1170 |
|
1171 |
/* |
1172 |
* Below is a simple translation of serveral dash patterns |
1173 |
* to valid windows pen types. Far from complete, |
1174 |
* but I don't know how to do it better. |
1175 |
* Any ideas: <mailto:j.nijtmans@chello.nl> |
1176 |
*/ |
1177 |
|
1178 |
if (p[1] && p[2]) { |
1179 |
if (!p[3] || p[4]) { |
1180 |
style = PS_DASHDOTDOT; /* -.. */ |
1181 |
} else { |
1182 |
style = PS_DASHDOT; /* -. */ |
1183 |
} |
1184 |
} else { |
1185 |
if (p[0] > (4 * gc->line_width)) { |
1186 |
style = PS_DASH; /* - */ |
1187 |
} else { |
1188 |
style = PS_DOT; /* . */ |
1189 |
} |
1190 |
} |
1191 |
} else { |
1192 |
style = PS_SOLID; |
1193 |
} |
1194 |
if (gc->line_width < 2) { |
1195 |
return CreatePen(style, gc->line_width, gc->foreground); |
1196 |
} else { |
1197 |
LOGBRUSH lb; |
1198 |
|
1199 |
lb.lbStyle = BS_SOLID; |
1200 |
lb.lbColor = gc->foreground; |
1201 |
lb.lbHatch = 0; |
1202 |
|
1203 |
style |= PS_GEOMETRIC; |
1204 |
switch (gc->cap_style) { |
1205 |
case CapNotLast: |
1206 |
case CapButt: |
1207 |
style |= PS_ENDCAP_FLAT; |
1208 |
break; |
1209 |
case CapRound: |
1210 |
style |= PS_ENDCAP_ROUND; |
1211 |
break; |
1212 |
default: |
1213 |
style |= PS_ENDCAP_SQUARE; |
1214 |
break; |
1215 |
} |
1216 |
switch (gc->join_style) { |
1217 |
case JoinMiter: |
1218 |
style |= PS_JOIN_MITER; |
1219 |
break; |
1220 |
case JoinRound: |
1221 |
style |= PS_JOIN_ROUND; |
1222 |
break; |
1223 |
default: |
1224 |
style |= PS_JOIN_BEVEL; |
1225 |
break; |
1226 |
} |
1227 |
return ExtCreatePen(style, gc->line_width, &lb, 0, NULL); |
1228 |
} |
1229 |
} |
1230 |
|
1231 |
/* |
1232 |
*---------------------------------------------------------------------- |
1233 |
* |
1234 |
* TkScrollWindow -- |
1235 |
* |
1236 |
* Scroll a rectangle of the specified window and accumulate |
1237 |
* a damage region. |
1238 |
* |
1239 |
* Results: |
1240 |
* Returns 0 if the scroll genereated no additional damage. |
1241 |
* Otherwise, sets the region that needs to be repainted after |
1242 |
* scrolling and returns 1. |
1243 |
* |
1244 |
* Side effects: |
1245 |
* Scrolls the bits in the window. |
1246 |
* |
1247 |
*---------------------------------------------------------------------- |
1248 |
*/ |
1249 |
|
1250 |
int |
1251 |
TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn) |
1252 |
Tk_Window tkwin; /* The window to be scrolled. */ |
1253 |
GC gc; /* GC for window to be scrolled. */ |
1254 |
int x, y, width, height; /* Position rectangle to be scrolled. */ |
1255 |
int dx, dy; /* Distance rectangle should be moved. */ |
1256 |
TkRegion damageRgn; /* Region to accumulate damage in. */ |
1257 |
{ |
1258 |
HWND hwnd = TkWinGetHWND(Tk_WindowId(tkwin)); |
1259 |
RECT scrollRect; |
1260 |
|
1261 |
scrollRect.left = x; |
1262 |
scrollRect.top = y; |
1263 |
scrollRect.right = x + width; |
1264 |
scrollRect.bottom = y + height; |
1265 |
return (ScrollWindowEx(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn, |
1266 |
NULL, 0) == NULLREGION) ? 0 : 1; |
1267 |
} |
1268 |
|
1269 |
/* |
1270 |
*---------------------------------------------------------------------- |
1271 |
* |
1272 |
* TkWinFillRect -- |
1273 |
* |
1274 |
* This routine fills a rectangle with the foreground color |
1275 |
* from the specified GC ignoring all other GC values. This |
1276 |
* is the fastest way to fill a drawable with a solid color. |
1277 |
* |
1278 |
* Results: |
1279 |
* None. |
1280 |
* |
1281 |
* Side effects: |
1282 |
* Modifies the contents of the DC drawing surface. |
1283 |
* |
1284 |
*---------------------------------------------------------------------- |
1285 |
*/ |
1286 |
|
1287 |
void |
1288 |
TkWinFillRect(dc, x, y, width, height, pixel) |
1289 |
HDC dc; |
1290 |
int x, y, width, height; |
1291 |
int pixel; |
1292 |
{ |
1293 |
RECT rect; |
1294 |
COLORREF oldColor; |
1295 |
|
1296 |
rect.left = x; |
1297 |
rect.top = y; |
1298 |
rect.right = x + width; |
1299 |
rect.bottom = y + height; |
1300 |
oldColor = SetBkColor(dc, (COLORREF)pixel); |
1301 |
SetBkMode(dc, OPAQUE); |
1302 |
ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); |
1303 |
SetBkColor(dc, oldColor); |
1304 |
} |
1305 |
|
1306 |
/* |
1307 |
*---------------------------------------------------------------------- |
1308 |
* |
1309 |
* TkpDrawHighlightBorder -- |
1310 |
* |
1311 |
* This procedure draws a rectangular ring around the outside of |
1312 |
* a widget to indicate that it has received the input focus. |
1313 |
* |
1314 |
* On Windows, we just draw the simple inset ring. On other sytems, |
1315 |
* e.g. the Mac, the focus ring is a little more complicated, so we |
1316 |
* need this abstraction. |
1317 |
* |
1318 |
* Results: |
1319 |
* None. |
1320 |
* |
1321 |
* Side effects: |
1322 |
* A rectangle "width" pixels wide is drawn in "drawable", |
1323 |
* corresponding to the outer area of "tkwin". |
1324 |
* |
1325 |
*---------------------------------------------------------------------- |
1326 |
*/ |
1327 |
|
1328 |
void |
1329 |
TkpDrawHighlightBorder(tkwin, fgGC, bgGC, highlightWidth, drawable) |
1330 |
Tk_Window tkwin; |
1331 |
GC fgGC; |
1332 |
GC bgGC; |
1333 |
int highlightWidth; |
1334 |
Drawable drawable; |
1335 |
{ |
1336 |
TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0); |
1337 |
} |
1338 |
|
1339 |
/* End of tkwindraw.c */ |