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 WPU widget->u.p
22 #define WINDOW widget->u.p->window
23 #define GC widget->u.p->gc
24 
25 static long gstyles[5] = {
26     /* G_SOLID */       PS_SOLID,
27     /* G_DASHED */      PS_DASH,
28     /* G_DOTTED */      PS_DOT,
29     /* G_LONGDASHED */  PS_DASH,
30     /* G_SHORTDASHED */ PS_DASH,
31 };
32 
33 static char grays[][4] = {
34     { 0x00, 0x00, 0x00, 0x00 },
35     { 0x08, 0x00, 0x00, 0x00 },
36     { 0x08, 0x00, 0x02, 0x00 },
37     { 0x0A, 0x00, 0x02, 0x00 },
38     { 0x0A, 0x00, 0x0A, 0x00 },
39     { 0x0A, 0x04, 0x0A, 0x00 },
40     { 0x0A, 0x04, 0x0A, 0x01 },
41     { 0x0A, 0x05, 0x0A, 0x01 },
42     { 0x0A, 0x05, 0x0A, 0x05 },
43     { 0x0E, 0x05, 0x0A, 0x05 },
44     { 0x0E, 0x05, 0x0B, 0x05 },
45     { 0x0F, 0x05, 0x0B, 0x05 },
46     { 0x0F, 0x05, 0x0F, 0x05 },
47     { 0x0F, 0x0D, 0x0F, 0x05 },
48     { 0x0F, 0x0D, 0x0F, 0x07 },
49     { 0x0F, 0x0F, 0x0F, 0x07 },
50     { 0x0F, 0x0F, 0x0F, 0x0F }
51 };
52 
53 char *Gpscanvasname = "out.emf";
54 
55 static void bezier (PIXpoint_t, PIXpoint_t, PIXpoint_t, PIXpoint_t);
56 static HFONT findfont (char *, int);
57 static int scalebitmap (Gwidget_t *, Gbitmap_t *, Gsize_t, int, int);
58 static void setgattr (Gwidget_t *, Ggattr_t *);
59 
60 static PIXrect_t  rdrawtopix (Gwidget_t *, Grect_t);
61 static PIXpoint_t pdrawtopix (Gwidget_t *, Gpoint_t);
62 static PIXsize_t  sdrawtopix (Gwidget_t *, Gsize_t);
63 static PIXrect_t  rdrawtobpix (Gbitmap_t *, Grect_t);
64 static PIXpoint_t pdrawtobpix (Gbitmap_t *, Gpoint_t);
65 
GPcreatewidget(Gwidget_t * parent,Gwidget_t * widget,int attrn,Gwattr_t * attrp)66 int GPcreatewidget (
67     Gwidget_t *parent, Gwidget_t *widget, int attrn, Gwattr_t *attrp
68 ) {
69     PIXpoint_t po;
70     PIXsize_t ps;
71     PRINTDLG pd;
72     DOCINFO di;
73     DEVMODE *dmp;
74     /* the 2 here is to provide enough space for palPalEntry[0] and [1] */
75     LOGPALETTE pal[2];
76 
77     HBRUSH brush;
78     HPEN pen;
79     HBITMAP bmap;
80     char *s, *s1;
81     int color, lflag, ai, dpix, dpiy, i;
82 
83     s = Gpscanvasname;
84     lflag = FALSE;
85     po.x = po.y = 0;
86     ps.x = ps.y = MINPWSIZE;
87     for (ai = 0; ai < attrn; ai++) {
88         switch (attrp[ai].id) {
89         case G_ATTRORIGIN:
90             GETORIGIN (attrp[ai].u.p, po);
91             break;
92         case G_ATTRSIZE:
93             GETSIZE (attrp[ai].u.s, ps, MINPWSIZE);
94             break;
95         case G_ATTRNAME:
96             if (attrp[ai].u.t && attrp[ai].u.t[0])
97                 s = attrp[ai].u.t;
98             break;
99         case G_ATTRMODE:
100             if (strcmp ("landscape", attrp[ai].u.t) == 0)
101                 lflag = TRUE;
102             else if (strcmp ("portrait", attrp[ai].u.t) == 0)
103                 lflag = FALSE;
104             else {
105                 Gerr (POS, G_ERRBADATTRVALUE, attrp[ai].u.t);
106                 return -1;
107             }
108             break;
109         case G_ATTRCOLOR:
110             /* will do it after the widget is created */
111             break;
112         case G_ATTRVIEWPORT:
113             /* will do it after the widget is created */
114             break;
115         case G_ATTRWINDOW:
116             /* will do it after the widget is created */
117             break;
118         case G_ATTRWINDOWID:
119             Gerr (POS, G_ERRCANNOTSETATTR1, "windowid");
120             return -1;
121         case G_ATTRUSERDATA:
122             widget->udata = attrp[ai].u.u;
123             break;
124         default:
125             Gerr (POS, G_ERRBADATTRID, attrp[ai].id);
126             return -1;
127         }
128     }
129     s1 = s + strlen (s) - 3;
130     if (s1 > s && strncmp (s1, "emf", 3) == 0) {
131         WPU->mode = 1;
132         ps.x *= 8.235, ps.y *= 8.235;
133         if (!(GC = CreateEnhMetaFile (NULL, s, NULL, "LEFTY\\0GRAPH\\0\\0"))) {
134             Gerr (POS, G_ERRCANNOTCREATEWIDGET);
135             return -1;
136         }
137     } else { /* open the printer device */
138         WPU->mode = 2;
139         di.cbSize = sizeof (DOCINFO);
140         di.lpszDocName = NULL;
141         di.lpszOutput = NULL;
142         di.lpszDatatype = "LEFTY";
143         di.fwType = 0;
144         pd.lStructSize = sizeof (pd);
145         pd.hwndOwner = NULL;
146         pd.hDevMode = NULL;
147         pd.hDevNames = NULL;
148         pd.hDC = NULL;
149         pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
150         pd.nFromPage = 0;
151         pd.nToPage = 0;
152         pd.nMinPage = 0;
153         pd.nMaxPage = 0;
154         pd.nCopies = 1;
155         pd.hInstance = NULL;
156         pd.lCustData = NULL;
157         pd.lpfnPrintHook = NULL;
158         pd.lpfnSetupHook = NULL;
159         pd.lpPrintTemplateName = NULL;
160         pd.lpSetupTemplateName = NULL;
161         pd.hPrintTemplate = NULL;
162         pd.hSetupTemplate = NULL;
163         if (!PrintDlg (&pd)) {
164             Gerr (POS, G_ERRCANNOTCREATEWIDGET);
165             return -1;
166         }
167         if (lflag && pd.hDevMode) {
168             dmp = (DEVMODE *) GlobalLock (pd.hDevMode);
169             dmp->dmOrientation = DMORIENT_LANDSCAPE;
170             GlobalUnlock (pd.hDevMode);
171             pd.Flags = PD_RETURNDC;
172             if (!PrintDlg (&pd)) {
173                 Gerr (POS, G_ERRCANNOTCREATEWIDGET);
174                 return -1;
175             }
176         }
177         GC = pd.hDC;
178         dpix = GetDeviceCaps (GC, LOGPIXELSX);
179         if (dpix != 300)
180             ps.x = ps.x * (double) dpix / 300.0;
181         dpiy = GetDeviceCaps (GC, LOGPIXELSY);
182         if (dpiy != 300)
183             ps.y = ps.y * (double) dpiy / 300.0;
184         if (StartDoc (GC, &di) <= 0 || StartPage (GC) <= 0) {
185             Gerr (POS, G_ERRCANNOTCREATEWIDGET);
186             return -1;
187         }
188     }
189     WPU->wrect.o.x = 0.0, WPU->wrect.o.y = 0.0;
190     WPU->wrect.c.x = 1.0, WPU->wrect.c.y = 1.0;
191     WPU->vsize.x = ps.x, WPU->vsize.y = ps.y;
192     WPU->ncolor = 2;
193     pal[0].palVersion = 0x300; /* HA HA HA */
194     pal[0].palNumEntries = 2;
195     pal[0].palPalEntry[0].peRed = 255;
196     pal[0].palPalEntry[0].peGreen = 255;
197     pal[0].palPalEntry[0].peBlue = 255;
198     pal[0].palPalEntry[0].peFlags = 0;
199     pal[0].palPalEntry[1].peRed = 0;
200     pal[0].palPalEntry[1].peGreen = 0;
201     pal[0].palPalEntry[1].peBlue = 0;
202     pal[0].palPalEntry[1].peFlags = 0;
203     WPU->cmap = CreatePalette (&pal[0]);
204     WPU->colors[0].color = pal[0].palPalEntry[0];
205     for (i = 1; i < G_MAXCOLORS; i++)
206         WPU->colors[i].color = pal[0].palPalEntry[1];
207     SelectPalette (GC, WPU->cmap, FALSE);
208     RealizePalette (GC);
209     WPU->colors[0].inuse = TRUE;
210     WPU->colors[1].inuse = TRUE;
211     for (i = 2; i < G_MAXCOLORS; i++)
212         WPU->colors[i].inuse = FALSE;
213     WPU->gattr.color = 1;
214     brush = CreateSolidBrush (PALETTEINDEX (1));
215     SelectObject (GC, brush);
216     pen = CreatePen (PS_SOLID, 1, PALETTEINDEX (1));
217     SelectObject (GC, pen);
218     SetTextColor (GC, PALETTEINDEX (1));
219     SetBkMode (GC, TRANSPARENT);
220     WPU->gattr.width = 0;
221     WPU->gattr.mode = G_SRC;
222     WPU->gattr.fill = 0;
223     WPU->gattr.style = 0;
224     WPU->defgattr = WPU->gattr;
225     WPU->font = NULL;
226     if (Gdepth == 1) {
227         for (i = 0; i < 17; i++) {
228             if (!(bmap = CreateBitmap (4, 4, 1, 1, &grays[i][0])))
229                 continue;
230             WPU->grays[i] = CreatePatternBrush (bmap);
231         }
232     }
233     for (ai = 0; ai < attrn; ai++) {
234         switch (attrp[ai].id) {
235         case G_ATTRCOLOR:
236             color = attrp[ai].u.c.index;
237             if (color < 0 || color > G_MAXCOLORS) {
238                 Gerr (POS, G_ERRBADCOLORINDEX, color);
239                 return -1;
240             }
241             WPU->colors[color].color.peRed = attrp[ai].u.c.r;
242             WPU->colors[color].color.peGreen = attrp[ai].u.c.g;
243             WPU->colors[color].color.peBlue = attrp[ai].u.c.b;
244             WPU->colors[color].color.peFlags = 0;
245             if (color >= WPU->ncolor)
246                 ResizePalette (WPU->cmap, color + 1), WPU->ncolor = color + 1;
247             SetPaletteEntries (
248                 WPU->cmap, (int) color, 1, &WPU->colors[color].color
249             );
250             RealizePalette (GC);
251             WPU->colors[color].inuse = TRUE;
252             if (color == WPU->gattr.color)
253                 WPU->gattr.color = -1;
254             break;
255         case G_ATTRVIEWPORT:
256             if (attrp[ai].u.s.x == 0)
257                 attrp[ai].u.s.x = 1;
258             if (attrp[ai].u.s.y == 0)
259                 attrp[ai].u.s.y = 1;
260             WPU->vsize.x = attrp[ai].u.s.x + 0.5;
261             WPU->vsize.y = attrp[ai].u.s.y + 0.5;
262             SetWindowPos (
263                 widget->w, (HWND) NULL, 0, 0, WPU->vsize.x,
264                 WPU->vsize.y, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE
265             );
266             break;
267         case G_ATTRWINDOW:
268             if (attrp[ai].u.r.o.x == attrp[ai].u.r.c.x)
269                 attrp[ai].u.r.c.x = attrp[ai].u.r.o.x + 1;
270             if (attrp[ai].u.r.o.y == attrp[ai].u.r.c.y)
271                 attrp[ai].u.r.c.y = attrp[ai].u.r.o.y + 1;
272             WPU->wrect = attrp[ai].u.r;
273             break;
274         }
275     }
276     return 0;
277 }
278 
GPsetwidgetattr(Gwidget_t * widget,int attrn,Gwattr_t * attrp)279 int GPsetwidgetattr (Gwidget_t *widget, int attrn, Gwattr_t *attrp) {
280     PIXsize_t ps;
281     int color, ai;
282 
283     for (ai = 0; ai < attrn; ai++) {
284         switch (attrp[ai].id) {
285         case G_ATTRORIGIN:
286             break;
287         case G_ATTRSIZE:
288             break;
289         case G_ATTRNAME:
290             break;
291         case G_ATTRMODE:
292             break;
293         case G_ATTRCOLOR:
294             color = attrp[ai].u.c.index;
295             if (color < 0 || color > G_MAXCOLORS) {
296                 Gerr (POS, G_ERRBADCOLORINDEX, color);
297                 return -1;
298             }
299             WPU->colors[color].color.peRed = attrp[ai].u.c.r;
300             WPU->colors[color].color.peGreen = attrp[ai].u.c.g;
301             WPU->colors[color].color.peBlue = attrp[ai].u.c.b;
302             WPU->colors[color].color.peFlags = 0;
303             if (color >= WPU->ncolor)
304                 ResizePalette (WPU->cmap, color + 1), WPU->ncolor = color + 1;
305             SetPaletteEntries (
306                 WPU->cmap, (int) color, 1, &WPU->colors[color].color
307             );
308             RealizePalette (GC);
309             WPU->colors[color].inuse = TRUE;
310             if (color == WPU->gattr.color)
311                 WPU->gattr.color = -1;
312             break;
313         case G_ATTRVIEWPORT:
314             if (attrp[ai].u.s.x == 0)
315                 attrp[ai].u.s.x = 1;
316             if (attrp[ai].u.s.y == 0)
317                 attrp[ai].u.s.y = 1;
318             WPU->vsize.x = attrp[ai].u.s.x + 0.5;
319             WPU->vsize.y = attrp[ai].u.s.y + 0.5;
320             ps.x = WPU->vsize.x, ps.y = WPU->vsize.y;
321             break;
322         case G_ATTRWINDOW:
323             if (attrp[ai].u.r.o.x == attrp[ai].u.r.c.x)
324                 attrp[ai].u.r.c.x = attrp[ai].u.r.o.x + 1;
325             if (attrp[ai].u.r.o.y == attrp[ai].u.r.c.y)
326                 attrp[ai].u.r.c.y = attrp[ai].u.r.o.y + 1;
327             WPU->wrect = attrp[ai].u.r;
328             break;
329         case G_ATTRWINDOWID:
330             Gerr (POS, G_ERRCANNOTSETATTR2, "windowid");
331             return -1;
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 
GPgetwidgetattr(Gwidget_t * widget,int attrn,Gwattr_t * attrp)343 int GPgetwidgetattr (Gwidget_t *widget, int attrn, Gwattr_t *attrp) {
344     PALETTEENTRY *cp;
345     int color, ai;
346 
347     for (ai = 0; ai < attrn; ai++) {
348         switch (attrp[ai].id) {
349         case G_ATTRORIGIN:
350             break;
351         case G_ATTRSIZE:
352             break;
353         case G_ATTRNAME:
354             break;
355         case G_ATTRMODE:
356             break;
357         case G_ATTRCOLOR:
358             color = attrp[ai].u.c.index;
359             if (color < 0 || color > G_MAXCOLORS) {
360                 Gerr (POS, G_ERRBADCOLORINDEX, color);
361                 return -1;
362             }
363             if (WPU->colors[color].inuse) {
364                 cp = &WPU->colors[color].color;
365                 attrp[ai].u.c.r = cp->peRed;
366                 attrp[ai].u.c.g = cp->peGreen;
367                 attrp[ai].u.c.b = cp->peBlue;
368             } else {
369                 attrp[ai].u.c.r = -1;
370                 attrp[ai].u.c.g = -1;
371                 attrp[ai].u.c.b = -1;
372             }
373             break;
374         case G_ATTRVIEWPORT:
375             attrp[ai].u.s = WPU->vsize;
376             break;
377         case G_ATTRWINDOW:
378             attrp[ai].u.r = WPU->wrect;
379             break;
380         case G_ATTRWINDOWID:
381             Gerr (POS, G_ERRCANNOTGETATTR, "windowid");
382             break;
383         case G_ATTRUSERDATA:
384             widget->udata = attrp[ai].u.u;
385             break;
386         default:
387             Gerr (POS, G_ERRBADATTRID, attrp[ai].id);
388             return -1;
389         }
390     }
391     return 0;
392 }
393 
GPdestroywidget(Gwidget_t * widget)394 int GPdestroywidget (Gwidget_t *widget) {
395     HENHMETAFILE mfile;
396 
397     if (WPU->mode == 1) {
398         mfile = CloseEnhMetaFile (GC);
399         OpenClipboard (NULL);
400         EmptyClipboard ();
401         SetClipboardData (CF_ENHMETAFILE, mfile);
402         CloseClipboard ();
403         DeleteMetaFile (mfile);
404     } else {
405         EndPage (GC);
406         EndDoc (GC);
407     }
408     return 0;
409 }
410 
GPcanvasclear(Gwidget_t * widget)411 int GPcanvasclear (Gwidget_t *widget) {
412     HBRUSH brush, pbrush;
413 
414     /* FIXME: drain repaint messages */
415     brush = CreateSolidBrush (PALETTEINDEX (0));
416     pbrush = SelectObject (GC, brush);
417     Rectangle (GC, 0, 0, (int) WPU->vsize.x, (int) WPU->vsize.y);
418     SelectObject (GC, pbrush);
419     return 0;
420 }
421 
GPsetgfxattr(Gwidget_t * widget,Ggattr_t * ap)422 int GPsetgfxattr (Gwidget_t *widget, Ggattr_t *ap) {
423     setgattr (widget, ap);
424     WPU->defgattr = WPU->gattr;
425     return 0;
426 }
427 
GPgetgfxattr(Gwidget_t * widget,Ggattr_t * ap)428 int GPgetgfxattr (Gwidget_t *widget, Ggattr_t *ap) {
429     if ((ap->flags & G_GATTRCOLOR))
430         ap->color = WPU->gattr.color;
431     if ((ap->flags & G_GATTRWIDTH))
432         ap->width = WPU->gattr.width;
433     if ((ap->flags & G_GATTRMODE))
434         ap->mode = WPU->gattr.mode;
435     if ((ap->flags & G_GATTRFILL))
436         ap->fill = WPU->gattr.fill;
437     if ((ap->flags & G_GATTRSTYLE))
438         ap->style = WPU->gattr.style;
439     return 0;
440 }
441 
GParrow(Gwidget_t * widget,Gpoint_t gp1,Gpoint_t gp2,Ggattr_t * ap)442 int GParrow (Gwidget_t *widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t *ap) {
443     PIXpoint_t pp1, pp2, pa, pb, pd;
444     double tangent, l;
445 
446     pp1 = pdrawtopix (widget, gp1), pp2 = pdrawtopix (widget, gp2);
447     pd.x = pp1.x - pp2.x, pd.y = pp1.y - pp2.y;
448     if (pd.x == 0 && pd.y == 0)
449         return 0;
450     tangent = atan2 ((double) pd.y, (double) pd.x);
451     if ((l = sqrt ((double) (pd.x * pd.x + pd.y * pd.y))) > 30)
452         l = 30;
453     pa.x = l * cos (tangent + M_PI / 7) + pp2.x;
454     pa.y = l * sin (tangent + M_PI / 7) + pp2.y;
455     pb.x = l * cos (tangent - M_PI / 7) + pp2.x;
456     pb.y = l * sin (tangent - M_PI / 7) + pp2.y;
457     setgattr (widget, ap);
458     MoveToEx (GC, pp1.x, pp1.y, NULL), LineTo (GC, pp2.x, pp2.y);
459     MoveToEx (GC, pa.x, pa.y, NULL), LineTo (GC, pp2.x, pp2.y);
460     MoveToEx (GC, pb.x, pb.y, NULL), LineTo (GC, pp2.x, pp2.y);
461     return 0;
462 }
463 
GPline(Gwidget_t * widget,Gpoint_t gp1,Gpoint_t gp2,Ggattr_t * ap)464 int GPline (Gwidget_t *widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t *ap) {
465     PIXpoint_t pp1, pp2;
466 
467     pp1 = pdrawtopix (widget, gp1), pp2 = pdrawtopix (widget, gp2);
468     setgattr (widget, ap);
469     MoveToEx (GC, pp1.x, pp1.y, NULL);
470     LineTo (GC, pp2.x, pp2.y);
471     return 0;
472 }
473 
GPbox(Gwidget_t * widget,Grect_t gr,Ggattr_t * ap)474 int GPbox (Gwidget_t *widget, Grect_t gr, Ggattr_t *ap) {
475     PIXrect_t pr;
476     Grect_t gr2;
477 
478     if (gr.o.x <= gr.c.x)
479         gr2.o.x = gr.o.x, gr2.c.x = gr.c.x;
480     else
481         gr2.o.x = gr.c.x, gr2.c.x = gr.o.x;
482     if (gr.o.y <= gr.c.y)
483         gr2.o.y = gr.o.y, gr2.c.y = gr.c.y;
484     else
485         gr2.o.y = gr.c.y, gr2.c.y = gr.o.y;
486     pr = rdrawtopix (widget, gr);
487     setgattr (widget, ap);
488     if (WPU->gattr.fill)
489         Rectangle (GC, pr.o.x, pr.o.y, pr.c.x, pr.c.y);
490     else {
491         Gppp[0].x = pr.o.x, Gppp[0].y = pr.o.y;
492         Gppp[1].x = pr.c.x, Gppp[1].y = pr.o.y;
493         Gppp[2].x = pr.c.x, Gppp[2].y = pr.c.y;
494         Gppp[3].x = pr.o.x, Gppp[3].y = pr.c.y;
495         Gppp[4].x = pr.o.x, Gppp[4].y = pr.o.y;
496         Polyline (GC, Gppp, 5);
497     }
498     return 0;
499 }
500 
GPpolygon(Gwidget_t * widget,int gpn,Gpoint_t * gpp,Ggattr_t * ap)501 int GPpolygon (Gwidget_t *widget, int gpn, Gpoint_t *gpp, Ggattr_t *ap) {
502     int n, i;
503 
504     if (gpn == 0)
505         return 0;
506     if (gpn + 1 > Gppn) {
507         n = (((gpn + 1) + PPINCR - 1) / PPINCR) * PPINCR;
508         Gppp = Marraygrow (Gppp, (long) n * PPSIZE);
509         Gppn = n;
510     }
511     for (i = 0; i < gpn; i++)
512         Gppp[i] = pdrawtopix (widget, gpp[i]);
513     setgattr (widget, ap);
514     if (WPU->gattr.fill) {
515         if (Gppp[gpn - 1].x != Gppp[0].x || Gppp[gpn - 1].y != Gppp[0].y)
516             Gppp[gpn] = Gppp[0], gpn++;
517         Polygon (GC, Gppp, (int) gpn);
518     } else
519         Polyline (GC, Gppp, (int) gpn);
520     return 0;
521 }
522 
GPsplinegon(Gwidget_t * widget,int gpn,Gpoint_t * gpp,Ggattr_t * ap)523 int GPsplinegon (Gwidget_t *widget, int gpn, Gpoint_t *gpp, Ggattr_t *ap) {
524     PIXpoint_t p0, p1, p2, p3;
525     int n, i;
526 
527     if (gpn == 0)
528         return 0;
529     Gppi = 1;
530     if (Gppi >= Gppn) {
531         n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR;
532         Gppp = Marraygrow (Gppp, (long) n * PPSIZE);
533         Gppn = n;
534     }
535     Gppp[0] = p3 = pdrawtopix (widget, gpp[0]);
536     for (i = 1; i < gpn; i += 3) {
537         p0 = p3;
538         p1 = pdrawtopix (widget, gpp[i]);
539         p2 = pdrawtopix (widget, gpp[i + 1]);
540         p3 = pdrawtopix (widget, gpp[i + 2]);
541         bezier (p0, p1, p2, p3);
542     }
543     setgattr (widget, ap);
544     if (WPU->gattr.fill) {
545         if (Gppp[Gppi - 1].x != Gppp[0].x || Gppp[Gppi - 1].y != Gppp[0].y)
546             Gppp[Gppi] = Gppp[0], Gppi++;
547         Polygon (GC, Gppp, (int) Gppi);
548     } else
549         Polyline (GC, Gppp, (int) Gppi);
550     return 0;
551 }
552 
bezier(PIXpoint_t p0,PIXpoint_t p1,PIXpoint_t p2,PIXpoint_t p3)553 static void bezier (
554     PIXpoint_t p0, PIXpoint_t p1, PIXpoint_t p2, PIXpoint_t p3
555 ) {
556     Gpoint_t gp0, gp1, gp2;
557     Gsize_t s;
558     PIXpoint_t p;
559     double t;
560     int n, i, steps;
561 
562     if ((s.x = p3.x - p0.x) < 0)
563         s.x = - s.x;
564     if ((s.y = p3.y - p0.y) < 0)
565         s.y = - s.y;
566     if (s.x > s.y)
567         steps = s.x / 5 + 1;
568     else
569         steps = s.y / 5 + 1;
570     for (i = 0; i <= steps; i++) {
571         t = i / (double) steps;
572         gp0.x = p0.x + t * (p1.x - p0.x);
573         gp0.y = p0.y + t * (p1.y - p0.y);
574         gp1.x = p1.x + t * (p2.x - p1.x);
575         gp1.y = p1.y + t * (p2.y - p1.y);
576         gp2.x = p2.x + t * (p3.x - p2.x);
577         gp2.y = p2.y + t * (p3.y - p2.y);
578         gp0.x = gp0.x + t * (gp1.x - gp0.x);
579         gp0.y = gp0.y + t * (gp1.y - gp0.y);
580         gp1.x = gp1.x + t * (gp2.x - gp1.x);
581         gp1.y = gp1.y + t * (gp2.y - gp1.y);
582         p.x = gp0.x + t * (gp1.x - gp0.x) + 0.5;
583         p.y = gp0.y + t * (gp1.y - gp0.y) + 0.5;
584         if (Gppi >= Gppn) {
585             n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR;
586             Gppp = Marraygrow (Gppp, (long) n * PPSIZE);
587             Gppn = n;
588         }
589         Gppp[Gppi++] = p;
590     }
591 }
592 
GParc(Gwidget_t * widget,Gpoint_t gc,Gsize_t gs,double ang1,double ang2,Ggattr_t * ap)593 int GParc (
594     Gwidget_t *widget, Gpoint_t gc, Gsize_t gs,
595     double ang1, double ang2, Ggattr_t *ap
596 ) {
597     PIXpoint_t pc;
598     PIXsize_t ps;
599     double a1, a2;
600 
601     pc = pdrawtopix (widget, gc), ps = sdrawtopix (widget, gs);
602     setgattr (widget, ap);
603     a1 = ang1 * M_PI / 180, a2 = ang2 * M_PI / 180;
604     if (WPU->gattr.fill)
605         Chord (
606             GC, pc.x - ps.x, pc.y - ps.y, pc.x + ps.x, pc.y + ps.y,
607             (int) (cos (a1) * ps.x), (int) (sin (a1) * ps.x),
608             (int) (cos (a2) * ps.x), (int) (sin (a2) * ps.x)
609         );
610     else
611         Arc (
612             GC, pc.x - ps.x, pc.y - ps.y, pc.x + ps.x, pc.y + ps.y,
613             (int) (cos (a1) * ps.x), (int) (sin (a1) * ps.x),
614             (int) (cos (a2) * ps.x), (int) (sin (a2) * ps.x)
615         );
616     return 0;
617 }
618 
GPtext(Gwidget_t * widget,Gtextline_t * tlp,int n,Gpoint_t go,char * fn,double fs,char * justs,Ggattr_t * ap)619 int GPtext (
620     Gwidget_t *widget, Gtextline_t *tlp, int n, Gpoint_t go, char *fn,
621     double fs, char *justs, Ggattr_t *ap
622 ) {
623     Gsize_t gs;
624     PIXpoint_t po;
625     PIXsize_t ps;
626     PIXrect_t pr;
627     HFONT font;
628     SIZE size;
629     RECT r;
630     int x, y, w, h, i;
631 
632     po = pdrawtopix (widget, go);
633     gs.x = 0, gs.y = fs;
634     ps = sdrawtopix (widget, gs);
635     if (!(font = findfont (fn, ps.y))) {
636         Rectangle (GC, po.x, po.y, po.x + 1, po.y + 1);
637         return 0;
638     }
639     setgattr (widget, ap);
640     if (font != WPU->font) {
641         WPU->font = font;
642         SelectObject (GC, font);
643     }
644     for (w = h = 0, i = 0; i < n; i++) {
645         if (tlp[i].n)
646             GetTextExtentPoint32 (GC, tlp[i].p, (int) tlp[i].n, &size);
647         else
648             GetTextExtentPoint32 (GC, "M", (int) 1, &size);
649         tlp[i].w = size.cx, tlp[i].h = size.cy;
650         w = max (w, size.cx), h += size.cy;
651     }
652     switch (justs[0]) {
653     case 'l': po.x += w / 2; break;
654     case 'r': po.x -= w / 2; break;
655     }
656     switch (justs[1]) {
657     case 'd': po.y -= h; break;
658     case 'c': po.y -= h / 2; break;
659     }
660     pr.o.x = po.x - w / 2, pr.o.y = po.y;
661     pr.c.x = po.x + w / 2, pr.c.y = po.y + h;
662     for (i = 0; i < n; i++) {
663         switch (tlp[i].j) {
664         case 'l': x = po.x - w / 2; break;
665         case 'n': x = po.x - tlp[i].w / 2; break;
666         case 'r': x = po.x - (tlp[i].w - w / 2); break;
667         }
668         y = po.y + i * tlp[i].h;
669         r.left = x, r.top = y;
670         r.right = x + tlp[i].w, r.bottom = y + tlp[i].h;
671         DrawText (GC, tlp[i].p, (int) tlp[i].n, &r, DT_LEFT | DT_TOP);
672     }
673     return 0;
674 }
675 
findfont(char * name,int size)676 static HFONT findfont (char *name, int size) {
677     HFONT font;
678     int fi;
679 
680     if (name[0] == '\000')
681         return Gfontp[0].font;
682 
683     sprintf (&Gbufp[0], name, size);
684     for (fi = 0; fi < Gfontn; fi++)
685         if (strcmp (&Gbufp[0], Gfontp[fi].name) == 0 && Gfontp[fi].size == size)
686             return Gfontp[fi].font;
687     font = CreateFont (
688         (int) size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &Gbufp[0]
689     );
690     if (!font)
691         font = Gfontp[0].font;
692 
693     Gfontp = Marraygrow (Gfontp, (long) (Gfontn + 1) * FONTSIZE);
694     Gfontp[Gfontn].name = strdup (&Gbufp[0]);
695     Gfontp[Gfontn].size = size;
696     Gfontp[Gfontn].font = font;
697     Gfontn++;
698     return font;
699 }
700 
GPcreatebitmap(Gwidget_t * widget,Gbitmap_t * bitmap,Gsize_t s)701 int GPcreatebitmap (Gwidget_t *widget, Gbitmap_t *bitmap, Gsize_t s) {
702     if (!widget) {
703         Gerr (POS, G_ERRNOPARENTWIDGET);
704         return -1;
705     }
706     if (!bitmap) {
707         Gerr (POS, G_ERRNOBITMAP);
708         return -1;
709     }
710     if (!(bitmap->u.bmap.orig = CreateBitmap (
711         (int) s.x, (int) s.y, 1, Gdepth, NULL
712     ))) {
713         Gerr (POS, G_ERRCANNOTCREATEBITMAP);
714         return -1;
715     }
716     bitmap->u.bmap.scaled = 0;
717     bitmap->scale.x = bitmap->scale.y = 1;
718     bitmap->ctype = widget->type;
719     bitmap->canvas = widget - &Gwidgets[0];
720     bitmap->size = s;
721     return 0;
722 }
723 
GPdestroybitmap(Gbitmap_t * bitmap)724 int GPdestroybitmap (Gbitmap_t *bitmap) {
725     if (!bitmap) {
726         Gerr (POS, G_ERRNOBITMAP);
727         return -1;
728     }
729     DeleteObject (bitmap->u.bmap.orig);
730     return 0;
731 }
732 
GPreadbitmap(Gwidget_t * widget,Gbitmap_t * bitmap,FILE * fp)733 int GPreadbitmap (Gwidget_t *widget, Gbitmap_t *bitmap, FILE *fp) {
734     Gsize_t s;
735     HDC gc;
736     char bufp[2048];
737     unsigned int rgb[3];
738     char *s1, *s2;
739     char c;
740     int bufn, bufi, step, x, y, k;
741 
742     if (!widget) {
743         Gerr (POS, G_ERRNOPARENTWIDGET);
744         return -1;
745     }
746     if (!bitmap) {
747         Gerr (POS, G_ERRNOBITMAP);
748         return -1;
749     }
750     step = 0;
751     while (step < 3) {
752 l1:
753         if (!fgets (bufp, 2048, fp)) {
754             Gerr (POS, G_ERRCANNOTREADBITMAP);
755             return -1;
756         }
757         s1 = &bufp[0];
758 l2:
759         for (; *s1 && isspace (*s1); s1++)
760             ;
761         if (!*s1 || *s1 == '#')
762             goto l1;
763         switch (step) {
764         case 0:
765             if (strncmp (s1, "P6", 2) != 0) {
766                 Gerr (POS, G_ERRCANNOTREADBITMAP);
767                 return -1;
768             }
769             step++, s1 += 2;
770             goto l2;
771         case 1:
772             for (s2 = s1; *s2 && *s2 >= '0' && *s2 <= '9'; s2++)
773                 ;
774             c = *s2, *s2 = 0;
775             if (s2 == s1 || (s.x = atoi (s1)) <= 0) {
776                 *s2 = c, Gerr (POS, G_ERRCANNOTREADBITMAP);
777                 return -1;
778             }
779             *s2 = c, step++, s1 = s2;
780             goto l2;
781         case 2:
782             for (s2 = s1; *s2 && *s2 >= '0' && *s2 <= '9'; s2++)
783                 ;
784             c = *s2, *s2 = 0;
785             if (s2 == s1 || (s.y = atoi (s1)) <= 0) {
786                 *s2 = c, Gerr (POS, G_ERRCANNOTREADBITMAP);
787                 return -1;
788             }
789             *s2 = c, step++, s1 = s2;
790             goto l2;
791         }
792     }
793     if (!(bitmap->u.bmap.orig = CreateBitmap (
794         (int) s.x, (int) s.y, 1, Gdepth, NULL
795     ))) {
796         Gerr (POS, G_ERRCANNOTCREATEBITMAP);
797         return -1;
798     }
799     gc = CreateCompatibleDC (GC);
800     SelectObject (gc, bitmap->u.bmap.orig);
801     bitmap->u.bmap.scaled = 0;
802     bitmap->scale.x = bitmap->scale.y = 1;
803     bitmap->ctype = widget->type;
804     bitmap->canvas = widget - &Gwidgets[0];
805     bitmap->size = s;
806     bufi = bufn = 0;
807     bufp[bufi] = 0;
808     for (y = 0; y < s.y; y++) {
809         for (x = 0; x < s.x; x++) {
810             for (k = 0; k < 3; k++) {
811                 if (bufi == bufn) {
812                     if ((bufn = fread (bufp, 1, 2047, fp)) == 0) {
813                         if (ferror (fp))
814                             bufn = -1;
815                         DeleteDC (gc);
816                         DeleteObject (bitmap->u.bmap.orig);
817                         Gerr (POS, G_ERRCANNOTCREATEBITMAP);
818                         return -1;
819                     }
820                     bufi = 0;
821                 }
822                 rgb[k] = (unsigned char) bufp[bufi++];
823             }
824             SetPixel (gc, x, y, RGB (rgb[0], rgb[1], rgb[2]));
825         }
826     }
827     DeleteDC (gc);
828     return 0;
829 }
830 
GPwritebitmap(Gbitmap_t * bitmap,FILE * fp)831 int GPwritebitmap (Gbitmap_t *bitmap, FILE *fp) {
832     Gwidget_t *widget;
833     HDC gc;
834     COLORREF color;
835     char bufp[2048];
836     int bufi, x, y, w, h;
837 
838     if (!bitmap) {
839         Gerr (POS, G_ERRNOBITMAP);
840         return -1;
841     }
842     if (
843         bitmap->canvas < 0 || bitmap->canvas >= Gwidgetn ||
844         !Gwidgets[bitmap->canvas].inuse
845     ) {
846         Gerr (POS, G_ERRBADWIDGETID, bitmap->canvas);
847         return -1;
848     }
849     widget = &Gwidgets[bitmap->canvas];
850     if (widget->type != G_CANVASWIDGET && widget->type != G_PCANVASWIDGET) {
851         Gerr (POS, G_ERRNOTACANVAS, bitmap->canvas);
852         return -1;
853     }
854     gc = CreateCompatibleDC (GC);
855     SelectObject (gc, bitmap->u.bmap.orig);
856     fprintf (fp, "P6\n%d %d 255\n", (int) bitmap->size.x, (int) bitmap->size.y);
857     bufi = 0;
858     w = bitmap->size.x;
859     h = bitmap->size.y;
860     for (y = 0; y < h; y++) {
861         for (x = 0; x < w; x++) {
862             color = GetPixel (gc, x, y);
863             bufp[bufi++] = GetRValue (color);
864             bufp[bufi++] = GetGValue (color);
865             bufp[bufi++] = GetBValue (color);
866             if (bufi + 3 >= 2048) {
867                 fwrite (bufp, 1, bufi, fp);
868                 bufi = 0;
869             }
870         }
871     }
872     if (bufi > 0)
873         fwrite (bufp, 1, bufi, fp);
874     DeleteDC (gc);
875     return 0;
876 }
877 
GPbitblt(Gwidget_t * widget,Gpoint_t gp,Grect_t gr,Gbitmap_t * bitmap,char * mode,Ggattr_t * ap)878 int GPbitblt (
879     Gwidget_t *widget, Gpoint_t gp, Grect_t gr, Gbitmap_t *bitmap,
880     char *mode, Ggattr_t *ap
881 ) {
882     PIXrect_t pr, r;
883     PIXpoint_t pp;
884     PIXsize_t s;
885     Gsize_t scale;
886     Gxy_t p;
887     HBITMAP pix;
888     HDC gc;
889     double tvx, tvy, twx, twy;
890 
891     if (gr.o.x > gr.c.x)
892         p.x = gr.o.x, gr.o.x = gr.c.x, gr.c.x = p.x;
893     if (gr.o.y > gr.c.y)
894         p.y = gr.o.y, gr.o.y = gr.c.y, gr.c.y = p.y;
895     if (strcmp (mode, "b2c") == 0) {
896         tvx = WPU->vsize.x, tvy = WPU->vsize.y;
897         twx = WPU->wrect.c.x - WPU->wrect.o.x;
898         twy = WPU->wrect.c.y - WPU->wrect.o.y;
899         scale.x = tvx / twx, scale.y = tvy / twy;
900         if (scale.x == 1 && scale.y == 1) {
901             pix = bitmap->u.bmap.orig;
902             bitmap->scale = scale;
903         } else {
904             if (scale.x != bitmap->scale.x || scale.y != bitmap->scale.y)
905                 scalebitmap (widget, bitmap, scale, TRUE, 1);
906             pix = bitmap->u.bmap.scaled;
907         }
908         pr = rdrawtopix (widget, gr);
909         pp = pdrawtobpix (bitmap, gp);
910         s.x = pr.c.x - pr.o.x + 1, s.y = pr.c.y - pr.o.y + 1;
911         r.o.x = pp.x, r.o.y = pp.y - s.y + 1;
912         r.c.x = r.o.x + s.x - 1, r.c.y = r.o.y + s.y - 1;
913         if (r.o.x < 0)
914             pr.o.x -= r.o.x, r.o.x = 0;
915         if (r.o.y < 0)
916             pr.o.y -= r.o.y, r.o.y = 0;
917         if (r.c.x >= bitmap->size.x * scale.x) {
918             pr.c.x -= (r.c.x + 1 - bitmap->size.x * scale.x);
919             r.c.x = bitmap->size.x * scale.x - 1;
920         }
921         if (r.c.y >= bitmap->size.y * scale.y) {
922             pr.c.y -= (r.c.y + 1 - bitmap->size.y * scale.y);
923             r.c.y = bitmap->size.y * scale.y - 1;
924         }
925         if (pr.o.x < 0)
926             r.o.x -= pr.o.x, pr.o.x = 0;
927         if (pr.o.y < 0)
928             r.o.y -= pr.o.y, pr.o.y = 0;
929         setgattr (widget, ap);
930         gc = CreateCompatibleDC (GC);
931         SelectObject (gc, pix);
932         BitBlt (
933             GC, pr.o.x, pr.o.y, r.c.x - r.o.x + 1, r.c.y - r.o.y + 1,
934             gc, r.o.x, r.o.y, (WPU->gattr.mode == G_SRC) ? SRCCOPY : SRCINVERT
935         );
936         DeleteDC (gc);
937     } else if (strcmp (mode, "c2b") == 0) {
938         tvx = WPU->vsize.x, tvy = WPU->vsize.y;
939         twx = WPU->wrect.c.x - WPU->wrect.o.x;
940         twy = WPU->wrect.c.y - WPU->wrect.o.y;
941         scale.x = tvx / twx, scale.y = tvy / twy;
942         if (scale.x == 1 && scale.y == 1) {
943             pix = bitmap->u.bmap.orig;
944             bitmap->scale = scale;
945         } else {
946             if (scale.x != bitmap->scale.x || scale.y != bitmap->scale.y)
947                 scalebitmap (widget, bitmap, scale, FALSE, 1);
948             pix = bitmap->u.bmap.scaled;
949         }
950         pr = rdrawtobpix (bitmap, gr);
951         pp = pdrawtopix (widget, gp);
952         s.x = pr.c.x - pr.o.x + 1, s.y = pr.c.y - pr.o.y + 1;
953         r.o.x = pp.x, r.o.y = pp.y - s.y + 1;
954         r.c.x = r.o.x + s.x - 1, r.c.y = r.o.y + s.y - 1;
955         if (pr.o.x < 0)
956             r.o.x -= pr.o.x, pr.o.x = 0;
957         if (pr.o.y < 0)
958             r.o.y -= pr.o.y, pr.o.y = 0;
959         if (pr.c.x >= bitmap->size.x * scale.x) {
960             r.c.x -= (pr.c.x + 1 - bitmap->size.x * scale.x);
961             pr.c.x = bitmap->size.x * scale.x - 1;
962         }
963         if (pr.c.y >= bitmap->size.y * scale.y) {
964             r.c.y -= (pr.c.y + 1 - bitmap->size.y * scale.y);
965             pr.c.y = bitmap->size.y * scale.y - 1;
966         }
967         if (r.o.x < 0)
968             pr.o.x -= r.o.x, r.o.x = 0;
969         if (r.o.y < 0)
970             pr.o.y -= r.o.y, r.o.y = 0;
971         setgattr (widget, ap);
972         gc = CreateCompatibleDC (GC);
973         SelectObject (gc, pix);
974         BitBlt (
975             gc, pr.o.x, pr.o.y, r.c.x - r.o.x + 1, r.c.y - r.o.y + 1,
976             GC, r.o.x, r.o.y, (WPU->gattr.mode == G_SRC) ? SRCCOPY : SRCINVERT
977         );
978         if (pix != bitmap->u.bmap.orig)
979             scalebitmap (widget, bitmap, scale, TRUE, -1);
980         DeleteDC (gc);
981     }
982     return 0;
983 }
984 
scalebitmap(Gwidget_t * widget,Gbitmap_t * bitmap,Gsize_t scale,int copybits,int dir)985 static int scalebitmap (
986     Gwidget_t *widget, Gbitmap_t *bitmap, Gsize_t scale,
987     int copybits, int dir
988 ) {
989     Gsize_t nsize, o2n;
990     HBITMAP opix, spix;
991     COLORREF color;
992     HDC gc1, gc2;
993     int x, y, x2, y2, xp, yp;
994     double prod, rgb[3], xr2, yr2, xl2, yl2, xf2, yf2, xr, yr, xl, yl;
995 
996     if (!copybits) {
997         if (dir == 1) {
998             nsize.x = (int) (bitmap->size.x * scale.x);
999             nsize.y = (int) (bitmap->size.y * scale.y);
1000             if (!(spix = CreateBitmap (
1001                 (int) nsize.x, (int) nsize.y, 1, Gdepth, NULL
1002             ))) {
1003                 Gerr (POS, G_ERRCANNOTCREATEBITMAP);
1004                 return -1;
1005             }
1006             if (bitmap->u.bmap.scaled)
1007                 DeleteObject (bitmap->u.bmap.scaled);
1008             bitmap->u.bmap.scaled = spix;
1009             bitmap->scale = scale;
1010         }
1011         return 0;
1012     }
1013     if (dir == 1) {
1014         nsize.x = (int) (bitmap->size.x * scale.x);
1015         nsize.y = (int) (bitmap->size.y * scale.y);
1016         o2n.x = 1 / scale.x, o2n.y = 1 / scale.y;
1017         if (!(spix = CreateBitmap (
1018             (int) nsize.x, (int) nsize.y, 1, Gdepth, NULL
1019         ))) {
1020             Gerr (POS, G_ERRCANNOTCREATEBITMAP);
1021             return -1;
1022         }
1023         opix = bitmap->u.bmap.orig;
1024     } else {
1025         nsize.x = (int) bitmap->size.x;
1026         nsize.y = (int) bitmap->size.y;
1027         o2n.x = scale.x, o2n.y = scale.y;
1028         spix = bitmap->u.bmap.orig;
1029         opix = bitmap->u.bmap.scaled;
1030     }
1031     gc1 = CreateCompatibleDC (GC);
1032     SelectObject (gc1, opix);
1033     gc2 = CreateCompatibleDC (GC);
1034     SelectObject (gc2, spix);
1035     prod = o2n.x * o2n.y;
1036     y = 0;
1037     yr = o2n.y;
1038     yl = 0;
1039     for (yp = 0; yp < nsize.y; yp++) {
1040         x = 0;
1041         xr = o2n.x;
1042         xl = 0;
1043         for (xp = 0; xp < nsize.x; xp++) {
1044             y2 = y;
1045             yr2 = yr;
1046             yl2 = yl;
1047             rgb[0] = rgb[1] = rgb[2] = 0;
1048             do {
1049                 x2 = x;
1050                 xr2 = xr;
1051                 xl2 = xl;
1052                 yf2 = (yl2 + yr2 > 1) ? 1 - yl2 : yr2, yr2 -= yf2;
1053                 do {
1054                     xf2 = (xl2 + xr2 > 1) ? 1 - xl2 : xr2, xr2 -= xf2;
1055                     color = GetPixel (gc1, x2, y2);
1056                     rgb[0] += (GetRValue (color) * xf2 * yf2 / prod);
1057                     rgb[1] += (GetGValue (color) * xf2 * yf2 / prod);
1058                     rgb[2] += (GetBValue (color) * xf2 * yf2 / prod);
1059                     xl2 += xf2;
1060                     if (xl2 >= 1)
1061                         x2++, xl2 -= 1;
1062                 } while (xr2 > 0);
1063                 xr2 = o2n.x;
1064                 yl2 += yf2;
1065                 if (yl2 >= 1)
1066                     y2++, yl2 -= 1;
1067             } while (yr2 > 0);
1068             yr2 = o2n.y;
1069             SetPixel (gc2, xp, yp, RGB (rgb[0], rgb[1], rgb[2]));
1070             x = x2;
1071             xr = xr2;
1072             xl = xl2;
1073         }
1074         y = y2;
1075         yr = yr2;
1076         yl = yl2;
1077     }
1078     DeleteDC (gc1);
1079     DeleteDC (gc2);
1080     if (dir == 1) {
1081         if (bitmap->u.bmap.scaled)
1082             DeleteObject (bitmap->u.bmap.scaled);
1083         bitmap->u.bmap.scaled = spix;
1084         bitmap->scale = scale;
1085     }
1086     return 0;
1087 }
1088 
setgattr(Gwidget_t * widget,Ggattr_t * ap)1089 static void setgattr (Gwidget_t *widget, Ggattr_t *ap) {
1090     HBRUSH brush, pbrush;
1091     HPEN pen, ppen;
1092     PALETTEENTRY *colorp;
1093     long color, mode, style, width, flag, pati;
1094     double intens;
1095 
1096     if (!(ap->flags & G_GATTRCOLOR))
1097         ap->color = WPU->defgattr.color;
1098     if (!(ap->flags & G_GATTRWIDTH))
1099         ap->width = WPU->defgattr.width;
1100     if (!(ap->flags & G_GATTRMODE))
1101         ap->mode = WPU->defgattr.mode;
1102     if (!(ap->flags & G_GATTRFILL))
1103         ap->fill = WPU->defgattr.fill;
1104     if (!(ap->flags & G_GATTRSTYLE))
1105         ap->style = WPU->defgattr.style;
1106     flag = FALSE;
1107     mode = ap->mode;
1108     if (mode != WPU->gattr.mode) {
1109         WPU->gattr.mode = mode;
1110         SetROP2 (GC, (int) mode);
1111     }
1112     WPU->gattr.fill = ap->fill;
1113     color = ap->color;
1114     if (color >= G_MAXCOLORS || !(WPU->colors[color].inuse))
1115         color = 1;
1116     if (color != WPU->gattr.color)
1117         WPU->gattr.color = color, flag = TRUE;
1118     width = ap->width;
1119     if (width != WPU->gattr.width)
1120         WPU->gattr.width = width, flag = TRUE;
1121     style = ap->style;
1122     if (style != WPU->gattr.style)
1123         WPU->gattr.style = style, flag = TRUE;
1124 
1125     if (!flag)
1126         return;
1127     WPU->gattr.color = color;
1128     if (Gdepth == 1) {
1129         colorp = &WPU->colors[color].color;
1130         intens = (
1131             0.3 * colorp->peBlue + 0.59 * colorp->peRed +
1132             0.11 * colorp->peGreen
1133         ) / 255.0;
1134         pati = (intens <= 0.0625) ? 16 : -16.0 * (log (intens) / 2.7725887222);
1135         brush = WPU->grays[pati];
1136     } else
1137         brush = CreateSolidBrush (PALETTEINDEX (WPU->gattr.color));
1138     pbrush = SelectObject (GC, brush);
1139     if (Gdepth != 1)
1140         DeleteObject (pbrush);
1141     pen = CreatePen (
1142         (int) gstyles[WPU->gattr.style], WPU->gattr.width,
1143         PALETTEINDEX (WPU->gattr.color)
1144     );
1145     ppen = SelectObject (GC, pen);
1146     DeleteObject (ppen);
1147     SetTextColor (GC, PALETTEINDEX (WPU->gattr.color));
1148 }
1149 
rdrawtopix(Gwidget_t * widget,Grect_t gr)1150 static PIXrect_t rdrawtopix (Gwidget_t *widget, Grect_t gr) {
1151     PIXrect_t pr;
1152     double tvx, tvy, twx, twy;
1153 
1154     tvx = WPU->vsize.x - 1, tvy = WPU->vsize.y - 1;
1155     twx = WPU->wrect.c.x - WPU->wrect.o.x;
1156     twy = WPU->wrect.c.y - WPU->wrect.o.y;
1157     pr.o.x = tvx * (gr.o.x - WPU->wrect.o.x) / twx + 0.5;
1158     pr.o.y = tvy * (1.0  - (gr.c.y - WPU->wrect.o.y) / twy) + 0.5;
1159     pr.c.x = tvx * (gr.c.x - WPU->wrect.o.x) / twx + 0.5;
1160     pr.c.y = tvy * (1.0  - (gr.o.y - WPU->wrect.o.y) / twy) + 0.5;
1161     return pr;
1162 }
1163 
pdrawtopix(Gwidget_t * widget,Gpoint_t gp)1164 static PIXpoint_t pdrawtopix (Gwidget_t *widget, Gpoint_t gp) {
1165     PIXpoint_t pp;
1166     double tvx, tvy, twx, twy;
1167 
1168     tvx = WPU->vsize.x - 1, tvy = WPU->vsize.y - 1;
1169     twx = WPU->wrect.c.x - WPU->wrect.o.x;
1170     twy = WPU->wrect.c.y - WPU->wrect.o.y;
1171     pp.x = tvx * (gp.x - WPU->wrect.o.x) / twx + 0.5;
1172     pp.y = tvy * (1.0  - (gp.y - WPU->wrect.o.y) / twy) + 0.5;
1173     return pp;
1174 }
1175 
sdrawtopix(Gwidget_t * widget,Gsize_t gs)1176 static PIXsize_t sdrawtopix (Gwidget_t *widget, Gsize_t gs) {
1177     PIXsize_t ps;
1178     double tvx, tvy, twx, twy;
1179 
1180     tvx = WPU->vsize.x - 1, tvy = WPU->vsize.y - 1;
1181     twx = WPU->wrect.c.x - WPU->wrect.o.x;
1182     twy = WPU->wrect.c.y - WPU->wrect.o.y;
1183     ps.x = tvx * (gs.x - 1) / twx + 1.5;
1184     ps.y = tvy * (gs.y - 1) / twy + 1.5;
1185     return ps;
1186 }
1187 
rdrawtobpix(Gbitmap_t * bitmap,Grect_t gr)1188 static PIXrect_t rdrawtobpix (Gbitmap_t *bitmap, Grect_t gr) {
1189     PIXrect_t pr;
1190     double tvy;
1191 
1192     tvy = (int) ((bitmap->size.y - 1) * bitmap->scale.y);
1193     pr.o.x = gr.o.x + 0.5;
1194     pr.o.y = tvy - gr.c.y + 0.5;
1195     pr.c.x = gr.c.x + 0.5;
1196     pr.c.y = tvy - gr.o.y + 0.5;
1197     return pr;
1198 }
1199 
pdrawtobpix(Gbitmap_t * bitmap,Gpoint_t gp)1200 static PIXpoint_t pdrawtobpix (Gbitmap_t *bitmap, Gpoint_t gp) {
1201     PIXpoint_t pp;
1202     double tvy;
1203 
1204     tvy = (int) ((bitmap->size.y - 1) * bitmap->scale.y);
1205     pp.x = gp.x + 0.5;
1206     pp.y = tvy - gp.y + 0.5;
1207     return pp;
1208 }
1209