diff options
author | paul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-04 01:57:52 +0000 |
---|---|---|
committer | paul@chromium.org <paul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-04 01:57:52 +0000 |
commit | e23ed5427d0892d07480781f45b4367adebc0c00 (patch) | |
tree | 4319705f7c85f969170443045cc1c872a7dcbdd4 /chrome/browser/cocoa/download_started_animation_mac.mm | |
parent | ceba3fe8061aaefe743f22d641e11562e1c6e8d1 (diff) | |
download | chromium_src-e23ed5427d0892d07480781f45b4367adebc0c00.zip chromium_src-e23ed5427d0892d07480781f45b4367adebc0c00.tar.gz chromium_src-e23ed5427d0892d07480781f45b4367adebc0c00.tar.bz2 |
Implement the download arrow animation for Mac.
TEST=Download something and notice the nice download arrow animation.
BUG=14661 (http://crbug.com/14661)
Review URL: http://codereview.chromium.org/159623
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22355 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/download_started_animation_mac.mm')
-rw-r--r-- | chrome/browser/cocoa/download_started_animation_mac.mm | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/download_started_animation_mac.mm b/chrome/browser/cocoa/download_started_animation_mac.mm new file mode 100644 index 0000000..a4b5ab0 --- /dev/null +++ b/chrome/browser/cocoa/download_started_animation_mac.mm @@ -0,0 +1,200 @@ +// 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. +// +// This file contains the Mac implementation the download animation, displayed +// at the start of a download. The animation produces an arrow pointing +// downwards and animates towards the bottom of the window where the new +// download appears in the download shelf. + +#include "chrome/browser/download/download_started_animation.h" + +#import <QuartzCore/QuartzCore.h> + +#include "app/resource_bundle.h" +#include "base/scoped_cftyperef.h" +#include "base/scoped_nsobject.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view_mac.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/notification_service.h" +#include "third_party/skia/include/utils/mac/SkCGUtils.h" + +class DownloadAnimationTabObserver; + +// A class for managing the Core Animation download animation. +@interface DownloadStartedAnimationMac : NSObject { + // The download arrow image which we are responsible for freeing. + scoped_cftyperef<CGImageRef> image_; + + // The TabContents we will animate in (weak). + TabContents* tabContents_; + + // The cocoa view object for our TabContents (weak). + NSView* view_; + + // The observer for the TabContents we are drawing on. + scoped_ptr<DownloadAnimationTabObserver> observer_; + + // Our animation layer. + scoped_nsobject<CALayer> layer_; + + // Set once the animation is complete, either by interrupting (via window + // close) or through normal a end of the animation. + BOOL isComplete_; +}; + +// Called by our DownloadAnimationTabObserver if the tab is hidden or closed. +- (void)animationComplete; + +@end // interface DownloadStartedAnimationMac. + + +// A helper class to monitor tab hidden and closed notifications. If we receive +// such a notification, we stop the animation. +class DownloadAnimationTabObserver : public NotificationObserver { +public: + DownloadAnimationTabObserver(DownloadStartedAnimationMac* owner, + TabContents* tab_contents) + : owner_(owner), + tab_contents_(tab_contents) { + registrar_.Add(this, + NotificationType::TAB_CONTENTS_HIDDEN, + Source<TabContents>(tab_contents_)); + registrar_.Add(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab_contents_)); + } + + // Runs when a tab is hidden or destroyed. Let our owner know we should end + // the animation. + void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + registrar_.Remove(this, + NotificationType::TAB_CONTENTS_HIDDEN, + Source<TabContents>(tab_contents_)); + registrar_.Remove(this, + NotificationType::TAB_CONTENTS_DESTROYED, + Source<TabContents>(tab_contents_)); + [owner_ animationComplete]; + } + +private: + // The object we need to inform when we get a notification. Weak. + DownloadStartedAnimationMac* owner_; + + // The tab we are observing. Weak. + TabContents* tab_contents_; + + // Used for registering to receive notifications and automatic clean up. + NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(DownloadAnimationTabObserver); +}; + + +@implementation DownloadStartedAnimationMac + +// Load the image of the download arrow. +- (id)initWithTabContents:(TabContents*)tabContents { + if ((self = [super init])) { + SkBitmap* image_bitmap = + ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_DOWNLOAD_ANIMATION_BEGIN); + image_.reset(SkCreateCGImageRef(*image_bitmap)); + tabContents_ = tabContents; + view_ = tabContents_->GetContentNativeView(); + observer_.reset(new DownloadAnimationTabObserver(self, tabContents)); + isComplete_ = NO; + } + return self; +} + +// Common clean up code. +- (void)animationComplete { + if (isComplete_) + return; + isComplete_ = YES; + [view_ setWantsLayer:NO]; + [layer_ removeAllAnimations]; + [layer_ removeFromSuperlayer]; +} + +// Set up the animation and let Core Animation do all the hard work. +- (void)animate { + // Figure out the positioning in the current tab. We try to position ourselves + // against the left edge, and three times the download image's height from the + // bottom of the tab, assuming there is enough room. If there isn't enough, we + // won't show the animation and let the shelf speak for itself. + gfx::Rect bounds; + tabContents_->GetContainerBounds(&bounds); + int imageWidth = CGImageGetWidth(image_); + int imageHeight = CGImageGetHeight(image_); + CGRect imageBounds = CGRectMake(0, 0, imageWidth, imageHeight); + + // Sanity check the size in case there's no room to display the animation. + if (bounds.height() < imageHeight) { + [self release]; + return; + } + + int animationHeight = std::min(bounds.height(), 3 * imageHeight); + NSPoint start = NSMakePoint(0, animationHeight); + NSPoint stop = NSMakePoint(0, 0); // Bottom of the tab. + + // Set for the duration of the animation, or we won't see our layer. We reset + // this in the completion callback. + [view_ setWantsLayer:YES]; + + // CALayer initalization. + layer_.reset([[CALayer layer] retain]); + [layer_ setNeedsDisplay]; + [layer_ setContents:(id)image_.get()]; + [layer_ setAnchorPoint:CGPointMake(0, 0)]; + [layer_ setFrame:imageBounds]; + [[view_ layer] addSublayer:layer_]; + + // Positional animation. + CABasicAnimation *animation = + [CABasicAnimation animationWithKeyPath:@"position"]; + [animation setFromValue:[NSValue valueWithPoint:start]]; + [animation setToValue:[NSValue valueWithPoint:stop]]; + [animation setDuration:0.6]; + CAMediaTimingFunction* mediaFunction = + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + [animation setTimingFunction:mediaFunction]; + [animation setDelegate:self]; + [layer_ addAnimation:animation forKey:@"downloadPosition"]; + + // Opacity animation. + animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + [animation setFromValue:[NSNumber numberWithFloat:1.0]]; + [animation setToValue:[NSNumber numberWithFloat:0.0]]; + [animation setDuration:1.5]; // Slightly longer, so it doesn't fade too much. + mediaFunction = + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + [animation setTimingFunction:mediaFunction]; + [layer_ addAnimation:animation forKey:@"downloadOpacity"]; +} + +// CAAnimation delegate method called when the animation is complete. +- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag { + [self animationComplete]; + [self release]; +} + +@end // implementation DownloadStartedAnimationMac + + +// static +void DownloadStartedAnimation::Show(TabContents* tab_contents) { + DCHECK(tab_contents); + + // Will be deleted when the animation is complete. + DownloadStartedAnimationMac* downloadArrow = + [[DownloadStartedAnimationMac alloc] initWithTabContents:tab_contents]; + + // Go! + [downloadArrow animate]; +} |