]> granicus.if.org Git - graphviz/blob - cmd/lefty/ws/gtk/gcanvas.c
rephrase unnecessarily cryptic string comparisons in lefty
[graphviz] / cmd / lefty / ws / gtk / gcanvas.c
1 /*************************************************************************
2  * Copyright (c) 2011 AT&T Intellectual Property 
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors: Details at https://graphviz.org
9  *************************************************************************/
10
11
12 #include "common.h"
13 #include "g.h"
14 #include "gcommon.h"
15 #include <string.h>
16
17 #define WCU widget->u.c
18 #define WINDOW widget->u.c->window
19 #define GC widget->u.c->gc
20 #define ISVISIBLE(r) ( \
21         (r.o.x <= WCU->clip.c.x) && (r.c.x >= WCU->clip.o.x) && \
22         (r.o.y <= WCU->clip.c.y) && (r.c.y >= WCU->clip.o.y) \
23 )
24
25 #define IS8BIT(font) ((font)->min_byte1 == 0 && (font)->max_byte1 == 0)
26 #define max(a, b) (((a) >= (b)) ? (a) : (b))
27 #define min(a, b) (((a) <= (b)) ? (a) : (b))
28
29 #define SETFONT(font) { \
30         if(font != WCU->font) { \
31                 WCU->font = font; \
32                 gdk_gc_set_font(GC, font); \
33         } \
34 }
35
36 Gwidget_t *canvas;
37 static int curcursori = -1;
38
39 static gchar gstyles[][2] = {
40     /* G_SOLID */ {16},
41     /* G_DASHED */ {4, 4},
42     /* G_DOTTED */ {2, 2},
43     /* G_LONGDASHED */ {4, 12},
44     /* G_SHORTDASHED */ {12, 4}
45 };
46
47 static char grays[][4] = {
48     {0x00, 0x00, 0x00, 0x00,},
49     {0x08, 0x00, 0x00, 0x00,},
50     {0x08, 0x00, 0x02, 0x00,},
51     {0x0A, 0x00, 0x02, 0x00,},
52     {0x0A, 0x00, 0x0A, 0x00,},
53     {0x0A, 0x04, 0x0A, 0x00,},
54     {0x0A, 0x04, 0x0A, 0x01,},
55     {0x0A, 0x05, 0x0A, 0x01,},
56     {0x0A, 0x05, 0x0A, 0x05,},
57     {0x0E, 0x05, 0x0A, 0x05,},
58     {0x0E, 0x05, 0x0B, 0x05,},
59     {0x0F, 0x05, 0x0B, 0x05,},
60     {0x0F, 0x05, 0x0F, 0x05,},
61     {0x0F, 0x0D, 0x0F, 0x05,},
62     {0x0F, 0x0D, 0x0F, 0x07,},
63     {0x0F, 0x0F, 0x0F, 0x07,},
64     {0x0F, 0x0F, 0x0F, 0x0F,},
65 };
66
67 static void setgattr(Gwidget_t *, Ggattr_t *);
68
69 static PIXrect_t rdrawtopix(Gwidget_t *, Grect_t);
70 static PIXpoint_t pdrawtopix(Gwidget_t *, Gpoint_t);
71 static PIXsize_t sdrawtopix(Gwidget_t *, Gsize_t);
72 static Gpoint_t Gppixtodraw(Gwidget_t *, PIXpoint_t);
73 static Gsize_t spixtodraw(Gwidget_t *, PIXsize_t);
74 static Grect_t rpixtodraw(Gwidget_t *, PIXrect_t);
75 static PIXrect_t rdrawtobpix(Gbitmap_t *, Grect_t);
76 static PIXpoint_t pdrawtobpix(Gbitmap_t *, Gpoint_t);
77 static void adjustclip(Gwidget_t *);
78
79
80 int GCcreatewidget(Gwidget_t * parent, Gwidget_t * widget,
81                    int attrn, Gwattr_t * attrp)
82 {
83     PIXsize_t ps;
84     int width, height;
85     int ai, i;
86     GdkGCValues gcv;
87     int r, g, b, color;
88     GdkColor *cp;
89
90     if (!parent) {
91         Gerr(POS, G_ERRNOPARENTWIDGET);
92         return -1;
93     }
94
95     canvas = widget;
96     WCU->func = NULL;
97     WCU->needredraw = FALSE;
98     WCU->buttonsdown = 0;
99     WCU->bstate[0] = WCU->bstate[1] = WCU->bstate[2] = 0;
100     ps.x = ps.y = MINCWSIZE;
101
102     for (ai = 0; ai < attrn; ai++) {
103         switch (attrp[ai].id) {
104         case G_ATTRSIZE:
105             GETSIZE(attrp[ai].u.s, ps, MINCWSIZE);
106             break;
107         case G_ATTRBORDERWIDTH:
108             break;
109 #ifdef FEATURE_GMAP
110         case G_ATTRMODE:
111             if (strcmp("gmap", attrp[ai].u.t) == 0) {
112                 gmapmode = TRUE;
113             } else {
114                 Gerr(POS, G_ERRBADATTRVALUE, attrp[ai].u.t);
115                 return -1;
116             }
117             break;
118 #endif
119         case G_ATTRCURSOR:
120             break;
121         case G_ATTRCOLOR:
122             break;
123         case G_ATTRVIEWPORT:
124             break;
125         case G_ATTRWINDOW:
126             break;
127         case G_ATTRWINDOWID:
128             Gerr(POS, G_ERRCANNOTSETATTR2, "windowid");
129             return -1;
130         case G_ATTREVENTCB:
131             WCU->func = (Gcanvascb) attrp[ai].u.func;
132             break;
133         case G_ATTRUSERDATA:
134             widget->udata = attrp[ai].u.u;
135             break;
136         default:
137             Gerr(POS, G_ERRBADATTRID, attrp[ai].id);
138             return -1;
139         }
140     }
141 /*      XtSetValues (widget->w, argp, argn);    */
142
143     widget->w = gtk_drawing_area_new();
144     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(parent->w),
145                                           widget->w);
146     gtk_drawing_area_size(GTK_DRAWING_AREA(widget->w), ps.x, ps.y);
147
148     gtk_widget_add_events(widget->w, GDK_ALL_EVENTS_MASK);
149     gtk_signal_connect(GTK_OBJECT(widget->w), "key_release_event",
150                        GTK_SIGNAL_FUNC(Gcwkeyaction), NULL);
151     gtk_signal_connect(GTK_OBJECT(widget->w), "key_press_event",
152                        GTK_SIGNAL_FUNC(Gcwkeyaction), NULL);
153     gtk_signal_connect(G_OBJECT(widget->w), "button_press_event",
154                        GTK_SIGNAL_FUNC(Gcwbutaction), NULL);
155     gtk_signal_connect(G_OBJECT(widget->w), "button_release_event",
156                        GTK_SIGNAL_FUNC(Gcwbutaction), NULL);
157     gtk_signal_connect(G_OBJECT(widget->w), "visibility_notify_event",
158                        GTK_SIGNAL_FUNC(cweventhandler), NULL);
159     gtk_signal_connect(G_OBJECT(widget->w), "expose_event",
160                        GTK_SIGNAL_FUNC(exposeeventhandler), NULL);
161     gtk_signal_connect(G_OBJECT(widget->w), "motion_notify_event",
162                        GTK_SIGNAL_FUNC(cweventhandler), NULL);
163
164     gtk_widget_show(widget->w);
165     gtk_widget_show(parent->w);
166
167     GC = gdk_gc_new(widget->w->window);
168     WCU->cmap = gdk_colormap_get_system();
169     WCU->colors[0].color.pixel = WCU->colors[1].color.pixel = 1000000;
170     if (WCU->colors[0].color.pixel == 1000000) {
171         gdk_gc_get_values(GC, &gcv);
172         WCU->colors[0].color = gcv.background;
173     }
174     if (WCU->colors[1].color.pixel == 1000000) {
175         gdk_gc_get_values(GC, &gcv);
176         WCU->colors[1].color = gcv.foreground;
177     }
178
179     WCU->colors[0].color.red = 65535;
180     WCU->colors[0].color.green = 65535;
181     WCU->colors[0].color.blue = 65535;
182     WCU->colors[1].color.red = 0;
183     WCU->colors[1].color.green = 0;
184     WCU->colors[1].color.blue = 0;
185
186     gdk_colormap_alloc_color(WCU->cmap, &WCU->colors[0].color, FALSE,
187                              TRUE);
188     WCU->colors[0].inuse = TRUE;
189     gdk_colormap_alloc_color(WCU->cmap, &WCU->colors[1].color, FALSE,
190                              TRUE);
191     WCU->colors[1].inuse = TRUE;
192
193     WCU->allocedcolor[0] = WCU->allocedcolor[1] = FALSE;
194     for (i = 2; i < G_MAXCOLORS; i++)
195         WCU->colors[i].inuse = FALSE;
196
197     WCU->gattr.color = 1;
198 /*      gdk_gc_set_background(GC, widget->w->style->white_gc);
199         gdk_gc_set_foreground(GC, widget->w->style->black_gc);
200 */
201
202     WCU->gattr.width = 0;
203     WCU->gattr.mode = 0;
204     WCU->gattr.fill = 0;
205     WCU->gattr.style = 0;
206     WCU->defgattr = WCU->gattr;
207     WCU->font = NULL;
208     WCU->wrect.o.x = 0.0, WCU->wrect.o.y = 0.0;
209     WCU->wrect.c.x = 1.0, WCU->wrect.c.y = 1.0;
210     WCU->vsize.x = ps.x, WCU->vsize.y = ps.y;
211
212     for (ai = 0; ai < attrn; ai++) {
213         switch (attrp[ai].id) {
214         case G_ATTRCURSOR:
215             if (strcmp(attrp[ai].u.t, "default") == 0) {
216                 curcursori = -1;
217             }
218             break;
219         case G_ATTRCOLOR:
220             color = attrp[ai].u.c.index;
221             if (color < 0 || color > G_MAXCOLORS) {
222                 Gerr(POS, G_ERRBADCOLORINDEX, color);
223                 return -1;
224             }
225             r = attrp[ai].u.c.r * 257;
226             g = attrp[ai].u.c.g * 257;
227             b = attrp[ai].u.c.b * 257;
228             cp = &WCU->colors[color].color;
229             if (WCU->colors[color].inuse)
230                 if (cp->red != r || cp->green != g || cp->blue != b)
231                     if (color > 1 || WCU->allocedcolor[color])
232                         gdk_colormap_free_colors(WCU->cmap, cp, 1);
233
234             cp->red = r, cp->green = g, cp->blue = b;
235             if (gdk_colormap_alloc_color(WCU->cmap, cp, TRUE, TRUE)) {
236                 WCU->colors[color].inuse = TRUE;
237                 if (color <= 1)
238                     WCU->allocedcolor[color] = TRUE;
239             }
240             cp->red = r, cp->green = g, cp->blue = b;
241             if (color == WCU->gattr.color)
242                 WCU->gattr.color = -1;
243             break;
244         case G_ATTRVIEWPORT:
245             WCU->vsize.x = (int) (attrp[ai].u.s.x + 0.5);
246             WCU->vsize.y = (int) (attrp[ai].u.s.y + 0.5);
247             break;
248         case G_ATTRWINDOW:
249             WCU->wrect = attrp[ai].u.r;
250             break;
251         }
252     }
253     adjustclip(widget);
254     return 0;
255 }
256
257
258 int GCsetwidgetattr(Gwidget_t * widget, int attrn, Gwattr_t * attrp)
259 {
260     PIXsize_t ps;
261     int ai, r, g, b, color;
262     GdkColor *cp;
263
264     for (ai = 0; ai < attrn; ai++) {
265         switch (attrp[ai].id) {
266         case G_ATTRSIZE:
267             GETSIZE(attrp[ai].u.s, ps, MINCWSIZE);
268             gtk_drawing_area_size(GTK_DRAWING_AREA(widget->w), ps.x, ps.y);
269             break;
270         case G_ATTRBORDERWIDTH:
271             break;
272         case G_ATTRCURSOR:
273             if (strcmp(attrp[ai].u.t, "watch") == 0) {
274                 gdk_window_set_cursor(widget->w->window,
275                                       gdk_cursor_new(GDK_WATCH));
276             } else {
277                 gdk_window_set_cursor(widget->w->window,
278                                       gdk_cursor_new(GDK_LEFT_PTR));
279             }
280             Gsync();
281             break;
282         case G_ATTRCOLOR:
283             color = attrp[ai].u.c.index;
284             if (color < 0 || color > G_MAXCOLORS) {
285                 Gerr(POS, G_ERRBADCOLORINDEX, color);
286                 return -1;
287             }
288             r = attrp[ai].u.c.r * 257;
289             g = attrp[ai].u.c.g * 257;
290             b = attrp[ai].u.c.b * 257;
291             cp = &WCU->colors[color].color;
292             if (WCU->colors[color].inuse)
293                 if (cp->red != r || cp->green != g || cp->blue != b)
294                     if (color > 1 || WCU->allocedcolor[color])
295                         gdk_colormap_free_colors(WCU->cmap, cp, 1);
296
297             cp->red = r, cp->green = g, cp->blue = b;
298             if (gdk_colormap_alloc_color(WCU->cmap, cp, TRUE, TRUE)) {
299                 WCU->colors[color].inuse = TRUE;
300                 if (color <= 1)
301                     WCU->allocedcolor[color] = TRUE;
302             }
303             cp->red = r, cp->green = g, cp->blue = b;
304             if (color == WCU->gattr.color)
305                 WCU->gattr.color = -1;
306             break;
307         case G_ATTRVIEWPORT:
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             break;
311         case G_ATTRWINDOW:
312             WCU->wrect = attrp[ai].u.r;
313             adjustclip(widget);
314             break;
315         case G_ATTRWINDOWID:
316             Gerr(POS, G_ERRCANNOTSETATTR2, "windowid");
317             return -1;
318         case G_ATTREVENTCB:
319             WCU->func = (Gcanvascb) attrp[ai].u.func;
320             break;
321         case G_ATTRUSERDATA:
322             widget->udata = attrp[ai].u.u;
323             break;
324         default:
325             Gerr(POS, G_ERRBADATTRID, attrp[ai].id);
326             return -1;
327         }
328     }
329     return 0;
330 }
331
332
333 int GCgetwidgetattr(Gwidget_t * widget, int attrn, Gwattr_t * attrp)
334 {
335     GdkColor *cp;
336     int width, height;
337     int ai, color;
338
339     for (ai = 0; ai < attrn; ai++) {
340         switch (attrp[ai].id) {
341         case G_ATTRSIZE:
342             attrp[ai].u.s.x = width, attrp[ai].u.s.y = height;
343             break;
344         case G_ATTRBORDERWIDTH:
345             attrp[ai].u.i = width;
346             break;
347         case G_ATTRCURSOR:
348 /*                              attrp[ai].u.t = (curcursori == -1) ? "default" : cursormap[curcursori].name;
349 */
350             attrp[ai].u.t = (curcursori == -1) ? "default" : "watch";
351             break;
352         case G_ATTRCOLOR:
353             color = attrp[ai].u.c.index;
354             if (color < 0 || color > G_MAXCOLORS) {
355                 Gerr(POS, G_ERRBADCOLORINDEX, color);
356                 return -1;
357             }
358             if (WCU->colors[color].inuse) {
359                 cp = &WCU->colors[color].color;
360                 attrp[ai].u.c.r = cp->red / 257.0;
361                 attrp[ai].u.c.g = cp->green / 257.0;
362                 attrp[ai].u.c.b = cp->blue / 257.0;
363             } else {
364                 attrp[ai].u.c.r = -1;
365                 attrp[ai].u.c.g = -1;
366                 attrp[ai].u.c.b = -1;
367             }
368             break;
369         case G_ATTRVIEWPORT:
370             attrp[ai].u.s = WCU->vsize;
371             break;
372         case G_ATTRWINDOW:
373             attrp[ai].u.r = WCU->wrect;
374             break;
375         case G_ATTRWINDOWID:
376             sprintf(&Gbufp[0], "0x%lx", (unsigned long) widget->w);
377             break;
378         case G_ATTREVENTCB:
379             attrp[ai].u.func = WCU->func;
380             break;
381         case G_ATTRUSERDATA:
382             attrp[ai].u.u = widget->udata;
383             break;
384         default:
385             Gerr(POS, G_ERRBADATTRID, attrp[ai].id);
386             return -1;
387         }
388     }
389     return 0;
390 }
391
392
393 int GCdestroywidget(Gwidget_t * widget)
394 {
395     gtk_widget_destroy(widget->w);
396     return 0;
397 }
398
399
400 int GCsetgfxattr(Gwidget_t * widget, Ggattr_t * ap)
401 {
402     setgattr(widget, ap);
403     WCU->defgattr = WCU->gattr;
404     return 0;
405 }
406
407
408 int GCarrow(Gwidget_t * widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t * ap)
409 {
410
411     PIXpoint_t pp1, pp2, pa, pb, pd;
412     Grect_t gr;
413     double tangent, l;
414
415     if (gp1.x < gp2.x)
416         gr.o.x = gp1.x, gr.c.x = gp2.x;
417     else
418         gr.o.x = gp2.x, gr.c.x = gp1.x;
419     if (gp1.y < gp2.y)
420         gr.o.y = gp1.y, gr.c.y = gp2.y;
421     else
422         gr.o.y = gp2.y, gr.c.y = gp1.y;
423
424     pp1 = pdrawtopix(widget, gp1), pp2 = pdrawtopix(widget, gp2);
425     pd.x = pp1.x - pp2.x, pd.y = pp1.y - pp2.y;
426     if (pd.x == 0 && pd.y == 0)
427         return 0;
428     tangent = atan2((double) pd.y, (double) pd.x);
429     if ((l = sqrt((double) (pd.x * pd.x + pd.y * pd.y))) > 30)
430         l = 30;
431     pa.x = l * cos(tangent + M_PI / 7) + pp2.x;
432     pa.y = l * sin(tangent + M_PI / 7) + pp2.y;
433     pb.x = l * cos(tangent - M_PI / 7) + pp2.x;
434     pb.y = l * sin(tangent - M_PI / 7) + pp2.y;
435     setgattr(widget, ap);
436
437     gdk_draw_line(widget->w->window, GC, pp1.x, pp1.y, pp2.x, pp2.y);
438     gdk_draw_line(widget->w->window, GC, pa.x, pa.y, pp2.x, pp2.y);
439     gdk_draw_line(widget->w->window, GC, pb.x, pb.y, pp2.x, pp2.y);
440     return 0;
441 }
442
443
444 int GCline(Gwidget_t * widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t * ap)
445 {
446     PIXpoint_t pp1, pp2;
447     Grect_t gr;
448
449     if (gp1.x < gp2.x)
450         gr.o.x = gp1.x, gr.c.x = gp2.x;
451     else
452         gr.o.x = gp2.x, gr.c.x = gp1.x;
453     if (gp1.y < gp2.y)
454         gr.o.y = gp1.y, gr.c.y = gp2.y;
455     else
456         gr.o.y = gp2.y, gr.c.y = gp1.y;
457
458 /*      if(!ISVISIBLE(gr))
459                 return 1;
460 */
461
462     pp1 = pdrawtopix(widget, gp1), pp2 = pdrawtopix(widget, gp2);
463     setgattr(widget, ap);
464     gdk_draw_line(widget->w->window, GC, pp1.x, pp1.y, pp2.x, pp2.y);
465     return 0;
466 }
467
468
469 int GCbox(Gwidget_t * widget, Grect_t gr, Ggattr_t * ap)
470 {
471     PIXrect_t pr;
472     Gxy_t p;
473
474     if (gr.o.x > gr.c.x)
475         p.x = gr.o.x, gr.o.x = gr.c.x, gr.c.x = p.x;
476     if (gr.o.y > gr.c.y)
477         p.y = gr.o.y, gr.o.y = gr.c.y, gr.c.y = p.y;
478 /*      if(!ISVISIBLE(gr))
479                 return 1;
480 */
481
482     pr = rdrawtopix(widget, gr);
483     setgattr(widget, ap);
484     if (WCU->gattr.fill)
485         gdk_draw_rectangle(widget->w->window, GC, TRUE, pr.o.x, pr.o.y,
486                            pr.c.x - pr.o.x, pr.c.y - pr.o.y);
487     else {
488         gdk_draw_rectangle(widget->w->window, GC, FALSE, pr.o.x, pr.o.y,
489                            pr.c.x - pr.o.x, pr.c.y - pr.o.y);
490     }
491
492     return 0;
493 }
494
495
496 int GCpolygon(Gwidget_t * widget, int gpn, Gpoint_t * gpp, Ggattr_t * ap)
497 {
498
499     Grect_t gr;
500     int n, i;
501
502     if (gpn == 0)
503         return 0;
504
505     gr.o = gpp[0], gr.c = gpp[0];
506     for (i = 1; i < gpn; i++) {
507         gr.o.x = min(gr.o.x, gpp[i].x);
508         gr.o.y = min(gr.o.y, gpp[i].y);
509         gr.c.x = min(gr.c.x, gpp[i].x);
510         gr.c.y = min(gr.c.y, gpp[i].y);
511     }
512 /*      if(!ISVISIBLE(gr))
513                 return 1;
514 */
515     if (gpn + 1 > Gppn) {
516         n = (((gpn + 1) + PPINCR - 1) / PPINCR) * PPINCR;
517         Gppp = Marraygrow(Gppp, (long) n * PPSIZE);
518         Gppn = n;
519     }
520     for (i = 0; i < gpn; i++)
521         Gppp[i] = pdrawtopix(widget, gpp[i]);
522
523     setgattr(widget, ap);
524     if (WCU->gattr.fill) {
525         if (Gppp[gpn - 1].x != Gppp[0].x || Gppp[gpn - 1].y != Gppp[0].y)
526             Gppp[gpn] = Gppp[0], gpn++;
527
528         gdk_draw_polygon(widget->w, GC, TRUE, Gppp, gpn);
529     } else
530         gdk_draw_polygon(widget->w, GC, FALSE, Gppp, gpn);
531
532     return 0;
533 }
534
535
536 static void bezier(PIXpoint_t p0, PIXpoint_t p1, PIXpoint_t p2,
537                    PIXpoint_t p3)
538 {
539
540     Gpoint_t gp0, gp1, gp2;
541     Gsize_t s;
542     PIXpoint_t p;
543     double t;
544     int n, i, steps;
545
546     if ((s.x = p3.x - p0.x) < 0)
547         s.x = -s.x;
548     if ((s.y = p3.y - p0.y) < 0)
549         s.y = -s.y;
550     if (s.x > s.y)
551         steps = s.x / 5 + 1;
552     else
553         steps = s.y / 5 + 1;
554     for (i = 0; i <= steps; i++) {
555         t = i / (double) steps;
556         gp0.x = p0.x + t * (p1.x - p0.x);
557         gp0.y = p0.y + t * (p1.y - p0.y);
558         gp1.x = p1.x + t * (p2.x - p1.x);
559         gp1.y = p1.y + t * (p2.y - p1.y);
560         gp2.x = p2.x + t * (p3.x - p2.x);
561         gp2.y = p2.y + t * (p3.y - p2.y);
562         gp0.x = gp0.x + t * (gp1.x - gp0.x);
563         gp0.y = gp0.y + t * (gp1.y - gp0.y);
564         gp1.x = gp1.x + t * (gp2.x - gp1.x);
565         gp1.y = gp1.y + t * (gp2.y - gp1.y);
566         p.x = gp0.x + t * (gp1.x - gp0.x) + 0.5;
567         p.y = gp0.y + t * (gp1.y - gp0.y) + 0.5;
568         if (Gppi >= Gppn) {
569             n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR;
570             Gppp = Marraygrow(Gppp, (long) n * PPSIZE);
571             Gppn = n;
572         }
573         Gppp[Gppi++] = p;
574     }
575 }
576
577
578 int GCsplinegon(Gwidget_t * widget, int gpn, Gpoint_t * gpp, Ggattr_t * ap)
579 {
580
581     PIXpoint_t p0, p1, p2, p3;
582     Grect_t gr;
583     int n, i;
584
585     if (gpn == 0)
586         return 0;
587
588     gr.o = gpp[0], gr.c = gpp[0];
589     for (i = 1; i < gpn; i++) {
590         gr.o.x = min(gr.o.x, gpp[i].x);
591         gr.o.y = min(gr.o.y, gpp[i].y);
592         gr.c.x = max(gr.c.x, gpp[i].x);
593         gr.c.y = max(gr.c.y, gpp[i].y);
594     }
595
596     Gppi = 1;
597     if (Gppi >= Gppn) {
598         n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR;
599         Gppp = Marraygrow(Gppp, (long) n * PPSIZE);
600         Gppn = n;
601     }
602     Gppp[0] = p3 = pdrawtopix(widget, gpp[0]);
603     for (i = 1; i < gpn; i += 3) {
604         p0 = p3;
605         p1 = pdrawtopix(widget, gpp[i]);
606         p2 = pdrawtopix(widget, gpp[i + 1]);
607         p3 = pdrawtopix(widget, gpp[i + 2]);
608         bezier(p0, p1, p2, p3);
609     }
610     setgattr(widget, ap);
611     gdk_draw_lines(widget->w->window, GC, Gppp, Gppi);
612     return 0;
613 }
614
615
616 int GCarc(Gwidget_t * widget, Gpoint_t gc, Gsize_t gs, double ang1,
617           double ang2, Ggattr_t * ap)
618 {
619
620     PIXpoint_t pc;
621     PIXsize_t ps;
622     Grect_t gr;
623
624     gr.o.x = gc.x - gs.x, gr.o.y = gc.y - gs.y;
625     gr.c.x = gc.x + gs.x, gr.c.y = gc.y + gs.y;
626 /*      if(!ISVISIBLE(gr))
627                 return 1;
628 */
629
630     pc = pdrawtopix(widget, gc), ps = sdrawtopix(widget, gs);
631     setgattr(widget, ap);
632
633     if (WCU->gattr.fill) {
634         gdk_draw_arc(widget->w->window, GC, TRUE, pc.x - ps.x, pc.y - ps.y,
635                      ps.x * 2, ps.y * 2, (int) (ang1 * 64), (ang2 * 64));
636     } else {
637         gdk_draw_arc(widget->w->window, GC, FALSE, pc.x - ps.x,
638                      pc.y - ps.y, ps.x * 2, ps.y * 2, (int) (ang1 * 64),
639                      (ang2 * 64));
640     }
641     return 0;
642 }
643
644
645 static GdkFont *findfont(char *name, int size)
646 {
647     GdkFont *font;
648     int fi, n, i;
649
650     if (strcmp(name, "") == 0)
651         return Gfontp[0].font;
652
653     sprintf(&Gbufp[0], name, size);
654     for (fi = 0; fi < Gfontn; fi++)
655         if (strcmp(&Gbufp[0], Gfontp[fi].name) == 0)
656             return Gfontp[fi].font;
657
658     if (!(font = gdk_font_load(&Gbufp[0]))) {
659         n = strlen(&Gbufp[0]) + 1;
660         for (i = 1; i < size; i++) {
661             sprintf(&Gbufp[n], name, size - i);
662             if ((font = gdk_font_load(&Gbufp[n])))
663                 break;
664             sprintf(&Gbufp[n], name, size + i);
665             if ((font = gdk_font_load(&Gbufp[n])))
666                 break;
667         }
668     }
669     if (!font)
670         font = Gfontp[0].font;
671
672     Gfontp = Marraygrow(Gfontp, (long) (Gfontn + 1) * FONTSIZE);
673     Gfontp[Gfontn].name = strdup(&Gbufp[0]);
674     Gfontp[Gfontn].font = font;
675     Gfontn++;
676     return font;
677 }
678
679
680 int GCtext(Gwidget_t * widget, Gtextline_t * tlp, int n, Gpoint_t go,
681            char *fn, double fs, char *justs, Ggattr_t * ap)
682 {
683
684     Gsize_t gs;
685     PIXpoint_t po;
686     PIXsize_t ps;
687     PIXrect_t pr;
688     Grect_t gr;
689     GdkFont *font;
690     int dir, asc, des, x = 0, y, w, h, i;
691     int lbearing, rbearing, width;
692
693     po = pdrawtopix(widget, go);
694     gs.x = 0, gs.y = fs;
695     ps = sdrawtopix(widget, gs);
696     if (!(font = findfont(fn, ps.y))) {
697         printf("NO FONT\n");
698         gdk_draw_rectangle(widget->w, GC, FALSE, po.x, po.y, 1, 1);
699         return 0;
700     }
701
702     setgattr(widget, ap);
703     SETFONT(font);
704
705     for (w = h = 0, i = 0; i < n; i++) {
706         gdk_text_extents(font, tlp[i].p, tlp[i].n, &lbearing, &rbearing,
707                          &width, &asc, &des);
708
709         tlp[i].w = width, tlp[i].h = asc + des;
710         w = max(w, width), h += asc + des;
711
712     }
713
714     switch (justs[0]) {
715     case 'l':
716         po.x += w / 2;
717         break;
718     case 'r':
719         po.x -= w / 2;
720         break;
721     }
722     switch (justs[1]) {
723     case 'd':
724         po.y -= h;
725         break;
726     case 'c':
727         po.y -= h / 2;
728         break;
729     }
730     pr.o.x = po.x - w / 2, pr.o.y = po.y;
731     pr.c.x = po.x + w / 2, pr.c.y = po.y + h;
732     gr = rpixtodraw(widget, pr);
733
734 /*      if(!ISVISIBLE(gr))
735                 return 1;
736 */
737
738     for (i = 0; i < n; i++) {
739         switch (tlp[i].j) {
740         case 'l':
741             x = po.x - w / 2;
742             break;
743         case 'n':
744             x = po.x - tlp[i].w / 2;
745             break;
746         case 'r':
747             x = po.x - (tlp[i].w - w / 2);
748             break;
749         }
750         y = po.y + (i + 1) * tlp[i].h - des;
751
752         gdk_draw_text(widget->w->window, font, GC, x, y, tlp[i].p,
753                       tlp[i].n);
754     }
755
756     return 0;
757 }
758
759
760 int GCgettextsize(Gwidget_t * widget, Gtextline_t * tlp, int n, char *fn,
761                   double fs, Gsize_t * gsp)
762 {
763
764     Gsize_t gs;
765     PIXsize_t ps;
766     GdkFont *font;
767     int i, dir, asc, des, rbearing, lbearing, width;
768
769     gs.x = 0, gs.y = fs;
770     ps = sdrawtopix(widget, gs);
771     if (!(font = findfont(fn, ps.y))) {
772         gsp->x = 1, gsp->y = 1;
773         return 0;
774     }
775     SETFONT(font);
776     for (ps.x = ps.y = 0, i = 0; i < n; i++) {
777         gdk_text_extents(font, tlp[i].p, tlp[i].n, &lbearing, &rbearing,
778                          &width, &asc, &des);
779         ps.x = max(ps.x, width), ps.y += asc + des;
780     }
781
782     *gsp = spixtodraw(widget, ps);
783     return 0;
784 }
785
786
787 int GCcreatebitmap(Gwidget_t * widget, Gbitmap_t * bitmap, Gsize_t s)
788 {
789
790     return 0;
791 }
792
793
794 int GCdestroybitmap(Gbitmap_t * bitmap)
795 {
796
797     return 0;
798 }
799
800
801 int GCreadbitmap(Gwidget_t * widget, Gbitmap_t * bitmap, FILE * fp)
802 {
803
804     return 0;
805 }
806
807
808 int GCwritebitmap(Gbitmap_t * bitmap, FILE * fp)
809 {
810
811     return 0;
812 }
813
814
815 int GCbitblt(Gwidget_t * widget, Gpoint_t gp, Grect_t gr,
816              Gbitmap_t * bitmap, char *mode, Ggattr_t * ap)
817 {
818 }
819
820
821 int GCgetmousecoords(Gwidget_t * widget, Gpoint_t * gpp, int *count)
822 {
823     PIXpoint_t pp;
824     int state;
825
826     gdk_window_get_pointer(widget->w->window, &pp.x, &pp.y, &state);
827     *gpp = Gppixtodraw(widget, pp);
828     *count = 1;
829
830     return 0;
831 }
832
833
834 int GCcanvasclear(Gwidget_t * widget)
835 {
836     int gotit;
837     GdkDrawable *drawable;
838     GtkWidget *drawing_area = widget->w;
839     drawable = drawing_area->window;
840
841     gdk_window_clear(widget->w->window);
842     gdk_draw_rectangle(drawable, drawing_area->style->white_gc, TRUE, 0, 0,
843                        drawing_area->allocation.width,
844                        drawing_area->allocation.height);
845     WCU->needredraw = FALSE;
846     gotit = FALSE;
847
848
849     if (gotit)
850         adjustclip(widget);
851     return 0;
852 }
853
854
855 int GCgetgfxattr(Gwidget_t * widget, Ggattr_t * ap)
856 {
857
858     if ((ap->flags & G_GATTRCOLOR))
859         ap->color = WCU->gattr.color;
860     if ((ap->flags & G_GATTRWIDTH))
861         ap->width = WCU->gattr.width;
862     if ((ap->flags & G_GATTRMODE))
863         ap->mode = WCU->gattr.mode;
864     if ((ap->flags & G_GATTRFILL))
865         ap->fill = WCU->gattr.fill;
866     if ((ap->flags & G_GATTRSTYLE))
867         ap->style = WCU->gattr.style;
868     return 0;
869 }
870
871
872 gint Gcwbutaction(GtkWidget * w, GdkEvent * event, gpointer data)
873 {
874     Gwidget_t *widget;
875     Gevent_t gev;
876     int xtype, bn, wi;
877     PIXpoint_t pp;
878
879     widget = findwidget((unsigned long) w, G_CANVASWIDGET);
880     switch ((xtype = event->type)) {
881     case GDK_BUTTON_PRESS:
882     case GDK_2BUTTON_PRESS:
883     case GDK_3BUTTON_PRESS:
884     case GDK_BUTTON_RELEASE:
885
886         gev.type = G_MOUSE;
887         gev.code = (xtype == GDK_BUTTON_PRESS) ? G_DOWN : G_UP;
888
889         gev.data = event->button.button - 1;
890         pp.x = event->button.x, pp.y = event->button.y;
891         gev.p = Gppixtodraw(widget, pp);
892         bn = WCU->bstate[gev.data];
893         WCU->bstate[gev.data] = (xtype == GDK_BUTTON_PRESS) ? 1 : 0;
894         bn = WCU->bstate[gev.data] - bn;
895         WCU->buttonsdown += bn;
896         Gbuttonsdown += bn;
897         break;
898     default:
899         break;
900     }
901
902     wi = gev.wi = widget - &Gwidgets[0];
903     Gpopdownflag = FALSE;
904     if (WCU->func) {
905         (*WCU->func) (&gev);
906     }
907
908     if (Gpopdownflag) {
909         Gpopdownflag = FALSE;
910         if (gev.code == G_DOWN) {
911
912             gev.code = G_UP;
913             widget = &Gwidgets[wi];
914             WCU->bstate[gev.data] = 0;
915             WCU->buttonsdown--;
916             Gbuttonsdown--;
917             if (widget->inuse && WCU->func)
918                 (*WCU->func) (&gev);
919         }
920     }
921     return TRUE;
922 }
923
924
925 void Gcwkeyaction(GtkWidget * w, GdkEventKey * event, gpointer data)
926 {
927     Gwidget_t *widget;
928     Gevent_t gev;
929     int xtype, bn, wi, state;
930     PIXpoint_t pp;
931     unsigned int mask;
932     char c;
933
934     widget = findwidget((unsigned long) canvas->w, G_CANVASWIDGET);
935     switch ((xtype = event->type)) {
936     case GDK_KEY_PRESS:
937     case GDK_KEY_RELEASE:
938         gdk_window_get_pointer(event->window, &pp.x, &pp.y, &state);
939         gev.type = G_KEYBD;
940         gev.code = (xtype == GDK_KEY_PRESS) ? G_DOWN : G_UP;
941         gev.data = event->keyval;
942         gev.p = Gppixtodraw(widget, pp);
943         break;
944     default:
945         return;
946     }
947     gev.wi = widget - &Gwidgets[0];
948     Gpopdownflag = FALSE;
949     if (WCU->func)
950         (*WCU->func) (&gev);
951     if (Gpopdownflag)
952         Gpopdownflag = FALSE;
953
954 }
955
956
957 gint exposeeventhandler(GtkWidget * w, GdkEvent * event, gpointer data)
958 {
959     Gwidget_t *widget;
960
961     widget = findwidget((unsigned long) w, G_CANVASWIDGET);
962     gdk_draw_rectangle(widget->w->window, widget->w->style->white_gc, TRUE,
963                        0, 0, widget->w->allocation.width,
964                        widget->w->allocation.height);
965 }
966
967
968 gint cweventhandler(GtkWidget * w, GdkEvent * event, gpointer data)
969 {
970     Gwidget_t *widget;
971
972     widget = findwidget((unsigned long) w, G_CANVASWIDGET);
973     Gneedredraw = WCU->needredraw = TRUE;
974     adjustclip(widget);
975
976     gtk_signal_connect(G_OBJECT(w), "visibility_notify_event",
977                        GTK_SIGNAL_FUNC(cweventhandler), NULL);
978     gtk_signal_connect(G_OBJECT(w), "motion_notify_event",
979                        GTK_SIGNAL_FUNC(cweventhandler), NULL);
980 }
981
982
983 static void setgattr(Gwidget_t * widget, Ggattr_t * ap)
984 {
985     GdkGCValues gcv;
986     GdkColor c;
987     int color, width, mode, style, pati;
988     double intens;
989
990     if (!(ap->flags & G_GATTRCOLOR))
991         ap->color = WCU->defgattr.color;
992     if (!(ap->flags & G_GATTRWIDTH))
993         ap->width = WCU->defgattr.width;
994     if (!(ap->flags & G_GATTRMODE))
995         ap->mode = WCU->defgattr.mode;
996     if (!(ap->flags & G_GATTRFILL))
997         ap->fill = WCU->defgattr.fill;
998     if (!(ap->flags & G_GATTRSTYLE))
999         ap->style = WCU->defgattr.style;
1000     color = ap->color;
1001
1002     if (color >= G_MAXCOLORS || !(WCU->colors[color].inuse))
1003         color = 1;
1004
1005     if (color != WCU->gattr.color) {
1006
1007         WCU->gattr.color = color;
1008         /*if (ap->mode == GDK_XOR) {
1009            gdk_gc_set_foreground (GC, widget->w->style->white_gc);
1010            }
1011            else {
1012          */
1013         gdk_gc_set_foreground(GC, &WCU->colors[WCU->gattr.color].color);
1014         /* } */
1015
1016 /*          if (Gdepth == 1) {
1017                 cp = &WCU->colors[color].color;
1018                 intens = (0.3 * cp->blue + 0.59 * cp->red +
1019                                 0.11 * cp->green) / 65535.0;
1020                 pati = (intens <= 0.0625) ? 16 :
1021                             -16.0 * (log (intens) / 2.7725887222);
1022                 XSetTile (Gdisplay, GC, WCU->grays[pati]);
1023             }
1024 */
1025     }
1026     mode = ap->mode;
1027     if (mode != WCU->gattr.mode) {
1028         WCU->gattr.mode = mode;
1029 /*          XSetFunction (Gdisplay, GC, WCU->gattr.mode);
1030             if (mode == GDK_XOR)
1031                 gdk_gc_set_foreground (GC, &WCU->colors[0].color);
1032             else
1033 */
1034         gdk_gc_set_foreground(GC, &WCU->colors[WCU->gattr.color].color);
1035     }
1036     width = ap->width;
1037     if (width != WCU->gattr.width) {
1038         gdk_gc_set_line_attributes(GC, width, GDK_LINE_SOLID,
1039                                    GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL);
1040     }
1041
1042     WCU->gattr.fill = ap->fill;
1043     style = ap->style;
1044     if (style != WCU->gattr.style) {
1045         WCU->gattr.style = style;
1046         if (style == G_SOLID) {
1047             gdk_gc_set_line_attributes(GC, width, GDK_LINE_SOLID,
1048                                        GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL);
1049         } else {
1050             gdk_gc_set_dashes(GC, 0, gstyles[style], 2);
1051             gdk_gc_set_line_attributes(GC, width, GDK_LINE_ON_OFF_DASH,
1052                                        GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL);
1053         }
1054     }
1055 }
1056
1057
1058 static PIXrect_t rdrawtopix(Gwidget_t * widget, Grect_t gr)
1059 {
1060     PIXrect_t pr;
1061     double tvx, tvy, twx, twy;
1062
1063     tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1064     twx = WCU->wrect.c.x - WCU->wrect.o.x;
1065     twy = WCU->wrect.c.y - WCU->wrect.o.y;
1066     pr.o.x = tvx * (gr.o.x - WCU->wrect.o.x) / twx + 0.5;
1067     pr.o.y = tvy * (1.0 - (gr.c.y - WCU->wrect.o.y) / twy) + 0.5;
1068     pr.c.x = tvx * (gr.c.x - WCU->wrect.o.x) / twx + 0.5;
1069     pr.c.y = tvy * (1.0 - (gr.o.y - WCU->wrect.o.y) / twy) + 0.5;
1070     return pr;
1071 }
1072
1073
1074 static PIXpoint_t pdrawtopix(Gwidget_t * widget, Gpoint_t gp)
1075 {
1076     PIXpoint_t pp;
1077     double tvx, tvy, twx, twy;
1078
1079     tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1080     twx = WCU->wrect.c.x - WCU->wrect.o.x;
1081     twy = WCU->wrect.c.y - WCU->wrect.o.y;
1082
1083     pp.x = tvx * (gp.x - WCU->wrect.o.x) / twx + 0.5;
1084     pp.y = tvy * (1.0 - (gp.y - WCU->wrect.o.y) / twy) + 0.5;
1085     return pp;
1086 }
1087
1088
1089 static PIXsize_t sdrawtopix(Gwidget_t * widget, Gsize_t gs)
1090 {
1091     PIXsize_t ps;
1092     double tvx, tvy, twx, twy;
1093
1094     tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1095     twx = WCU->wrect.c.x - WCU->wrect.o.x;
1096     twy = WCU->wrect.c.y - WCU->wrect.o.y;
1097     ps.x = tvx * (gs.x - 1) / twx + 1.5;
1098     ps.y = tvy * (gs.y - 1) / twy + 1.5;
1099
1100     return ps;
1101 }
1102
1103
1104 static Gpoint_t Gppixtodraw(Gwidget_t * widget, PIXpoint_t pp)
1105 {
1106     Gpoint_t gp;
1107     double tvx, tvy, twx, twy;
1108
1109     tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1110     twx = WCU->wrect.c.x - WCU->wrect.o.x;
1111     twy = WCU->wrect.c.y - WCU->wrect.o.y;
1112
1113     gp.x = (pp.x / tvx) * twx + WCU->wrect.o.x;
1114     gp.y = (1.0 - pp.y / tvy) * twy + WCU->wrect.o.y;
1115     return gp;
1116 }
1117
1118
1119 static Gsize_t spixtodraw(Gwidget_t * widget, PIXsize_t ps)
1120 {
1121     Gsize_t gs;
1122     double tvx, tvy, twx, twy;
1123
1124     tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1125     twx = WCU->wrect.c.x - WCU->wrect.o.x;
1126     twy = WCU->wrect.c.y - WCU->wrect.o.y;
1127     gs.x = ((ps.x - 1) / tvx) * twx + 1;
1128     gs.y = ((ps.y - 1) / tvy) * twy + 1;
1129     return gs;
1130 }
1131
1132
1133 static Grect_t rpixtodraw(Gwidget_t * widget, PIXrect_t pr)
1134 {
1135     Grect_t gr;
1136     double tvx, tvy, twx, twy, n;
1137
1138     tvx = WCU->vsize.x - 1, tvy = WCU->vsize.y - 1;
1139     twx = WCU->wrect.c.x - WCU->wrect.o.x;
1140     twy = WCU->wrect.c.y - WCU->wrect.o.y;
1141
1142     gr.o.x = (pr.o.x / tvx) * twx + WCU->wrect.o.x;
1143     gr.o.y = (1.0 - pr.c.y / tvy) * twy + WCU->wrect.o.y;
1144     gr.c.x = (pr.c.x / tvx) * twx + WCU->wrect.o.x;
1145     gr.c.y = (1.0 - pr.o.y / tvy) * twy + WCU->wrect.o.y;
1146
1147     if (gr.o.x > gr.c.x)
1148         n = gr.o.x, gr.o.x = gr.c.x, gr.c.x = n;
1149     if (gr.o.y > gr.c.y)
1150         n = gr.o.y, gr.o.y = gr.c.y, gr.c.y = n;
1151     return gr;
1152 }
1153
1154
1155 static PIXrect_t rdrawtobpix(Gbitmap_t * bitmap, Grect_t gr)
1156 {
1157     PIXrect_t pr;
1158     double tvy;
1159
1160     tvy = (bitmap->size.y - 1) * bitmap->scale.y;
1161     pr.o.x = gr.o.x + 0.5;
1162     pr.o.y = tvy - gr.c.y + 0.5;
1163     pr.c.x = gr.c.x + 0.5;
1164     pr.c.y = tvy - gr.o.y + 0.5;
1165     return pr;
1166 }
1167
1168
1169 static PIXpoint_t pdrawtobpix(Gbitmap_t * bitmap, Gpoint_t gp)
1170 {
1171     PIXpoint_t pp;
1172     double tvy;
1173
1174     tvy = (bitmap->size.y - 1) * bitmap->scale.y;
1175     pp.x = gp.x + 0.5;
1176     pp.y = tvy - gp.y + 0.5;
1177     return pp;
1178 }
1179
1180
1181 static void adjustclip(Gwidget_t * widget)
1182 {
1183     Gwidget_t *parent;
1184     PIXrect_t pr;
1185     int width, height;
1186
1187 }