home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / DispGraph.C < prev    next >
C/C++ Source or Header  |  1998-11-17  |  30KB  |  1,240 lines

  1. // $Id: DispGraph.C,v 1.45 1998/11/17 11:22:32 zeller Exp $
  2. // Store information about all displayed display expressions
  3.  
  4. // Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
  6. // and Andreas Zeller <zeller@ips.cs.tu-bs.de>
  7. // 
  8. // This file is part of DDD.
  9. // 
  10. // DDD is free software; you can redistribute it and/or
  11. // modify it under the terms of the GNU General Public
  12. // License as published by the Free Software Foundation; either
  13. // version 2 of the License, or (at your option) any later version.
  14. // 
  15. // DDD is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18. // See the GNU General Public License for more details.
  19. // 
  20. // You should have received a copy of the GNU General Public
  21. // License along with DDD -- see the file COPYING.
  22. // If not, write to the Free Software Foundation, Inc.,
  23. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  24. // 
  25. // DDD is the data display debugger.
  26. // For details, see the DDD World-Wide-Web page, 
  27. // `http://www.cs.tu-bs.de/softech/ddd/',
  28. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  29.  
  30. char DispGraph_rcsid[] =
  31.     "$Id: DispGraph.C,v 1.45 1998/11/17 11:22:32 zeller Exp $";
  32.  
  33. #ifdef __GNUG__
  34. #pragma implementation
  35. #endif
  36.  
  37. //-----------------------------------------------------------------------------
  38. // DispGraph stores information about all displayed display expressions.
  39. //-----------------------------------------------------------------------------
  40.  
  41. #include "DispGraph.h"
  42.  
  43. #include <math.h>
  44. #include "pi.h"
  45. #include "hypot.h"
  46. #include <X11/StringDefs.h>
  47.  
  48. #include "AppData.h"
  49. #include "GraphEdit.h"
  50. #include "assert.h"
  51. #include "VarArray.h"
  52. #include "AliasGE.h"
  53. #include "HintGraphN.h"
  54. #include "VoidArray.h"
  55. #include "regexps.h"
  56. #include "BoxEdgeA.h"
  57. #include "annotation.h"
  58. #include "DispBox.h"
  59. #include "EdgeAPA.h"
  60.  
  61. DEFINE_TYPE_INFO_1(DispGraph, Graph)
  62.  
  63.  
  64. //-------------------------------------------------------------------------
  65. // Basics
  66. //-------------------------------------------------------------------------
  67.  
  68. // Constructor
  69. DispGraph::DispGraph()
  70.     : Graph(), idMap(), handlers(DispGraph_NTypes),
  71.       no_enabled(true), no_disabled(true)
  72. {
  73.     DispNode::addHandler(DispNode_Disabled,
  74.              disp_node_disabledHP,
  75.              (void*)this);
  76. }
  77.  
  78. // Destructor
  79. DispGraph::~DispGraph() 
  80. {
  81.     DispGraph::clear();
  82. }
  83.  
  84. // Delete all
  85. void DispGraph::clear()
  86. {
  87.     idMap.delete_all_contents();
  88. }
  89.  
  90.  
  91.  
  92. //-------------------------------------------------------------------------
  93. // Node management
  94. //-------------------------------------------------------------------------
  95.  
  96. // Return number of nodes
  97. int DispGraph::count_all (Displaying e) const
  98. {
  99.     if (e == Both)
  100.     return idMap.length();
  101.  
  102.     int count = 0;
  103.     MapRef ref;
  104.     for (int k = idMap.first_key(ref); k != 0; k =
  105.          idMap.next_key(ref))
  106.     {
  107.     switch (e) 
  108.     {
  109.     case Both:
  110.         count++;
  111.         break;
  112.     case Enabled:
  113.         if (idMap.get(k)->enabled())
  114.         count++;
  115.         break;
  116.     case Disabled:
  117.         if (!(idMap.get(k)->enabled()))
  118.         count++;
  119.         break;
  120.     default:
  121.         // Falscher Fehler
  122.         assert (0);
  123.         break;
  124.     }
  125.     }
  126.     return count;
  127. }
  128.  
  129. // Count selected nodes
  130. int DispGraph::count_selected() const
  131. {
  132.     int count = 0;
  133.     MapRef ref;
  134.     for (int k = idMap.first_key(ref); k != 0; k = idMap.next_key(ref)) {
  135.         if (!idMap.get(k)->selected())
  136.         count++;
  137.     }
  138.     return count;
  139. }
  140.  
  141. // Add an event handler
  142. void DispGraph::addHandler (unsigned    type,
  143.                 HandlerProc proc,
  144.                 void*       client_data)
  145. {
  146.     handlers.add(type, proc, client_data);
  147. }
  148.  
  149. // Remove an event handler
  150. void DispGraph::removeHandler (unsigned    type,
  151.                    HandlerProc proc,
  152.                    void        *client_data)
  153. {
  154.     handlers.remove(type, proc, client_data);
  155. }
  156.  
  157. // Call event handlers
  158. void DispGraph::callHandlers ()
  159. {
  160.     handlers.call(DispGraph_Empty,
  161.           this,
  162.           (void*)(count_all() == 0));
  163.     handlers.call(NoEnabled,
  164.           this,
  165.           (void*)(no_enabled));
  166.     handlers.call(NoDisabled,
  167.           this,
  168.           (void*)(no_disabled));
  169. }
  170.  
  171.  
  172. // Add a new edge
  173. void DispGraph::add_edge(DispNode *from, DispNode *to)
  174. {
  175.     string a = annotation(from->name(), to->name());
  176.     BoxEdgeAnnotation *ann = 0;
  177.     if (a != "")
  178.     ann = new BoxEdgeAnnotation(DispBox::eval("annotation", a));
  179.  
  180.     *this += new LineGraphEdge(from, to, ann);
  181. }
  182.  
  183.  
  184. // Insert NEW_DN into graph, return its number iff successful
  185. int DispGraph::insert(int new_disp_nr, DispNode *new_dn, int depends_on)
  186. {
  187.     if (idMap.contains(new_disp_nr))
  188.     return 0;
  189.     if (idMap.length() == 0)
  190.     handlers.call(DispGraph_Empty, this, (void*)false);
  191.  
  192.     *this += new_dn;
  193.  
  194.     if (depends_on != 0)
  195.     {
  196.     DispNode *old_dn = idMap.get(depends_on);
  197.     add_edge(old_dn, new_dn);
  198.  
  199.     if (old_dn->clustered())
  200.     {
  201.         DispNode *cluster = idMap.get(old_dn->clustered());
  202.         if (cluster != 0)
  203.         add_edge(cluster, new_dn);
  204.     }
  205.     }
  206.     assert (Graph::OK());
  207.  
  208.     idMap.insert (new_disp_nr, new_dn);
  209.  
  210.     if (no_enabled) {
  211.     if (!( no_enabled = (count_all(Enabled) == 0) ))
  212.         handlers.call(NoEnabled, this, (void*)false);
  213.     }
  214.     if (no_disabled) {
  215.     if (!( no_disabled = (count_all(Disabled) == 0) ))
  216.         handlers.call(NoDisabled, this, (void*)false);
  217.     }
  218.  
  219.     refresh_titles();
  220.  
  221.     return new_disp_nr;
  222. }
  223.  
  224.  
  225. // Get a good position for NEW_NODE
  226. BoxPoint DispGraph::adjust_position (DispNode *new_node,
  227.                      Widget w,
  228.                      BoxPoint pos,
  229.                      BoxPoint offset,
  230.                      BoxPoint grid) const
  231. {
  232.     const GraphGC& graphGC = graphEditGetGraphGC(w);
  233.  
  234.     // clog << "new node       at " << pos << "\n";
  235.  
  236.     BoxSize new_size(new_node->box()->size());
  237.  
  238.     // Leave GRID space around the box
  239.     BoxRegion new_region(pos - (new_size + grid) / 2, new_size + grid);
  240.  
  241.     // Make sure the new node is fully visible
  242.     while (new_region.origin()[X] <= 0)
  243.     {
  244.     pos                 += BoxPoint(grid[X], 0);
  245.     new_region.origin() += BoxPoint(grid[X], 0);
  246.     // clog << "new node now   at " << pos << "\n";
  247.     }
  248.  
  249.     while (new_region.origin()[Y] <= 0)
  250.     {
  251.     pos                 += BoxPoint(0, grid[Y]);
  252.     new_region.origin() += BoxPoint(0, grid[Y]);
  253.     // clog << "new node now   at " << pos << "\n";
  254.     }
  255.  
  256.     // Make sure the new node does not obscure existing nodes
  257.     GraphNode *n = firstVisibleNode();
  258.     while (n != 0)
  259.     {
  260.     const BoxRegion& region = n->region(graphGC);
  261.     if (new_region <= region)
  262.     {
  263.         pos                 += offset;
  264.         new_region.origin() += offset;
  265.  
  266.         n = firstVisibleNode();
  267.         // clog << "new node now   at " << pos << "\n";
  268.     }
  269.     else
  270.         n = nextVisibleNode(n);
  271.     }
  272.  
  273.     return pos;
  274. }
  275.  
  276. // Return a default position for NEW_NODE
  277. BoxPoint DispGraph::default_pos(DispNode *new_node, 
  278.                 Widget w, int depends_on) const
  279. {
  280.     Dimension grid_height = 16;
  281.     Dimension grid_width  = 16;
  282.     Cardinal rotation     = 0;
  283.     XtVaGetValues(w,
  284.           XtNgridHeight, &grid_height,
  285.           XtNgridWidth,  &grid_width,
  286.           XtNrotation,   &rotation,
  287.           NULL);
  288.  
  289.     BoxPoint grid(max(grid_height, 1), max(grid_width, 1));
  290.     BoxPoint delta(grid[X] * 3, grid[Y] * 2);
  291.  
  292.     bool horizontal = rotation % 90;
  293.  
  294.     BoxPoint pos;
  295.     BoxPoint offset;
  296.  
  297.     if (depends_on == 0)
  298.     {
  299.     // Default offset: create new displays orthogonal to 
  300.     // dereference direction
  301.     offset = horizontal ? BoxPoint(grid[X], 0) : BoxPoint(0, grid[Y]);
  302.  
  303.     // New node: start with the top-level visible position
  304.     Position x = 0;
  305.     Position y = 0;
  306.     XtVaGetValues(w, XtNx, &x, XtNy, &y, NULL);
  307.     pos = BoxPoint(max(-x, grid[X]), max(-y, grid[Y] * 2));
  308.  
  309.     // Add size offset
  310.     BoxSize new_size(new_node->box()->size());
  311.     pos += new_size / 2;
  312.  
  313.     // Round to nearest grid position
  314.     pos = graphEditFinalPosition(w, pos);
  315.     }
  316.     else
  317.     {
  318.     // Dependent node
  319.  
  320.     // Default offset: create new displays in dereference direction
  321.     offset = horizontal ? BoxPoint(0, delta[Y]) : BoxPoint(delta[X], 0);
  322.  
  323.     // Place new node below/on the right of original node, depending
  324.     // on last layout orientation.
  325.     //
  326.     // NODE -> (new)
  327.  
  328.     BoxGraphNode *node = idMap.get(depends_on);
  329.     // clog << "node           at " << node->pos() << "\n";
  330.     pos = node->pos() + offset;
  331.  
  332.     assert(pos.isValid());
  333.  
  334.     // Check if we already have a successor
  335.     BoxGraphNode *max_child      = 0;
  336.     BoxGraphNode *next_max_child = 0;
  337.  
  338.     // Find two greatest children
  339.     for (GraphEdge *edge = node->firstFrom(); 
  340.          edge != 0; 
  341.          edge = node->nextFrom(edge))
  342.     {
  343.         BoxDimension d = horizontal ? X : Y;
  344.  
  345.         GraphNode *child = edge->to();
  346.         while (child->isHint())
  347.         child = child->firstFrom()->to();
  348.         if (child->hidden())
  349.         continue;
  350.         if (child == new_node)
  351.         continue;
  352.         if (child->pos() == BoxPoint())
  353.         continue;
  354.  
  355.         BoxGraphNode *bgn = ptr_cast(BoxGraphNode, child);
  356.         if (bgn == 0)
  357.         continue;
  358.  
  359.         if (max_child == 0 || child->pos()[d] > max_child->pos()[d])
  360.         {
  361.         next_max_child = max_child;
  362.         max_child = bgn;
  363.         }
  364.         else if (next_max_child == 0 
  365.              || child->pos()[d] > next_max_child->pos()[d])
  366.         {
  367.         next_max_child = bgn;
  368.         }
  369.     }
  370.  
  371.     if (max_child && next_max_child)
  372.     {
  373.         // Re-use offset between the two last children
  374.         //
  375.         //   NODE ->         .
  376.         //        \->        .
  377.         //         \->       .
  378.         //          \->   NEXT_MAX_CHILD
  379.         //           \->  MAX_CHILD
  380.         //            \-> (new)
  381.  
  382.         // clog << "max_child      at " << max_child->pos() << "\n";
  383.         // clog << "next_max_child at " << next_max_child->pos() << "\n";
  384.  
  385.         // Re-use offset between last two children
  386.         pos = max_child->pos() 
  387.         + (max_child->pos() - next_max_child->pos());
  388.  
  389.         // If MAX_CHILD is on the right of NEXT_MAX_CHILD, place new
  390.         // node on the right; if MAX_CHILD is below NEXT_MAX_CHILD,
  391.         // place new node below.  If position is occupied, try later
  392.         // in the same direction.
  393.         bool horizontal = 
  394.         (abs(max_child->pos()[X] - next_max_child->pos()[X]) >
  395.          abs(max_child->pos()[Y] - next_max_child->pos()[Y]));
  396.  
  397.         offset = horizontal ? 
  398.         BoxPoint(delta[X], 0) : BoxPoint(0, delta[Y]);
  399.     }
  400.     else if (max_child)
  401.     {
  402.         // Place new child below last child
  403.         //
  404.         //   NODE ->     MAX_CHILD
  405.         //        \->    (new)
  406.  
  407.         // clog << "child          at " << max_child->pos() << "\n";
  408.  
  409.         // If MAX_CHILD is on the right of NODE, place new node below;
  410.         // if MAX_CHILD is below NODE, place new node on the right.
  411.         bool horizontal = 
  412.         (abs(max_child->pos()[X] - node->pos()[X]) >
  413.          abs(max_child->pos()[Y] - node->pos()[Y]));
  414.         offset = horizontal ? 
  415.         BoxPoint(0, delta[Y]) : BoxPoint(delta[X], 0);
  416.  
  417.         pos = max_child->pos() + offset;
  418.     }
  419.     else
  420.     {
  421.         GraphEdge *edge = node->firstTo();
  422.         if (edge)
  423.         {
  424.         // We have a predecessor: use this offset instead
  425.         //
  426.         // PARENT -> NODE -> (new)
  427.         //
  428.  
  429.         GraphNode *parent = edge->from();
  430.         assert(parent->pos().isValid());
  431.  
  432.         // clog << "parent         at " << parent->pos() << "\n";
  433.  
  434.         // Re-use offset between parent and node
  435.         pos = node->pos() + (node->pos() - parent->pos());
  436.  
  437.         // If NODE is on the right of PARENT, place new node on
  438.         // the right; if NODE is below PARENT, place new node
  439.         // below.
  440.         bool horizontal = 
  441.             (abs(node->pos()[X] - parent->pos()[X]) >
  442.              abs(node->pos()[Y] - parent->pos()[Y]));
  443.  
  444.         offset = horizontal ? BoxPoint(delta[X], 0) 
  445.             : BoxPoint(0, delta[Y]);
  446.         }
  447.     }
  448.     }
  449.  
  450.     assert(pos.isValid());
  451.     assert(offset.isValid());
  452.  
  453.     return adjust_position(new_node, w, pos, offset, grid);
  454. }
  455.  
  456. // Find all hints in edges leading to NODE; store them in HINTS
  457. void DispGraph::find_hints_to(GraphNode *node, GraphNodePointerArray& hints)
  458. {
  459.     for (GraphEdge *edge = node->firstTo();
  460.      edge != 0;
  461.      edge = node->nextTo(edge))
  462.     {
  463.     if (edge->from()->isHint())
  464.     {
  465.         find_hints_to(edge->from(), hints);
  466.         hints += edge->from();
  467.     }
  468.     }
  469. }
  470.  
  471. // Find all hints in edges coming from NODE; store them in HINTS
  472. void DispGraph::find_hints_from(GraphNode *node, GraphNodePointerArray& hints)
  473. {
  474.     for (GraphEdge *edge = node->firstFrom();
  475.      edge != 0;
  476.      edge = node->nextFrom(edge))
  477.     {
  478.     if (edge->to()->isHint())
  479.     {
  480.         find_hints_from(edge->to(), hints);
  481.         hints += edge->to();
  482.     }
  483.     }
  484. }
  485.  
  486. // Remove an edge from graph and from memory
  487. void DispGraph::delete_edge(GraphEdge *edge)
  488. {
  489.     *this -= edge;
  490.     delete edge;
  491. }
  492.  
  493. // Remove a node and all its edges
  494. void DispGraph::delete_node(GraphNode *node)
  495. {
  496.     // Remove all edges
  497.     GraphEdge *e;
  498.     while ((e = node->firstFrom()) != 0)
  499.     delete_edge(e);
  500.     while ((e = node->firstTo()) != 0)
  501.     delete_edge(e);
  502.  
  503.     // Remove node from graph
  504.     *this -= node;
  505.     delete node;
  506. }
  507.  
  508. // Delete display
  509. bool DispGraph::del (int disp_nr)
  510. {
  511.     if (!idMap.contains (disp_nr))
  512.     return false;
  513.  
  514.     unalias(disp_nr);
  515.     DispNode* dn = idMap.get(disp_nr);
  516.  
  517.     GraphNodePointerArray hints;
  518.  
  519.     find_hints_from(dn, hints);
  520.     find_hints_to(dn, hints);
  521.     for (int i = 0; i < hints.size(); i++)
  522.     delete_node(hints[i]);
  523.  
  524.     delete_node(dn);
  525.     idMap.del(disp_nr);
  526.  
  527.     if (idMap.length() == 0)
  528.     handlers.call(DispGraph_Empty, this, (void*)true);
  529.     if (!no_enabled)
  530.     if ((no_enabled = (count_all(Enabled) == 0)))
  531.         handlers.call(NoEnabled, this, (void*)true);
  532.     if (!no_disabled)
  533.     if ((no_disabled = (count_all(Disabled) == 0)))
  534.         handlers.call(NoDisabled, this, (void*)true);
  535.  
  536.     refresh_titles();
  537.     return true;
  538. }
  539.  
  540. // Return display number of NODE
  541. int DispGraph::get_nr(BoxGraphNode *node) const
  542. {
  543.     DispNode *dn = ptr_cast(DispNode, node);
  544.     return dn == 0 ? 0 : dn->disp_nr();
  545. }
  546.  
  547.  
  548. // Get number of node NAME
  549. int DispGraph::get_by_name(const string& name) const
  550. {
  551.     if (name.matches(rxint))
  552.     return atoi(name);
  553.  
  554.     MapRef ref;
  555.     for (int k = idMap.first_key(ref); k != 0; k = idMap.next_key(ref))
  556.     if (idMap.get(k)->name() == name)
  557.         return k;
  558.     return 0;
  559. }
  560.  
  561.  
  562. // Return first node; 0 if not found
  563. DispNode* DispGraph::first (MapRef& ref, Displaying e) const
  564. {
  565.     for (DispNode* dn = idMap.first(ref); dn != 0; dn = idMap.next(ref)) {
  566.     switch (e) {
  567.     case Both:
  568.         return dn;
  569.  
  570.     case Enabled:
  571.         if (dn->enabled())
  572.         return dn;
  573.         break;
  574.  
  575.     case Disabled:
  576.         if (!dn->enabled())
  577.         return dn;
  578.         break;
  579.  
  580.     default:
  581.         assert (0);        // This can't happen
  582.         break;
  583.     }
  584.     }
  585.     return 0;
  586. }
  587.  
  588.  
  589. // Return next node; 0 if not found
  590. DispNode* DispGraph::next (MapRef& ref, Displaying e) const
  591. {
  592.     for (DispNode* dn = idMap.next(ref); dn != 0; dn = idMap.next(ref)) {
  593.     switch (e) {
  594.     case Both:
  595.         return dn;
  596.  
  597.     case Enabled:
  598.         if (dn->enabled())
  599.         return dn;
  600.         break;
  601.  
  602.     case Disabled:
  603.         if (!dn->enabled())
  604.         return dn;
  605.         break;
  606.  
  607.     default:
  608.         assert (0);        // This can't happen.
  609.         break;
  610.     }
  611.     }
  612.     return 0;
  613. }
  614.  
  615. // Return number of first node; 0 if not found
  616. int DispGraph::first_nr (MapRef& ref, Displaying e) const
  617. {
  618.     for (int k = idMap.first_key(ref); k != 0; k = idMap.next_key(ref)) {
  619.     switch (e) {
  620.     case Both:
  621.         return k;
  622.  
  623.     case Enabled:
  624.         if (idMap.get (k)->enabled())
  625.         return k;
  626.         break;
  627.  
  628.     case Disabled:
  629.         if (!idMap.get (k)->enabled())
  630.         return k;
  631.         break;
  632.  
  633.     default:
  634.         assert (0);        // This can't happen.
  635.         break;
  636.     }
  637.     }
  638.     return 0;
  639. }
  640.  
  641. // Return next node number; 0 if not found
  642. int DispGraph::next_nr (MapRef& ref, Displaying e) const
  643. {
  644.     for (int k = idMap.next_key(ref); k != 0; k = idMap.next_key(ref)) {
  645.     switch (e) {
  646.     case Both:
  647.         return k;
  648.  
  649.     case Enabled:
  650.         if (idMap.get(k)->enabled())
  651.         return k;
  652.         break;
  653.  
  654.     case Disabled:
  655.         if (!idMap.get(k)->enabled())
  656.         return k;
  657.         break;
  658.  
  659.     default:
  660.         assert (0);        // This can't happen
  661.         break;
  662.     }
  663.     }
  664.     return 0;
  665. }
  666.  
  667. // Helper for disabling nodes
  668. void DispGraph::disp_node_disabledHP (void*,
  669.                       void* client_data,
  670.                       void* call_data)
  671. {
  672.     DispGraph* disp_graph = (DispGraph*) client_data;
  673.     bool    disabled   = bool(call_data);
  674.  
  675.     if (disabled) {
  676.     if (disp_graph->no_disabled) {
  677.         disp_graph->no_disabled = false;
  678.         disp_graph->handlers.call(NoDisabled, disp_graph, (void*)false);
  679.     }
  680.     if (disp_graph->no_enabled = (disp_graph->count_all(Enabled) == 0))
  681.         disp_graph->handlers.call(NoEnabled, disp_graph, (void*)true);
  682.     }
  683.     else {
  684.     if (disp_graph->no_enabled) {
  685.         disp_graph->no_enabled = false;
  686.         disp_graph->handlers.call(NoEnabled, disp_graph, (void*)false);
  687.     }
  688.     if (disp_graph->no_disabled = (disp_graph->count_all(Disabled) == 0))
  689.         disp_graph->handlers.call(NoDisabled, disp_graph, (void*)true);
  690.     }
  691. }
  692.  
  693.  
  694. //-------------------------------------------------------------------------
  695. // Alias handling
  696. //-------------------------------------------------------------------------
  697.  
  698. // Make DISP_NR an alias of ALIAS_DISP_NR.  Suppress ALIAS_DISP_NR.
  699. bool DispGraph::alias(Widget w, int disp_nr, int alias_disp_nr)
  700. {
  701.     DispNode *d0 = get(disp_nr);
  702.     DispNode *dn = get(alias_disp_nr);
  703.  
  704.     if (d0 == 0 || dn == 0)
  705.     return false;
  706.  
  707.     if (!dn->active())
  708.     {
  709.     // Already hidden because it is out of scope
  710.     return false;
  711.     }
  712.  
  713.     if (dn->clustered())
  714.     {
  715.     // Already hidden because it is clustered
  716.     return false;
  717.     }
  718.  
  719.     if (dn->hidden() && dn->alias_of == disp_nr)
  720.     {
  721.     // Already hidden as alias of DISP_NR
  722.     return false;
  723.     }
  724.  
  725.     if (dn->hidden())
  726.     unalias(alias_disp_nr);
  727.  
  728.     // Hide alias
  729.     dn->hidden() = true;
  730.     dn->alias_of = disp_nr;
  731.  
  732.     // Clear any special selections in this alias
  733.     dn->select();
  734.  
  735.     // Hide ordinary hints and insert new alias edges
  736.     GraphEdge *edge;
  737.     GraphNodePointerArray from_nodes;
  738.     GraphNodePointerArray to_nodes;
  739.     EdgeAnnotationPointerArray from_annotations;
  740.     EdgeAnnotationPointerArray to_annotations;
  741.     int i;
  742.  
  743.     for (edge = dn->firstFrom(); edge != 0; edge = dn->nextFrom(edge))
  744.     {
  745.     GraphEdge *e = edge;
  746.     while (e->to()->isHint())
  747.     {
  748.         e->to()->hidden() = true;
  749.         e = e->to()->firstFrom();
  750.     }
  751.     to_nodes += e->to();
  752.  
  753.     EdgeAnnotation *anno = 0;
  754.     LineGraphEdge *ge = ptr_cast(LineGraphEdge, e);
  755.     if (ge != 0)
  756.         anno = ge->annotation();
  757.     to_annotations += anno;
  758.     }
  759.     for (edge = dn->firstTo(); edge != 0; edge = dn->nextTo(edge))
  760.     {
  761.     GraphEdge *e = edge;
  762.     while (e->from()->isHint())
  763.     {
  764.         e->from()->hidden() = true;
  765.         e = e->from()->firstTo();
  766.     }
  767.     from_nodes += e->from();
  768.  
  769.     EdgeAnnotation *anno = 0;
  770.     LineGraphEdge *ge = ptr_cast(LineGraphEdge, e);
  771.     if (ge != 0)
  772.         anno = ge->annotation();
  773.     from_annotations += anno;
  774.     }
  775.  
  776.     for (i = 0; i < to_nodes.size(); i++)
  777.     add_alias_edge(w, alias_disp_nr, 
  778.                d0, to_nodes[i], to_annotations[i]);
  779.     for (i = 0; i < from_nodes.size(); i++)
  780.     add_alias_edge(w, alias_disp_nr, 
  781.                from_nodes[i], d0, from_annotations[i]);
  782.  
  783.     // Propagate `selected' state to hints
  784.     for (GraphNode *node = firstNode(); node != 0; node = nextNode(node))
  785.     {
  786.     if (!node->isHint())
  787.         continue;
  788.     AliasGraphEdge *edge = ptr_cast(AliasGraphEdge, node->firstTo());
  789.     if (edge == 0)
  790.         continue;
  791.     if (edge->disp_nr() == alias_disp_nr)
  792.         node->selected() = dn->selected();
  793.     }
  794.  
  795.     return true;
  796. }
  797.  
  798.  
  799. // Un-alias ALIAS_DISP_NR.  Unsuppress ALIAS_DISP_NR.  Return true iff
  800. // changed.
  801. bool DispGraph::unalias(int alias_disp_nr)
  802. {
  803.     DispNode *dn = get(alias_disp_nr);
  804.     if (dn == 0 || !dn->active() || dn->clustered())
  805.     return false;
  806.  
  807.     if (!dn->hidden())
  808.     return false;
  809.  
  810.     // Unsuppress display
  811.     dn->hidden() = false;
  812.  
  813.     // Delete all alias edges associated with this node
  814.     VoidArray kill_edges;
  815.     GraphEdge *edge;
  816.     for (edge = firstEdge(); edge != 0; edge = nextEdge(edge))
  817.     {
  818.     AliasGraphEdge *e = ptr_cast(AliasGraphEdge, edge);
  819.     if (e != 0 && e->disp_nr() == alias_disp_nr)
  820.         kill_edges += (void *)e;
  821.     }
  822.     for (int i = 0; i < kill_edges.size(); i++)
  823.     {
  824.     AliasGraphEdge *e = (AliasGraphEdge *)kill_edges[i];
  825.     if (e->to()->isHint())
  826.     {
  827.         *this -= e->to();    // Also removes E from graph
  828.         delete e->to();
  829.     }
  830.     else
  831.     {
  832.         *this -= e;
  833.     }
  834.     delete e;
  835.     }
  836.  
  837.     // Unsuppress remaining (ordinary) hints
  838.     for (edge = dn->firstFrom(); edge != 0; edge = dn->nextFrom(edge))
  839.     {
  840.     GraphEdge *e = edge;
  841.     while (e->to()->isHint())
  842.     {
  843.         e->to()->hidden() = false;
  844.         e = e->to()->firstFrom();
  845.     }
  846.     }
  847.     for (edge = dn->firstTo(); edge != 0; edge = dn->nextTo(edge))
  848.     {
  849.     GraphEdge *e = edge;
  850.     while (e->from()->isHint())
  851.     {
  852.         e->from()->hidden() = false;
  853.         e = e->from()->firstTo();
  854.     }
  855.     }
  856.  
  857.     dn->alias_of = 0;
  858.     return true;
  859. }
  860.  
  861.  
  862.  
  863. //-----------------------------------------------------------------------------
  864. // Routing
  865. //-----------------------------------------------------------------------------
  866.  
  867. // True iff R->P1 and R->P2 have the same angle
  868. bool DispGraph::same_angle(const BoxPoint& r,
  869.                const BoxPoint& p1,
  870.                const BoxPoint& p2)
  871. {
  872.     if (p1 == r || p2 == r)
  873.     return false;        // No angle to determine
  874.  
  875.     double angle1 = atan2(double(r[Y] - p1[Y]), double(r[X] - p1[X]));
  876.     double angle2 = atan2(double(r[Y] - p2[Y]), double(r[X] - p2[X]));
  877.  
  878.     const double epsilon = 0.1;
  879.     return fabs(angle1 - angle2) < epsilon;
  880. }
  881.  
  882. // True iff NODE is attached to an edge with the same angle as P
  883. bool DispGraph::has_angle(PosGraphNode *node, const BoxPoint& p)
  884. {
  885.     GraphEdge *edge;
  886.     for (edge = node->firstFrom(); edge != 0; edge = node->nextFrom(edge))
  887.     {
  888.     if (same_angle(node->pos(), edge->to()->pos(), p))
  889.         return true;
  890.     }
  891.     for (edge = node->firstTo(); edge != 0; edge = node->nextTo(edge))
  892.     {
  893.     if (same_angle(node->pos(), edge->from()->pos(), p))
  894.         return true;
  895.     }
  896.  
  897.     return false;
  898. }
  899.  
  900. // Add a new edge in existing graph
  901. void DispGraph::add_alias_edge(Widget w, int alias_disp_nr, 
  902.                    GraphNode *_from, GraphNode *_to,
  903.                    EdgeAnnotation *anno)
  904. {
  905.     PosGraphNode *from = ptr_cast(PosGraphNode, _from);
  906.     PosGraphNode *to   = ptr_cast(PosGraphNode, _to);
  907.  
  908.     if (anno != 0)
  909.     anno = anno->dup();
  910.  
  911.     // Check whether the new edge may be hidden by existing edges
  912.     if (from == to || (from == 0 || to == 0))
  913.     {
  914.     // Self-referring edge or bad nodes
  915.     add_direct_alias_edge(w, alias_disp_nr, _from, _to, anno);
  916.     }
  917.     else
  918.     {
  919.     // Check for interferences with existing edge
  920.     add_routed_alias_edge(w, alias_disp_nr, from, to, anno);
  921.     }
  922. }
  923.  
  924. // Add a direct edge from FROM to TO
  925. void DispGraph::add_direct_alias_edge(Widget, int alias_disp_nr, 
  926.                       GraphNode *from, GraphNode *to,
  927.                       EdgeAnnotation *anno)
  928. {
  929.     *this += new AliasGraphEdge(alias_disp_nr, from, to, anno);
  930. }
  931.  
  932. // Check whether P is obscured by any node
  933. bool DispGraph::is_hidden(Widget w, const BoxPoint& p) const
  934. {
  935.     const GraphGC& graphGC = graphEditGetGraphGC(w);
  936.  
  937.     for (GraphNode *n = firstVisibleNode(); n != 0; n = nextVisibleNode(n))
  938.     {
  939.     RegionGraphNode *node = ptr_cast(RegionGraphNode, n);
  940.     if (node == 0)
  941.         continue;
  942.  
  943.     if (p == node->pos() || p <= node->sensitiveRegion(graphGC))
  944.         return true;
  945.     }
  946.  
  947.     return false;
  948. }
  949.  
  950. // Rotate offset P by ANGLE (in degrees)
  951. BoxPoint DispGraph::rotate_offset(const BoxPoint& p, int angle)
  952. {
  953.     if (p == BoxPoint(0, 0))
  954.     return p;
  955.  
  956.     double length = hypot(p[X], p[Y]);
  957.     double alpha  = atan2(double(p[X]), double(p[Y]));
  958.  
  959.     alpha += (2.0 * PI * angle / 360.0);
  960.  
  961.     return BoxPoint(BoxCoordinate(length * cos(alpha)), 
  962.             BoxCoordinate(length * sin(alpha)));
  963. }
  964.  
  965.  
  966. // Check whether POS1 and POS2 are okay as hint positions for FROM and TO
  967. bool DispGraph::hint_positions_ok(Widget w,
  968.                   PosGraphNode *from,
  969.                   PosGraphNode *to,
  970.                   const BoxPoint& pos1,
  971.                   const BoxPoint& pos2) const
  972. {
  973.     BoxPoint p1 = graphEditFinalPosition(w, pos1);
  974.     BoxPoint p2 = graphEditFinalPosition(w, pos2);
  975.  
  976.     if (p1[X] <= 0 || p2[X] <= 0 || p1[Y] <= 0 || p2[Y] <= 0)
  977.     return false;        // Bad coordinates
  978.     
  979.     if (p1 == from->pos() && p2 == to->pos())
  980.     {
  981.     // Direct edge
  982.     if (has_angle(from, to->pos()))
  983.         return false;    // New edge obscured by existing edge
  984.     if (has_angle(to, from->pos()))
  985.         return false;    // New edge obscured by existing edge
  986.     }
  987.     else
  988.     {
  989.     // One or two hints
  990.     if (has_angle(from, p1))
  991.         return false;    // New edge obscured by existing edge
  992.     if (has_angle(to, p2))
  993.         return false;    // New edge obscured by existing edge
  994.     if (is_hidden(w, p1))
  995.         return false;    // Hint obscured by existing node
  996.     if (is_hidden(w, p2))
  997.         return false;    // Hint obscured by existing node
  998.     }
  999.  
  1000.     BoxPoint dist = p2 - p1;
  1001.     if (dist[X] > 0 || dist[Y] > 0)
  1002.     {
  1003.     BoxPoint center = graphEditFinalPosition(w, p1 + dist / 2);
  1004.     if (is_hidden(w, center))    // Center obscured by existing node
  1005.         return false;
  1006.     }
  1007.  
  1008.     return true;
  1009. }
  1010.  
  1011.  
  1012. // Add edge from FROM to TO, inserting hints if required
  1013. void DispGraph::add_routed_alias_edge(Widget w, int alias_disp_nr, 
  1014.                       PosGraphNode *from, PosGraphNode *to,
  1015.                       EdgeAnnotation *anno)
  1016. {
  1017.     // Determine hint offsets
  1018.     Dimension grid_height = 16;
  1019.     Dimension grid_width  = 16;
  1020.     XtVaGetValues(w,
  1021.           XtNgridHeight, &grid_height,
  1022.           XtNgridWidth,  &grid_width,
  1023.           NULL);
  1024.  
  1025.     BoxPoint dist   = to->pos() - from->pos();
  1026.     BoxPoint center = from->pos() + dist / 2;
  1027.     double angle    = atan2(double(dist[X]), double(dist[Y]));
  1028.     BoxPoint grid_offset(BoxCoordinate(grid_width  * cos(angle)),
  1029.              BoxCoordinate(grid_height * sin(angle)));
  1030.  
  1031.     const int LEFT  = 1;
  1032.     const int RIGHT = 0;
  1033.  
  1034.     BoxPoint offsets[2];
  1035.     offsets[LEFT]  = rotate_offset(grid_offset, +90);
  1036.     offsets[RIGHT] = rotate_offset(grid_offset, -90);
  1037.  
  1038. #if 0
  1039.     clog << "offsets[LEFT]  = " << offsets[LEFT]  << "\n";
  1040.     clog << "offsets[RIGHT] = " << offsets[RIGHT] << "\n";
  1041. #endif
  1042.  
  1043.     // Try hint offsets
  1044.     BoxPoint pos1, pos2;
  1045.     bool found = false;
  1046.  
  1047.     const bool try_direct = false;
  1048.  
  1049.     const int max_iterations = 100;
  1050.     for (int i = 0; i < max_iterations && !found; i++)
  1051.     {
  1052.     for (int side = RIGHT; !found && side <= LEFT; side++)
  1053.     {
  1054.         BoxPoint offset = offsets[side] * i;
  1055.  
  1056.         if (try_direct && i == 0)
  1057.         {
  1058.         // Try direct edge
  1059.         pos1 = from->pos() + offset;
  1060.         pos2 = to->pos()   + offset;
  1061.         }        
  1062.         else
  1063.         {
  1064.         // Try one-hint edge
  1065.         pos1 = pos2 = center + offset;
  1066.         }
  1067. #if 0
  1068.         clog << "#" << i << " - "
  1069.          << (side == LEFT ? "left side:  " : "right side: ")
  1070.          << "trying pos1 = " << pos1 
  1071.          << " and pos2 = " << pos2 << "\n";
  1072. #endif
  1073.  
  1074.         found = hint_positions_ok(w, from, to, pos1, pos2);
  1075.     }
  1076.     }
  1077.  
  1078.     if (!found)
  1079.     {
  1080.     // Give up
  1081.     cerr << "Warning: could not find edge route after " 
  1082.          << max_iterations << " iterations\n";
  1083.     pos1 = from->pos();
  1084.     pos2 = to->pos();
  1085.     }
  1086.  
  1087.     if (try_direct && pos1 == from->pos() && pos2 == to->pos())
  1088.     {
  1089.     // No need for hints - add direct edge
  1090.     add_direct_alias_edge(w, alias_disp_nr, from, to, anno);
  1091.     }
  1092.     else
  1093.     {
  1094. #if 0
  1095.     assert(!try_direct || pos1 == pos2);
  1096. #endif
  1097.  
  1098.     // Add single hint
  1099.     HintGraphNode *hint = new HintGraphNode(pos1);
  1100.     hint->hidden() = from->hidden() || to->hidden();
  1101.     *this += hint;
  1102.  
  1103.     // Add edges
  1104.     *this += new AliasGraphEdge(alias_disp_nr, from, hint, anno);
  1105.     *this += new AliasGraphEdge(alias_disp_nr, hint, to);
  1106.     }
  1107. }
  1108.  
  1109.  
  1110.  
  1111. //-----------------------------------------------------------------------------
  1112. // Display clustering
  1113. //-----------------------------------------------------------------------------
  1114.  
  1115. // Hide/Unhide all alias edges of NODE according to its status
  1116. void DispGraph::update_alias_edges(DispNode *node)
  1117. {
  1118.     for (GraphEdge *edge = firstEdge(); edge != 0; edge = nextEdge(edge))
  1119.     {
  1120.     AliasGraphEdge *e = ptr_cast(AliasGraphEdge, edge);
  1121.     if (e != 0 && e->disp_nr() == node->disp_nr())
  1122.     {
  1123.         if (e->to()->isHint())
  1124.         e->to()->hidden() = node->hidden();
  1125.         e->hidden() = node->hidden();
  1126.     }
  1127.     }
  1128. }
  1129.  
  1130. void DispGraph::cluster(DispNode *dn, int cluster)
  1131. {
  1132.     dn->cluster(cluster);
  1133.     update_alias_edges(dn);
  1134. }
  1135.  
  1136.  
  1137. //-----------------------------------------------------------------------------
  1138. // Display activation
  1139. //-----------------------------------------------------------------------------
  1140.  
  1141. bool DispGraph::hide_inactive_displays = true;
  1142.  
  1143. bool DispGraph::make_inactive(DispNode *dn)
  1144. {
  1145.     if (dn->active() && dn->enabled())
  1146.     {
  1147.     if (!hide_inactive_displays)
  1148.     {
  1149.         dn->disable();
  1150.     }
  1151.     else
  1152.     {
  1153.         dn->make_inactive();
  1154.         update_alias_edges(dn);
  1155.     }
  1156.     return true;
  1157.     }
  1158.  
  1159.     return false;
  1160. }
  1161.  
  1162. bool DispGraph::make_active(DispNode *dn)
  1163. {
  1164.     if (!dn->active())
  1165.     {
  1166.     dn->make_active();
  1167.     update_alias_edges(dn);
  1168.  
  1169.     return true;
  1170.     }
  1171.  
  1172.     return false;
  1173. }
  1174.  
  1175.  
  1176.  
  1177. //-----------------------------------------------------------------------------
  1178. // Title stuff
  1179. //-----------------------------------------------------------------------------
  1180.  
  1181. bool DispGraph::refresh_titles() const
  1182. {
  1183.     bool changed = false;
  1184.  
  1185.     MapRef ref;
  1186.     for (DispNode *dn = first(ref); dn != 0; dn = next(ref))
  1187.     {
  1188.     bool is_dependent = false;
  1189.     for (GraphEdge *e = dn->firstTo(); e != 0; e = dn->nextTo(e))
  1190.     {
  1191.         if (e->from() == dn)
  1192.         continue;    // Self edge
  1193.         if (ptr_cast(AliasGraphEdge, e) != 0)
  1194.         continue;    // Alias edge
  1195.         if (e->from()->hidden())
  1196.         continue;    // Invisible edge
  1197.  
  1198.         LineGraphEdge *le = ptr_cast(LineGraphEdge, e);
  1199.         if (le != 0 && le->annotation() != 0)
  1200.         {
  1201.         is_dependent = true;
  1202.         break;
  1203.         }
  1204.     }
  1205.  
  1206.     bool need_title = false;
  1207.     if (is_dependent && app_data.show_dependent_display_titles)
  1208.         need_title = true;
  1209.     else if (!is_dependent && app_data.show_base_display_titles)
  1210.         need_title = true;
  1211.  
  1212.     if (dn->set_title(need_title))
  1213.         changed = true;
  1214.     }
  1215.  
  1216.     return changed;
  1217. }
  1218.  
  1219.  
  1220. //-----------------------------------------------------------------------------
  1221. // Plotting
  1222. //-----------------------------------------------------------------------------
  1223.  
  1224. // Print all plots
  1225. void DispGraph::print_plots(const string& filename, const GraphGC& gc) const
  1226. {
  1227.     for (GraphNode *node = firstVisibleNode(); node != 0; 
  1228.      node = nextVisibleNode(node))
  1229.     {
  1230.     DispNode *dn = ptr_cast(DispNode, node);
  1231.     if (dn == 0)
  1232.         continue;
  1233.  
  1234.     if (gc.printSelectedNodesOnly && !dn->selected())
  1235.         continue;
  1236.  
  1237.     dn->print_plots(filename, gc);
  1238.     }
  1239. }
  1240.