📄 gcanvas.c
字号:
/* $Id: gcanvas.c,v 1.2 2005/11/30 22:19:13 erg Exp $ $Revision: 1.2 $ *//* vim:set shiftwidth=4 ts=8: *//*********************************************************** This software is part of the graphviz package ** http://www.graphviz.org/ ** ** Copyright (c) 1994-2004 AT&T Corp. ** and is licensed under the ** Common Public License, Version 1.0 ** by AT&T Corp. ** ** Information and Software Systems Research ** AT&T Research, Florham Park NJ ***********************************************************/#include "common.h"#include "g.h"#include "gcommon.h"#define WCU widget->u.c#define WINDOW widget->u.c->window#define GC widget->u.c->gc#define ISVISIBLE(r) ( \ (r.o.x <= WCU->clip.c.x) && (r.c.x >= WCU->clip.o.x) && \ (r.o.y <= WCU->clip.c.y) && (r.c.y >= WCU->clip.o.y) \)#define IS8BIT(font) ((font)->min_byte1 == 0 && (font)->max_byte1 == 0)#define max(a, b) (((a) >= (b)) ? (a) : (b))#define min(a, b) (((a) <= (b)) ? (a) : (b))#define SETFONT(font) { \ if(font != WCU->font) { \ WCU->font = font; \ gdk_gc_set_font(GC, font); \ } \}Gwidget_t *canvas;static int curcursori = -1;static gchar gstyles[][2] = { /* G_SOLID */ {16}, /* G_DASHED */ {4, 4}, /* G_DOTTED */ {2, 2}, /* G_LONGDASHED */ {4, 12}, /* G_SHORTDASHED */ {12, 4}};static char grays[][4] = { {0x00, 0x00, 0x00, 0x00,}, {0x08, 0x00, 0x00, 0x00,}, {0x08, 0x00, 0x02, 0x00,}, {0x0A, 0x00, 0x02, 0x00,}, {0x0A, 0x00, 0x0A, 0x00,}, {0x0A, 0x04, 0x0A, 0x00,}, {0x0A, 0x04, 0x0A, 0x01,}, {0x0A, 0x05, 0x0A, 0x01,}, {0x0A, 0x05, 0x0A, 0x05,}, {0x0E, 0x05, 0x0A, 0x05,}, {0x0E, 0x05, 0x0B, 0x05,}, {0x0F, 0x05, 0x0B, 0x05,}, {0x0F, 0x05, 0x0F, 0x05,}, {0x0F, 0x0D, 0x0F, 0x05,}, {0x0F, 0x0D, 0x0F, 0x07,}, {0x0F, 0x0F, 0x0F, 0x07,}, {0x0F, 0x0F, 0x0F, 0x0F,},};static void setgattr(Gwidget_t *, Ggattr_t *);static PIXrect_t rdrawtopix(Gwidget_t *, Grect_t);static PIXpoint_t pdrawtopix(Gwidget_t *, Gpoint_t);static PIXsize_t sdrawtopix(Gwidget_t *, Gsize_t);static Gpoint_t Gppixtodraw(Gwidget_t *, PIXpoint_t);static Gsize_t spixtodraw(Gwidget_t *, PIXsize_t);static Grect_t rpixtodraw(Gwidget_t *, PIXrect_t);static PIXrect_t rdrawtobpix(Gbitmap_t *, Grect_t);static PIXpoint_t pdrawtobpix(Gbitmap_t *, Gpoint_t);static void adjustclip(Gwidget_t *);int GCcreatewidget(Gwidget_t * parent, Gwidget_t * widget, int attrn, Gwattr_t * attrp){ PIXsize_t ps; int width, height; int ai, i; GdkGCValues gcv; int r, g, b, color; GdkColor *cp; if (!parent) { Gerr(POS, G_ERRNOPARENTWIDGET); return -1; } canvas = widget; WCU->func = NULL; WCU->needredraw = FALSE; WCU->buttonsdown = 0; WCU->bstate[0] = WCU->bstate[1] = WCU->bstate[2] = 0; ps.x = ps.y = MINCWSIZE; for (ai = 0; ai < attrn; ai++) { switch (attrp[ai].id) { case G_ATTRSIZE: GETSIZE(attrp[ai].u.s, ps, MINCWSIZE); break; case G_ATTRBORDERWIDTH: break;#ifdef FEATURE_GMAP case G_ATTRMODE: if (Strcmp("gmap", attrp[ai].u.t) == 0) { gmapmode = TRUE; } else { Gerr(POS, G_ERRBADATTRVALUE, attrp[ai].u.t); return -1; } break;#endif case G_ATTRCURSOR: break; case G_ATTRCOLOR: break; case G_ATTRVIEWPORT: break; case G_ATTRWINDOW: break; case G_ATTRWINDOWID: Gerr(POS, G_ERRCANNOTSETATTR2, "windowid"); return -1; case G_ATTREVENTCB: WCU->func = (Gcanvascb) attrp[ai].u.func; break; case G_ATTRUSERDATA: widget->udata = attrp[ai].u.u; break; default: Gerr(POS, G_ERRBADATTRID, attrp[ai].id); return -1; } }/* XtSetValues (widget->w, argp, argn); */ widget->w = gtk_drawing_area_new(); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(parent->w), widget->w); gtk_drawing_area_size(GTK_DRAWING_AREA(widget->w), ps.x, ps.y); gtk_widget_add_events(widget->w, GDK_ALL_EVENTS_MASK); gtk_signal_connect(GTK_OBJECT(widget->w), "key_release_event", GTK_SIGNAL_FUNC(Gcwkeyaction), NULL); gtk_signal_connect(GTK_OBJECT(widget->w), "key_press_event", GTK_SIGNAL_FUNC(Gcwkeyaction), NULL); gtk_signal_connect(G_OBJECT(widget->w), "button_press_event", GTK_SIGNAL_FUNC(Gcwbutaction), NULL); gtk_signal_connect(G_OBJECT(widget->w), "button_release_event", GTK_SIGNAL_FUNC(Gcwbutaction), NULL); gtk_signal_connect(G_OBJECT(widget->w), "visibility_notify_event", GTK_SIGNAL_FUNC(cweventhandler), NULL); gtk_signal_connect(G_OBJECT(widget->w), "expose_event", GTK_SIGNAL_FUNC(exposeeventhandler), NULL); gtk_signal_connect(G_OBJECT(widget->w), "motion_notify_event", GTK_SIGNAL_FUNC(cweventhandler), NULL); gtk_widget_show(widget->w); gtk_widget_show(parent->w); GC = gdk_gc_new(widget->w->window); WCU->cmap = gdk_colormap_get_system(); WCU->colors[0].color.pixel = WCU->colors[1].color.pixel = 1000000; if (WCU->colors[0].color.pixel == 1000000) { gdk_gc_get_values(GC, &gcv); WCU->colors[0].color = gcv.background; } if (WCU->colors[1].color.pixel == 1000000) { gdk_gc_get_values(GC, &gcv); WCU->colors[1].color = gcv.foreground; } WCU->colors[0].color.red = 65535; WCU->colors[0].color.green = 65535; WCU->colors[0].color.blue = 65535; WCU->colors[1].color.red = 0; WCU->colors[1].color.green = 0; WCU->colors[1].color.blue = 0; gdk_colormap_alloc_color(WCU->cmap, &WCU->colors[0].color, FALSE, TRUE); WCU->colors[0].inuse = TRUE; gdk_colormap_alloc_color(WCU->cmap, &WCU->colors[1].color, FALSE, TRUE); WCU->colors[1].inuse = TRUE; WCU->allocedcolor[0] = WCU->allocedcolor[1] = FALSE; for (i = 2; i < G_MAXCOLORS; i++) WCU->colors[i].inuse = FALSE; WCU->gattr.color = 1;/* gdk_gc_set_background(GC, widget->w->style->white_gc); gdk_gc_set_foreground(GC, widget->w->style->black_gc);*/ WCU->gattr.width = 0; WCU->gattr.mode = 0; WCU->gattr.fill = 0; WCU->gattr.style = 0; WCU->defgattr = WCU->gattr; WCU->font = NULL; WCU->wrect.o.x = 0.0, WCU->wrect.o.y = 0.0; WCU->wrect.c.x = 1.0, WCU->wrect.c.y = 1.0; WCU->vsize.x = ps.x, WCU->vsize.y = ps.y; for (ai = 0; ai < attrn; ai++) { switch (attrp[ai].id) { case G_ATTRCURSOR: if (Strcmp(attrp[ai].u.t, "default") == 0) { curcursori = -1; } break; case G_ATTRCOLOR: color = attrp[ai].u.c.index; if (color < 0 || color > G_MAXCOLORS) { Gerr(POS, G_ERRBADCOLORINDEX, color); return -1; } r = attrp[ai].u.c.r * 257; g = attrp[ai].u.c.g * 257; b = attrp[ai].u.c.b * 257; cp = &WCU->colors[color].color; if (WCU->colors[color].inuse) if (cp->red != r || cp->green != g || cp->blue != b) if (color > 1 || WCU->allocedcolor[color]) gdk_colormap_free_colors(WCU->cmap, cp, 1); cp->red = r, cp->green = g, cp->blue = b; if (gdk_colormap_alloc_color(WCU->cmap, cp, TRUE, TRUE)) { WCU->colors[color].inuse = TRUE; if (color <= 1) WCU->allocedcolor[color] = TRUE; } cp->red = r, cp->green = g, cp->blue = b; if (color == WCU->gattr.color) WCU->gattr.color = -1; break; case G_ATTRVIEWPORT: WCU->vsize.x = (int) (attrp[ai].u.s.x + 0.5); WCU->vsize.y = (int) (attrp[ai].u.s.y + 0.5); break; case G_ATTRWINDOW: WCU->wrect = attrp[ai].u.r; break; } } adjustclip(widget); return 0;}int GCsetwidgetattr(Gwidget_t * widget, int attrn, Gwattr_t * attrp){ PIXsize_t ps; int ai, r, g, b, color; GdkColor *cp; for (ai = 0; ai < attrn; ai++) { switch (attrp[ai].id) { case G_ATTRSIZE: GETSIZE(attrp[ai].u.s, ps, MINCWSIZE); gtk_drawing_area_size(GTK_DRAWING_AREA(widget->w), ps.x, ps.y); break; case G_ATTRBORDERWIDTH: break; case G_ATTRCURSOR: if (Strcmp(attrp[ai].u.t, "watch") == 0) { gdk_window_set_cursor(widget->w->window, gdk_cursor_new(GDK_WATCH)); } else { gdk_window_set_cursor(widget->w->window, gdk_cursor_new(GDK_LEFT_PTR)); } Gsync(); break; case G_ATTRCOLOR: color = attrp[ai].u.c.index; if (color < 0 || color > G_MAXCOLORS) { Gerr(POS, G_ERRBADCOLORINDEX, color); return -1; } r = attrp[ai].u.c.r * 257; g = attrp[ai].u.c.g * 257; b = attrp[ai].u.c.b * 257; cp = &WCU->colors[color].color; if (WCU->colors[color].inuse) if (cp->red != r || cp->green != g || cp->blue != b) if (color > 1 || WCU->allocedcolor[color]) gdk_colormap_free_colors(WCU->cmap, cp, 1); cp->red = r, cp->green = g, cp->blue = b; if (gdk_colormap_alloc_color(WCU->cmap, cp, TRUE, TRUE)) { WCU->colors[color].inuse = TRUE; if (color <= 1) WCU->allocedcolor[color] = TRUE; } cp->red = r, cp->green = g, cp->blue = b; if (color == WCU->gattr.color) WCU->gattr.color = -1; break; case G_ATTRVIEWPORT: WCU->vsize.x = (int) (attrp[ai].u.s.x + 0.5); WCU->vsize.y = (int) (attrp[ai].u.s.y + 0.5); break; case G_ATTRWINDOW: WCU->wrect = attrp[ai].u.r; adjustclip(widget); break; case G_ATTRWINDOWID: Gerr(POS, G_ERRCANNOTSETATTR2, "windowid"); return -1; case G_ATTREVENTCB: WCU->func = (Gcanvascb) attrp[ai].u.func; break; case G_ATTRUSERDATA: widget->udata = attrp[ai].u.u; break; default: Gerr(POS, G_ERRBADATTRID, attrp[ai].id); return -1; } } return 0;}int GCgetwidgetattr(Gwidget_t * widget, int attrn, Gwattr_t * attrp){ GdkColor *cp; int width, height; int ai, color; for (ai = 0; ai < attrn; ai++) { switch (attrp[ai].id) { case G_ATTRSIZE: attrp[ai].u.s.x = width, attrp[ai].u.s.y = height; break; case G_ATTRBORDERWIDTH: attrp[ai].u.i = width; break; case G_ATTRCURSOR:/* attrp[ai].u.t = (curcursori == -1) ? "default" : cursormap[curcursori].name;*/ attrp[ai].u.t = (curcursori == -1) ? "default" : "watch"; break; case G_ATTRCOLOR: color = attrp[ai].u.c.index; if (color < 0 || color > G_MAXCOLORS) { Gerr(POS, G_ERRBADCOLORINDEX, color); return -1; } if (WCU->colors[color].inuse) { cp = &WCU->colors[color].color; attrp[ai].u.c.r = cp->red / 257.0; attrp[ai].u.c.g = cp->green / 257.0; attrp[ai].u.c.b = cp->blue / 257.0; } else { attrp[ai].u.c.r = -1; attrp[ai].u.c.g = -1; attrp[ai].u.c.b = -1; } break; case G_ATTRVIEWPORT: attrp[ai].u.s = WCU->vsize; break; case G_ATTRWINDOW: attrp[ai].u.r = WCU->wrect; break; case G_ATTRWINDOWID: sprintf(&Gbufp[0], "0x%lx", (unsigned long) widget->w); break; case G_ATTREVENTCB: attrp[ai].u.func = WCU->func; break; case G_ATTRUSERDATA: attrp[ai].u.u = widget->udata; break; default: Gerr(POS, G_ERRBADATTRID, attrp[ai].id); return -1; } } return 0;}int GCdestroywidget(Gwidget_t * widget){ gtk_widget_destroy(widget->w); return 0;}int GCsetgfxattr(Gwidget_t * widget, Ggattr_t * ap){ setgattr(widget, ap); WCU->defgattr = WCU->gattr; return 0;}int GCarrow(Gwidget_t * widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t * ap){ PIXpoint_t pp1, pp2, pa, pb, pd; Grect_t gr; double tangent, l; if (gp1.x < gp2.x) gr.o.x = gp1.x, gr.c.x = gp2.x; else gr.o.x = gp2.x, gr.c.x = gp1.x; if (gp1.y < gp2.y) gr.o.y = gp1.y, gr.c.y = gp2.y; else gr.o.y = gp2.y, gr.c.y = gp1.y; pp1 = pdrawtopix(widget, gp1), pp2 = pdrawtopix(widget, gp2); pd.x = pp1.x - pp2.x, pd.y = pp1.y - pp2.y; if (pd.x == 0 && pd.y == 0) return 0; tangent = atan2((double) pd.y, (double) pd.x); if ((l = sqrt((double) (pd.x * pd.x + pd.y * pd.y))) > 30) l = 30; pa.x = l * cos(tangent + M_PI / 7) + pp2.x; pa.y = l * sin(tangent + M_PI / 7) + pp2.y; pb.x = l * cos(tangent - M_PI / 7) + pp2.x; pb.y = l * sin(tangent - M_PI / 7) + pp2.y; setgattr(widget, ap); gdk_draw_line(widget->w->window, GC, pp1.x, pp1.y, pp2.x, pp2.y); gdk_draw_line(widget->w->window, GC, pa.x, pa.y, pp2.x, pp2.y); gdk_draw_line(widget->w->window, GC, pb.x, pb.y, pp2.x, pp2.y); return 0;}int GCline(Gwidget_t * widget, Gpoint_t gp1, Gpoint_t gp2, Ggattr_t * ap){ PIXpoint_t pp1, pp2; Grect_t gr; if (gp1.x < gp2.x) gr.o.x = gp1.x, gr.c.x = gp2.x; else gr.o.x = gp2.x, gr.c.x = gp1.x; if (gp1.y < gp2.y) gr.o.y = gp1.y, gr.c.y = gp2.y; else gr.o.y = gp2.y, gr.c.y = gp1.y;/* if(!ISVISIBLE(gr)) return 1;*/ pp1 = pdrawtopix(widget, gp1), pp2 = pdrawtopix(widget, gp2); setgattr(widget, ap); gdk_draw_line(widget->w->window, GC, pp1.x, pp1.y, pp2.x, pp2.y); return 0;}int GCbox(Gwidget_t * widget, Grect_t gr, Ggattr_t * ap){ PIXrect_t pr; Gxy_t p; if (gr.o.x > gr.c.x) p.x = gr.o.x, gr.o.x = gr.c.x, gr.c.x = p.x; if (gr.o.y > gr.c.y) p.y = gr.o.y, gr.o.y = gr.c.y, gr.c.y = p.y;/* if(!ISVISIBLE(gr)) return 1;*/ pr = rdrawtopix(widget, gr); setgattr(widget, ap); if (WCU->gattr.fill) gdk_draw_rectangle(widget->w->window, GC, TRUE, pr.o.x, pr.o.y, pr.c.x - pr.o.x, pr.c.y - pr.o.y); else { gdk_draw_rectangle(widget->w->window, GC, FALSE, pr.o.x, pr.o.y, pr.c.x - pr.o.x, pr.c.y - pr.o.y); } return 0;}int GCpolygon(Gwidget_t * widget, int gpn, Gpoint_t * gpp, Ggattr_t * ap){ Grect_t gr; int n, i; if (gpn == 0) return 0; gr.o = gpp[0], gr.c = gpp[0]; for (i = 1; i < gpn; i++) { gr.o.x = min(gr.o.x, gpp[i].x); gr.o.y = min(gr.o.y, gpp[i].y); gr.c.x = min(gr.c.x, gpp[i].x); gr.c.y = min(gr.c.y, gpp[i].y); }/* if(!ISVISIBLE(gr)) return 1;*/ if (gpn + 1 > Gppn) { n = (((gpn + 1) + PPINCR - 1) / PPINCR) * PPINCR; Gppp = Marraygrow(Gppp, (long) n * PPSIZE); Gppn = n; } for (i = 0; i < gpn; i++) Gppp[i] = pdrawtopix(widget, gpp[i]); setgattr(widget, ap); if (WCU->gattr.fill) { if (Gppp[gpn - 1].x != Gppp[0].x || Gppp[gpn - 1].y != Gppp[0].y) Gppp[gpn] = Gppp[0], gpn++; gdk_draw_polygon(widget->w, GC, TRUE, Gppp, gpn); } else gdk_draw_polygon(widget->w, GC, FALSE, Gppp, gpn); return 0;}static void bezier(PIXpoint_t p0, PIXpoint_t p1, PIXpoint_t p2, PIXpoint_t p3){ Gpoint_t gp0, gp1, gp2; Gsize_t s; PIXpoint_t p; double t; int n, i, steps; if ((s.x = p3.x - p0.x) < 0) s.x = -s.x; if ((s.y = p3.y - p0.y) < 0) s.y = -s.y; if (s.x > s.y) steps = s.x / 5 + 1; else steps = s.y / 5 + 1; for (i = 0; i <= steps; i++) { t = i / (double) steps; gp0.x = p0.x + t * (p1.x - p0.x); gp0.y = p0.y + t * (p1.y - p0.y); gp1.x = p1.x + t * (p2.x - p1.x); gp1.y = p1.y + t * (p2.y - p1.y); gp2.x = p2.x + t * (p3.x - p2.x); gp2.y = p2.y + t * (p3.y - p2.y); gp0.x = gp0.x + t * (gp1.x - gp0.x); gp0.y = gp0.y + t * (gp1.y - gp0.y); gp1.x = gp1.x + t * (gp2.x - gp1.x); gp1.y = gp1.y + t * (gp2.y - gp1.y); p.x = gp0.x + t * (gp1.x - gp0.x) + 0.5; p.y = gp0.y + t * (gp1.y - gp0.y) + 0.5; if (Gppi >= Gppn) { n = (((Gppi + 1) + PPINCR - 1) / PPINCR) * PPINCR; Gppp = Marraygrow(Gppp, (long) n * PPSIZE); Gppn = n; } Gppp[Gppi++] = p; }}int GCsplinegon(Gwidget_t * widget, int gpn, Gpoint_t * gpp, Ggattr_t * ap){ PIXpoint_t p0, p1, p2, p3; Grect_t gr; int n, i; if (gpn == 0) return 0; gr.o = gpp[0], gr.c = gpp[0]; for (i = 1; i < gpn; i++) { gr.o.x = min(gr.o.x, gpp[i].x); gr.o.y = min(gr.o.y, gpp[i].y); gr.c.x = max(gr.c.x, gpp[i].x);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -