/*
This software may only be used by you under license from AT&T Corp.
("AT&T"). A copy of AT&T's Source Code Agreement is available at
AT&T's Internet website having the URL:
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
If you received this software without first entering into a license
with AT&T, you have an infringing copy of this software and cannot use
it without violating AT&T's intellectual property rights.
*/
#pragma prototyped
#include "render.h"
#include "gd.h"
/* IMAP font modifiers */
#define REGULAR 0
#define BOLD 1
#define ITALIC 2
/* IMAP patterns */
#define P_SOLID 0
#define P_NONE 15
#define P_DOTTED 4 /* i wasn't sure about this */
#define P_DASHED 11 /* or this */
#define SCALE (GD_RESOLUTION/72.0)
/* IMAP bold line constant */
#define WIDTH_NORMAL 1
#define WIDTH_BOLD 3
/* static int N_pages; */
/* static point Pages; */
static double ArgScale;
static double Scale;
static int Rot;
static int onetime = TRUE;
typedef struct context_t {
char color_ix, *fontfam, fontopt, font_was_set;
char pen, fill, penwidth, style_was_set;
double fontsz;
} context_t;
#define MAXNEST 4
static context_t cstk[MAXNEST];
static int SP;
void
map_output_rect (pointf p1, pointf p2, char *url, char *label, char *tooltip)
{
pointf pp1,pp2;
double t;
if (!(url && url[0])) return;
/* apply scaling and translation if necessary */
if (Output_lang == IMAP || Output_lang == ISMAP || Output_lang == CMAP) {
pp1 = gdpt(p1);
pp2 = gdpt(p2);
} else {
pp1 = p1;
pp2 = p2;
}
/* fix up coordinate order */
if (pp2.x < pp1.x) {
t = pp2.x;
pp2.x = pp1.x;
pp1.x = t;
}
if (pp2.y < pp1.y) {
t = pp2.y;
pp2.y = pp1.y;
pp1.y = t;
}
if (Output_lang == IMAP) {
fprintf(Output_file,"rect %s %d,%d %d,%d\n",
url,
ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y));
} else if (Output_lang == ISMAP) {
fprintf(Output_file,"rectangle (%d,%d) (%d,%d) %s %s\n",
ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y),
url,label);
} else if (Output_lang == CMAP) {
fprintf(Output_file,"<area shape=\"rect\" href=\"%s\"",
xml_string(url));
if (tooltip && tooltip[0]) {
fprintf(Output_file," title=\"%s\"", xml_string(tooltip));
}
if (label && label[0]) {
fprintf(Output_file," alt=\"%s\"", xml_string(label));
}
fprintf(Output_file," coords=\"%d,%d,%d,%d\">\n",
ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y));
} else if (Output_lang == POSTSCRIPT || Output_lang == PDF) {
fprintf(Output_file,"[ /Rect [ %d %d %d %d ]\n"
" /Border [ 0 0 0 ]\n"
" /Action << /Subtype /URI /URI %s >>\n"
" /Subtype /Link\n"
"/ANN pdfmark\n",
ROUND(pp1.x),ROUND(pp1.y),ROUND(pp2.x),ROUND(pp2.y),
ps_string(url));
}
}
/* radius of mouse-sensitive region around a point */
#define FUZZ 3
void
map_output_fuzzy_point (pointf p, char *url, char *label, char *tooltip)
{
pointf p1, p2;
p1.x = p.x - FUZZ;
p1.y = p.y - FUZZ;
p2.x = p.x + FUZZ;
p2.y = p.y + FUZZ;
map_output_rect(p1, p2, url, label, tooltip);
}
static void
map_reset(void)
{
onetime = TRUE;
}
static void
init_imap(void)
{
SP = 0;
cstk[0].color_ix = 0; /* IMAP color index 0-7 */
cstk[0].fontfam = "Times"; /* font family name */
cstk[0].fontopt = REGULAR; /* modifier: REGULAR, BOLD or ITALIC */
cstk[0].pen = P_SOLID; /* pen pattern style, default is sold */
cstk[0].fill = P_NONE;
cstk[0].penwidth = WIDTH_NORMAL;
}
static void map_font(context_t* cp) { }
static void map_color(int i) { }
static void map_style(context_t* cp) { }
static void
map_begin_job(FILE *ofp, graph_t *g, char **lib, char *user, char *info[], point pages)
{
/* Pages = pages; */
/* N_pages = pages.x * pages.y; */
if (Output_lang == IMAP) {
fprintf(Output_file,"base referer\n");
} else if (Output_lang == ISMAP) {
/* fprintf(Output_file,"base referer\n"); */
} else if (Output_lang == CMAP) {
/* fprintf(Output_file,"base referer\n"); */
} else if (Output_lang == POSTSCRIPT || Output_lang == PDF) {
/* fprintf(Output_file,"base referer\n"); */
}
}
static void map_end_job(void) { }
static void
map_begin_graph(graph_t* g, box bb, point pb)
{
gd_begin_graph(g, bb, pb);
if (onetime) {
init_imap();
onetime = FALSE;
}
}
static pointf Default_p1,Default_p2;
static char *Default_URL, *Default_label;
static void
map_begin_page(graph_t *g, point page, double scale, int rot, point offset)
{
char *s;
ArgScale = scale;
Scale = scale * SCALE;
Rot = rot;
gd_begin_page(g, page, scale, rot, offset);
Default_URL = NULL;
if ((s = agget(g, "URL")) && strlen(s)) {
if (Output_lang == IMAP) {
fprintf(Output_file,"default %s\n",s);
} else if (Output_lang == ISMAP) {
fprintf(Output_file,"default %s %s\n",s,g->name);
} else if (Output_lang == CMAP) {
Default_URL = strdup_and_subst_graph(s,g);
Default_label = g->name;
Default_p1.x = GD_bb(g).LL.x;
Default_p1.y = GD_bb(g).LL.y;
Default_p2.x = GD_bb(g).UR.x;
Default_p2.y = GD_bb(g).UR.y;
}
}
}
static void map_end_page(void) {
if (Default_URL) {
map_output_rect(Default_p1,Default_p2,Default_URL,Default_label,"");
free(Default_URL);
}
}
static void map_end_graph(void) { }
void
map_begin_cluster(graph_t* g)
{
char *s, *t="";
pointf p1,p2;
if ((s = agget(g, "URL")) && strlen(s)) {
if (GD_label(g) != NULL) t=GD_label(g)->text;
p1.x = GD_bb(g).LL.x;
p1.y = GD_bb(g).LL.y;
p2.x = GD_bb(g).UR.x;
p2.y = GD_bb(g).UR.y;
s = strdup_and_subst_graph(s,g);
map_output_rect(p1,p2,s,t,t);
free(s);
}
}
static void map_end_cluster(void) { }
static void map_begin_nodes(void) { }
static void map_end_nodes(void) { }
static void map_begin_edges(void) { }
static void map_end_edges(void) { }
void
map_begin_node(node_t* n)
{
char *url=NULL, *tooltip=NULL;
char *m_tooltip=NULL;
pointf p1,p2;
if ((url = agget(n, "URL")) && url[0]) {
p1.x = ND_coord_i(n).x - ND_lw_i(n);
p1.y = ND_coord_i(n).y - (ND_ht_i(n)/2);
p2.x = ND_coord_i(n).x + ND_rw_i(n);
p2.y = ND_coord_i(n).y + (ND_ht_i(n)/2);
url = strdup_and_subst_node(url,n);
if ((tooltip = agget(n, "tooltip")) && tooltip[0]) {
m_tooltip = tooltip = strdup_and_subst_node(tooltip,n);
}
else {
tooltip = ND_label(n)->text;
}
map_output_rect(p1,p2,url,ND_label(n)->text,tooltip);
if (m_tooltip) free(m_tooltip);
free(url);
}
}
static void map_end_node(void) { }
void
map_begin_edge(edge_t* e)
{
/* strings */
char *label=NULL, *taillabel=NULL, *headlabel=NULL;
char *url=NULL, *headurl=NULL, *tailurl=NULL;
char *tooltip=NULL, *tailtooltip=NULL, *headtooltip=NULL;
/* malloc flags for strings */
char *m_url=NULL, *m_headurl=NULL, *m_tailurl=NULL;
char *m_tooltip=NULL, *m_tailtooltip=NULL, *m_headtooltip=NULL;
textlabel_t *lab=NULL, *tlab=NULL, *hlab=NULL;
pointf p,p1,p2;
bezier bz;
/* establish correct text for main edge label, URL, tooltip */
if ((lab=ED_label(e))) {
label = lab->text;
} else {
label = "";
}
if ((url = agget(e, "URL")) && url[0]) {
m_url = url = strdup_and_subst_edge(url,e);
if ((tooltip = agget(e, "tooltip")) && tooltip[0]) {
m_tooltip = tooltip = strdup_and_subst_edge(tooltip,e);
} else {
tooltip = label;
}
} else {
tooltip = "";
}
/* establish correct text for tail label, URL, tooltip */
if ((tlab=ED_tail_label(e))) {
taillabel = tlab->text;
} else {
taillabel=label;
}
if ((tailurl = agget(e, "tailURL")) && tailurl[0]) {
m_tailurl = tailurl = strdup_and_subst_edge(tailurl,e);
if ((tailtooltip = agget(e, "tailtooltip")) && tailtooltip[0]) {
m_tailtooltip = tailtooltip = strdup_and_subst_edge(tailtooltip,e);
} else {
tailtooltip = taillabel;
}
} else if (url) {
tailurl = url;
tailtooltip = tooltip;
}
/* establish correct text for head label, URL, tooltip */
if ((hlab=ED_head_label(e))) {
headlabel = hlab->text;
} else {
headlabel = label;
}
if ((headurl = agget(e, "headURL")) && headurl[0]) {
m_headurl = headurl = strdup_and_subst_edge(headurl,e);
if ((headtooltip = agget(e, "headtooltip")) && headtooltip[0]) {
m_headtooltip = headtooltip = strdup_and_subst_edge(headtooltip,e);
} else {
headtooltip = headlabel;
}
} else if (url) {
headurl = url;
headtooltip = tooltip;
}
/* strings are now set - next we map the three labels */
if (lab && url) {
/* map a rectangle around the edge label */
p1.x = lab->p.x - lab->dimen.x*64/2;
p1.y = lab->p.y - lab->dimen.y*64/2;
p2.x = lab->p.x + lab->dimen.x*64/2;
p2.y = lab->p.y + lab->dimen.y*64/2;
map_output_rect(p1,p2,url,label,tooltip);
}
if (tlab && (url || tailurl)) {
/* map a rectangle around the edge taillabel */
p1.x = tlab->p.x - tlab->dimen.x*64/2;
p1.y = tlab->p.y - tlab->dimen.y*64/2;
p2.x = tlab->p.x + tlab->dimen.x*64/2;
p2.y = tlab->p.y + tlab->dimen.y*64/2;
map_output_rect(p1,p2,tailurl,taillabel,tailtooltip);
}
if (hlab && (url || headurl)) {
/* map a rectangle around the edge headlabel */
p1.x = hlab->p.x - hlab->dimen.x*64/2;
p1.y = hlab->p.y - hlab->dimen.y*64/2;
p2.x = hlab->p.x + hlab->dimen.x*64/2;
p2.y = hlab->p.y + hlab->dimen.y*64/2;
map_output_rect(p1,p2,headurl,headlabel,headtooltip);
}
#if 0
# FIXME - what is this supposed to do? Perhaps map spline control points?
if (ED_spl(e) && url) {
int i,j;
for (i = 0; i < ED_spl(e)->size; i++) {
bz = ED_spl(e)->list[i];
for (j = 0; j < bz.size; j +=3) {
if (((i == 0) && (j == 0)) /* origin */
|| ((i == (ED_spl(e)->size -1)) && (j == (bz.size - 1)))) {
continue;
}
p.x = bz.list[j].x;
p.y = bz.list[j].y;
map_output_fuzzy_point(p, url, ED_label(e)->text);
}
}
}
#endif
/* finally we map the two ends of the edge where they touch nodes */
/* process intersecion with tail node */
if (ED_spl(e) && (url || tailurl)) {
bz = ED_spl(e)->list[0];
if (bz.sflag) {
/* Arrow at start of splines */
p.x = bz.sp.x;
p.y = bz.sp.y;
} else {
/* No arrow at start of splines */
p.x = bz.list[0].x;
p.y = bz.list[0].y;
}
map_output_fuzzy_point(p, tailurl, taillabel, tailtooltip);
}
/* process intersection with head node */
if (ED_spl(e) && (url || headurl)) {
bz = ED_spl(e)->list[ED_spl(e)->size-1];
if (bz.eflag) {
/* Arrow at end of splines */
p.x = bz.ep.x;
p.y = bz.ep.y;
} else {
/* No arrow at end of splines */
p.x = bz.list[bz.size-1].x;
p.y = bz.list[bz.size-1].y;
}
map_output_fuzzy_point(p, headurl, headlabel, headtooltip);
}
if (m_url) free(m_url);
if (m_tailurl) free(m_tailurl);
if (m_headurl) free(m_headurl);
if (m_tooltip) free(m_tooltip);
if (m_tailtooltip) free(m_tailtooltip);
if (m_headtooltip) free(m_headtooltip);
}
static void map_end_edge(void) { }
static void
map_begin_context(void)
{
assert(SP + 1 < MAXNEST);
cstk[SP + 1] = cstk[SP];
SP++;
}
static void
map_end_context(void)
{
int c, psp = SP - 1;
assert(SP > 0);
if (cstk[SP].color_ix != (c = cstk[psp].color_ix))
map_color(c);
if (cstk[SP].font_was_set)
map_font(&(cstk[psp]));
if (cstk[SP].style_was_set)
map_style(&(cstk[psp]));
/* free(cstk[psp].fontfam); */
SP = psp;
}
static void
map_set_font(char* name, double size) { }
static void
map_set_color(char* name) { }
static void
map_set_style(char** s) { }
static void
map_textline(point p, textline_t *line) { }
static void
map_bezier(point* A, int n, int arrow_at_start, int arrow_at_end) { }
static void
map_polygon(point *A, int n, int filled) { }
static void
map_ellipse(point p, int rx, int ry, int filled) { }
static void
map_polyline(point* A, int n) { }
static void
map_user_shape(char *name, point *A,int n, int filled) { }
codegen_t IMAP_CodeGen = {
map_reset,
map_begin_job, map_end_job,
map_begin_graph, map_end_graph,
map_begin_page, map_end_page,
map_begin_cluster, map_end_cluster,
map_begin_nodes, map_end_nodes,
map_begin_edges, map_end_edges,
map_begin_node, map_end_node,
map_begin_edge, map_end_edge,
map_begin_context, map_end_context,
map_set_font, map_textline,
map_set_color, map_set_color, map_set_style,
map_ellipse, map_polygon,
map_bezier, map_polyline,
0 /* map_arrowhead */, map_user_shape,
0 /* map_comment */, gd_textsize
};
codegen_t ISMAP_CodeGen = {
map_reset,
map_begin_job, map_end_job,
map_begin_graph, map_end_graph,
map_begin_page, map_end_page,
map_begin_cluster, map_end_cluster,
map_begin_nodes, map_end_nodes,
map_begin_edges, map_end_edges,
map_begin_node, map_end_node,
map_begin_edge, map_end_edge,
map_begin_context, map_end_context,
map_set_font, map_textline,
map_set_color, map_set_color, map_set_style,
map_ellipse, map_polygon,
map_bezier, map_polyline,
0 /* map_arrowhead */, map_user_shape,
0 /* map_comment */, gd_textsize
};
codegen_t CMAP_CodeGen = {
map_reset,
map_begin_job, map_end_job,
map_begin_graph, map_end_graph,
map_begin_page, map_end_page,
map_begin_cluster, map_end_cluster,
map_begin_nodes, map_end_nodes,
map_begin_edges, map_end_edges,
map_begin_node, map_end_node,
map_begin_edge, map_end_edge,
map_begin_context, map_end_context,
map_set_font, map_textline,
map_set_color, map_set_color, map_set_style,
map_ellipse, map_polygon,
map_bezier, map_polyline,
0 /* map_arrowhead */, map_user_shape,
0 /* map_comment */, gd_textsize
};
|