1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 /* Lefteris Koutsofios - AT&T Labs Research */
15
16 #include "common.h"
17 #include "g.h"
18 #include "gcommon.h"
19 #include "mem.h"
20
21 #define WCU widget->u.c
22 #define WINDOW widget->u.c->window
23 #define GC widget->u.c->gc
24 #define ISVISIBLE(r) ( \
25 (r.o.x <= WCU->clip.c.x) && (r.c.x >= WCU->clip.o.x) && \
26 (r.o.y <= WCU->clip.c.y) && (r.c.y >= WCU->clip.o.y) \
27 )
28
29 #define max(a, b) (((a) >= (b)) ? (a) : (b))
30 #define min(a, b) (((a) <= (b)) ? (a) : (b))
31
32 static long gstyles[5] = {
33 /* G_SOLID */ PS_SOLID,
34 /* G_DASHED */ PS_DASH,
35 /* G_DOTTED */ PS_DOT,
36 /* G_LONGDASHED */ PS_DASH,
37 /* G_SHORTDASHED */ PS_DASH,
38 };
39
40 static char grays[][4] = {
41 { 0x00, 0x00, 0x00, 0x00 },
42 { 0x08, 0x00, 0x00, 0x00 },
43 { 0x08, 0x00, 0x02, 0x00 },
44 { 0x0A, 0x00, 0x02, 0x00 },
45 { 0x0A, 0x00, 0x0A, 0x00 },
46 { 0x0A, 0x04, 0x0A, 0x00 },
47 { 0x0A, 0x04, 0x0A, 0x01 },
48 { 0x0A, 0x05, 0x0A, 0x01 },
49 { 0x0A, 0x05, 0x0A, 0x05 },
50 { 0x0E, 0x05, 0x0A, 0x05 },
51 { 0x0E, 0x05, 0x0B, 0x05 },
52 { 0x0F, 0x05, 0x0B, 0x05 },
53 { 0x0F, 0x05, 0x0F, 0x05 },
54 { 0x0F, 0x0D, 0x0F, 0x05 },
55 { 0x0F, 0x0D, 0x0F, 0x07 },
56 { 0x0F, 0x0F, 0x0F, 0x07 },
57 { 0x0F, 0x0F, 0x0F, 0x0F }
58 };
59
60 static int curcursori = -1;
61
62 static void bezier (PIXpoint_t, PIXpoint_t, PIXpoint_t, PIXpoint_t);
63 static HFONT findfont (char *, int);
64 static int scalebitmap (Gwidget_t *, Gbitmap_t *, Gsize_t, int, int);
65 static void setgattr (Gwidget_t *, Ggattr_t *);
66
67 static PIXrect_t rdrawtopix (Gwidget_t *, Grect_t);
68 static PIXpoint_t pdrawtopix (Gwidget_t *, Gpoint_t);
69 static PIXsize_t sdrawtopix (Gwidget_t *, Gsize_t);
70 static Gsize_t spixtodraw (Gwidget_t *, PIXsize_t);
71 static Grect_t rpixtodraw (Gwidget_t *, PIXrect_t);
72 static PIXrect_t rdrawtobpix (Gbitmap_t *, Grect_t);
73 static PIXpoint_t pdrawtobpix (Gbitmap_t *, Gpoint_t);
74
GCcreatewidget(Gwidget_t * parent,Gwidget_t * widget,int attrn,Gwattr_t * attrp)75 int GCcreatewidget (
76 Gwidget_t *parent, Gwidget_t *widget, int attrn, Gwattr_t *attrp
77 ) {
78 PIXsize_t ps;
79 /* the 2 here is to provide enough space for palPalEntry[0] and [1] */
80 LOGPALETTE pal[2];
81
82 HBRUSH brush;
83 HPEN pen;
84 HBITMAP bmap;
85 HCURSOR cursor;
86 DWORD wflags;
87 int color, ai, i;
88
89 if (!parent) {
90 Gerr (POS, G_ERRNOPARENTWIDGET);
91 return -1;
92 }
93 wflags = WS_CHILDWINDOW;
94 WCU->func = NULL;
95 WCU->needredraw = FALSE;
96 WCU->buttonsdown = 0;
97 WCU->bstate[0] = WCU->bstate[1] = WCU->bstate[2] = 0;
98 ps.x = ps.y = MINCWSIZE;
99 for (ai = 0; ai < attrn; ai++) {
100 switch (attrp[ai].id) {
101 case G_ATTRSIZE:
102 GETSIZE (attrp[ai].u.s, ps, MINCWSIZE);
103 break;
104 case G_ATTRBORDERWIDTH:
105 wflags |= WS_BORDER;
106 break;
107 case G_ATTRCURSOR:
108 /* will do it after the widget is created */
109 break;
110 case G_ATTRCOLOR:
111 /* will do it after the widget is created */
112 break;
113 case G_ATTRVIEWPORT:
114 /* will do it after the widget is created */
115 break;
116 case G_ATTRWINDOW:
117 /* will do it after the widget is created */
118 break;
119 case G_ATTRWINDOWID:
120 Gerr (POS, G_ERRCANNOTSETATTR1, "windowid");
121 return -1;
122 case G_ATTREVENTCB:
123 WCU->func = attrp[ai].u.func;
124 break;
125 case G_ATTRUSERDATA:
126 widget->udata = attrp[ai].u.u;
127 break;
128 default:
129 Gerr (POS, G_ERRBADATTRID, attrp[ai].id);
130 return -1;
131 }
132 }
133 Gadjustwrect (parent, &ps);
134 WCU->wrect.o.x = 0.0, WCU->wrect.o.y = 0.0;
135 WCU->wrect.c.x = 1.0, WCU->wrect.c.y = 1.0;
136 WCU->vsize.x = ps.x, WCU->vsize.y = ps.y;
137 if (!(widget->w = CreateWindow (
138 "CanvasClass", "canvas", wflags, 0, 0,
139 ps.x, ps.y, parent->w, (HMENU) (widget - &Gwidgets[0]),
140 hinstance, NULL
141 ))) {
142 Gerr (POS, G_ERRCANNOTCREATEWIDGET);
143 return -1;
144 }
145 ShowWindow (widget->w, SW_SHOW);
146 UpdateWindow (widget->w);
147 SetCursor (LoadCursor ((HINSTANCE) NULL, IDC_ARROW));
148 GC = GetDC (widget->w);
149 WCU->ncolor = 2;
150 pal[0].palVersion = 0x300; /* HA HA HA */
151 pal[0].palNumEntries = 2;
152 pal[0].palPalEntry[0].peRed = 255;
153 pal[0].palPalEntry[0].peGreen = 255;
154 pal[0].palPalEntry[0].peBlue = 255;
155 pal[0].palPalEntry[0].peFlags = 0;
156 pal[0].palPalEntry[1].peRed = 0;
157 pal[0].palPalEntry[1].peGreen = 0;
158 pal[0].palPalEntry[1].peBlue = 0;
159 pal[0].palPalEntry[1].peFlags = 0;
160 WCU->cmap = CreatePalette (&pal[0]);
161 WCU->colors[0].color = pal[0].palPalEntry[0];
162 for (i = 1; i < G_MAXCOLORS; i++)
163 WCU->colors[i].color = pal[0].palPalEntry[1];
164 SelectPalette (GC, WCU->cmap, FALSE);
165 RealizePalette (GC);
166 WCU->colors[0].inuse = TRUE;
167 WCU->colors[1].inuse = TRUE;
168 for (i = 2; i < G_MAXCOLORS; i++)
169 WCU->colors[i].inuse = FALSE;
170 WCU->gattr.color = 1;
171 brush = CreateSolidBrush (PALETTEINDEX (1));
172 SelectObject (GC, brush);
173 pen = CreatePen (PS_SOLID, 1, PALETTEINDEX (1));
174 SelectObject (GC, pen);
175 SetTextColor (GC, PALETTEINDEX (1));
176 SetBkMode (GC, TRANSPARENT);
177 WCU->gattr.width = 0;
178 WCU->gattr.mode = G_SRC;
179 WCU->gattr.fill = 0;
180 WCU->gattr.style = 0;
181 WCU->defgattr = WCU->gattr;
182 WCU->font = NULL;
183 if (Gdepth == 1) {
184 for (i = 0; i < 17; i++) {
185 if (!(bmap = CreateBitmap (4, 4, 1, 1, &grays[i][0])))
186 continue;
187 WCU->grays[i] = CreatePatternBrush (bmap);
188 }
189 }
190 for (ai = 0; ai < attrn; ai++) {
191 switch (attrp[ai].id) {
192 case G_ATTRCURSOR:
193 if (strcmp (attrp[ai].u.t, "watch") == 0) {
194 curcursori = 1;
195 cursor = LoadCursor ((HINSTANCE) NULL, IDC_WAIT);
196 } else if (strcmp (attrp[ai].u.t, "default") == 0) {
197 curcursori = -1;
198 cursor = LoadCursor ((HINSTANCE) NULL, IDC_ARROW);
199 } else {
200 Gerr (POS, G_ERRNOSUCHCURSOR, attrp[ai].u.t);
201 return -1;
202 }
203 SetCursor (cursor);
204 break;
205 case G_ATTRCOLOR:
206 color = attrp[ai].u.c.index;
207 if (color < 0 || color > G_MAXCOLORS) {
208 Gerr (POS, G_ERRBADCOLORINDEX, color);
209 return -1;
210 }
211 WCU->colors[color].color.peRed = attrp[ai].u.c.r;
212 WCU->colors[color].color.peGreen = attrp[ai].u.c.g;
213 WCU->colors[color].color.peBlue = attrp[ai].u.c.b;
214 WCU->colors[color].color.peFlags = 0;
215 if (color >= WCU->ncolor)
216 ResizePalette (WCU->cmap, color + 1), WCU->ncolor = color + 1;
217 SetPaletteEntries (
218 WCU->cmap, (int) color, 1, &WCU->colors[color].color);
219 RealizePalette (GC);
220 WCU->colors[color].inuse = TRUE;
221 if (color == WCU->gattr.color)
222 WCU->gattr.color = -1;
223 break;
224 case G_ATTRVIEWPORT:
225 if (attrp[ai].u.s.x == 0)
226 attrp[ai].u.s.x = 1;
227 if (attrp[ai].u.s.y == 0)
228 attrp[ai].u.s.y = 1;
229 WCU->vsize.x = (int) (attrp[ai].u.s.x + 0.5);
230 WCU->vsize.y = (int) (attrp[ai].u.s.y + 0.5);
231 SetWindowPos (
232 widget->w, (HWND) NULL, 0, 0, WCU->vsize.x,
233 WCU->vsize.y, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE
234 );
235 break;
236 case G_ATTRWINDOW:
237 if (attrp[ai].u.r.o.x == attrp[ai].u.r.c.x)
238 attrp[ai].u.r.c.x = attrp[ai].u.r.o.x + 1;
239 if (attrp[ai].u.r.o.y == attrp[ai].u.r.c.y)
240 attrp[ai].u.r.c.y = attrp[ai].u.r.o.y + 1;
241 WCU->wrect = attrp[ai].u.r;
242 break;
243 }
244 }
245 if (parent && parent->type == G_ARRAYWIDGET)
246 Gawinsertchild (parent, widget);
247 Gadjustclip (widget);
248 return 0;
249 }
250
GCsetwidgetattr(Gwidget_t * widget,int attrn,Gwattr_t * attrp)251 int GCsetwidgetattr (Gwidget_t *widget, int attrn, Gwattr_t *attrp) {
252 HCURSOR cursor;
253 Gwidget_t *parent;
254 PIXsize_t ps;
255 DWORD wflags1;
256 int ai, color;
257
258 parent = (widget->pwi == -1) ? NULL : &Gwidgets[widget->pwi];
259 wflags1 = SWP_NOMOVE | SWP_NOZORDER;
260 for (ai = 0; ai < attrn; ai++) {
261 switch (attrp[ai].id) {
262 case G_ATTRSIZE:
263 GETSIZE (attrp[ai].u.s, ps, MINCWSIZE);
264 Gadjustwrect (parent, &ps);
265 SetWindowPos (widget->w, (HWND) NULL, 0, 0, ps.x, ps.y, wflags1);
266 break;
267 case G_ATTRBORDERWIDTH:
268 Gerr (POS, G_ERRCANNOTSETATTR2, "borderwidth");
269 return -1;
270 case G_ATTRCURSOR:
271 if (strcmp (attrp[ai].u.t, "watch") == 0) {
272 curcursori = 1;
273 cursor = LoadCursor ((HINSTANCE) NULL, IDC_WAIT);
274 } else if (strcmp (attrp[ai].u.t, "default") == 0) {
275 curcursori = -1;
276 cursor = LoadCursor ((HINSTANCE) NULL, IDC_ARROW);
277 } else {
278 Gerr (POS, G_ERRNOSUCHCURSOR, attrp[ai].u.t);
279 return -1;
280 }
281 SetCursor (cursor);
282 break;
283 case G_ATTRCOLOR:
284 color = attrp[ai].u.c.index;
285 if (color < 0 || color > G_MAXCOLORS) {
286 Gerr (POS, G_ERRBADCOLORINDEX, color);
287 return -1;
288 }
289 WCU->colors[color].color.peRed = attrp[ai].u.c.r;
290 WCU->colors[color].color.peGreen = attrp[ai].u.c.g;
291 WCU->colors[color].color.peBlue = attrp[ai].u.c.b;
292 WCU->colors[color].color.peFlags = 0;
293 if (color >= WCU->ncolor)
294 ResizePalette (WCU->cmap, color + 1), WCU->ncolor = color + 1;
295 SetPaletteEntries (
296 WCU->cmap, (int) color, 1, &WCU->colors[color].color
297 );
298 RealizePalette (GC);
299 WCU->colors[color].inuse = TRUE;
300 if (color == WCU->gattr.color)
301 WCU->gattr.color = -1;
302 break;
303 case G_ATTRVIEWPORT:
304 if (attrp[ai].u.s.x == 0)
305 attrp[ai].u.s.x = 1;
306 if (attrp[ai].u.s.y == 0)
307 attrp[ai].u.s.y = 1;
308 WCU->vsize.x = (int) (attrp[ai].u.s.x + 0.5);
309 WCU->vsize.y = (int) (attrp[ai].u.s.y + 0.5);
310 ps.x = WCU->vsize.x, ps.y = WCU->vsize.y;
311 Gadjustwrect (&Gwidgets[widget->pwi], &ps);
312 SetWindowPos (
313 widget->w, (HWND) NULL, 0, 0, ps.x,
314 ps.y, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE
315 );
316 Gadjustclip (widget);
317 break;
318 case G_ATTRWINDOW:
319 if (attrp[ai].u.r.o.x == attrp[ai].u.r.c.x)
320 attrp[ai].u.r.c.x = attrp[ai].u.r.o.x + 1;
321 if (attrp[ai].u.r.o.y == attrp[ai].u.r.c.y)
322 attrp[ai].u.r.c.y = attrp[ai].u.r.o.y + 1;
323 WCU->wrect = attrp[ai].u.r;
324 Gadjustclip (widget);
325 break;
326 case G_ATTRWINDOWID:
327 Gerr (POS, G_ERRCANNOTSETATTR2, "windowid");
328 return -1;
329 case G_ATTREVENTCB:
330 WCU->func = attrp[ai].u.func;
331 break;
332 case G_ATTRUSERDATA:
333 widget->udata = attrp[ai].u.u;
334 break;
335 default:
336 Gerr (POS, G_ERRBADATTRID, attrp[ai].id);
337 return -1;
338 }
339 }
340 return 0;
341 }
342
GCgetwidgetattr(Gwidget_t * widget,int attrn,Gwattr_t * attrp)343 int GCgetwidgetattr (Gwidget_t *widget, int attrn, Gwattr_t *attrp) {
344 PALETTEENTRY *cp;
345 RECT r;
346 int color, ai;
347
348 for (ai = 0; ai < attrn; ai++) {
349 switch (attrp[ai].id) {
350 case G_ATTRSIZE:
351 GetWindowRect (widget->w, &r);
352 attrp[ai].u.s.x = r.right - r.left;
353 attrp[ai].u.s.y = r.bottom - r.top;
354 break;
355 case G_ATTRBORDERWIDTH:
356 Gerr (POS, G_ERRCANNOTGETATTR, "borderwidth");
357 return -1;
358 case G_ATTRCURSOR:
359 attrp[ai].u.t = (curcursori == -1) ? "default" : "watch";
360 break;
361 case G_ATTRCOLOR:
362 color = attrp[ai].u.c.index;
363 if (color < 0 || color > G_MAXCOLORS) {
364 Gerr (POS, G_ERRBADCOLORINDEX, color);
365 return -1;
366 }
367 if (WCU->colors[color].inuse) {
368 cp = &WCU->colors[color].color;
369 attrp[ai].u.c.r = cp->peRed;
370 attrp[ai].u.c.g = cp->peGreen;
371 attrp[ai].u.c.b = cp->peBlue;
372 } else {
373 attrp[ai].u.c.r = -1;
374 attrp[ai].u.c.g = -1;
375 attrp[ai].u.c.b = -1;
376 }
377 break;
378 case G_ATTRVIEWPORT:
379 attrp[ai].u.s = WCU->vsize;
380 break;
381 case G_ATTRWINDOW:
382 attrp[ai].u.r = WCU->wrect;
383 break;
384 case G_ATTRWINDOWID:
385 sprintf (&Gbufp[0], "0x%lx", widget->w);
386 attrp[ai].u.t = &Gbufp[0];
387 break;
388 case G_ATTREVENTCB:
389 attrp[ai].u.func = WCU->func;
390 break;
391 case G_ATTRUSERDATA:
392 attrp[ai].u.u = widget->udata;
393 break;
394 default:
395 Gerr (POS, G_ERRBADATTRID, attrp[ai].id);
396 return -1;
397 }
398 }
399 return 0;
400 }
401
GCdestroywidget(Gwidget_t * widget)402 int GCdestroywidget (Gwidget_t *widget) {
403 Gwidget_t *parent;
404
405 parent = (widget->pwi == -1) ? NULL : &Gwidgets[widget->pwi];
406 if (parent && parent->type == G_ARRAYWIDGET)
407 Gawdeletechild (parent, widget);
408 DestroyWindow (widget->w);
409 return 0;
410 }
411
GCcanvasclear(Gwidget_t * widget)412 int GCcanvasclear (Gwidget_t *widget) {
413 Ggattr_t attr;
414 RECT r;
415 HBRUSH brush, pbrush;
416
417 attr.flags = 0;
418 setgattr (widget, &attr);
419 brush = CreateSolidBrush (PALETTEINDEX (0));
420 pbrush = SelectObject (GC, brush);
421 GetClientRect (widget->w, &r);
422 Rectangle (GC, r.left, r.top, r.right, r.bottom);
423 SelectObject (GC, pbrush);
424 DeleteObject (brush);
425 WCU->needredraw = FALSE;
426 return 0;
427 }
428
GCsetgfxattr(Gwidget_t * widget,Ggattr_t * ap)429 int GCsetgfxattr (Gwidget_t *widget, Ggattr_t *ap) {
430 setgattr (widget, ap);
431 WCU->defgattr = WCU->gattr;
432 return 0;
433 }
434
GCgetgfxattr(Gwidget_t * widget,Ggattr_t * ap)435 int GCgetgfxattr (Gwidget_t *widget, Ggattr_t *ap) {
436 if ((ap->flags & G_GATTRCOLOR))
437 ap->color = WCU->gattr.color;
438 if ((ap->flags & G_GATTRWIDTH))
439 ap->width = WCU->gattr.width;
440 if ((ap->flags & G_GATTRMODE))
441 ap->mode = WCU->gattr.mode;
442 if ((ap->flags & G_GATTRFILL))
443 ap->fill = WCU->gattr.fill;
444 if ((ap->flags & G_GATTRSTYLE))
445 ap->style = WCU->gattr.style;
446 return 0;
447 }
448
GCarrow(Gwidget_t * widget,Gpoint_t gp1,Gpoint_t gp2,Ggattr_t * ap)449 int GCarrow (Gwidget_t *widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t *ap) {
450 PIXpoint_t pp1, pp2, pa, pb, pd;
451 Grect_t gr;
452 double tangent, l;
453
454 if (gp1.x < gp2.x)
455 gr.o.x = gp1.x, gr.c.x = gp2.x;
456 else
457 gr.o.x = gp2.x, gr.c.x = gp1.x;
458 if (gp1.y < gp2.y)
459 gr.o.y = gp1.y, gr.c.y = gp2.y;
460 else
461 gr.o.y = gp2.y, gr.c.y = gp1.y;
462 if (!ISVISIBLE (gr))
463 return 1;
464 pp1 = pdrawtopix (widget, gp1), pp2 = pdrawtopix (widget, gp2);
465 pd.x = pp1.x - pp2.x, pd.y = pp1.y - pp2.y;
466 if (pd.x == 0 && pd.y == 0)
467 return 0;
468 tangent = atan2 ((double) pd.y, (double) pd.x);
469 if ((l = sqrt ((double) (pd.x * pd.x + pd.y * pd.y))) > 30)
470 l = 30;
471 pa.x = l * cos (tangent + M_PI / 7) + pp2.x;
472 pa.y = l * sin (tangent + M_PI / 7) + pp2.y;
473 pb.x = l * cos (tangent - M_PI / 7) + pp2.x;
474 pb.y = l * sin (tangent - M_PI / 7) + pp2.y;
475 setgattr (widget, ap);
476 MoveToEx (GC, pp1.x, pp1.y, NULL), LineTo (GC, pp2.x, pp2.y);
477 MoveToEx (GC, pa.x, pa.y, NULL), LineTo (GC, pp2.x, pp2.y);
478 MoveToEx (GC, pb.x, pb.y, NULL), LineTo (GC, pp2.x, pp2.y);
479 return 0;
480 }
481
GCline(Gwidget_t * widget,Gpoint_t gp1,Gpoint_t gp2,Ggattr_t * ap)482 int GCline (Gwidget_t *widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t *ap) {
483 PIXpoint_t pp1, pp2;
484 Grect_t gr;
485
486 if (gp1.x < gp2.x)
487 gr.o.x = gp1.x, gr.c.x = gp2.x;
488 else
489 gr.o.x = gp2.x, gr.c.x = gp1.x;
490 if (gp1.y < gp2.y)
491 gr.o.y = gp1.y, gr.c.y = gp2.y;
492 else
493 gr.o.y = gp2.y, gr.c.y = gp1.y;
494 if (!ISVISIBLE (gr))
495 return 1;
496 pp1 = pdrawtopix (widget, gp1), pp2 = pdrawtopix (widget, gp2);
497 setgattr (widget, ap);
498 MoveToEx (GC, pp1.x, pp1.y, NULL);
499 LineTo (GC, pp2.x, pp2.y);
500 return 0;
501 }
502
GCbox(Gwidget_t * widget,Grect_t gr,Ggattr_t * ap)503 int GCbox (Gwidget_t *widget, Grect_t gr, Ggattr_t *ap) {
504 PIXrect_t pr;
505 Grect_t gr2;
506
507 if (gr.o.x <= gr.c.x)
508 gr2.o.x = gr.o.x, gr2.c.x = gr.c.x;
509 else
510 gr2.o.x = gr.c.x, gr2.c.x = gr.o.x;
511 if (gr.o.y <= gr.c.y)
512 gr2.o.y = gr.o.y, gr2.c.y = gr.c.y;
513 else
514 gr2.o.y = gr.c.y, gr2.c.y = gr.o.y;
515 if (!ISVISIBLE (gr2))
516 return 1;
517 pr = rdrawtopix (widget, gr);
518 setgattr (widget, ap);
519 if (WCU->gattr.fill)
520 Rectangle (GC, pr.o.x, pr.o.y, pr.c.x, pr.c.y);
521 else {
522 Gppp[0].x = pr.o.x, Gppp[0].y = pr.o.y;
523 Gppp[1].x = pr.c.x, Gppp[1].y = pr.o.y;
524 Gppp[2].x = pr.c.x, Gppp[2].y = pr.c.y;
525 Gppp[3].x = pr.o.x, Gppp[3].y = pr.c.y;
526 Gppp[4].x = pr.o.x, Gppp[4].y = pr.o.y;
527 Polyline (GC, Gppp, 5);
528 }
529 return 0;
530 }
531
GCpolygon(Gwidget_t * widget,int gpn,Gpoint_t * gpp,Ggattr_t * ap)532 int GCpolygon (Gwidget_t *widget, int gpn, Gpoint_t *gpp, Ggattr_t *ap) {
533 Grect_t gr;
534 int n, i;
535
536 if (gpn == 0)
537 return 0;
538 gr.o = gpp[0], gr.c = gpp[0];
539 for (i = 1; i < gpn; i++) {
540 gr.o.x = min (gr.o.x, gpp[i].x);
541 gr.o.y = min (gr.o.y, gpp[i].y);
542 gr.c.x = max (gr.c.x, gpp[i].x);
543 gr.c.y = max (gr.c.y, gpp[i].y);
544 }
545 if (!ISVISIBLE (gr))
546 return 1;
547 if (gpn + 1 > Gppn) {
548 n = (((gpn + 1) + PPINCR - 1) / PPINCR) * PPINCR;
549 Gppp = Marraygrow (Gppp, (long) n * PPSIZE);
550 Gppn = n;
551 }
552 for (i = 0; i < gpn; i++)
553 Gppp[i] = pdrawtopix (widget, gpp[i]);
554 setgattr (widget, ap);
555 if (WCU->gattr.fill) {
556 if (Gppp[gpn - 1].x != Gppp[0].x || Gppp[gpn - 1].y != Gppp[0].y)
557 Gppp[gpn] = Gppp[0], gpn++;
558 Polygon (GC, Gppp, (int) gpn);
559 } else
560 Polyline (GC, Gppp, (int) gpn);
561 return 0;
562 }
563
GCsplinegon(Gwidget_t * widget,int gpn,Gpoint_t * gpp,Ggattr_t * ap)564 int GCsplinegon (Gwidget_t *widget, int gpn, Gpoint_t *gpp, Ggattr_t *ap) {
565 PIXpoint_t p0, p1, p2, p3;
566 Grect_t gr;
567 int n, i;
568
569 if (gpn == 0)
570 return 0;
571 gr.o = gpp[0], gr.c = gpp[0];
572 for (i = 1; i < gpn; i++) {
573 gr.o.x = min (gr.o.x, gpp[i].x);
574 gr.o.y = min (gr.o.y, gpp[i].y);
575 gr.c.x = max (gr.c.x, gpp[i].x);
576 gr.c.y = max (gr.c.y, gpp[i].y);
577 }
578 if (!ISVISIBLE (gr))
579 return 1;
580 Gppi = 1;
581 if (Gppi >= Gppn) {
582 n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR;
583 Gppp = Marraygrow (Gppp, (long) n * PPSIZE);
584 Gppn = n;
585 }
586 Gppp[0] = p3 = pdrawtopix (widget, gpp[0]);
587 for (i = 1; i < gpn; i += 3) {
588 p0 = p3;
589 p1 = pdrawtopix (widget, gpp[i]);
590 p2 = pdrawtopix (widget, gpp[i + 1]);
591 p3 = pdrawtopix (widget, gpp[i + 2]);
592 bezier (p0, p1, p2, p3);
593 }
594 setgattr (widget, ap);
595 if (WCU->gattr.fill) {
596 if (Gppp[Gppi - 1].x != Gppp[0].x || Gppp[Gppi - 1].y != Gppp[0].y)
597 Gppp[Gppi] = Gppp[0], Gppi++;
598 Polygon (GC, Gppp, (int) Gppi);
599 } else
600 Polyline (GC, Gppp, (int) Gppi);
601 return 0;
602 }
603
bezier(PIXpoint_t p0,PIXpoint_t p1,PIXpoint_t p2,PIXpoint_t p3)604 static void bezier (
605 PIXpoint_t p0, PIXpoint_t p1, PIXpoint_t p2, PIXpoint_t p3
606 ) {
607 Gpoint_t gp0, gp1, gp2;
608 Gsize_t s;
609 PIXpoint_t p;
610 double t;
611 int n, i, steps;
612
613 if ((s.x = p3.x - p0.x) < 0)
614 s.x = - s.x;
615 if ((s.y = p3.y - p0.y) < 0)
616 s.y = - s.y;
617 if (s.x > s.y)
618 steps = s.x / 5 + 1;
619 else
620 steps = s.y / 5 + 1;
621 for (i = 0; i <= steps; i++) {
622 t = i / (double) steps;
623 gp0.x = p0.x + t * (p1.x - p0.x);
624 gp0.y = p0.y + t * (p1.y - p0.y);
625 gp1.x = p1.x + t * (p2.x - p1.x);
626 gp1.y = p1.y + t * (p2.y - p1.y);
627 gp2.x = p2.x + t * (p3.x - p2.x);
628 gp2.y = p2.y + t * (p3.y - p2.y);
629 gp0.x = gp0.x + t * (gp1.x - gp0.x);
630 gp0.y = gp0.y + t * (gp1.y - gp0.y);
631 gp1.x = gp1.x + t * (gp2.x - gp1.x);
632 gp1.y = gp1.y + t * (gp2.y - gp1.y);
633 p.x = gp0.x + t * (gp1.x - gp0.x) + 0.5;
634 p.y = gp0.y + t * (gp1.y - gp0.y) + 0.5;
635 if (Gppi >= Gppn) {
636 n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR;
637 Gppp = Marraygrow (Gppp, (long) n * PPSIZE);
638 Gppn = n;
639 }
640 Gppp[Gppi++] = p;
641 }
642 }
643
GCarc(Gwidget_t * widget,Gpoint_t gc,Gsize_t gs,double ang1,double ang2,Ggattr_t * ap)644 int GCarc (
645 Gwidget_t *widget, Gpoint_t gc, Gsize_t gs, double ang1,
646 double ang2, Ggattr_t *ap
647 ) {
648 PIXpoint_t pc;
649 PIXsize_t ps;
650 Grect_t gr;
651 double a1, a2;
652
653 gr.o.x = gc.x - gs.x, gr.o.y = gc.y - gs.y;
654 gr.c.x = gc.x + gs.x, gr.c.y = gc.y + gs.y;
655 if (!ISVISIBLE (gr))
656 return 1;
657 pc = pdrawtopix (widget, gc), ps = sdrawtopix (widget, gs);
658 setgattr (widget, ap);
659 a1 = ang1 * M_PI / 180, a2 = ang2 * M_PI / 180;
660 if (WCU->gattr.fill)
661 Chord (
662 GC, pc.x - ps.x, pc.y - ps.y, pc.x + ps.x, pc.y + ps.y,
663 (int) (cos (a1) * ps.x), (int) (sin (a1) * ps.x),
664 (int) (cos (a2) * ps.x), (int) (sin (a2) * ps.x)
665 );
666 else
667 Arc (
668 GC, pc.x - ps.x, pc.y - ps.y, pc.x + ps.x, pc.y + ps.y,
669 (int) (cos (a1) * ps.x), (int) (sin (a1) * ps.x),
670 (int) (cos (a2) * ps.x), (int) (sin (a2) * ps.x)
671 );
672 return 0;
673 }
674
675 #define YSCALE ((WCU->vsize.y) / (WCU->wrect.c.y - WCU->wrect.o.y))
676
GCtext(Gwidget_t * widget,Gtextline_t * tlp,int n,Gpoint_t go,char * fn,double fs,char * justs,Ggattr_t * ap)677 int GCtext (
678 Gwidget_t *widget, Gtextline_t *tlp, int n, Gpoint_t go,
679 char *fn, double fs, char *justs, Ggattr_t *ap
680 ) {
681 Gsize_t gs;
682 PIXpoint_t po;
683 PIXsize_t ps;
684 PIXrect_t pr;
685 Grect_t gr;
686 HFONT font;
687 TEXTMETRIC tm;
688 SIZE size;
689 RECT r;
690 int x, y, w, h, i;
691
692 po = pdrawtopix (widget, go);
693 gs.x = 0, gs.y = fs;
694 ps = sdrawtopix (widget, gs);
695 if (!(font = findfont (fn, ps.y))) {
696 Rectangle (GC, po.x, po.y, po.x + 1, po.y + 1);
697 return 0;
698 }
699 setgattr (widget, ap);
700 SETFONT (font);
701 GetTextMetrics (GC, &tm);
702 for (w = h = 0, i = 0; i < n; i++) {
703 if (tlp[i].n)
704 GetTextExtentPoint32 (GC, tlp[i].p, (int) tlp[i].n, &size);
705 else
706 GetTextExtentPoint32 (GC, "M", (int) 1, &size);
707 tlp[i].w = size.cx, tlp[i].h = size.cy;
708 w = max (w, size.cx), h += size.cy;
709 }
710 switch (justs[0]) {
711 case 'l': po.x += w / 2; break;
712 case 'r': po.x -= w / 2; break;
713 }
714 switch (justs[1]) {
715 case 'd': po.y -= h; break;
716 case 'b': po.y -= (h - tm.tmDescent); break;
717 case 'c': po.y -= h / 2; break;
718 }
719 pr.o.x = po.x - w / 2, pr.o.y = po.y;
720 pr.c.x = po.x + w / 2, pr.c.y = po.y + h;
721 gr = rpixtodraw (widget, pr);
722 if (!ISVISIBLE (gr))
723 return 1;
724 for (i = 0; i < n; i++) {
725 switch (tlp[i].j) {
726 case 'l': x = po.x - w / 2; break;
727 case 'n': x = po.x - tlp[i].w / 2; break;
728 case 'r': x = po.x - (tlp[i].w - w / 2); break;
729 }
730 y = po.y + i * tlp[i].h;
731 r.left = x, r.top = y;
732 r.right = x + tlp[i].w, r.bottom = y + tlp[i].h;
733 DrawText (GC, tlp[i].p, (int) tlp[i].n, &r, DT_LEFT | DT_TOP);
734 }
735 return 0;
736 }
737
GCgettextsize(Gwidget_t * widget,Gtextline_t * tlp,int n,char * fn,double fs,Gsize_t * gsp)738 int GCgettextsize (
739 Gwidget_t *widget, Gtextline_t *tlp, int n, char *fn,
740 double fs, Gsize_t *gsp
741 ) {
742 Gsize_t gs;
743 PIXsize_t ps;
744 HFONT font;
745 int i;
746 SIZE size;
747
748 gs.x = 0, gs.y = fs;
749 ps = sdrawtopix (widget, gs);
750 if (!(font = findfont (fn, ps.y))) {
751 gsp->x = 1, gsp->y = 1;
752 return 0;
753 }
754 SETFONT (font);
755 for (ps.x = ps.y = 0, i = 0; i < n; i++) {
756 GetTextExtentPoint32 (GC, tlp[i].p, (int) tlp[i].n, &size);
757 ps.x = max (ps.x, size.cx), ps.y += size.cy;
758 }
759 *gsp = spixtodraw (widget, ps);
760 return 0;
761 }
762
findfont(char * name,int size)763 static HFONT findfont (char *name, int size) {
764 HFONT font;
765 int fi;
766
767 if (name[0] == '\000')
768 return Gfontp[0].font;
769
770 sprintf (&Gbufp[0], name, size);
771 for (fi = 0; fi < Gfontn; fi++)
772 if (strcmp (&Gbufp[0], Gfontp[fi].name) == 0 && Gfontp[fi].size == size)
773 return Gfontp[fi].font;
774 font = CreateFont (
775 (int) size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &Gbufp[0]
776 );
777 if (!font)
778 font = Gfontp[0].font;
779
780 Gfontp = Marraygrow (Gfontp, (long) (Gfontn + 1) * FONTSIZE);
781 Gfontp[Gfontn].name = strdup (&Gbufp[0]);
782 Gfontp[Gfontn].size = size;
783 Gfontp[Gfontn].font = font;
784 Gfontn++;
785 return font;
786 }
787
GCcreatebitmap(Gwidget_t * widget,Gbitmap_t * bitmap,Gsize_t s)788 int GCcreatebitmap (Gwidget_t *widget, Gbitmap_t *bitmap, Gsize_t s) {
789 if (!widget) {
790 Gerr (POS, G_ERRNOPARENTWIDGET);
791 return -1;
792 }
793 if (!bitmap) {
794 Gerr (POS, G_ERRNOBITMAP);
795 return -1;
796 }
797 if (!(bitmap->u.bmap.orig = CreateBitmap (
798 (int) s.x, (int) s.y, 1, Gdepth, NULL
799 ))) {
800 Gerr (POS, G_ERRCANNOTCREATEBITMAP);
801 return -1;
802 }
803 bitmap->u.bmap.scaled = 0;
804 bitmap->scale.x = bitmap->scale.y = 1;
805 bitmap->ctype = widget->type;
806 bitmap->canvas = widget - &Gwidgets[0];
807 bitmap->size = s;
808 return 0;
809 }
810
GCdestroybitmap(Gbitmap_t * bitmap)811 int GCdestroybitmap (Gbitmap_t *bitmap) {
812 if (!bitmap) {
813 Gerr (POS, G_ERRNOBITMAP);
814 return -1;
815 }
816 DeleteObject (bitmap->u.bmap.orig);
817 if (bitmap->u.bmap.scaled)
818 DeleteObject (bitmap->u.bmap.scaled);
819 return 0;
820 }
821
GCreadbitmap(Gwidget_t * widget,Gbitmap_t * bitmap,FILE * fp)822 int GCreadbitmap (Gwidget_t *widget, Gbitmap_t *bitmap, FILE *fp) {
823 Gsize_t s;
824 HDC gc;
825 char bufp[2048];
826 unsigned int rgb[3];
827 char *s1, *s2;
828 char c;
829 int bufn, bufi, step, x, y, k;
830
831 if (!widget) {
832 Gerr (POS, G_ERRNOPARENTWIDGET);
833 return -1;
834 }
835 if (!bitmap) {
836 Gerr (POS, G_ERRNOBITMAP);
837 return -1;
838 }
839 step = 0;
840 while (step < 3) {
841 l1:
842 if (!fgets (bufp, 2048, fp)) {
843 Gerr (POS, G_ERRCANNOTREADBITMAP);
844 return -1;
845 }
846 s1 = &bufp[0];
847 l2:
848 for (; *s1 && isspace (*s1); s1++)
849 ;
850 if (!*s1 || *s1 == '#')
851 goto l1;
852 switch (step) {
853 case 0:
854 if (strncmp (s1, "P6", 2) != 0) {
855 Gerr (POS, G_ERRCANNOTREADBITMAP);
856 return -1;
857 }
858 step++, s1 += 2;
859 goto l2;
860 case 1:
861 for (s2 = s1; *s2 && *s2 >= '0' && *s2 <= '9'; s2++)
862 ;
863 c = *s2, *s2 = 0;
864 if (s2 == s1 || (s.x = atoi (s1)) <= 0) {
865 *s2 = c, Gerr (POS, G_ERRCANNOTREADBITMAP);
866 return -1;
867 }
868 *s2 = c, step++, s1 = s2;
869 goto l2;
870 case 2:
871 for (s2 = s1; *s2 && *s2 >= '0' && *s2 <= '9'; s2++)
872 ;
873 c = *s2, *s2 = 0;
874 if (s2 == s1 || (s.y = atoi (s1)) <= 0) {
875 *s2 = c, Gerr (POS, G_ERRCANNOTREADBITMAP);
876 return -1;
877 }
878 *s2 = c, step++, s1 = s2;
879 goto l2;
880 }
881 }
882 if (!(bitmap->u.bmap.orig = CreateBitmap (
883 (int) s.x, (int) s.y, 1, Gdepth, NULL
884 ))) {
885 Gerr (POS, G_ERRCANNOTCREATEBITMAP);
886 return -1;
887 }
888 gc = CreateCompatibleDC (GC);
889 SelectObject (gc, bitmap->u.bmap.orig);
890 bitmap->u.bmap.scaled = 0;
891 bitmap->scale.x = bitmap->scale.y = 1;
892 bitmap->ctype = widget->type;
893 bitmap->canvas = widget - &Gwidgets[0];
894 bitmap->size = s;
895 bufi = bufn = 0;
896 bufp[bufi] = 0;
897 for (y = 0; y < s.y; y++) {
898 for (x = 0; x < s.x; x++) {
899 for (k = 0; k < 3; k++) {
900 if (bufi == bufn) {
901 if ((bufn = fread (bufp, 1, 2047, fp)) == 0) {
902 if (ferror (fp))
903 bufn = -1;
904 DeleteDC (gc);
905 DeleteObject (bitmap->u.bmap.orig);
906 Gerr (POS, G_ERRCANNOTCREATEBITMAP);
907 return -1;
908 }
909 bufi = 0;
910 }
911 rgb[k] = (unsigned char) bufp[bufi++];
912 }
913 SetPixel (gc, x, y, RGB (rgb[0], rgb[1], rgb[2]));
914 }
915 }
916 DeleteDC (gc);
917 return 0;
918 }
919
GCwritebitmap(Gbitmap_t * bitmap,FILE * fp)920 int GCwritebitmap (Gbitmap_t *bitmap, FILE *fp) {
921 Gwidget_t *widget;
922 HDC gc;
923 COLORREF color;
924 char bufp[2048];
925 int bufi, x, y, w, h;
926
927 if (!bitmap) {
928 Gerr (POS, G_ERRNOBITMAP);
929 return -1;
930 }
931 if (
932 bitmap->canvas < 0 || bitmap->canvas >= Gwidgetn ||
933 !Gwidgets[bitmap->canvas].inuse
934 ) {
935 Gerr (POS, G_ERRBADWIDGETID, bitmap->canvas);
936 return -1;
937 }
938 widget = &Gwidgets[bitmap->canvas];
939 if (widget->type != G_CANVASWIDGET && widget->type != G_PCANVASWIDGET) {
940 Gerr (POS, G_ERRNOTACANVAS, bitmap->canvas);
941 return -1;
942 }
943 gc = CreateCompatibleDC (GC);
944 SelectObject (gc, bitmap->u.bmap.orig);
945 fprintf (fp, "P6\n%d %d 255\n", (int) bitmap->size.x, (int) bitmap->size.y);
946 bufi = 0;
947 w = bitmap->size.x;
948 h = bitmap->size.y;
949 for (y = 0; y < h; y++) {
950 for (x = 0; x < w; x++) {
951 color = GetPixel (gc, x, y);
952 bufp[bufi++] = GetRValue (color);
953 bufp[bufi++] = GetGValue (color);
954 bufp[bufi++] = GetBValue (color);
955 if (bufi + 3 >= 2048) {
956 fwrite (bufp, 1, bufi, fp);
957 bufi = 0;
958 }
959 }
960 }
961 if (bufi > 0)
962 fwrite (bufp, 1, bufi, fp);
963 DeleteDC (gc);
964 return 0;
965 }
966
GCbitblt(Gwidget_t * widget,Gpoint_t gp,Grect_t gr,Gbitmap_t * bitmap,char * mode,Ggattr_t * ap)967 int GCbitblt (
968 Gwidget_t *widget, Gpoint_t gp, Grect_t gr, Gbitmap_t *bitmap,
969 char *mode, Ggattr_t *ap
970 ) {
971 PIXrect_t pr, r;
972 PIXpoint_t pp;
973 PIXsize_t s;
974 Gsize_t scale;
975 Gxy_t p;
976 HBITMAP pix;
977 HDC gc;
978 double tvx, tvy, twx, twy;
979
980 if (gr.o.x > gr.c.x)
981 p.x = gr.o.x, gr.o.x = gr.c.x, gr.c.x = p.x;
982 if (gr.o.y > gr.c.y)
983 p.y = gr.o.y, gr.o.y = gr.c.y, gr.c.y = p.y;
984 if (strcmp (mode, "b2c") == 0) {
985 if (!ISVISIBLE (gr))
986 return 1;
987 tvx = WCU->vsize.x, tvy = WCU->vsize.y;
988 twx = WCU->wrect.c.x - WCU->wrect.o.x;
989 twy = WCU->wrect.c.y - WCU->wrect.o.y;
990 scale.x = tvx / twx, scale.y = tvy / twy;
991 if (scale.x == 1 && scale.y == 1)
992 pix = bitmap->u.bmap.orig;
993 else {
994 if (scale.x != bitmap->scale.x || scale.y != bitmap->scale.y)
995 scalebitmap (widget, bitmap, scale, TRUE, 1);
996 pix = bitmap->u.bmap.scaled;
997 }
998 pr = rdrawtopix (widget, gr);
999 pp = pdrawtobpix (bitmap, gp);
1000 s.x = pr.c.x - pr.o.x + 1, s.y = pr.c.y - pr.o.y + 1;
1001 r.o.x = pp.x, r.o.y = pp.y - s.y + 1;
1002 r.c.x = r.o.x + s.x - 1, r.c.y = r.o.y + s.y - 1;
1003 if (r.o.x < 0)
1004 pr.o.x -= r.o.x, r.o.x = 0;
1005 if (r.o.y < 0)
1006 pr.o.y -= r.o.y, r.o.y = 0;
1007 if (r.c.x >= bitmap->size.x * scale.x) {
1008 pr.c.x -= (r.c.x + 1 - bitmap->size.x * scale.x);
1009 r.c.x = bitmap->size.x * scale.x - 1;
1010 }
1011 if (r.c.y >= bitmap->size.y * scale.y) {
1012 pr.c.y -= (r.c.y + 1 - bitmap->size.y * scale.y);
1013 r.c.y = bitmap->size.y * scale.y - 1;
1014 }
1015 if (pr.o.x < 0)
1016 r.o.x -= pr.o.x, pr.o.x = 0;
1017 if (pr.o.y < 0)
1018 r.o.y -= pr.o.y, pr.o.y = 0;
1019 setgattr (widget, ap);
1020 gc = CreateCompatibleDC (GC);
1021 SelectObject (gc, pix);
1022 BitBlt (
1023 GC, pr.o.x, pr.o.y, r.c.x - r.o.x + 1, r.c.y - r.o.y + 1,
1024 gc, r.o.x, r.o.y, (WCU->gattr.mode == G_SRC) ? SRCCOPY : SRCINVERT
1025 );
1026 DeleteDC (gc);
1027 } else if (strcmp (mode, "c2b") == 0) {
1028 tvx = WCU->vsize.x, tvy = WCU->vsize.y;
1029 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1030 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1031 scale.x = tvx / twx, scale.y = tvy / twy;
1032 if (scale.x == 1 && scale.y == 1)
1033 pix = bitmap->u.bmap.orig;
1034 else {
1035 if (scale.x != bitmap->scale.x || scale.y != bitmap->scale.y)
1036 scalebitmap (widget, bitmap, scale, FALSE, 1);
1037 pix = bitmap->u.bmap.scaled;
1038 }
1039 pr = rdrawtobpix (bitmap, gr);
1040 pp = pdrawtopix (widget, gp);
1041 s.x = pr.c.x - pr.o.x + 1, s.y = pr.c.y - pr.o.y + 1;
1042 r.o.x = pp.x, r.o.y = pp.y - s.y + 1;
1043 r.c.x = r.o.x + s.x - 1, r.c.y = r.o.y + s.y - 1;
1044 if (pr.o.x < 0)
1045 r.o.x -= pr.o.x, pr.o.x = 0;
1046 if (pr.o.y < 0)
1047 r.o.y -= pr.o.y, pr.o.y = 0;
1048 if (pr.c.x >= bitmap->size.x * scale.x) {
1049 r.c.x -= (pr.c.x + 1 - bitmap->size.x * scale.x);
1050 pr.c.x = bitmap->size.x * scale.x - 1;
1051 }
1052 if (pr.c.y >= bitmap->size.y * scale.y) {
1053 r.c.y -= (pr.c.y + 1 - bitmap->size.y * scale.y);
1054 pr.c.y = bitmap->size.y * scale.y - 1;
1055 }
1056 if (r.o.x < 0)
1057 pr.o.x -= r.o.x, r.o.x = 0;
1058 if (r.o.y < 0)
1059 pr.o.y -= r.o.y, r.o.y = 0;
1060 setgattr (widget, ap);
1061 gc = CreateCompatibleDC (GC);
1062 SelectObject (gc, pix);
1063 BitBlt (
1064 gc, pr.o.x, pr.o.y, r.c.x - r.o.x + 1, r.c.y - r.o.y + 1,
1065 GC, r.o.x, r.o.y, (WCU->gattr.mode == G_SRC) ? SRCCOPY : SRCINVERT
1066 );
1067 if (pix != bitmap->u.bmap.orig)
1068 scalebitmap (widget, bitmap, scale, TRUE, -1);
1069 DeleteDC (gc);
1070 }
1071 return 0;
1072 }
1073
scalebitmap(Gwidget_t * widget,Gbitmap_t * bitmap,Gsize_t scale,int copybits,int dir)1074 static int scalebitmap (
1075 Gwidget_t *widget, Gbitmap_t *bitmap, Gsize_t scale,
1076 int copybits, int dir
1077 ) {
1078 Gsize_t nsize, o2n;
1079 HBITMAP opix, spix;
1080 COLORREF color;
1081 HDC gc1, gc2;
1082 int x, y, x2, y2, xp, yp;
1083 double prod, rgb[3], xr2, yr2, xl2, yl2, xf2, yf2, xr, yr, xl, yl;
1084
1085 if (!copybits) {
1086 if (dir == 1) {
1087 nsize.x = (int) (bitmap->size.x * scale.x);
1088 nsize.y = (int) (bitmap->size.y * scale.y);
1089 if (!(spix = CreateBitmap (
1090 (int) nsize.x, (int) nsize.y, 1, Gdepth, NULL
1091 ))) {
1092 Gerr (POS, G_ERRCANNOTCREATEBITMAP);
1093 return -1;
1094 }
1095 if (bitmap->u.bmap.scaled)
1096 DeleteObject (bitmap->u.bmap.scaled);
1097 bitmap->u.bmap.scaled = spix;
1098 bitmap->scale = scale;
1099 }
1100 return 0;
1101 }
1102 if (dir == 1) {
1103 nsize.x = (int) (bitmap->size.x * scale.x);
1104 nsize.y = (int) (bitmap->size.y * scale.y);
1105 o2n.x = 1 / scale.x, o2n.y = 1 / scale.y;
1106 if (!(spix = CreateBitmap (
1107 (int) nsize.x, (int) nsize.y, 1, Gdepth, NULL
1108 ))) {
1109 Gerr (POS, G_ERRCANNOTCREATEBITMAP);
1110 return -1;
1111 }
1112 opix = bitmap->u.bmap.orig;
1113 } else {
1114 nsize.x = (int) bitmap->size.x;
1115 nsize.y = (int) bitmap->size.y;
1116 o2n.x = scale.x, o2n.y = scale.y;
1117 spix = bitmap->u.bmap.orig;
1118 opix = bitmap->u.bmap.scaled;
1119 }
1120 gc1 = CreateCompatibleDC (GC);
1121 SelectObject (gc1, opix);
1122 gc2 = CreateCompatibleDC (GC);
1123 SelectObject (gc2, spix);
1124 prod = o2n.x * o2n.y;
1125 y = 0;
1126 yr = o2n.y;
1127 yl = 0;
1128 for (yp = 0; yp < nsize.y; yp++) {
1129 x = 0;
1130 xr = o2n.x;
1131 xl = 0;
1132 for (xp = 0; xp < nsize.x; xp++) {
1133 y2 = y;
1134 yr2 = yr;
1135 yl2 = yl;
1136 rgb[0] = rgb[1] = rgb[2] = 0;
1137 do {
1138 x2 = x;
1139 xr2 = xr;
1140 xl2 = xl;
1141 yf2 = (yl2 + yr2 > 1) ? 1 - yl2 : yr2, yr2 -= yf2;
1142 do {
1143 xf2 = (xl2 + xr2 > 1) ? 1 - xl2 : xr2, xr2 -= xf2;
1144 color = GetPixel (gc1, x2, y2);
1145 rgb[0] += (GetRValue (color) * xf2 * yf2 / prod);
1146 rgb[1] += (GetGValue (color) * xf2 * yf2 / prod);
1147 rgb[2] += (GetBValue (color) * xf2 * yf2 / prod);
1148 xl2 += xf2;
1149 if (xl2 >= 1)
1150 x2++, xl2 -= 1;
1151 } while (xr2 > 0);
1152 xr2 = o2n.x;
1153 yl2 += yf2;
1154 if (yl2 >= 1)
1155 y2++, yl2 -= 1;
1156 } while (yr2 > 0);
1157 yr2 = o2n.y;
1158 SetPixel (gc2, xp, yp, RGB (rgb[0], rgb[1], rgb[2]));
1159 x = x2;
1160 xr = xr2;
1161 xl = xl2;
1162 }
1163 y = y2;
1164 yr = yr2;
1165 yl = yl2;
1166 }
1167 DeleteDC (gc1);
1168 DeleteDC (gc2);
1169 if (dir == 1) {
1170 if (bitmap->u.bmap.scaled)
1171 DeleteObject (bitmap->u.bmap.scaled);
1172 bitmap->u.bmap.scaled = spix;
1173 bitmap->scale = scale;
1174 }
1175 return 0;
1176 }
1177
GCgetmousecoords(Gwidget_t * widget,Gpoint_t * gpp,int * count)1178 int GCgetmousecoords (Gwidget_t *widget, Gpoint_t *gpp, int *count) {
1179 PIXpoint_t pp;
1180 POINT p;
1181 int n1, n2, n3;
1182
1183 GetCursorPos (&p);
1184 ScreenToClient (widget->w, &p);
1185 pp.x = p.x, pp.y = p.y;
1186 *gpp = ppixtodraw (widget, pp);
1187 n1 = GetAsyncKeyState (VK_LBUTTON);
1188 n2 = GetAsyncKeyState (VK_MBUTTON);
1189 n3 = GetAsyncKeyState (VK_RBUTTON);
1190 *count = (n1 < 0 ? 1 : 0) + (n2 < 0 ? 1 : 0) + (n3 < 0 ? 1 : 0);
1191 return 0;
1192 }
1193
setgattr(Gwidget_t * widget,Ggattr_t * ap)1194 static void setgattr (Gwidget_t *widget, Ggattr_t *ap) {
1195 HBRUSH brush, pbrush;
1196 HPEN pen, ppen;
1197 PALETTEENTRY *colorp;
1198 long color, mode, style, width, flag, pati;
1199 double intens;
1200
1201 if (!(ap->flags & G_GATTRCOLOR))
1202 ap->color = WCU->defgattr.color;
1203 if (!(ap->flags & G_GATTRWIDTH))
1204 ap->width = WCU->defgattr.width;
1205 if (!(ap->flags & G_GATTRMODE))
1206 ap->mode = WCU->defgattr.mode;
1207 if (!(ap->flags & G_GATTRFILL))
1208 ap->fill = WCU->defgattr.fill;
1209 if (!(ap->flags & G_GATTRSTYLE))
1210 ap->style = WCU->defgattr.style;
1211 flag = FALSE;
1212 mode = ap->mode;
1213 if (mode != WCU->gattr.mode) {
1214 WCU->gattr.mode = mode;
1215 SetROP2 (GC, (int) mode);
1216 }
1217 WCU->gattr.fill = ap->fill;
1218 color = ap->color;
1219 if (color >= G_MAXCOLORS || !(WCU->colors[color].inuse))
1220 color = 1;
1221 if (color != WCU->gattr.color)
1222 WCU->gattr.color = color, flag = TRUE;
1223 width = ap->width;
1224 if (width != WCU->gattr.width)
1225 WCU->gattr.width = width, flag = TRUE;
1226 style = ap->style;
1227 if (style != WCU->gattr.style)
1228 WCU->gattr.style = style, flag = TRUE;
1229
1230 if (!flag)
1231 return;
1232 WCU->gattr.color = color;
1233 if (Gdepth == 1) {
1234 colorp = &WCU->colors[color].color;
1235 intens = (
1236 0.3 * colorp->peBlue + 0.59 * colorp->peRed +
1237 0.11 * colorp->peGreen
1238 ) / 255.0;
1239 pati = (intens <= 0.0625) ? 16 : -16.0 * (log (intens) / 2.7725887222);
1240 brush = WCU->grays[pati];
1241 } else
1242 brush = CreateSolidBrush (PALETTEINDEX (WCU->gattr.color));
1243 pbrush = SelectObject (GC, brush);
1244 if (Gdepth != 1)
1245 DeleteObject (pbrush);
1246 pen = CreatePen (
1247 (int) gstyles[WCU->gattr.style], WCU->gattr.width,
1248 PALETTEINDEX (WCU->gattr.color)
1249 );
1250 ppen = SelectObject (GC, pen);
1251 DeleteObject (ppen);
1252 SetTextColor (GC, PALETTEINDEX (WCU->gattr.color));
1253 }
1254
rdrawtopix(Gwidget_t * widget,Grect_t gr)1255 static PIXrect_t rdrawtopix (Gwidget_t *widget, Grect_t gr) {
1256 PIXrect_t pr;
1257 double tvx, tvy, twx, twy;
1258
1259 tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1260 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1261 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1262 pr.o.x = tvx * (gr.o.x - WCU->wrect.o.x) / twx + 0.5;
1263 pr.o.y = tvy * (1.0 - (gr.c.y - WCU->wrect.o.y) / twy) + 0.5;
1264 pr.c.x = tvx * (gr.c.x - WCU->wrect.o.x) / twx + 0.5;
1265 pr.c.y = tvy * (1.0 - (gr.o.y - WCU->wrect.o.y) / twy) + 0.5;
1266 return pr;
1267 }
1268
pdrawtopix(Gwidget_t * widget,Gpoint_t gp)1269 static PIXpoint_t pdrawtopix (Gwidget_t *widget, Gpoint_t gp) {
1270 PIXpoint_t pp;
1271 double tvx, tvy, twx, twy;
1272
1273 tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1274 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1275 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1276 pp.x = tvx * (gp.x - WCU->wrect.o.x) / twx + 0.5;
1277 pp.y = tvy * (1.0 - (gp.y - WCU->wrect.o.y) / twy) + 0.5;
1278 return pp;
1279 }
1280
sdrawtopix(Gwidget_t * widget,Gsize_t gs)1281 static PIXsize_t sdrawtopix (Gwidget_t *widget, Gsize_t gs) {
1282 PIXsize_t ps;
1283 double tvx, tvy, twx, twy;
1284
1285 tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1286 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1287 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1288 ps.x = tvx * (gs.x - 1) / twx + 1.5;
1289 ps.y = tvy * (gs.y - 1) / twy + 1.5;
1290 return ps;
1291 }
1292
ppixtodraw(Gwidget_t * widget,PIXpoint_t pp)1293 Gpoint_t ppixtodraw (Gwidget_t *widget, PIXpoint_t pp) {
1294 Gpoint_t gp;
1295 double tvx, tvy, twx, twy;
1296
1297 tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1298 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1299 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1300 gp.x = (pp.x / tvx) * twx + WCU->wrect.o.x;
1301 gp.y = (1.0 - pp.y / tvy) * twy + WCU->wrect.o.y;
1302 return gp;
1303 }
1304
spixtodraw(Gwidget_t * widget,PIXsize_t ps)1305 static Gsize_t spixtodraw (Gwidget_t *widget, PIXsize_t ps) {
1306 Gsize_t gs;
1307 double tvx, tvy, twx, twy;
1308
1309 tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1310 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1311 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1312 gs.x = ((ps.x - 1) / tvx) * twx + 1;
1313 gs.y = ((ps.y - 1) / tvy) * twy + 1;
1314 return gs;
1315 }
1316
rpixtodraw(Gwidget_t * widget,PIXrect_t pr)1317 static Grect_t rpixtodraw (Gwidget_t *widget, PIXrect_t pr) {
1318 Grect_t gr;
1319 double tvx, tvy, twx, twy, n;
1320
1321 tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1322 twx = WCU->wrect.c.x - WCU->wrect.o.x;
1323 twy = WCU->wrect.c.y - WCU->wrect.o.y;
1324 gr.o.x = (pr.o.x / tvx) * twx + WCU->wrect.o.x;
1325 gr.o.y = (1.0 - pr.c.y / tvy) * twy + WCU->wrect.o.y;
1326 gr.c.x = (pr.c.x / tvx) * twx + WCU->wrect.o.x;
1327 gr.c.y = (1.0 - pr.o.y / tvy) * twy + WCU->wrect.o.y;
1328 if (gr.o.x > gr.c.x)
1329 n = gr.o.x, gr.o.x = gr.c.x, gr.c.x = n;
1330 if (gr.o.y > gr.c.y)
1331 n = gr.o.y, gr.o.y = gr.c.y, gr.c.y = n;
1332 return gr;
1333 }
1334
rdrawtobpix(Gbitmap_t * bitmap,Grect_t gr)1335 static PIXrect_t rdrawtobpix (Gbitmap_t *bitmap, Grect_t gr) {
1336 PIXrect_t pr;
1337 double tvy;
1338
1339 tvy = (int) ((bitmap->size.y - 1) * bitmap->scale.y);
1340 pr.o.x = gr.o.x + 0.5;
1341 pr.o.y = tvy - gr.c.y + 0.5;
1342 pr.c.x = gr.c.x + 0.5;
1343 pr.c.y = tvy - gr.o.y + 0.5;
1344 return pr;
1345 }
1346
pdrawtobpix(Gbitmap_t * bitmap,Gpoint_t gp)1347 static PIXpoint_t pdrawtobpix (Gbitmap_t *bitmap, Gpoint_t gp) {
1348 PIXpoint_t pp;
1349 double tvy;
1350
1351 tvy = (int) ((bitmap->size.y - 1) * bitmap->scale.y);
1352 pp.x = gp.x + 0.5;
1353 pp.y = tvy - gp.y + 0.5;
1354 return pp;
1355 }
1356
Gadjustclip(Gwidget_t * widget)1357 void Gadjustclip (Gwidget_t *widget) {
1358 Gwidget_t *parent;
1359 PIXrect_t pr;
1360 RECT r1, r2, r3;
1361
1362 parent = &Gwidgets[widget->pwi];
1363 GetWindowRect (widget->w, &r1);
1364 GetClientRect (parent->w, &r2);
1365 GetWindowRect (parent->w, &r3);
1366 pr.o.x = max (0, -(r1.left - r3.left));
1367 pr.o.y = max (0, -(r1.top - r3.top));
1368 pr.c.x = min (r1.right - r1.left, pr.o.x + r2.right - r2.left);
1369 pr.c.y = min (r1.bottom - r1.top, pr.o.y + r2.bottom - r2.top);
1370 pr.c.x = max (pr.o.x, pr.c.x);
1371 pr.c.y = max (pr.o.y, pr.c.y);
1372 WCU->clip = rpixtodraw (widget, pr);
1373 }
1374