diff options
-rw-r--r-- | chrome/browser/cocoa/animatable_view.h | 8 | ||||
-rw-r--r-- | chrome/browser/cocoa/animatable_view.mm | 5 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.h | 44 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.mm | 327 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller_unittest.mm | 93 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_state.h | 61 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_toolbar_view.h | 7 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_toolbar_view.mm | 68 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm | 56 | ||||
-rw-r--r-- | chrome/browser/cocoa/browser_window_controller.mm | 44 | ||||
-rw-r--r-- | chrome/browser/cocoa/browser_window_controller_unittest.mm | 1 | ||||
-rw-r--r-- | chrome/browser/cocoa/toolbar_controller.h | 7 | ||||
-rw-r--r-- | chrome/browser/cocoa/toolbar_controller.mm | 13 | ||||
-rw-r--r-- | chrome/browser/cocoa/toolbar_view.h | 9 | ||||
-rw-r--r-- | chrome/browser/cocoa/toolbar_view.mm | 9 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 5 |
16 files changed, 521 insertions, 236 deletions
diff --git a/chrome/browser/cocoa/animatable_view.h b/chrome/browser/cocoa/animatable_view.h index aa8f01d..9221095 100644 --- a/chrome/browser/cocoa/animatable_view.h +++ b/chrome/browser/cocoa/animatable_view.h @@ -30,7 +30,8 @@ } // Properties for bindings. -@property(assign) id delegate; +@property(assign, nonatomic) id delegate; +@property(assign, nonatomic) id<ViewResizer> resizeDelegate; // 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 @@ -49,9 +50,8 @@ // (mid-animation) height. - (void)stopAnimation; -// Sets the delegate that gets notified when this view needs to chanage its -// height. -- (void)setResizeDelegate:(id<ViewResizer>)resizeDelegate; +// Gets the progress of any current animation. +- (NSAnimationProgress)currentAnimationProgress; @end diff --git a/chrome/browser/cocoa/animatable_view.mm b/chrome/browser/cocoa/animatable_view.mm index 2f716f8..bf5da1d 100644 --- a/chrome/browser/cocoa/animatable_view.mm +++ b/chrome/browser/cocoa/animatable_view.mm @@ -49,6 +49,7 @@ @implementation AnimatableView @synthesize delegate = delegate_; +@synthesize resizeDelegate = resizeDelegate_; - (void)dealloc { // Stop the animation if it is running, since it holds a pointer to this view. @@ -84,8 +85,8 @@ [currentAnimation_ stopAnimation]; } -- (void)setResizeDelegate:(id<ViewResizer>)resizeDelegate { - resizeDelegate_ = resizeDelegate; +- (NSAnimationProgress)currentAnimationProgress { + return [currentAnimation_ currentProgress]; } - (void)animationDidStop:(NSAnimation*)animation { diff --git a/chrome/browser/cocoa/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h index 456f2bc..aadec09 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.h +++ b/chrome/browser/cocoa/bookmark_bar_controller.h @@ -11,6 +11,7 @@ #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" #include "chrome/browser/cocoa/bookmark_bar_bridge.h" +#import "chrome/browser/cocoa/bookmark_bar_state.h" #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h" #include "chrome/browser/cocoa/tab_strip_model_observer_bridge.h" #include "webkit/glue/window_open_disposition.h" @@ -38,24 +39,15 @@ const CGFloat kBookmarkVerticalPadding = 2.0; const CGFloat kBookmarkHorizontalPadding = 1.0; const CGFloat kNoBookmarksHorizontalOffset = 5.0; -const CGFloat kNoBookmarksVerticalOffset = 22.0; -const CGFloat kNoBookmarksNTPVerticalOffset = 28.0; - -// States for the bookmark bar. -enum VisualState { - kInvalidState = 0, - kHiddenState = 1, - kShowingState = 2, - kDetachedState = 3, -}; +const CGFloat kNoBookmarksVerticalOffset = 6.0; } // namespace bookmarks // The interface for the bookmark bar controller's delegate. Currently, the // delegate is the BWC and is responsible for ensuring that the toolbar is // displayed correctly (as specified by |-getDesiredToolbarHeightCompression| -// and |-shouldToolbarShowDivider|) at the beginning and at the end of an -// animation (or after a state change). +// and |-toolbarDividerOpacity|) at the beginning and at the end of an animation +// (or after a state change). @protocol BookmarkBarControllerDelegate // Sent when the state has changed (after any animation), but before the final @@ -74,7 +66,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState // A controller for the bookmark bar in the browser window. Handles showing // and hiding based on the preference in the given profile. @interface BookmarkBarController : - NSViewController<BookmarkBarToolbarViewController> { + NSViewController<BookmarkBarState, BookmarkBarToolbarViewController> { @private // The visual state of the bookmark bar. If an animation is running, this is // set to the "destination" and |lastVisualState_| is set to the "original" @@ -160,31 +152,21 @@ willAnimateFromState:(bookmarks::VisualState)oldState // if needed. For fullscreen mode. - (void)setBookmarkBarEnabled:(BOOL)enabled; -// Returns YES if the bookmarks bar is currently visible (as a normal toolbar or -// as a detached bar on the NTP), NO otherwise. -- (BOOL)isVisible; - -// Returns YES if an animation is currently running, NO otherwise. -- (BOOL)isAnimationRunning; - -// Returns YES if the bookmarks bar is (to be) shown as part of the normal -// toolbar, NO otherwise. This is exclusive of |-isShownAsDetachedBar|. -- (BOOL)isShownAsToolbar; - -// Returns YES if the bookmarks bar is (to be) shown as a detached bar, NO -// otherwise; required for the |BookmarkBarToolbarViewController| protocol. This -// is exclusive of |-isShownAsToolbar|. -- (BOOL)isShownAsDetachedBar; - // Returns the amount by which the toolbar above should be compressed. - (CGFloat)getDesiredToolbarHeightCompression; -// Returns whether or not the toolbar above should show the divider. -- (BOOL)shouldToolbarShowDivider; +// Gets the appropriate opacity for the toolbar's divider; 0 means that it +// shouldn't be shown. +- (CGFloat)toolbarDividerOpacity; // Returns true if at least one bookmark was added. - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point; +// Updates the sizes and positions of the subviews. +// TODO(viettrungluu): I'm not convinced this should be public, but I currently +// need it for animations. Try not to propagate its use. +- (void)layoutSubviews; + // Complete a drag of a bookmark button to this location on the main bar. // TODO(jrg): submenu DnD. // Returns YES on success. diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm index a6ddfd7..6f2806d 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller.mm @@ -63,7 +63,7 @@ // via either the resize delegate or our general delegate. If the BWC needs any // information about what it should do, or tell the toolbar to do, it can then // query us back (e.g., |-isShownAs...|, |-getDesiredToolbarHeightCompression|, -// |-shouldToolbarShowDivider|, etc.). +// |-toolbarDividerOpacity|, etc.). // // Animation-related complications: // - Compression of the toolbar is touchy during animation. It must not be @@ -90,9 +90,9 @@ // Pointers to animation logic: // - |-moveToVisualState:withAnimation:| starts animations, deciding which ones // we know how to handle. -// - |showBookmarkBarWithAnimation:| has most of the actual logic. -// - |-getDesiredToolbarHeightCompression| and |-shouldToolbarShowDivider| -// contain related logic. +// - |-doBookmarkBarAnimation| has most of the actual logic. +// - |-getDesiredToolbarHeightCompression| and |-toolbarDividerOpacity| contain +// related logic. // - The BWC's |-layoutSubviews| needs to know how to position things. // - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and // |-bookmarkBar:willAnimateFromState:toState:| in order to inform the @@ -102,7 +102,7 @@ namespace { // Overlap (in pixels) between the toolbar and the bookmark bar (when showing in // normal mode). -const CGFloat kBookmarkBarOverlap = 6.0; +const CGFloat kBookmarkBarOverlap = 5.0; // Duration of the bookmark bar animations. const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; @@ -133,11 +133,15 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; // Stops any current animation in its tracks (midway). - (void)stopCurrentAnimation; -// Show/hide the bookmark bar. Handles animating the resize of the content view. +// Show/hide the bookmark bar. // if |animate| is YES, the changes are made using the animator; otherwise they // are made immediately. - (void)showBookmarkBarWithAnimation:(BOOL)animate; +// Handles animating the resize of the content view. Returns YES if it handled +// the animation, NO if not (and hence it should be done instantly). +- (BOOL)doBookmarkBarAnimation; + - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu; - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu; - (void)tagEmptyMenu:(NSMenu*)menu; @@ -290,95 +294,120 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; // Keep the "no items" label centered in response to a frame size change. - (void)centerNoItemsLabel { - NSView* noItemsView = [buttonView_ noItemTextfield]; - NSRect frame = [noItemsView frame]; - NSRect parent = [buttonView_ bounds]; - NSPoint newOrigin; - newOrigin.x = parent.origin.x + bookmarks::kNoBookmarksHorizontalOffset; - newOrigin.y = parent.origin.y + parent.size.height - - ([self isShownAsToolbar] ? bookmarks::kNoBookmarksVerticalOffset : - bookmarks::kNoBookmarksNTPVerticalOffset); - [noItemsView setFrameOrigin:newOrigin]; + // Note that this computation is done in the parent's coordinate system, which + // is unflipped. Also, we want the label to be a fixed distance from the + // bottom, so that it slides up properly (on animating to hidden). + NSPoint parentOrigin = [buttonView_ bounds].origin; + [[buttonView_ noItemTextfield] setFrameOrigin:NSMakePoint( + parentOrigin.x + bookmarks::kNoBookmarksHorizontalOffset, + parentOrigin.y + bookmarks::kNoBookmarksVerticalOffset)]; } // Change the layout of the bookmark bar's subviews in response to a visibility // change (e.g., show or hide the bar) or style change (attached or floating). - (void)layoutSubviews { - if (visualState_ == bookmarks::kDetachedState) { - // The internal bookmark bar should have padding to center it. - NSRect frame = [[self view] frame]; - [buttonView_ setFrame: - NSMakeRect(bookmarks::kNTPBookmarkBarPadding, - bookmarks::kNTPBookmarkBarPadding, - (NSWidth(frame) - - bookmarks::kNTPBookmarkBarPadding*2), - (NSHeight(frame) - - bookmarks::kNTPBookmarkBarPadding))]; - } else { - // The frame of our child should be equal to our frame, excluding - // space for stuff on the right side (e.g. off-the-side chevron). - NSRect frame = [[self view] frame]; - [buttonView_ setFrame:NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame))]; - } + NSRect frame = [[self view] frame]; + NSRect buttonViewFrame = NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame)); + + // The state of our morph (if any); 1 is total bubble, 0 is the regular bar. + CGFloat morph = [self detachedMorphProgress]; + + // Add padding to the detached bookmark bar. + buttonViewFrame = NSInsetRect(buttonViewFrame, + morph * bookmarks::kNTPBookmarkBarPadding, + morph * bookmarks::kNTPBookmarkBarPadding); + + [buttonView_ setFrame:buttonViewFrame]; } // (Private) - (void)showBookmarkBarWithAnimation:(BOOL)animate { if (animate) { - // Animating from hidden to normal bar. - if (lastVisualState_ == bookmarks::kHiddenState && - visualState_ == bookmarks::kShowingState) { - [[self backgroundGradientView] setShowsDivider:YES]; - [[self view] setHidden:NO]; - AnimatableView* view = [self animatableView]; - // Height takes into account the extra height we have since the toolbar - // only compresses when we're done. - [view animateToNewHeight:([self preferredHeight] - kBookmarkBarOverlap) - duration:kBookmarkBarAnimationDuration]; - return; - } - - // Animating from normal bar to hidden. - if (lastVisualState_ == bookmarks::kShowingState && - visualState_ == bookmarks::kHiddenState) { - // The toolbar uncompresses immediately at the beginning (otherwise the - // slide looks wrong, since we slide into the bottom of stuff in the - // toolbar). Do this only if we're at the beginning height since we may - // enter this mid-animation. - if (NSHeight([[self view] frame]) == bookmarks::kBookmarkBarHeight) { - [resizeDelegate_ resizeView:[self view] - newHeight:(bookmarks::kBookmarkBarHeight - - kBookmarkBarOverlap)]; - } - [[self backgroundGradientView] setShowsDivider:YES]; - [[self view] setHidden:NO]; - AnimatableView* view = [self animatableView]; - [view animateToNewHeight:0 - duration:kBookmarkBarAnimationDuration]; + // If |-doBookmarkBarAnimation| does the animation, we're done. + if ([self doBookmarkBarAnimation]) return; - } - - // TODO(viettrungluu): other animation cases. Note: will need to fade in/out - // divider when animating from/to detached bar (to/from normal bar). - // Fall through for any cases we don't know about. + // Else fall through and do the change instantly. } - BOOL show = [self isVisible]; - CGFloat height = show ? [self preferredHeight] : 0; - [resizeDelegate_ resizeView:[self view] newHeight:height]; + // Set our height. + [resizeDelegate_ resizeView:[self view] + newHeight:[self preferredHeight]]; // Only show the divider if showing the normal bookmark bar. - BOOL showDivider = (visualState_ == bookmarks::kShowingState || - lastVisualState_ == bookmarks::kShowingState) ? YES : NO; - [[self backgroundGradientView] setShowsDivider:showDivider]; + BOOL showsDivider = [self isInState:bookmarks::kShowingState]; + [[self backgroundGradientView] setShowsDivider:showsDivider]; // Make sure we're shown. - [[self view] setHidden:(show ? NO : YES)]; + [[self view] setHidden:([self isVisible] ? NO : YES)]; + + // Update everything else. [self layoutSubviews]; [self frameDidChange]; } +// (Private) +- (BOOL)doBookmarkBarAnimation { + if ([self isAnimatingFromState:bookmarks::kHiddenState + toState:bookmarks::kShowingState]) { + [[self backgroundGradientView] setShowsDivider:YES]; + [[self view] setHidden:NO]; + AnimatableView* view = [self animatableView]; + // Height takes into account the extra height we have since the toolbar + // only compresses when we're done. + [view animateToNewHeight:(bookmarks::kBookmarkBarHeight - + kBookmarkBarOverlap) + duration:kBookmarkBarAnimationDuration]; + } else if ([self isAnimatingFromState:bookmarks::kShowingState + toState:bookmarks::kHiddenState]) { + // The toolbar uncompresses immediately at the beginning (otherwise the + // slide looks wrong, since we slide into the bottom of stuff in the + // toolbar). Do this only if we're at the beginning height since we may + // enter this mid-animation. + if (NSHeight([[self view] frame]) == bookmarks::kBookmarkBarHeight) { + [resizeDelegate_ resizeView:[self view] + newHeight:(bookmarks::kBookmarkBarHeight - + kBookmarkBarOverlap)]; + } + [[self backgroundGradientView] setShowsDivider:YES]; + [[self view] setHidden:NO]; + AnimatableView* view = [self animatableView]; + [view animateToNewHeight:0 + duration:kBookmarkBarAnimationDuration]; + } else if ([self isAnimatingFromState:bookmarks::kShowingState + toState:bookmarks::kDetachedState]) { + // The toolbar uncompresses immediately at the beginning (otherwise the + // slide looks wrong, since we slide into the bottom of stuff in the + // toolbar). Do this only if we're at the beginning height since we may + // enter this mid-animation. + if (NSHeight([[self view] frame]) == bookmarks::kBookmarkBarHeight) { + [resizeDelegate_ resizeView:[self view] + newHeight:(bookmarks::kBookmarkBarHeight - + kBookmarkBarOverlap)]; + } + [[self backgroundGradientView] setShowsDivider:YES]; + [[self view] setHidden:NO]; + AnimatableView* view = [self animatableView]; + [view animateToNewHeight:bookmarks::kNTPBookmarkBarHeight + duration:kBookmarkBarAnimationDuration]; + } else if ([self isAnimatingFromState:bookmarks::kDetachedState + toState:bookmarks::kShowingState]) { + [[self backgroundGradientView] setShowsDivider:YES]; + [[self view] setHidden:NO]; + AnimatableView* view = [self animatableView]; + // Height takes into account the extra height we have since the toolbar + // only compresses when we're done. + [view animateToNewHeight:(bookmarks::kBookmarkBarHeight - + kBookmarkBarOverlap) + duration:kBookmarkBarAnimationDuration]; + } else { + // Oops! An animation we don't know how to handle. + return NO; + } + + return YES; +} + // We don't change a preference; we only change visibility. Preference changing // (global state) is handled in |BrowserWindowCocoa::ToggleBookmarkBar()|. We // simply update based on what we're told. @@ -391,56 +420,44 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; [self updateVisibility]; } -- (BOOL)isVisible { - return (barIsEnabled_ && (visualState_ == bookmarks::kShowingState || - visualState_ == bookmarks::kDetachedState)) ? - YES : NO; -} - -- (BOOL)isAnimationRunning { - return (lastVisualState_ == bookmarks::kInvalidState) ? NO : YES; -} - -- (BOOL)isShownAsToolbar { - return (visualState_ == bookmarks::kShowingState) ? YES : NO; -} - -- (BOOL)isShownAsDetachedBar { - return (visualState_ == bookmarks::kDetachedState) ? YES : NO; -} - - (CGFloat)getDesiredToolbarHeightCompression { // Some special cases.... if ([self isAnimationRunning]) { - // No toolbar compression when animating between showing and hidden. - if ((lastVisualState_ == bookmarks::kHiddenState && - visualState_ == bookmarks::kShowingState) || - (lastVisualState_ == bookmarks::kShowingState && - visualState_ == bookmarks::kHiddenState)) + // No toolbar compression when animating between hidden and showing, nor + // between showing and detached. + if ([self isAnimatingBetweenState:bookmarks::kHiddenState + andState:bookmarks::kShowingState] || + [self isAnimatingBetweenState:bookmarks::kShowingState + andState:bookmarks::kDetachedState]) return 0; - // TODO(viettrungluu): other animation cases. + // If we ever need any other animation cases, code would go here. } - return (visualState_ == bookmarks::kShowingState) ? kBookmarkBarOverlap : 0; + return [self isInState:bookmarks::kShowingState] ? kBookmarkBarOverlap : 0; } -- (BOOL)shouldToolbarShowDivider { +- (CGFloat)toolbarDividerOpacity { // Some special cases.... if ([self isAnimationRunning]) { // In general, the toolbar shouldn't show a divider while we're animating // between showing and hidden. The exception is when our height is < 1, in - // which case we can't draw it. - if ((lastVisualState_ == bookmarks::kHiddenState && - visualState_ == bookmarks::kShowingState) || - (lastVisualState_ == bookmarks::kShowingState && - visualState_ == bookmarks::kHiddenState)) - return (NSHeight([[self view] frame]) < 1) ? YES : NO; - - // TODO(viettrungluu): other animation cases. + // which case we can't draw it. It's all-or-nothing (no partial opacity). + if ([self isAnimatingBetweenState:bookmarks::kHiddenState + andState:bookmarks::kShowingState]) + return (NSHeight([[self view] frame]) < 1) ? 1 : 0; + + // The toolbar should show the divider when animating between showing and + // detached (but opacity will vary). + if ([self isAnimatingBetweenState:bookmarks::kShowingState + andState:bookmarks::kDetachedState]) + return static_cast<CGFloat>([self detachedMorphProgress]); + + // If we ever need any other animation cases, code would go here. } - return (visualState_ == bookmarks::kShowingState) ? NO : YES; + // In general, only show the divider when it's in the normal showing state. + return [self isInState:bookmarks::kShowingState] ? 0 : 1; } - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { @@ -594,8 +611,23 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; } - (int)preferredHeight { - return [self isShownAsToolbar] ? bookmarks::kBookmarkBarHeight : - bookmarks::kNTPBookmarkBarHeight; + DCHECK(![self isAnimationRunning]); + + if (!barIsEnabled_) + return 0; + + switch (visualState_) { + case bookmarks::kShowingState: + return bookmarks::kBookmarkBarHeight; + case bookmarks::kDetachedState: + return bookmarks::kNTPBookmarkBarHeight; + case bookmarks::kHiddenState: + return 0; + case bookmarks::kInvalidState: + default: + NOTREACHED(); + return 0; + } } // Recursively add the given bookmark node and all its children to @@ -941,8 +973,7 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; // bookmark. On Safari that menu has a "new folder" option. - (void)addNodesToButtonList:(const BookmarkNode*)node { BOOL hidden = (node->GetChildCount() == 0) ? NO : YES; - NSView* item = [buttonView_ noItemTextfield]; - [item setHidden:hidden]; + [[buttonView_ noItemTextfield] setHidden:hidden]; int xOffset = 0; for (int i = 0; i < node->GetChildCount(); i++) { @@ -1218,19 +1249,18 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; if (animate) { // Take care of any animation cases we know how to handle. - // We know how to handle hidden <-> normal.... - if ((lastVisualState_ == bookmarks::kHiddenState && - visualState_ == bookmarks::kShowingState) || - (lastVisualState_ == bookmarks::kShowingState && - visualState_ == bookmarks::kHiddenState)) { + // We know how to handle hidden <-> normal, normal <-> detached.... + if ([self isAnimatingBetweenState:bookmarks::kHiddenState + andState:bookmarks::kShowingState] || + [self isAnimatingBetweenState:bookmarks::kShowingState + andState:bookmarks::kDetachedState]) { [delegate_ bookmarkBar:self willAnimateFromState:lastVisualState_ toState:visualState_]; [self showBookmarkBarWithAnimation:YES]; return; } - // TODO(viettrungluu): we don't know about any yet.... - + // If we ever need any other animation cases, code would go here. // Let any animation cases which we don't know how to handle fall through to // the unanimated case. } @@ -1276,4 +1306,63 @@ const NSTimeInterval kBookmarkBarAnimationDuration = 0.12; [self finalizeVisualState]; } +// (BookmarkBarState protocol) +- (BOOL)isVisible { + return (barIsEnabled_ && (visualState_ == bookmarks::kShowingState || + visualState_ == bookmarks::kDetachedState)) ? + YES : NO; +} + +// (BookmarkBarState protocol) +- (BOOL)isAnimationRunning { + return (lastVisualState_ == bookmarks::kInvalidState) ? NO : YES; +} + +// (BookmarkBarState protocol) +- (BOOL)isInState:(bookmarks::VisualState)state { + return (visualState_ == state && + lastVisualState_ == bookmarks::kInvalidState) ? YES : NO; +} + +// (BookmarkBarState protocol) +- (BOOL)isAnimatingToState:(bookmarks::VisualState)state { + return (visualState_ == state && + lastVisualState_ != bookmarks::kInvalidState) ? YES : NO; +} + +// (BookmarkBarState protocol) +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state { + return (lastVisualState_ == state) ? YES : NO; +} + +// (BookmarkBarState protocol) +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState + toState:(bookmarks::VisualState)toState { + return (lastVisualState_ == fromState && visualState_ == toState) ? YES : NO; +} + +// (BookmarkBarState protocol) +- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState + andState:(bookmarks::VisualState)toState { + return ((lastVisualState_ == fromState && visualState_ == toState) || + (visualState_ == fromState && lastVisualState_ == toState)) ? + YES : NO; +} + +// (BookmarkBarState protocol) +- (CGFloat)detachedMorphProgress { + if ([self isInState:bookmarks::kDetachedState]) { + return 1; + } + if ([self isAnimatingToState:bookmarks::kDetachedState]) { + return static_cast<CGFloat>( + [[self animatableView] currentAnimationProgress]); + } + if ([self isAnimatingFromState:bookmarks::kDetachedState]) { + return static_cast<CGFloat>( + 1 - [[self animatableView] currentAnimationProgress]); + } + return 0; +} + @end diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm index c025b0e..0fc68e3 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm @@ -126,13 +126,6 @@ class BookmarkBarControllerTest : public PlatformTest { withAnimation:NO]; } - // Update the state of the bookmark bar. - void UpdateBookmarkBar() { - [bar_ updateAndShowNormalBar:[bar_ isShownAsToolbar] - showDetachedBar:[bar_ isShownAsDetachedBar] - withAnimation:NO]; - } - // Return a menu item that points to the right URL. NSMenuItem* ItemForBookmarkBarMenu(GURL& gurl) { node_.reset(new BookmarkNode(gurl)); @@ -161,9 +154,10 @@ TEST_F(BookmarkBarControllerTest, ShowWhenShowBookmarkBarTrue) { [bar_ updateAndShowNormalBar:YES showDetachedBar:NO withAnimation:NO]; - EXPECT_TRUE([bar_ isShownAsToolbar]); - EXPECT_FALSE([bar_ isShownAsDetachedBar]); + EXPECT_TRUE([bar_ isInState:bookmarks::kShowingState]); + EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]); EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); EXPECT_FALSE([[bar_ view] isHidden]); EXPECT_GT([resizeDelegate_ height], 0); EXPECT_GT([[bar_ view] frame].size.height, 0); @@ -173,9 +167,10 @@ TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarFalse) { [bar_ updateAndShowNormalBar:NO showDetachedBar:NO withAnimation:NO]; - EXPECT_FALSE([bar_ isShownAsToolbar]); - EXPECT_FALSE([bar_ isShownAsDetachedBar]); + EXPECT_FALSE([bar_ isInState:bookmarks::kShowingState]); + EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]); EXPECT_FALSE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); EXPECT_TRUE([[bar_ view] isHidden]); EXPECT_EQ(0, [resizeDelegate_ height]); EXPECT_EQ(0, [[bar_ view] frame].size.height); @@ -186,9 +181,10 @@ TEST_F(BookmarkBarControllerTest, HideWhenShowBookmarkBarTrueButDisabled) { [bar_ updateAndShowNormalBar:YES showDetachedBar:NO withAnimation:NO]; - EXPECT_TRUE([bar_ isShownAsToolbar]); - EXPECT_FALSE([bar_ isShownAsDetachedBar]); + EXPECT_TRUE([bar_ isInState:bookmarks::kShowingState]); + EXPECT_FALSE([bar_ isInState:bookmarks::kDetachedState]); EXPECT_FALSE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); EXPECT_TRUE([[bar_ view] isHidden]); EXPECT_EQ(0, [resizeDelegate_ height]); EXPECT_EQ(0, [[bar_ view] frame].size.height); @@ -198,11 +194,12 @@ TEST_F(BookmarkBarControllerTest, ShowOnNewTabPage) { [bar_ updateAndShowNormalBar:NO showDetachedBar:YES withAnimation:NO]; - EXPECT_FALSE([bar_ isShownAsToolbar]); - EXPECT_TRUE([bar_ isShownAsDetachedBar]); + EXPECT_FALSE([bar_ isInState:bookmarks::kShowingState]); + EXPECT_TRUE([bar_ isInState:bookmarks::kDetachedState]); EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); EXPECT_FALSE([[bar_ view] isHidden]); - ;EXPECT_GT([resizeDelegate_ height], 0); + EXPECT_GT([resizeDelegate_ height], 0); EXPECT_GT([[bar_ view] frame].size.height, 0); // Make sure no buttons fall off the bar, either now or when resized @@ -238,6 +235,68 @@ TEST_F(BookmarkBarControllerTest, ShowOnNewTabPage) { } } +// Test whether |-updateAndShowNormalBar:...| sets states as we expect. Make +// sure things don't crash. +TEST_F(BookmarkBarControllerTest, StateChanges) { + // First, go in one-at-a-time cycle. + [bar_ updateAndShowNormalBar:NO + showDetachedBar:NO + withAnimation:NO]; + EXPECT_EQ(bookmarks::kHiddenState, [bar_ visualState]); + EXPECT_FALSE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + [bar_ updateAndShowNormalBar:YES + showDetachedBar:NO + withAnimation:NO]; + EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]); + EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + [bar_ updateAndShowNormalBar:YES + showDetachedBar:YES + withAnimation:NO]; + EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]); + EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + [bar_ updateAndShowNormalBar:NO + showDetachedBar:YES + withAnimation:NO]; + EXPECT_EQ(bookmarks::kDetachedState, [bar_ visualState]); + EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + + // Now try some "jumps". + for (int i = 0; i < 2; i++) { + [bar_ updateAndShowNormalBar:NO + showDetachedBar:NO + withAnimation:NO]; + EXPECT_EQ(bookmarks::kHiddenState, [bar_ visualState]); + EXPECT_FALSE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + [bar_ updateAndShowNormalBar:YES + showDetachedBar:YES + withAnimation:NO]; + EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]); + EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + } + + // Now try some "jumps". + for (int i = 0; i < 2; i++) { + [bar_ updateAndShowNormalBar:YES + showDetachedBar:NO + withAnimation:NO]; + EXPECT_EQ(bookmarks::kShowingState, [bar_ visualState]); + EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + [bar_ updateAndShowNormalBar:NO + showDetachedBar:YES + withAnimation:NO]; + EXPECT_EQ(bookmarks::kDetachedState, [bar_ visualState]); + EXPECT_TRUE([bar_ isVisible]); + EXPECT_FALSE([bar_ isAnimationRunning]); + } +} + // Make sure we're watching for frame change notifications. TEST_F(BookmarkBarControllerTest, FrameChangeNotification) { scoped_nsobject<BookmarkBarControllerTogglePong> bar; @@ -789,4 +848,6 @@ TEST_F(BookmarkBarControllerTest, TestDragButton) { EXPECT_TRUE([[[[bar_ buttons] objectAtIndex:2] title] isEqual:@"a"]); } +// TODO(viettrungluu): figure out how to test animations. + } // namespace diff --git a/chrome/browser/cocoa/bookmark_bar_state.h b/chrome/browser/cocoa/bookmark_bar_state.h new file mode 100644 index 0000000..4d6af05 --- /dev/null +++ b/chrome/browser/cocoa/bookmark_bar_state.h @@ -0,0 +1,61 @@ +// 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_BOOKMARK_BAR_STATE_H_ +#define CHROME_BROWSER_COCOA_BOOKMARK_BAR_STATE_H_ + +#import <Cocoa/Cocoa.h> + +namespace bookmarks { + +// States for the bookmark bar. +enum VisualState { + kInvalidState = 0, + kHiddenState = 1, + kShowingState = 2, + kDetachedState = 3, +}; + +} // namespace bookmarks + +// The interface for controllers (etc.) which can give information about the +// bookmark bar's state. +@protocol BookmarkBarState + +// Returns YES if the bookmark bar is currently visible (as a normal toolbar or +// as a detached bar on the NTP), NO otherwise. +- (BOOL)isVisible; + +// Returns YES if an animation is currently running, NO otherwise. +- (BOOL)isAnimationRunning; + +// Returns YES if the bookmark bar is in the given state and not in an +// animation, NO otherwise. +- (BOOL)isInState:(bookmarks::VisualState)state; + +// Returns YES if the bookmark bar is animating from the given state (to any +// other state), NO otherwise. +- (BOOL)isAnimatingToState:(bookmarks::VisualState)state; + +// Returns YES if the bookmark bar is animating to the given state (from any +// other state), NO otherwise. +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state; + +// Returns YES if the bookmark bar is animating from the first given state to +// the second given state, NO otherwise. +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState + toState:(bookmarks::VisualState)toState; + +// Returns YES if the bookmark bar is animating between the two given states (in +// either direction), NO otherwise. +- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState + andState:(bookmarks::VisualState)toState; + +// Returns how morphed into the detached bubble the bookmark bar should be (1 = +// completely detached, 0 = normal). +- (CGFloat)detachedMorphProgress; + +@end + +#endif // CHROME_BROWSER_COCOA_BOOKMARK_BAR_STATE_H_ diff --git a/chrome/browser/cocoa/bookmark_bar_toolbar_view.h b/chrome/browser/cocoa/bookmark_bar_toolbar_view.h index 2232309..b2b08ac 100644 --- a/chrome/browser/cocoa/bookmark_bar_toolbar_view.h +++ b/chrome/browser/cocoa/bookmark_bar_toolbar_view.h @@ -13,6 +13,7 @@ #import <Cocoa/Cocoa.h> #import "chrome/browser/cocoa/animatable_view.h" +#import "chrome/browser/cocoa/bookmark_bar_state.h" @class BookmarkBarView; class TabContents; @@ -20,7 +21,7 @@ class ThemeProvider; // An interface to allow mocking of a BookmarkBarController by the // BookmarkBarToolbarView. -@protocol BookmarkBarToolbarViewController +@protocol BookmarkBarToolbarViewController <BookmarkBarState> // Displaying the bookmark toolbar background in bubble (floating) mode requires // the size of the currently selected tab to properly calculate where the // background image is joined. @@ -29,10 +30,6 @@ class ThemeProvider; // Current theme provider, passed to the cross platform NtpBackgroundUtil class. - (ThemeProvider*)themeProvider; -// Returns true if the bookmark bar should be drawn as if it's a disconnected -// bookmark bar on the New Tag Page. -- (BOOL)isShownAsDetachedBar; - @end @interface BookmarkBarToolbarView : AnimatableView { diff --git a/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm b/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm index d327170..6ca3f54 100644 --- a/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm +++ b/chrome/browser/cocoa/bookmark_bar_toolbar_view.mm @@ -23,11 +23,13 @@ const CGFloat kBorderRadius = 3.0; @implementation BookmarkBarToolbarView - (BOOL)isOpaque { - return [controller_ isShownAsDetachedBar]; + return [controller_ isInState:bookmarks::kDetachedState]; } - (void)drawRect:(NSRect)rect { - if ([controller_ isShownAsDetachedBar]) { + if ([controller_ isInState:bookmarks::kDetachedState] || + [controller_ isAnimatingToState:bookmarks::kDetachedState] || + [controller_ isAnimatingFromState:bookmarks::kDetachedState]) { [self drawRectAsBubble:rect]; } else { NSPoint phase = [self gtm_themePatternPhase]; @@ -37,16 +39,20 @@ const CGFloat kBorderRadius = 3.0; } - (void)drawRectAsBubble:(NSRect)rect { + // The state of our morph; 1 is total bubble, 0 is the regular bar. We use it + // to morph the bubble to a regular bar (shape and colour). + CGFloat morph = [controller_ detachedMorphProgress]; + NSRect bounds = [self bounds]; ThemeProvider* themeProvider = [controller_ themeProvider]; if (!themeProvider) return; - NSGraphicsContext* theContext = [NSGraphicsContext currentContext]; - [theContext saveGraphicsState]; + NSGraphicsContext* context = [NSGraphicsContext currentContext]; + [context saveGraphicsState]; - // Draw the background + // Draw the background. { // CanvasPaint draws to the NSGraphicsContext during its destructor, so // explicitly scope this. @@ -69,16 +75,19 @@ const CGFloat kBorderRadius = 3.0; // Draw our bookmark bar border on top of the background. NSRect frameRect = - NSMakeRect(bookmarks::kNTPBookmarkBarPadding, - bookmarks::kNTPBookmarkBarPadding, - NSWidth(bounds) - 2 * bookmarks::kNTPBookmarkBarPadding, - NSHeight(bounds) - 2 * bookmarks::kNTPBookmarkBarPadding); - // Now draw a bezier path with rounded rectangles around the area - frameRect = NSInsetRect(frameRect, 0.5, 0.5); + NSMakeRect( + morph * bookmarks::kNTPBookmarkBarPadding, + morph * bookmarks::kNTPBookmarkBarPadding, + NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding, + NSHeight(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding); + // Now draw a bezier path with rounded rectangles around the area. + frameRect = NSInsetRect(frameRect, morph * 0.5, morph * 0.5); NSBezierPath* border = [NSBezierPath bezierPathWithRoundedRect:frameRect - xRadius:kBorderRadius - yRadius:kBorderRadius]; + xRadius:(morph * kBorderRadius) + yRadius:(morph * kBorderRadius)]; + + // Draw the rounded rectangle. NSColor* toolbarColor = [[self gtm_theme] backgroundColorForStyle:GTMThemeStyleToolBar state:GTMThemeStateActiveWindow]; @@ -89,16 +98,43 @@ const CGFloat kBorderRadius = 3.0; toolbarColor = nil; if (!toolbarColor) toolbarColor = [NSColor colorWithCalibratedWhite:0.9 alpha:1.0]; - [toolbarColor set]; + [[toolbarColor colorWithAlphaComponent:morph] set]; // Set with opacity. [border fill]; + // Fade in/out the background. + [context saveGraphicsState]; + [border setClip]; + CGContextRef cgContext = (CGContextRef)[context graphicsPort]; + CGContextBeginTransparencyLayer(cgContext, NULL); + CGContextSetAlpha(cgContext, 1 - morph); + [context setPatternPhase:[self gtm_themePatternPhase]]; + [self drawBackground]; + CGContextEndTransparencyLayer(cgContext); + [context restoreGraphicsState]; + + // Draw the border of the rounded rectangle. NSColor* borderColor = [[self gtm_theme] strokeColorForStyle:GTMThemeStyleToolBarButton state:GTMThemeStateActiveWindow]; - [borderColor set]; + [[borderColor colorWithAlphaComponent:morph] set]; // Set with opacity. [border stroke]; - [theContext restoreGraphicsState]; + // Fade in/out the divider. + // TODO(viettrungluu): It's not obvious that this divider lines up exactly + // with |BackgroundGradientView|'s (in fact, it probably doesn't). + [[[self strokeColor] colorWithAlphaComponent:(1 - morph)] set]; + NSBezierPath* divider = [NSBezierPath bezierPath]; + NSPoint dividerStart = + NSMakePoint(morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5, + morph * bookmarks::kNTPBookmarkBarPadding + morph * 0.5); + CGFloat dividerWidth = + NSWidth(bounds) - 2 * morph * bookmarks::kNTPBookmarkBarPadding - 2 * 0.5; + [divider moveToPoint:dividerStart]; + [divider relativeLineToPoint:NSMakePoint(dividerWidth, 0)]; + [divider stroke]; + + // Restore the graphics context. + [context restoreGraphicsState]; } @end // @implementation BookmarkBarToolbarView diff --git a/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm b/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm index 5073764..7a55edc 100644 --- a/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm @@ -53,20 +53,52 @@ class MockThemeProvider : public ThemeProvider { // Allows us to control which way the view is rendered. @interface DrawDetachedBarFakeController : - NSObject<BookmarkBarToolbarViewController> { - int current_tab_contents_height_; - ThemeProvider* theme_provider_; - BOOL isShownAsDetachedBar_; + NSObject<BookmarkBarState, BookmarkBarToolbarViewController> { + @private + int currentTabContentsHeight_; + ThemeProvider* themeProvider_; + bookmarks::VisualState visualState_; } @property(assign) int currentTabContentsHeight; @property(assign) ThemeProvider* themeProvider; -@property(assign) BOOL isShownAsDetachedBar; +@property(assign) bookmarks::VisualState visualState; + +// |BookmarkBarState| protocol: +- (BOOL)isVisible; +- (BOOL)isAnimationRunning; +- (BOOL)isInState:(bookmarks::VisualState)state; +- (BOOL)isAnimatingToState:(bookmarks::VisualState)state; +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state; +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState + toState:(bookmarks::VisualState)toState; +- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState + andState:(bookmarks::VisualState)toState; +- (CGFloat)detachedMorphProgress; @end @implementation DrawDetachedBarFakeController -@synthesize currentTabContentsHeight = current_tab_contents_height_; -@synthesize themeProvider = theme_provider_; -@synthesize isShownAsDetachedBar = isShownAsDetachedBar_; +@synthesize currentTabContentsHeight = currentTabContentsHeight_; +@synthesize themeProvider = themeProvider_; +@synthesize visualState = visualState_; + +- (id)init { + if ((self = [super init])) { + [self setVisualState:bookmarks::kHiddenState]; + } + return self; +} + +- (BOOL)isVisible { return YES; } +- (BOOL)isAnimationRunning { return NO; } +- (BOOL)isInState:(bookmarks::VisualState)state + { return ([self visualState] == state) ? YES : NO; } +- (BOOL)isAnimatingToState:(bookmarks::VisualState)state { return NO; } +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)state { return NO; } +- (BOOL)isAnimatingFromState:(bookmarks::VisualState)fromState + toState:(bookmarks::VisualState)toState { return NO; } +- (BOOL)isAnimatingBetweenState:(bookmarks::VisualState)fromState + andState:(bookmarks::VisualState)toState { return NO; } +- (CGFloat)detachedMorphProgress { return 1; } @end class BookmarkBarToolbarViewTest : public PlatformTest { @@ -94,13 +126,13 @@ TEST_F(BookmarkBarToolbarViewTest, AddRemove) { // Test drawing (part 1), mostly to ensure nothing leaks or crashes. TEST_F(BookmarkBarToolbarViewTest, DisplayAsNormalBar) { - [controller_.get() setIsShownAsDetachedBar:NO]; + [controller_.get() setVisualState:bookmarks::kShowingState]; [view_ display]; } // Test drawing (part 2), mostly to ensure nothing leaks or crashes. TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithNoImage) { - [controller_.get() setIsShownAsDetachedBar:YES]; + [controller_.get() setVisualState:bookmarks::kDetachedState]; // Tests where we don't have a background image, only a color. MockThemeProvider provider; @@ -126,7 +158,7 @@ ACTION(SetAlignLeft) { // Test drawing (part 3), mostly to ensure nothing leaks or crashes. TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithBgImage) { - [controller_.get() setIsShownAsDetachedBar:YES]; + [controller_.get() setVisualState:bookmarks::kDetachedState]; // Tests where we have a background image, with positioning information. MockThemeProvider provider; @@ -158,3 +190,5 @@ TEST_F(BookmarkBarToolbarViewTest, DisplayAsDetachedBarWithBgImage) { [view_ display]; } + +// TODO(viettrungluu): write more unit tests, especially after my refactoring. diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index 71c09f2..ff2c441 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -396,7 +396,7 @@ willPositionSheet:(NSWindow*)sheet TabContents* contents = browser_->tabstrip_model()->GetSelectedTabContents(); if (contents) { // If the intrinsic width is bigger, then make it the zoomed width. - const int kScrollbarWidth = 16; // FIXME(viettrungluu@gmail.com): ugh. + const int kScrollbarWidth = 16; // TODO(viettrungluu): ugh. CGFloat intrinsicWidth = static_cast<CGFloat>( contents->view()->preferred_width() + kScrollbarWidth); zoomedWidth = std::max(zoomedWidth, @@ -1228,9 +1228,8 @@ willPositionSheet:(NSWindow*)sheet toState:(bookmarks::VisualState)newState { [toolbarController_ setHeightCompression:[controller getDesiredToolbarHeightCompression]]; - [toolbarController_ setShowsDivider:[controller shouldToolbarShowDivider]]; - - // TODO(viettrungluu): anything else? + [toolbarController_ + setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]]; } // (Needed for |BookmarkBarControllerDelegate| protocol.) @@ -1239,9 +1238,8 @@ willAnimateFromState:(bookmarks::VisualState)oldState toState:(bookmarks::VisualState)newState { [toolbarController_ setHeightCompression:[controller getDesiredToolbarHeightCompression]]; - [toolbarController_ setShowsDivider:[controller shouldToolbarShowDivider]]; - - // TODO(viettrungluu): anything else? + [toolbarController_ + setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]]; } @end @@ -1350,8 +1348,8 @@ willPositionSheet:(NSWindow*)sheet defaultSheetRect.origin.y = toolbarFrame.origin.y; break; } - default: case bookmarks::kInvalidState: + default: NOTREACHED(); } return defaultSheetRect; @@ -1434,18 +1432,17 @@ willPositionSheet:(NSWindow*)sheet } [toolbarView setFrame:toolbarFrame]; - bookmarks::VisualState bookmarkBarState = - [bookmarkBarController_ visualState]; - bookmarks::VisualState lastBookmarkBarState = - [bookmarkBarController_ lastVisualState]; - - // If the bookmark bar is showing, or animating between showing and hidden, - // place the bookmark bar immediately below the toolbar. - // TODO(viettrungluu): Improve/abstract this when I implement other - // animations. - if ((bookmarkBarState == bookmarks::kShowingState) || - (bookmarkBarState == bookmarks::kHiddenState && - lastBookmarkBarState == bookmarks::kShowingState)) { + // If we are currently displaying the NTP detached bookmark bar or animating + // to/from it (from/to anything else), we display the bookmark bar below the + // infobar. + BOOL placeBookmarkBarBelowInfobar = + [bookmarkBarController_ isInState:bookmarks::kDetachedState] || + [bookmarkBarController_ isAnimatingToState:bookmarks::kDetachedState] || + [bookmarkBarController_ isAnimatingFromState:bookmarks::kDetachedState]; + + // If we're not displaying the bookmark bar below the infobar, then it goes + // immediately below the toolbar. + if (!placeBookmarkBarBelowInfobar) { NSView* bookmarkBarView = [bookmarkBarController_ view]; [bookmarkBarView setHidden:NO]; NSRect bookmarkBarFrame = [bookmarkBarView frame]; @@ -1464,7 +1461,7 @@ willPositionSheet:(NSWindow*)sheet maxY -= NSHeight(infoBarFrame); // If the bookmark bar is detached, place it at the bottom of the stack. - if (bookmarkBarState == bookmarks::kDetachedState) { + if (placeBookmarkBarBelowInfobar) { NSView* bookmarkBarView = [bookmarkBarController_ view]; [bookmarkBarView setHidden:NO]; NSRect bookmarkBarFrame = [bookmarkBarView frame]; @@ -1472,6 +1469,9 @@ willPositionSheet:(NSWindow*)sheet bookmarkBarFrame.size.width = NSWidth(contentFrame); [bookmarkBarView setFrame:bookmarkBarFrame]; maxY -= NSHeight(bookmarkBarFrame); + + // TODO(viettrungluu): this really doesn't belong here. + [bookmarkBarController_ layoutSubviews]; } // Place the extension shelf at the bottom of the view, if it exists. @@ -1511,7 +1511,7 @@ willPositionSheet:(NSWindow*)sheet // Normally, we don't need to tell the toolbar whether or not to show the // divider, but things break down during animation. [toolbarController_ - setShowsDivider:[bookmarkBarController_ shouldToolbarShowDivider]]; + setDividerOpacity:[bookmarkBarController_ toolbarDividerOpacity]]; } - (BOOL)shouldShowBookmarkBar { diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm index b03d095..6e8fc96 100644 --- a/chrome/browser/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm @@ -247,6 +247,7 @@ TEST_F(BrowserWindowControllerTest, TestResizeViewsWithBookmarkBar) { // Force a display of the bookmark bar. browser_helper_.profile()->GetPrefs()-> SetBoolean(prefs::kShowBookmarkBar, true); + [controller_ updateBookmarkBarVisibilityWithAnimation:NO]; TabStripView* tabstrip = [controller_ tabStripView]; NSView* contentView = [[tabstrip window] contentView]; diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h index f46e264..a78ae47 100644 --- a/chrome/browser/cocoa/toolbar_controller.h +++ b/chrome/browser/cocoa/toolbar_controller.h @@ -31,7 +31,6 @@ class PrefObserverBridge; class Profile; class TabContents; class ToolbarModel; -class ToolbarView; // A controller for the toolbar in the browser window. Manages // updating the state for location bar and back/fwd/reload/go buttons. @@ -139,9 +138,9 @@ class ToolbarView; // bookmark bar is attached. - (void)setHeightCompression:(CGFloat)compressByHeight; -// Display (or not) the divider (line at bottom); needed when the bookmark bar -// is attached. -- (void)setShowsDivider:(BOOL)showDivider; +// Set the opacity of the divider (the line at the bottom) *if* we have a +// |ToolbarView| (0 means don't show it); no-op otherwise. +- (void)setDividerOpacity:(CGFloat)opacity; @end diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm index 8653f49..cc719dd 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -21,6 +21,7 @@ #import "chrome/browser/cocoa/gradient_button_cell.h" #import "chrome/browser/cocoa/location_bar_view_mac.h" #import "chrome/browser/cocoa/menu_button.h" +#import "chrome/browser/cocoa/toolbar_view.h" #include "chrome/browser/profile.h" #include "chrome/browser/search_engines/template_url_model.h" #include "chrome/browser/toolbar_model.h" @@ -522,8 +523,16 @@ class PrefObserverBridge : public NotificationObserver { [resizeDelegate_ resizeView:[self view] newHeight:newToolbarHeight]; } -- (void)setShowsDivider:(BOOL)showDivider { - [[self backgroundGradientView] setShowsDivider:showDivider]; +- (void)setDividerOpacity:(CGFloat)opacity { + BackgroundGradientView* view = [self backgroundGradientView]; + [view setShowsDivider:(opacity > 0 ? YES : NO)]; + + // We may not have a toolbar view (e.g., popup windows only have a location + // bar). + if ([view isKindOfClass:[ToolbarView class]]) { + ToolbarView* toolbarView = (ToolbarView*)view; + [toolbarView setDividerOpacity:opacity]; + } } - (NSString*)view:(NSView*)view diff --git a/chrome/browser/cocoa/toolbar_view.h b/chrome/browser/cocoa/toolbar_view.h index dee3a92..678fe757a 100644 --- a/chrome/browser/cocoa/toolbar_view.h +++ b/chrome/browser/cocoa/toolbar_view.h @@ -12,7 +12,14 @@ // this time it only draws a gradient. Future changes (e.g. themes) // may require new functionality here. -@interface ToolbarView : BackgroundGradientView +@interface ToolbarView : BackgroundGradientView { + @private + // The opacity of the divider line (at the bottom of the toolbar); used when + // the detached bookmark bar is morphing to the normal bar and vice versa. + CGFloat dividerOpacity_; +} + +@property(assign, nonatomic) CGFloat dividerOpacity; @end #endif // CHROME_BROWSER_COCOA_TOOLBAR_VIEW_H_ diff --git a/chrome/browser/cocoa/toolbar_view.mm b/chrome/browser/cocoa/toolbar_view.mm index e8111d0..d8ce333 100644 --- a/chrome/browser/cocoa/toolbar_view.mm +++ b/chrome/browser/cocoa/toolbar_view.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. + // 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. @@ -6,6 +6,8 @@ @implementation ToolbarView +@synthesize dividerOpacity = dividerOpacity_; + // Prevent mouse down events from moving the parent window around. - (BOOL)mouseDownCanMoveWindow { return NO; @@ -19,4 +21,9 @@ [self drawBackground]; } +// Override of |-[BackgroundGradientView strokeColor]|; make it respect opacity. +- (NSColor*)strokeColor { + return [[super strokeColor] colorWithAlphaComponent:[self dividerOpacity]]; +} + @end diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 7934790..db813c6 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1074,10 +1074,11 @@ 'browser/cocoa/bookmark_bar_constants.h', 'browser/cocoa/bookmark_bar_controller.h', 'browser/cocoa/bookmark_bar_controller.mm', - 'browser/cocoa/bookmark_bar_view.h', - 'browser/cocoa/bookmark_bar_view.mm', + 'browser/cocoa/bookmark_bar_state.h', 'browser/cocoa/bookmark_bar_toolbar_view.h', 'browser/cocoa/bookmark_bar_toolbar_view.mm', + 'browser/cocoa/bookmark_bar_view.h', + 'browser/cocoa/bookmark_bar_view.mm', 'browser/cocoa/bookmark_bubble_controller.h', 'browser/cocoa/bookmark_bubble_controller.mm', 'browser/cocoa/bookmark_button.h', |