summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorrohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-03 20:05:02 +0000
committerrohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-03 20:05:02 +0000
commit06c87330d661e508402b6db25bf93ebb0fc25277 (patch)
treeea2770fc6794254117ba8bcbb3caaa4dd99f4a66 /chrome/browser/cocoa
parentd338629d11ebad49ce3dc1d4715a1c12ffe5d9f9 (diff)
downloadchromium_src-06c87330d661e508402b6db25bf93ebb0fc25277.zip
chromium_src-06c87330d661e508402b6db25bf93ebb0fc25277.tar.gz
chromium_src-06c87330d661e508402b6db25bf93ebb0fc25277.tar.bz2
[Mac] Adds a new view that will allow us to animate the height property of views. This class will be the base class for any view that needs to be animated.
BUG=None TEST=No visible impact. New unittests should pass. Review URL: http://codereview.chromium.org/350002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30852 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/animatable_view.h56
-rw-r--r--chrome/browser/cocoa/animatable_view.mm100
-rw-r--r--chrome/browser/cocoa/animatable_view_unittest.mm48
3 files changed, 204 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/animatable_view.h b/chrome/browser/cocoa/animatable_view.h
new file mode 100644
index 0000000..cf55781
--- /dev/null
+++ b/chrome/browser/cocoa/animatable_view.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
+#define CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/view_resizer.h"
+
+// A view that provides an animatable height property. Provides methods to
+// animate to a new height, set a new height immediately, or cancel any running
+// animations.
+//
+// AnimatableView sends an |animationDidEnd:| message to its delegate when the
+// animation ends normally and an |animationDidStop:| message when the animation
+// was canceled (even when canceled as a result of a new animation starting).
+
+@interface AnimatableView : NSView {
+ @protected
+ IBOutlet id delegate_; // weak, used to send animation ended messages.
+
+ @private
+ scoped_nsobject<NSAnimation> currentAnimation_;
+ id<ViewResizer> resizeDelegate_; // weak, usually owns us
+}
+
+// Properties for bindings.
+@property(assign) id delegate;
+
+// Gets the current height of the view. If an animation is currently running,
+// this will give the current height at the time of the call, not the target
+// height at the end of the animation.
+- (CGFloat)height;
+
+// Sets the height of the view immediately. Cancels any running animations.
+- (void)setHeight:(CGFloat)newHeight;
+
+// Starts a new animation to the given |newHeight| for the given |duration|.
+// Cancels any running animations.
+- (void)animateToNewHeight:(CGFloat)newHeight
+ duration:(NSTimeInterval)duration;
+
+// Cancels any running animations, leaving the view at its current
+// (mid-animation) height.
+- (void)stopAnimation;
+
+// Sets the delegate that gets notified when this view needs to chanage its
+// height.
+- (void)setResizeDelegate:(id<ViewResizer>)resizeDelegate;
+
+@end
+
+#endif // CHROME_BROWSER_COCOA_ANIMATABLE_VIEW_H_
diff --git a/chrome/browser/cocoa/animatable_view.mm b/chrome/browser/cocoa/animatable_view.mm
new file mode 100644
index 0000000..06d039b
--- /dev/null
+++ b/chrome/browser/cocoa/animatable_view.mm
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+#import <QuartzCore/QuartzCore.h>
+
+#import "chrome/browser/cocoa/animatable_view.h"
+
+// NSAnimation subclass that animates the height of an AnimatableView. Allows
+// the caller to start and cancel the animation as desired.
+@interface NSHeightAnimation : NSAnimation {
+ @private
+ AnimatableView* view_; // weak, owns us.
+ CGFloat startHeight_;
+ CGFloat endHeight_;
+}
+
+// Initialize a new height animation for the given view. The animation will not
+// start until startAnimation: is called.
+- (id)initWithView:(AnimatableView*)view
+ finalHeight:(CGFloat)height
+ duration:(NSTimeInterval)duration;
+@end
+
+@implementation NSHeightAnimation
+- (id)initWithView:(AnimatableView*)view
+ finalHeight:(CGFloat)height
+ duration:(NSTimeInterval)duration {
+ if ((self = [super initWithDuration:duration
+ animationCurve:NSAnimationEaseIn])) {
+ view_ = view;
+ startHeight_ = [view_ height];
+ endHeight_ = height;
+ [self setAnimationBlockingMode:NSAnimationNonblocking];
+ [self setDelegate:view_];
+ }
+ return self;
+}
+
+// Overridden to call setHeight for each progress tick.
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ [super setCurrentProgress:progress];
+ [view_ setHeight:((progress * (endHeight_ - startHeight_)) + startHeight_)];
+}
+@end
+
+
+@implementation AnimatableView
+@synthesize delegate = delegate_;
+
+- (void)dealloc {
+ // Stop the animation if it is running, since it holds a pointer to this view.
+ [self stopAnimation];
+ [super dealloc];
+}
+
+- (CGFloat)height {
+ return [self frame].size.height;
+}
+
+- (void)setHeight:(CGFloat)newHeight {
+ // Force the height to be an integer because some animations look terrible
+ // with non-integer intermediate heights. We only ever set integer heights
+ // for our views, so this shouldn't be a limitation in practice.
+ int height = floor(newHeight);
+ [resizeDelegate_ resizeView:self newHeight:height];
+}
+
+- (void)animateToNewHeight:(CGFloat)newHeight
+ duration:(NSTimeInterval)duration {
+ [currentAnimation_ stopAnimation];
+
+ currentAnimation_.reset([[NSHeightAnimation alloc] initWithView:self
+ finalHeight:newHeight
+ duration:duration]);
+ [currentAnimation_ startAnimation];
+}
+
+- (void)stopAnimation {
+ [currentAnimation_ stopAnimation];
+}
+
+- (void)setResizeDelegate:(id<ViewResizer>)resizeDelegate {
+ resizeDelegate_ = resizeDelegate;
+}
+
+- (void)animationDidStop:(NSAnimation*)animation {
+ if ([delegate_ respondsToSelector:@selector(animationDidStop:)])
+ [delegate_ animationDidStop:animation];
+ currentAnimation_.reset(nil);
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+ if ([delegate_ respondsToSelector:@selector(animationDidEnd:)])
+ [delegate_ animationDidEnd:animation];
+ currentAnimation_.reset(nil);
+}
+
+@end
diff --git a/chrome/browser/cocoa/animatable_view_unittest.mm b/chrome/browser/cocoa/animatable_view_unittest.mm
new file mode 100644
index 0000000..35a7e8f
--- /dev/null
+++ b/chrome/browser/cocoa/animatable_view_unittest.mm
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/animatable_view.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/cocoa/view_resizer_pong.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class AnimatableViewTest : public CocoaTest {
+ public:
+ AnimatableViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 100);
+ view_.reset([[AnimatableView alloc] initWithFrame:frame]);
+ [[test_window() contentView] addSubview:view_.get()];
+
+ resizeDelegate_.reset([[ViewResizerPong alloc] init]);
+ [view_ setResizeDelegate:resizeDelegate_.get()];
+ }
+
+ scoped_nsobject<ViewResizerPong> resizeDelegate_;
+ scoped_nsobject<AnimatableView> view_;
+};
+
+// Basic view tests (AddRemove, Display).
+TEST_VIEW(AnimatableViewTest, view_);
+
+TEST_F(AnimatableViewTest, GetAndSetHeight) {
+ // Make sure the view's height starts out at 100.
+ NSRect initialFrame = [view_ frame];
+ ASSERT_EQ(100, initialFrame.size.height);
+ EXPECT_EQ(initialFrame.size.height, [view_ height]);
+
+ // Set it directly to 50 and make sure it takes effect.
+ [resizeDelegate_ setHeight:-1];
+ [view_ setHeight:50];
+ EXPECT_EQ(50, [resizeDelegate_ height]);
+}
+
+// TODO(rohitrao): Find a way to unittest the animations and delegate messages.
+
+} // namespace