diff options
author | akissinger <akissinger@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64> | 2012-01-16 17:00:11 +0000 |
---|---|---|
committer | akissinger <akissinger@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64> | 2012-01-16 17:00:11 +0000 |
commit | caaac57631bda3df581eac462cddd9473bc05b28 (patch) | |
tree | a87654230dc1e137937cd60fe0ced1cc5efb7302 /tikzit/src | |
parent | 525059964fbaf380ad2c3079b965d64e7c6d06d1 (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.h | 86 | ||||
-rw-r--r-- | tikzit/src/common/Graph.m | 309 | ||||
-rw-r--r-- | tikzit/src/common/SupportDir.m | 1 | ||||
-rw-r--r-- | tikzit/src/osx/GraphicsView.h | 1 | ||||
-rw-r--r-- | tikzit/src/osx/GraphicsView.m | 40 |
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]]; |