summaryrefslogtreecommitdiff
path: root/tikzit/src
diff options
context:
space:
mode:
authorakissinger <akissinger@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64>2012-01-16 17:00:11 +0000
committerakissinger <akissinger@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64>2012-01-16 17:00:11 +0000
commitcaaac57631bda3df581eac462cddd9473bc05b28 (patch)
treea87654230dc1e137937cd60fe0ced1cc5efb7302 /tikzit/src
parent525059964fbaf380ad2c3079b965d64e7c6d06d1 (diff)
graphs now store edges and nodes in an array, GraphicsView has actions for re-ordering the z-index of nodes and edges
git-svn-id: https://tikzit.svn.sourceforge.net/svnroot/tikzit/trunk@380 7c02a99a-9b00-45e3-bf44-6f3dd7fddb64
Diffstat (limited to 'tikzit/src')
-rw-r--r--tikzit/src/common/Graph.h86
-rw-r--r--tikzit/src/common/Graph.m309
-rw-r--r--tikzit/src/common/SupportDir.m1
-rw-r--r--tikzit/src/osx/GraphicsView.h1
-rw-r--r--tikzit/src/osx/GraphicsView.m40
5 files changed, 342 insertions, 95 deletions
diff --git a/tikzit/src/common/Graph.h b/tikzit/src/common/Graph.h
index fe8c2e5..f396912 100644
--- a/tikzit/src/common/Graph.h
+++ b/tikzit/src/common/Graph.h
@@ -46,12 +46,12 @@
by calling applyGraphChange on [change inverse].
*/
@interface Graph : NSObject {
- NSLock *graphLock;
- BOOL dirty; // this bit keeps track of whether nodesCache and edgesCache are up to date
- NSMutableSet *nodes;
- NSMutableSet *edges;
- NSSet *nodesCache;
- NSSet *edgesCache;
+ NSRecursiveLock *graphLock;
+ BOOL dirty; // keep track of when inEdges and outEdges need an update
+ NSMutableArray *nodes;
+ NSMutableArray *edges;
+// NSSet *nodesCache;
+// NSSet *edgesCache;
BasicMapTable *inEdges;
BasicMapTable *outEdges;
@@ -72,7 +72,7 @@
@details The node set is cached internally, so no need to lock
the graph when enumerating.
*/
-@property (readonly) NSSet *nodes;
+@property (readonly) NSArray *nodes;
/*!
@property edges
@@ -80,7 +80,7 @@
@details The edge set is cached internally, so no need to lock
the graph when enumerating.
*/
-@property (readonly) NSSet *edges;
+@property (readonly) NSArray *edges;
/*!
@property boundingBox
@@ -189,6 +189,69 @@
- (GraphChange*)addEdgeFrom:(Node*)source to:(Node*)target;
/*!
+ @brief Return the z-index for a given node (lower is farther back).
+ @param node a node in the graph
+ @result An <tt>int</tt>
+ */
+- (int)indexOfNode:(Node*)node;
+
+/*!
+ @brief Set the z-index for a given node (lower is farther back).
+ @param idx a new z-index
+ @param node a node in the graph
+ */
+- (void)setIndex:(int)idx ofNode:(Node*)node;
+
+/*!
+ @brief Bring set of nodes forward by one.
+ @param nodeSet a set of nodes
+ */
+- (GraphChange*)bringNodesForward:(NSSet*)nodeSet;
+
+/*!
+ @brief Bring set of nodes to the front.
+ @param nodeSet a set of nodes
+ */
+- (GraphChange*)bringNodesToFront:(NSSet*)nodeSet;
+
+/*!
+ @brief Bring set of edges to the front.
+ @param edgeSet a set of edges
+ */
+- (GraphChange*)bringEdgesToFront:(NSSet*)edgeSet;
+
+/*!
+ @brief Bring set of edges forward by one.
+ @param edgeSet a set of edges
+ */
+- (GraphChange*)bringEdgesForward:(NSSet*)edgeSet;
+
+/*!
+ @brief Send set of nodes backward by one.
+ @param nodeSet a set of nodes
+ */
+- (GraphChange*)sendNodesBackward:(NSSet*)nodeSet;
+
+/*!
+ @brief Send set of edges backward by one.
+ @param edgeSet a set of edges
+ */
+- (GraphChange*)sendEdgesBackward:(NSSet*)edgeSet;
+
+/*!
+ @brief Send set of nodes to back.
+ @param nodeSet a set of nodes
+ */
+- (GraphChange*)sendNodesToBack:(NSSet*)nodeSet;
+
+/*!
+ @brief Send set of edges to back.
+ @param edgeSet a set of edges
+ */
+- (GraphChange*)sendEdgesToBack:(NSSet*)edgeSet;
+
+
+/*!
@brief Transform every node in the graph to screen space.
@param t a transformer
*/
@@ -200,7 +263,7 @@
@param p an x and y distance, given as an NSPoint.
@result A <tt>GraphChange</tt> recording this action.
*/
-- (GraphChange*)shiftNodes:(NSSet*)ns byPoint:(NSPoint)p;
+- (GraphChange*)shiftNodes:(id<NSFastEnumeration>)ns byPoint:(NSPoint)p;
/*!
@brief Insert the given graph into this one. Used for copy
@@ -243,6 +306,7 @@
*/
- (NSString*)tikz;
+
/*!
@brief Copy the node set and return a table of copies, whose
keys are the original nodes. This is used to save the state
@@ -263,10 +327,10 @@
/*!
@brief Compute the bounds for a set of nodes.
- @param nds a set of nodes.
+ @param nds an enumerable collection of nodes.
@result The bounds.
*/
-+ (NSRect)boundsForNodeSet:(NSSet *)nds;
++ (NSRect)boundsForNodes:(id<NSFastEnumeration>)nds;
/*!
@brief Factory method for constructing graphs.
diff --git a/tikzit/src/common/Graph.m b/tikzit/src/common/Graph.m
index 4250f7f..293695a 100644
--- a/tikzit/src/common/Graph.m
+++ b/tikzit/src/common/Graph.m
@@ -32,11 +32,10 @@
boundingBox = NSMakeRect(0, 0, 0, 0);
graphLock = [[NSRecursiveLock alloc] init];
[graphLock lock];
- nodes = [[NSMutableSet alloc] initWithCapacity:10];
- edges = [[NSMutableSet alloc] initWithCapacity:10];
+ nodes = [[NSMutableArray alloc] initWithCapacity:10];
+ edges = [[NSMutableArray alloc] initWithCapacity:10];
inEdges = nil;
outEdges = nil;
- dirty = YES;
[graphLock unlock];
return self;
}
@@ -44,12 +43,6 @@
- (void)sync {
[graphLock lock];
if (dirty) {
- [nodesCache release];
- nodesCache = [nodes copy];
- [edgesCache release];
- edgesCache = [edges copy];
-
-
[inEdges release];
[outEdges release];
inEdges = [[BasicMapTable alloc] init];
@@ -83,19 +76,17 @@
[graphLock unlock];
}
-- (NSSet*)nodes {
- [self sync];
- return nodesCache;
+- (NSArray*)nodes {
+ return nodes;
}
-- (NSSet*)edges {
- [self sync];
- return edgesCache;
+- (NSArray*)edges {
+ return edges;
}
- (NSRect)bounds {
[graphLock lock];
- NSRect b = [Graph boundsForNodeSet:nodes];
+ NSRect b = [Graph boundsForNodes:nodes];
[graphLock unlock];
return b;
}
@@ -148,38 +139,40 @@
[graphLock unlock];
}
-
- (GraphChange*)addNode:(Node *)node{
- [graphLock lock];
- [nodes addObject:node];
- dirty = YES;
- [graphLock unlock];
-
- return [GraphChange graphAdditionWithNodes:[NSSet setWithObject:node]
+ [graphLock lock];
+ NSSet *addedNode;
+
+ // addNode is a no-op if graph already contains node
+ if (![nodes containsObject:node]) {
+ [nodes addObject:node];
+ dirty = YES;
+ addedNode = [NSSet setWithObject:node];
+ } else {
+ addedNode = [NSSet set];
+ }
+ [graphLock unlock];
+
+ return [GraphChange graphAdditionWithNodes:addedNode
edges:[NSSet set]];
}
- (GraphChange*)removeNode:(Node*)node {
- [graphLock lock];
-
- NSMutableSet *affectedEdges = [NSMutableSet set];
+ [graphLock lock];
+ NSMutableSet *affectedEdges = [NSMutableSet set];
for (Edge *e in edges) {
if ([e source] == node || [e target] == node) {
[affectedEdges addObject:e];
}
}
-
for (Edge *e in affectedEdges) {
[edges removeObject:e];
}
-
[nodes removeObject:node];
-
dirty = YES;
-
- [graphLock unlock];
-
- return [GraphChange graphDeletionWithNodes:[NSSet setWithObject:node]
+ [graphLock unlock];
+
+ return [GraphChange graphDeletionWithNodes:[NSSet setWithObject:node]
edges:affectedEdges];
}
@@ -209,13 +202,22 @@
return [GraphChange graphDeletionWithNodes:nds edges:affectedEdges];
}
-- (GraphChange*)addEdge:(Edge *)edge {
- [graphLock lock];
- [edges addObject:edge];
- dirty = YES;
- [graphLock unlock];
- return [GraphChange graphAdditionWithNodes:[NSSet set]
- edges:[NSSet setWithObject:edge]];
+- (GraphChange*)addEdge:(Edge*)edge {
+ [graphLock lock];
+ NSSet *addedEdge;
+
+ // addEdge is a no-op if graph already contains edge
+ if (![edges containsObject:edge]) {
+ [edges addObject:edge];
+ dirty = YES;
+ addedEdge = [NSSet setWithObject:edge];
+ } else {
+ addedEdge = [NSSet set];
+ }
+ [graphLock unlock];
+
+ return [GraphChange graphAdditionWithNodes:[NSSet set]
+ edges:addedEdge];
}
- (GraphChange*)removeEdge:(Edge *)edge {
@@ -244,44 +246,190 @@
return [self addEdge:[Edge edgeWithSource:source andTarget:target]];
}
-- (GraphChange*)shiftNodes:(NSSet*)ns byPoint:(NSPoint)p {
- NSEnumerator *en = [ns objectEnumerator];
- Node *n;
+- (GraphChange*)shiftNodes:(id<NSFastEnumeration>)ns byPoint:(NSPoint)p {
NSPoint newLoc;
- while ((n = [en nextObject])) {
+ NSMutableSet *nodeSet = [NSMutableSet setWithCapacity:5];
+ for (Node *n in ns) {
newLoc = NSMakePoint([n point].x + p.x, [n point].y + p.y);
[n setPoint:newLoc];
+ [nodeSet addObject:n];
}
- return [GraphChange shiftNodes:ns byPoint:p];
+ return [GraphChange shiftNodes:nodeSet byPoint:p];
+}
+
+- (int)indexOfNode:(Node *)node {
+ return [nodes indexOfObject:node];
+}
+
+- (void)setIndex:(int)idx ofNode:(Node *)node {
+ [graphLock lock];
+
+ if ([nodes containsObject:node]) {
+ [nodes removeObject:node];
+ [nodes insertObject:node atIndex:idx];
+ }
+
+ [graphLock unlock];
+}
+
+- (int)indexOfEdge:(Edge *)edge {
+ return [edges indexOfObject:edge];
+}
+
+- (void)setIndex:(int)idx ofEdge:(Edge *)edge {
+ [graphLock lock];
+
+ if ([edges containsObject:edge]) {
+ [edges removeObject:edge];
+ [edges insertObject:edge atIndex:idx];
+ }
+
+ [graphLock unlock];
+}
+
+- (GraphChange*)bringNodesForward:(NSSet*)nodeSet {
+ [graphLock lock];
+ // start at the top of the array and work backwards
+ for (int i = [nodes count]-2; i >= 0; --i) {
+ if ( [nodeSet containsObject:[nodes objectAtIndex:i]] &&
+ ![nodeSet containsObject:[nodes objectAtIndex:i+1]])
+ {
+ [self setIndex:(i+1) ofNode:[nodes objectAtIndex:i]];
+ }
+ }
+ [graphLock unlock];
+
+ return nil;
+}
+
+- (GraphChange*)bringNodesToFront:(NSSet*)nodeSet {
+ int i = 0, top = [nodes count]-1;
+
+ while (i <= top) {
+ if ([nodeSet containsObject:[nodes objectAtIndex:i]]) {
+ [self setIndex:([nodes count]-1) ofNode:[nodes objectAtIndex:i]];
+ --top;
+ } else {
+ ++i;
+ }
+ }
+
+ return nil;
+}
+
+- (GraphChange*)bringEdgesForward:(NSSet*)edgeSet {
+ [graphLock lock];
+ // start at the top of the array and work backwards
+ for (int i = [edges count]-2; i >= 0; --i) {
+ if ( [edgeSet containsObject:[edges objectAtIndex:i]] &&
+ ![edgeSet containsObject:[edges objectAtIndex:i+1]])
+ {
+ [self setIndex:(i+1) ofEdge:[edges objectAtIndex:i]];
+ }
+ }
+ [graphLock unlock];
+
+ return nil;
+}
+
+- (GraphChange*)bringEdgesToFront:(NSSet*)edgeSet {
+ int i = 0, top = [edges count]-1;
+
+ while (i <= top) {
+ if ([edgeSet containsObject:[edges objectAtIndex:i]]) {
+ [self setIndex:([edges count]-1) ofEdge:[edges objectAtIndex:i]];
+ --top;
+ } else {
+ ++i;
+ }
+ }
+
+ return nil;
+}
+
+- (GraphChange*)sendNodesBackward:(NSSet*)nodeSet {
+ [graphLock lock];
+ // start at the top of the array and work backwards
+ for (int i = 1; i < [nodes count]; ++i) {
+ if ( [nodeSet containsObject:[nodes objectAtIndex:i]] &&
+ ![nodeSet containsObject:[nodes objectAtIndex:i-1]])
+ {
+ [self setIndex:(i-1) ofNode:[nodes objectAtIndex:i]];
+ }
+ }
+ [graphLock unlock];
+
+ return nil;
+}
+
+- (GraphChange*)sendEdgesBackward:(NSSet*)edgeSet {
+ [graphLock lock];
+ // start at the top of the array and work backwards
+ for (int i = 1; i < [edges count]; ++i) {
+ if ( [edgeSet containsObject:[edges objectAtIndex:i]] &&
+ ![edgeSet containsObject:[edges objectAtIndex:i-1]])
+ {
+ [self setIndex:(i-1) ofEdge:[edges objectAtIndex:i]];
+ }
+ }
+ [graphLock unlock];
+
+ return nil;
+}
+
+- (GraphChange*)sendNodesToBack:(NSSet*)nodeSet {
+ int i = [nodes count]-1, bot = 0;
+
+ while (i >= bot) {
+ if ([nodeSet containsObject:[nodes objectAtIndex:i]]) {
+ [self setIndex:0 ofNode:[nodes objectAtIndex:i]];
+ ++bot;
+ } else {
+ --i;
+ }
+ }
+
+ return nil;
+}
+
+- (GraphChange*)sendEdgesToBack:(NSSet*)edgeSet {
+ int i = [edges count]-1, bot = 0;
+
+ while (i >= bot) {
+ if ([edgeSet containsObject:[edges objectAtIndex:i]]) {
+ [self setIndex:0 ofEdge:[edges objectAtIndex:i]];
+ ++bot;
+ } else {
+ --i;
+ }
+ }
+
+ return nil;
}
- (GraphChange*)insertGraph:(Graph*)g {
[graphLock lock];
- NSEnumerator *en;
- Node *n;
- Edge *e;
- en = [[g nodes] objectEnumerator];
- while ((n = [en nextObject])) {
- [nodes addObject:n];
+ for (Node *n in [g nodes]) {
+ [self addNode:n];
}
- en = [[g edges] objectEnumerator];
- while ((e = [en nextObject])) {
- [edges addObject:e];
+ for (Edge *e in [g edges]) {
+ [self addEdge:e];
}
dirty = YES;
[graphLock unlock];
+
- return [GraphChange graphAdditionWithNodes:[g nodes] edges:[g edges]];
+ return [GraphChange graphAdditionWithNodes:[NSSet setWithArray:[g nodes]] edges:[NSSet setWithArray:[g edges]]];
}
- (void)flipNodes:(NSSet*)nds horizontal:(BOOL)horiz {
[graphLock lock];
- NSRect bds = [Graph boundsForNodeSet:nds];
+ NSRect bds = [Graph boundsForNodes:nds];
float ctr;
if (horiz) ctr = bds.origin.x + (bds.size.width/2);
else ctr = bds.origin.y + (bds.size.height/2);
@@ -364,7 +512,7 @@
- (NSSet*)pathCover {
[self sync];
- NSMutableSet *remainingEdges = [edges mutableCopy];
+ NSMutableSet *remainingEdges = [NSMutableSet setWithArray:edges];
NSMutableSet *cover = [NSMutableSet set];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -488,15 +636,14 @@
[NSNumber numberWithFloat:boundingBox.origin.y + boundingBox.size.height]];
}
- NSArray *sortedNodeList = [[nodes allObjects]
- sortedArrayUsingSelector:@selector(compareTo:)];
+// NSArray *sortedNodeList = [[nodes allObjects]
+// sortedArrayUsingSelector:@selector(compareTo:)];
//NSMutableDictionary *nodeNames = [NSMutableDictionary dictionary];
if ([nodes count] > 0) [code appendFormat:@"\t\\begin{pgfonlayer}{nodelayer}\n"];
- int i;
- for (i = 0; i < [sortedNodeList count]; ++i) {
- Node *n = [sortedNodeList objectAtIndex:i];
+ int i = 0;
+ for (Node *n in nodes) {
[n updateData];
[n setName:[NSString stringWithFormat:@"%d", i]];
[code appendFormat:@"\t\t\\node %@ (%d) at (%@, %@) {%@};\n",
@@ -506,6 +653,7 @@
[NSNumber numberWithFloat:[n point].y],
[n label]
];
+ i++;
}
if ([nodes count] > 0) [code appendFormat:@"\t\\end{pgfonlayer}\n"];
@@ -549,8 +697,6 @@
[graphLock lock];
[nodes release];
[edges release];
- [nodesCache release];
- [edgesCache release];
[data release];
[inEdges release];
[outEdges release];
@@ -584,25 +730,26 @@
return tab;
}
-+ (NSRect)boundsForNodeSet:(NSSet*)nds {
+
++ (NSRect)boundsForNodes:(id<NSFastEnumeration>)nds {
NSPoint tl, br;
- Node *n;
NSPoint p;
- NSEnumerator *en = [nds objectEnumerator];
- if ((n = [en nextObject])==nil) {
- return NSMakeRect(0, 0, 0, 0);
- }
- p = [n point];
- tl = p;
- br = p;
- while ((n = [en nextObject])) {
- p = [n point];
- if (p.x < tl.x) tl.x = p.x;
- if (p.y > tl.y) tl.y = p.y;
- if (p.x > br.x) br.x = p.x;
- if (p.y < br.y) br.y = p.y;
- }
- return NSRectAroundPoints(tl, br);
+ BOOL hasPoints = NO;
+ for (Node *n in nds) {
+ p = [n point];
+ if (!hasPoints) {
+ tl = p;
+ br = p;
+ hasPoints = YES;
+ } else {
+ if (p.x < tl.x) tl.x = p.x;
+ if (p.y > tl.y) tl.y = p.y;
+ if (p.x > br.x) br.x = p.x;
+ if (p.y < br.y) br.y = p.y;
+ }
+ }
+
+ return (hasPoints) ? NSRectAroundPoints(tl, br) : NSMakeRect(0, 0, 0, 0);
}
@end
diff --git a/tikzit/src/common/SupportDir.m b/tikzit/src/common/SupportDir.m
index c014f4d..d2b5da6 100644
--- a/tikzit/src/common/SupportDir.m
+++ b/tikzit/src/common/SupportDir.m
@@ -49,7 +49,6 @@
+ (void)createUserSupportDir {
#ifdef __APPLE__
NSFileManager *fileManager = [NSFileManager defaultManager];
- NSError *error = nil;
[fileManager createDirectoryAtPath:[SupportDir userSupportDir]
withIntermediateDirectories:YES
attributes:nil
diff --git a/tikzit/src/osx/GraphicsView.h b/tikzit/src/osx/GraphicsView.h
index ddd005f..e963ac7 100644
--- a/tikzit/src/osx/GraphicsView.h
+++ b/tikzit/src/osx/GraphicsView.h
@@ -121,6 +121,7 @@ typedef enum {
- (void)copy:(id)sender;
- (void)paste:(id)sender;
- (void)delete:(id)sender;
+- (void)bringForward:(id)sender;
- (void)flipHorizonal:(id)sender;
- (void)flipVertical:(id)sender;
- (void)reverseEdgeDirection:(id)sender;
diff --git a/tikzit/src/osx/GraphicsView.m b/tikzit/src/osx/GraphicsView.m
index 38ed1f0..f03f95c 100644
--- a/tikzit/src/osx/GraphicsView.m
+++ b/tikzit/src/osx/GraphicsView.m
@@ -999,7 +999,7 @@ static CGColorRef cgGrayColor, cgWhiteColor, cgClearColor = nil;
}
- (void)selectAll:(id)sender {
- [pickSupport selectAllNodes:graph.nodes];
+ [pickSupport selectAllNodes:[NSSet setWithArray:[graph nodes]]];
for (Node *n in [graph nodes]) {
[[[nodeLayers objectForKey:n] selection] select];
@@ -1031,7 +1031,7 @@ static CGColorRef cgGrayColor, cgWhiteColor, cgClearColor = nil;
}
- (void)copy:(id)sender {
- if ([pickSupport selectedNodes].count != 0) {
+ if ([[pickSupport selectedNodes] count] != 0) {
Graph *clip = [graph copyOfSubgraphWithNodes:[pickSupport selectedNodes]];
NSString *tikz = [clip tikz];
NSData *data = [tikz dataUsingEncoding:NSUTF8StringEncoding];
@@ -1101,6 +1101,42 @@ static CGColorRef cgGrayColor, cgWhiteColor, cgClearColor = nil;
}
}
+- (void)bringForward:(id)sender {
+ NSString *oldTikz = [graph tikz];
+ [graph bringNodesForward:[pickSupport selectedNodes]];
+ [graph bringEdgesForward:[pickSupport selectedEdges]];
+ [self registerUndo:oldTikz withActionName:@"Bring Forward"];
+ [self postGraphChange];
+ [self refreshLayers];
+}
+
+- (void)sendBackward:(id)sender {
+ NSString *oldTikz = [graph tikz];
+ [graph sendNodesBackward:[pickSupport selectedNodes]];
+ [graph sendEdgesBackward:[pickSupport selectedEdges]];
+ [self registerUndo:oldTikz withActionName:@"Send Backward"];
+ [self postGraphChange];
+ [self refreshLayers];
+}
+
+- (void)bringToFront:(id)sender {
+ NSString *oldTikz = [graph tikz];
+ [graph bringNodesToFront:[pickSupport selectedNodes]];
+ [graph bringEdgesToFront:[pickSupport selectedEdges]];
+ [self registerUndo:oldTikz withActionName:@"Bring to Front"];
+ [self postGraphChange];
+ [self refreshLayers];
+}
+
+- (void)sendToBack:(id)sender {
+ NSString *oldTikz = [graph tikz];
+ [graph sendNodesToBack:[pickSupport selectedNodes]];
+ [graph sendEdgesToBack:[pickSupport selectedEdges]];
+ [self registerUndo:oldTikz withActionName:@"Send to Back"];
+ [self postGraphChange];
+ [self refreshLayers];
+}
+
- (void)flipHorizonal:(id)sender {
NSString *oldTikz = [graph tikz];
[graph flipHorizontalNodes:[pickSupport selectedNodes]];