gabriel / gh-kit

Utilities and categories for Objective-C

gh-kit / Classes / GHViewAnimation.m
2d29c36d » gabriel 2008-08-07 importing 1 //
2 // GHViewAnimation.m
13e87165 » gabriel 2008-08-12 where did this originally c... 3 //
2d29c36d » gabriel 2008-08-07 importing 4 // From ViewAnimationTest project. (TODO: Find source)
13e87165 » gabriel 2008-08-12 where did this originally c... 5 // Not sure where this is from originally, and I refactored it a bunch.
6 // If anyone recognizes this code, let me know.
2d29c36d » gabriel 2008-08-07 importing 7 //
8
9 #import "GHViewAnimation.h"
10
11
12 @implementation GHViewAnimation
13
14 - (id)initWithContainer:(NSView *)container view:(NSView *)view1 view:(NSView *)view2 {
15 self = [super init];
16 if (self) {
17 container_ = container;
18
19 view1_ = [self wrapView:view1 container:container_ hide:NO];
20 view2_ = [self wrapView:view2 container:container_ hide:YES];
21
22 toView_ = view2_;
23 fromView_ = view1_;
24
25 }
26 return self;
27 }
28
29 - (NSView *)wrapView:(NSView *)view container:(NSView *)container hide:(BOOL)hide {
30 NSRect rect = [container bounds];
31 NSView *tempView = [[NSView alloc] initWithFrame:rect];
32 [tempView addSubview:view];
33 [tempView setAutoresizingMask:[container autoresizingMask]];
34 [container addSubview:tempView];
35 rect = [tempView bounds];
36 [tempView setHidden:hide];
37 [view setFrame:rect];
698fda67 » gabriel 2009-09-18 Fixing leak 38 return [tempView autorelease];
2d29c36d » gabriel 2008-08-07 importing 39 }
40
41 - (void)prepareSubviewOfView:(NSView *)view {
42 NSView *subview = [[view subviews] objectAtIndex:0];
43 [subview setFrameOrigin:NSZeroPoint];
44 // Reset the mask and let each animation turn on whatever resizing options it needs
45 [subview setAutoresizingMask:NSViewNotSizable];
46 }
47
48 - (void)resetSubviewOfView:(NSView *)view {
49 NSView *subview = [[view subviews] objectAtIndex:0];
50 [subview setFrameOrigin:NSZeroPoint];
51 // Allow the views to resize properly now that the animation is done.
52 [subview setAutoresizingMask:[container_ autoresizingMask]];
53 }
54
55 - (NSViewAnimation *)dissolve {
56 [toView_ setFrame:[container_ bounds]];
57 // Note: view does not need to be unhidden manually as in the other cases. This is because the fade in
58 // effect will do it for you.
59
60 NSViewAnimation *animation = [[[NSViewAnimation alloc] initWithViewAnimations:
61 [NSArray arrayWithObjects:
62 // Old view is set to fade out
63 [NSDictionary dictionaryWithObjectsAndKeys:fromView_, NSViewAnimationTargetKey, NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey, nil],
64 // New view is set to fade in
65 [NSDictionary dictionaryWithObjectsAndKeys:toView_, NSViewAnimationTargetKey, NSViewAnimationFadeInEffect, NSViewAnimationEffectKey, nil],
66 nil]
67 ] autorelease];
68 return animation;
69 }
70
71 - (NSViewAnimation *)moveIn {
72 NSRect rect = [container_ bounds];
73 // Set the old view to be resizable on the right side. It will appear as if it's sitting still
74 [[[fromView_ subviews] objectAtIndex:0] setAutoresizingMask:NSViewMaxXMargin];
75
76 // Set the new view to be out of bounds on the right side, ready to be animated in
77 [toView_ setFrame:NSMakeRect(NSMaxX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect))];
78 // If a previous animation resulted in a zero frame, it set it to hidden. We have to unhide it manually.
79 [toView_ setHidden:NO];
80
81 NSViewAnimation *animation = [[[NSViewAnimation alloc] initWithViewAnimations:
82 [NSArray arrayWithObjects:
83 // The left "viewport" shrinks to zero-width on the left side
84 [NSDictionary dictionaryWithObjectsAndKeys:fromView_, NSViewAnimationTargetKey, [NSValue valueWithRect:NSMakeRect(NSMinX(rect), NSMinY(rect), 0.0, NSHeight(rect))], NSViewAnimationEndFrameKey, nil],
85 // New view frame is just the viewable area. Since it is currently out of bounds, it will appear to slide
86 // in bounds.
87 [NSDictionary dictionaryWithObjectsAndKeys:toView_, NSViewAnimationTargetKey, [NSValue valueWithRect:rect], NSViewAnimationEndFrameKey, nil],
88 nil]
89 ] autorelease];
90 return animation;
91 }
92
93 - (NSViewAnimation *)push {
94 NSRect rect = [container_ bounds];
95 // Set old view to be resizable on the left side. It will appear to move to the left since the right margin is
96 // fixed.
97 [[[fromView_ subviews] objectAtIndex:0] setAutoresizingMask:NSViewMinXMargin];
98
99 // Set the new view to be out of bounds on the right side, ready to be animated in
100 [toView_ setFrame:NSMakeRect(NSMaxX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect))];
101 // If a previous animation resulted in a zero frame, it set it to hidden. We have to unhide it manually.
102 [toView_ setHidden:NO];
103
104 NSViewAnimation *animation = [[[NSViewAnimation alloc] initWithViewAnimations:
105 [NSArray arrayWithObjects:
106 // Old view frame gets moved to the left, out of bounds.
107 [NSDictionary dictionaryWithObjectsAndKeys:fromView_, NSViewAnimationTargetKey, [NSValue valueWithRect:NSMakeRect(NSMinX(rect) - NSWidth(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect))], NSViewAnimationEndFrameKey, nil],
108 // New view frame is just the viewable area. Since it is currently out of bounds, it will appear to slide
109 // in bounds. Note, this is the same as in the "Move In" case.
110 [NSDictionary dictionaryWithObjectsAndKeys:toView_, NSViewAnimationTargetKey, [NSValue valueWithRect:rect], NSViewAnimationEndFrameKey, nil],
111 nil]
112 ] autorelease];
113 return animation;
114 }
115
116 - (NSViewAnimation *)reveal {
117 NSRect rect = [container_ bounds];
118 // Set old view to be resizable on the left side. It will appear to move to the left since the right margin is
119 // fixed.
120 [[[fromView_ subviews] objectAtIndex:0] setAutoresizingMask:NSViewMinXMargin];
121
122 // Set new view to be resizable on the right side. It will appear to sit still.
123 [[[toView_ subviews] objectAtIndex:0] setAutoresizingMask:NSViewMinXMargin];
124
125 // Make the right viewport zero-width view on the right side. It will reveal the view as it expands to the left.
126 [toView_ setFrame:NSMakeRect(NSMaxX(rect), NSMinY(rect), 0.0, NSHeight(rect))];
127 [toView_ setHidden:NO];
128
129 // Make the subview such that it's right edge is flush with its superview/viewport.
130 [[[toView_ subviews] objectAtIndex:0] setFrame:NSMakeRect(NSMinX(rect) - NSWidth(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect))];
131
132 NSViewAnimation *animation = [[[NSViewAnimation alloc] initWithViewAnimations:
133 [NSArray arrayWithObjects:
134 // The left "viewport" shrinks to zero-width
135 [NSDictionary dictionaryWithObjectsAndKeys:fromView_, NSViewAnimationTargetKey, [NSValue valueWithRect:NSMakeRect(NSMinX(rect), NSMinY(rect), 0.0, NSHeight(rect))], NSViewAnimationEndFrameKey, nil],
136 // The right view port expands to encompass the full bounds.
137 [NSDictionary dictionaryWithObjectsAndKeys:toView_, NSViewAnimationTargetKey, [NSValue valueWithRect:rect], NSViewAnimationEndFrameKey, nil],
138 nil]
139 ] autorelease];
140 return animation;
141 }
142
143 - (NSViewAnimation *)wipe {
144 NSRect rect = [container_ bounds];
145 // Set the old view to be resizable on the right side. It will appear as if it's sitting still
146 [[[fromView_ subviews] objectAtIndex:0] setAutoresizingMask:NSViewMaxXMargin];
147
148 // Set new view to be resizable on the right side. It will appear to sit still.
149 [[[toView_ subviews] objectAtIndex:0] setAutoresizingMask:NSViewMinXMargin];
150
151 // Make the right viewport zero-wdith
152 [toView_ setFrame:NSMakeRect(NSMaxX(rect), NSMinY(rect), 0.0, NSHeight(rect))];
153 [toView_ setHidden:NO];
154
155 // Make the subview such that it's right edge is flush with its superview/viewport.
156 [[[toView_ subviews] objectAtIndex:0] setFrame:NSMakeRect(NSMinX(rect) - NSWidth(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect))];
157
158 NSViewAnimation *animation = [[[NSViewAnimation alloc] initWithViewAnimations:
159 [NSArray arrayWithObjects:
160 // The left "viewport" shrinks to zero-width
161 [NSDictionary dictionaryWithObjectsAndKeys:fromView_, NSViewAnimationTargetKey, [NSValue valueWithRect:NSMakeRect(NSMinX(rect), NSMinY(rect), 0.0, NSHeight(rect))], NSViewAnimationEndFrameKey, nil],
162 // The right view port expands to encompass the full bounds.
163 [NSDictionary dictionaryWithObjectsAndKeys:toView_, NSViewAnimationTargetKey, [NSValue valueWithRect:rect], NSViewAnimationEndFrameKey, nil],
164 nil]
165 ] autorelease];
166 return animation;
167 }
168
169
170 - (void)animate:(GHViewAnimationType)animationType {
171
172 if ([view1_ isHidden]) {
173 toView_ = view1_;
174 fromView_ = view2_;
175 } else {
176 toView_ = view2_;
177 fromView_ = view1_;
178 }
179
180 // Unset the first responder. Can cause drawing artifacts since the blue glow extends beyond the view's bounds.
181 //[[container_ window] makeFirstResponder:nil];
182
183 // Turn off all autoresizing for now. Will be twiddling these for different effects.
184 [self prepareSubviewOfView:toView_];
185 [self prepareSubviewOfView:fromView_];
186
187 NSViewAnimation *animation = nil;
188 switch (animationType) {
189 case GHViewAnimationDissolve: animation = [self dissolve]; break;
190 case GHViewAnimationMoveIn: animation = [self moveIn]; break;
191 case GHViewAnimationPush: animation = [self push]; break;
192 case GHViewAnimationReveal: animation = [self reveal]; break;
193 case GHViewAnimationWipe: animation = [self wipe]; break;
194 default:
195 NSAssert(false, @"Invalid animation type");
196 }
197
198
199 [animation setAnimationBlockingMode:NSAnimationBlocking];
200 [animation startAnimation];
201
202 // Not all the animations above result in the old view being hidden so do it here
203 [fromView_ setHidden:YES];
204
205 [self resetSubviewOfView:fromView_];
206 [self resetSubviewOfView:toView_];
207 }
208
209 @end