home *** CD-ROM | disk | FTP | other *** search
- // $Id: DispGraph.C,v 1.45 1998/11/17 11:22:32 zeller Exp $
- // Store information about all displayed display expressions
-
- // Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
- // Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
- // and Andreas Zeller <zeller@ips.cs.tu-bs.de>
- //
- // This file is part of DDD.
- //
- // DDD is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public
- // License as published by the Free Software Foundation; either
- // version 2 of the License, or (at your option) any later version.
- //
- // DDD is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- // See the GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public
- // License along with DDD -- see the file COPYING.
- // If not, write to the Free Software Foundation, Inc.,
- // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // DDD is the data display debugger.
- // For details, see the DDD World-Wide-Web page,
- // `http://www.cs.tu-bs.de/softech/ddd/',
- // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
-
- char DispGraph_rcsid[] =
- "$Id: DispGraph.C,v 1.45 1998/11/17 11:22:32 zeller Exp $";
-
- #ifdef __GNUG__
- #pragma implementation
- #endif
-
- //-----------------------------------------------------------------------------
- // DispGraph stores information about all displayed display expressions.
- //-----------------------------------------------------------------------------
-
- #include "DispGraph.h"
-
- #include <math.h>
- #include "pi.h"
- #include "hypot.h"
- #include <X11/StringDefs.h>
-
- #include "AppData.h"
- #include "GraphEdit.h"
- #include "assert.h"
- #include "VarArray.h"
- #include "AliasGE.h"
- #include "HintGraphN.h"
- #include "VoidArray.h"
- #include "regexps.h"
- #include "BoxEdgeA.h"
- #include "annotation.h"
- #include "DispBox.h"
- #include "EdgeAPA.h"
-
- DEFINE_TYPE_INFO_1(DispGraph, Graph)
-
-
- //-------------------------------------------------------------------------
- // Basics
- //-------------------------------------------------------------------------
-
- // Constructor
- DispGraph::DispGraph()
- : Graph(), idMap(), handlers(DispGraph_NTypes),
- no_enabled(true), no_disabled(true)
- {
- DispNode::addHandler(DispNode_Disabled,
- disp_node_disabledHP,
- (void*)this);
- }
-
- // Destructor
- DispGraph::~DispGraph()
- {
- DispGraph::clear();
- }
-
- // Delete all
- void DispGraph::clear()
- {
- idMap.delete_all_contents();
- }
-
-
-
- //-------------------------------------------------------------------------
- // Node management
- //-------------------------------------------------------------------------
-
- // Return number of nodes
- int DispGraph::count_all (Displaying e) const
- {
- if (e == Both)
- return idMap.length();
-
- int count = 0;
- MapRef ref;
- for (int k = idMap.first_key(ref); k != 0; k =
- idMap.next_key(ref))
- {
- switch (e)
- {
- case Both:
- count++;
- break;
- case Enabled:
- if (idMap.get(k)->enabled())
- count++;
- break;
- case Disabled:
- if (!(idMap.get(k)->enabled()))
- count++;
- break;
- default:
- // Falscher Fehler
- assert (0);
- break;
- }
- }
- return count;
- }
-
- // Count selected nodes
- int DispGraph::count_selected() const
- {
- int count = 0;
- MapRef ref;
- for (int k = idMap.first_key(ref); k != 0; k = idMap.next_key(ref)) {
- if (!idMap.get(k)->selected())
- count++;
- }
- return count;
- }
-
- // Add an event handler
- void DispGraph::addHandler (unsigned type,
- HandlerProc proc,
- void* client_data)
- {
- handlers.add(type, proc, client_data);
- }
-
- // Remove an event handler
- void DispGraph::removeHandler (unsigned type,
- HandlerProc proc,
- void *client_data)
- {
- handlers.remove(type, proc, client_data);
- }
-
- // Call event handlers
- void DispGraph::callHandlers ()
- {
- handlers.call(DispGraph_Empty,
- this,
- (void*)(count_all() == 0));
- handlers.call(NoEnabled,
- this,
- (void*)(no_enabled));
- handlers.call(NoDisabled,
- this,
- (void*)(no_disabled));
- }
-
-
- // Add a new edge
- void DispGraph::add_edge(DispNode *from, DispNode *to)
- {
- string a = annotation(from->name(), to->name());
- BoxEdgeAnnotation *ann = 0;
- if (a != "")
- ann = new BoxEdgeAnnotation(DispBox::eval("annotation", a));
-
- *this += new LineGraphEdge(from, to, ann);
- }
-
-
- // Insert NEW_DN into graph, return its number iff successful
- int DispGraph::insert(int new_disp_nr, DispNode *new_dn, int depends_on)
- {
- if (idMap.contains(new_disp_nr))
- return 0;
- if (idMap.length() == 0)
- handlers.call(DispGraph_Empty, this, (void*)false);
-
- *this += new_dn;
-
- if (depends_on != 0)
- {
- DispNode *old_dn = idMap.get(depends_on);
- add_edge(old_dn, new_dn);
-
- if (old_dn->clustered())
- {
- DispNode *cluster = idMap.get(old_dn->clustered());
- if (cluster != 0)
- add_edge(cluster, new_dn);
- }
- }
- assert (Graph::OK());
-
- idMap.insert (new_disp_nr, new_dn);
-
- if (no_enabled) {
- if (!( no_enabled = (count_all(Enabled) == 0) ))
- handlers.call(NoEnabled, this, (void*)false);
- }
- if (no_disabled) {
- if (!( no_disabled = (count_all(Disabled) == 0) ))
- handlers.call(NoDisabled, this, (void*)false);
- }
-
- refresh_titles();
-
- return new_disp_nr;
- }
-
-
- // Get a good position for NEW_NODE
- BoxPoint DispGraph::adjust_position (DispNode *new_node,
- Widget w,
- BoxPoint pos,
- BoxPoint offset,
- BoxPoint grid) const
- {
- const GraphGC& graphGC = graphEditGetGraphGC(w);
-
- // clog << "new node at " << pos << "\n";
-
- BoxSize new_size(new_node->box()->size());
-
- // Leave GRID space around the box
- BoxRegion new_region(pos - (new_size + grid) / 2, new_size + grid);
-
- // Make sure the new node is fully visible
- while (new_region.origin()[X] <= 0)
- {
- pos += BoxPoint(grid[X], 0);
- new_region.origin() += BoxPoint(grid[X], 0);
- // clog << "new node now at " << pos << "\n";
- }
-
- while (new_region.origin()[Y] <= 0)
- {
- pos += BoxPoint(0, grid[Y]);
- new_region.origin() += BoxPoint(0, grid[Y]);
- // clog << "new node now at " << pos << "\n";
- }
-
- // Make sure the new node does not obscure existing nodes
- GraphNode *n = firstVisibleNode();
- while (n != 0)
- {
- const BoxRegion& region = n->region(graphGC);
- if (new_region <= region)
- {
- pos += offset;
- new_region.origin() += offset;
-
- n = firstVisibleNode();
- // clog << "new node now at " << pos << "\n";
- }
- else
- n = nextVisibleNode(n);
- }
-
- return pos;
- }
-
- // Return a default position for NEW_NODE
- BoxPoint DispGraph::default_pos(DispNode *new_node,
- Widget w, int depends_on) const
- {
- Dimension grid_height = 16;
- Dimension grid_width = 16;
- Cardinal rotation = 0;
- XtVaGetValues(w,
- XtNgridHeight, &grid_height,
- XtNgridWidth, &grid_width,
- XtNrotation, &rotation,
- NULL);
-
- BoxPoint grid(max(grid_height, 1), max(grid_width, 1));
- BoxPoint delta(grid[X] * 3, grid[Y] * 2);
-
- bool horizontal = rotation % 90;
-
- BoxPoint pos;
- BoxPoint offset;
-
- if (depends_on == 0)
- {
- // Default offset: create new displays orthogonal to
- // dereference direction
- offset = horizontal ? BoxPoint(grid[X], 0) : BoxPoint(0, grid[Y]);
-
- // New node: start with the top-level visible position
- Position x = 0;
- Position y = 0;
- XtVaGetValues(w, XtNx, &x, XtNy, &y, NULL);
- pos = BoxPoint(max(-x, grid[X]), max(-y, grid[Y] * 2));
-
- // Add size offset
- BoxSize new_size(new_node->box()->size());
- pos += new_size / 2;
-
- // Round to nearest grid position
- pos = graphEditFinalPosition(w, pos);
- }
- else
- {
- // Dependent node
-
- // Default offset: create new displays in dereference direction
- offset = horizontal ? BoxPoint(0, delta[Y]) : BoxPoint(delta[X], 0);
-
- // Place new node below/on the right of original node, depending
- // on last layout orientation.
- //
- // NODE -> (new)
-
- BoxGraphNode *node = idMap.get(depends_on);
- // clog << "node at " << node->pos() << "\n";
- pos = node->pos() + offset;
-
- assert(pos.isValid());
-
- // Check if we already have a successor
- BoxGraphNode *max_child = 0;
- BoxGraphNode *next_max_child = 0;
-
- // Find two greatest children
- for (GraphEdge *edge = node->firstFrom();
- edge != 0;
- edge = node->nextFrom(edge))
- {
- BoxDimension d = horizontal ? X : Y;
-
- GraphNode *child = edge->to();
- while (child->isHint())
- child = child->firstFrom()->to();
- if (child->hidden())
- continue;
- if (child == new_node)
- continue;
- if (child->pos() == BoxPoint())
- continue;
-
- BoxGraphNode *bgn = ptr_cast(BoxGraphNode, child);
- if (bgn == 0)
- continue;
-
- if (max_child == 0 || child->pos()[d] > max_child->pos()[d])
- {
- next_max_child = max_child;
- max_child = bgn;
- }
- else if (next_max_child == 0
- || child->pos()[d] > next_max_child->pos()[d])
- {
- next_max_child = bgn;
- }
- }
-
- if (max_child && next_max_child)
- {
- // Re-use offset between the two last children
- //
- // NODE -> .
- // \-> .
- // \-> .
- // \-> NEXT_MAX_CHILD
- // \-> MAX_CHILD
- // \-> (new)
-
- // clog << "max_child at " << max_child->pos() << "\n";
- // clog << "next_max_child at " << next_max_child->pos() << "\n";
-
- // Re-use offset between last two children
- pos = max_child->pos()
- + (max_child->pos() - next_max_child->pos());
-
- // If MAX_CHILD is on the right of NEXT_MAX_CHILD, place new
- // node on the right; if MAX_CHILD is below NEXT_MAX_CHILD,
- // place new node below. If position is occupied, try later
- // in the same direction.
- bool horizontal =
- (abs(max_child->pos()[X] - next_max_child->pos()[X]) >
- abs(max_child->pos()[Y] - next_max_child->pos()[Y]));
-
- offset = horizontal ?
- BoxPoint(delta[X], 0) : BoxPoint(0, delta[Y]);
- }
- else if (max_child)
- {
- // Place new child below last child
- //
- // NODE -> MAX_CHILD
- // \-> (new)
-
- // clog << "child at " << max_child->pos() << "\n";
-
- // If MAX_CHILD is on the right of NODE, place new node below;
- // if MAX_CHILD is below NODE, place new node on the right.
- bool horizontal =
- (abs(max_child->pos()[X] - node->pos()[X]) >
- abs(max_child->pos()[Y] - node->pos()[Y]));
- offset = horizontal ?
- BoxPoint(0, delta[Y]) : BoxPoint(delta[X], 0);
-
- pos = max_child->pos() + offset;
- }
- else
- {
- GraphEdge *edge = node->firstTo();
- if (edge)
- {
- // We have a predecessor: use this offset instead
- //
- // PARENT -> NODE -> (new)
- //
-
- GraphNode *parent = edge->from();
- assert(parent->pos().isValid());
-
- // clog << "parent at " << parent->pos() << "\n";
-
- // Re-use offset between parent and node
- pos = node->pos() + (node->pos() - parent->pos());
-
- // If NODE is on the right of PARENT, place new node on
- // the right; if NODE is below PARENT, place new node
- // below.
- bool horizontal =
- (abs(node->pos()[X] - parent->pos()[X]) >
- abs(node->pos()[Y] - parent->pos()[Y]));
-
- offset = horizontal ? BoxPoint(delta[X], 0)
- : BoxPoint(0, delta[Y]);
- }
- }
- }
-
- assert(pos.isValid());
- assert(offset.isValid());
-
- return adjust_position(new_node, w, pos, offset, grid);
- }
-
- // Find all hints in edges leading to NODE; store them in HINTS
- void DispGraph::find_hints_to(GraphNode *node, GraphNodePointerArray& hints)
- {
- for (GraphEdge *edge = node->firstTo();
- edge != 0;
- edge = node->nextTo(edge))
- {
- if (edge->from()->isHint())
- {
- find_hints_to(edge->from(), hints);
- hints += edge->from();
- }
- }
- }
-
- // Find all hints in edges coming from NODE; store them in HINTS
- void DispGraph::find_hints_from(GraphNode *node, GraphNodePointerArray& hints)
- {
- for (GraphEdge *edge = node->firstFrom();
- edge != 0;
- edge = node->nextFrom(edge))
- {
- if (edge->to()->isHint())
- {
- find_hints_from(edge->to(), hints);
- hints += edge->to();
- }
- }
- }
-
- // Remove an edge from graph and from memory
- void DispGraph::delete_edge(GraphEdge *edge)
- {
- *this -= edge;
- delete edge;
- }
-
- // Remove a node and all its edges
- void DispGraph::delete_node(GraphNode *node)
- {
- // Remove all edges
- GraphEdge *e;
- while ((e = node->firstFrom()) != 0)
- delete_edge(e);
- while ((e = node->firstTo()) != 0)
- delete_edge(e);
-
- // Remove node from graph
- *this -= node;
- delete node;
- }
-
- // Delete display
- bool DispGraph::del (int disp_nr)
- {
- if (!idMap.contains (disp_nr))
- return false;
-
- unalias(disp_nr);
- DispNode* dn = idMap.get(disp_nr);
-
- GraphNodePointerArray hints;
-
- find_hints_from(dn, hints);
- find_hints_to(dn, hints);
- for (int i = 0; i < hints.size(); i++)
- delete_node(hints[i]);
-
- delete_node(dn);
- idMap.del(disp_nr);
-
- if (idMap.length() == 0)
- handlers.call(DispGraph_Empty, this, (void*)true);
- if (!no_enabled)
- if ((no_enabled = (count_all(Enabled) == 0)))
- handlers.call(NoEnabled, this, (void*)true);
- if (!no_disabled)
- if ((no_disabled = (count_all(Disabled) == 0)))
- handlers.call(NoDisabled, this, (void*)true);
-
- refresh_titles();
- return true;
- }
-
- // Return display number of NODE
- int DispGraph::get_nr(BoxGraphNode *node) const
- {
- DispNode *dn = ptr_cast(DispNode, node);
- return dn == 0 ? 0 : dn->disp_nr();
- }
-
-
- // Get number of node NAME
- int DispGraph::get_by_name(const string& name) const
- {
- if (name.matches(rxint))
- return atoi(name);
-
- MapRef ref;
- for (int k = idMap.first_key(ref); k != 0; k = idMap.next_key(ref))
- if (idMap.get(k)->name() == name)
- return k;
- return 0;
- }
-
-
- // Return first node; 0 if not found
- DispNode* DispGraph::first (MapRef& ref, Displaying e) const
- {
- for (DispNode* dn = idMap.first(ref); dn != 0; dn = idMap.next(ref)) {
- switch (e) {
- case Both:
- return dn;
-
- case Enabled:
- if (dn->enabled())
- return dn;
- break;
-
- case Disabled:
- if (!dn->enabled())
- return dn;
- break;
-
- default:
- assert (0); // This can't happen
- break;
- }
- }
- return 0;
- }
-
-
- // Return next node; 0 if not found
- DispNode* DispGraph::next (MapRef& ref, Displaying e) const
- {
- for (DispNode* dn = idMap.next(ref); dn != 0; dn = idMap.next(ref)) {
- switch (e) {
- case Both:
- return dn;
-
- case Enabled:
- if (dn->enabled())
- return dn;
- break;
-
- case Disabled:
- if (!dn->enabled())
- return dn;
- break;
-
- default:
- assert (0); // This can't happen.
- break;
- }
- }
- return 0;
- }
-
- // Return number of first node; 0 if not found
- int DispGraph::first_nr (MapRef& ref, Displaying e) const
- {
- for (int k = idMap.first_key(ref); k != 0; k = idMap.next_key(ref)) {
- switch (e) {
- case Both:
- return k;
-
- case Enabled:
- if (idMap.get (k)->enabled())
- return k;
- break;
-
- case Disabled:
- if (!idMap.get (k)->enabled())
- return k;
- break;
-
- default:
- assert (0); // This can't happen.
- break;
- }
- }
- return 0;
- }
-
- // Return next node number; 0 if not found
- int DispGraph::next_nr (MapRef& ref, Displaying e) const
- {
- for (int k = idMap.next_key(ref); k != 0; k = idMap.next_key(ref)) {
- switch (e) {
- case Both:
- return k;
-
- case Enabled:
- if (idMap.get(k)->enabled())
- return k;
- break;
-
- case Disabled:
- if (!idMap.get(k)->enabled())
- return k;
- break;
-
- default:
- assert (0); // This can't happen
- break;
- }
- }
- return 0;
- }
-
- // Helper for disabling nodes
- void DispGraph::disp_node_disabledHP (void*,
- void* client_data,
- void* call_data)
- {
- DispGraph* disp_graph = (DispGraph*) client_data;
- bool disabled = bool(call_data);
-
- if (disabled) {
- if (disp_graph->no_disabled) {
- disp_graph->no_disabled = false;
- disp_graph->handlers.call(NoDisabled, disp_graph, (void*)false);
- }
- if (disp_graph->no_enabled = (disp_graph->count_all(Enabled) == 0))
- disp_graph->handlers.call(NoEnabled, disp_graph, (void*)true);
- }
- else {
- if (disp_graph->no_enabled) {
- disp_graph->no_enabled = false;
- disp_graph->handlers.call(NoEnabled, disp_graph, (void*)false);
- }
- if (disp_graph->no_disabled = (disp_graph->count_all(Disabled) == 0))
- disp_graph->handlers.call(NoDisabled, disp_graph, (void*)true);
- }
- }
-
-
- //-------------------------------------------------------------------------
- // Alias handling
- //-------------------------------------------------------------------------
-
- // Make DISP_NR an alias of ALIAS_DISP_NR. Suppress ALIAS_DISP_NR.
- bool DispGraph::alias(Widget w, int disp_nr, int alias_disp_nr)
- {
- DispNode *d0 = get(disp_nr);
- DispNode *dn = get(alias_disp_nr);
-
- if (d0 == 0 || dn == 0)
- return false;
-
- if (!dn->active())
- {
- // Already hidden because it is out of scope
- return false;
- }
-
- if (dn->clustered())
- {
- // Already hidden because it is clustered
- return false;
- }
-
- if (dn->hidden() && dn->alias_of == disp_nr)
- {
- // Already hidden as alias of DISP_NR
- return false;
- }
-
- if (dn->hidden())
- unalias(alias_disp_nr);
-
- // Hide alias
- dn->hidden() = true;
- dn->alias_of = disp_nr;
-
- // Clear any special selections in this alias
- dn->select();
-
- // Hide ordinary hints and insert new alias edges
- GraphEdge *edge;
- GraphNodePointerArray from_nodes;
- GraphNodePointerArray to_nodes;
- EdgeAnnotationPointerArray from_annotations;
- EdgeAnnotationPointerArray to_annotations;
- int i;
-
- for (edge = dn->firstFrom(); edge != 0; edge = dn->nextFrom(edge))
- {
- GraphEdge *e = edge;
- while (e->to()->isHint())
- {
- e->to()->hidden() = true;
- e = e->to()->firstFrom();
- }
- to_nodes += e->to();
-
- EdgeAnnotation *anno = 0;
- LineGraphEdge *ge = ptr_cast(LineGraphEdge, e);
- if (ge != 0)
- anno = ge->annotation();
- to_annotations += anno;
- }
- for (edge = dn->firstTo(); edge != 0; edge = dn->nextTo(edge))
- {
- GraphEdge *e = edge;
- while (e->from()->isHint())
- {
- e->from()->hidden() = true;
- e = e->from()->firstTo();
- }
- from_nodes += e->from();
-
- EdgeAnnotation *anno = 0;
- LineGraphEdge *ge = ptr_cast(LineGraphEdge, e);
- if (ge != 0)
- anno = ge->annotation();
- from_annotations += anno;
- }
-
- for (i = 0; i < to_nodes.size(); i++)
- add_alias_edge(w, alias_disp_nr,
- d0, to_nodes[i], to_annotations[i]);
- for (i = 0; i < from_nodes.size(); i++)
- add_alias_edge(w, alias_disp_nr,
- from_nodes[i], d0, from_annotations[i]);
-
- // Propagate `selected' state to hints
- for (GraphNode *node = firstNode(); node != 0; node = nextNode(node))
- {
- if (!node->isHint())
- continue;
- AliasGraphEdge *edge = ptr_cast(AliasGraphEdge, node->firstTo());
- if (edge == 0)
- continue;
- if (edge->disp_nr() == alias_disp_nr)
- node->selected() = dn->selected();
- }
-
- return true;
- }
-
-
- // Un-alias ALIAS_DISP_NR. Unsuppress ALIAS_DISP_NR. Return true iff
- // changed.
- bool DispGraph::unalias(int alias_disp_nr)
- {
- DispNode *dn = get(alias_disp_nr);
- if (dn == 0 || !dn->active() || dn->clustered())
- return false;
-
- if (!dn->hidden())
- return false;
-
- // Unsuppress display
- dn->hidden() = false;
-
- // Delete all alias edges associated with this node
- VoidArray kill_edges;
- GraphEdge *edge;
- for (edge = firstEdge(); edge != 0; edge = nextEdge(edge))
- {
- AliasGraphEdge *e = ptr_cast(AliasGraphEdge, edge);
- if (e != 0 && e->disp_nr() == alias_disp_nr)
- kill_edges += (void *)e;
- }
- for (int i = 0; i < kill_edges.size(); i++)
- {
- AliasGraphEdge *e = (AliasGraphEdge *)kill_edges[i];
- if (e->to()->isHint())
- {
- *this -= e->to(); // Also removes E from graph
- delete e->to();
- }
- else
- {
- *this -= e;
- }
- delete e;
- }
-
- // Unsuppress remaining (ordinary) hints
- for (edge = dn->firstFrom(); edge != 0; edge = dn->nextFrom(edge))
- {
- GraphEdge *e = edge;
- while (e->to()->isHint())
- {
- e->to()->hidden() = false;
- e = e->to()->firstFrom();
- }
- }
- for (edge = dn->firstTo(); edge != 0; edge = dn->nextTo(edge))
- {
- GraphEdge *e = edge;
- while (e->from()->isHint())
- {
- e->from()->hidden() = false;
- e = e->from()->firstTo();
- }
- }
-
- dn->alias_of = 0;
- return true;
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Routing
- //-----------------------------------------------------------------------------
-
- // True iff R->P1 and R->P2 have the same angle
- bool DispGraph::same_angle(const BoxPoint& r,
- const BoxPoint& p1,
- const BoxPoint& p2)
- {
- if (p1 == r || p2 == r)
- return false; // No angle to determine
-
- double angle1 = atan2(double(r[Y] - p1[Y]), double(r[X] - p1[X]));
- double angle2 = atan2(double(r[Y] - p2[Y]), double(r[X] - p2[X]));
-
- const double epsilon = 0.1;
- return fabs(angle1 - angle2) < epsilon;
- }
-
- // True iff NODE is attached to an edge with the same angle as P
- bool DispGraph::has_angle(PosGraphNode *node, const BoxPoint& p)
- {
- GraphEdge *edge;
- for (edge = node->firstFrom(); edge != 0; edge = node->nextFrom(edge))
- {
- if (same_angle(node->pos(), edge->to()->pos(), p))
- return true;
- }
- for (edge = node->firstTo(); edge != 0; edge = node->nextTo(edge))
- {
- if (same_angle(node->pos(), edge->from()->pos(), p))
- return true;
- }
-
- return false;
- }
-
- // Add a new edge in existing graph
- void DispGraph::add_alias_edge(Widget w, int alias_disp_nr,
- GraphNode *_from, GraphNode *_to,
- EdgeAnnotation *anno)
- {
- PosGraphNode *from = ptr_cast(PosGraphNode, _from);
- PosGraphNode *to = ptr_cast(PosGraphNode, _to);
-
- if (anno != 0)
- anno = anno->dup();
-
- // Check whether the new edge may be hidden by existing edges
- if (from == to || (from == 0 || to == 0))
- {
- // Self-referring edge or bad nodes
- add_direct_alias_edge(w, alias_disp_nr, _from, _to, anno);
- }
- else
- {
- // Check for interferences with existing edge
- add_routed_alias_edge(w, alias_disp_nr, from, to, anno);
- }
- }
-
- // Add a direct edge from FROM to TO
- void DispGraph::add_direct_alias_edge(Widget, int alias_disp_nr,
- GraphNode *from, GraphNode *to,
- EdgeAnnotation *anno)
- {
- *this += new AliasGraphEdge(alias_disp_nr, from, to, anno);
- }
-
- // Check whether P is obscured by any node
- bool DispGraph::is_hidden(Widget w, const BoxPoint& p) const
- {
- const GraphGC& graphGC = graphEditGetGraphGC(w);
-
- for (GraphNode *n = firstVisibleNode(); n != 0; n = nextVisibleNode(n))
- {
- RegionGraphNode *node = ptr_cast(RegionGraphNode, n);
- if (node == 0)
- continue;
-
- if (p == node->pos() || p <= node->sensitiveRegion(graphGC))
- return true;
- }
-
- return false;
- }
-
- // Rotate offset P by ANGLE (in degrees)
- BoxPoint DispGraph::rotate_offset(const BoxPoint& p, int angle)
- {
- if (p == BoxPoint(0, 0))
- return p;
-
- double length = hypot(p[X], p[Y]);
- double alpha = atan2(double(p[X]), double(p[Y]));
-
- alpha += (2.0 * PI * angle / 360.0);
-
- return BoxPoint(BoxCoordinate(length * cos(alpha)),
- BoxCoordinate(length * sin(alpha)));
- }
-
-
- // Check whether POS1 and POS2 are okay as hint positions for FROM and TO
- bool DispGraph::hint_positions_ok(Widget w,
- PosGraphNode *from,
- PosGraphNode *to,
- const BoxPoint& pos1,
- const BoxPoint& pos2) const
- {
- BoxPoint p1 = graphEditFinalPosition(w, pos1);
- BoxPoint p2 = graphEditFinalPosition(w, pos2);
-
- if (p1[X] <= 0 || p2[X] <= 0 || p1[Y] <= 0 || p2[Y] <= 0)
- return false; // Bad coordinates
-
- if (p1 == from->pos() && p2 == to->pos())
- {
- // Direct edge
- if (has_angle(from, to->pos()))
- return false; // New edge obscured by existing edge
- if (has_angle(to, from->pos()))
- return false; // New edge obscured by existing edge
- }
- else
- {
- // One or two hints
- if (has_angle(from, p1))
- return false; // New edge obscured by existing edge
- if (has_angle(to, p2))
- return false; // New edge obscured by existing edge
- if (is_hidden(w, p1))
- return false; // Hint obscured by existing node
- if (is_hidden(w, p2))
- return false; // Hint obscured by existing node
- }
-
- BoxPoint dist = p2 - p1;
- if (dist[X] > 0 || dist[Y] > 0)
- {
- BoxPoint center = graphEditFinalPosition(w, p1 + dist / 2);
- if (is_hidden(w, center)) // Center obscured by existing node
- return false;
- }
-
- return true;
- }
-
-
- // Add edge from FROM to TO, inserting hints if required
- void DispGraph::add_routed_alias_edge(Widget w, int alias_disp_nr,
- PosGraphNode *from, PosGraphNode *to,
- EdgeAnnotation *anno)
- {
- // Determine hint offsets
- Dimension grid_height = 16;
- Dimension grid_width = 16;
- XtVaGetValues(w,
- XtNgridHeight, &grid_height,
- XtNgridWidth, &grid_width,
- NULL);
-
- BoxPoint dist = to->pos() - from->pos();
- BoxPoint center = from->pos() + dist / 2;
- double angle = atan2(double(dist[X]), double(dist[Y]));
- BoxPoint grid_offset(BoxCoordinate(grid_width * cos(angle)),
- BoxCoordinate(grid_height * sin(angle)));
-
- const int LEFT = 1;
- const int RIGHT = 0;
-
- BoxPoint offsets[2];
- offsets[LEFT] = rotate_offset(grid_offset, +90);
- offsets[RIGHT] = rotate_offset(grid_offset, -90);
-
- #if 0
- clog << "offsets[LEFT] = " << offsets[LEFT] << "\n";
- clog << "offsets[RIGHT] = " << offsets[RIGHT] << "\n";
- #endif
-
- // Try hint offsets
- BoxPoint pos1, pos2;
- bool found = false;
-
- const bool try_direct = false;
-
- const int max_iterations = 100;
- for (int i = 0; i < max_iterations && !found; i++)
- {
- for (int side = RIGHT; !found && side <= LEFT; side++)
- {
- BoxPoint offset = offsets[side] * i;
-
- if (try_direct && i == 0)
- {
- // Try direct edge
- pos1 = from->pos() + offset;
- pos2 = to->pos() + offset;
- }
- else
- {
- // Try one-hint edge
- pos1 = pos2 = center + offset;
- }
- #if 0
- clog << "#" << i << " - "
- << (side == LEFT ? "left side: " : "right side: ")
- << "trying pos1 = " << pos1
- << " and pos2 = " << pos2 << "\n";
- #endif
-
- found = hint_positions_ok(w, from, to, pos1, pos2);
- }
- }
-
- if (!found)
- {
- // Give up
- cerr << "Warning: could not find edge route after "
- << max_iterations << " iterations\n";
- pos1 = from->pos();
- pos2 = to->pos();
- }
-
- if (try_direct && pos1 == from->pos() && pos2 == to->pos())
- {
- // No need for hints - add direct edge
- add_direct_alias_edge(w, alias_disp_nr, from, to, anno);
- }
- else
- {
- #if 0
- assert(!try_direct || pos1 == pos2);
- #endif
-
- // Add single hint
- HintGraphNode *hint = new HintGraphNode(pos1);
- hint->hidden() = from->hidden() || to->hidden();
- *this += hint;
-
- // Add edges
- *this += new AliasGraphEdge(alias_disp_nr, from, hint, anno);
- *this += new AliasGraphEdge(alias_disp_nr, hint, to);
- }
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Display clustering
- //-----------------------------------------------------------------------------
-
- // Hide/Unhide all alias edges of NODE according to its status
- void DispGraph::update_alias_edges(DispNode *node)
- {
- for (GraphEdge *edge = firstEdge(); edge != 0; edge = nextEdge(edge))
- {
- AliasGraphEdge *e = ptr_cast(AliasGraphEdge, edge);
- if (e != 0 && e->disp_nr() == node->disp_nr())
- {
- if (e->to()->isHint())
- e->to()->hidden() = node->hidden();
- e->hidden() = node->hidden();
- }
- }
- }
-
- void DispGraph::cluster(DispNode *dn, int cluster)
- {
- dn->cluster(cluster);
- update_alias_edges(dn);
- }
-
-
- //-----------------------------------------------------------------------------
- // Display activation
- //-----------------------------------------------------------------------------
-
- bool DispGraph::hide_inactive_displays = true;
-
- bool DispGraph::make_inactive(DispNode *dn)
- {
- if (dn->active() && dn->enabled())
- {
- if (!hide_inactive_displays)
- {
- dn->disable();
- }
- else
- {
- dn->make_inactive();
- update_alias_edges(dn);
- }
- return true;
- }
-
- return false;
- }
-
- bool DispGraph::make_active(DispNode *dn)
- {
- if (!dn->active())
- {
- dn->make_active();
- update_alias_edges(dn);
-
- return true;
- }
-
- return false;
- }
-
-
-
- //-----------------------------------------------------------------------------
- // Title stuff
- //-----------------------------------------------------------------------------
-
- bool DispGraph::refresh_titles() const
- {
- bool changed = false;
-
- MapRef ref;
- for (DispNode *dn = first(ref); dn != 0; dn = next(ref))
- {
- bool is_dependent = false;
- for (GraphEdge *e = dn->firstTo(); e != 0; e = dn->nextTo(e))
- {
- if (e->from() == dn)
- continue; // Self edge
- if (ptr_cast(AliasGraphEdge, e) != 0)
- continue; // Alias edge
- if (e->from()->hidden())
- continue; // Invisible edge
-
- LineGraphEdge *le = ptr_cast(LineGraphEdge, e);
- if (le != 0 && le->annotation() != 0)
- {
- is_dependent = true;
- break;
- }
- }
-
- bool need_title = false;
- if (is_dependent && app_data.show_dependent_display_titles)
- need_title = true;
- else if (!is_dependent && app_data.show_base_display_titles)
- need_title = true;
-
- if (dn->set_title(need_title))
- changed = true;
- }
-
- return changed;
- }
-
-
- //-----------------------------------------------------------------------------
- // Plotting
- //-----------------------------------------------------------------------------
-
- // Print all plots
- void DispGraph::print_plots(const string& filename, const GraphGC& gc) const
- {
- for (GraphNode *node = firstVisibleNode(); node != 0;
- node = nextVisibleNode(node))
- {
- DispNode *dn = ptr_cast(DispNode, node);
- if (dn == 0)
- continue;
-
- if (gc.printSelectedNodesOnly && !dn->selected())
- continue;
-
- dn->print_plots(filename, gc);
- }
- }
-