Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactored layout code.

Reviewed graphLayout code and supporting routines.  Refactored code for
clarity and new features, it reads better now.
  • Loading branch information...
commit 878a7ee110f54f4f484043595c1d522aa213c5cb 1 parent 167cbfa
@epreston authored
View
4 PSTreeGraphView/PSBaseBranchView.h
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
View
34 PSTreeGraphView/PSBaseBranchView.m
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
@@ -52,9 +52,11 @@ - (UIBezierPath *) directConnectionsPath
PSTreeGraphOrientationStyle treeDirection = [[self enclosingTreeGraph] treeGraphOrientation];
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- rootPoint = CGPointMake(CGRectGetMinX(bounds), CGRectGetMidY(bounds));
+ rootPoint = CGPointMake(CGRectGetMinX(bounds),
+ CGRectGetMidY(bounds));
} else {
- rootPoint = CGPointMake(CGRectGetMidX(bounds), CGRectGetMinY(bounds));
+ rootPoint = CGPointMake(CGRectGetMidX(bounds),
+ CGRectGetMinY(bounds));
}
// Create a single bezier path that we'll use to stroke all the lines.
@@ -70,9 +72,11 @@ - (UIBezierPath *) directConnectionsPath
CGPoint targetPoint = CGPointZero;
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds)) fromView:subview];
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds))
+ fromView:subview];
} else {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds)) fromView:subview];
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds))
+ fromView:subview];
}
[path moveToPoint:rootPoint];
@@ -111,9 +115,11 @@ - (UIBezierPath *) orthogonalConnectionsPath
CGPoint rootPoint = CGPointZero;
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
// Compute point at right edge of root node, from which its connecting line to the vertical line will emerge.
- rootPoint = CGPointMake(CGRectGetMinX(bounds), CGRectGetMidY(bounds));
+ rootPoint = CGPointMake(CGRectGetMinX(bounds),
+ CGRectGetMidY(bounds));
} else {
- rootPoint = CGPointMake(CGRectGetMidX(bounds), CGRectGetMinY(bounds));
+ rootPoint = CGPointMake(CGRectGetMidX(bounds),
+ CGRectGetMinY(bounds));
}
@@ -124,8 +130,8 @@ - (UIBezierPath *) orthogonalConnectionsPath
// rootPoint = [self convertPointFromBase:basePoint];
- // Compute point (really, we're just interested in the x value) at which line from root node intersects the
- // vertical connecting line.
+ // Compute point (really, we're just interested in the x value) at which line
+ // from root node intersects the vertical connecting line.
CGPoint rootIntersection = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
@@ -161,9 +167,11 @@ - (UIBezierPath *) orthogonalConnectionsPath
CGPoint targetPoint = CGPointZero;
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds)) fromView:subview];
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds))
+ fromView:subview];
} else {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds)) fromView:subview];
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds))
+ fromView:subview];
}
// Align the line to get exact pixel coverage, for sharper rendering.
@@ -222,7 +230,7 @@ - (UIBezierPath *) orthogonalConnectionsPath
}
- (void) drawRect:(CGRect)dirtyRect
-{
+{
// Build the set of lines to stroke, according to our enclosingTreeGraph's connectingLineStyle.
UIBezierPath *path = nil;
View
4 PSTreeGraphView/PSBaseLeafView.h
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
View
4 PSTreeGraphView/PSBaseLeafView.m
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
View
10 PSTreeGraphView/PSBaseSubtreeView.h
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
@@ -16,12 +16,14 @@
#import "PSTreeGraphModelNode.h"
+
@class PSBaseBranchView;
@class PSBaseTreeGraphView;
-/// A SubtreeView draws nothing itself (unless showsSubtreeFrames is set to YES for the enclosingTreeGraph), but
-/// provides a local coordinate frame and grouping mechanism for a graph subtree, and implements subtree layout.
+/// A SubtreeView draws nothing itself (unless showsSubtreeFrames is set to YES for
+/// the enclosingTreeGraph), but provides a local coordinate frame and grouping mechanism
+/// for a graph subtree, and implements subtree layout.
@interface PSBaseSubtreeView : UIView
View
502 PSTreeGraphView/PSBaseSubtreeView.m
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
@@ -34,6 +34,14 @@ static CGFloat subtreeBorderWidth(void)
}
+@interface PSBaseSubtreeView ()
+
+- (CGSize) layoutExpandedGraph;
+- (CGSize) layoutCollapsedGraph;
+
+@end
+
+
@implementation PSBaseSubtreeView
@@ -111,7 +119,8 @@ - (BOOL) isLeaf
_connectorsView = [[PSBaseBranchView alloc] initWithFrame:CGRectZero];
if (_connectorsView) {
[_connectorsView setAutoresizesSubviews:YES];
- [_connectorsView setContentMode:UIViewContentModeRedraw]; // if we dont redraw lines, they get out of place
+ // if we dont redraw lines, they get out of place
+ [_connectorsView setContentMode:UIViewContentModeRedraw];
[_connectorsView setOpaque:YES];
[self addSubview:_connectorsView];
@@ -161,275 +170,286 @@ - (void) recursiveSetNeedsGraphLayout
- (CGSize) sizeNodeViewToFitContent
{
- // TODO: Node size is hardwired for now, but the layout algorithm could accommodate variable-sized nodes
- // if we implement size-to-fit for nodes.
+ // TODO: Node size is hardwired for now, but the layout algorithm could accommodate
+ // variable-sized nodes if we implement size-to-fit for nodes.
return [self.nodeView frame].size;
}
- (CGSize) layoutGraphIfNeeded
{
- CGSize selfTargetSize;
-
+ // Return early if layout not needed
if ( !self.needsGraphLayout )
return [self frame].size;
- PSBaseTreeGraphView *treeGraph = [self enclosingTreeGraph];
+ // Do the layout
+ CGSize selfTargetSize;
+ if ( [self isExpanded] ) {
+ selfTargetSize = [self layoutExpandedGraph];
+ } else {
+ selfTargetSize = [self layoutCollapsedGraph];
+ }
+
+ // Mark as having completed layout.
+ self.needsGraphLayout = NO;
+
+ // Return our new size.
+ return selfTargetSize;
+}
+
+- (CGSize) layoutExpandedGraph
+{
+ CGSize selfTargetSize;
- // BOOL animateLayout = [treeView animatesLayout] && ![treeView layoutAnimationSuppressed];
+ PSBaseTreeGraphView *treeGraph = [self enclosingTreeGraph];
CGFloat parentChildSpacing = [treeGraph parentChildSpacing];
CGFloat siblingSpacing = [treeGraph siblingSpacing];
- PSTreeGraphOrientationStyle treeDirection = [treeGraph treeGraphOrientation];
+ PSTreeGraphOrientationStyle treeOrientation = [treeGraph treeGraphOrientation];
// Size this SubtreeView's nodeView to fit its content. Our tree layout model assumes the assessment
// of a node's natural size is a function of intrinsic properties of the node, and isn't influenced
// by any other nodes or layout in the tree.
CGSize rootNodeViewSize = [self sizeNodeViewToFitContent];
-
- if ( [self isExpanded] ) {
-
- // Recurse to lay out each of our child SubtreeViews (and their non-collapsed descendants in turn).
- // Knowing the sizes of our child SubtreeViews will tell us what size this SubtreeView needs to be
- // to contain them (and our nodeView and connectorsView).
-
- NSArray *subviews = [self subviews];
- NSInteger count = [subviews count];
- NSInteger index;
- NSUInteger subtreeViewCount = 0;
- CGFloat maxWidth = 0.0f;
- CGFloat maxHeight = 0.0f;
- CGPoint nextSubtreeViewOrigin = CGPointZero;
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- nextSubtreeViewOrigin = CGPointMake(rootNodeViewSize.width + parentChildSpacing, 0.0f);
- } else {
- nextSubtreeViewOrigin = CGPointMake(0.0f, rootNodeViewSize.height + parentChildSpacing);
- }
-
- for (index = count - 1; index >= 0; index--) {
- UIView *subview = [subviews objectAtIndex:index];
-
- if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
- ++subtreeViewCount;
-
- // Unhide the view if needed.
- [subview setHidden:NO];
-
- // Recursively layout the subtree, and obtain the SubtreeView's resultant size.
- CGSize subtreeViewSize = [(PSBaseSubtreeView *)subview layoutGraphIfNeeded];
-
- // Position the SubtreeView.
- // [(animateLayout ? [subview animator] : subview) setFrameOrigin:nextSubtreeViewOrigin];
-
-
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- // Since SubtreeView is unflipped, lay out our child SubtreeViews going upward from our
- // bottom edge, from last to first.
- subview.frame = CGRectMake( nextSubtreeViewOrigin.x,
- nextSubtreeViewOrigin.y,
- subtreeViewSize.width,
- subtreeViewSize.height );
-
- // Advance nextSubtreeViewOrigin for the next SubtreeView.
- nextSubtreeViewOrigin.y += subtreeViewSize.height + siblingSpacing;
-
- // Keep track of the widest SubtreeView width we encounter.
- if (maxWidth < subtreeViewSize.width) {
- maxWidth = subtreeViewSize.width;
- }
-
-
- } else {
- // TODO: Lay out our child SubtreeViews going from our left edge, last to first. SWITCH ME
- subview.frame = CGRectMake( nextSubtreeViewOrigin.x,
- nextSubtreeViewOrigin.y,
- subtreeViewSize.width,
- subtreeViewSize.height );
-
- // Advance nextSubtreeViewOrigin for the next SubtreeView.
- nextSubtreeViewOrigin.x += subtreeViewSize.width + siblingSpacing;
-
- // Keep track of the widest SubtreeView width we encounter.
- if (maxHeight < subtreeViewSize.height) {
- maxHeight = subtreeViewSize.height;
- }
- }
+ // Recurse to lay out each of our child SubtreeViews (and their non-collapsed descendants in turn).
+ // Knowing the sizes of our child SubtreeViews will tell us what size this SubtreeView needs to be
+ // to contain them (and our nodeView and connectorsView).
+
+ NSArray *subviews = [self subviews];
+ NSInteger count = [subviews count];
+ NSInteger index;
+ NSUInteger subtreeViewCount = 0;
+ CGFloat maxWidth = 0.0f;
+ CGFloat maxHeight = 0.0f;
+ CGPoint nextSubtreeViewOrigin = CGPointZero;
+
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ nextSubtreeViewOrigin = CGPointMake(rootNodeViewSize.width + parentChildSpacing, 0.0f);
+ } else {
+ nextSubtreeViewOrigin = CGPointMake(0.0f, rootNodeViewSize.height + parentChildSpacing);
+ }
+
+ for (index = count - 1; index >= 0; index--) {
+ UIView *subview = [subviews objectAtIndex:index];
+
+ if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
+ ++subtreeViewCount;
+
+ // Unhide the view if needed.
+ [subview setHidden:NO];
+
+ // Recursively layout the subtree, and obtain the SubtreeView's resultant size.
+ CGSize subtreeViewSize = [(PSBaseSubtreeView *)subview layoutGraphIfNeeded];
+
+ // Position the SubtreeView.
+ // [(animateLayout ? [subview animator] : subview) setFrameOrigin:nextSubtreeViewOrigin];
+
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ // Since SubtreeView is unflipped, lay out our child SubtreeViews going upward from our
+ // bottom edge, from last to first.
+ subview.frame = CGRectMake( nextSubtreeViewOrigin.x,
+ nextSubtreeViewOrigin.y,
+ subtreeViewSize.width,
+ subtreeViewSize.height );
+
+ // Advance nextSubtreeViewOrigin for the next SubtreeView.
+ nextSubtreeViewOrigin.y += subtreeViewSize.height + siblingSpacing;
+
+ // Keep track of the widest SubtreeView width we encounter.
+ if (maxWidth < subtreeViewSize.width) {
+ maxWidth = subtreeViewSize.width;
+ }
+
+ } else {
+ // TODO: Lay out our child SubtreeViews going from our left edge, last to first. SWITCH ME
+ subview.frame = CGRectMake( nextSubtreeViewOrigin.x,
+ nextSubtreeViewOrigin.y,
+ subtreeViewSize.width,
+ subtreeViewSize.height );
+
+ // Advance nextSubtreeViewOrigin for the next SubtreeView.
+ nextSubtreeViewOrigin.x += subtreeViewSize.width + siblingSpacing;
+
+ // Keep track of the widest SubtreeView width we encounter.
+ if (maxHeight < subtreeViewSize.height) {
+ maxHeight = subtreeViewSize.height;
+ }
}
}
-
- // Calculate the total height of all our SubtreeViews, including the vertical spacing between them.
- // We have N child SubtreeViews, but only (N-1) gaps between them, so subtract 1 increment of
- // siblingSpacing that was added by the loop above.
-
- CGFloat totalHeight = 0.0f;
- CGFloat totalWidth = 0.0f;
-
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- totalHeight = nextSubtreeViewOrigin.y;
- if (subtreeViewCount > 0) {
- totalHeight -= siblingSpacing;
- }
- } else {
- totalWidth = nextSubtreeViewOrigin.x;
- if (subtreeViewCount > 0) {
- totalWidth -= siblingSpacing;
- }
- }
-
-
- // Size self to contain our nodeView all our child SubtreeViews, and position our nodeView and connectorsView.
+ }
+
+ // Calculate the total height of all our SubtreeViews, including the vertical spacing between them.
+ // We have N child SubtreeViews, but only (N-1) gaps between them, so subtract 1 increment of
+ // siblingSpacing that was added by the loop above.
+
+ CGFloat totalHeight = 0.0f;
+ CGFloat totalWidth = 0.0f;
+
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ totalHeight = nextSubtreeViewOrigin.y;
if (subtreeViewCount > 0) {
-
- // Determine our width and height.
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- selfTargetSize = CGSizeMake(rootNodeViewSize.width + parentChildSpacing + maxWidth,
- MAX(totalHeight, rootNodeViewSize.height) );
- } else {
- selfTargetSize = CGSizeMake(MAX(totalWidth, rootNodeViewSize.width),
- rootNodeViewSize.height + parentChildSpacing + maxHeight);
- }
-
-
-
- // Resize to our new width and height.
- // [(animateLayout ? [self animator] : self) setFrameSize:selfTargetSize];
- self.frame = CGRectMake(self.frame.origin.x,
- self.frame.origin.y,
- selfTargetSize.width,
- selfTargetSize.height );
-
-
- CGPoint nodeViewOrigin = CGPointZero;
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- // Position our nodeView vertically centered along the left edge of our new bounds.
- nodeViewOrigin = CGPointMake(0.0f, 0.5f * (selfTargetSize.height - rootNodeViewSize.height));
-
- } else {
- // Position our nodeView horizontally centered along the top edge of our new bounds.
- nodeViewOrigin = CGPointMake(0.5f * (selfTargetSize.width - rootNodeViewSize.width), 0.0f);
- }
-
- // Pixel-align its position to keep its rendering crisp.
- CGPoint windowPoint = [self convertPoint:nodeViewOrigin toView:nil];
- windowPoint.x = round(windowPoint.x);
- windowPoint.y = round(windowPoint.y);
- nodeViewOrigin = [self convertPoint:windowPoint fromView:nil];
-
-
- // [(animateLayout ? [nodeView animator] : nodeView) setFrameOrigin:nodeViewOrigin];
- // [nodeView setCenter:nodeViewOrigin];
-
- self.nodeView.frame = CGRectMake(nodeViewOrigin.x,
- nodeViewOrigin.y,
- self.nodeView.frame.size.width,
- self.nodeView.frame.size.height );
-
- // Position, show our connectorsView and button.
-
- // TODO: Can shrink height a bit on top and bottom ends, since the connecting lines
- // meet at the nodes' vertical centers
-
- // [connectorsView setLayerContentsRedrawPolicy:UIViewLayerContentsRedrawBeforeViewResize];
- // [(animateLayout ? [connectorsView animator] : connectorsView) setFrameSize:CGSizeMake(parentChildSpacing, selfTargetSize.height)];
- // [(animateLayout ? [connectorsView animator] : connectorsView) setFrameOrigin:CGPointMake(rootNodeViewSize.width, 0.0)];
- // [connectorsView setLayerContentsRedrawPolicy:UIViewLayerContentsRedrawDuringViewResize];
-
- //[connectorsView setFrameSize:CGSizeMake(parentChildSpacing, selfTargetSize.height)];
-
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- _connectorsView.frame = CGRectMake(rootNodeViewSize.width,
- 0.0f,
- parentChildSpacing,
- selfTargetSize.height );
- } else {
- _connectorsView.frame = CGRectMake(0.0f,
- rootNodeViewSize.height,
- selfTargetSize.width,
- parentChildSpacing );
- }
-
-
- // connectorsView.contentMode = UIViewContentModeRedraw;
-
- [_connectorsView setHidden:NO];
-
+ totalHeight -= siblingSpacing;
+ }
+ } else {
+ totalWidth = nextSubtreeViewOrigin.x;
+ if (subtreeViewCount > 0) {
+ totalWidth -= siblingSpacing;
+ }
+ }
+
+ // Size self to contain our nodeView all our child SubtreeViews, and position our
+ // nodeView and connectorsView.
+ if (subtreeViewCount > 0) {
+
+ // Determine our width and height.
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ selfTargetSize = CGSizeMake(rootNodeViewSize.width + parentChildSpacing + maxWidth,
+ MAX(totalHeight, rootNodeViewSize.height) );
} else {
- // No SubtreeViews; this is a leaf node.
- // Size self to exactly wrap nodeView, hide connectorsView, and hide the button.
-
- selfTargetSize = rootNodeViewSize;
+ selfTargetSize = CGSizeMake(MAX(totalWidth, rootNodeViewSize.width),
+ rootNodeViewSize.height + parentChildSpacing + maxHeight);
+ }
+
+ // Resize to our new width and height.
+ // [(animateLayout ? [self animator] : self) setFrameSize:selfTargetSize];
+ self.frame = CGRectMake(self.frame.origin.x,
+ self.frame.origin.y,
+ selfTargetSize.width,
+ selfTargetSize.height );
+
+ CGPoint nodeViewOrigin = CGPointZero;
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ // Position our nodeView vertically centered along the left edge of our new bounds.
+ nodeViewOrigin = CGPointMake(0.0f, 0.5f * (selfTargetSize.height - rootNodeViewSize.height));
- self.frame = CGRectMake(self.frame.origin.x,
- self.frame.origin.y,
- selfTargetSize.width,
- selfTargetSize.height );
-
- self.nodeView.frame = CGRectMake(0.0f,
- 0.0f,
- self.nodeView.frame.size.width,
- self.nodeView.frame.size.height );
-
- [_connectorsView setHidden:YES];
+ } else {
+ // Position our nodeView horizontally centered along the top edge of our new bounds.
+ nodeViewOrigin = CGPointMake(0.5f * (selfTargetSize.width - rootNodeViewSize.width), 0.0f);
+ }
+
+ // Pixel-align its position to keep its rendering crisp.
+ CGPoint windowPoint = [self convertPoint:nodeViewOrigin toView:nil];
+ windowPoint.x = round(windowPoint.x);
+ windowPoint.y = round(windowPoint.y);
+ nodeViewOrigin = [self convertPoint:windowPoint fromView:nil];
+
+ self.nodeView.frame = CGRectMake(nodeViewOrigin.x,
+ nodeViewOrigin.y,
+ self.nodeView.frame.size.width,
+ self.nodeView.frame.size.height );
+
+ // Position, show our connectorsView and button.
+
+ // TODO: Can shrink height a bit on top and bottom ends, since the connecting lines
+ // meet at the nodes' vertical centers
+
+ // NOTE: It may be better to stretch the content if a collapse animation is added?
+ // Be sure to test. Given the size, and how they just contain the lines, it seems
+ // best to just redraw these things.
+
+ // [_connectorsView setContentMode:UIViewContentModeScaleToFill ];
+
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ _connectorsView.frame = CGRectMake(rootNodeViewSize.width,
+ 0.0f,
+ parentChildSpacing,
+ selfTargetSize.height );
+ } else {
+ _connectorsView.frame = CGRectMake(0.0f,
+ rootNodeViewSize.height,
+ selfTargetSize.width,
+ parentChildSpacing );
}
+
+ // NOTE: Enable this line if a collapse animation is added (line below not used)
+ // [_connectorsView setContentMode:UIViewContentModeRedraw];
+
+ [_connectorsView setHidden:NO];
+
} else {
- // This node is collapsed.
+ // No SubtreeViews; this is a leaf node.
+ // Size self to exactly wrap nodeView, hide connectorsView, and hide the button.
+
selfTargetSize = rootNodeViewSize;
-
-
- self.frame = CGRectMake(self.frame.origin.x,
- self.frame.origin.y,
- selfTargetSize.width,
- selfTargetSize.height );
-
- for (UIView *subview in [self subviews]) {
- if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
-
- [(PSBaseSubtreeView *)subview layoutGraphIfNeeded];
-
- subview.frame = CGRectMake(0.0f,
- 0.0f,
- subview.frame.size.width,
- subview.frame.size.height );
-
- [subview setHidden:YES];
-
- } else if (subview == _connectorsView) {
-
- // [connectorsView setLayerContentsRedrawPolicy:UIViewLayerContentsRedrawNever];
- // [(animateLayout ? [connectorsView animator] : connectorsView) setFrameSize:CGSizeZero];
- // [(animateLayout ? [connectorsView animator] : connectorsView) setFrameOrigin:CGPointMake(0.0, 0.5 * selfTargetSize.height)];
- // [connectorsView setLayerContentsRedrawPolicy:UIViewLayerContentsRedrawDuringViewResize];
-
-
- if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- _connectorsView.frame = CGRectMake(0.0f,
- 0.5f * selfTargetSize.height,
- 0.0f, 0.0f );
- } else {
- _connectorsView.frame = CGRectMake(0.5f * selfTargetSize.width,
- 0.0f,
- 0.0f, 0.0f );
- }
-
-
- [subview setHidden:YES];
-
- } else if (subview == _nodeView) {
-
- subview.frame = CGRectMake(0.0f,
- 0.0f,
- selfTargetSize.width,
- selfTargetSize.height );
-
+
+ self.frame = CGRectMake(self.frame.origin.x,
+ self.frame.origin.y,
+ selfTargetSize.width,
+ selfTargetSize.height );
+
+ self.nodeView.frame = CGRectMake(0.0f,
+ 0.0f,
+ self.nodeView.frame.size.width,
+ self.nodeView.frame.size.height );
+
+ [_connectorsView setHidden:YES];
+ }
+
+ // Return our new size.
+ return selfTargetSize;
+}
+
+- (CGSize) layoutCollapsedGraph
+{
+
+ // This node is collapsed. Everything will be collapsed behind the leafNode
+ CGSize selfTargetSize = [self sizeNodeViewToFitContent];
+
+ self.frame = CGRectMake(self.frame.origin.x,
+ self.frame.origin.y,
+ selfTargetSize.width,
+ selfTargetSize.height );
+
+ for (UIView *subview in [self subviews]) {
+ if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
+
+ [(PSBaseSubtreeView *)subview layoutGraphIfNeeded];
+
+ subview.frame = CGRectMake(0.0f,
+ 0.0f,
+ subview.frame.size.width,
+ subview.frame.size.height );
+
+ [subview setHidden:YES];
+
+ } else if (subview == _connectorsView) {
+
+ // NOTE: It may be better to stretch the content if a collapse animation is added?
+ // Be sure to test. Given the size, and how they just contain the lines, it seems
+ // best to just redraw these things.
+
+ // [_connectorsView setContentMode:UIViewContentModeScaleToFill ];
+
+ PSTreeGraphOrientationStyle treeOrientation = [[self enclosingTreeGraph] treeGraphOrientation];
+ if ( treeOrientation == PSTreeGraphOrientationStyleHorizontal ) {
+ _connectorsView.frame = CGRectMake(0.0f,
+ 0.5f * selfTargetSize.height,
+ 0.0f,
+ 0.0f );
+ } else {
+ _connectorsView.frame = CGRectMake(0.5f * selfTargetSize.width,
+ 0.0f,
+ 0.0f,
+ 0.0f );
}
+
+ // NOTE: Enable this line if a collapse animation is added (line below not used)
+ // [_connectorsView setContentMode:UIViewContentModeRedraw];
+
+ [subview setHidden:YES];
+
+ } else if (subview == _nodeView) {
+
+ subview.frame = CGRectMake(0.0f,
+ 0.0f,
+ selfTargetSize.width,
+ selfTargetSize.height );
+
}
}
-
- // Mark as having completed layout.
- self.needsGraphLayout = NO;
-
+
// Return our new size.
return selfTargetSize;
}
View
19 PSTreeGraphView/PSBaseTreeGraphView.h
@@ -6,9 +6,9 @@
// Copyright 2010 Preston Software. All rights reserved.
//
//
-// This is a port of the sample code from Max OS X to iOS (iPad).
+// This is a port of the sample code from Max OS X to iOS (iPad).
//
-// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
+// WWDC 2010 Session 141, “Crafting Custom Cocoa Views”
//
@@ -19,21 +19,18 @@
// A TreeGraph's nodes may be connected by either "direct" or "orthogonal" lines.
-enum PSTreeGraphConnectingLineStyle {
+typedef enum {
PSTreeGraphConnectingLineStyleDirect = 0,
- PSTreeGraphConnectingLineStyleOrthogonal = 1
-};
-typedef NSInteger PSTreeGraphConnectingLineStyle;
+ PSTreeGraphConnectingLineStyleOrthogonal = 1,
+} PSTreeGraphConnectingLineStyle;
// A TreeGraph's orientation may be either "horizontal" or "vertical".
-enum PSTreeGraphOrientationStyle {
+typedef enum {
PSTreeGraphOrientationStyleHorizontal = 0,
- PSTreeGraphOrientationStyleVertical = 1
-};
-typedef NSInteger PSTreeGraphOrientationStyle;
-
+ PSTreeGraphOrientationStyleVertical = 1,
+} PSTreeGraphOrientationStyle;
@class PSBaseSubtreeView;
View
10 PSTreeGraphView/PSBaseTreeGraphView.m
@@ -431,18 +431,16 @@ - (CGSize) layoutGraphIfNeeded
PSBaseSubtreeView *rootSubtreeView = [self rootSubtreeView];
if ([self needsGraphLayout] && [self modelRoot]) {
- // TODO: Build graph tree if needed.
-
// Do recursive graph layout, starting at our rootSubtreeView.
CGSize rootSubtreeViewSize = [rootSubtreeView layoutGraphIfNeeded];
// Compute self's new minimumFrameSize. Make sure it's pixel-integral.
CGFloat margin = [self contentMargin];
- CGSize minimumBoundsSize = CGSizeMake(rootSubtreeViewSize.width + 2.0 * margin, rootSubtreeViewSize.height + 2.0 * margin);
+ CGSize minimumBoundsSize = CGSizeMake(rootSubtreeViewSize.width + 2.0 * margin,
+ rootSubtreeViewSize.height + 2.0 * margin);
[self setMinimumFrameSize:minimumBoundsSize];
-
// Set the TreeGraph's frame size.
[self updateFrameSizeForContentAndClipView];
@@ -463,7 +461,6 @@ - (BOOL) needsGraphLayout
- (void) setNeedsGraphLayout
{
[[self rootSubtreeView] recursiveSetNeedsGraphLayout];
- [self setNeedsDisplay];
}
- (void) collapseRoot
@@ -506,10 +503,10 @@ - (CGRect) boundsOfModelNodes:(NSSet *)modelNodes
} else {
boundingBox = CGRectUnion(boundingBox, rect);
}
-
}
}
}
+
return boundingBox;
}
@@ -526,7 +523,6 @@ - (void) scrollModelNodesToVisible:(NSSet *)modelNodes animated:(BOOL)animated
// NSLog(@"Scrolling to target rect: %@", NSStringFromCGRect(targetRect) );
[parentScroll scrollRectToVisible:targetRect animated:animated];
}
-
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.