1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import <Cocoa/Cocoa.h>
6 #import <QuartzCore/QuartzCore.h>
8 #import "chrome/browser/ui/cocoa/animatable_view.h"
9 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
11 // NSAnimation subclass that animates the height of an AnimatableView. Allows
12 // the caller to start and cancel the animation as desired.
13 @interface HeightAnimation : NSAnimation {
15 AnimatableView* view_; // weak, owns us.
20 // Initialize a new height animation for the given view. The animation will not
21 // start until startAnimation: is called.
22 - (id)initWithView:(AnimatableView*)view
23 finalHeight:(CGFloat)height
24 duration:(NSTimeInterval)duration;
27 @implementation HeightAnimation
28 - (id)initWithView:(AnimatableView*)view
29 finalHeight:(CGFloat)height
30 duration:(NSTimeInterval)duration {
31 if ((self = [super gtm_initWithDuration:duration
32 eventMask:NSLeftMouseUpMask
33 animationCurve:NSAnimationEaseIn])) {
35 startHeight_ = [view_ height];
37 [self setAnimationBlockingMode:NSAnimationNonblocking];
38 [self setDelegate:view_];
43 // Overridden to call setHeight for each progress tick.
44 - (void)setCurrentProgress:(NSAnimationProgress)progress {
45 [super setCurrentProgress:progress];
46 [view_ setHeight:((progress * (endHeight_ - startHeight_)) + startHeight_)];
51 @implementation AnimatableView
52 @synthesize delegate = delegate_;
53 @synthesize resizeDelegate = resizeDelegate_;
56 // Stop the animation if it is running, since it holds a pointer to this view.
62 return [self frame].size.height;
65 - (void)setHeight:(CGFloat)newHeight {
66 // Force the height to be an integer because some animations look terrible
67 // with non-integer intermediate heights. We only ever set integer heights
68 // for our views, so this shouldn't be a limitation in practice.
69 int height = floor(newHeight);
70 [resizeDelegate_ resizeView:self newHeight:height];
73 - (void)animateToNewHeight:(CGFloat)newHeight
74 duration:(NSTimeInterval)duration {
75 [currentAnimation_ stopAnimation];
77 currentAnimation_.reset([[HeightAnimation alloc] initWithView:self
80 if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
81 [resizeDelegate_ setAnimationInProgress:YES];
82 [currentAnimation_ startAnimation];
85 - (void)stopAnimation {
86 [currentAnimation_ stopAnimation];
89 - (NSAnimationProgress)currentAnimationProgress {
90 return [currentAnimation_ currentProgress];
93 - (void)animationDidStop:(NSAnimation*)animation {
94 if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
95 [resizeDelegate_ setAnimationInProgress:NO];
96 if ([delegate_ respondsToSelector:@selector(animationDidStop:)])
97 [delegate_ animationDidStop:animation];
98 currentAnimation_.reset(nil);
101 - (void)animationDidEnd:(NSAnimation*)animation {
102 if ([resizeDelegate_ respondsToSelector:@selector(setAnimationInProgress:)])
103 [resizeDelegate_ setAnimationInProgress:NO];
104 if ([delegate_ respondsToSelector:@selector(animationDidEnd:)])
105 [delegate_ animationDidEnd:animation];
106 currentAnimation_.reset(nil);