/* place_root_label: * Set position of root graph label. * Note that at this point, after translate_drawing, a * flipped drawing has been transposed, so we don't have * to worry about switching x and y. */ static void place_root_label(graph_t * g, point d) { point p; if (GD_label_pos(g) & LABEL_AT_RIGHT) { p.x = GD_bb(g).UR.x - d.x / 2; } else if (GD_label_pos(g) & LABEL_AT_LEFT) { p.x = GD_bb(g).LL.x + d.x / 2; } else { p.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2; } if (GD_label_pos(g) & LABEL_AT_TOP) { p.y = GD_bb(g).UR.y - d.y / 2; } else { p.y = GD_bb(g).LL.y + d.y / 2; } GD_label(g)->p = p; GD_label(g)->set = TRUE; }
/* do_graph_label: * Set characteristics of graph label if it exists. * */ void do_graph_label(graph_t * sg) { char *str, *pos, *just; int pos_ix; /* it would be nice to allow multiple graph labels in the future */ if ((str = agget(sg, "label")) && (*str != '\0')) { char pos_flag; pointf dimen; GD_has_labels(sg->root) |= GRAPH_LABEL; GD_label(sg) = make_label((void*)sg, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), late_double(sg, agfindgraphattr(sg, "fontsize"), DEFAULT_FONTSIZE, MIN_FONTSIZE), late_nnstring(sg, agfindgraphattr(sg, "fontname"), DEFAULT_FONTNAME), late_nnstring(sg, agfindgraphattr(sg, "fontcolor"), DEFAULT_COLOR)); /* set label position */ pos = agget(sg, "labelloc"); if (sg != agroot(sg)) { if (pos && (pos[0] == 'b')) pos_flag = LABEL_AT_BOTTOM; else pos_flag = LABEL_AT_TOP; } else { if (pos && (pos[0] == 't')) pos_flag = LABEL_AT_TOP; else pos_flag = LABEL_AT_BOTTOM; } just = agget(sg, "labeljust"); if (just) { if (just[0] == 'l') pos_flag |= LABEL_AT_LEFT; else if (just[0] == 'r') pos_flag |= LABEL_AT_RIGHT; } GD_label_pos(sg) = pos_flag; if (sg == agroot(sg)) return; /* Set border information for cluster labels to allow space */ dimen = GD_label(sg)->dimen; PAD(dimen); if (!GD_flip(agroot(sg))) { if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = TOP_IX; else pos_ix = BOTTOM_IX; GD_border(sg)[pos_ix] = dimen; } else { /* when rotated, the labels will be restored to TOP or BOTTOM */ if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = RIGHT_IX; else pos_ix = LEFT_IX; GD_border(sg)[pos_ix].x = dimen.y; GD_border(sg)[pos_ix].y = dimen.x; } } }
/* gv_postprocess: * Set graph and cluster label positions. * Add space for root graph label and translate graph accordingly. * Set final nodesize using ns. * Assumes the boxes of all clusters have been computed. * When done, the bounding box of g has LL at origin. */ void gv_postprocess(Agraph_t * g, int allowTranslation) { double diff; pointf dimen = { 0., 0. }; Rankdir = GD_rankdir(g); Flip = GD_flip(g); /* Handle cluster labels */ if (Flip) place_flip_graph_label(g); else place_graph_label(g); /* Everything has been placed except the root graph label, if any. * The graph positions have not yet been rotated back if necessary. */ addXLabels(g); /* Add space for graph label if necessary */ if (GD_label(g) && !GD_label(g)->set) { dimen = GD_label(g)->dimen; PAD(dimen); if (Flip) { if (GD_label_pos(g) & LABEL_AT_TOP) { GD_bb(g).UR.x += dimen.y; } else { GD_bb(g).LL.x -= dimen.y; } if (dimen.x > (GD_bb(g).UR.y - GD_bb(g).LL.y)) { diff = dimen.x - (GD_bb(g).UR.y - GD_bb(g).LL.y); diff = diff / 2.; GD_bb(g).LL.y -= diff; GD_bb(g).UR.y += diff; } } else { if (GD_label_pos(g) & LABEL_AT_TOP) { if (Rankdir == RANKDIR_TB) GD_bb(g).UR.y += dimen.y; else GD_bb(g).LL.y -= dimen.y; } else { if (Rankdir == RANKDIR_TB) GD_bb(g).LL.y -= dimen.y; else GD_bb(g).UR.y += dimen.y; } if (dimen.x > (GD_bb(g).UR.x - GD_bb(g).LL.x)) { diff = dimen.x - (GD_bb(g).UR.x - GD_bb(g).LL.x); diff = diff / 2.; GD_bb(g).LL.x -= diff; GD_bb(g).UR.x += diff; } } } if (allowTranslation) { switch (Rankdir) { case RANKDIR_TB: Offset = GD_bb(g).LL; break; case RANKDIR_LR: Offset = pointfof(-GD_bb(g).UR.y, GD_bb(g).LL.x); break; case RANKDIR_BT: Offset = pointfof(GD_bb(g).LL.x, -GD_bb(g).UR.y); break; case RANKDIR_RL: Offset = pointfof(GD_bb(g).LL.y, GD_bb(g).LL.x); break; } translate_drawing(g); } if (GD_label(g) && !GD_label(g)->set) place_root_label(g, dimen); if (Show_boxes) { char buf[BUFSIZ]; if (Flip) sprintf(buf, M2, Offset.x, Offset.y, Offset.x, Offset.y); else sprintf(buf, M1, Offset.y, Offset.x, Offset.y, Offset.x, -Offset.x, -Offset.y); Show_boxes[0] = strdup(buf); } }
/* do_graph_label: * If the ifdef'ed parts are added, clusters are guaranteed not * to overlap and have sufficient room for the label. The problem * is this approach does not use the actual size of the cluster, so * the resulting cluster tends to be far too large. */ void do_graph_label(graph_t* sg) { char *p, *pos, *just; int pos_ix; GVC_t *gvc = GD_gvc(sg->root); /* it would be nice to allow multiple graph labels in the future */ if ((p = agget(sg,"label"))) { char pos_flag; int html = aghtmlstr(p); GD_has_labels(sg->root) |= GRAPH_LABEL; GD_label(sg) = make_label(gvc, html,strdup_and_subst_graph(p,sg), late_double(sg,agfindattr(sg,"fontsize"),DEFAULT_FONTSIZE,MIN_FONTSIZE), late_nnstring(sg,agfindattr(sg,"fontname"),DEFAULT_FONTNAME), late_nnstring(sg,agfindattr(sg,"fontcolor"),DEFAULT_COLOR),sg); if (html) { if (make_html_label(gvc, GD_label(sg), sg)) agerr (AGPREV, "in label of graph %s\n", sg->name); } /* set label position */ pos = agget(sg,"labelloc"); if (sg != sg->root) { if (pos && (pos[0] == 'b')) pos_flag = LABEL_AT_BOTTOM; else pos_flag = LABEL_AT_TOP; } else { if (pos && (pos[0] == 't')) pos_flag = LABEL_AT_TOP; else pos_flag = LABEL_AT_BOTTOM; } just = agget(sg,"labeljust"); if (just) { if (just[0] == 'l') pos_flag |= LABEL_AT_LEFT; else if (just[0] == 'r') pos_flag |= LABEL_AT_RIGHT; } GD_label_pos(sg) = pos_flag; if(!GD_left_to_right(sg->root)) { point dpt; dpt = cvt2pt(GD_label(sg)->dimen); if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = TOP_IX; else pos_ix = BOTTOM_IX; GD_border(sg)[pos_ix] = dpt; #if 0 if(g != g->root) { GD_border(g)[LEFT_IX].x = dpt.x/2; GD_border(g)[RIGHT_IX].x = dpt.x/2; GD_border(g)[LEFT_IX].y = 0; GD_border(g)[RIGHT_IX].y = 0; } #endif } else { point dpt; dpt = cvt2pt(GD_label(sg)->dimen); /* when rotated, the labels will be restored to TOP or BOTTOM */ if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = RIGHT_IX; else pos_ix = LEFT_IX; GD_border(sg)[pos_ix].x = dpt.y; GD_border(sg)[pos_ix].y = dpt.x; #if 0 if(g != g->root) { GD_border(g)[TOP_IX].y = dpt.x/2; GD_border(g)[BOTTOM_IX].y = dpt.x/2; GD_border(g)[TOP_IX].x = 0; GD_border(g)[BOTTOM_IX].x = 0; } #endif } } }
/* do_graph_label: * Set characteristics of graph label if it exists. * */ void do_graph_label(graph_t * sg) { char *p, *pos, *just; int pos_ix; /* it would be nice to allow multiple graph labels in the future */ if ((p = agget(sg, "label"))) { char pos_flag; int lbl_kind = LT_NONE; point dpt; pointf dimen; if (aghtmlstr(p)) lbl_kind = LT_HTML; GD_has_labels(sg->root) |= GRAPH_LABEL; 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), late_nnstring(sg, agfindattr(sg, "fontname"), DEFAULT_FONTNAME), late_nnstring(sg, agfindattr(sg, "fontcolor"), DEFAULT_COLOR)); if (lbl_kind) { if (make_html_label(sg->root, GD_label(sg), sg) == 1) agerr(AGPREV, "in label of graph %s\n", sg->name); } /* set label position */ pos = agget(sg, "labelloc"); if (sg != sg->root) { if (pos && (pos[0] == 'b')) pos_flag = LABEL_AT_BOTTOM; else pos_flag = LABEL_AT_TOP; } else { if (pos && (pos[0] == 't')) pos_flag = LABEL_AT_TOP; else pos_flag = LABEL_AT_BOTTOM; } just = agget(sg, "labeljust"); if (just) { if (just[0] == 'l') pos_flag |= LABEL_AT_LEFT; else if (just[0] == 'r') pos_flag |= LABEL_AT_RIGHT; } GD_label_pos(sg) = pos_flag; if (sg == sg->root) return; /* Set border information for cluster labels to allow space */ dimen = GD_label(sg)->dimen; PAD(dimen); PF2P(dimen, dpt); if (!GD_flip(sg->root)) { if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = TOP_IX; else pos_ix = BOTTOM_IX; GD_border(sg)[pos_ix] = dpt; } else { /* when rotated, the labels will be restored to TOP or BOTTOM */ if (GD_label_pos(sg) & LABEL_AT_TOP) pos_ix = RIGHT_IX; else pos_ix = LEFT_IX; GD_border(sg)[pos_ix].x = dpt.y; GD_border(sg)[pos_ix].y = dpt.x; } } }
/* place_flip_graph_label: * Put cluster labels recursively in the flip case. */ static void place_flip_graph_label(graph_t * g) { int c; point p, d; #ifdef OLD int maxx, minx; int maxy, miny; pointf dimen; #endif if ((g != g->root) && (GD_label(g)) && !GD_label(g)->set) { if (GD_label_pos(g) & LABEL_AT_TOP) { d = GD_border(g)[RIGHT_IX]; p.x = GD_bb(g).UR.x - d.x / 2; #ifdef OLD maxx = GD_bb(g).UR.x + d.y; GD_bb(g).UR.x = maxx; if (GD_bb(g->root).UR.x < maxx) GD_bb(g->root).UR.x = maxx; #endif } else { d = GD_border(g)[LEFT_IX]; p.x = GD_bb(g).LL.x + d.x / 2; #ifdef OLD minx = GD_bb(g).LL.x - d.y; GD_bb(g).LL.x = minx; if (GD_bb(g->root).LL.x > minx) GD_bb(g->root).LL.x = minx; #endif } if (GD_label_pos(g) & LABEL_AT_RIGHT) { p.y = GD_bb(g).LL.y + d.y / 2; #ifdef OLD maxy = p.y + d.x / 2; if (GD_bb(g->root).UR.y < maxy) GD_bb(g->root).UR.y = maxy; #endif } else if (GD_label_pos(g) & LABEL_AT_LEFT) { p.y = GD_bb(g).UR.y - d.y / 2; #ifdef OLD miny = p.y - d.x / 2; if (GD_bb(g->root).LL.y > miny) GD_bb(g->root).LL.y = miny; #endif } else { p.y = (GD_bb(g).LL.y + GD_bb(g).UR.y) / 2; #ifdef OLD maxy = p.y + d.x / 2; miny = p.y - d.x / 2; #endif } GD_label(g)->p = p; GD_label(g)->set = TRUE; } for (c = 1; c <= GD_n_cluster(g); c++) place_flip_graph_label(GD_clust(g)[c]); }
/* dotneato_postprocess: * Set graph and cluster label positions. * Add space for root graph label and translate graph accordingly. * Set final nodesize using ns. * Assumes the boxes of all clusters have been computed. * When done, the bounding box of g has LL at origin. */ void dotneato_postprocess(Agraph_t * g) { int diff; pointf dimen; point d = { 0, 0 }; Rankdir = GD_rankdir(g); Flip = GD_flip(g); if (Flip) place_flip_graph_label(g); else place_graph_label(g); if (GD_label(g) && !GD_label(g)->set) { dimen = GD_label(g)->dimen; PAD(dimen); PF2P(dimen, d); if (Flip) { if (GD_label_pos(g) & LABEL_AT_TOP) { GD_bb(g).UR.x += d.y; } else { GD_bb(g).LL.x -= d.y; } if (d.x > GD_bb(g).UR.y - GD_bb(g).LL.y) { diff = d.x - (GD_bb(g).UR.y - GD_bb(g).LL.y); diff = diff / 2; GD_bb(g).LL.y -= diff; GD_bb(g).UR.y += diff; } } else { if (GD_label_pos(g) & LABEL_AT_TOP) { if (Rankdir == RANKDIR_TB) GD_bb(g).UR.y += d.y; else GD_bb(g).LL.y -= d.y; } else { if (Rankdir == RANKDIR_TB) GD_bb(g).LL.y -= d.y; else GD_bb(g).UR.y += d.y; } if (d.x > GD_bb(g).UR.x - GD_bb(g).LL.x) { diff = d.x - (GD_bb(g).UR.x - GD_bb(g).LL.x); diff = diff / 2; GD_bb(g).LL.x -= diff; GD_bb(g).UR.x += diff; } } } switch (Rankdir) { case RANKDIR_TB: Offset = GD_bb(g).LL; break; case RANKDIR_LR: Offset = pointof(-GD_bb(g).UR.y, GD_bb(g).LL.x); break; case RANKDIR_BT: Offset = pointof(GD_bb(g).LL.x, -GD_bb(g).UR.y); break; case RANKDIR_RL: Offset = pointof(GD_bb(g).LL.y, GD_bb(g).LL.x); break; } translate_drawing(g); if (GD_label(g) && !GD_label(g)->set) place_root_label(g, d); if (Show_boxes) { char buf[BUFSIZ]; if (Flip) sprintf(buf, M2, Offset.x, Offset.y, Offset.x, Offset.y); else sprintf(buf, M1, Offset.y, Offset.x, Offset.y, Offset.x, -Offset.x, -Offset.y); Show_boxes[0] = strdup(buf); } }