Index: chrome/browser/cocoa/bookmark_bar_controller.mm |
=================================================================== |
--- chrome/browser/cocoa/bookmark_bar_controller.mm (revision 30216) |
+++ chrome/browser/cocoa/bookmark_bar_controller.mm (working copy) |
@@ -52,6 +52,10 @@ |
- (void)tagEmptyMenu:(NSMenu*)menu; |
- (void)clearMenuTagMap; |
- (int)preferredHeight; |
+- (void)addNonBookmarkButtonsToView; |
+- (void)addButtonsToView; |
+- (void)resizeButtons; |
+- (void)centerNoItemsLabel; |
@end |
@implementation BookmarkBarController |
@@ -105,16 +109,21 @@ |
// done. Thus, this call is (almost) last. |
bridge_.reset(new BookmarkBarBridge(self, bookmarkModel_)); |
+ DCHECK([offTheSideButton_ attachedMenu]); |
+ |
+ // To make life happier when the bookmark bar is floating, the |
+ // chevron is a child of the button view. |
+ [offTheSideButton_ removeFromSuperview]; |
+ [buttonView_ addSubview:offTheSideButton_]; |
+ |
// When resized we may need to add new buttons, or remove them (if |
// no longer visible), or add/remove the "off the side" menu. |
[[self view] setPostsFrameChangedNotifications:YES]; |
[[NSNotificationCenter defaultCenter] |
- addObserver:self |
- selector:@selector(frameDidChange) |
- name:NSViewFrameDidChangeNotification |
- object:[self view]]; |
- |
- DCHECK([offTheSideButton_ attachedMenu]); |
+ addObserver:self |
+ selector:@selector(frameDidChange) |
+ name:NSViewFrameDidChangeNotification |
+ object:[self view]]; |
} |
// Method is the same as [self view], but is provided to be explicit. |
@@ -127,18 +136,28 @@ |
[self showBookmarkBar:YES immediately:YES]; |
} |
-// Check if we should enable the off-the-side button. |
+// Position the off-the-side chevron to the left of the otherBookmarks button. |
+- (void)positionOffTheSideButton { |
+ NSRect frame = [offTheSideButton_ frame]; |
+ frame.origin.x = ([otherBookmarksButton_ frame].origin.x - |
+ (frame.size.width + bookmarks::kBookmarkHorizontalPadding)); |
+ [offTheSideButton_ setFrame:frame]; |
+} |
+ |
+// Check if we should enable or disable the off-the-side chevron. |
+// Assumes that buttons which don't fit in the parent view are removed |
+// from it. |
+// |
// TODO(jrg): when we are smarter about creating buttons (e.g. don't |
// bother creating buttons which aren't visible), we'll have to be |
// smarter here too. |
-- (void)checkHideOffTheSideButton { |
+- (void)showOrHideOffTheSideButton { |
+ // Then determine if we'll hide or show it. |
NSButton* button = [buttons_ lastObject]; |
- if ((!button) || |
- (NSMaxX([button frame]) <= |
- NSMaxX([[button superview] frame]))) { |
+ if (button && ![button superview]) { |
+ [offTheSideButton_ setHidden:NO]; |
+ } else { |
[offTheSideButton_ setHidden:YES]; |
- } else { |
- [offTheSideButton_ setHidden:NO]; |
} |
} |
@@ -147,11 +166,16 @@ |
} |
// Called when our controlled frame has changed size. |
-// TODO(jrg): be smarter (e.g. add/remove buttons as appropriate). |
- (void)frameDidChange { |
- [self checkHideOffTheSideButton]; |
+ [self resizeButtons]; |
+ [self positionOffTheSideButton]; |
+ [self addButtonsToView]; |
+ [self showOrHideOffTheSideButton]; |
+ [self centerNoItemsLabel]; |
+} |
- // Need to keep the "no items" label centered. |
+// 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]; |
@@ -163,6 +187,28 @@ |
[noItemsView setFrameOrigin:newOrigin]; |
} |
+// 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 ([self drawAsFloatingBar]) { |
+ // 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))]; |
+ } |
+} |
+ |
// Show or hide the bar based on the value of |show|. Handles animating the |
// resize of the content view. if |immediately| is YES, make changes |
// immediately instead of using an animator. The routine which enables the bar |
@@ -177,7 +223,8 @@ |
[[self view] setHidden:show ? NO : YES]; |
DCHECK([[self view] isKindOfClass:[BookmarkBarToolbarView class]]); |
- [(BookmarkBarToolbarView*)[self view] layoutViews]; |
+ [self layoutSubviews]; |
+ [self frameDidChange]; |
} |
// We don't change a preference; we only change visibility. |
@@ -394,13 +441,10 @@ |
for (NSInteger i = [menu numberOfItems] - 1; i >= 1 ; i--) |
[menu removeItemAtIndex:i]; |
- // Add items corresponding to buttons which aren't displayed or are only |
- // partly displayed. |
- for (NSButton* each_button in buttons_.get()) { |
- if (NSMaxX([each_button frame]) > |
- NSMaxX([[each_button superview] frame])) { |
- [self addNode:[self nodeFromButton:each_button] toMenu:menu]; |
- } |
+ // Add items corresponding to buttons which aren't displayed. |
+ for (NSButton* button in buttons_.get()) { |
+ if (![button superview]) |
+ [self addNode:[self nodeFromButton:button] toMenu:menu]; |
} |
} |
@@ -532,8 +576,8 @@ |
return buttonView_; |
} |
-// Delete all bookmarks from the bookmark bar, and reset knowledge of |
-// bookmarks. |
+// Delete all buttons (bookmarks, chevron, "other bookmarks") from the |
+// bookmark bar; reset knowledge of bookmarks. |
- (void)clearBookmarkBar { |
[buttons_ makeObjectsPerformSelector:@selector(removeFromSuperview)]; |
[buttons_ removeAllObjects]; |
@@ -589,7 +633,7 @@ |
// the height wasn't precisely zero. The previous author wrote that they were |
// doing this because of an animator, but we are not doing animations for beta |
// so we do not care. |
- bounds.size.height = bookmarks::kBookmarkBarHeight; |
+ bounds.size.height = bookmarks::kBookmarkButtonHeight; |
NSRect frame = NSInsetRect(bounds, |
bookmarks::kBookmarkHorizontalPadding, |
@@ -615,17 +659,17 @@ |
if (delta) { |
frame.size.width = desiredSize; |
[button setFrame:frame]; |
- for (NSButton* each_button in buttons_.get()) { |
- NSRect each_frame = [each_button frame]; |
- if (each_frame.origin.x > frame.origin.x) { |
- each_frame.origin.x += delta; |
- [each_button setFrame:each_frame]; |
+ for (NSButton* button in buttons_.get()) { |
+ NSRect buttonFrame = [button frame]; |
+ if (buttonFrame.origin.x > frame.origin.x) { |
+ buttonFrame.origin.x += delta; |
+ [button setFrame:buttonFrame]; |
} |
} |
} |
// We may have just crossed a threshold to enable the off-the-side |
// button. |
- [self checkHideOffTheSideButton]; |
+ [self showOrHideOffTheSideButton]; |
} |
- (IBAction)openBookmarkMenuItem:(id)sender { |
@@ -636,22 +680,22 @@ |
[urlDelegate_ openBookmarkURL:node->GetURL() disposition:disposition]; |
} |
-// Add all items from the given model to our bookmark bar. |
+// Create buttons for all items in the bookmark node tree. |
// |
// TODO(jrg): write a "build bar" so there is a nice spot for things |
// like the contextual menu which is invoked when not over a |
// bookmark. On Safari that menu has a "new folder" option. |
-- (void)addNodesToBar:(const BookmarkNode*)node { |
+- (void)addNodesToButtonList:(const BookmarkNode*)node { |
BOOL hidden = (node->GetChildCount() == 0) ? NO : YES; |
NSView* item = [buttonView_ noItemTextfield]; |
[item setHidden:hidden]; |
- int x_offset = 0; |
+ int xOffset = 0; |
for (int i = 0; i < node->GetChildCount(); i++) { |
const BookmarkNode* child = node->GetChild(i); |
NSCell* cell = [self cellForBookmarkNode:child]; |
- NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:&x_offset]; |
+ NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:&xOffset]; |
NSButton* button = [[[BookmarkButton alloc] initWithFrame:frame] |
autorelease]; |
DCHECK(button); |
@@ -678,11 +722,96 @@ |
url_string.c_str()]; |
[button setToolTip:tooltip]; |
} |
- // Finally, add it to the bookmark bar. |
- [buttonView_ addSubview:button]; |
} |
} |
+// Add non-bookmark buttons to the view. This includes the chevron |
+// and the "other bookmarks" button. Technically "other bookmarks" is |
+// a bookmark button but it is treated specially. Only needs to be |
+// called when these buttons are new or when the bookmark bar is |
+// cleared (e.g. on a loaded: call). Unlike addButtonsToView below, |
+// we don't need to add/remove these dynamically in response to window |
+// resize. |
+- (void)addNonBookmarkButtonsToView { |
+ [buttonView_ addSubview:otherBookmarksButton_.get()]; |
+ [buttonView_ addSubview:offTheSideButton_]; |
+} |
+ |
+// Add bookmark buttons to the view only if they are completely |
+// visible and don't overlap the "other bookmarks". Remove buttons |
+// which are clipped. Called when building the bookmark bar and when |
+// the window resizes. |
+- (void)addButtonsToView { |
+ NSView* superview = nil; |
+ for (NSButton* button in buttons_.get()) { |
+ superview = [button superview]; |
+ if (NSMaxX([button frame]) <= NSMinX([offTheSideButton_ frame])) { |
+ if (!superview) |
+ [buttonView_ addSubview:button]; |
+ } else { |
+ if (superview) |
+ [button removeFromSuperview]; |
+ } |
+ } |
+} |
+ |
+// Helper for resizeButtons to resize buttons based on a new parent |
+// view height. |
+- (void)resizeButtonsInArray:(NSArray*)array { |
+ NSRect parentBounds = [buttonView_ bounds]; |
+ CGFloat height = (bookmarks::kBookmarkButtonHeight - |
+ (bookmarks::kBookmarkVerticalPadding*2)); |
+ for (NSButton* button in array) { |
+ NSRect frame = [button frame]; |
+ frame.size.height = height; |
+ [button setFrame:frame]; |
+ } |
+} |
+ |
+// Resize our buttons; the parent view height may have changed. This |
+// applies to all bookmarks, the chevron, and the "Other Bookmarks" |
+- (void)resizeButtons { |
+ [self resizeButtonsInArray:buttons_.get()]; |
+ NSMutableArray* array = [NSMutableArray arrayWithObject:offTheSideButton_]; |
+ // We must handle resize before the bookmarks are loaded. If not loaded, |
+ // we have no otherBookmarksButton_ yet. |
+ if (otherBookmarksButton_.get()) |
+ [array addObject:otherBookmarksButton_.get()]; |
+ [self resizeButtonsInArray:array]; |
+} |
+ |
+// Create the button for "Other Bookmarks" on the right of the bar. |
+- (void)createOtherBookmarksButton { |
+ // Can't create this until the model is loaded, but only need to |
+ // create it once. |
+ if (otherBookmarksButton_.get()) |
+ return; |
+ |
+ // TODO(jrg): remove duplicate code |
+ NSCell* cell = [self cellForBookmarkNode:bookmarkModel_->other_node()]; |
+ int ignored = 0; |
+ NSRect frame = [self frameForBookmarkButtonFromCell:cell xOffset:&ignored]; |
+ frame.origin.x = [[self buttonView] bounds].size.width - frame.size.width; |
+ frame.origin.x -= bookmarks::kBookmarkHorizontalPadding; |
+ NSButton* button = [[BookmarkButton alloc] initWithFrame:frame]; |
+ otherBookmarksButton_.reset(button); |
+ |
+ // Peg at right; keep same height as bar. |
+ [button setAutoresizingMask:(NSViewMinXMargin)]; |
+ [button setCell:cell]; |
+ [button setTarget:self]; |
+ [button setAction:@selector(openFolderMenuFromButton:)]; |
+ [buttonView_ addSubview:button]; |
+ |
+ // Now that it's here, move the chevron over. |
+ NSRect oframe = [offTheSideButton_ frame]; |
+ oframe.origin.x = frame.origin.x - (oframe.size.width + |
+ bookmarks::kBookmarkHorizontalPadding); |
+ |
+ // Force it to be the right size, right now. |
+ [self resizeButtons]; |
+} |
+ |
// TODO(jrg): for now this is brute force. |
- (void)loaded:(BookmarkModel*)model { |
DCHECK(model == bookmarkModel_); |
@@ -691,8 +820,13 @@ |
// Else brute force nuke and build. |
const BookmarkNode* node = model->GetBookmarkBarNode(); |
[self clearBookmarkBar]; |
- [self addNodesToBar:node]; |
- [self checkHideOffTheSideButton]; |
+ [self addNodesToButtonList:node]; |
+ [self createOtherBookmarksButton]; |
+ [self resizeButtons]; |
+ [self positionOffTheSideButton]; |
+ [self addNonBookmarkButtonsToView]; |
+ [self addButtonsToView]; |
+ [self showOrHideOffTheSideButton]; |
} |
- (void)beingDeleted:(BookmarkModel*)model { |
@@ -767,4 +901,12 @@ |
return buttons_.get(); |
} |
+- (NSButton*)offTheSideButton { |
+ return offTheSideButton_; |
+} |
+ |
+- (NSButton*)otherBookmarksButton { |
+ return otherBookmarksButton_.get(); |
+} |
+ |
@end |