Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #8 from GunioRobot/clean

Merging changes for everyone who uses text editors with dark themes. Thank you Gunio project !!!!
  • Loading branch information...
commit 59f519c16bcabfac9e2e3d0bd957218e8d336bbc 2 parents 27763e6 + 38b99a1
@epreston authored
Showing with 633 additions and 633 deletions.
  1. +1 −1  Doxyfile
  2. +9 −9 Example 1/Classes/Controller/PSHTreeGraphAppDelegate.m
  3. +1 −1  Example 1/Classes/Controller/PSHTreeGraphViewController.h
  4. +25 −25 Example 1/Classes/Controller/PSHTreeGraphViewController.m
  5. +2 −2 Example 1/Classes/Model/ObjCClass/ObjCClassWrapper.h
  6. +14 −14 Example 1/Classes/Model/ObjCClass/ObjCClassWrapper.m
  7. +3 −3 Example 1/Classes/View/PSHLeafView.h
  8. +6 −6 Example 1/Classes/View/PSHLeafView.m
  9. +1 −1  Example 1/Classes/View/PSHTreeGraphView.h
  10. +9 −9 Example 1/Classes/View/PSHTreeGraphView.m
  11. +1 −1  PSTreeGraphView/PSBaseBranchView.h
  12. +54 −54 PSTreeGraphView/PSBaseBranchView.m
  13. +4 −4 PSTreeGraphView/PSBaseLeafView.h
  14. +27 −27 PSTreeGraphView/PSBaseLeafView.m
  15. +29 −29 PSTreeGraphView/PSBaseSubtreeView.h
  16. +163 −163 PSTreeGraphView/PSBaseSubtreeView.m
  17. +69 −69 PSTreeGraphView/PSBaseTreeGraphView.h
  18. +176 −176 PSTreeGraphView/PSBaseTreeGraphView.m
  19. +16 −16 PSTreeGraphView/PSBaseTreeGraphView_Internal.h
  20. +2 −2 PSTreeGraphView/PSTreeGraphModelNode.h
  21. +2 −2 Unit Tests/PSTTreeGraph/PSTTreeGraphAppDelegate.m
  22. +1 −1  Unit Tests/PSTTreeGraph/PSTTreeGraphViewController.m
  23. +5 −5 Unit Tests/PSTTreeGraphTests/BranchTests.m
  24. +2 −2 Unit Tests/PSTTreeGraphTests/GraphTests.m
  25. +9 −9 Unit Tests/PSTTreeGraphTests/LeafTests.m
  26. +2 −2 Unit Tests/PSTTreeGraphTests/SubTreeTests.m
