Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: chrome/browser/cocoa/bookmark_bar_controller.mm

Issue 384105: Mac: Animate the bookmark bar showing/hiding. (Closed)
Patch Set: Comments added per rohitrao's review. Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "app/l10n_util_mac.h" 5 #include "app/l10n_util_mac.h"
6 #include "app/resource_bundle.h" 6 #include "app/resource_bundle.h"
7 #include "base/mac_util.h" 7 #include "base/mac_util.h"
8 #include "base/sys_string_conversions.h" 8 #include "base/sys_string_conversions.h"
9 #include "chrome/browser/bookmarks/bookmark_editor.h" 9 #include "chrome/browser/bookmarks/bookmark_editor.h"
10 #include "chrome/browser/bookmarks/bookmark_model.h" 10 #include "chrome/browser/bookmarks/bookmark_model.h"
11 #include "chrome/browser/browser.h" 11 #include "chrome/browser/browser.h"
12 #include "chrome/browser/browser_list.h" 12 #include "chrome/browser/browser_list.h"
13 #import "chrome/browser/cocoa/background_gradient_view.h"
13 #import "chrome/browser/cocoa/bookmark_bar_bridge.h" 14 #import "chrome/browser/cocoa/bookmark_bar_bridge.h"
14 #import "chrome/browser/cocoa/bookmark_bar_constants.h" 15 #import "chrome/browser/cocoa/bookmark_bar_constants.h"
15 #import "chrome/browser/cocoa/bookmark_bar_controller.h" 16 #import "chrome/browser/cocoa/bookmark_bar_controller.h"
16 #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h" 17 #import "chrome/browser/cocoa/bookmark_bar_toolbar_view.h"
17 #import "chrome/browser/cocoa/bookmark_bar_view.h" 18 #import "chrome/browser/cocoa/bookmark_bar_view.h"
18 #import "chrome/browser/cocoa/bookmark_button_cell.h" 19 #import "chrome/browser/cocoa/bookmark_button_cell.h"
19 #import "chrome/browser/cocoa/bookmark_editor_controller.h" 20 #import "chrome/browser/cocoa/bookmark_editor_controller.h"
20 #import "chrome/browser/cocoa/bookmark_name_folder_controller.h" 21 #import "chrome/browser/cocoa/bookmark_name_folder_controller.h"
21 #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h" 22 #import "chrome/browser/cocoa/bookmark_menu_cocoa_controller.h"
22 #import "chrome/browser/cocoa/event_utils.h" 23 #import "chrome/browser/cocoa/event_utils.h"
23 #import "chrome/browser/cocoa/menu_button.h" 24 #import "chrome/browser/cocoa/menu_button.h"
24 #import "chrome/browser/cocoa/toolbar_controller.h" 25 #import "chrome/browser/cocoa/toolbar_controller.h"
25 #import "chrome/browser/cocoa/view_resizer.h" 26 #import "chrome/browser/cocoa/view_resizer.h"
26 #include "chrome/browser/metrics/user_metrics.h" 27 #include "chrome/browser/metrics/user_metrics.h"
27 #include "chrome/browser/profile.h" 28 #include "chrome/browser/profile.h"
28 #include "chrome/browser/tab_contents/tab_contents.h" 29 #include "chrome/browser/tab_contents/tab_contents.h"
29 #include "chrome/browser/tab_contents/tab_contents_view.h" 30 #include "chrome/browser/tab_contents/tab_contents_view.h"
30 #include "chrome/common/pref_names.h" 31 #include "chrome/common/pref_names.h"
31 #include "chrome/common/pref_service.h" 32 #include "chrome/common/pref_service.h"
32 #include "grit/app_resources.h" 33 #include "grit/app_resources.h"
33 #include "grit/generated_resources.h" 34 #include "grit/generated_resources.h"
34 #include "grit/theme_resources.h" 35 #include "grit/theme_resources.h"
35 #include "skia/ext/skia_utils_mac.h" 36 #include "skia/ext/skia_utils_mac.h"
36 #import "third_party/mozilla/include/NSPasteboard+Utils.h" 37 #import "third_party/mozilla/include/NSPasteboard+Utils.h"
37 38
39 // Bookmark bar state changing and animations
40 //
41 // The bookmark bar has three real states: "showing" (a normal bar attached to
42 // the toolbar), "hidden", and "detached" (pretending to be part of the web
43 // content on the NTP). It can, or at least should be able to, animate between
44 // these states. There are several complications even without animation:
45 // - The placement of the bookmark bar is done by the BWC, and it needs to know
46 // the state in order to place the bookmark bar correctly (immediately below
47 // the toolbar when showing, below the infobar when detached).
48 // - The "divider" (a black line) needs to be drawn by either the toolbar (when
49 // the bookmark bar is hidden or detached) or by the bookmark bar (when it is
50 // showing). It should not be drawn by both.
51 // - The toolbar needs to vertically "compress" when the bookmark bar is
52 // showing. This ensures the proper display of both the bookmark bar and the
53 // toolbar, and gives a padded area around the bookmark bar items for right
54 // clicks, etc.
55 //
56 // Our model is that the BWC controls us and also the toolbar. We try not to
57 // talk to the browser nor the toolbar directly, instead centralizing control in
58 // the BWC. The key method by which the BWC controls us is
59 // |-updateAndShowNormalBar:showDetachedBar:withAnimation:|. This invokes state
60 // changes, and at appropriate times we request that the BWC do things for us
61 // via either the resize delegate or our general delegate. If the BWC needs any
62 // information about what it should do, or tell the toolbar to do, it can then
63 // query us back (e.g., |-isShownAs...|, |-getDesiredToolbarHeightCompression|,
64 // |-shouldToolbarShowDivider|, etc.).
65 //
66 // Animation-related complications:
67 // - Compression of the toolbar is touchy during animation. It must not be
68 // compressed while the bookmark bar is animating to/from showing (from/to
69 // hidden), otherwise it would look like the bookmark bar's contents are
70 // sliding out of the controls inside the toolbar. As such, we have to make
71 // sure that the bookmark bar is shown at the right location and at the
72 // right height (at various points in time).
73 // - Showing the divider is also complicated during animation between hidden
74 // and showing. We have to make sure that the toolbar does not show the
75 // divider despite the fact that it's not compressed. The exception to this
76 // is at the beginning/end of the animation when the toolbar is still
77 // uncompressed but the bookmark bar has height 0. If we're not careful, we
78 // get a flicker at this point.
79 // - We have to ensure that we do the right thing if we're told to change state
80 // while we're running an animation. The generic/easy thing to do is to jump
81 // to the end state of our current animation, and (if the new state change
82 // again involves an animation) begin the new animation. We can do better
83 // than that, however, and sometimes just change the current animation to go
84 // to the new end state (e.g., by "reversing" the animation in the showing ->
85 // hidden -> showing case). We also have to ensure that demands to
86 // immediately change state are always honoured.
87 //
88 // Pointers to animation logic:
89 // - |-moveToVisualState:withAnimation:| starts animations, deciding which ones
90 // we know how to handle.
91 // - |showBookmarkBarWithAnimation:| has most of the actual logic.
92 // - |-getDesiredToolbarHeightCompression| and |-shouldToolbarShowDivider|
93 // contain related logic.
94 // - The BWC's |-layoutSubviews| needs to know how to position things.
95 // - The BWC should implement |-bookmarkBar:didChangeFromState:toState:| and
96 // |-bookmarkBar:willAnimateFromState:toState:| in order to inform the
97 // toolbar of required changes.
98
99 namespace {
100
101 // Overlap (in pixels) between the toolbar and the bookmark bar (when showing in
102 // normal mode).
103 const CGFloat kBookmarkBarOverlap = 6.0;
104
105 // Duration of the bookmark bar animations.
106 const NSTimeInterval kBookmarkBarAnimationDuration = 0.12;
107
108 } // namespace
109
38 // Specialization of NSButton that responds to middle-clicks. By default, 110 // Specialization of NSButton that responds to middle-clicks. By default,
39 // NSButton ignores them. 111 // NSButton ignores them.
40 @interface BookmarkButton : NSButton 112 @interface BookmarkButton : NSButton
41 @end 113 @end
42 114
43 @implementation BookmarkButton 115 @implementation BookmarkButton
44 - (void)otherMouseUp:(NSEvent*) event { 116 - (void)otherMouseUp:(NSEvent*) event {
45 [self performClick:self]; 117 [self performClick:self];
46 } 118 }
47 @end 119 @end
48 120
49 @interface BookmarkBarController(Private) 121 @interface BookmarkBarController(Private)
50 - (void)showBookmarkBar:(BOOL)enable immediately:(BOOL)immediately; 122 // Determines the appropriate state for the given situation.
123 + (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
124 showDetachedBar:(BOOL)showDetachedBar;
125
126 // Moves to the given next state (from the current state), possibly animating.
127 // If |animate| is NO, it will stop any running animation and jump to the given
128 // state. If YES, it may either (depending on implementation) jump to the end of
129 // the current animation and begin the next one, or stop the current animation
130 // mid-flight and animate to the next state.
131 - (void)moveToVisualState:(bookmarks::VisualState)nextVisualState
132 withAnimation:(BOOL)animate;
133
134 // Return the backdrop to the bookmark bar as various types.
135 - (BackgroundGradientView*)backgroundGradientView;
136 - (AnimatableView*)animatableView;
137
138 // Puts stuff into the final visual state without animating, stopping a running
139 // animation if necessary.
140 - (void)finalizeVisualState;
141
142 // Stops any current animation in its tracks (midway).
143 - (void)stopCurrentAnimation;
144
145 // Show/hide the bookmark bar. Handles animating the resize of the content view.
146 // if |animate| is YES, the changes are made using the animator; otherwise they
147 // are made immediately.
148 - (void)showBookmarkBarWithAnimation:(BOOL)animate;
149
51 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu; 150 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu;
52 - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu; 151 - (void)addFolderNode:(const BookmarkNode*)node toMenu:(NSMenu*)menu;
53 - (void)tagEmptyMenu:(NSMenu*)menu; 152 - (void)tagEmptyMenu:(NSMenu*)menu;
54 - (void)clearMenuTagMap; 153 - (void)clearMenuTagMap;
55 - (int)preferredHeight; 154 - (int)preferredHeight;
56 - (void)addNonBookmarkButtonsToView; 155 - (void)addNonBookmarkButtonsToView;
57 - (void)addButtonsToView; 156 - (void)addButtonsToView;
58 - (void)resizeButtons; 157 - (void)resizeButtons;
59 - (void)centerNoItemsLabel; 158 - (void)centerNoItemsLabel;
60 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node; 159 - (NSImage*)getFavIconForNode:(const BookmarkNode*)node;
61 @end 160 @end
62 161
63 @implementation BookmarkBarController 162 @implementation BookmarkBarController
64 163
164 @synthesize visualState = visualState_;
165 @synthesize lastVisualState = lastVisualState_;
166 @synthesize delegate = delegate_;
167
65 - (id)initWithBrowser:(Browser*)browser 168 - (id)initWithBrowser:(Browser*)browser
66 initialWidth:(float)initialWidth 169 initialWidth:(float)initialWidth
67 compressDelegate:(id<ToolbarCompressable>)compressDelegate 170 delegate:(id<BookmarkBarControllerDelegate>)delegate
68 resizeDelegate:(id<ViewResizer>)resizeDelegate { 171 resizeDelegate:(id<ViewResizer>)resizeDelegate {
69 if ((self = [super initWithNibName:@"BookmarkBar" 172 if ((self = [super initWithNibName:@"BookmarkBar"
70 bundle:mac_util::MainAppBundle()])) { 173 bundle:mac_util::MainAppBundle()])) {
174 // Initialize to an invalid state.
175 visualState_ = bookmarks::kInvalidState;
176 lastVisualState_ = bookmarks::kInvalidState;
177
71 browser_ = browser; 178 browser_ = browser;
72 initialWidth_ = initialWidth; 179 initialWidth_ = initialWidth;
73 bookmarkModel_ = browser_->profile()->GetBookmarkModel(); 180 bookmarkModel_ = browser_->profile()->GetBookmarkModel();
74 buttons_.reset([[NSMutableArray alloc] init]); 181 buttons_.reset([[NSMutableArray alloc] init]);
75 compressDelegate_ = compressDelegate; 182 delegate_ = delegate;
76 resizeDelegate_ = resizeDelegate; 183 resizeDelegate_ = resizeDelegate;
77 tabObserver_.reset( 184 [[self animatableView] setResizeDelegate:resizeDelegate];
78 new TabStripModelObserverBridge(browser_->tabstrip_model(), self));
79 185
80 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 186 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
81 folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]); 187 folderImage_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
82 defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]); 188 defaultImage_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]);
83 } 189 }
84 return self; 190 return self;
85 } 191 }
86 192
87 - (void)dealloc { 193 - (void)dealloc {
194 // We better stop any in-flight animation if we're being killed.
195 [[self animatableView] stopAnimation];
196
88 // Remove our view from its superview so it doesn't attempt to reference 197 // Remove our view from its superview so it doesn't attempt to reference
89 // it when the controller is gone. 198 // it when the controller is gone.
90 //TODO(dmaclach): Remove -- http://crbug.com/25845 199 //TODO(dmaclach): Remove -- http://crbug.com/25845
91 [[self view] removeFromSuperview]; 200 [[self view] removeFromSuperview];
92 201
93 bridge_.reset(NULL); 202 bridge_.reset(NULL);
94 [[NSNotificationCenter defaultCenter] removeObserver:self]; 203 [[NSNotificationCenter defaultCenter] removeObserver:self];
95 [super dealloc]; 204 [super dealloc];
96 } 205 }
97 206
98 - (void)awakeFromNib { 207 - (void)awakeFromNib {
99 // We default to NOT open, which means height=0. 208 // We default to NOT open, which means height=0.
100 DCHECK([[self view] isHidden]); // Hidden so it's OK to change. 209 DCHECK([[self view] isHidden]); // Hidden so it's OK to change.
101 210
102 // Set our initial height to zero, since that is what the superview 211 // Set our initial height to zero, since that is what the superview
103 // expects. We will resize ourselves open later if needed. 212 // expects. We will resize ourselves open later if needed.
104 [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)]; 213 [[self view] setFrame:NSMakeRect(0, 0, initialWidth_, 0)];
105 214
106 // We are enabled by default. 215 // We are enabled by default.
107 barIsEnabled_ = YES; 216 barIsEnabled_ = YES;
108 217
109 // Don't pass ourself along (as 'self') until our init is completely 218 // Don't pass ourself along (as 'self') until our init is completely
110 // done. Thus, this call is (almost) last. 219 // done. Thus, this call is (almost) last.
111 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); 220 bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_));
112 221
113 DCHECK([offTheSideButton_ attachedMenu]); 222 DCHECK([offTheSideButton_ attachedMenu]);
114 223
115 // To make life happier when the bookmark bar is floating, the 224 // To make life happier when the bookmark bar is floating, the chevron is a
116 // chevron is a child of the button view. 225 // child of the button view.
117 [offTheSideButton_ removeFromSuperview]; 226 [offTheSideButton_ removeFromSuperview];
118 [buttonView_ addSubview:offTheSideButton_]; 227 [buttonView_ addSubview:offTheSideButton_];
119 228
120 // When resized we may need to add new buttons, or remove them (if 229 // When resized we may need to add new buttons, or remove them (if
121 // no longer visible), or add/remove the "off the side" menu. 230 // no longer visible), or add/remove the "off the side" menu.
122 [[self view] setPostsFrameChangedNotifications:YES]; 231 [[self view] setPostsFrameChangedNotifications:YES];
123 [[NSNotificationCenter defaultCenter] 232 [[NSNotificationCenter defaultCenter]
124 addObserver:self 233 addObserver:self
125 selector:@selector(frameDidChange) 234 selector:@selector(frameDidChange)
126 name:NSViewFrameDidChangeNotification 235 name:NSViewFrameDidChangeNotification
127 object:[self view]]; 236 object:[self view]];
128 } 237 }
129 238
130 // Method is the same as [self view], but is provided to be explicit. 239 // (Private) Method is the same as [self view], but is provided to be explicit.
131 - (BackgroundGradientView*)backgroundGradientView { 240 - (BackgroundGradientView*)backgroundGradientView {
241 DCHECK([[self view] isKindOfClass:[BackgroundGradientView class]]);
132 return (BackgroundGradientView*)[self view]; 242 return (BackgroundGradientView*)[self view];
133 } 243 }
134 244
135 - (void)showIfNeeded { 245 // (Private) Method is the same as [self view], but is provided to be explicit.
136 if (browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar)) 246 - (AnimatableView*)animatableView {
137 [self showBookmarkBar:YES immediately:YES]; 247 DCHECK([[self view] isKindOfClass:[AnimatableView class]]);
248 return (AnimatableView*)[self view];
138 } 249 }
139 250
140 // Position the off-the-side chevron to the left of the otherBookmarks button. 251 // Position the off-the-side chevron to the left of the otherBookmarks button.
141 - (void)positionOffTheSideButton { 252 - (void)positionOffTheSideButton {
142 NSRect frame = [offTheSideButton_ frame]; 253 NSRect frame = [offTheSideButton_ frame];
143 if (otherBookmarksButton_.get()) { 254 if (otherBookmarksButton_.get()) {
144 frame.origin.x = ([otherBookmarksButton_ frame].origin.x - 255 frame.origin.x = ([otherBookmarksButton_ frame].origin.x -
145 (frame.size.width + bookmarks::kBookmarkHorizontalPadding) ); 256 (frame.size.width + bookmarks::kBookmarkHorizontalPadding) );
146 [offTheSideButton_ setFrame:frame]; 257 [offTheSideButton_ setFrame:frame];
147 } 258 }
(...skipping 30 matching lines...) Expand all
178 } 289 }
179 290
180 // Keep the "no items" label centered in response to a frame size change. 291 // Keep the "no items" label centered in response to a frame size change.
181 - (void)centerNoItemsLabel { 292 - (void)centerNoItemsLabel {
182 NSView* noItemsView = [buttonView_ noItemTextfield]; 293 NSView* noItemsView = [buttonView_ noItemTextfield];
183 NSRect frame = [noItemsView frame]; 294 NSRect frame = [noItemsView frame];
184 NSRect parent = [buttonView_ bounds]; 295 NSRect parent = [buttonView_ bounds];
185 NSPoint newOrigin; 296 NSPoint newOrigin;
186 newOrigin.x = parent.origin.x + bookmarks::kNoBookmarksHorizontalOffset; 297 newOrigin.x = parent.origin.x + bookmarks::kNoBookmarksHorizontalOffset;
187 newOrigin.y = parent.origin.y + parent.size.height - 298 newOrigin.y = parent.origin.y + parent.size.height -
188 ([self isAlwaysVisible] ? bookmarks::kNoBookmarksVerticalOffset : 299 ([self isShownAsToolbar] ? bookmarks::kNoBookmarksVerticalOffset :
189 bookmarks::kNoBookmarksNTPVerticalOffset); 300 bookmarks::kNoBookmarksNTPVerticalOffset);
190 [noItemsView setFrameOrigin:newOrigin]; 301 [noItemsView setFrameOrigin:newOrigin];
191 } 302 }
192 303
193 // Change the layout of the bookmark bar's subviews in response to a 304 // Change the layout of the bookmark bar's subviews in response to a visibility
194 // visibility change (e.g. show or hide the bar) or style change 305 // change (e.g., show or hide the bar) or style change (attached or floating).
195 // (attached or floating).
196 - (void)layoutSubviews { 306 - (void)layoutSubviews {
197 if ([self drawAsFloatingBar]) { 307 if (visualState_ == bookmarks::kDetachedState) {
198 // The internal bookmark bar should have padding to center it. 308 // The internal bookmark bar should have padding to center it.
199 NSRect frame = [[self view] frame]; 309 NSRect frame = [[self view] frame];
200 [buttonView_ setFrame: 310 [buttonView_ setFrame:
201 NSMakeRect(bookmarks::kNTPBookmarkBarPadding, 311 NSMakeRect(bookmarks::kNTPBookmarkBarPadding,
202 bookmarks::kNTPBookmarkBarPadding, 312 bookmarks::kNTPBookmarkBarPadding,
203 (NSWidth(frame) - 313 (NSWidth(frame) -
204 bookmarks::kNTPBookmarkBarPadding*2), 314 bookmarks::kNTPBookmarkBarPadding*2),
205 (NSHeight(frame) - 315 (NSHeight(frame) -
206 bookmarks::kNTPBookmarkBarPadding))]; 316 bookmarks::kNTPBookmarkBarPadding))];
207 } else { 317 } else {
208 // The frame of our child should be equal to our frame, excluding 318 // The frame of our child should be equal to our frame, excluding
209 // space for stuff on the right side (e.g. off-the-side chevron). 319 // space for stuff on the right side (e.g. off-the-side chevron).
210 NSRect frame = [[self view] frame]; 320 NSRect frame = [[self view] frame];
211 [buttonView_ setFrame:NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame))]; 321 [buttonView_ setFrame:NSMakeRect(0, 0, NSWidth(frame), NSHeight(frame))];
212 } 322 }
213 } 323 }
214 324
215 // Show or hide the bar based on the value of |show|. Handles animating the 325 // (Private)
216 // resize of the content view. if |immediately| is YES, make changes 326 - (void)showBookmarkBarWithAnimation:(BOOL)animate {
217 // immediately instead of using an animator. The routine which enables the bar 327 if (animate) {
218 // will show it if relevant using other mechanisms (the pref) to determine 328 // Animating from hidden to normal bar.
219 // desired state. 329 if (lastVisualState_ == bookmarks::kHiddenState &&
220 - (void)showBookmarkBar:(BOOL)show immediately:(BOOL)immediately { 330 visualState_ == bookmarks::kShowingState) {
221 BOOL compressed = [self isAlwaysVisible]; 331 [[self backgroundGradientView] setShowsDivider:YES];
222 [compressDelegate_ setShouldBeCompressed:compressed]; 332 [[self view] setHidden:NO];
333 AnimatableView* view = [self animatableView];
334 // Height takes into account the extra height we have since the toolbar
335 // only compresses when we're done.
336 [view animateToNewHeight:([self preferredHeight] - kBookmarkBarOverlap)
337 duration:kBookmarkBarAnimationDuration];
338 return;
339 }
223 340
341 // Animating from normal bar to hidden.
342 if (lastVisualState_ == bookmarks::kShowingState &&
343 visualState_ == bookmarks::kHiddenState) {
344 // The toolbar uncompresses immediately at the beginning (otherwise the
345 // slide looks wrong, since we slide into the bottom of stuff in the
346 // toolbar). Do this only if we're at the beginning height since we may
347 // enter this mid-animation.
348 if (NSHeight([[self view] frame]) == bookmarks::kBookmarkBarHeight) {
349 [resizeDelegate_ resizeView:[self view]
350 newHeight:(bookmarks::kBookmarkBarHeight -
351 kBookmarkBarOverlap)];
352 }
353 [[self backgroundGradientView] setShowsDivider:YES];
354 [[self view] setHidden:NO];
355 AnimatableView* view = [self animatableView];
356 [view animateToNewHeight:0
357 duration:kBookmarkBarAnimationDuration];
358 return;
359 }
360
361 // TODO(viettrungluu): other animation cases. Note: will need to fade in/out
362 // divider when animating from/to detached bar (to/from normal bar).
363
364 // Fall through for any cases we don't know about.
365 }
366
367 BOOL show = [self isVisible];
224 CGFloat height = show ? [self preferredHeight] : 0; 368 CGFloat height = show ? [self preferredHeight] : 0;
225 [resizeDelegate_ resizeView:[self view] newHeight:height]; 369 [resizeDelegate_ resizeView:[self view] newHeight:height];
226 [[self view] setHidden:show ? NO : YES];
227 370
228 DCHECK([[self view] isKindOfClass:[BookmarkBarToolbarView class]]); 371 // Only show the divider if showing the normal bookmark bar.
372 BOOL showDivider = (visualState_ == bookmarks::kShowingState ||
373 lastVisualState_ == bookmarks::kShowingState) ? YES : NO;
374 [[self backgroundGradientView] setShowsDivider:showDivider];
375
376 // Make sure we're shown.
377 [[self view] setHidden:(show ? NO : YES)];
229 [self layoutSubviews]; 378 [self layoutSubviews];
230 [self frameDidChange]; 379 [self frameDidChange];
231 } 380 }
232 381
233 // We don't change a preference; we only change visibility. 382 // We don't change a preference; we only change visibility. Preference changing
234 // Preference changing (global state) is handled in 383 // (global state) is handled in |BrowserWindowCocoa::ToggleBookmarkBar()|. We
235 // BrowserWindowCocoa::ToggleBookmarkBar(). We simply update the visibility of 384 // simply update based on what we're told.
236 // the bar based on the current value of the pref.
237 - (void)updateVisibility { 385 - (void)updateVisibility {
238 [self showBookmarkBar:[self isVisible] immediately:YES]; 386 [self showBookmarkBarWithAnimation:NO];
239 } 387 }
240 388
241 - (void)setBookmarkBarEnabled:(BOOL)enabled { 389 - (void)setBookmarkBarEnabled:(BOOL)enabled {
242 barIsEnabled_ = enabled ? YES : NO; 390 barIsEnabled_ = enabled;
243 [self updateVisibility]; 391 [self updateVisibility];
244 } 392 }
245 393
246 - (BOOL)isVisible { 394 - (BOOL)isVisible {
247 return ([self isAlwaysVisible] && barIsEnabled_) || [self isNewTabPage]; 395 return (barIsEnabled_ && (visualState_ == bookmarks::kShowingState ||
396 visualState_ == bookmarks::kDetachedState)) ?
397 YES : NO;
248 } 398 }
249 399
250 - (BOOL)isNewTabPage { 400 - (BOOL)isAnimationRunning {
251 return browser_ && browser_->GetSelectedTabContents() && 401 return (lastVisualState_ == bookmarks::kInvalidState) ? NO : YES;
252 browser_->GetSelectedTabContents()->ShouldShowBookmarkBar();
253 } 402 }
254 403
255 - (BOOL)isAlwaysVisible { 404 - (BOOL)isShownAsToolbar {
256 return browser_ && 405 return (visualState_ == bookmarks::kShowingState) ? YES : NO;
257 browser_->profile()->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar); 406 }
407
408 - (BOOL)isShownAsDetachedBar {
409 return (visualState_ == bookmarks::kDetachedState) ? YES : NO;
410 }
411
412 - (CGFloat)getDesiredToolbarHeightCompression {
413 // Some special cases....
414 if ([self isAnimationRunning]) {
415 // No toolbar compression when animating between showing and hidden.
416 if ((lastVisualState_ == bookmarks::kHiddenState &&
417 visualState_ == bookmarks::kShowingState) ||
418 (lastVisualState_ == bookmarks::kShowingState &&
419 visualState_ == bookmarks::kHiddenState))
420 return 0;
421
422 // TODO(viettrungluu): other animation cases.
423 }
424
425 return (visualState_ == bookmarks::kShowingState) ? kBookmarkBarOverlap : 0;
426 }
427
428 - (BOOL)shouldToolbarShowDivider {
429 // Some special cases....
430 if ([self isAnimationRunning]) {
431 // In general, the toolbar shouldn't show a divider while we're animating
432 // between showing and hidden. The exception is when our height is < 1, in
433 // which case we can't draw it.
434 if ((lastVisualState_ == bookmarks::kHiddenState &&
435 visualState_ == bookmarks::kShowingState) ||
436 (lastVisualState_ == bookmarks::kShowingState &&
437 visualState_ == bookmarks::kHiddenState))
438 return (NSHeight([[self view] frame]) < 1) ? YES : NO;
439
440 // TODO(viettrungluu): other animation cases.
441 }
442
443 return (visualState_ == bookmarks::kShowingState) ? NO : YES;
258 } 444 }
259 445
260 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point { 446 - (BOOL)addURLs:(NSArray*)urls withTitles:(NSArray*)titles at:(NSPoint)point {
261 // TODO(jrg): Support drops on folders etc 447 // TODO(jrg): Support drops on folders etc
262 // TODO(jrg): Use |point|. 448 // TODO(jrg): Use |point|.
263 DCHECK([urls count] == [titles count]); 449 DCHECK([urls count] == [titles count]);
264 const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode(); 450 const BookmarkNode* node = bookmarkModel_->GetBookmarkBarNode();
265 451
266 for (size_t i = 0; i < [urls count]; ++i) { 452 for (size_t i = 0; i < [urls count]; ++i) {
267 bookmarkModel_->AddURL( 453 bookmarkModel_->AddURL(
268 node, 454 node,
269 node->GetChildCount(), 455 node->GetChildCount(),
270 base::SysNSStringToWide([titles objectAtIndex:i]), 456 base::SysNSStringToWide([titles objectAtIndex:i]),
271 GURL([[urls objectAtIndex:i] UTF8String])); 457 GURL([[urls objectAtIndex:i] UTF8String]));
272 } 458 }
273 return YES; 459 return YES;
274 } 460 }
275 461
276 - (int)currentTabContentsHeight { 462 - (int)currentTabContentsHeight {
277 return browser_->GetSelectedTabContents()->view()->GetContainerSize(). 463 return browser_->GetSelectedTabContents() ?
278 height(); 464 browser_->GetSelectedTabContents()->view()->GetContainerSize().height() :
465 0;
279 } 466 }
280 467
281 - (ThemeProvider*)themeProvider { 468 - (ThemeProvider*)themeProvider {
282 return browser_->profile()->GetThemeProvider(); 469 return browser_->profile()->GetThemeProvider();
283 } 470 }
284 471
285 - (BOOL)drawAsFloatingBar {
286 return ![self isAlwaysVisible] && [self isNewTabPage];
287 }
288
289 // Return nil if menuItem has no delegate. 472 // Return nil if menuItem has no delegate.
290 - (BookmarkNode*)nodeFromMenuItem:(id)menuItem { 473 - (BookmarkNode*)nodeFromMenuItem:(id)menuItem {
291 NSCell* cell = reinterpret_cast<NSCell*>([[menuItem menu] delegate]); 474 NSCell* cell = reinterpret_cast<NSCell*>([[menuItem menu] delegate]);
292 if (!cell) 475 if (!cell)
293 return nil; 476 return nil;
294 BookmarkNode* node = static_cast<BookmarkNode*>( 477 BookmarkNode* node = static_cast<BookmarkNode*>(
295 [[cell representedObject] pointerValue]); 478 [[cell representedObject] pointerValue]);
296 return node; 479 return node;
297 } 480 }
298 481
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 menuTagMap_[tag] = menuid; 525 menuTagMap_[tag] = menuid;
343 return tag; 526 return tag;
344 } 527 }
345 528
346 - (void)clearMenuTagMap { 529 - (void)clearMenuTagMap {
347 seedId_ = 0; 530 seedId_ = 0;
348 menuTagMap_.clear(); 531 menuTagMap_.clear();
349 } 532 }
350 533
351 - (int)preferredHeight { 534 - (int)preferredHeight {
352 return [self isAlwaysVisible] ? bookmarks::kBookmarkBarHeight : 535 return [self isShownAsToolbar] ? bookmarks::kBookmarkBarHeight :
353 bookmarks::kNTPBookmarkBarHeight; 536 bookmarks::kNTPBookmarkBarHeight;
354 } 537 }
355 538
356 - (void)selectTabWithContents:(TabContents*)newContents
357 previousContents:(TabContents*)oldContents
358 atIndex:(NSInteger)index
359 userGesture:(bool)wasUserGesture {
360 // We need selectTabWithContents: for when we change from a tab that is the
361 // new tab page to a tab that isn't.
362 [self updateVisibility];
363 }
364
365 - (void)tabChangedWithContents:(TabContents*)contents
366 atIndex:(NSInteger)index
367 loadingOnly:(BOOL)loading {
368 // We need tabChangedWithContents: for when the user clicks a bookmark from
369 // the bookmark bar on the new tab page.
370 [self updateVisibility];
371 }
372
373 // Recursively add the given bookmark node and all its children to 539 // Recursively add the given bookmark node and all its children to
374 // menu, one menu item per node. 540 // menu, one menu item per node.
375 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu { 541 - (void)addNode:(const BookmarkNode*)child toMenu:(NSMenu*)menu {
376 NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child]; 542 NSString* title = [BookmarkMenuCocoaController menuTitleForNode:child];
377 NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title 543 NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:title
378 action:nil 544 action:nil
379 keyEquivalent:@""] autorelease]; 545 keyEquivalent:@""] autorelease];
380 [menu addItem:item]; 546 [menu addItem:item];
381 [item setImage:[self getFavIconForNode:child]]; 547 [item setImage:[self getFavIconForNode:child]];
382 if (child->is_folder()) { 548 if (child->is_folder()) {
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 if (node->is_folder()) 1093 if (node->is_folder())
928 return folderImage_; 1094 return folderImage_;
929 1095
930 const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node); 1096 const SkBitmap& favIcon = bookmarkModel_->GetFavIcon(node);
931 if (!favIcon.isNull()) 1097 if (!favIcon.isNull())
932 return gfx::SkBitmapToNSImage(favIcon); 1098 return gfx::SkBitmapToNSImage(favIcon);
933 1099
934 return defaultImage_; 1100 return defaultImage_;
935 } 1101 }
936 1102
1103 // Determines the appropriate state for the given situation.
1104 + (bookmarks::VisualState)visualStateToShowNormalBar:(BOOL)showNormalBar
1105 showDetachedBar:(BOOL)showDetachedBar {
1106 if (showNormalBar)
1107 return bookmarks::kShowingState;
1108 if (showDetachedBar)
1109 return bookmarks::kDetachedState;
1110 return bookmarks::kHiddenState;
1111 }
1112
1113 - (void)moveToVisualState:(bookmarks::VisualState)nextVisualState
1114 withAnimation:(BOOL)animate {
1115 BOOL isAnimationRunning = [self isAnimationRunning];
1116
1117 // No-op if the next state is the same as the "current" one, subject to the
1118 // following conditions:
1119 // - no animation is running; or
1120 // - an animation is running and |animate| is YES ([*] if it's NO, we'd want
1121 // to cancel the animation and jump to the final state).
1122 if ((nextVisualState == visualState_) && (!isAnimationRunning || animate))
1123 return;
1124
1125 // If an animation is running, we want to finalize it. Otherwise we'd have to
1126 // be able to animate starting from the middle of one type of animation. We
1127 // assume that animations that we know about can be "reversed".
1128 if (isAnimationRunning) {
1129 // Don't cancel if we're going to reverse the animation.
1130 if (nextVisualState != lastVisualState_) {
1131 [self stopCurrentAnimation];
1132 [self finalizeVisualState];
1133 }
1134
1135 // If we're in case [*] above, we can stop here.
1136 if (nextVisualState == visualState_)
1137 return;
1138 }
1139
1140 // Now update with the new state change.
1141 lastVisualState_ = visualState_;
1142 visualState_ = nextVisualState;
1143
1144 if (animate) {
1145 // Take care of any animation cases we know how to handle.
1146
1147 // We know how to handle hidden <-> normal....
1148 if ((lastVisualState_ == bookmarks::kHiddenState &&
1149 visualState_ == bookmarks::kShowingState) ||
1150 (lastVisualState_ == bookmarks::kShowingState &&
1151 visualState_ == bookmarks::kHiddenState)) {
1152 [delegate_ bookmarkBar:self willAnimateFromState:lastVisualState_
1153 toState:visualState_];
1154 [self showBookmarkBarWithAnimation:YES];
1155 return;
1156 }
1157
1158 // TODO(viettrungluu): we don't know about any yet....
1159
1160 // Let any animation cases which we don't know how to handle fall through to
1161 // the unanimated case.
1162 }
1163
1164 // Just jump to the state.
1165 [self finalizeVisualState];
1166 }
1167
1168 // N.B.: |-moveToVisualState:...| will check if this should be a no-op or not.
1169 - (void)updateAndShowNormalBar:(BOOL)showNormalBar
1170 showDetachedBar:(BOOL)showDetachedBar
1171 withAnimation:(BOOL)animate {
1172 bookmarks::VisualState newVisualState =
1173 [BookmarkBarController visualStateToShowNormalBar:showNormalBar
1174 showDetachedBar:showDetachedBar];
1175 [self moveToVisualState:newVisualState
1176 withAnimation:animate];
1177 }
1178
1179 // (Private)
1180 - (void)finalizeVisualState {
1181 // We promise that our delegate that the variables will be finalized before
1182 // the call to |-bookmarkBar:didChangeFromState:toState:|.
1183 bookmarks::VisualState oldVisualState = lastVisualState_;
1184 lastVisualState_ = bookmarks::kInvalidState;
1185
1186 // Notify our delegate.
1187 [delegate_ bookmarkBar:self didChangeFromState:oldVisualState
1188 toState:visualState_];
1189
1190 // Update ourselves visually.
1191 [self updateVisibility];
1192 }
1193
1194 // (Private)
1195 - (void)stopCurrentAnimation {
1196 [[self animatableView] stopAnimation];
1197 }
1198
1199 // Delegate method for |AnimatableView| (a superclass of
1200 // |BookmarkBarToolbarView|).
1201 - (void)animationDidEnd:(NSAnimation*)animation {
1202 [self finalizeVisualState];
1203 }
1204
937 @end 1205 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/bookmark_bar_controller.h ('k') | chrome/browser/cocoa/bookmark_bar_controller_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698