From: erg Date: Wed, 21 Mar 2007 18:07:54 +0000 (+0000) Subject: Cleanup and fixing of various code related to hot spots and HTML labels. X-Git-Tag: LAST_LIBGRAPH~32^2~5613 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=75cc79d1a755176b5b38c80fdc81c2b1b282bad7;p=graphviz Cleanup and fixing of various code related to hot spots and HTML labels. In particular: HTML labels were not being initialized correctly when used with graphs or edges HTML labels now inherent url info from the object and use that unless a subpart overrides it. There is now more control over which parts of an edge are active. The URL attribute still provides a default for all pieces, which can be overridden. We now also give control over the edge and main label separately, so now the edge, label, headlabel and taillabel can be independently set. --- diff --git a/lib/common/emit.c b/lib/common/emit.c index d26924660..253cb1f81 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -69,12 +69,15 @@ void pop_obj_state(GVJ_t *job) assert(obj); free(obj->url); + free(obj->labelurl); free(obj->tailurl); free(obj->headurl); free(obj->tooltip); + free(obj->labeltooltip); free(obj->tailtooltip); free(obj->headtooltip); free(obj->target); + free(obj->labeltarget); free(obj->tailtarget); free(obj->headtarget); free(obj->url_map_p); @@ -85,39 +88,41 @@ void pop_obj_state(GVJ_t *job) free(obj); } -void +/* initMapData: + * Store image map data into job, substituting for node, edge, etc. + * names. + * Return 1 if an assignment was made for url or tooltip or target. + */ +int initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target, void* gobj) { obj_state_t *obj = job->obj; int flags = job->flags; + int assigned = 0; if ((flags & GVRENDER_DOES_LABELS) && lbl) obj->label = lbl; - if (obj->url) free (obj->url); if ((flags & GVRENDER_DOES_MAPS) && url && url[0]) { obj->url = strdup_and_subst_obj(url, gobj); + assigned = 1; } - else - obj->url = NULL; - if (obj->tooltip) free (obj->tooltip); if (flags & GVRENDER_DOES_TOOLTIPS) { if (tooltip && tooltip[0]) { obj->tooltip = strdup_and_subst_obj(tooltip, gobj); obj->explicit_tooltip = TRUE; + assigned = 1; } else if (obj->label) { obj->tooltip = strdup(obj->label); + assigned = 1; } } - else - obj->tooltip = NULL; - if (obj->target) free (obj->target); if ((flags & GVRENDER_DOES_TARGETS) && target && target[0]) { obj->target = strdup_and_subst_obj(target, gobj); + assigned = 1; } - else - obj->target = NULL; + return assigned; } static void @@ -1524,6 +1529,8 @@ void emit_begin_edge(GVJ_t * job, edge_t * e) textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL; pointf *pbs = NULL; int i, nump, *pbs_n = NULL, pbs_poly_n = 0; + char* dflt_url = NULL; + char* dflt_target = NULL; obj = push_obj_state(job); obj->type = EDGE_OBJTYPE; @@ -1547,38 +1554,72 @@ void emit_begin_edge(GVJ_t * job, edge_t * e) if (flags & GVRENDER_DOES_MAPS) { if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0])) + dflt_url = strdup_and_subst_obj(s, (void*)e); + if (((s = agget(e, "edgehref")) && s[0]) || ((s = agget(e, "edgeURL")) && s[0])) obj->url = strdup_and_subst_obj(s, (void*)e); - if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0])) + else if (dflt_url) + obj->url = strdup(dflt_url); + if (((s = agget(e, "labelhref")) && s[0]) || ((s = agget(e, "labelURL")) && s[0])) + obj->labelurl = strdup_and_subst_obj(s, (void*)e); + else if (dflt_url) + obj->labelurl = strdup(dflt_url); + if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0])) { obj->tailurl = strdup_and_subst_obj(s, (void*)e); - else if (obj->url) - obj->tailurl = strdup(obj->url); - if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0])) + obj->explicit_tailurl = TRUE; + } + else if (dflt_url) + obj->tailurl = strdup(dflt_url); + if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0])) { obj->headurl = strdup_and_subst_obj(s, (void*)e); - else if (obj->url) - obj->headurl = strdup(obj->url); + obj->explicit_headurl = TRUE; + } + else if (dflt_url) + obj->headurl = strdup(dflt_url); } if (flags & GVRENDER_DOES_TARGETS) { if ((s = agget(e, "target")) && s[0]) + dflt_target = strdup_and_subst_obj(s, (void*)e); + if ((s = agget(e, "edgetarget")) && s[0]) { + obj->explicit_edgetarget = TRUE; obj->target = strdup_and_subst_obj(s, (void*)e); - if ((s = agget(e, "tailtarget")) && s[0]) + } + else if (dflt_target) + obj->target = strdup(dflt_target); + if ((s = agget(e, "labeltarget")) && s[0]) + obj->labeltarget = strdup_and_subst_obj(s, (void*)e); + else if (dflt_target) + obj->labeltarget = strdup(dflt_target); + if ((s = agget(e, "tailtarget")) && s[0]) { obj->tailtarget = strdup_and_subst_obj(s, (void*)e); - else if (obj->target) - obj->tailtarget = strdup(obj->target); - if ((s = agget(e, "headtarget")) && s[0]) + obj->explicit_tailtarget = TRUE; + } + else if (dflt_target) + obj->tailtarget = strdup(dflt_target); + if ((s = agget(e, "headtarget")) && s[0]) { + obj->explicit_headtarget = TRUE; obj->headtarget = strdup_and_subst_obj(s, (void*)e); - else if (obj->target) - obj->headtarget = strdup(obj->target); + } + else if (dflt_target) + obj->headtarget = strdup(dflt_target); } if (flags & GVRENDER_DOES_TOOLTIPS) { - if ((s = agget(e, "tooltip")) && s[0]) { + if (((s = agget(e, "tooltip")) && s[0]) || + ((s = agget(e, "edgetooltip")) && s[0])) { obj->tooltip = strdup_and_subst_obj(s, (void*)e); obj->explicit_tooltip = TRUE; } else if (obj->label) obj->tooltip = strdup(obj->label); + if ((s = agget(e, "labeltooltip")) && s[0]) { + obj->labeltooltip = strdup_and_subst_obj(s, (void*)e); + obj->explicit_labeltooltip = TRUE; + } + else if (obj->label) + obj->labeltooltip = strdup(obj->label); + if ((s = agget(e, "tailtooltip")) && s[0]) { obj->tailtooltip = strdup_and_subst_obj(s, (void*)e); obj->explicit_tailtooltip = TRUE; @@ -1594,6 +1635,9 @@ void emit_begin_edge(GVJ_t * job, edge_t * e) obj->headtooltip = strdup(obj->headlabel); } + free (dflt_url); + free (dflt_target); + if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) { if (ED_spl(e) && (obj->url || obj->tooltip) && (flags & GVRENDER_DOES_MAP_POLYGON)) { int ns; @@ -1626,11 +1670,83 @@ void emit_begin_edge(GVJ_t * job, edge_t * e) gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); } +static void +emit_edge_label(GVJ_t* job, textlabel_t* lbl, int lkind, int explicit, + char* url, char* tooltip, char* target, splines* spl) +{ + int flags = job->flags; + if (lbl == NULL) return; + if ((url || explicit) && !(flags & EMIT_CLUSTERS_LAST)) { + map_label(job, lbl); + gvrender_begin_anchor(job, url, tooltip, target); + } + emit_label(job, lkind, lbl); + if (spl) emit_attachment(job, lbl, spl); + if (url || explicit) { + if (flags & EMIT_CLUSTERS_LAST) { + map_label(job, lbl); + gvrender_begin_anchor(job, url, tooltip, target); + } + gvrender_end_anchor(job); + } +} + +/* nodeIntersect: + * Common logic for setting hot spots at the beginning and end of + * an edge. + * If we are given a value (url, tooltip, target) explicitly set for + * the head/tail, we use that. + * Otherwise, if we are given a value explicitly set for the edge, + * we use that. + * Otherwise, we use whatever the argument value is. + * We also note whether or not the tooltip was explicitly set. + * If the url is non-NULL or the tooltip was explicit, we set + * a hot spot around point p. + */ +static void +nodeIntersect (GVJ_t * job, point p, + boolean explicit_iurl, char* iurl, + boolean explicit_itooltip, char* itooltip, + boolean explicit_itarget, char* itarget) +{ + obj_state_t *obj = job->obj; + char* url; + char* tooltip; + char* target; + boolean explicit; + + if (explicit_iurl) url = iurl; + else url = obj->url; + if (explicit_itooltip) { + tooltip = itooltip; + explicit = TRUE; + } + else if (obj->explicit_tooltip) { + tooltip = obj->tooltip; + explicit = TRUE; + } + else { + explicit = FALSE; + tooltip = itooltip; + } + if (explicit_itarget) + target = itarget; + else if (obj->explicit_edgetarget) + target = obj->target; + else + target = itarget; + + if (url || explicit) { + map_point(job, p); + gvrender_begin_anchor(job, url, tooltip, target); + gvrender_end_anchor(job); + } +} + void emit_end_edge(GVJ_t * job) { obj_state_t *obj = job->obj; edge_t *e = obj->u.e; - bezier bz; int i, nump; if (obj->url || obj->explicit_tooltip) { @@ -1649,57 +1765,38 @@ void emit_end_edge(GVJ_t * job) obj->url_map_n = 0; /* null out copy so that it doesn't get freed twice */ obj->url_map_p = NULL; - /* process intersecion with tail node */ - if (ED_spl(e) && (obj->tailurl || obj->tailtooltip)) { + if (ED_spl(e)) { + point p; + bezier bz; + + /* process intersection with tail node */ bz = ED_spl(e)->list[0]; if (bz.sflag) /* Arrow at start of splines */ - map_point(job, bz.sp); + p = bz.sp; else /* No arrow at start of splines */ - map_point(job, bz.list[0]); - gvrender_begin_anchor(job, obj->tailurl, obj->tailtooltip, obj->tailtarget); - gvrender_end_anchor(job); - } + p = bz.list[0]; + nodeIntersect (job, p, obj->explicit_tailurl, obj->tailurl, + obj->explicit_tailtooltip, obj->tailtooltip, + obj->explicit_tailtarget, obj->tailtarget); - /* process intersection with head node */ - if (ED_spl(e) && (obj->headurl || obj->headtooltip)) { + /* process intersection with head node */ bz = ED_spl(e)->list[ED_spl(e)->size - 1]; if (bz.eflag) /* Arrow at end of splines */ - map_point(job, bz.ep); + p = bz.ep; else /* No arrow at end of splines */ - map_point(job, bz.list[bz.size - 1]); - gvrender_begin_anchor(job, obj->headurl, obj->headtooltip, obj->headtarget); - gvrender_end_anchor(job); + p = bz.list[bz.size - 1]; + nodeIntersect (job, p, obj->explicit_headurl, obj->headurl, + obj->explicit_headtooltip, obj->headtooltip, + obj->explicit_headtarget, obj->headtarget); } - if (ED_label(e)) { - if (obj->url || obj->explicit_tooltip) { - map_label(job, ED_label(e)); - gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); - } - emit_label(job, EMIT_ELABEL, ED_label(e)); - if (mapbool(late_string(e, E_decorate, "false")) && ED_spl(e)) - emit_attachment(job, ED_label(e), ED_spl(e)); - if (obj->url || obj->explicit_tooltip) - gvrender_end_anchor(job); - } - if (ED_head_label(e)) { - if (obj->headurl || obj->explicit_headtooltip) { - map_label(job, ED_head_label(e)); - gvrender_begin_anchor(job, obj->headurl, obj->headtooltip, obj->headtarget); - } - emit_label(job, EMIT_HLABEL, ED_head_label(e)); /* vladimir */ - if (obj->headurl || obj->explicit_headtooltip) - gvrender_end_anchor(job); - } - if (ED_tail_label(e)) { - if (obj->tailurl || obj->explicit_tailtooltip) { - map_label(job, ED_tail_label(e)); - gvrender_begin_anchor(job, obj->tailurl, obj->tailtooltip, obj->tailtarget); - } - emit_label(job, EMIT_TLABEL, ED_tail_label(e)); /* vladimir */ - if (obj->tailurl || obj->explicit_tailtooltip) - gvrender_end_anchor(job); - } + emit_edge_label(job, ED_label(e), EMIT_ELABEL, obj->explicit_labeltooltip, + obj->labelurl, obj->labeltooltip, obj->labeltarget, + ((mapbool(late_string(e, E_decorate, "false")) && ED_spl(e)) ? ED_spl(e) : 0)); + emit_edge_label(job, ED_head_label(e), EMIT_HLABEL, + obj->explicit_headtooltip, obj->headurl, obj->headtooltip, obj->headtarget, 0); + emit_edge_label(job, ED_tail_label(e), EMIT_TLABEL, + obj->explicit_tailtooltip, obj->tailurl, obj->tailtooltip, obj->tailtarget, 0); gvrender_end_edge(job); gvrender_end_context(job); @@ -1987,8 +2084,6 @@ static void emit_view(GVJ_t * job, graph_t * g, int flags) edge_t *e; gvc->common.viewNum++; - if (GD_label(g)) - emit_label(job, EMIT_GLABEL, GD_label(g)); /* when drawing, lay clusters down before nodes and edges */ if (!(flags & EMIT_CLUSTERS_LAST)) emit_clusters(job, g, flags); @@ -2130,6 +2225,8 @@ void emit_graph(GVJ_t * job, graph_t * g) } if (job->numLayers == 1) emit_background(job, g); + if (GD_label(g)) + emit_label(job, EMIT_GLABEL, GD_label(g)); if (!(flags & EMIT_CLUSTERS_LAST) && (obj->url || obj->explicit_tooltip)) gvrender_end_anchor(job); @@ -2249,7 +2346,7 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags) edge_t *e; obj_state_t *obj; textlabel_t *lab; - int doAnchor, inAnchor; + int doAnchor; for (c = 1; c <= GD_n_cluster(g); c++) { sg = GD_clust(g)[c]; @@ -2264,11 +2361,9 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags) setColorScheme (agget (sg, "colorscheme")); gvrender_begin_context(job); if (doAnchor && !(flags & EMIT_CLUSTERS_LAST)) { - inAnchor = 1; emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR); gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); } - else inAnchor = 0; filled = FALSE; istyle = 0; if ((style = checkClusterStyle(sg, &istyle))) { @@ -2335,20 +2430,16 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags) gvrender_box(job, BF, filled); } } - if ((lab = GD_label(sg))) { - if (lab->html && inAnchor) { - gvrender_end_anchor(job); - inAnchor = 0; - } + if ((lab = GD_label(sg))) emit_label(job, EMIT_CLABEL, lab); - } - if (doAnchor && (flags & EMIT_CLUSTERS_LAST)) { - inAnchor = 1; - emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR); - gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); - } - if (doAnchor) + + if (doAnchor) { + if (flags & EMIT_CLUSTERS_LAST) { + emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR); + gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); + } gvrender_end_anchor(job); + } if (flags & EMIT_PREORDER) { for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) { diff --git a/lib/common/htmltable.c b/lib/common/htmltable.c index 5a8569f10..d642507d3 100644 --- a/lib/common/htmltable.c +++ b/lib/common/htmltable.c @@ -50,6 +50,15 @@ typedef struct { graph_t *g; } htmlenv_t; +typedef struct { + char *url; + char *tooltip; + char *target; + boolean explicit_tooltip; + point LL; + point UR; +} htmlmap_data_t; + #ifdef DEBUG static void printCell(htmlcell_t * cp, int ind); #endif @@ -269,27 +278,67 @@ static void doFill(GVJ_t * job, char *color, box B) } /* initAnchor: + * Save current map values * Initialize fields in job->obj pertaining to anchors. * In particular, this also sets the output rectangle. - * If there is somethine to do, it starts the anchor and returns 1 + * If there is something to do, close current anchor if + * necesary, start the anchor and returns 1. * Otherwise, it returns 0. * * FIX: Should we provide a tooltip if none is set, as is done * for nodes, edges, etc. ? */ static int -initAnchor (GVJ_t* job, htmldata_t* data, box pts) +initAnchor (GVJ_t* job, htmldata_t* data, box pts, htmlmap_data_t* save, + int closePrev) { obj_state_t *obj = job->obj; + int changed; - initMapData (job, NULL, data->href, data->title, data->target, obj->u.g); + save->url = obj->url; + save->tooltip = obj->tooltip; + save->target = obj->target; + save->explicit_tooltip = obj->explicit_tooltip; + changed = initMapData (job, NULL, data->href, data->title, data->target, obj->u.g); - if (obj->url || obj->tooltip) { - emit_map_rect(job, pts.LL, pts.UR); - gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); - return 1; + if (changed) { + if (closePrev && (save->url || save->explicit_tooltip)) + gvrender_end_anchor(job); + if (obj->url || obj->explicit_tooltip) { + emit_map_rect(job, pts.LL, pts.UR); + gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); + } } - else return 0; + return changed; +} + +#define RESET(fld) \ + if(obj->fld != save->fld) {free(obj->fld); obj->fld = save->fld;} + +/* endAnchor: + * Pop context pushed by initAnchor. + * This is done by ending current anchor, restoring old values and + * freeing new, and reopening previous anchor if necessary. + * + * NB: We don't save or restore geometric map info. This is because + * this preservation of map context is only necessary for SVG-like + * systems where graphical items are wrapped in an anchor, and we map + * top-down. For ordinary map anchors, this is all done bottom-up, so + * the geometric map info at the higher level hasn't been emitted yet. + */ +static void +endAnchor (GVJ_t* job, htmlmap_data_t* save, int openPrev) +{ + obj_state_t *obj = job->obj; + + if (obj->url || obj->explicit_tooltip) + gvrender_end_anchor(job); + RESET(url); + RESET(tooltip); + RESET(target); + obj->explicit_tooltip = save->explicit_tooltip; + if (openPrev && (obj->url || obj->explicit_tooltip)) + gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); } /* forward declaration */ @@ -302,7 +351,9 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env) point p = env->p; htmlcell_t **cells = tbl->u.n.cells; htmlfont_t savef; - int inAnchor, doAnchor = (tbl->data.href || tbl->data.target); + htmlmap_data_t saved; + int anchor; /* if true, we need to undo anchor settings. */ + int doAnchor = (tbl->data.href || tbl->data.target); if (tbl->font) pushFontInfo(env, tbl->font, &savef); @@ -313,9 +364,9 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env) pts.UR.y += p.y; if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST)) - inAnchor = initAnchor(job, &tbl->data, pts); + anchor = initAnchor(job, &tbl->data, pts, &saved, 1); else - inAnchor = 0; + anchor = 0; if (tbl->data.bgcolor) doFill(job, tbl->data.bgcolor, pts); @@ -323,17 +374,17 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env) if (tbl->data.border) doBorder(job, tbl->data.pencolor, tbl->data.border, pts); - if (inAnchor) - gvrender_end_anchor(job); - while (*cells) { emit_html_cell(job, *cells, env); cells++; } + if (anchor) + endAnchor (job, &saved, 1); + if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) { - if (initAnchor(job, &tbl->data, pts)) - gvrender_end_anchor(job); + if (initAnchor(job, &tbl->data, pts, &saved, 0)) + endAnchor (job, &saved, 0); } if (tbl->font) @@ -364,6 +415,7 @@ emit_html_img(GVJ_t * job, htmlimg_t * cp, htmlenv_t * env) static void emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) { + htmlmap_data_t saved; box pts = cp->data.box; point p = env->p; int inAnchor, doAnchor = (cp->data.href || cp->data.target); @@ -374,7 +426,7 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) pts.UR.y += p.y; if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST)) - inAnchor = initAnchor(job, &cp->data, pts); + inAnchor = initAnchor(job, &cp->data, pts, &saved, 1); else inAnchor = 0; @@ -385,9 +437,6 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) if (cp->data.border) doBorder(job, cp->data.pencolor, cp->data.border, pts); - if (inAnchor) - gvrender_end_anchor(job); - if (cp->child.kind == HTML_TBL) emit_html_tbl(job, cp->child.u.tbl, env); else if (cp->child.kind == HTML_IMAGE) @@ -395,9 +444,12 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) else emit_html_txt(job, cp->child.u.txt, env); + if (inAnchor) + endAnchor (job, &saved, 1); + if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) { - if (initAnchor(job, &cp->data, pts)) - gvrender_end_anchor(job); + if (initAnchor(job, &cp->data, pts, &saved, 0)) + endAnchor (job, &saved, 0); } } @@ -405,42 +457,59 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env) * Push new obj on stack to be used in common by all * html elements with anchors. * This inherits the type, emit_state, and object of the - * parent. + * parent, as well as the url, explicit, target and tooltip. */ static void allocObj (GVJ_t * job) { obj_state_t *obj; + obj_state_t *parent; obj = push_obj_state(job); - obj->type = obj->parent->type; - obj->emit_state = obj->parent->emit_state; + parent = obj->parent; + obj->type = parent->type; + obj->emit_state = parent->emit_state; switch (obj->type) { case NODE_OBJTYPE : - obj->u.n = obj->parent->u.n; + obj->u.n = parent->u.n; #ifdef WITH_CODEGENS Obj = NODE; #endif break; case ROOTGRAPH_OBJTYPE : - obj->u.g = obj->parent->u.g; + obj->u.g = parent->u.g; #ifdef WITH_CODEGENS Obj = NONE; #endif break; case CLUSTER_OBJTYPE : - obj->u.sg = obj->parent->u.sg; + obj->u.sg = parent->u.sg; #ifdef WITH_CODEGENS Obj = CLST; #endif break; case EDGE_OBJTYPE : - obj->u.e = obj->parent->u.e; + obj->u.e = parent->u.e; #ifdef WITH_CODEGENS Obj = EDGE; #endif break; } + obj->url = parent->url; + obj->tooltip = parent->tooltip; + obj->target = parent->target; + obj->explicit_tooltip = parent->explicit_tooltip; +} + +static void +freeObj (GVJ_t * job) +{ + obj_state_t *obj = job->obj; + + obj->url = NULL; + obj->tooltip = NULL; + obj->target = NULL; + pop_obj_state(job); } /* emit_html_label: @@ -471,7 +540,7 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp) } else { emit_html_txt(job, lp->u.txt, &env); } - pop_obj_state(job); + freeObj (job); } void free_html_font(htmlfont_t * fp) diff --git a/lib/common/input.c b/lib/common/input.c index 9bed14c31..cfe6cae12 100644 --- a/lib/common/input.c +++ b/lib/common/input.c @@ -766,12 +766,15 @@ void do_graph_label(graph_t * sg) /* it would be nice to allow multiple graph labels in the future */ if ((p = agget(sg, "label"))) { char pos_flag; - int html = aghtmlstr(p); + int lbl_kind = LT_NONE; point dpt; pointf dimen; + if (aghtmlstr(p)) lbl_kind = LT_HTML; GD_has_labels(sg->root) |= GRAPH_LABEL; - GD_label(sg) = make_label(sg->root, html, strdup_and_subst_obj(p, (void*)sg), + if (lbl_kind) p = strdup (p); + else p = strdup_and_subst_obj(p, (void*)sg); + GD_label(sg) = make_label(sg->root, lbl_kind, p, late_double(sg, agfindattr(sg, "fontsize"), DEFAULT_FONTSIZE, MIN_FONTSIZE), @@ -781,7 +784,7 @@ void do_graph_label(graph_t * sg) late_nnstring(sg, agfindattr(sg, "fontcolor"), DEFAULT_COLOR)); - if (html) { + if (lbl_kind) { if (make_html_label(sg->root, GD_label(sg), sg) == 1) agerr(AGPREV, "in label of graph %s\n", sg->name); } diff --git a/lib/common/render.h b/lib/common/render.h index 46830f4af..119607d76 100644 --- a/lib/common/render.h +++ b/lib/common/render.h @@ -115,7 +115,7 @@ extern "C" { extern void global_def(char *, Agsym_t * (*fun) (Agraph_t *, char *, char *)); extern int gvRenderJobs (GVC_t * gvc, graph_t * g); - extern void initMapData (GVJ_t*, char*, char*, char*, char*, void*); + extern int initMapData (GVJ_t*, char*, char*, char*, char*, void*); extern boolean isPolygon(node_t *); extern char *strdup_and_subst_obj(char *str, void *obj); extern char *xml_string(char *s); diff --git a/lib/common/shapes.c b/lib/common/shapes.c index 8308b5121..b2e6309de 100644 --- a/lib/common/shapes.c +++ b/lib/common/shapes.c @@ -1312,24 +1312,12 @@ static void poly_gencode(GVJ_t * job, node_t * n) filled = FALSE; } - if (ND_label(n)->html) { - if (doMap && !(job->flags & EMIT_CLUSTERS_LAST)) - gvrender_end_anchor(job); - emit_label(job, EMIT_NLABEL, ND_label(n)); - if (doMap && (job->flags & EMIT_CLUSTERS_LAST)) { + emit_label(job, EMIT_NLABEL, ND_label(n)); + if (doMap) { + if (job->flags & EMIT_CLUSTERS_LAST) gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); - gvrender_end_anchor(job); - } - } - else { - emit_label(job, EMIT_NLABEL, ND_label(n)); - if (doMap) { - if (job->flags & EMIT_CLUSTERS_LAST) - gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); - gvrender_end_anchor(job); - } + gvrender_end_anchor(job); } - } /*=======================end poly======================================*/ @@ -1928,12 +1916,11 @@ static void record_gencode(GVJ_t * job, node_t * n) else gvrender_box(job, BF, style & FILLED); - if (doMap && !(job->flags & EMIT_CLUSTERS_LAST)) - gvrender_end_anchor(job); - gen_fields(job, n, f); - if (doMap && (job->flags & EMIT_CLUSTERS_LAST)) { - gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); + + if (doMap) { + if (job->flags & EMIT_CLUSTERS_LAST) + gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); gvrender_end_anchor(job); } } @@ -2010,11 +1997,13 @@ static void epsf_gencode(GVJ_t * job, node_t * n) { obj_state_t *obj = job->obj; epsf_t *desc; + int doMap = (obj->url || obj->explicit_tooltip); desc = (epsf_t *) (ND_shape_info(n)); if (!desc) return; - if (obj->url || obj->explicit_tooltip) + + if (doMap && !(job->flags & EMIT_CLUSTERS_LAST)) gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); gvrender_begin_context(job); if (desc) @@ -2024,8 +2013,11 @@ static void epsf_gencode(GVJ_t * job, node_t * n) ND_coord_i(n).y + desc->offset.y, desc->macro_id); ND_label(n)->p = ND_coord_i(n); gvrender_end_context(job); - if (obj->url || obj->explicit_tooltip) - gvrender_end_anchor(job); emit_label(job, EMIT_NLABEL, ND_label(n)); + if (doMap) { + if (job->flags & EMIT_CLUSTERS_LAST) + gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target); + gvrender_end_anchor(job); + } } diff --git a/lib/common/utils.c b/lib/common/utils.c index 624488d0d..5ec3a0eac 100644 --- a/lib/common/utils.c +++ b/lib/common/utils.c @@ -716,24 +716,26 @@ chkPort (port (*pf)(node_t*, char*, char*), node_t* n, char* s) int common_init_edge(edge_t * e) { char *s; - int html = 0, r = 0; + int r = 0; struct fontinfo fi; struct fontinfo lfi; graph_t *sg = e->tail->graph; + int lbl_kind; fi.fontname = NULL; lfi.fontname = NULL; if (E_label && (s = agxget(e, E_label->index)) && (s[0])) { r = 1; - html = aghtmlstr(s); - if (html) + if (aghtmlstr(s)) lbl_kind = LT_HTML; + else lbl_kind = LT_NONE; + if (lbl_kind) s = strdup(s); else s = strdup_and_subst_obj(s, (void*)e); initFontEdgeAttr(e, &fi); - ED_label(e) = make_label(sg->root, html, s, + ED_label(e) = make_label(sg->root, lbl_kind, s, fi.fontsize, fi.fontname, fi.fontcolor); - if (html) { + if (lbl_kind == LT_HTML) { if (make_html_label(sg->root, ED_label(e), e) == 1) edgeError(e, "label"); } @@ -745,31 +747,33 @@ int common_init_edge(edge_t * e) /* vladimir */ if (E_headlabel && (s = agxget(e, E_headlabel->index)) && (s[0])) { - html = aghtmlstr(s); - if (html) + if (aghtmlstr(s)) lbl_kind = LT_HTML; + else lbl_kind = LT_NONE; + if (lbl_kind) s = strdup(s); else s = strdup_and_subst_obj(s, (void*)e); initFontLabelEdgeAttr(e, &fi, &lfi); - ED_head_label(e) = make_label(sg->root, html, s, + ED_head_label(e) = make_label(sg->root, lbl_kind, s, lfi.fontsize, lfi.fontname, lfi.fontcolor); - if (html) { + if (lbl_kind) { if (make_html_label(sg->root, ED_head_label(e), e) == 1) edgeError(e, "head label"); } GD_has_labels(sg) |= HEAD_LABEL; } if (E_taillabel && (s = agxget(e, E_taillabel->index)) && (s[0])) { - html = aghtmlstr(s); - if (html) + if (aghtmlstr(s)) lbl_kind = LT_HTML; + else lbl_kind = LT_NONE; + if (lbl_kind) s = strdup(s); else s = strdup_and_subst_obj(s, (void*)e); if (!lfi.fontname) initFontLabelEdgeAttr(e, &fi, &lfi); - ED_tail_label(e) = make_label(sg->root, html, s, + ED_tail_label(e) = make_label(sg->root, lbl_kind, s, lfi.fontsize, lfi.fontname, lfi.fontcolor); - if (html) { + if (lbl_kind) { if (make_html_label(sg->root, ED_tail_label(e), e) == 1) edgeError(e, "tail label"); } diff --git a/lib/gvc/gvcjob.h b/lib/gvc/gvcjob.h index e56adc623..6f935231f 100644 --- a/lib/gvc/gvcjob.h +++ b/lib/gvc/gvcjob.h @@ -171,20 +171,30 @@ extern "C" { char *headlabel; char *url; /* if GVRENDER_DOES_MAPS */ + char *labelurl; char *tailurl; char *headurl; char *tooltip; /* if GVRENDER_DOES_TOOLTIPS */ + char *labeltooltip; char *tailtooltip; char *headtooltip; - boolean explicit_tooltip; - boolean explicit_tailtooltip; - boolean explicit_headtooltip; char *target; /* if GVRENDER_DOES_TARGETS */ + char *labeltarget; char *tailtarget; char *headtarget; + int explicit_tooltip:1; + int explicit_tailtooltip:1; + int explicit_headtooltip:1; + int explicit_labeltooltip:1; + int explicit_tailtarget:1; + int explicit_headtarget:1; + int explicit_edgetarget:1; + int explicit_tailurl:1; + int explicit_headurl:1; + /* primary mapped region - node shape, edge labels */ map_shape_t url_map_shape; int url_map_n; /* number of points for url map if GVRENDER_DOES_MAPS */