View
2  Doxyfile
@@ -44,7 +44,7 @@ PROJECT_BRIEF = "A tree graph view control for iPad applications."
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
-PROJECT_LOGO =
+PROJECT_LOGO =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
View
18 Example 1/Classes/Controller/PSHTreeGraphAppDelegate.m
@@ -20,16 +20,16 @@ @implementation PSHTreeGraphAppDelegate
#pragma mark - Application Lifecycle
-- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
- // Override point for customization after app launch.
+- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ // Override point for customization after app launch.
[window_ addSubview:viewController_.view];
[window_ makeKeyAndVisible];
return YES;
}
-- (void) applicationWillResignActive:(UIApplication *)application
+- (void) applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for
// certain types of temporary interruptions (such as an incoming phone call or SMS message) or
@@ -39,13 +39,13 @@ - (void) applicationWillResignActive:(UIApplication *)application
// Games should use this method to pause the game.
}
-- (void) applicationDidBecomeActive:(UIApplication *)application
+- (void) applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive.
// If the application was previously in the background, optionally refresh the user interface.
}
-- (void) applicationWillTerminate:(UIApplication *)application
+- (void) applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate.
// See also applicationDidEnterBackground:.
@@ -54,13 +54,13 @@ - (void) applicationWillTerminate:(UIApplication *)application
#pragma mark - Resouce Management
-- (void) applicationDidReceiveMemoryWarning:(UIApplication *)application
+- (void) applicationDidReceiveMemoryWarning:(UIApplication *)application
{
- // Free up as much memory as possible by purging cached data objects that can be recreated
+ // Free up as much memory as possible by purging cached data objects that can be recreated
// (or reloaded from disk) later.
}
-- (void) dealloc
+- (void) dealloc
{
[viewController_ release];
[window_ release];
View
2  Example 1/Classes/Controller/PSHTreeGraphViewController.h
@@ -13,7 +13,7 @@
@class PSBaseTreeGraphView;
-@interface PSHTreeGraphViewController : UIViewController <PSTreeGraphDelegate>
+@interface PSHTreeGraphViewController : UIViewController <PSTreeGraphDelegate>
{
@private
View
50 Example 1/Classes/Controller/PSHTreeGraphViewController.m
@@ -23,14 +23,14 @@ @implementation PSHTreeGraphViewController
@synthesize treeGraphView = treeGraphView_;
@synthesize rootClassName = rootClassName_;
-- (void) setRootClassName:(NSString *)newRootClassName
-{
+- (void) setRootClassName:(NSString *)newRootClassName
+{
NSParameterAssert(newRootClassName != nil);
-
+
if (![rootClassName_ isEqualToString:newRootClassName]) {
[rootClassName_ release];
rootClassName_ = [newRootClassName copy];
-
+
// Get an ObjCClassWrapper for the named Objective-C Class, and set it as the TreeGraph's root.
[treeGraphView_ setModelRoot:[ObjCClassWrapper wrapperForClassNamed:rootClassName_]];
}
@@ -40,30 +40,30 @@ - (void) setRootClassName:(NSString *)newRootClassName
#pragma mark - View Creation and Initializer
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
-- (void) viewDidLoad
+- (void) viewDidLoad
{
[super viewDidLoad];
-
+
// Set the delegate to self.
[self.treeGraphView setDelegate:self];
-
+
// Specify a .nib file for the TreeGraph to load each time it needs to create a new node view.
[self.treeGraphView setNodeViewNibName:@"ObjCClassTreeNodeView"];
-
+
// Specify a starting root class to inspect on launch.
[self setRootClassName:@"UIControl"];
-
+
}
// Override to allow orientations other than the default portrait orientation.
-- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
-- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
- duration:(NSTimeInterval)duration
-{
+- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+ duration:(NSTimeInterval)duration
+{
// Keep the view in sync
[self.treeGraphView parentClipViewDidResize:nil];
}
@@ -71,45 +71,45 @@ - (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)inter
#pragma mark - TreeGraph Delegate
--(void) configureNodeView:(UIView *)nodeView
- withModelNode:(id <PSTreeGraphModelNode> )modelNode
-{
+-(void) configureNodeView:(UIView *)nodeView
+ withModelNode:(id <PSTreeGraphModelNode> )modelNode
+{
NSParameterAssert(nodeView != nil);
NSParameterAssert(modelNode != nil);
-
+
// NOT FLEXIBLE: treat it like a model node instead of the interface.
ObjCClassWrapper *objectWrapper = (ObjCClassWrapper *)modelNode;
PSHLeafView *leafView = (PSHLeafView *)nodeView;
-
+
// button
if ( [[objectWrapper childModelNodes] count] == 0 ) {
[leafView.expandButton setHidden:YES];
}
-
+
// labels
- leafView.titleLabel.text = [objectWrapper name];
+ leafView.titleLabel.text = [objectWrapper name];
leafView.detailLabel.text = [NSString stringWithFormat:@"%d bytes", [objectWrapper wrappedClassInstanceSize]];
-
+
}
#pragma mark - Resouce Management
-- (void) didReceiveMemoryWarning
+- (void) didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
-
+
// Release any cached data, images, etc that aren't in use.
}
-- (void) viewDidUnload
+- (void) viewDidUnload
{
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-- (void) dealloc
+- (void) dealloc
{
[rootClassName_ release];
[super dealloc];
View
4 Example 1/Classes/Model/ObjCClass/ObjCClassWrapper.h
@@ -23,7 +23,7 @@
#pragma mark - Creating Instances
-// Returns an ObjCClassWrapper for the given Objective-C class. ObjCClassWrapper maintains
+// Returns an ObjCClassWrapper for the given Objective-C class. ObjCClassWrapper maintains
// a set of unique instances, so this will always return the same ObjCClassWrapper for a given Class.
+ (ObjCClassWrapper *) wrapperForClass:(Class)aClass;
@@ -44,7 +44,7 @@
@property (nonatomic, readonly) ObjCClassWrapper *superclassWrapper;
-// An array of ObjCClassWrappers representing the wrappedClass' subclasses.
+// An array of ObjCClassWrappers representing the wrappedClass' subclasses.
// (For convenience, the subclasses are sorted by name.)
@property (nonatomic, readonly) NSArray *subclasses;
View
28 Example 1/Classes/Model/ObjCClass/ObjCClassWrapper.m
@@ -10,15 +10,15 @@
#import <objc/runtime.h>
-// Keeps track of the ObjCClassWrapper instances we create. We create one unique
+// Keeps track of the ObjCClassWrapper instances we create. We create one unique
// ObjCClassWrapper for each Objective-C "Class" we're asked to wrap.
static NSMutableDictionary *classToWrapperMapTable = nil;
// Compares two ObjCClassWrappers by name, and returns an NSComparisonResult.
-
-static NSInteger CompareClassNames(id classA, id classB, void* context)
+
+static NSInteger CompareClassNames(id classA, id classB, void* context)
{
return [[classA description] compare:[classB description]];
}
@@ -30,7 +30,7 @@ @implementation ObjCClassWrapper
#pragma mark - NSCopying
-- (id) copyWithZone:(NSZone *)zone
+- (id) copyWithZone:(NSZone *)zone
{
return [self retain];
}
@@ -38,7 +38,7 @@ - (id) copyWithZone:(NSZone *)zone
#pragma mark - Creating Instances
-- initWithWrappedClass:(Class)aClass
+- initWithWrappedClass:(Class)aClass
{
self = [super init];
if (self) {
@@ -56,7 +56,7 @@ - (id) copyWithZone:(NSZone *)zone
return self;
}
-+ (ObjCClassWrapper *) wrapperForClass:(Class)aClass
++ (ObjCClassWrapper *) wrapperForClass:(Class)aClass
{
ObjCClassWrapper *wrapper = [classToWrapperMapTable objectForKey:aClass];
if (wrapper == nil) {
@@ -65,7 +65,7 @@ + (ObjCClassWrapper *) wrapperForClass:(Class)aClass
return wrapper;
}
-+ (ObjCClassWrapper *) wrapperForClassNamed:(NSString *)aClassName
++ (ObjCClassWrapper *) wrapperForClassNamed:(NSString *)aClassName
{
return [self wrapperForClass:NSClassFromString(aClassName)];
}
@@ -73,27 +73,27 @@ + (ObjCClassWrapper *) wrapperForClassNamed:(NSString *)aClassName
#pragma mark - Property Accessors
-- (NSString *) name
+- (NSString *) name
{
return NSStringFromClass(wrappedClass);
}
-- (NSString *) description
+- (NSString *) description
{
return [self name];
}
-- (size_t) wrappedClassInstanceSize
+- (size_t) wrappedClassInstanceSize
{
return class_getInstanceSize(wrappedClass);
}
-- (ObjCClassWrapper *) superclassWrapper
+- (ObjCClassWrapper *) superclassWrapper
{
return [[self class] wrapperForClass:class_getSuperclass(wrappedClass)];
}
-- (NSArray *) subclasses
+- (NSArray *) subclasses
{
// If we haven't built our array of subclasses yet, do so.
if (subclassesCache == nil) {
@@ -127,12 +127,12 @@ - (NSArray *) subclasses
#pragma mark - TreeGraphModelNode Protocol
-- (id <PSTreeGraphModelNode> ) parentModelNode
+- (id <PSTreeGraphModelNode> ) parentModelNode
{
return [self superclassWrapper];
}
-- (NSArray *) childModelNodes
+- (NSArray *) childModelNodes
{
return [self subclasses];
}
View
6 Example 1/Classes/View/PSHLeafView.h
@@ -11,11 +11,11 @@
#import "PSBaseLeafView.h"
-@interface PSHLeafView : PSBaseLeafView
+@interface PSHLeafView : PSBaseLeafView
{
-
+
@private
-
+
// Interface
UIButton *expandButton_;
UILabel *titleLabel_;
View
12 Example 1/Classes/View/PSHLeafView.m
@@ -19,19 +19,19 @@ @implementation PSHLeafView
#pragma mark - NSCoding
-- (id) initWithCoder:(NSCoder *)decoder
+- (id) initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder];
if (self) {
-
+
// Initialization code, leaf views are always loaded from the corresponding XIB.
// Be sure to set the view class to your subclass in interface builder.
-
+
// Example: Inverse the color scheme
-
+
// self.fillColor = [UIColor yellowColor];
// self.selectionColor = [UIColor orangeColor];
-
+
}
return self;
}
@@ -39,7 +39,7 @@ - (id) initWithCoder:(NSCoder *)decoder
#pragma mark - Resource Management
-- (void) dealloc
+- (void) dealloc
{
[super dealloc];
}
View
2  Example 1/Classes/View/PSHTreeGraphView.h
@@ -11,7 +11,7 @@
#import "PSBaseTreeGraphView.h"
-@interface PSHTreeGraphView : PSBaseTreeGraphView
+@interface PSHTreeGraphView : PSBaseTreeGraphView
{
// TODO: Place project specific code, extentions here.
}
View
18 Example 1/Classes/View/PSHTreeGraphView.m
@@ -15,12 +15,12 @@ @implementation PSHTreeGraphView
#pragma mark - UIView
-- (id) initWithFrame:(CGRect)frame
+- (id) initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
-
+
// Initialization code when created dynamicly
-
+
}
return self;
}
@@ -28,24 +28,24 @@ - (id) initWithFrame:(CGRect)frame
#pragma mark - NSCoding
-- (id) initWithCoder:(NSCoder *)decoder
+- (id) initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder];
if (self) {
-
+
// Initialization code when loaded from XIB (this example)
-
+
// Example: Set a larger content margin than default.
-
+
// self.contentMargin = 60.0;
-
+
}
return self;
}
#pragma mark - Resource Management
-- (void) dealloc
+- (void) dealloc
{
[super dealloc];
}
View
2  PSTreeGraphView/PSBaseBranchView.h
@@ -22,7 +22,7 @@
@interface PSBaseBranchView : UIView
-/// Link to the enclosing TreeGraph. (The getter for this is a convenience method that ascends the view tree
+/// Link to the enclosing TreeGraph. (The getter for this is a convenience method that ascends the view tree
/// until it encounters a TreeGraph.)
@property (nonatomic, readonly) PSBaseTreeGraphView *enclosingTreeGraph;
View
108 PSTreeGraphView/PSBaseBranchView.m
@@ -28,7 +28,7 @@ - (UIBezierPath *) orthogonalConnectionsPath;
@implementation PSBaseBranchView
-- (PSBaseTreeGraphView *) enclosingTreeGraph
+- (PSBaseTreeGraphView *) enclosingTreeGraph
{
UIView *ancestor = [self superview];
while (ancestor) {
@@ -43,38 +43,38 @@ - (PSBaseTreeGraphView *) enclosingTreeGraph
#pragma mark - Drawing
-- (UIBezierPath *) directConnectionsPath
+- (UIBezierPath *) directConnectionsPath
{
CGRect bounds = [self bounds];
CGPoint rootPoint = CGPointZero;
-
+
PSTreeGraphOrientationStyle treeDirection = [[self enclosingTreeGraph] treeGraphOrientation];
-
+
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- rootPoint = CGPointMake(CGRectGetMinX(bounds),
+ rootPoint = CGPointMake(CGRectGetMinX(bounds),
CGRectGetMidY(bounds));
} else {
- rootPoint = CGPointMake(CGRectGetMidX(bounds),
+ rootPoint = CGPointMake(CGRectGetMidX(bounds),
CGRectGetMinY(bounds));
}
// Create a single bezier path that we'll use to stroke all the lines.
UIBezierPath *path = [UIBezierPath bezierPath];
-
+
// Add a stroke from rootPoint to each child SubtreeView of our containing SubtreeView.
UIView *subtreeView = [self superview];
if ([subtreeView isKindOfClass:[PSBaseSubtreeView class]]) {
-
+
for (UIView *subview in [subtreeView subviews]) {
if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
CGRect subviewBounds = [subview bounds];
CGPoint targetPoint = CGPointZero;
-
+
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds))
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds))
fromView:subview];
} else {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds))
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds))
fromView:subview];
}
@@ -83,93 +83,93 @@ - (UIBezierPath *) directConnectionsPath
}
}
}
-
+
// Return the path.
return path;
}
-- (UIBezierPath *) orthogonalConnectionsPath
+- (UIBezierPath *) orthogonalConnectionsPath
{
- // Compute the needed adjustment in x and y to align our lines for crisp, exact pixel coverage.
+ // Compute the needed adjustment in x and y to align our lines for crisp, exact pixel coverage.
// (We can only do this if the lineWidth is integral, which it usually is.)
// CGFloat adjustment = 0.0;
// CGFloat lineWidth = [[self enclosingTreeGraph] connectingLineWidth];
// CGSize lineSize = CGSizeMake(lineWidth, lineWidth);
// CGSize lineSizeInPixels = [self convertSizeToBase:lineSize];
- //
+ //
// CGFloat halfLineWidthInPixels = 0.5 * lineSizeInPixels.width;
// if (fabs(halfLineWidthInPixels - floor(halfLineWidthInPixels)) > 0.0001) {
// // If line width in pixels is odd, lay our path segments along the centers of pixel rows.
// CGSize adjustmentAsSizeInPixels = CGSizeMake(0.5, 0.5);
// CGSize adjustmentAsSize = [self convertSizeFromBase:adjustmentAsSizeInPixels];
- //
+ //
// adjustment = adjustmentAsSize.width;
// }
-
+
CGRect bounds = [self bounds];
// CGPoint basePoint;
-
+
PSTreeGraphOrientationStyle treeDirection = [[self enclosingTreeGraph] treeGraphOrientation];
-
+
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),
+ rootPoint = CGPointMake(CGRectGetMinX(bounds),
CGRectGetMidY(bounds));
} else {
- rootPoint = CGPointMake(CGRectGetMidX(bounds),
+ rootPoint = CGPointMake(CGRectGetMidX(bounds),
CGRectGetMinY(bounds));
}
-
+
// Align the line to get exact pixel coverage, for sharper rendering.
// basePoint = [self convertPointToBase:rootPoint];
// basePoint.x = round(basePoint.x) + adjustment;
// basePoint.y = round(basePoint.y) + adjustment;
// rootPoint = [self convertPointFromBase:basePoint];
-
-
- // Compute point (really, we're just interested in the x value) at which 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));
-
+
// Align the line to get exact pixel coverage, for sharper rendering.
// basePoint = [self convertPointToBase:rootIntersection];
// basePoint.x = round(basePoint.x) + adjustment;
// basePoint.y = round(basePoint.y) + adjustment;
// rootIntersection = [self convertPointFromBase:basePoint];
-
+
// Create a single bezier path that we'll use to stroke all the lines.
UIBezierPath *path = [UIBezierPath bezierPath];
-
- // Add a stroke from each child SubtreeView to where we'll put the vertical connecting line.
+
+ // Add a stroke from each child SubtreeView to where we'll put the vertical connecting line.
// And while we're iterating over SubtreeViews, make a note of the minimum and maximum Y we'll
// want for the endpoints of the vertical connecting line.
-
+
CGFloat minY = rootPoint.y;
CGFloat maxY = rootPoint.y;
CGFloat minX = rootPoint.x;
CGFloat maxX = rootPoint.x;
-
+
UIView *subtreeView = [self superview];
NSInteger subtreeViewCount = 0;
-
+
if ([subtreeView isKindOfClass:[PSBaseSubtreeView class]]) {
-
+
for (UIView *subview in [subtreeView subviews]) {
if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
++subtreeViewCount;
-
+
CGRect subviewBounds = [subview bounds];
CGPoint targetPoint = CGPointZero;
-
+
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds))
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMinX(subviewBounds), CGRectGetMidY(subviewBounds))
fromView:subview];
} else {
- targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds))
+ targetPoint = [self convertPoint:CGPointMake(CGRectGetMidX(subviewBounds), CGRectGetMinY(subviewBounds))
fromView:subview];
}
@@ -178,12 +178,12 @@ - (UIBezierPath *) orthogonalConnectionsPath
// basePoint.x = round(basePoint.x) + adjustment;
// basePoint.y = round(basePoint.y) + adjustment;
// targetPoint = [self convertPointFromBase:basePoint];
-
+
// TODO: Make clean line joins (test at high values of line thickness to see the problem).
-
+
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
[path moveToPoint:CGPointMake(rootIntersection.x, targetPoint.y)];
-
+
if (minY > targetPoint.y) {
minY = targetPoint.y;
}
@@ -192,7 +192,7 @@ - (UIBezierPath *) orthogonalConnectionsPath
}
} else {
[path moveToPoint:CGPointMake(targetPoint.x, rootIntersection.y)];
-
+
if (minX > targetPoint.x) {
minX = targetPoint.x;
}
@@ -202,16 +202,16 @@ - (UIBezierPath *) orthogonalConnectionsPath
}
[path addLineToPoint:targetPoint];
-
+
}
}
}
-
+
if (subtreeViewCount) {
// Add a stroke from rootPoint to where we'll put the vertical connecting line.
[path moveToPoint:rootPoint];
[path addLineToPoint:rootIntersection];
-
+
if ( treeDirection == PSTreeGraphOrientationStyleHorizontal ) {
// Add a stroke for the vertical connecting line.
[path moveToPoint:CGPointMake(rootIntersection.x, minY)];
@@ -223,41 +223,41 @@ - (UIBezierPath *) orthogonalConnectionsPath
}
}
-
+
// Return the path.
return path;
}
-- (void) drawRect:(CGRect)dirtyRect
-{
+- (void) drawRect:(CGRect)dirtyRect
+{
// Build the set of lines to stroke, according to our enclosingTreeGraph's connectingLineStyle.
UIBezierPath *path = nil;
-
+
switch ([[self enclosingTreeGraph] connectingLineStyle]) {
case PSTreeGraphConnectingLineStyleDirect:
default:
path = [self directConnectionsPath];
break;
-
+
case PSTreeGraphConnectingLineStyleOrthogonal:
path = [self orthogonalConnectionsPath];
break;
}
-
+
// Stroke the path with the appropriate color and line width.
PSBaseTreeGraphView *treeGraph = [self enclosingTreeGraph];
-
+
if ( [self isOpaque] ) {
// Fill background.
[[treeGraph backgroundColor] set];
UIRectFill(dirtyRect);
}
-
+
// Draw lines
[[treeGraph connectingLineColor] set];
[path setLineWidth:[treeGraph connectingLineWidth]];
[path stroke];
-
+
}
@end
View
8 PSTreeGraphView/PSBaseLeafView.h
@@ -16,18 +16,18 @@
/// Draws background fill and a stroked, optionally rounded rectangular shape. This is meant
/// to be a subclass for project specific node views loaded from a nib file.
-
+
@interface PSBaseLeafView : UIView
{
-
+
@private
UIColor *borderColor_;
CGFloat borderWidth_;
CGFloat cornerRadius_;
-
+
UIColor *fillColor_;
UIColor *selectionColor_;
-
+
BOOL showingSelected_;
}
View
54 PSTreeGraphView/PSBaseLeafView.m
@@ -29,11 +29,11 @@ - (void) configureDetaults;
@implementation PSBaseLeafView
-#pragma mark - Styling
+#pragma mark - Styling
@synthesize borderColor = borderColor_;
-- (void) setBorderColor:(UIColor *)color
+- (void) setBorderColor:(UIColor *)color
{
if (borderColor_ != color) {
[borderColor_ release];
@@ -44,7 +44,7 @@ - (void) setBorderColor:(UIColor *)color
@synthesize borderWidth = borderWidth_;
-- (void) setBorderWidth:(CGFloat)width
+- (void) setBorderWidth:(CGFloat)width
{
if (borderWidth_ != width) {
borderWidth_ = width;
@@ -54,7 +54,7 @@ - (void) setBorderWidth:(CGFloat)width
@synthesize cornerRadius = cornerRadius_;
-- (void) setCornerRadius:(CGFloat)radius
+- (void) setCornerRadius:(CGFloat)radius
{
if (cornerRadius_ != radius) {
cornerRadius_ = radius;
@@ -64,7 +64,7 @@ - (void) setCornerRadius:(CGFloat)radius
@synthesize fillColor = fillColor_;
-- (void) setFillColor:(UIColor *)color
+- (void) setFillColor:(UIColor *)color
{
if (fillColor_ != color) {
[fillColor_ release];
@@ -89,7 +89,7 @@ - (void) setSelectionColor:(UIColor *)color
@synthesize showingSelected = showingSelected_;
-- (void) setShowingSelected:(BOOL)newShowingSelected
+- (void) setShowingSelected:(BOOL)newShowingSelected
{
if (showingSelected_ != newShowingSelected) {
showingSelected_ = newShowingSelected;
@@ -100,38 +100,38 @@ - (void) setShowingSelected:(BOOL)newShowingSelected
#pragma mark - Update Layer
-- (void) updateLayerAppearanceToMatchContainerView
+- (void) updateLayerAppearanceToMatchContainerView
{
CALayer *layer = [self layer];
if (layer) {
-
+
// Disable implicit animations during these layer property changes, to make them take effect immediately.
-
+
// BOOL actionsWereDisabled = [CATransaction disableActions];
// [CATransaction setDisableActions:YES];
-
- // Apply the ContainerView's appearance properties to its backing layer.
+
+ // Apply the ContainerView's appearance properties to its backing layer.
// Important: While UIView metrics are conventionally expressed in points, CALayer metrics are
- // expressed in pixels. To produce the correct borderWidth and cornerRadius to apply to the
+ // expressed in pixels. To produce the correct borderWidth and cornerRadius to apply to the
// layer, we must multiply by the window's userSpaceScaleFactor (which is normally 1.0, but may
// be larger on a higher-resolution display) to yield pixel units.
-
+
// CGFloat scaleFactor = [[self window] userSpaceScaleFactor];
CGFloat scaleFactor = 1.0f;
-
+
[layer setBorderWidth:(borderWidth_ * scaleFactor)];
if (borderWidth_ > 0.0f) {
[layer setBorderColor:[borderColor_ CGColor]];
}
-
+
[layer setCornerRadius:(cornerRadius_ * scaleFactor)];
-
+
if ( showingSelected_ ) {
[layer setBackgroundColor:[[self selectionColor] CGColor] ];
} else {
[layer setBackgroundColor:[[self fillColor] CGColor] ];
}
-
+
// [CATransaction setDisableActions:actionsWereDisabled];
} else {
[self setNeedsDisplay];
@@ -141,11 +141,11 @@ - (void) updateLayerAppearanceToMatchContainerView
#pragma mark - Initialization
-- (void) configureDetaults
+- (void) configureDetaults
{
// Initialize ivars directly. As a rule, it's best to avoid invoking accessors from an -init...
// method, since they may wrongly expect the instance to be fully formed.
-
+
borderColor_ = [[UIColor colorWithRed:1.0 green:0.8 blue:0.4 alpha:1.0] retain];
borderWidth_ = 3.0;
cornerRadius_ = 8.0;
@@ -157,19 +157,19 @@ - (void) configureDetaults
#pragma mark - Resource Management
-- (void) dealloc
+- (void) dealloc
{
[borderColor_ release];
[fillColor_ release];
[selectionColor_ release];
-
+
[super dealloc];
}
#pragma mark - UIView
-- initWithFrame:(CGRect)newFrame
+- initWithFrame:(CGRect)newFrame
{
self = [super initWithFrame:newFrame];
if (self) {
@@ -182,7 +182,7 @@ - (void) dealloc
#pragma mark - NSCoding
-- (void) encodeWithCoder:(NSCoder *)encoder
+- (void) encodeWithCoder:(NSCoder *)encoder
{
[super encodeWithCoder:encoder];
[encoder encodeObject:borderColor_ forKey:@"borderColor"];
@@ -193,13 +193,13 @@ - (void) encodeWithCoder:(NSCoder *)encoder
[encoder encodeBool:showingSelected_ forKey:@"showingSelected"];
}
-- (id) initWithCoder:(NSCoder *)decoder
+- (id) initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder];
if (self) {
-
+
[self configureDetaults];
-
+
if ([decoder containsValueForKey:@"borderColor"])
borderColor_ = [[decoder decodeObjectForKey:@"borderColor"] retain];
if ([decoder containsValueForKey:@"borderWidth"])
@@ -212,7 +212,7 @@ - (id) initWithCoder:(NSCoder *)decoder
selectionColor_ = [[decoder decodeObjectForKey:@"selectionColor"] retain];
if ([decoder containsValueForKey:@"showingSelected"])
showingSelected_ = [decoder decodeBoolForKey:@"showingSelected"];
-
+
[self updateLayerAppearanceToMatchContainerView];
}
return self;
View
58 PSTreeGraphView/PSBaseSubtreeView.h
@@ -21,54 +21,54 @@
@class PSBaseTreeGraphView;
-/// A SubtreeView draws nothing itself (unless showsSubtreeFrames is set to YES for
+/// 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
{
-
+
@private
// Model
id <PSTreeGraphModelNode> modelNode_; // the model node that nodeView represents
-
+
// Views
UIView *nodeView_; // the subview of this SubtreeView that shows a representation
// of the modelNode
-
+
PSBaseBranchView *connectorsView_; // the view that shows connections from nodeView to its child nodes
-
+
// State
- BOOL expanded_; // YES if this subtree is expanded to show its descendants;
+ BOOL expanded_; // YES if this subtree is expanded to show its descendants;
// NO if it's been collapsed to show just its root node
-
- BOOL needsGraphLayout_; // YES if this SubtreeView needs to position its child views
+
+ BOOL needsGraphLayout_; // YES if this SubtreeView needs to position its child views
// and assess its size; NO if we're sure its layout is up to date
}
/// Initializes a SubtreeView with the associated modelNode. This is SubtreeView's designated initializer.
-
+
- initWithModelNode:( id <PSTreeGraphModelNode> )newModelNode;
/// The root of the model subtree that this SubtreeView represents.
-
+
@property (nonatomic, retain) id <PSTreeGraphModelNode> modelNode;
/// The view that represents the modelNode. Is a subview of SubtreeView, and may itself have descendant views.
-
+
@property (nonatomic, assign) IBOutlet UIView *nodeView;
/// Link to the enclosing TreeGraph. (The getter for this is a convenience method that ascends
/// the view tree until it encounters a TreeGraph.)
-
+
@property (nonatomic, readonly) PSBaseTreeGraphView *enclosingTreeGraph;
-// Whether the model node represented by this SubtreeView is a leaf node (one without child nodes). This
-// can be a useful property to bind user interface state to. In the TreeGraph demo app, for example,
+// Whether the model node represented by this SubtreeView is a leaf node (one without child nodes). This
+// can be a useful property to bind user interface state to. In the TreeGraph demo app, for example,
// we've bound the "isHidden" property of subtree expand/collapse buttons to this, so that expand/collapse
// buttons will only be shown for non-leaf nodes.
-
+
@property (nonatomic, readonly, getter=isLeaf) BOOL leaf;
@@ -76,61 +76,61 @@
/// Whether the node is part of the TreeGraph's current selection. This can be a useful property to bind user
/// interface state to.
-
+
@property (nonatomic, readonly) BOOL nodeIsSelected;
#pragma mark - Layout
/// Returns YES if this subtree needs relayout.
-
+
@property (nonatomic, assign) BOOL needsGraphLayout;
/// Recursively marks this subtree, and all of its descendants, as needing relayout.
-
+
- (void) recursiveSetNeedsGraphLayout;
/// Recursively performs graph layout, if this subtree is marked as needing it.
-
+
- (CGSize) layoutGraphIfNeeded;
/// Resizes this subtree's nodeView to the minimum size required to hold its content, and returns the nodeView's
/// new size. (This currently does nothing, and is just stubbed out for future use.)
-
+
- (CGSize) sizeNodeViewToFitContent;
/// Whether this subtree is currently shown as expanded. If NO, the node's children have been collapsed into it.
-
+
@property (nonatomic, assign, getter=isExpanded) BOOL expanded;
/// Toggles expansion of this subtree. This can be wired up as the action of a button or other user interface
/// control.
-
+
- (IBAction) toggleExpansion:(id)sender;
#pragma mark - Invalidation
/// Marks all BranchView instances in this subtree as needing display.
-
+
- (void) recursiveSetConnectorsViewsNeedDisplay;
/// Marks all SubtreeView debug borders as needing display.
-
+
- (void) resursiveSetSubtreeBordersNeedDisplay;
#pragma mark - Node Hit-Testing
-/// Returns the visible model node whose nodeView contains the given point "p", where "p" is specified in the
+/// Returns the visible model node whose nodeView contains the given point "p", where "p" is specified in the
/// SubtreeView's interior (bounds) coordinate space. Returns nil if there is no node under the specified point.
/// When a subtree is collapsed, only its root nodeView is eligible for hit-testing.
-
+
- ( id <PSTreeGraphModelNode> ) modelNodeAtPoint:(CGPoint)p;
/// Returns the visible model node that is closest to the specified y coordinate, where "y" is specified in the
/// SubtreeView's interior (bounds) coordinate space.
-
+
- ( id <PSTreeGraphModelNode> ) modelNodeClosestToY:(CGFloat)y;
/// Returns the visible model node that is closest to the specified x coordinate, where "x" is specified in the
@@ -141,7 +141,7 @@
#pragma mark - Debugging
/// Returns an indented multi-line NSString summary of the displayed tree. Provided as a debugging aid.
-
+
- (NSString *) treeSummaryWithDepth:(NSInteger)depth;
@end
View
326 PSTreeGraphView/PSBaseSubtreeView.m
@@ -23,12 +23,12 @@
#define CENTER_COLLAPSED_SUBTREE_ROOT 1
-static UIColor *subtreeBorderColor(void)
+static UIColor *subtreeBorderColor(void)
{
return [[UIColor colorWithRed:0.0f green:0.5f blue:0.0f alpha:1.0f] retain];
}
-static CGFloat subtreeBorderWidth(void)
+static CGFloat subtreeBorderWidth(void)
{
return 2.0f;
}
@@ -52,16 +52,16 @@ @implementation PSBaseSubtreeView
@synthesize expanded = expanded_;
-- (void) setExpanded:(BOOL)flag
+- (void) setExpanded:(BOOL)flag
{
if (expanded_ != flag) {
-
+
// Remember this SubtreeView's new state.
expanded_ = flag;
-
+
// Notify the TreeGraph we need layout.
[[self enclosingTreeGraph] setNeedsGraphLayout];
-
+
// Expand or collapse subtrees recursively.
for (UIView *subview in [self subviews]) {
if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
@@ -77,20 +77,20 @@ - (IBAction) toggleExpansion:(id)sender
// [UIView setAnimationDuration:8.0];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
-
+
[self setExpanded:![self isExpanded]];
-
+
[[self enclosingTreeGraph] layoutGraphIfNeeded];
-
+
if ( [self modelNode] != nil ) {
NSSet *visibleSet = [NSSet setWithObject:[self modelNode]];
[[self enclosingTreeGraph] scrollModelNodesToVisible:visibleSet animated:NO];
}
-
+
[UIView commitAnimations];
}
-- (BOOL) isLeaf
+- (BOOL) isLeaf
{
return [[[self modelNode] childModelNodes] count] == 0;
}
@@ -98,23 +98,23 @@ - (BOOL) isLeaf
#pragma mark - Instance Initialization
-- initWithModelNode:(id <PSTreeGraphModelNode> )newModelNode
-{
+- initWithModelNode:(id <PSTreeGraphModelNode> )newModelNode
+{
NSParameterAssert(newModelNode);
-
+
self = [super initWithFrame:CGRectMake(10.0, 10.0, 100.0, 25.0)];
if (self) {
-
- // Initialize ivars directly. As a rule, it's best to avoid invoking accessors from an -init...
+
+ // Initialize ivars directly. As a rule, it's best to avoid invoking accessors from an -init...
// method, since they may wrongly expect the instance to be fully formed.
-
+
expanded_ = YES;
needsGraphLayout_ = YES;
-
+
// autoresizesSubviews defaults to YES. We don't want autoresizing, which would interfere
// with the explicit layout we do, so we switch it off for SubtreeView instances.
[self setAutoresizesSubviews:NO];
-
+
self.modelNode = newModelNode;
connectorsView_ = [[PSBaseBranchView alloc] initWithFrame:CGRectZero];
if (connectorsView_) {
@@ -122,7 +122,7 @@ - (BOOL) isLeaf
// if we dont redraw lines, they get out of place
[connectorsView_ setContentMode:UIViewContentModeRedraw];
[connectorsView_ setOpaque:YES];
-
+
[self addSubview:connectorsView_];
}
}
@@ -130,7 +130,7 @@ - (BOOL) isLeaf
}
-- (PSBaseTreeGraphView *) enclosingTreeGraph
+- (PSBaseTreeGraphView *) enclosingTreeGraph
{
UIView *ancestor = [self superview];
while (ancestor) {
@@ -144,12 +144,12 @@ - (PSBaseTreeGraphView *) enclosingTreeGraph
#pragma mark - Resource Management
-- (void) dealloc
+- (void) dealloc
{
// [nodeView release]; // not retained, since an IBOutlet
[connectorsView_ release];
[modelNode_ release];
-
+
[super dealloc];
}
@@ -158,7 +158,7 @@ - (void) dealloc
@synthesize needsGraphLayout = needsGraphLayout_;
-- (void) recursiveSetNeedsGraphLayout
+- (void) recursiveSetNeedsGraphLayout
{
[self setNeedsGraphLayout:YES];
for (UIView *subview in [self subviews]) {
@@ -168,20 +168,20 @@ - (void) recursiveSetNeedsGraphLayout
}
}
-- (CGSize) sizeNodeViewToFitContent
+- (CGSize) sizeNodeViewToFitContent
{
- // TODO: Node size is hardwired for now, but the layout algorithm could accommodate
+ // 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) layoutGraphIfNeeded
{
// Return early if layout not needed
if ( !self.needsGraphLayout )
return [self frame].size;
-
+
// Do the layout
CGSize selfTargetSize;
if ( [self isExpanded] ) {
@@ -189,10 +189,10 @@ - (CGSize) layoutGraphIfNeeded
} else {
selfTargetSize = [self layoutCollapsedGraph];
}
-
+
// Mark as having completed layout.
self.needsGraphLayout = NO;
-
+
// Return our new size.
return selfTargetSize;
}
@@ -200,23 +200,23 @@ - (CGSize) layoutGraphIfNeeded
- (CGSize) layoutExpandedGraph
{
CGSize selfTargetSize;
-
+
PSBaseTreeGraphView *treeGraph = [self enclosingTreeGraph];
-
+
CGFloat parentChildSpacing = [treeGraph parentChildSpacing];
CGFloat siblingSpacing = [treeGraph siblingSpacing];
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
+ // 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];
-
+
// 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;
@@ -224,54 +224,54 @@ - (CGSize) layoutExpandedGraph
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,
+ 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,
+ 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;
@@ -279,14 +279,14 @@ - (CGSize) layoutExpandedGraph
}
}
}
-
- // 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
+
+ // 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) {
@@ -298,158 +298,158 @@ - (CGSize) layoutExpandedGraph
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,
+ 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,
+ 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));
-
+
} 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 = 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
+
+ // 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,
+ connectorsView_.frame = CGRectMake(rootNodeViewSize.width,
+ 0.0f,
+ parentChildSpacing,
selfTargetSize.height );
} else {
- connectorsView_.frame = CGRectMake(0.0f,
- rootNodeViewSize.height,
+ connectorsView_.frame = CGRectMake(0.0f,
+ rootNodeViewSize.height,
selfTargetSize.width,
- parentChildSpacing );
+ parentChildSpacing );
}
-
+
// NOTE: Enable this line if a collapse animation is added (line below not used)
// [_connectorsView setContentMode:UIViewContentModeRedraw];
-
+
[connectorsView_ setHidden:NO];
-
+
} else {
- // No SubtreeViews; this is a leaf node.
+ // 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,
+
+ 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.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,
+
+ 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.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,
+ connectorsView_.frame = CGRectMake(0.0f,
+ 0.5f * selfTargetSize.height,
+ 0.0f,
0.0f );
} else {
- connectorsView_.frame = CGRectMake(0.5f * selfTargetSize.width,
+ connectorsView_.frame = CGRectMake(0.5f * selfTargetSize.width,
+ 0.0f,
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,
+
+ subview.frame = CGRectMake(0.0f,
+ 0.0f,
+ selfTargetSize.width,
selfTargetSize.height );
-
+
}
}
-
+
// Return our new size.
return selfTargetSize;
}
@@ -457,19 +457,19 @@ - (CGSize) layoutCollapsedGraph
#pragma mark - Drawing
-- (void) updateSubtreeBorder
+- (void) updateSubtreeBorder
{
CALayer *layer = [self layer];
if (layer) {
// Disable implicit animations during these layer property changes, to make them take effect immediately.
// BOOL actionsWereDisabled = [CATransaction disableActions];
// [CATransaction setDisableActions:YES];
-
- // If the enclosing TreeGraph has its "showsSubtreeFrames" debug feature enabled,
+
+ // If the enclosing TreeGraph has its "showsSubtreeFrames" debug feature enabled,
// configure the backing layer to draw its border programmatically. This is much more efficient
// than allocating a backing store for each SubtreeView's backing layer, only to stroke a simple
// rectangle into that backing store.
-
+
PSBaseTreeGraphView *treeGraph = [self enclosingTreeGraph];
if ([treeGraph showsSubtreeFrames]) {
[layer setBorderWidth:subtreeBorderWidth()];
@@ -477,7 +477,7 @@ - (void) updateSubtreeBorder
} else {
[layer setBorderWidth:0.0];
}
-
+
// [CATransaction setDisableActions:actionsWereDisabled];
}
}
@@ -485,11 +485,11 @@ - (void) updateSubtreeBorder
#pragma mark - Invalidation
-- (void) recursiveSetConnectorsViewsNeedDisplay
+- (void) recursiveSetConnectorsViewsNeedDisplay
{
// Mark this SubtreeView's connectorsView as needing display.
[connectorsView_ setNeedsDisplay];
-
+
// Recurse for descendant SubtreeViews.
NSArray *subviews = [self subviews];
for (UIView *subview in subviews) {
@@ -499,14 +499,14 @@ - (void) recursiveSetConnectorsViewsNeedDisplay
}
}
-- (void) resursiveSetSubtreeBordersNeedDisplay
+- (void) resursiveSetSubtreeBordersNeedDisplay
{
if ( [self layer] ) {
- // We only need this if layer-backed. When we have a backing layer, we use the
+ // We only need this if layer-backed. When we have a backing layer, we use the
// layer's "border" properties to draw the subtree debug border.
-
+
[self updateSubtreeBorder];
-
+
// Recurse for descendant SubtreeViews.
NSArray *subviews = [self subviews];
for (UIView *subview in subviews) {
@@ -522,7 +522,7 @@ - (void) resursiveSetSubtreeBordersNeedDisplay
#pragma mark - Selection State
-- (BOOL) nodeIsSelected
+- (BOOL) nodeIsSelected
{
return [[[self enclosingTreeGraph] selectedModelNodes] containsObject:[self modelNode]];
}
@@ -530,26 +530,26 @@ - (BOOL) nodeIsSelected
#pragma mark - Node Hit-Testing
-- (id <PSTreeGraphModelNode> ) modelNodeAtPoint:(CGPoint)p
-{
- // Check for intersection with our subviews, enumerating them in reverse order to get
+- (id <PSTreeGraphModelNode> ) modelNodeAtPoint:(CGPoint)p
+{
+ // Check for intersection with our subviews, enumerating them in reverse order to get
// front-to-back ordering. We could use UIView's -hitTest: method here, but we don't
// want to bother hit-testing deeper than the nodeView level.
-
+
NSArray *subviews = [self subviews];
NSInteger count = [subviews count];
NSInteger index;
-
+
for (index = count - 1; index >= 0; index--) {
UIView *subview = [subviews objectAtIndex:index];
-
+
// CGRect subviewBounds = [subview bounds];
CGPoint subviewPoint = [subview convertPoint:p fromView:self];
- //
+ //
// if (CGPointInRect(subviewPoint, subviewBounds)) {
-
- if ( [subview pointInside:subviewPoint withEvent:nil] ) {
-
+
+ if ( [subview pointInside:subviewPoint withEvent:nil] ) {
+
if (subview == [self nodeView]) {
return [self modelNode];
} else if ( [subview isKindOfClass:[PSBaseSubtreeView class]] ) {
@@ -559,21 +559,21 @@ - (BOOL) nodeIsSelected
}
}
}
-
+
// We didn't find a hit.
return nil;
}
-- (id <PSTreeGraphModelNode> ) modelNodeClosestToY:(CGFloat)y
-{
+- (id <PSTreeGraphModelNode> ) modelNodeClosestToY:(CGFloat)y
+{
// Do a simple linear search of our subviews, ignoring non-SubtreeViews. If performance was ever
// an issue for this code, we could take advantage of knowing the layout order of the nodes to do
// a sort of binary search.
-
+
NSArray *subviews = [self subviews];
PSBaseSubtreeView *subtreeViewWithClosestNodeView = nil;
CGFloat closestNodeViewDistance = MAXFLOAT;
-
+
for (UIView *subview in subviews) {
if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
UIView *childNodeView = [(PSBaseSubtreeView *)subview nodeView];
@@ -587,20 +587,20 @@ - (BOOL) nodeIsSelected
}
}
}
-
+
return [subtreeViewWithClosestNodeView modelNode];
}
-- (id <PSTreeGraphModelNode> ) modelNodeClosestToX:(CGFloat)x
-{
+- (id <PSTreeGraphModelNode> ) modelNodeClosestToX:(CGFloat)x
+{
// Do a simple linear search of our subviews, ignoring non-SubtreeViews. If performance was ever
// an issue for this code, we could take advantage of knowing the layout order of the nodes to do
// a sort of binary search.
-
+
NSArray *subviews = [self subviews];
PSBaseSubtreeView *subtreeViewWithClosestNodeView = nil;
CGFloat closestNodeViewDistance = MAXFLOAT;
-
+
for (UIView *subview in subviews) {
if ([subview isKindOfClass:[PSBaseSubtreeView class]]) {
UIView *childNodeView = [(PSBaseSubtreeView *)subview nodeView];
@@ -614,7 +614,7 @@ - (BOOL) nodeIsSelected
}
}
}
-
+
return [subtreeViewWithClosestNodeView modelNode];
}
@@ -628,12 +628,12 @@ - (NSString *) description
return [NSString stringWithFormat:@"SubtreeView<%@>", [modelNode_ description]];
}
-- (NSString *) nodeSummary
+- (NSString *) nodeSummary
{
return [NSString stringWithFormat:@"f=%@ %@", NSStringFromCGRect([nodeView_ frame]), [modelNode_ description]];
}
-- (NSString *) treeSummaryWithDepth:(NSInteger)depth
+- (NSString *) treeSummaryWithDepth:(NSInteger)depth
{
NSEnumerator *subviewsEnumerator = [[self subviews] objectEnumerator];
UIView *subview;
View
138 PSTreeGraphView/PSBaseTreeGraphView.h
@@ -18,7 +18,7 @@
// A TreeGraph's nodes may be connected by either "direct" or "orthogonal" lines.
-
+
typedef enum {
PSTreeGraphConnectingLineStyleDirect = 0,
PSTreeGraphConnectingLineStyleOrthogonal = 1,
@@ -43,52 +43,52 @@ typedef enum {
@interface PSBaseTreeGraphView : UIView <UIKeyInput>
{
-
+
@private
// Model
id <PSTreeGraphModelNode> modelRoot_;
-
+
// Delegate
id <PSTreeGraphDelegate> delegate_;
-
+
// Model Object -> SubtreeView Mapping
NSMutableDictionary *modelNodeToSubtreeViewMapTable_;
-
+
// Selection State
NSSet *selectedModelNodes_;
-
+
// Layout State
CGSize minimumFrameSize_;
-
+
// Animation Support
BOOL animatesLayout_;
BOOL layoutAnimationSuppressed_;
-
+
// Layout Metrics
CGFloat contentMargin_;
CGFloat parentChildSpacing_;
CGFloat siblingSpacing_;
-
+
// Layout Behavior
BOOL resizesToFillEnclosingScrollView_;
PSTreeGraphOrientationStyle treeGraphOrientation_;
-
+
// Styling
// UIColor *backgroundColor;
-
+
UIColor *connectingLineColor_;
CGFloat connectingLineWidth_;
PSTreeGraphConnectingLineStyle connectingLineStyle_;
-
+
// A debug feature that outlines the view hiarchy.
BOOL showsSubtreeFrames_;
-
+
// Node View Nib Specification
NSString *nodeViewNibName_;
-
+
// iOS 4 and above ONLY
UINib *cachedNodeViewNib_;
-
+
// Custom input view support
UIView *inputView_;
}
@@ -108,11 +108,11 @@ typedef enum {
#pragma mark - Creating Instances
-/// Initializes a new TreeGraph instance. (TreeGraph's designated initializer is the same as
-/// UIView's: -initWithFrame:.) The TreeGraph has default appearance properties and layout
-/// metrics, but to have a usable TreeGraph with actual content, you need to specify a
+/// Initializes a new TreeGraph instance. (TreeGraph's designated initializer is the same as
+/// UIView's: -initWithFrame:.) The TreeGraph has default appearance properties and layout
+/// metrics, but to have a usable TreeGraph with actual content, you need to specify a
/// nodeViewNibName and a modelRoot.
-
+
- (id) initWithFrame:(CGRect)frame;
@@ -122,29 +122,29 @@ typedef enum {
/// may have ancestor nodes, but TreeGraph will ignore them and treat modelRoot as the root.) May
/// be set to nil, in which case the TreeGraph displays no content. The modelRoot object, and all
/// of its desdendants as exposed through recursive application of the "-childModelNodes" accessor
-/// to traverse the model tree, must conform to the TreeGraphModelNode protocol declared in
+/// to traverse the model tree, must conform to the TreeGraphModelNode protocol declared in
/// TreeGraphModelNode.h
-
+
@property (nonatomic, retain) id <PSTreeGraphModelNode> modelRoot;
#pragma mark - Root SubtreeView Access
/// A TreeGraph builds the tree it displays using recursively nested SubtreeView instances. This
-/// read-only accessor provides a way to get the rootmost SubtreeView (the one that corresponds
+/// read-only accessor provides a way to get the rootmost SubtreeView (the one that corresponds
/// to the modelRoot model node).
-
+
@property (nonatomic, readonly) PSBaseSubtreeView *rootSubtreeView;
#pragma mark - Node View Nib Specification
/// The name of the .nib file from which to instantiate node views. (This API design assumes that
-/// all node views should be instantiated from the same .nib. If a tree of heterogeneous nodes
+/// all node views should be instantiated from the same .nib. If a tree of heterogeneous nodes
/// was desired, we could switch to a different mechanism for identifying the .nib to instantiate.)
/// Must specify a "View" .nib file, whose File's Owner is a SubtreeView, or the TreeGraph will be
/// unable to instantiate node views.
-
+
@property (nonatomic, copy) NSString *nodeViewNibName;
@@ -152,164 +152,164 @@ typedef enum {
/// The unordered set of model nodes that are currently selected in the TreeGraph. When no nodes
/// are selected, this is an empty NSSet. It will never be nil (and attempting to set it to nil
-/// will raise an exception). Every member of this set must be a descendant of the TreeGraph's
+/// will raise an exception). Every member of this set must be a descendant of the TreeGraph's
/// modelRoot (or modelRoot itself). If any member is not, TreeGraph will raise an exception.
-
+
@property (nonatomic, copy) NSSet *selectedModelNodes;
-/// Convenience accessor that returns the selected node, if exactly one node is currently
+/// Convenience accessor that returns the selected node, if exactly one node is currently
/// selected. Returns nil if zero, or more than one, nodes are currently selected.
-
+
@property (nonatomic, readonly) id <PSTreeGraphModelNode> singleSelectedModelNode;
/// Returns the bounding box of the selectedModelNodes. The bounding box takes only the selected
/// nodes into account, disregarding any descendants they might have.
-
+
@property (nonatomic, readonly) CGRect selectionBounds;
#pragma mark - Node Hit-Testing
-/// Returns the model node under the given point, which must be expressed in the TreeGraph's
-/// interior (bounds) coordinate space. If there is a collapsed subtree at the given point,
-/// returns the model node at the root of the collapsed subtree. If there is no model node
+/// Returns the model node under the given point, which must be expressed in the TreeGraph's
+/// interior (bounds) coordinate space. If there is a collapsed subtree at the given point,
+/// returns the model node at the root of the collapsed subtree. If there is no model node
/// at the given point, returns nil.
-
+
- (id <PSTreeGraphModelNode> ) modelNodeAtPoint:(CGPoint)p;
#pragma mark - Sizing and Layout
-/// A TreeGraph's minimumFrameSize is the size needed to accommodate its content (as currently
-/// laid out) and margins. Changes to the TreeGraph's content, layout, or margins will update
+/// A TreeGraph's minimumFrameSize is the size needed to accommodate its content (as currently
+/// laid out) and margins. Changes to the TreeGraph's content, layout, or margins will update
/// this. When a TreeGraph is the documentView of an UIScrollView, its actual frame may be larger
-/// than its minimumFrameSize, since we automatically expand the TreeGraph to always be at least
+/// than its minimumFrameSize, since we automatically expand the TreeGraph to always be at least
/// as large as the UIScrollView's clip area (contentView) to provide a nicer user experience.
-
+
@property (nonatomic, assign) CGSize minimumFrameSize;
-/// If YES, and if the TreeGraph is the documentView of an UIScrollView, the TreeGraph will
-/// automatically resize itself as needed to ensure that it always at least fills the content
-/// area of its enclosing UIScrollView. If NO, or if the TreeGraph is not the documentView of
+/// If YES, and if the TreeGraph is the documentView of an UIScrollView, the TreeGraph will
+/// automatically resize itself as needed to ensure that it always at least fills the content
+/// area of its enclosing UIScrollView. If NO, or if the TreeGraph is not the documentView of
/// an UIScrollView, the TreeGraph's size is determined only by its content and margins.
-
+
@property (nonatomic, assign) BOOL resizesToFillEnclosingScrollView;
-/// The style for tree graph orientation
+/// The style for tree graph orientation
//(See the TreeGraphOrientationStyle enumeration above.)
@property (nonatomic, assign) PSTreeGraphOrientationStyle treeGraphOrientation;
/// Returns YES if the tree needs relayout.
-
+
- (BOOL) needsGraphLayout;
/// Marks the tree as needing relayout.
-
+
- (void) setNeedsGraphLayout;
/// Performs graph layout, if the tree is marked as needing it. Returns the size computed for the
/// tree (not including contentMargin).
-
+
- (CGSize) layoutGraphIfNeeded;
/// Collapses the root node, if it is currently expanded.
-
+
- (void) collapseRoot;
/// Expands the root node, if it is currently collapsed.
-
+
- (void) expandRoot;
/// Toggles the expansion state of the TreeGraph's selectedModelNodes, expanding those that are
/// currently collapsed, and collapsing those that are currently expanded.
-
+
- (IBAction) toggleExpansionOfSelectedModelNodes:(id)sender;
-/// Returns the bounding box of the node views that represent the specified modelNodes. Model
+/// Returns the bounding box of the node views that represent the specified modelNodes. Model
/// nodes that aren't part of the displayed tree, or are part of a collapsed subtree, are ignored
/// and don't contribute to the returned bounding box. The bounding box takes only the specified
/// nodes into account, disregarding any descendants they might have.
-
+
- (CGRect) boundsOfModelNodes:(NSSet *)modelNodes;
#pragma mark - Scrolling
/// Does a [self scrollRectToVisible:] with the bounding box of the specified model nodes.
-
+
- (void) scrollModelNodesToVisible:(NSSet *)modelNodes animated:(BOOL)animated;
/// Does a [self scrollRectToVisible:] with the bounding box of the selected model nodes.
-
+
- (void) scrollSelectedModelNodesToVisibleAnimated:(BOOL)animated;
#pragma mark - Animation Support
-/// Whether the TreeGraph animates layout operations. Defaults to YES. If set to NO, layout
+/// Whether the TreeGraph animates layout operations. Defaults to YES. If set to NO, layout
/// jumpst instantaneously to the tree's new state.
-
+
@property (nonatomic, assign) BOOL animatesLayout;
/// Used to temporarily suppress layout animation during event tracking. Layout animation happens
/// only if animatesLayout is YES and this is NO.
-
+
@property (nonatomic, assign) BOOL layoutAnimationSuppressed;
#pragma mark - Layout Metrics
-/// The amount of padding to leave between the displayed tree and each of the four edges of the
+/// The amount of padding to leave between the displayed tree and each of the four edges of the
/// TreeGraph's bounds.
-
+
@property (nonatomic, assign) CGFloat contentMargin;
/// The horizonal spacing between each parent node and its child nodes.
-
+
@property (nonatomic, assign) CGFloat parentChildSpacing;
/// The vertical spacing betwen sibling nodes.
-
+
@property (nonatomic, assign) CGFloat siblingSpacing;
#pragma mark - Styling
// The fill color for the TreeGraph's content area.
-
+
// @property(copy) UIColor *backgroundColor;
/// The stroke color for node connecting lines.
-
+
@property (nonatomic, retain) UIColor *connectingLineColor;
/// The width for node connecting lines.
-
+
@property (nonatomic, assign) CGFloat connectingLineWidth;
/// The style for node connecting lines. (See the PSTreeGraphConnectingLineStyle enumeration above.)
-
+
@property (nonatomic, assign) PSTreeGraphConnectingLineStyle connectingLineStyle;
-/// Defaults to NO. If YES, a stroked outline is shown around each of the TreeGraph's
+/// Defaults to NO. If YES, a stroked outline is shown around each of the TreeGraph's
/// SubtreeViews. This can be helpful for visualizing the TreeGraph's structure and layout.
-
+
@property (nonatomic, assign) BOOL showsSubtreeFrames;
#pragma mark - Input and Navigation
-/// Custom input view for navigation.
+/// Custom input view for navigation.
///
/// By default, this control supports a hardware keyboard unless this property is assigned
/// to another input view.
///
/// More Info:
-///
+///
/// A placeholder view is created to so the default keyboard is not presented to the user.
/// When a hardware keyboard is attached, touching the TreeGraph makes it first responder
-/// and certain keyboard shortcuts become available for navigation. ie. the space bar
+/// and certain keyboard shortcuts become available for navigation. ie. the space bar
/// expands and collapses the current selection. The following keys; w, a, s, d, navigate
/// relative to the graph.
///