summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/cocoa/animatable_view.h8
-rw-r--r--chrome/browser/cocoa/animatable_view.mm5
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.h44
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller.mm327
-rw-r--r--chrome/browser/cocoa/bookmark_bar_controller_unittest.mm93
-rw-r--r--chrome/browser/cocoa/bookmark_bar_state.h61
-rw-r--r--chrome/browser/cocoa/bookmark_bar_toolbar_view.h7
-rw-r--r--chrome/browser/cocoa/bookmark_bar_toolbar_view.mm68
-rw-r--r--chrome/browser/cocoa/bookmark_bar_toolbar_view_unittest.mm56
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm44
-rw-r--r--chrome/browser/cocoa/browser_window_controller_unittest.mm1
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h7
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm13
-rw-r--r--chrome/browser/cocoa/toolbar_view.h9
-rw-r--r--chrome/browser/cocoa/toolbar_view.mm9
-rwxr-xr-xchrome/chrome.gyp5
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',