Subject: | Patch: Support for nested labels (and ports), allow Mrecord type. |
This is a combination bugfix, feature expansion. First, the automatic
substitution of record shape for list labels has been changed to only
happen when the node shape isn't already a record (either directly or
via the default). This allows the Mrecord shape to be used. Secondly,
list labels have been extended to allow recursive lists. Ports for
recursive lists are numbered by list 0 based index, outermost list
first, delimited by underscores ('_'). This does not change the
programming interface for single depth lists. Documentation for this new
feature has been added.
Subject: | GraphViz.pm-nested list and Mrecord.patch |
--- GraphViz.originalpm 2007-01-25 20:26:20.000000000 -0800
+++ GraphViz.pm 2007-01-26 11:47:07.000000000 -0800
@@ -509,11 +509,18 @@
Also, nodes can consist of multiple parts (known as ports). This is
implemented by passing an array reference as the label, and the parts
-are displayed as a label. GraphViz has a much more complete port
-system, this is just a simple interface to it. See the 'from_port' and
-'to_port' attributes of add_edge:
+are displayed as a label. The list of labels can recursively contain
+recursively contain other lists, which are displayed in the opposite
+direction. GraphViz has a much more complete port system, this is just
+a simple interface to it. See the 'from_port' and 'to_port' attributes
+of add_edge:
$g->add_node('London', label => ['Heathrow', 'Gatwick']);
+ $g->add_node('Glasgow', label => [['Check-in', 'Arrivals], 'Glasgow', ['Departures', 'Baggage Claim']]);
+
+The ports are named by the position in each list, seperated by
+underscores. 'Gatwick' and 'Glasgow' would both be port 1. 'Arrivals'
+port '0_1', and 'Baggage Claim' port '1_1'.
=cut
@@ -564,11 +571,14 @@
# Deal with ports
if (ref($node->{label}) eq 'ARRAY') {
- $node->{shape} = 'record'; # force a record
- my $nports = 0;
- $node->{label} = join '|', map
- { $_ =~ s#([|<>\[\]{}"])#\\$1#g; '<port' . $nports++ . '>' . $_ }
- (@{$node->{label}});
+ # Need to check this node for record or Mrecord, or the default node
+ # against the same if this node has none:
+ my $isrecord = ($node->{shape}) ?
+ ($node->{shape} eq 'record' || $node->{shape} eq 'Mrecord') :
+ ($self->{NODE_ATTRS}->{shape} eq 'record' || $self->{NODE_ATTRS}->{shape} eq 'Mrecord');
+
+ $node->{shape} = 'record' unless ($isrecord); # force a record
+ $node->{label} = _record_label($node->{label}, 'port');
}
# Save ourselves
@@ -592,6 +602,25 @@
return $node->{name};
}
+sub _record_label {
+ my $label = shift;
+ my $port = shift;
+ my $arrayprefix = ($port eq 'port') ? '' : '{';
+ my $arraypostfix = ($port eq 'port') ? '' : '}';
+ my $portseperator = ($port eq 'port') ? '' : '_';
+ my $nports = 0;
+ if (ref($label) eq 'ARRAY') {
+ return $arrayprefix . (join '|', map { _record_label($_, $port . $portseperator . $nports++) } (@{$label})) . $arraypostfix ;
+ } else {
+ $label =~ s#([|<>\[\]{}"])#\\$1#g;
+ if ($port eq 'port') {
+ return $label;
+ } else {
+ return "<$port>" . $label;
+ }
+ }
+}
+
=head2 add_edge
@@ -698,9 +727,12 @@
Additionally, adding edges between ports of a node is done via the
'from_port' and 'to_port' parameters, which currently takes in the
-offset of the port (ie 0, 1, 2...).
+offset of the port (ie 0, 1, 2...). If the ports come from nested
+lists of labels the offsets are seperated by underscores (ie '0_1',
+'3_0_5').
$g->add_edge('London' => 'Paris', from_port => 0);
+ $g->add_edge('Boston' => 'Glasgow', to_port => '0_1');
=cut