home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / xgrab.lha / xgrab / ui / graph.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-24  |  34.8 KB  |  1,566 lines

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1989, Tera Computer Company
  5.  **/
  6.  
  7.   /**
  8.      Implementation of the graph data structure.
  9.      Just a list of representation of graphical objects.
  10.      You can add new objects, draw the objects, erase the objects, delete
  11.      the objects, change the values of the attributes of the objects.
  12.    **/
  13.  
  14. #include <InterViews/painter.h>
  15. #include <math.h>
  16. #include <InterViews/brush.h>
  17. #include <InterViews/defs.h>
  18. #include <InterViews/graphic.h>
  19. #include <InterViews/Graphic/lines.h>
  20. #include <InterViews/Graphic/polygons.h>
  21. #include <InterViews/Graphic/ellipses.h>
  22. #include "gview.h"
  23. #include "graph.h"
  24. #include "fonthandler.h"
  25. #include "tedge.h"
  26. #include "routines.h"
  27. #include "istring.h"
  28.  
  29. const singlewidth = 1;        /* width of a normal line */
  30. const boldwidth = 2;        /* width of a bold line */
  31.  
  32. Graph::Graph ()
  33. {
  34.       /* initialize the brushes and colors */
  35.     brushes[solidb] = single;                /* normal line */
  36.     brushes[bsolidb] = new Brush(0xffff, boldwidth);    /* bold normal line */
  37.     brushes[dottedb] = new Brush(0xcccc, singlewidth);    /* dotted line */
  38.     brushes[bdottedb] = new Brush(0xcccc, boldwidth);    /* bold dotted line */
  39.     brushes[dashedb] = new Brush(0xff00, singlewidth);    /* dashed line */
  40.     brushes[bdashedb] = new Brush(0xff00, boldwidth);    /* bold dashed line */
  41.  
  42.     palette[blackc] = black;
  43.     palette[grayc] = new Color("gray");
  44.  
  45.     if (!palette[grayc]->Valid())
  46.       /**
  47.      who knows what colors your machine knows about?  It'd better know
  48.      about black and white, though, or there'll be hell to pay.
  49.  
  50.      Of course, we could add more colors, but right now I don't see
  51.      too many color monitors about, so you'll just have to be happy
  52.      with these three.  Most people don't have color plotters
  53.      anyway, so printing color graphs could be ugly (postscript
  54.      monochrome gray looks stupid enough as it is)
  55.        **/
  56.     {
  57.     fprintf(stderr, 
  58.         "Color gray not supported.  Using black for display.\n");
  59.         palette[grayc] = black;
  60.     }
  61.  
  62.     palette[whitec] = white;
  63.  
  64.     head = nil;
  65.  
  66.       /* initialize the canonical painters for nodes and edges */
  67.     ndfault = new Painter();        
  68.     ndfault->FillBg(true);
  69.     ndfault->SetColors(black, white);
  70.     ndfault->SetPattern(solid);
  71.     ndfault->SetBrush(brushes[solidb]);
  72.  
  73.     edfault = new Painter();
  74.     edfault->FillBg(true);
  75.     edfault->SetColors(black, white);
  76.     edfault->SetPattern(solid);
  77.     edfault->SetBrush(brushes[solidb]);
  78. }
  79.  
  80. void Graph::SetFHandler(FontHandler* f)
  81.   /* the graph has to know about the fonthandler */
  82. {
  83.     fhandler = f;
  84.     ndfault->SetFont(fhandler->node_font);
  85.     edfault->SetFont(fhandler->edge_font);
  86. }
  87.  
  88. void Graph::SetGB(GView* gview)
  89.   /**
  90.      the graph also likes to know about the graph view, so it can
  91.      call routines there
  92.    **/
  93. {
  94.     gb = gview;
  95. }
  96.  
  97. Graph::~Graph () 
  98. {
  99.     register GraphData* p, * next;
  100.  
  101.     for (p = head; p != nil; p = next) 
  102.     {
  103.     next = p->next;
  104.  
  105.     switch (p->gdtype)
  106.     {
  107.         case node:
  108.         case dummy:
  109.             delete (GNode *) p;
  110.             break;
  111.         case edge:
  112.         case line:
  113.         delete (GEdge *) p;
  114.         break;
  115.     }
  116.     }
  117. }
  118.  
  119. void Graph::DeleteAll ()
  120.   /* this takes entirely too long and I don't know why */
  121. {
  122.     register GraphData *p, *next;
  123.  
  124. /*   Does the garbage collector really work?  Let's find out, cause
  125.     deleting sure doesn't.
  126.  
  127.     for (p = head; p != nil; p = next) 
  128.     {
  129.     next = p->next;
  130.  
  131.     switch (p->gdtype)
  132.     {
  133.         case node:
  134.         case dummy:
  135.             delete (GNode *) p;
  136.             break;
  137.         case edge:
  138.         case line:
  139.         delete (GEdge *) p;
  140.         break;
  141.     }
  142.     }
  143. */
  144.  
  145.     head = nil;
  146. }
  147.  
  148.   /**
  149.      for all the 'Add' routines, 'draw' indicates whether the object
  150.      should be drawn immediately or not
  151.      for nodes and edges, gp is a pointer to a component of the digraph
  152.      structure, used along with ord to identify a node/edge.  the only
  153.      operation done on the gp for nodes is a comparison for equality.
  154.      Edge gp's are actually pointers to tedges.  The components of a tedge
  155.      are accessed, but again only for comparisions
  156.    **/
  157.  
  158. void Graph::AddLine (Coord x1, Coord y1, Coord x2, Coord y2, BType linetype,
  159.     CType color, boolean draw)
  160.   /**
  161.      add a line with no particular destination or source.  Right now
  162.      this is used only to show the levels of the graph.
  163.    **/
  164. {
  165.     Painter *p = new Painter (edfault);
  166.  
  167.     p->SetBrush(brushes[linetype]);
  168.     p->SetColors(palette[color], white);
  169.     MyGraphic* g = new MyGraphic(x1, y1, x2, y2, line, linetype, color, p);
  170.  
  171.     GEdge* e = new GEdge (g, linet, nil, false, "\0", false, nil, nil, -1);
  172.     Append((GraphData*) e);
  173.  
  174.     if (draw)
  175.     {
  176.     DrawGD((GraphData*) e);
  177.     }
  178. }
  179.  
  180. void Graph::AddEdge (Coord x1, Coord y1, Coord x2, Coord y2, boolean arr, 
  181.     char* gp, char* s, BType linetype, CType color, boolean draw, int ord)
  182.   /**
  183.      Add an edge, maybe with arrows.  gp corresponds to a tedge structure.
  184.      s is the edge label. 
  185.    **/
  186. {
  187.     boolean lab;
  188.     MyGraphic* arr1 = nil;
  189.     MyGraphic* arr2 = nil;
  190.  
  191. //fprintf(stderr, "Ae: %d %d %d %d %d %d %s %d\n", x1, y1, x2, y2, arr, gp, s, linetype);
  192.     Painter* p = new Painter(edfault);
  193.     p->SetBrush(brushes[linetype]);
  194.     p->SetColors(palette[color], white);
  195.     p->SetFont(fhandler->edge_font);
  196.     MyGraphic* g = new MyGraphic(x1, y1, x2, y2, line, linetype, color, p);
  197.  
  198.     lab = (fhandler->elabel_forced);
  199.  
  200.     if (arr)
  201.     {
  202.         MakeArrowHeads(x1, y1, x2, y2, &arr1, &arr2, linetype, color, p);
  203.     }
  204.  
  205.     GEdge* e = new GEdge (g, edge, gp, lab, s, arr, arr1, arr2, ord);
  206.     Append((GraphData *) e);
  207.  
  208.     if (draw)
  209.     {
  210.     DrawGD((GraphData*) e);
  211.     }
  212. }
  213.  
  214. const double DIST_FACTOR = 0.5; /* length of arrow lines, relatively */
  215. const double ARR_ANGLE = 30.0;    /* angle between arrow lines and the edge */
  216. const double MAXDIST = 10.0;    /* arrows get no bigger than this */
  217.  
  218. void Graph::MakeArrowHeads(Coord x1, Coord y1, Coord x2, Coord y2, 
  219.     MyGraphic** arr1, MyGraphic** arr2, BType linetype, CType color,
  220.     Painter* dfault)
  221. {
  222.     double angle;    /* angle between the line and the horizontal */
  223.     double dist;    /* length of one line of the arrow */
  224.     double x_dist, y_dist;
  225.     int a, b, c, d, e, f, g, height;
  226.  
  227.     gb->GetBounds(&a, &b, &c, &height, &d, &e, &f, &g);
  228.  
  229.     angle = atan2((double) (y1-y2), (double) (x1-x2));
  230.     dist = (double) height * DIST_FACTOR * GetHeight();
  231.        /* the arrow grows as the size of the canvas and the size of a node */
  232.     
  233.     if (dist > MAXDIST)
  234.     {
  235.     dist = MAXDIST;
  236.     }
  237.  
  238.     x_dist = cos(angle) * dist;
  239.     y_dist = sin(angle) * dist;
  240.  
  241.     *arr1 = new MyGraphic(x2, y2, x2 + (Coord) x_dist, y2 + (Coord) y_dist, 
  242.               line, linetype, color, new Painter(dfault));
  243.     *arr2 = new MyGraphic(x2, y2, x2 + (Coord) x_dist, y2 + (Coord) y_dist, 
  244.               line, linetype, color, new Painter(dfault));
  245.  
  246.     (*arr1)->Rotate(ARR_ANGLE, x2, y2);
  247.     (*arr2)->Rotate(-ARR_ANGLE, x2, y2);
  248. }
  249.  
  250. void Graph::AddNode (Coord x1, Coord y1, Coord x2, Coord y2, 
  251.     NShape sh, char* s, boolean d, char* gp, char* upbc, 
  252.     char* downbc, BType linetype, CType color, boolean draw, int ord)
  253.   /**
  254.      Add a node.  s is the node label; d indicates if it's a dummy node.
  255.      gp is a pointer to the node in the digraph structure.  Ord has meaning
  256.      for dummy nodes:  when drawing a dummy node that handles k edges, 
  257.      the node is split up into k points.  ord indicates which one.
  258.    **/
  259. {
  260.     GNode* g;
  261.     MyGraphic* gr;
  262.     boolean lab;
  263.  
  264. //fprintf(stderr, "An: %d %d %d %d %d %s %d %d %d %s %s\n", x1, y1, x2, y2, sh, s, d, gp, linetype, upbc, downbc);
  265.     Painter* p = new Painter(ndfault);
  266.     p->SetBrush(brushes[linetype]);
  267.     p->SetColors(palette[color], white);
  268.     p->SetFont(fhandler->node_font);
  269.     gr = new MyGraphic(x1, y1, x2, y2, sh, linetype, color, p);
  270.  
  271.     lab = (fhandler->text_flag == true || fhandler->nlabel_forced == true);
  272.  
  273.     g = new GNode (gr, d ? dummy : node, gp, lab, s, upbc, downbc, ord);
  274.     Append((GraphData *) g);
  275.  
  276.     if (draw)
  277.     {
  278.     DrawGD((GraphData*) g);
  279.     }
  280. }
  281.  
  282. void Graph::ChangeNodeLabel(char* node, char* s)
  283.   /* change node's label to s */
  284. {
  285.     GNode *gn = FindNode(node);
  286.  
  287.     if (gn->text) 
  288.     {
  289.     EraseLabel(gn);
  290.     EraseGraphic(gn);    /* labels can overlap the node, so redraw it */
  291.     DrawGraphic(gn);
  292.     }
  293.  
  294.     gn->lstr = strdup(s);
  295.  
  296.     if (fhandler->text_flag || fhandler->nlabel_forced) 
  297.       /* only draw the label if it fits or node labels are forced */
  298.     {
  299.     gn->gr->GetPainter()->SetFont(fhandler->node_font);
  300.     DrawLabel(gn);
  301.     gn->text = true;
  302.     }
  303.     else 
  304.     {
  305.     gn->text = false;
  306.     }
  307. }
  308.  
  309. void Graph::ChangeEdgeLabel(char* fromnode, char* tonode, int ord, char* s)
  310.   /** 
  311.      change the label of the edge from fromnode to tonode of ordinality ord
  312.      to s.
  313.    **/
  314. {
  315.     GEdge *ge = FindEdge(fromnode, tonode, ord);
  316.  
  317.     if (ge->text) 
  318.     {
  319.     EraseLabel(ge);
  320.     EraseGraphic(ge);
  321.     DrawGraphic(ge);    /* labels can overlap the edge, so redraw it */
  322.     }
  323.  
  324.     ge->lstr = strdup(s);
  325.  
  326.     if (fhandler->elabel_forced) 
  327.        /* draw only if edge labels are forced */
  328.     {
  329.     ge->gr->GetPainter()->SetFont(fhandler->edge_font);
  330.     DrawLabel(ge);
  331.     ge->text = true;
  332.     } 
  333.     else 
  334.     {
  335.     ge->text = false;
  336.     }
  337. }
  338.  
  339. void Graph::ChangeBC()
  340.   /* the bc flag has been changed.  Either draw or erase them all */
  341. {
  342.     GNode* gn;
  343.     GraphData* p;
  344.  
  345.     for (p = head; p != nil; p = p->next) 
  346.     {
  347.     if (p->gdtype == node || p->gdtype == dummy) 
  348.     {
  349.         gn = (GNode *) p;
  350.  
  351.             if (GetBCFlag()) 
  352.         {
  353.         DrawBC(gn);
  354.         }
  355.         else 
  356.         {
  357.         EraseBC(gn);
  358.         EraseGraphic(gn); /* bc's overlap the node, so redraw it */
  359.         DrawGraphic(gn);
  360.         }
  361.     }
  362.     }
  363. }
  364.  
  365. void Graph::ChangeMarkDummy()
  366.   /* the mark dummy flag has been changed. */
  367. {
  368.     GNode* gn;
  369.     GraphData* p;
  370.     Painter *pa;
  371.     MyGraphic *g;
  372.     BType brush;
  373.     CType color;
  374.  
  375.     Coord x0, y0, x1, y1;     
  376.  
  377.     for (p = head; p != nil; p = p->next) 
  378.     {
  379.     if (p->gdtype == dummy) 
  380.     {
  381.         gn = (GNode *) p;
  382.  
  383.         pa = new Painter(gn->gr->GetPainter());
  384.         brush = gn->gr->GetBrush();
  385.         color = gn->gr->GetColor();
  386.         gn->gr->GetOriginal(x0, y0, x1, y1);
  387.         delete gn->grf;
  388.  
  389.         if (GetMarkDummyFlag())
  390.           /* change dummy node so it's a teeny rectangle */
  391.         {
  392.         g = new MyGraphic(x0 - 1, y0 - 1, 2, 2, rectangle, brush,
  393.                   color, pa);
  394.         gn->grf = new FillRect(x0 - 1, y0 - 1, x0 + 1, y0 + 1);
  395.         EraseGraphic(gn);
  396.         delete gn->gr;
  397.         gn->gr = g;
  398.         DrawGraphic(gn);
  399.         }
  400.         else
  401.           /* change it back to a point */
  402.         {
  403.         g = new MyGraphic(x0 + 1, y0 + 1, x0 + 1, y0 + 1, npoint, 
  404.                   brush, color, pa);
  405.         gn->grf = new Point(x0 + 1, y0 + 1);
  406.         EraseGraphic(gn);
  407.         delete gn->gr;
  408.         gn->gr = g;
  409.         DrawGraphic(gn);
  410.         }
  411.     }
  412.     }
  413. }
  414.  
  415.   /**
  416.      the ChangeLabels routines are called when labels change size, or
  417.      suddenly become displayed, or suddenly become undisplayed.  
  418.    **/
  419. void Graph::ChangeLabels()
  420. {
  421.     ChangeAllLabels(true, true);
  422. }
  423.  
  424. void Graph::ChangeForceNL()
  425. {
  426.     ChangeAllLabels(true, false);
  427. }
  428.  
  429. void Graph::ChangeForceEL()
  430. {
  431.     ChangeAllLabels(false, true);
  432. }
  433.  
  434. void Graph::ChangeAllLabels(boolean doNode, boolean doEdge)
  435.   /** 
  436.      if doNode is true, change node labels
  437.      if doEdge is true, change edge labels
  438.    **/
  439. {
  440.     GNode* gn;
  441.     GEdge* ge;
  442.     GraphData* p;
  443.  
  444.     for (p = head; p != nil; p = p->next) 
  445.     {
  446.     if (doNode && (p->gdtype == node || p->gdtype == dummy))
  447.     {
  448.         gn = (GNode *) p;
  449.  
  450.             if (gn->text)
  451.         {
  452.         EraseLabel(gn);
  453.         EraseGraphic(gn);    
  454.         DrawGraphic(gn); /* labels can overlap the node, so redraw it */
  455.         }
  456.  
  457.             if (fhandler->text_flag == true || fhandler->nlabel_forced == true)
  458.           /* draw node labels if they fit or they're forced */
  459.         {
  460.         gn->text = true;
  461.         gn->gr->GetPainter()->SetFont(fhandler->node_font);
  462.         DrawLabel(gn);
  463.         } 
  464.         else
  465.         {
  466.         gn->text = false;
  467.         }
  468.     }
  469.     else if (doEdge && p->gdtype == edge)    
  470.     {
  471.         ge = (GEdge *) p;
  472.  
  473.             if (ge->text)
  474.         {
  475.         EraseLabel(ge);
  476.         EraseGraphic(ge);
  477.         DrawGraphic(ge); /* labels can overlap the edge, so redraw it */
  478.         }
  479.  
  480.             if (fhandler->elabel_forced) 
  481.           /* draw edge labels if they are forced */
  482.         {
  483.         ge->text = true;
  484.             ge->gr->GetPainter()->SetFont(fhandler->edge_font);
  485.         DrawLabel(ge);
  486.             } 
  487.         else
  488.         {
  489.         ge->text = false;
  490.         }
  491.     }
  492.     }
  493. }
  494.  
  495. void Graph::ChangePA()
  496.   /* the print arrows option has changed */
  497. {
  498.     GEdge* ge;
  499.     GraphData* p;
  500.  
  501.     for (p = head; p != nil; p = p->next) 
  502.     {
  503.     if (p->gdtype == edge)    
  504.     {
  505.         ge = (GEdge *) p;
  506.  
  507.             if (ge->arrow && GetPAFlag()) 
  508.           /**
  509.          Draw arrows for this edge.  Arrowheads are only created
  510.          if they're displayed.  This saves time when displaying
  511.          the graph.  But that means we have to create them here.
  512.            **/
  513.         {
  514.         int x1, y1, x2, y2;
  515.         MyGraphic* arr1;
  516.         MyGraphic* arr2;
  517.         BType linetype = ge->gr->GetBrush();
  518.         CType color = ge->gr->GetColor();
  519.         
  520.             Painter* p = new Painter(edfault);
  521.             p->SetBrush(brushes[linetype]);
  522.             p->SetColors(palette[color], white);
  523.             p->SetFont(fhandler->edge_font);
  524.  
  525.             ge->gr->GetOriginal(x1, y1, x2, y2);
  526.                 MakeArrowHeads(x1, y1, x2, y2, &arr1, &arr2, linetype, color, 
  527.                    p);
  528.         ge->arr1 = arr1;
  529.         ge->arr2 = arr2;
  530.         DrawArrows(ge);
  531.             } 
  532.         else if (ge->arrow)
  533.         {
  534.         EraseArrows(ge);
  535.         delete ge->arr1;
  536.         delete ge->arr2;
  537.         ge->arr1 = nil;
  538.         ge->arr2 = nil;
  539.             }
  540.     }
  541.     }
  542. }
  543.  
  544. GraphData::GraphData () 
  545.   /* used at one point to allocate an array of them */
  546. {
  547. }
  548.  
  549. GraphData::GraphData (GDType t, char* gp) 
  550.   /**
  551.      used in myGraphicsIntersecting, when we're allocating dummy GraphData
  552.      objects
  553.    **/
  554. {
  555.     gr = nil;
  556.     gdtype = t;
  557.     gpart = gp;
  558.     text = false;
  559.     lstr = "\0";
  560.     next = nil;
  561.     ord = -1;
  562. }
  563.  
  564. GraphData::GraphData (MyGraphic* g, GDType t, char* gp, boolean te, char* str,
  565.     int o) 
  566.   /**
  567.      The standard constructor routine for real nodes and edges
  568.    **/
  569. {
  570.     gr = g;
  571.     gdtype = t;
  572.     gpart = gp;
  573.     text = te;
  574.  
  575.     if (strcmp(str, "\0"))
  576.     {
  577.         lstr = strdup(str);
  578.     }
  579.     else
  580.     {
  581.     lstr = "\0";
  582.     }
  583.  
  584.     ord = o;
  585.     next = nil;
  586. }
  587.  
  588. GraphData::~GraphData()
  589. {
  590.     delete gr;
  591.     delete lstr;
  592. }
  593.  
  594.   /**
  595.      In the following 4 routines, the any flag is sometimes used to
  596.      denote that you can ignore the ord of a node/edge when searching
  597.      for it.  The ord routine doesn't enter into FindNode.
  598.      Since the ord is always defined for all edges, it isn't necessary for 
  599.      FindEdge.  In RemoveNode and RemoveEdge, the any flag is used to 
  600.      delete all edges: Call RemoveNode/Edge with the any flag set until 
  601.      all the nodes/edges that match are deleted.  This avoids having to know 
  602.      how many nodes/edges there are that fit the criteria.
  603.    **/
  604.    
  605. GNode *Graph::RemoveNode (char* n, int ord, boolean any)
  606.   /**
  607.      find the node whose gpart is the same as n and ord the same as ord.  
  608.      Remove it from the graph and return it.
  609.    **/
  610. {
  611.     GNode *rval = nil;
  612.     boolean found = false;
  613.  
  614.     if (head == nil)
  615.         /**
  616.            yes, this can happen.  See DelAllNodes.  Useful sanity check,
  617.        anyway.
  618.      **/
  619.     {
  620.     }
  621.     else if ((head->gdtype == node || head->gdtype == dummy) && 
  622.          (head->gpart == n) && (any || head->ord == ord))
  623.       /* the head matches */
  624.     {
  625.     rval = (GNode *) head;
  626.     head = head->next;
  627.     } 
  628.     else     /* check the rest of the list */
  629.     {
  630.         for (GraphData* p = head; !found; p = p->next) 
  631.     {
  632.         if (p->next == nil) 
  633.           /* no match */
  634.         {
  635.         break;
  636.         } 
  637.         else if ((p->next->gdtype == node || p->next->gdtype == dummy) &&
  638.              (p->next->gpart == n) && 
  639.              (any || p->next->ord == ord)) 
  640.         {
  641.         found = true;
  642.         rval = (GNode *) p->next;
  643.         p->next = p->next->next;
  644.         }
  645.     }
  646.     }
  647.  
  648.     return rval;
  649. }
  650.  
  651. GNode* Graph::FindNode (char* n)
  652.   /**
  653.      find the first node whose gpart is the same as n and ord the same as ord.  
  654.    **/
  655. {
  656.     GNode *rval = nil;
  657.     boolean found = false;
  658.  
  659.     if ((head->gdtype == node || head->gdtype == dummy) &&
  660.     (head->gpart == n))
  661.       /* head matches */
  662.     {
  663.     rval = (GNode *) head;
  664.     }
  665.     else    /* check the rest of the list */
  666.     {
  667.         for (GraphData* p = head; found == false; p = p->next)
  668.         {
  669.         if (p->next == nil)
  670.         {
  671.             fprintf (stderr, "Find Node:  not found\n");
  672.         break;
  673.         }
  674.         else if ((p->next->gdtype == node || p->next->gdtype == dummy) &&
  675.              (p->next->gpart == n))
  676.         {
  677.         found = true;
  678.         rval = (GNode *) p->next;
  679.         }
  680.     }
  681.     }
  682.  
  683.     return rval;
  684. }
  685.  
  686. GEdge *Graph::RemoveEdge (char* prev, char* next, int ord, boolean any)
  687.   /**
  688.      find the edge whose gpart has a fromnode to match prev, and a tonode
  689.      to match next, and an ord to match ord.  Remove it from the graph and 
  690.      return it.
  691.    **/
  692. {
  693.     GEdge *rval = nil;
  694.     boolean found = false;
  695.  
  696.     if (head == nil)
  697.         /**
  698.            I doubt this could happen, but a useful sanity check,
  699.        anyway.
  700.      **/
  701.     {
  702.     }
  703.     else if ((head->gdtype == edge) &&
  704.          (((TEDGE *) head->gpart)->fromnode == prev) &&
  705.          (((TEDGE *) head->gpart)->tonode == next) && 
  706.          (any || head->ord == ord))
  707.       /* head matches */
  708.     {
  709.     rval = (GEdge *) head;
  710.     head = head->next;
  711.     }
  712.     else    /* check the rest of the list */
  713.     {
  714.         for (GraphData* p = head; found == false; p = p->next)
  715.         {
  716.         if (p->next == nil)
  717.           /* no match */
  718.         {
  719.         break;
  720.         }
  721.         else if ((p->next->gdtype == edge) &&
  722.              (((TEDGE *) p->next->gpart)->fromnode == prev) &&
  723.              (((TEDGE *) p->next->gpart)->tonode == next) &&
  724.              (any || p->next->ord == ord))
  725.         {
  726.         found = true;
  727.         rval = (GEdge *) p->next;
  728.         p->next = p->next->next;
  729.         }
  730.     }
  731.     }
  732.  
  733.     return rval;
  734. }
  735.  
  736. GEdge *Graph::FindEdge (char* prev, char* next, int ord)
  737.   /**
  738.      find the edge whose gpart has a fromnode to match prev, and a tonode
  739.      to match next, and whose ord matches ord.  return it.
  740.    **/
  741. {
  742.     GEdge *rval = nil;
  743.     boolean found = false;
  744.  
  745.     if ((head->gdtype == edge) &&
  746.     (((TEDGE *) head->gpart)->fromnode == prev) &&
  747.     (((TEDGE *) head->gpart)->tonode == next) &&
  748.     head->ord == ord)
  749.       /* head matches */
  750.     {
  751.     rval = (GEdge *) head;
  752.     }
  753.     else    /* check the rest of the list */
  754.     {
  755.         for (GraphData* p = head; found == false; p = p->next)
  756.         {
  757.         if (p->next == nil)
  758.         {
  759.             fprintf (stderr, "Find Edge:  not found\n");
  760.         break;
  761.         }
  762.         else if ((p->next->gdtype == edge) &&
  763.              (((TEDGE *) p->next->gpart)->fromnode == prev) &&
  764.              (((TEDGE *) p->next->gpart)->tonode == next) &&
  765.              p->next->ord == ord)
  766.         {
  767.         found = true;
  768.         rval = (GEdge *) p->next;
  769.         }
  770.     }
  771.     }
  772.  
  773.     return rval;
  774. }
  775.  
  776. GNode::GNode (MyGraphic* g, GDType t, char* gp, boolean lab, char* str,
  777.     char* upbc, char* downbc, int ord) 
  778.     : (g, t, gp, lab, str, ord)
  779. {
  780.     int x0, y0, x1, y1;
  781.  
  782.     g->GetOriginal(x0, y0, x1, y1);
  783.     grf = makeFill(g->GetShape(), x0, y0, x1, y1);
  784.     upstr = strdup(upbc);
  785.     downstr = strdup(downbc);
  786. }
  787.  
  788. Graphic* GNode::makeFill(NShape s, Coord x0, Coord y0, Coord x1, Coord y1)
  789.   /**
  790.      The nodes all keep a filled graphic object around.  This way, we
  791.      can easily test if the cursor is over a node by seeing if it intersects
  792.      the graphic.  
  793.    **/
  794. {
  795.     switch (s)
  796.     {
  797.     case circle:
  798.         return new FillCircle(x0, y0, y1);
  799.  
  800.     case oval:
  801.         return new FillEllipse(x0, y0, x1, y1);
  802.  
  803.     case npoint:
  804.         return new Point(x0, y0);
  805.  
  806.     case diamond:
  807.         {
  808.             Coord x[4], y[4];
  809.  
  810.             x[0] = x0 - x1;     y[0] = y0;
  811.             x[1] = x0;         y[1] = y0 - y1;
  812.             x[2] = x0 + x1;        y[2] = y0;
  813.             x[3] = x0;        y[3] = y0 + y1;
  814.             return new FillPolygon(x, y, 4);
  815.         }
  816.  
  817.     case double_box:
  818.     case rectangle:
  819.         return new FillRect(x0 - x1, y0 - y1, x0 + x1, y0 + y1);
  820.  
  821.     case line:
  822.         /* better not be a line! */
  823.         return nil;
  824.     }
  825. }
  826.  
  827. GEdge::GEdge (MyGraphic* g, GDType t, char* gp, boolean lab, char* s,
  828.     boolean arr, MyGraphic* a1, MyGraphic* a2, int ord) 
  829.     : (g, t, gp, lab, s, ord)
  830. {
  831.     arrow = arr;
  832.     arr1 = a1;
  833.     arr2 = a2;
  834. }
  835.  
  836. int Graph::myGraphicsIntersecting(BoxObj& b, GraphData**& garray)
  837.   /**
  838.      so-called because it resembles the GraphicsIntersecting routine
  839.      of the InterViews class GraphicBlock.  Return the objects which
  840.      intersect the box in the garray.  Don't bother testing line objects.
  841.      Node/dummy node intersecting is done with InterViews routines.
  842.      The InterViews line intersection routine was bogus last time I looked,
  843.      so use the routine in intersect.c
  844.    **/
  845. {
  846.     GraphData* p, *q, *gdlist;
  847.     Graphic* ng;
  848.     MyGraphic* eg;
  849.     int size = 0, n = 0;
  850.     Coord x0, y0, x1, y1;
  851.  
  852.     gdlist = nil;
  853.  
  854.       /* create a list of objects that intersect */
  855.     for (p = head; p != nil; p = p->next) 
  856.     {
  857.     switch (p->gdtype)
  858.     {
  859.         case node:
  860.         case dummy:
  861.           /* see if the FILLED graphic intersects it */
  862.             ng = (((GNode*)p)->grf);
  863.  
  864.         if (ng->Intersects(b))
  865.         {
  866.                    q = new GraphData(p->gdtype, p->gpart);
  867.                 q->next = gdlist;
  868.                 gdlist = q;
  869.                 ++size;
  870.         }
  871.         break;
  872.         case edge:
  873.         eg = p->gr;
  874.         eg->GetOriginal(x0, y0, x1, y1);
  875.  
  876.                 if (Intersect(x0, y0, x1, y1, b.left, b.bottom, b.right, b.top))
  877.         {
  878.                    q = new GraphData(p->gdtype, p->gpart);
  879.                 q->next = gdlist;
  880.                 gdlist = q;
  881.                 ++size;
  882.         }
  883.         break;
  884.         case line:
  885.         break;
  886.     }
  887.     }
  888.  
  889.       /* change the list into an array */
  890.     garray = new GraphData*[size];
  891.  
  892.     for (p = gdlist; p != nil; ++n) 
  893.     {
  894.     garray[n] = p;
  895.     p = p->next;
  896.     }
  897.  
  898.     return size;
  899. }
  900.  
  901. void Graph::Append(GraphData *g)
  902.   /* append this to the graph */
  903. {
  904.     g->next = head;
  905.     head = g;
  906. }
  907.  
  908. void Graph::DelAllNodes(char* node)
  909.   /**
  910.      delete all nodes with a gpart that matches node.  This is useful
  911.      for dummy nodes, which are actually a series of subnodes in the
  912.      graph data structure (each subnode has the same gpart, but a different
  913.      ord
  914.    **/
  915. {
  916.     GNode *gn;
  917.     int dummy;
  918.  
  919.     while ((gn = RemoveNode(node, dummy, true)) != nil)
  920.     {
  921.     DelNode(gn);
  922.     }
  923. }
  924.  
  925. void Graph::DelNode(char* node, int ord)
  926.   /* Delete a node, we know its ord */
  927.  
  928. {
  929.     GNode *gn = RemoveNode(node, ord);
  930.     DelNode(gn);
  931. }
  932.  
  933. void Graph::DelAllEdges(char* prev, char* next)
  934.   /**
  935.      delete all edges from prev to next, regardless of the ord.
  936.      Again, useful when deleting dummy nodes, but in other cases, too
  937.    **/
  938. {
  939.     GEdge *ge;
  940.     int dummy;
  941.  
  942.     while ((ge = RemoveEdge(prev, next, dummy, true)) != nil)
  943.     {
  944.      DelEdge(ge);
  945.     }
  946. }
  947.  
  948. void Graph::DelEdge(char* prev, char* next, int ord)
  949.   /* delete a specific edge */
  950. {
  951.     GEdge *ge = RemoveEdge(prev, next, ord);
  952.     DelEdge(ge);
  953. }
  954.  
  955. void Graph::DelNode(GNode *gn)
  956.   /* delete this gnode.  Erase the text, bc, and the node itself */
  957. {
  958.     if (gn->text)
  959.     {
  960.     EraseLabel(gn);
  961.     }
  962.  
  963.     if (GetBCFlag())
  964.     {
  965.     EraseBC(gn);
  966.     }
  967.  
  968.     EraseGraphic(gn);
  969. }
  970.  
  971. void Graph::DelEdge(GEdge *ge)
  972.   /* erase the label, the arrows, and the line itself */
  973. {
  974.     if (ge == nil)
  975.     {
  976.     fprintf (stderr, "Delete Edge:  nothing to delete!");
  977.     return;
  978.     }
  979.  
  980.     if (ge->text)
  981.     {
  982.     EraseLabel(ge);
  983.     }
  984.  
  985.     if (ge->arr1 != nil)
  986.     {
  987.     EraseArrows(ge);
  988.     }
  989.  
  990.     EraseGraphic(ge);
  991. }
  992.  
  993. void Graph::ChangeEdge(char* prev, char* next, int ord, BType brush, 
  994.     CType color)
  995.   /* change the brush and color of the matching edge */
  996. {
  997.     GEdge *ge = FindEdge(prev, next, ord);
  998.  
  999.     if (ge != nil)
  1000.     {
  1001.         BType b = ge->gr->GetBrush();
  1002.         CType c = ge->gr->GetColor();
  1003.  
  1004.         if (b != brush || c != color)
  1005.     {
  1006.         if (ge->text)
  1007.         {
  1008.         EraseLabel(ge);
  1009.         }
  1010.  
  1011.         EraseGraphic(ge);
  1012.         ge->gr->GetPainter()->SetBrush(brushes[brush]);
  1013.             ge->gr->GetPainter()->SetColors(palette[color], white);
  1014.         DrawGraphic(ge);
  1015.  
  1016.         if (ge->text)
  1017.         {
  1018.         DrawLabel(ge);
  1019.         }
  1020.  
  1021.             if (ge->arrow && GetPAFlag())
  1022.           /* change the arrows, too */
  1023.             {
  1024.             EraseArrows(ge);
  1025.                 ge->arr1->GetPainter()->SetBrush(brushes[brush]);
  1026.                 ge->arr2->GetPainter()->SetBrush(brushes[brush]);
  1027.         ge->arr1->GetPainter()->SetColors(palette[color], white);
  1028.         ge->arr2->GetPainter()->SetColors(palette[color], white);
  1029.             DrawArrows(ge);
  1030.             ge->arr1->SetBrush(brush);
  1031.             ge->arr1->SetColor(color);
  1032.             ge->arr2->SetBrush(brush);
  1033.             ge->arr2->SetColor(color);
  1034.             }
  1035.  
  1036.         ge->gr->SetBrush(brush);
  1037.         ge->gr->SetColor(color);
  1038.     }
  1039.     }
  1040. }
  1041.  
  1042. void Graph::ChangeNode(char* node, NShape shape, BType brush, CType color)
  1043.   /* change the shape, brush, and color of the matching node */
  1044. {
  1045.     GNode *gn = FindNode(node);
  1046.  
  1047.     if (gn != nil)
  1048.     {
  1049.     NShape s = gn->gr->GetShape();
  1050.         BType b = gn->gr->GetBrush();
  1051.         CType c = gn->gr->GetColor();
  1052.  
  1053.     if (s != shape)
  1054.       /* must create a new graphic and fill graphic */
  1055.     {
  1056.         Coord x1, y1, x2, y2;
  1057.  
  1058.             gn->gr->GetOriginal(x1, y1, x2, y2);
  1059.  
  1060.         if (gn->text)
  1061.         {
  1062.         EraseLabel(gn);
  1063.         }
  1064.  
  1065.             EraseGraphic(gn);
  1066.  
  1067.             Painter* p = new Painter(ndfault);
  1068.             p->SetBrush(brushes[brush]);
  1069.             p->SetColors(palette[color], white);
  1070.             p->SetFont(fhandler->node_font);
  1071.  
  1072.         MyGraphic* g = new MyGraphic(x1, y1, x2, y2, shape, brush, color, 
  1073.                      p);
  1074.         Graphic* gf = gn->makeFill(shape, x1, y1, x2, y2);
  1075.         delete gn->gr;
  1076.         delete gn->grf;
  1077.         gn->gr = g;
  1078.         gn->grf = gf;
  1079.             DrawGraphic(gn);
  1080.  
  1081.         if (gn->text)
  1082.         {
  1083.         DrawLabel(gn);
  1084.         }
  1085.     }
  1086.     else if (b != brush || c != color)
  1087.         /* less drastic change */
  1088.     {
  1089.         if (gn->text)
  1090.         {
  1091.         EraseLabel(gn);
  1092.         }
  1093.  
  1094.         EraseGraphic(gn);
  1095.         gn->gr->GetPainter()->SetBrush(brushes[brush]);
  1096.             gn->gr->GetPainter()->SetColors(palette[color], white);
  1097.         gn->gr->SetBrush(brush);
  1098.         gn->gr->SetColor(color);
  1099.         DrawGraphic(gn);
  1100.  
  1101.         if (gn->text)
  1102.         {
  1103.         DrawLabel(gn);
  1104.         }
  1105.     }
  1106.     }
  1107. }
  1108.  
  1109. GNode::~GNode ()
  1110. {
  1111.     delete gr;
  1112.     delete lstr;
  1113.     delete grf;
  1114.     delete upstr;
  1115.     delete downstr;
  1116. }
  1117.  
  1118. GEdge::~GEdge ()
  1119. {
  1120.     delete gr;
  1121.     delete lstr;
  1122.     delete arr1;
  1123.     delete arr2;
  1124. }
  1125.  
  1126. void Graph::SetupMove(char* mnode, char* prev[], char* next[], int numprev,
  1127.     int numnext, Coord* wid, Coord* ht)
  1128.   /** 
  1129.      We're about to move node mnode.  prev and next are a list of its 
  1130.      predecessors and successors, with numprev and numnext to indicate
  1131.      how big they are.  Return the half-width and half-height of the node in 
  1132.      wid and ht.
  1133.  
  1134.      Remove the node and all associated edges
  1135.    **/
  1136. {
  1137.     GNode* gn = FindNode(mnode);
  1138.  
  1139.     *wid = gn->gr->Width() / 2;
  1140.     *ht = gn->gr->Height() / 2;
  1141.  
  1142.     DelAllNodes(mnode);
  1143.  
  1144.     for (int i = 0; i < numprev; i++)
  1145.     {
  1146.     DelAllEdges(prev[i], mnode);
  1147.     }
  1148.  
  1149.     for (i = 0; i < numnext; i++)
  1150.     {
  1151.     DelAllEdges(mnode, next[i]);
  1152.     }
  1153. }
  1154.  
  1155. static const double RADPERDEG = PI/180.0;
  1156.  
  1157. void MyGraphic::Rotate(double angle, Coord x = 0, Coord y = 0)
  1158.   /**
  1159.      Rotate a graphic by the angle (in degrees), around the point (x, y)
  1160.      Formula lifted from the PostScript reference manual, if you can believe
  1161.      it.
  1162.    **/
  1163. {
  1164.     double tx0, ty0, tx1, ty1, tmp1, tmp2;
  1165.     angle *= RADPERDEG;
  1166.     tmp1 = cos(angle);
  1167.     tmp2 = sin(angle);
  1168.     tx0 = (double) x0 - x;
  1169.     ty0 = (double) y0 - y;
  1170.     tx1 = (double) x1 - x;
  1171.     ty1 = (double) y1 - y;
  1172.  
  1173.     tx0 = tmp1*tx0 - tmp2*ty0;
  1174.     ty0 = tmp2*tx0 + tmp1*ty0;
  1175.     tx1 = tmp1*tx1 - tmp2*ty1;
  1176.     ty1 = tmp2*tx1 + tmp1*ty1;
  1177.  
  1178.     x0 = round(tx0) + x;
  1179.     y0 = round(ty0) + y;
  1180.     x1 = round(tx1) + x;
  1181.     y1 = round(ty1) + y;
  1182. }
  1183.  
  1184. void MyGraphic::Translate(Coord dx, Coord dy)
  1185.   /* translate a graphic by dx and dy */
  1186. {
  1187.     x0 += dx;
  1188.     x1 += dx;
  1189.     y0 += dy;
  1190.     y1 += dy;
  1191. }
  1192.  
  1193. void MyGraphic::Scale(float sx, float sy)
  1194.   /* scale a graphic by sx and sy */
  1195. {
  1196.     x0 = round(x0 * sx);
  1197.     x1 = round(x1 * sx);
  1198.     y0 = round(y0 * sy);
  1199.     y1 = round(y1 * sy);
  1200. }
  1201.  
  1202. MyGraphic::MyGraphic(Coord x, Coord y, Coord xx, Coord yy, NShape s, 
  1203.     BType b, CType c, Painter* p)
  1204.     x0 = x; 
  1205.     y0 = y; 
  1206.     x1 = xx; 
  1207.     y1 = yy; 
  1208.     shape = s; 
  1209.     painter = p;
  1210.     brush = b;
  1211.     color = c;
  1212. }
  1213.  
  1214. MyGraphic::~MyGraphic()
  1215. {
  1216.     delete painter;
  1217. }
  1218.  
  1219.   /* erase by changing the foreground color to white and drawing */
  1220.  
  1221. void Graph::EraseLabel(GNode* gn)
  1222. {
  1223.     Color *c = gn->gr->GetPainter()->GetFgColor();
  1224.  
  1225.     gn->gr->GetPainter()->SetColors(white, white);
  1226.     DrawLabel(gn);
  1227.     gn->gr->GetPainter()->SetColors(c, white);
  1228. }
  1229.  
  1230. void Graph::EraseLabel(GEdge* ge)
  1231. {
  1232.     Color *c = ge->gr->GetPainter()->GetFgColor();
  1233.  
  1234.     ge->gr->GetPainter()->SetColors(white, white);
  1235.     DrawLabel(ge);
  1236.     ge->gr->GetPainter()->SetColors(c, white);
  1237. }
  1238.  
  1239. void Graph::EraseBC(GNode* gn)
  1240. {
  1241.     Color *c = gn->gr->GetPainter()->GetFgColor();
  1242.  
  1243.     gn->gr->GetPainter()->SetColors(white, white);
  1244.     DrawBC(gn);
  1245.     gn->gr->GetPainter()->SetColors(c, white);
  1246. }
  1247.  
  1248. void Graph::EraseArrows(GEdge* ge)
  1249. {
  1250.     Color *c = ge->gr->GetPainter()->GetFgColor();
  1251.  
  1252.     ge->arr1->GetPainter()->SetColors(white, white);
  1253.     ge->arr2->GetPainter()->SetColors(white, white);
  1254.     DrawArrows(ge);
  1255.     ge->arr1->GetPainter()->SetColors(c, white);
  1256.     ge->arr2->GetPainter()->SetColors(c, white);
  1257. }
  1258.  
  1259. void Graph::EraseGraphic(GraphData* g)
  1260. {
  1261.     Color *c = g->gr->GetPainter()->GetFgColor();
  1262.  
  1263. //
  1264.     Painter *p = g->gr->GetPainter();
  1265.     g->gr->SetPainter(new Painter(p));
  1266.     g->gr->GetPainter()->SetColors(white, white);
  1267.     DrawGraphic(g);
  1268.     g->gr->SetPainter(p);
  1269. //    g->gr->GetPainter()->SetColors(c, white);
  1270. }
  1271.  
  1272. void Graph::DrawLabel(GNode* gn)
  1273.   /* draw the node label (in the center of the node */
  1274. {
  1275.     Canvas* c = gb->GetCanvas();
  1276.  
  1277.     int width = gn->gr->GetPainter()->GetFont()->Width(gn->lstr, 
  1278.                                strlen(gn->lstr));
  1279.     int height = gn->gr->GetPainter()->GetFont()->Height();
  1280.     int cx = gn->gr->XCenter();
  1281.     int cy = gn->gr->YCenter();
  1282.  
  1283.     gn->gr->GetPainter()->Text(c, gn->lstr, cx - width / 2, cy - height / 2);
  1284. }
  1285.  
  1286. void Graph::DrawLabel(GEdge* ge)
  1287.   /* draw an edge label (to the right of the edge, about in the center) */
  1288. {
  1289.     Coord x1, y1, x2, y2;
  1290.     Canvas* c = gb->GetCanvas();
  1291.  
  1292.     int width = ge->gr->GetPainter()->GetFont()->Width(ge->lstr, 
  1293.                                strlen(ge->lstr));
  1294.     int height = ge->gr->GetPainter()->GetFont()->Height();
  1295.     ge->gr->GetOriginal(x1, y1, x2, y2);
  1296.  
  1297.     Coord xpos = (x1 + x2) / 2;
  1298.     Coord ypos = (y1 + y2) / 2;
  1299.  
  1300.       /** 
  1301.      multigraph support:  labels for edges should be staggered so
  1302.      they don't overrun each other 
  1303.        **/
  1304.  
  1305.     if ((y1 - y2) / 2 != 0)
  1306.       /* don't bother to change labels for horizontal edges */
  1307.     {
  1308.         Coord shift = (height * (ge->ord / 2)) % abs((y1 - y2) / 2) * 
  1309.               ((ge->ord % 2 == 0) ? -1 : 1);
  1310.       /**
  1311.          Got that?  Same formula as in clip.h, except we're shifting
  1312.          upward or downward by the height of the font.  Also, take
  1313.          the remainder with respect to half the length of the edge so
  1314.          we don't go too far 
  1315.        **/
  1316.  
  1317.      ypos += shift;
  1318.      xpos += shift * (x1 - x2) / (y1 - y2);
  1319.     }
  1320.  
  1321.     ge->gr->GetPainter()->Text(c, ge->lstr, xpos, ypos);
  1322. }
  1323.  
  1324. void Graph::DrawBC(GNode* gn)
  1325.   /**
  1326.      Up barycenters go at the top of the node, centered.
  1327.      Down barycenters go at the bottom of the node, centered
  1328.    **/
  1329. {
  1330.     Canvas* c = gb->GetCanvas();
  1331.  
  1332.     int uwidth = gn->gr->GetPainter()->GetFont()->Width(gn->upstr, 
  1333.                                 strlen(gn->upstr));
  1334.     int dwidth = gn->gr->GetPainter()->GetFont()->Width(gn->downstr, 
  1335.                                 strlen(gn->downstr));
  1336.     int height = gn->gr->GetPainter()->GetFont()->Height();
  1337.     int cx = gn->gr->XCenter();
  1338.     int by = gn->gr->YBottom();
  1339.     int ty = gn->gr->YTop();
  1340.  
  1341.     gn->gr->GetPainter()->Text(c, gn->downstr, cx - dwidth / 2, 
  1342.                    by - height / 2);
  1343.     gn->gr->GetPainter()->Text(c, gn->upstr, cx - uwidth / 2, ty - height / 2);
  1344. }
  1345.  
  1346. void Graph::DrawArrows(GEdge* ge)
  1347.   /* pretty straightforward */
  1348. {
  1349.     Coord x1, y1, x2, y2;
  1350.     Canvas* c = gb->GetCanvas();
  1351.  
  1352.     ge->arr1->GetOriginal(x1, y1, x2, y2);
  1353.     ge->arr1->GetPainter()->Line(c, x1, y1, x2, y2);
  1354.     ge->arr2->GetOriginal(x1, y1, x2, y2);
  1355.     ge->arr2->GetPainter()->Line(c, x1, y1, x2, y2);
  1356. }
  1357.  
  1358. void Graph::DrawGraphic(GraphData* g)
  1359.   /**
  1360.      except for the line, the x1 and y1 coordinates work as width and height,
  1361.      x0 and y0 work as the center
  1362.    **/
  1363. {
  1364.     Coord x0, y0, x1, y1;
  1365.     Canvas* c = gb->GetCanvas();
  1366.  
  1367.     g->gr->GetOriginal(x0, y0, x1, y1);
  1368.  
  1369.     switch(g->gr->GetShape())
  1370.     {
  1371.     case circle:
  1372.           /* use the height, not the width, as the radius */
  1373.         g->gr->GetPainter()->Circle(c, x0, y0, y1);
  1374.         break;
  1375.     case oval:
  1376.         g->gr->GetPainter()->Ellipse(c, x0, y0, x1, y1);
  1377.         break;
  1378.     case npoint:
  1379.         g->gr->GetPainter()->Point(c, x0, y0);
  1380.         break;
  1381.     case diamond:
  1382.         {
  1383.             Coord x[4], y[4];
  1384.  
  1385.             x[0] = x0 - x1;        y[0] = y0;
  1386.             x[1] = x0;        y[1] = y0 - y1;
  1387.             x[2] = x0 + x1;        y[2] = y0;
  1388.             x[3] = x0;        y[3] = y0 + y1;
  1389.             g->gr->GetPainter()->Polygon(c, x, y, 4);
  1390.         }
  1391.         break;
  1392.     case double_box:
  1393.         g->gr->GetPainter()->Rect(c, x0 - x1, y0 - y1, x0 + x1, y0 + y1);
  1394.           /**
  1395.          mins and maxs are to insure the lines don't go past the 
  1396.          center (which they can if the box is tiny enough).  For
  1397.          example, if the the graph is too short, the top of the 
  1398.          inner box could be below the bottom, which looks strange.
  1399.            **/
  1400.         g->gr->GetPainter()->Rect(c, min(x0 - x1 + db_margin, x0), 
  1401.                       min(y0 - y1 + db_margin, y0),
  1402.                       max(x0 + x1 - db_margin, x0), 
  1403.                       max(y0 + y1 - db_margin, y0));
  1404.         break;
  1405.     case rectangle:
  1406.         g->gr->GetPainter()->Rect(c, x0 - x1, y0 - y1, x0 + x1, y0 + y1);
  1407.         break;
  1408.     case line:
  1409.         g->gr->GetPainter()->Line(c, x0, y0, x1, y1);
  1410.         break;
  1411.     }
  1412. }
  1413.  
  1414. int MyGraphic::Width()
  1415. {
  1416.     switch(shape)
  1417.     {
  1418.     case circle:
  1419.       /* use height as the radius */
  1420.         return y1 * 2;
  1421.     case oval:
  1422.     case diamond:
  1423.     case double_box:
  1424.     case rectangle:
  1425.         return x1 * 2;
  1426.     case npoint:
  1427.         return 0;
  1428.     case line:
  1429.         return x1 - x0;
  1430.     }
  1431. }
  1432.  
  1433. int MyGraphic::Height()
  1434. {
  1435.     switch(shape)
  1436.     {
  1437.     case circle:
  1438.         return y1 * 2;
  1439.     case oval:
  1440.     case diamond:
  1441.     case double_box:
  1442.     case rectangle:
  1443.         return y1 * 2;
  1444.     case npoint:
  1445.         return 0;
  1446.     case line:
  1447.         return y1 - y0;
  1448.     }
  1449. }
  1450.  
  1451. Coord MyGraphic::XCenter()
  1452. {
  1453.     switch(shape)
  1454.     {
  1455.     case circle:
  1456.     case oval:
  1457.     case npoint:
  1458.     case diamond:
  1459.     case double_box:
  1460.     case rectangle:
  1461.         return x0;
  1462.     case line:
  1463.         return (x0 + x1) / 2;
  1464.     }
  1465. }
  1466.  
  1467. Coord MyGraphic::YCenter()
  1468. {
  1469.     switch(shape)
  1470.     {
  1471.     case circle:
  1472.     case oval:
  1473.     case npoint:
  1474.     case diamond:
  1475.     case double_box:
  1476.     case rectangle:
  1477.         return y0;
  1478.     case line:
  1479.         return (y0 + y1) / 2;
  1480.     }
  1481. }
  1482.  
  1483. Coord MyGraphic::YBottom()
  1484. {
  1485.     switch(shape)
  1486.     {
  1487.     case circle:
  1488.         return y0 - y1;
  1489.     case oval:
  1490.     case diamond:
  1491.     case double_box:
  1492.     case rectangle:
  1493.         return y0 - y1;
  1494.     case npoint:
  1495.     case line:
  1496.         return y0;
  1497.     }
  1498. }
  1499.  
  1500. Coord MyGraphic::YTop()
  1501. {
  1502.     switch(shape)
  1503.     {
  1504.     case circle:
  1505.         return y0 + y1;
  1506.     case oval:
  1507.     case diamond:
  1508.     case double_box:
  1509.     case rectangle:
  1510.         return y0 + y1;
  1511.     case npoint:
  1512.     case line:
  1513.         return y0;
  1514.     }
  1515. }
  1516.  
  1517. void Graph::DrawAll()
  1518.   /* draw everything */
  1519. {
  1520.     GraphData* p;
  1521.  
  1522.     for (p = head; p != nil; p = p->next) 
  1523.     {
  1524.     DrawGD(p);
  1525.     }
  1526. }
  1527.  
  1528. void Graph::DrawGD(GraphData* g)
  1529.   /* draw one thing */
  1530. {
  1531.     GNode* gn;
  1532.     GEdge* ge;
  1533.  
  1534.     DrawGraphic(g);
  1535.  
  1536.     if ((g->gdtype == node || g->gdtype == dummy))
  1537.     {
  1538.         gn = (GNode *) g;
  1539.  
  1540.         if (gn->text)
  1541.         {
  1542.             DrawLabel(gn);
  1543.         }
  1544.  
  1545.         if (GetBCFlag())
  1546.         {
  1547.             DrawBC(gn);
  1548.         }
  1549.     }
  1550.     else if (g->gdtype == edge || g->gdtype == line)
  1551.     {
  1552.         ge = (GEdge *) g;
  1553.  
  1554.         if (ge->text)
  1555.         {
  1556.             DrawLabel(ge);
  1557.         }
  1558.  
  1559.         if (ge->arrow && GetPAFlag())
  1560.         {
  1561.             DrawArrows(ge);
  1562.     }
  1563.     }
  1564. }
  1565.