xdot* xd = NULL;
if ((p = agget(g, "_draw_")) && p[0]) {
+#define DEBUG 1
#ifdef DEBUG
if (Verbose) {
start_timer();
return assigned;
}
+/* genObjId:
+ * Use id of root graph if any, plus kind and internal id of object
+ */
+char*
+getObjId (GVJ_t* job, void* obj, agxbuf* xb)
+{
+ char* id;
+ graph_t* root = job->gvc->g;
+ char* gid = GD_drawing(root)->id;
+ long idnum;
+ char* pfx;
+ char buf[30]; /* large enough for decimal 64-bit int */
+
+ id = agget(obj, "id");
+ if (id && *id)
+ return id;
+
+ switch (agobjkind(obj)) {
+#ifndef WITH_CGRAPH
+ case AGGRAPH:
+ idnum = ((graph_t*)obj)->meta_node->id;
+#else
+ case AGRAPH:
+ idnum = AGID((graph_t*)obj);
+#endif
+ pfx = "graph";
+ break;
+ case AGNODE:
+ idnum = AGID((node_t*)obj);
+ pfx = "node";
+ break;
+ case AGEDGE:
+ idnum = AGID((edge_t*)obj);
+ pfx = "edge";
+ break;
+ }
+
+ if (gid) {
+ agxbput (xb, gid);
+ agxbputc (xb, '_');
+ }
+ agxbput (xb, pfx);
+ sprintf (buf, "%ld", idnum);
+ agxbput (xb, buf);
+
+ return agxbuse(xb);
+}
+
static void
-initObjMapData (GVJ_t* job, textlabel_t *lab, char *otyp, long int idnum, void* gobj)
+initObjMapData (GVJ_t* job, textlabel_t *lab, void* gobj)
{
char* lbl;
char* url = agget(gobj, "href");
char* tooltip = agget(gobj, "tooltip");
char* target = agget(gobj, "target");
- char* id = agget(gobj, "id");
- char buf[50];
+ char* id;
+ unsigned char buf[SMALLBUF];
+ agxbuf xb;
+
+ agxbinit(&xb, SMALLBUF, buf);
if (lab) lbl = lab->text;
else lbl = NULL;
if (!url || !*url) /* try URL as an alias for href */
url = agget(gobj, "URL");
- if (!id || !*id) { /* no external id, so use the internal one */
- sprintf(buf, "%s%ld", otyp, idnum);
- id = buf;
- }
+ id = getObjId (job, gobj, &xb);
initMapData (job, lbl, url, tooltip, target, id, gobj);
+
+ agxbfree(&xb);
}
static void map_point(GVJ_t *job, pointf pf)
else
obj->z = 0.0;
}
- initObjMapData (job, ND_label(n), "node", AGID(n), n);
+ initObjMapData (job, ND_label(n), n);
if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS))
&& (obj->url || obj->explicit_tooltip)) {
{
obj_state_t *obj;
int flags = job->flags;
- char *s, buf[50];
+ char *s;
textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL;
pointf *pbs = NULL;
int i, nump, *pbs_n = NULL, pbs_poly_n = 0;
}
if (flags & GVRENDER_DOES_MAPS) {
- s = agget(e, "id");
- if (!s || !*s) { /* no external id, so use the internal one */
-#ifndef WITH_CGRAPH
- sprintf(buf,"edge%d", AGID(e));
-#else
- sprintf(buf,"edge%ld", AGID(e));
-#endif
- s = buf;
- }
+ agxbuf xb;
+ unsigned char xbuf[SMALLBUF];
+
+ agxbinit(&xb, SMALLBUF, xbuf);
+ s = getObjId (job, e, &xb);
obj->id = strdup_and_subst_obj(s, (void*)e);
+ agxbfree(&xb);
+
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->u.g = g;
obj->emit_state = EMIT_GDRAW;
-#ifndef WITH_CGRAPH
- initObjMapData (job, GD_label(g), "graph", g->meta_node->id, g);
-#else
- initObjMapData (job, GD_label(g), "graph", AGID(g), g);
-#endif
+ initObjMapData (job, GD_label(g), g);
gvrender_begin_graph(job, g);
}
obj->u.sg = sg;
obj->emit_state = EMIT_CDRAW;
-#ifndef WITH_CGRAPH
- initObjMapData (job, GD_label(sg), "graph", sg->meta_node->id, sg);
-#else
- initObjMapData (job, GD_label(sg), "graph", AGID(sg), sg);
-#endif
+ initObjMapData (job, GD_label(sg), sg);
gvrender_begin_cluster(job, sg);
}
return 0;
}
+static int idfn(htmldata_t * p, char *v)
+{
+ p->id = strdup(v);
+ return 0;
+}
+
/* doInt:
* Scan v for integral value. Check that
* the value is >= min and <= max. Return value in ul.
{"fixedsize", (attrFn) fixedsizefn},
{"height", (attrFn) heightfn},
{"href", (attrFn) hreffn},
+ {"id", (attrFn) idfn},
{"port", (attrFn) portfn},
{"target", (attrFn) targetfn},
{"title", (attrFn) titlefn},
{"fixedsize", (attrFn) fixedsizefn},
{"height", (attrFn) heightfn},
{"href", (attrFn) hreffn},
+ {"id", (attrFn) idfn},
{"port", (attrFn) portfn},
{"rowspan", (attrFn) rowspanfn},
{"target", (attrFn) targetfn},
void *obj;
graph_t *g;
char* imgscale;
+ char* objid;
+ boolean objid_set;
} htmlenv_t;
typedef struct {
char *url;
char *tooltip;
char *target;
+ char *id;
boolean explicit_tooltip;
point LL;
point UR;
* Initialize fields in job->obj pertaining to anchors.
* In particular, this also sets the output rectangle.
* If there is something to do, close current anchor if
- * necesary, start the anchor and returns 1.
+ * necessary, 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, boxf b, htmlmap_data_t* save,
+initAnchor (GVJ_t* job, htmlenv_t* env, htmldata_t* data, boxf b, htmlmap_data_t* save,
int closePrev)
{
obj_state_t *obj = job->obj;
int changed;
+ char* id;
+ static int anchorId;
+ int internalId = 0;
+ agxbuf xb;
+ char intbuf[30]; /* hold 64-bit decimal integer */
+ unsigned char buf[SMALLBUF];
save->url = obj->url;
save->tooltip = obj->tooltip;
save->target = obj->target;
+ save->id = obj->id;
save->explicit_tooltip = obj->explicit_tooltip;
- changed = initMapData (job, NULL, data->href, data->title, data->target, "\\N", obj->u.g);
+ id = data->id;
+ if (!id || !*id) { /* no external id, so use the internal one */
+ agxbinit(&xb, SMALLBUF, buf);
+ if (!env->objid) {
+ env->objid = strdup (getObjId (job, obj->u.n, &xb));
+ env->objid_set = 1;
+ }
+ agxbput (&xb, env->objid);
+ sprintf (intbuf, "_%d", anchorId++);
+ agxbput (&xb, intbuf);
+ id = agxbuse (&xb);
+ internalId = 1;
+ }
+ changed = initMapData (job, NULL, data->href, data->title, data->target, id, obj->u.g);
+ if (internalId)
+ agxbfree (&xb);
if (changed) {
if (closePrev && (save->url || save->explicit_tooltip))
RESET(url);
RESET(tooltip);
RESET(target);
+ RESET(id);
obj->explicit_tooltip = save->explicit_tooltip;
if (openPrev && (obj->url || obj->explicit_tooltip))
gvrender_begin_anchor(job,
pts.UR.y += pos.y;
if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
- anchor = initAnchor(job, &tbl->data, pts, &saved, 1);
+ anchor = initAnchor(job, env, &tbl->data, pts, &saved, 1);
else
anchor = 0;
endAnchor (job, &saved, 1);
if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
- if (initAnchor(job, &tbl->data, pts, &saved, 0))
+ if (initAnchor(job, env, &tbl->data, pts, &saved, 0))
endAnchor (job, &saved, 0);
}
pts.UR.y += pos.y;
if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
- inAnchor = initAnchor(job, &cp->data, pts, &saved, 1);
+ inAnchor = initAnchor(job, env, &cp->data, pts, &saved, 1);
else
inAnchor = 0;
endAnchor (job, &saved, 1);
if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
- if (initAnchor(job, &cp->data, pts, &saved, 0))
+ if (initAnchor(job, env, &cp->data, pts, &saved, 0))
endAnchor (job, &saved, 0);
}
}
obj->url = NULL;
obj->tooltip = NULL;
obj->target = NULL;
+ obj->id = NULL;
pop_obj_state(job);
}
env.finfo.size = tp->fontsize;
env.finfo.size = tp->fontsize;
env.imgscale = agget (job->obj->u.n, "imagescale");
+ env.objid = job->obj->id;
+ env.objid_set = 0;
if ((env.imgscale == NULL) || (env.imgscale[0] == '\0'))
env.imgscale = "false";
if (lp->kind == HTML_TBL) {
} else {
emit_html_txt(job, lp->u.txt, &env);
}
+ if (env.objid_set)
+ free (env.objid);
freeObj (job);
}
free(dp->href);
free(dp->port);
free(dp->target);
+ free(dp->id);
free(dp->title);
free(dp->bgcolor);
free(dp->pencolor);
char *port;
char *target;
char *title;
+ char *id;
char *bgcolor;
char *pencolor;
signed char space;
/* background */
GD_drawing(g)->xdots = init_xdot (g);
+
+ /* initialize id, if any */
+
+ if ((p = agget(g, "id")) && *p)
+ GD_drawing(g)->id = strdup_and_subst_obj(p, g);
}
void graph_cleanup(graph_t *g)
{
if (GD_drawing(g)->xdots)
freeXDot ((xdot*)GD_drawing(g)->xdots);
+ if (GD_drawing(g)->id)
+ free (GD_drawing(g)->id);
free(GD_drawing(g));
GD_drawing(g) = NULL;
free_label(GD_label(g));
extern void dotneato_write(GVC_t * gvc, graph_t *g);
extern void dotneato_write_one(GVC_t * gvc, graph_t *g);
extern void emit_clusters(GVJ_t * job, Agraph_t * g, int flags);
+ extern char* getObjId (GVJ_t* job, void* obj, agxbuf* xb);
/* extern void emit_begin_edge(GVJ_t * job, edge_t * e, char**); */
/* extern void emit_end_edge(GVJ_t * job); */
extern void emit_graph(GVJ_t * job, graph_t * g);
boolean centered;
ratio_t ratio_kind;
void* xdots;
+ char* id;
} layout_t;
/* for "record" shapes */