summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view.h24
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_container_view.mm99
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.h3
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.mm62
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_overflow_menu.h16
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_overflow_menu.mm9
-rwxr-xr-xchrome/chrome_browser.gypi2
7 files changed, 198 insertions, 17 deletions
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view.h b/chrome/browser/cocoa/extensions/browser_actions_container_view.h
index 6a50b8b..73cee1b 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view.h
+++ b/chrome/browser/cocoa/extensions/browser_actions_container_view.h
@@ -7,6 +7,9 @@
#import <Cocoa/Cocoa.h>
+#import "base/scoped_nsobject.h"
+
+@class MenuButton;
@class BrowserActionButton;
// Sent when a user-initiated drag to resize the container is initiated.
@@ -18,10 +21,20 @@ extern const NSString* kBrowserActionGrippyDraggingNotification;
// Sent when a user-initiated drag to resize the container has finished.
extern const NSString* kBrowserActionGrippyDragFinishedNotification;
+// The width of the chevron button in pixels.
+extern const CGFloat kChevronWidth;
+
+
// The view that encompasses the Browser Action buttons in the toolbar and
// provides mechanisms for resizing.
@interface BrowserActionsContainerView : NSView {
@private
+ // The currently running animation.
+ scoped_nsobject<NSAnimation> animation_;
+
+ // The chevron button used when Browser Actions are hidden.
+ scoped_nsobject<MenuButton> chevronMenuButton_;
+
// The frame encompasing the grippy used for resizing the container.
NSRect grippyRect_;
@@ -58,14 +71,19 @@ extern const NSString* kBrowserActionGrippyDragFinishedNotification;
// that |resizeDeltaX| is accurate.
- (void)resizeToWidth:(CGFloat)width animate:(BOOL)animate;
-// Returns the (visible) button at the given index in the view's hierarchy.
-- (BrowserActionButton*)buttonAtIndex:(NSUInteger)index;
-
// Returns the change in the x-pos of the frame rect during resizing. Meant to
// be queried when a NSViewFrameDidChangeNotification is fired to determine
// placement of surrounding elements.
- (CGFloat)resizeDeltaX;
+// Returns whether the chevron button is currently hidden or in the process of
+// being hidden (fading out). Will return NO if it is not hidden or is in the
+// process of fading in.
+- (BOOL)chevronIsHidden;
+
+// Sets whether to show the chevron button.
+- (void)setChevronHidden:(BOOL)hidden animate:(BOOL)animate;
+
@property(nonatomic) BOOL canDragLeft;
@property(nonatomic) BOOL canDragRight;
@property(nonatomic) BOOL grippyPinned;
diff --git a/chrome/browser/cocoa/extensions/browser_actions_container_view.mm b/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
index ce78490..82490a5 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
+++ b/chrome/browser/cocoa/extensions/browser_actions_container_view.mm
@@ -4,9 +4,14 @@
#include <algorithm>
+#include "app/resource_bundle.h"
+#include "base/logging.h"
#import "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/extensions/browser_action_button.h"
#import "chrome/browser/cocoa/extensions/browser_actions_container_view.h"
+#import "chrome/browser/cocoa/menu_button.h"
+#include "grit/theme_resources.h"
+#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
extern const NSString* kBrowserActionGrippyDragStartedNotification =
@"BrowserActionGrippyDragStartedNotification";
@@ -14,9 +19,12 @@ extern const NSString* kBrowserActionGrippyDraggingNotification =
@"BrowserActionGrippyDraggingNotification";
extern const NSString* kBrowserActionGrippyDragFinishedNotification =
@"BrowserActionGrippyDragFinishedNotification";
+extern const CGFloat kChevronWidth = 14.0;
namespace {
-const CGFloat kAnimationDuration = 0.1;
+const CGFloat kAnimationDuration = 0.2;
+const CGFloat kChevronHeight = 28.0;
+const CGFloat kChevronRightPadding = 5.0;
const CGFloat kGrippyLowerPadding = 4.0;
const CGFloat kGrippyUpperPadding = 8.0;
const CGFloat kGrippyWidth = 10.0;
@@ -31,6 +39,7 @@ const CGFloat kUpperPadding = 9.0;
@interface BrowserActionsContainerView(Private)
- (NSCursor*)appropriateCursorForGrippy;
- (void)drawGrippy;
+- (void)updateChevronPosition;
@end
@implementation BrowserActionsContainerView
@@ -44,6 +53,9 @@ const CGFloat kUpperPadding = 9.0;
- (id)initWithFrame:(NSRect)frameRect {
if ((self = [super initWithFrame:frameRect])) {
grippyRect_ = NSMakeRect(0.0, 0.0, kGrippyWidth, NSHeight([self bounds]));
+ animation_.reset([[NSViewAnimation alloc] init]);
+ [animation_ setDuration:kAnimationDuration];
+ [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
}
return self;
}
@@ -70,6 +82,11 @@ const CGFloat kUpperPadding = 9.0;
[self drawGrippy];
}
+- (void)setFrame:(NSRect)frameRect {
+ [super setFrame:frameRect];
+ [self updateChevronPosition];
+}
+
// Draws the area that the user can use to resize the container. Currently, two
// vertical "grip" bars.
- (void)drawGrippy {
@@ -112,10 +129,6 @@ const CGFloat kUpperPadding = 9.0;
[self setNeedsDisplay:YES];
}
-- (BrowserActionButton*)buttonAtIndex:(NSUInteger)index {
- return [[self subviews] objectAtIndex:index];
-}
-
// Returns the cursor to display over the grippy hover region depending on the
// current drag state.
- (NSCursor*)appropriateCursorForGrippy {
@@ -147,6 +160,8 @@ const CGFloat kUpperPadding = 9.0;
if (!NSMouseInRect(initialDragPoint_, grippyRect_, [self isFlipped]))
return;
+ [self setChevronHidden:YES animate:YES];
+
lastXPos_ = [self frame].origin.x;
userIsResizing_ = YES;
[[NSNotificationCenter defaultCenter]
@@ -175,6 +190,9 @@ const CGFloat kUpperPadding = 9.0;
}
- (void)mouseUp:(NSEvent*)theEvent {
+ if (!userIsResizing_)
+ return;
+
userIsResizing_ = NO;
[[NSNotificationCenter defaultCenter]
postNotificationName:kBrowserActionGrippyDragFinishedNotification
@@ -211,4 +229,75 @@ const CGFloat kUpperPadding = 9.0;
return [self frame].origin.x - lastXPos_;
}
+- (BOOL)chevronIsHidden {
+ if (!chevronMenuButton_.get())
+ return YES;
+
+ if (![animation_ isAnimating])
+ return [chevronMenuButton_ isHidden];
+
+ DCHECK([[animation_ viewAnimations] count] > 0);
+
+ // The chevron is animating in or out. Determine which one and have the return
+ // value reflect where the animation is headed.
+ NSString* effect = [[[animation_ viewAnimations] objectAtIndex:0]
+ valueForKey:NSViewAnimationEffectKey];
+ if (effect == NSViewAnimationFadeInEffect) {
+ return NO;
+ } else if (effect == NSViewAnimationFadeOutEffect) {
+ return YES;
+ }
+
+ NOTREACHED();
+ return YES;
+}
+
+- (void)setChevronHidden:(BOOL)hidden animate:(BOOL)animate {
+ if (hidden == [self chevronIsHidden])
+ return;
+
+ if (!chevronMenuButton_.get()) {
+ chevronMenuButton_.reset([[MenuButton alloc] init]);
+ [chevronMenuButton_ setBordered:NO];
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ [chevronMenuButton_ setImage:rb.GetNSImageNamed(IDR_BOOKMARK_BAR_CHEVRONS)];
+ [self addSubview:chevronMenuButton_];
+ }
+
+ [self updateChevronPosition];
+ // Stop any running animation.
+ [animation_ stopAnimation];
+
+ if (!animate) {
+ [chevronMenuButton_ setHidden:hidden];
+ return;
+ }
+
+ NSDictionary* animationDictionary;
+ if (hidden) {
+ animationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
+ chevronMenuButton_.get(), NSViewAnimationTargetKey,
+ NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey,
+ nil];
+ } else {
+ [chevronMenuButton_ setHidden:NO];
+ animationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
+ chevronMenuButton_.get(), NSViewAnimationTargetKey,
+ NSViewAnimationFadeInEffect, NSViewAnimationEffectKey,
+ nil];
+ }
+ [animation_ setViewAnimations:
+ [NSArray arrayWithObjects:animationDictionary, nil]];
+ [animation_ startAnimation];
+}
+
+- (void)updateChevronPosition {
+ CGFloat xPos = NSWidth([self frame]) - kChevronWidth - kChevronRightPadding;
+ NSRect buttonFrame = NSMakeRect(xPos,
+ kLowerPadding,
+ kChevronWidth,
+ kChevronHeight);
+ [chevronMenuButton_ setFrame:buttonFrame];
+}
+
@end
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.h b/chrome/browser/cocoa/extensions/browser_actions_controller.h
index 4ff528a..cd39283 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.h
+++ b/chrome/browser/cocoa/extensions/browser_actions_controller.h
@@ -49,6 +49,9 @@ extern const NSString* kBrowserActionVisibilityChangedNotification;
// buttons present in the container view. The ID is a string unique to each
// extension.
scoped_nsobject<NSMutableDictionary> buttons_;
+
+ // Array of hidden buttons in the correct order in which the user specified.
+ scoped_nsobject<NSMutableArray> hiddenButtons_;
}
@property(readonly, nonatomic) BrowserActionsContainerView* containerView;
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
index 2d494e4..491c516 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
@@ -39,13 +39,16 @@ const CGFloat kButtonOpacityLeadPadding = 5.0;
withIndex:(NSUInteger)index;
- (void)removeActionButtonForExtension:(Extension*)extension;
- (CGFloat)containerWidthWithButtonCount:(NSUInteger)buttonCount;
+- (NSUInteger)containerButtonCapacity;
- (void)repositionActionButtons;
- (void)updateButtonOpacityAndDragAbilities;
- (void)containerFrameChanged;
+- (void)containerDragStart;
- (void)containerDragging;
- (void)containerDragFinished;
- (int)currentTabId;
- (bool)shouldDisplayBrowserAction:(Extension*)extension;
+- (void)showChevronIfNecessaryWithAnimation:(BOOL)animation;
@end
// A helper class to proxy extension notifications to the view controller's
@@ -133,6 +136,11 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
object:containerView_];
[[NSNotificationCenter defaultCenter]
addObserver:self
+ selector:@selector(containerDragStart)
+ name:kBrowserActionGrippyDragStartedNotification
+ object:containerView_];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
selector:@selector(containerDragging)
name:kBrowserActionGrippyDraggingNotification
object:containerView_];
@@ -142,8 +150,10 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
name:kBrowserActionGrippyDragFinishedNotification
object:containerView_];
+ hiddenButtons_.reset([[NSMutableArray alloc] init]);
buttons_.reset([[NSMutableDictionary alloc] init]);
[self createButtons];
+ [self showChevronIfNecessaryWithAnimation:NO];
}
return self;
@@ -213,10 +223,14 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
if (!buttonKey)
return;
+
[buttons_ setObject:newButton forKey:buttonKey];
- [containerView_ addSubview:newButton];
- if (index >= [self visibleButtonCount])
+ if (index < [self containerButtonCapacity]) {
+ [containerView_ addSubview:newButton];
+ } else {
+ [hiddenButtons_ addObject:newButton];
[newButton setAlphaValue:0.0];
+ }
[self repositionActionButtons];
[containerView_ setNeedsDisplay:YES];
@@ -237,6 +251,10 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
return;
[button removeFromSuperview];
+ // It may or may not be hidden, but it won't matter to NSMutableArray either
+ // way.
+ [hiddenButtons_ removeObject:button];
+
[buttons_ removeObjectForKey:buttonKey];
if ([buttons_ count] == 0) {
// No more buttons? Hide the container.
@@ -273,10 +291,22 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
if (buttonCount > 0) {
width = kGrippyXOffset + kContainerPadding +
(buttonCount * (kBrowserActionWidth + kBrowserActionButtonPadding));
+ // Make room for the chevron if necessary.
+ if ([self buttonCount] != [self visibleButtonCount])
+ width += kChevronWidth + kBrowserActionButtonPadding;
}
return width;
}
+- (NSUInteger)containerButtonCapacity {
+ CGFloat containerWidth = [self savedWidth];
+ if (containerWidth == 0)
+ containerWidth = [self containerWidthWithButtonCount:[self buttonCount]];
+
+ return (containerWidth - kGrippyXOffset + kContainerPadding) /
+ (kBrowserActionWidth + kBrowserActionButtonPadding);
+}
+
// Resizes the container given the number of visible buttons in the container,
// taking into account the size of the grippy. Also updates the persistent
// width preference.
@@ -285,6 +315,8 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
[self containerWidthWithButtonCount:[self visibleButtonCount]];
[containerView_ resizeToWidth:width animate:animate];
+ [self showChevronIfNecessaryWithAnimation:YES];
+
if (!profile_->IsOffTheRecord())
profile_->GetPrefs()->SetReal(prefs::kBrowserActionContainerWidth,
NSWidth([containerView_ frame]));
@@ -322,6 +354,13 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
[self updateButtonOpacityAndDragAbilities];
}
+- (void)containerDragStart {
+ while([hiddenButtons_ count] > 0) {
+ [containerView_ addSubview:[hiddenButtons_ objectAtIndex:0]];
+ [hiddenButtons_ removeObjectAtIndex:0];
+ }
+}
+
- (void)containerDragging {
[[NSNotificationCenter defaultCenter]
postNotificationName:kBrowserActionGrippyDraggingNotification
@@ -337,9 +376,14 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
CGFloat intersectionWidth =
NSWidth(NSIntersectionRect([containerView_ bounds], buttonFrame));
+ // Pad the threshold by 5 pixels in order to have the buttons hide more
+ // easily.
if (([containerView_ grippyPinned] && intersectionWidth > 0) ||
- (intersectionWidth <= (NSWidth(buttonFrame) / 2)))
+ (intersectionWidth <= (NSWidth(buttonFrame) / 2) + 5.0)) {
[button setAlphaValue:0.0];
+ [button removeFromSuperview];
+ [hiddenButtons_ addObject:button];
+ }
}
[self resizeContainerWithAnimation:NO];
@@ -350,12 +394,7 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
}
- (NSUInteger)visibleButtonCount {
- int count = 0;
- for (BrowserActionButton* button in [buttons_ allValues]) {
- if ([button alphaValue] > 0.0)
- ++count;
- }
- return count;
+ return [buttons_ count] - [hiddenButtons_ count];
}
- (void)browserActionClicked:(BrowserActionButton*)sender {
@@ -434,6 +473,11 @@ class ExtensionsServiceObserverBridge : public NotificationObserver,
return profile_->GetPrefs()->GetReal(prefs::kBrowserActionContainerWidth);
}
+- (void)showChevronIfNecessaryWithAnimation:(BOOL)animation {
+ BOOL hideChevron = [self buttonCount] == [self visibleButtonCount];
+ [containerView_ setChevronHidden:hideChevron animate:animation];
+}
+
+ (void)registerUserPrefs:(PrefService*)prefs {
prefs->RegisterRealPref(prefs::kBrowserActionContainerWidth, 0);
}
diff --git a/chrome/browser/cocoa/extensions/browser_actions_overflow_menu.h b/chrome/browser/cocoa/extensions/browser_actions_overflow_menu.h
new file mode 100644
index 0000000..aee3b42
--- /dev/null
+++ b/chrome/browser/cocoa/extensions/browser_actions_overflow_menu.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2010 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_EXTENSIONS_BROWSER_ACTIONS_OVERFLOW_MENU_
+#define CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_OVERFLOW_MENU_
+
+#import <Cocoa/Cocoa.h>
+
+@interface BrowserActionsOverflowMenu : NSMenu {
+
+}
+
+@end
+
+#endif // CHROME_BROWSER_COCOA_EXTENSIONS_BROWSER_ACTIONS_OVERFLOW_MENU_
diff --git a/chrome/browser/cocoa/extensions/browser_actions_overflow_menu.mm b/chrome/browser/cocoa/extensions/browser_actions_overflow_menu.mm
new file mode 100644
index 0000000..25b967a
--- /dev/null
+++ b/chrome/browser/cocoa/extensions/browser_actions_overflow_menu.mm
@@ -0,0 +1,9 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "browser_actions_overflow_menu.h"
+
+@implementation BrowserActionsOverflowMenu
+
+@end
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 2cf75b5..9ce744d 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -597,6 +597,8 @@
'browser/cocoa/extensions/browser_actions_container_view.mm',
'browser/cocoa/extensions/browser_actions_controller.h',
'browser/cocoa/extensions/browser_actions_controller.mm',
+ 'browser/cocoa/extensions/browser_actions_overflow_menu.h',
+ 'browser/cocoa/extensions/browser_actions_overflow_menu.mm',
'browser/cocoa/extensions/extension_action_context_menu.h',
'browser/cocoa/extensions/extension_action_context_menu.mm',
'browser/cocoa/extensions/extension_popup_controller.h',