diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 20:46:37 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 20:46:37 +0000 |
commit | 1ae99501e0a15b85f0593a71c939063027c802d4 (patch) | |
tree | ae2c255da0ff4687c78b2a017dd1b660a8ed343c /chrome | |
parent | f8fc92385be0fb12cfffd14db9c6f3b461bec447 (diff) | |
download | chromium_src-1ae99501e0a15b85f0593a71c939063027c802d4.zip chromium_src-1ae99501e0a15b85f0593a71c939063027c802d4.tar.gz chromium_src-1ae99501e0a15b85f0593a71c939063027c802d4.tar.bz2 |
Implement a status throbber on the mac, currently using the Win artwork. Made the tab cell use a generic NSView for showing the icon instead of relying on the NSButtonCell to draw it, so a NSImageView is in place by default. Remove un-needed outlets, bindings, and views from the nib. BUG=11916. TEST=loading pages, opening and closing tabs.
Review URL: http://codereview.chromium.org/115527
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16410 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/app/nibs/en.lproj/TabView.xib | 147 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_cell.h | 7 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_cell.mm | 13 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_controller.h | 25 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_controller.mm | 17 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_strip_controller.mm | 42 | ||||
-rw-r--r-- | chrome/browser/cocoa/throbber_view.h | 37 | ||||
-rw-r--r-- | chrome/browser/cocoa/throbber_view.mm | 88 | ||||
-rw-r--r-- | chrome/browser/cocoa/throbber_view_unittest.mm | 44 | ||||
-rw-r--r-- | chrome/chrome.gyp | 5 |
10 files changed, 327 insertions, 98 deletions
diff --git a/chrome/app/nibs/en.lproj/TabView.xib b/chrome/app/nibs/en.lproj/TabView.xib index 3cd6798..9752f4b 100644 --- a/chrome/app/nibs/en.lproj/TabView.xib +++ b/chrome/app/nibs/en.lproj/TabView.xib @@ -2,10 +2,10 @@ <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03"> <data> <int key="IBDocument.SystemTarget">1050</int> - <string key="IBDocument.SystemVersion">9G55</string> + <string key="IBDocument.SystemVersion">9F33</string> <string key="IBDocument.InterfaceBuilderVersion">677</string> - <string key="IBDocument.AppKitVersion">949.43</string> - <string key="IBDocument.HIToolboxVersion">353.00</string> + <string key="IBDocument.AppKitVersion">949.34</string> + <string key="IBDocument.HIToolboxVersion">352.00</string> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> <integer value="1"/> @@ -58,10 +58,6 @@ <reference key="NSControlView" ref="279592484"/> <int key="NSButtonFlags">-2034482945</int> <int key="NSButtonFlags2">134</int> - <object class="NSCustomResource" key="NSNormalImage"> - <string key="NSClassName">NSImage</string> - <string key="NSResourceName">nav</string> - </object> <string key="NSAlternateContents"/> <string key="NSKeyEquivalent"/> <int key="NSPeriodicDelay">400</int> @@ -100,15 +96,37 @@ </object> <bool key="NSEditable">YES</bool> </object> - <object class="NSProgressIndicator" id="58797509"> + <object class="NSImageView" id="987403091"> <reference key="NSNextResponder" ref="1005"/> - <int key="NSvFlags">-2147482327</int> - <object class="NSPSMatrix" key="NSDrawMatrix"/> - <string key="NSFrame">{{131, 4}, {16, 16}}</string> + <int key="NSvFlags">268</int> + <object class="NSMutableSet" key="NSDragTypes"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMutableArray" key="set.sortedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>Apple PDF pasteboard type</string> + <string>Apple PICT pasteboard type</string> + <string>Apple PNG pasteboard type</string> + <string>NSFilenamesPboardType</string> + <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string> + <string>NeXT TIFF v4.0 pasteboard type</string> + </object> + </object> + <string key="NSFrame">{{18, 5}, {16, 16}}</string> <reference key="NSSuperview" ref="1005"/> - <int key="NSpiFlags">28938</int> - <double key="NSMinValue">1.600000e+01</double> - <double key="NSMaxValue">1.000000e+02</double> + <bool key="NSEnabled">YES</bool> + <object class="NSImageCell" key="NSCell" id="1061639670"> + <int key="NSCellFlags">537001472</int> + <int key="NSCellFlags2">33587200</int> + <object class="NSCustomResource" key="NSContents"> + <string key="NSClassName">NSImage</string> + <string key="NSResourceName">nav</string> + </object> + <int key="NSAlign">0</int> + <int key="NSScale">2</int> + <int key="NSStyle">0</int> + <bool key="NSAnimates">NO</bool> + </object> + <bool key="NSEditable">YES</bool> </object> <object class="NSButton" id="1054640993"> <reference key="NSNextResponder" ref="1005"/> @@ -160,14 +178,6 @@ <int key="connectionID">25</int> </object> <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">progressIndicator_</string> - <reference key="source" ref="1001"/> - <reference key="destination" ref="58797509"/> - </object> - <int key="connectionID">27</int> - </object> - <object class="IBConnectionRecord"> <object class="IBBindingConnection" key="connection"> <string key="label">title: title</string> <reference key="source" ref="707804163"/> @@ -185,58 +195,6 @@ </object> <object class="IBConnectionRecord"> <object class="IBBindingConnection" key="connection"> - <string key="label">animate: loading</string> - <reference key="source" ref="58797509"/> - <reference key="destination" ref="1001"/> - <object class="NSNibBindingConnector" key="connector"> - <reference key="NSSource" ref="58797509"/> - <reference key="NSDestination" ref="1001"/> - <string key="NSLabel">animate: loading</string> - <string key="NSBinding">animate</string> - <string key="NSKeyPath">loading</string> - <int key="NSNibBindingConnectorVersion">2</int> - </object> - </object> - <int key="connectionID">31</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBBindingConnection" key="connection"> - <string key="label">hidden: loading</string> - <reference key="source" ref="58797509"/> - <reference key="destination" ref="1001"/> - <object class="NSNibBindingConnector" key="connector"> - <reference key="NSSource" ref="58797509"/> - <reference key="NSDestination" ref="1001"/> - <string key="NSLabel">hidden: loading</string> - <string key="NSBinding">hidden</string> - <string key="NSKeyPath">loading</string> - <object class="NSDictionary" key="NSOptions"> - <string key="NS.key.0">NSValueTransformerName</string> - <string key="NS.object.0">NSNegateBoolean</string> - </object> - <int key="NSNibBindingConnectorVersion">2</int> - </object> - </object> - <int key="connectionID">43</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBBindingConnection" key="connection"> - <string key="label">image: image</string> - <reference key="source" ref="279592484"/> - <reference key="destination" ref="1001"/> - <object class="NSNibBindingConnector" key="connector" id="703997475"> - <reference key="NSSource" ref="279592484"/> - <reference key="NSDestination" ref="1001"/> - <string key="NSLabel">image: image</string> - <string key="NSBinding">image</string> - <string key="NSKeyPath">image</string> - <int key="NSNibBindingConnectorVersion">2</int> - </object> - </object> - <int key="connectionID">44</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBBindingConnection" key="connection"> <string key="label">title: title</string> <reference key="source" ref="279592484"/> <reference key="destination" ref="1001"/> @@ -246,7 +204,7 @@ <string key="NSLabel">title: title</string> <string key="NSBinding">title</string> <string key="NSKeyPath">title</string> - <reference key="NSPreviousConnector" ref="703997475"/> + <reference key="NSPreviousConnector"/> <int key="NSNibBindingConnectorVersion">2</int> </object> </object> @@ -284,6 +242,14 @@ </object> <int key="connectionID">54</int> </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">iconView_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="987403091"/> + </object> + <int key="connectionID">58</int> + </object> </object> <object class="IBMutableOrderedSet" key="objectRecords"> <object class="NSArray" key="orderedObjects"> @@ -320,9 +286,9 @@ <object class="NSMutableArray" key="children"> <bool key="EncodedWithXMLCoder">YES</bool> <reference ref="569334633"/> - <reference ref="58797509"/> <reference ref="279592484"/> <reference ref="1054640993"/> + <reference ref="987403091"/> </object> <reference key="parent" ref="1002"/> </object> @@ -341,11 +307,6 @@ <reference key="parent" ref="569334633"/> </object> <object class="IBObjectRecord"> - <int key="objectID">12</int> - <reference key="object" ref="58797509"/> - <reference key="parent" ref="1005"/> - </object> - <object class="IBObjectRecord"> <int key="objectID">17</int> <reference key="object" ref="279592484"/> <object class="NSMutableArray" key="children"> @@ -373,6 +334,20 @@ <reference key="object" ref="348599947"/> <reference key="parent" ref="1054640993"/> </object> + <object class="IBObjectRecord"> + <int key="objectID">55</int> + <reference key="object" ref="987403091"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="1061639670"/> + </object> + <reference key="parent" ref="1005"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">56</int> + <reference key="object" ref="1061639670"/> + <reference key="parent" ref="987403091"/> + </object> </object> </object> <object class="NSMutableDictionary" key="flattenedProperties"> @@ -387,13 +362,14 @@ <string>1.IBViewEditorWindowController.showingLayoutRectangles</string> <string>1.WindowOrigin</string> <string>1.editorWindowContentRectSynchronizationRect</string> - <string>12.IBPluginDependency</string> <string>17.IBEditorWindowLastContentRect</string> <string>17.IBPluginDependency</string> <string>18.CustomClassName</string> <string>18.IBPluginDependency</string> <string>50.IBPluginDependency</string> <string>51.IBPluginDependency</string> + <string>55.IBPluginDependency</string> + <string>56.IBPluginDependency</string> </object> <object class="NSMutableArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -405,13 +381,14 @@ <boolean value="NO"/> <string>{628, 654}</string> <string>{{217, 442}, {480, 272}}</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>{{77, 725}, {134, 29}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>TabCell</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> </object> </object> <object class="NSMutableDictionary" key="unlocalizedProperties"> @@ -434,7 +411,7 @@ </object> </object> <nil key="sourceID"/> - <int key="maxID">54</int> + <int key="maxID">58</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> @@ -466,12 +443,14 @@ <object class="NSMutableArray" key="dict.sortedKeys"> <bool key="EncodedWithXMLCoder">YES</bool> <string>backgroundButton_</string> + <string>iconView_</string> <string>progressIndicator_</string> <string>target_</string> </object> <object class="NSMutableArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> <string>NSButton</string> + <string>NSView</string> <string>NSProgressIndicator</string> <string>id</string> </object> diff --git a/chrome/browser/cocoa/tab_cell.h b/chrome/browser/cocoa/tab_cell.h index a3ad120..0f0ff0f 100644 --- a/chrome/browser/cocoa/tab_cell.h +++ b/chrome/browser/cocoa/tab_cell.h @@ -7,8 +7,11 @@ #import <Cocoa/Cocoa.h> -// A button cell that handles drawing/highlighting of tabs in the -// tab bar. +// A button cell that handles drawing/highlighting of tabs in the tab bar. Text +// drawing leaves room for an icon view on the left of the tab and a close +// button on the right. Technically, though, it doesn't know anything about what +// it's leaving space for, so they could be reversed or even replaced by views +// for other purposes. @interface TabCell : NSButtonCell { } diff --git a/chrome/browser/cocoa/tab_cell.mm b/chrome/browser/cocoa/tab_cell.mm index 205c7a5..a2adf27 100644 --- a/chrome/browser/cocoa/tab_cell.mm +++ b/chrome/browser/cocoa/tab_cell.mm @@ -145,11 +145,14 @@ namespace { [[NSGraphicsContext currentContext] restoreGraphicsState]; - // Inset where the text and favicon are drawn to keep them away from the - // sloping edges of the tab and the close box. - int kInteriorInset = cellFrame.size.height / 2.0; - NSRect frame = NSInsetRect(cellFrame, kInteriorInset, 0); - frame.size.width -= 16; // Inset for close box + // Inset where the text is drawn to keep it away from the sloping edges of the + // tab, the close box, and the icon view. These constants are derived + // empirically as the cell doesn't know about the surrounding view objects. + // TODO(pinkerton/alcor): Fix this somehow? + const int kIconXOffset = 28; + const int kCloseBoxXOffset = 16; + NSRect frame = NSOffsetRect(cellFrame, kIconXOffset, 0); + frame.size.width -= kCloseBoxXOffset + kIconXOffset; [self drawInteriorWithFrame:frame inView:controlView]; } diff --git a/chrome/browser/cocoa/tab_controller.h b/chrome/browser/cocoa/tab_controller.h index 45d93ab..d7783b7 100644 --- a/chrome/browser/cocoa/tab_controller.h +++ b/chrome/browser/cocoa/tab_controller.h @@ -14,21 +14,33 @@ // to be sent a message when the tab is selected by the user clicking. Setting // the |loading| property to YES visually indicates that this tab is currently // loading content via a spinner. +// +// The tab has the notion of an "icon view" which can be used to display +// identifying characteristics such as a favicon, or since it's a full-fledged +// view, something with state and animation such as a throbber for illustrating +// progress. The default in the nib is an image view so nothing special is +// required if that's all you need. @interface TabController : NSViewController { @private IBOutlet NSButton *backgroundButton_; - IBOutlet NSProgressIndicator *progressIndicator_; + IBOutlet NSView* iconView_; BOOL selected_; BOOL loading_; - NSImage *image_; + BOOL waiting_; id<TabControllerTarget> target_; // weak, where actions are sent SEL action_; // selector sent when tab is selected by clicking } -@property(retain, nonatomic) NSImage *image; -@property(assign, nonatomic) BOOL selected; +// The loading/waiting state of the tab. +// TODO(pinkerton): these really don't belong here, but something needs to +// know the state and another parallel array in TabStripController doesn't seem +// like the right place either. In a perfect world, this class shouldn't know +// anything about states that are specific to a browser. @property(assign, nonatomic) BOOL loading; +@property(assign, nonatomic) BOOL waiting; + +@property(assign, nonatomic) BOOL selected; @property(assign, nonatomic) id target; @property(assign, nonatomic) SEL action; @@ -43,6 +55,11 @@ // perform the close. - (IBAction)closeTab:(id)sender; +// Replace the current icon view with the given view. |iconView| will be +// resized to the size of the current icon view. +- (void)setIconView:(NSView*)iconView; +- (NSView*)iconView; + @end #endif // CHROME_BROWSER_COCOA_TAB_CONTROLLER_H_ diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm index 027f709..c5aae1a 100644 --- a/chrome/browser/cocoa/tab_controller.mm +++ b/chrome/browser/cocoa/tab_controller.mm @@ -8,8 +8,8 @@ @implementation TabController -@synthesize image = image_; @synthesize loading = loading_; +@synthesize waiting = waiting_; @synthesize target = target_; @synthesize action = action_; @@ -23,13 +23,11 @@ - (id)init { self = [super initWithNibName:@"TabView" bundle:mac_util::MainAppBundle()]; if (self != nil) { - [self setImage:[NSImage imageNamed:@"nav"]]; } return self; } - (void)dealloc { - [image_ release]; [super dealloc]; } @@ -44,6 +42,7 @@ // Called when the tab's nib is done loading and all outlets are hooked up. - (void)awakeFromNib { + [(id)iconView_ setImage:[NSImage imageNamed:@"nav"]]; [[self view] addSubview:backgroundButton_ positioned:NSWindowBelow relativeTo:nil]; @@ -66,4 +65,16 @@ return selected_; } +- (void)setIconView:(NSView*)iconView { + NSRect currentFrame = [iconView_ frame]; + [iconView_ removeFromSuperview]; + iconView_ = iconView; + [iconView_ setFrame:currentFrame]; + [[self view] addSubview:iconView_]; +} + +- (NSView*)iconView { + return iconView_; +} + @end diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm index bbc18f0..2bbdec8 100644 --- a/chrome/browser/cocoa/tab_strip_controller.mm +++ b/chrome/browser/cocoa/tab_strip_controller.mm @@ -16,6 +16,7 @@ #import "chrome/browser/cocoa/tab_controller.h" #import "chrome/browser/cocoa/tab_strip_model_observer_bridge.h" #import "chrome/browser/cocoa/tab_view.h" +#import "chrome/browser/cocoa/throbber_view.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/tabs/tab_strip_model.h" @@ -357,6 +358,18 @@ [self layoutTabs]; } +// A helper routine for creating an NSImageView to hold the fav icon for +// |contents|. +// TODO(pinkerton): fill in with code to use the real favicon, not the default +// for all cases. +- (NSImageView*)favIconImageViewForContents:(TabContents*)contents { + NSRect iconFrame = NSMakeRect(0, 0, 16, 16); + NSImageView* view = [[[NSImageView alloc] initWithFrame:iconFrame] + autorelease]; + [view setImage:[NSImage imageNamed:@"nav"]]; + return view; +} + // Called when a notification is received from the model that the given tab // has been updated. |loading| will be YES when we only want to update the // throbber state, not anything else about the (partially) loading tab. @@ -366,6 +379,35 @@ if (!loading) [self setTabTitle:[tabArray_ objectAtIndex:index] withContents:contents]; + // Update the current loading state, replacing the icon with a throbber, or + // vice versa. This will get called repeatedly with the same state during a + // load, so we need to make sure we're not creating the throbber view over and + // over. + if (contents) { + TabController* tabController = [tabArray_ objectAtIndex:index]; + NSString* imageName = nil; + if (contents->waiting_for_response() && ![tabController waiting]) { + imageName = @"throbber_waiting"; + [tabController setWaiting:YES]; + } else if (contents->is_loading() && ![tabController loading]) { + imageName = @"throbber"; + [tabController setLoading:YES]; + } + if (imageName) { + NSRect frame = NSMakeRect(0, 0, 16, 16); + NSImage* image = [NSImage imageNamed:imageName]; + ThrobberView* throbber = + [[[ThrobberView alloc] initWithFrame:frame image:image] autorelease]; + [tabController setIconView:throbber]; + } + else if (!contents->is_loading()) { + // Set everything back to normal, we're done loading. + [tabController setIconView:[self favIconImageViewForContents:contents]]; + [tabController setWaiting:NO]; + [tabController setLoading:NO]; + } + } + TabContentsController* updatedController = [tabContentsArray_ objectAtIndex:index]; [updatedController tabDidChange:contents]; diff --git a/chrome/browser/cocoa/throbber_view.h b/chrome/browser/cocoa/throbber_view.h new file mode 100644 index 0000000..5403371 --- /dev/null +++ b/chrome/browser/cocoa/throbber_view.h @@ -0,0 +1,37 @@ +// 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_THROBBER_VIEW_H_ +#define CHROME_BROWSER_COCOA_THROBBER_VIEW_H_ + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" + +@class TimerTarget; + +// A class that knows how to draw an animated state to indicate progress. +// Currently draws via a sequence of frames in an image, but may ultimately be +// written to render paths that are rotated around a center origin. Creating +// the class starts the animation, destroying it stops it. There is no state +// where the class is frozen on an image and not animating. + +@interface ThrobberView : NSView { + @private + scoped_nsobject<NSImage> image_; + scoped_nsobject<TimerTarget> target_; // Target of animation timer. + NSTimer* timer_; // Animation timer. Weak, owned by runloop. + unsigned int numFrames_; // Number of frames in this animation. + unsigned int animationFrame_; // Current frame of the animation, + // [0..numFrames_) +} + +// Creates the view with |frame| and the image strip desginated by |image|. The +// image needs to be made of squares such that the height divides evently into +// the width. Takes ownership of |image|. +- (id)initWithFrame:(NSRect)frame image:(NSImage*)image; + +@end + +#endif // CHROME_BROWSER_COCOA_THROBBER_VIEW_H_ diff --git a/chrome/browser/cocoa/throbber_view.mm b/chrome/browser/cocoa/throbber_view.mm new file mode 100644 index 0000000..948dcb4 --- /dev/null +++ b/chrome/browser/cocoa/throbber_view.mm @@ -0,0 +1,88 @@ +// 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 "chrome/browser/cocoa/throbber_view.h" + +#include "base/logging.h" + +const float kAnimationIntervalSeconds = 0.03; // 30ms, same as windows + +@interface ThrobberView(PrivateMethods) +- (void)animate; +@end + +// A very simple object that is the target for the animation timer so that +// the view isn't. We do this to avoid retain cycles as the timer +// retains its target. +@interface TimerTarget : NSObject { + @private + ThrobberView* throbber_; // Weak, owns us +} +- (id)initWithThrobber:(ThrobberView*)view; +@end + +@implementation TimerTarget +- (id)initWithThrobber:(ThrobberView*)view { + if ((self = [super init])) { + throbber_ = view; + } + return self; +} + +- (void)animate:(NSTimer*)timer { + [throbber_ animate]; +} +@end + +@implementation ThrobberView + +- (id)initWithFrame:(NSRect)frame image:(NSImage*)image { + if ((self = [super initWithFrame:frame])) { + // Ensure that the height divides evenly into the width. Cache the + // number of frames in the animation for later. + NSSize imageSize = [image size]; + DCHECK(imageSize.height && imageSize.width); + if (!imageSize.height) + return nil; + DCHECK((int)imageSize.width % (int)imageSize.height == 0); + numFrames_ = (int)imageSize.width / (int)imageSize.height; + DCHECK(numFrames_); + image_.reset([image retain]); + + // Start a timer for the animation frames. + target_.reset([[TimerTarget alloc] initWithThrobber:self]); + timer_ = + [NSTimer scheduledTimerWithTimeInterval:kAnimationIntervalSeconds + target:target_.get() + selector:@selector(animate:) + userInfo:nil + repeats:YES]; + } + return self; +} + +- (void)dealloc { + [timer_ invalidate]; + [super dealloc]; +} + +// Called when the TimerTarget gets tickled by our timer. Increment the frame +// counter and mark as needing display. +- (void)animate { + animationFrame_ = ++animationFrame_ % numFrames_; + [self setNeedsDisplay:YES]; +} + +// Overridden to draw the appropriate frame in the image strip. +- (void)drawRect:(NSRect)rect { + float imageDimension = [image_ size].height; + float xOffset = animationFrame_ * imageDimension; + NSRect sourceImageRect = + NSMakeRect(xOffset, 0, imageDimension, imageDimension); + [image_ compositeToPoint:NSMakePoint(0, 0) + fromRect:sourceImageRect + operation:NSCompositeSourceOver]; +} + +@end diff --git a/chrome/browser/cocoa/throbber_view_unittest.mm b/chrome/browser/cocoa/throbber_view_unittest.mm new file mode 100644 index 0000000..72d2240 --- /dev/null +++ b/chrome/browser/cocoa/throbber_view_unittest.mm @@ -0,0 +1,44 @@ +// 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/throbber_view.h" +#import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace { + +class ThrobberViewTest : public PlatformTest { + public: + ThrobberViewTest() { + NSRect frame = NSMakeRect(10, 10, 16, 16); + NSBundle* bundle = mac_util::MainAppBundle(); + NSImage* image = [[[NSImage alloc] initByReferencingFile: + [bundle pathForResource:@"throbber" ofType:@"png"]] + autorelease]; + view_.reset([[ThrobberView alloc] initWithFrame:frame image:image]); + [cocoa_helper_.contentView() addSubview:view_.get()]; + } + + scoped_nsobject<ThrobberView> view_; + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... +}; + +// Test adding/removing from the view hierarchy, mostly to ensure nothing +// leaks or crashes. +TEST_F(ThrobberViewTest, AddRemove) { + EXPECT_EQ(cocoa_helper_.contentView(), [view_ superview]); + [view_.get() removeFromSuperview]; + EXPECT_FALSE([view_ superview]); +} + +// Test drawing, mostly to ensure nothing leaks or crashes. +TEST_F(ThrobberViewTest, Display) { + [view_ display]; +} + +} // namespace diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 83d5766..6155d2f 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -671,6 +671,8 @@ 'browser/cocoa/tab_view.mm', 'browser/cocoa/tab_window_controller.h', 'browser/cocoa/tab_window_controller.mm', + 'browser/cocoa/throbber_view.h', + 'browser/cocoa/throbber_view.mm', 'browser/cocoa/toolbar_button_cell.h', 'browser/cocoa/toolbar_button_cell.mm', 'browser/cocoa/toolbar_controller.h', @@ -1933,6 +1935,8 @@ 'app/theme/star.pdf', 'app/theme/starred.pdf', 'app/theme/stop.pdf', + 'app/theme/throbber.png', + 'app/theme/throbber_waiting.png', 'app/app-Info.plist', ], # TODO(mark): Come up with a fancier way to do this. It should only @@ -2711,6 +2715,7 @@ 'browser/cocoa/tab_strip_controller_unittest.mm', 'browser/cocoa/tab_strip_view_unittest.mm', 'browser/cocoa/tab_view_unittest.mm', + 'browser/cocoa/throbber_view_unittest.mm', 'browser/cocoa/toolbar_button_cell_unittest.mm', 'browser/cocoa/toolbar_controller_unittest.mm', 'browser/cocoa/toolbar_view_unittest.mm', |