summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-03 20:42:24 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-03 20:42:24 +0000
commit1c977ab1081a4891419e40d6e4b1615c6e2583fb (patch)
treec82a78a053227719ae46739ef67f807ad095db4a /chrome/browser
parent588ac782287d7cbe82b71b825f268b8e0f026174 (diff)
downloadchromium_src-1c977ab1081a4891419e40d6e4b1615c6e2583fb.zip
chromium_src-1c977ab1081a4891419e40d6e4b1615c6e2583fb.tar.gz
chromium_src-1c977ab1081a4891419e40d6e4b1615c6e2583fb.tar.bz2
(Mac) Make the Page/Wrench buttons place their menu in the right place.
Also makes the buttons drag-able -- you can drag or click and wait to open their menu. Lucky for me, I wrote reusable code. To do (not now): The "off-the-end" button on the bookmark bar needs the same fix. Bug (not to be fixed now): The menu doesn't do the right thing when the window is moved off the left edge to the screen -- it doesn't open to the right in the correct fashion. Nor does it do the proper thing when you move the window off the bottom edge of the screen -- it doesn't open upwards entirely correctly. <shrug> BUG=18572 TEST=Click on the Page and Wrench menu buttons and observe. Also test \ dragging to open. Review URL: http://codereview.chromium.org/174556 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25362 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.h5
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.mm4
-rw-r--r--chrome/browser/cocoa/menu_button.h24
-rw-r--r--chrome/browser/cocoa/menu_button.mm118
-rw-r--r--chrome/browser/cocoa/menu_button_unittest.mm64
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h15
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm13
7 files changed, 216 insertions, 27 deletions
diff --git a/chrome/browser/cocoa/clickhold_button_cell.h b/chrome/browser/cocoa/clickhold_button_cell.h
index 483336e..1982281 100644
--- a/chrome/browser/cocoa/clickhold_button_cell.h
+++ b/chrome/browser/cocoa/clickhold_button_cell.h
@@ -26,8 +26,9 @@
// Enable click-hold? Default: NO.
@property(assign, nonatomic) BOOL enableClickHold;
-// Timeout is in seconds (at least 0.01, at most 3600). Default: 0.25 (a guess
-// at a Cocoa-ish value).
+// Timeout is in seconds (at least 0.0, at most 5; 0.0 means that the button
+// will always have its click-hold action activated immediately on press).
+// Default: 0.25 (a guess at a Cocoa-ish value).
@property(assign, nonatomic) NSTimeInterval clickHoldTimeout;
// Track only in the frame rectangle? Default: NO.
diff --git a/chrome/browser/cocoa/clickhold_button_cell.mm b/chrome/browser/cocoa/clickhold_button_cell.mm
index 67b3df6..0dd5c3f 100644
--- a/chrome/browser/cocoa/clickhold_button_cell.mm
+++ b/chrome/browser/cocoa/clickhold_button_cell.mm
@@ -7,8 +7,8 @@
#include "base/logging.h"
// Minimum and maximum click-hold timeout.
-static const NSTimeInterval kMinTimeout = 0.01;
-static const NSTimeInterval kMaxTimeout = 3600.0;
+static const NSTimeInterval kMinTimeout = 0.0;
+static const NSTimeInterval kMaxTimeout = 5.0;
// Drag distance threshold to activate click-hold; should be >= 0.
static const CGFloat kDragDistThreshold = 2.5;
diff --git a/chrome/browser/cocoa/menu_button.h b/chrome/browser/cocoa/menu_button.h
new file mode 100644
index 0000000..92b0569
--- /dev/null
+++ b/chrome/browser/cocoa/menu_button.h
@@ -0,0 +1,24 @@
+// 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_MENU_BUTTON_H_
+#define CHROME_BROWSER_COCOA_MENU_BUTTON_H_
+
+#import <Cocoa/Cocoa.h>
+
+// This a button which displays a user-provided menu "attached" below it upon
+// being clicked or dragged (or clicked and held). It expects a
+// |ClickHoldButtonCell| as cell.
+@interface MenuButton : NSButton {
+ @private
+ IBOutlet NSMenu* menu_;
+ BOOL openAtRight_;
+}
+
+// The menu to display.
+@property(assign, nonatomic) NSMenu* menu;
+
+@end // @interface MenuButton
+
+#endif // CHROME_BROWSER_COCOA_MENU_BUTTON_H_
diff --git a/chrome/browser/cocoa/menu_button.mm b/chrome/browser/cocoa/menu_button.mm
new file mode 100644
index 0000000..aed8034
--- /dev/null
+++ b/chrome/browser/cocoa/menu_button.mm
@@ -0,0 +1,118 @@
+// 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.
+
+#import "chrome/browser/cocoa/menu_button.h"
+
+#include "base/logging.h"
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/clickhold_button_cell.h"
+
+@interface MenuButton (Private)
+
+- (void)resetToDefaults;
+- (void)showMenu:(BOOL)isDragging;
+- (void)clickShowMenu:(id)sender;
+- (void)dragShowMenu:(id)sender;
+
+@end // @interface MenuButton (Private)
+
+@implementation MenuButton
+
+// Overrides:
+
++ (Class)cellClass {
+ return [ClickHoldButtonCell class];
+}
+
+- (id)init {
+ if ((self = [super init]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frameRect {
+ if ((self = [super initWithFrame:frameRect]))
+ [self resetToDefaults];
+ return self;
+}
+
+// Accessors and mutators:
+
+@synthesize menu = menu_;
+
+@end // @implementation MenuButton
+
+@implementation MenuButton (Private)
+
+// Reset various settings of the button and its associated |ClickHoldButtonCell|
+// to the standard state which provides reasonable defaults.
+- (void)resetToDefaults {
+ id cell = [self cell];
+ DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
+ [cell setEnableClickHold:YES];
+ [cell setClickHoldTimeout:0.0]; // Make menu trigger immediately.
+ [cell setAction:@selector(clickShowMenu:)];
+ [cell setTarget:self];
+ [cell setClickHoldAction:@selector(dragShowMenu:)];
+ [cell setClickHoldTarget:self];
+}
+
+// Actually show the menu (in the correct location). |isDragging| indicates
+// whether the mouse button is still down or not.
+- (void)showMenu:(BOOL)isDragging {
+ if (!menu_) {
+ LOG(WARNING) << "No menu available.";
+ if (isDragging) {
+ // If we're dragging, wait for mouse up.
+ [NSApp nextEventMatchingMask:NSLeftMouseUpMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSEventTrackingRunLoopMode
+ dequeue:YES];
+ }
+ return;
+ }
+
+ // FIXME(viettrungluu): Silly fudge factors (same as in
+ // delayedmenu_button.mm).
+ NSRect frame = [self convertRect:[self frame]
+ fromView:[self superview]];
+ frame.origin.x -= 2.0;
+ frame.size.height += 10.0;
+
+ // Make our pop-up button cell and set things up. This is, as of 10.5, the
+ // official Apple-recommended hack. Later, perhaps |-[NSMenu
+ // popUpMenuPositioningItem:atLocation:inView:]| may be a better option.
+ // However, using a pulldown has the benefit that Cocoa automatically places
+ // the menu correctly even when we're at the edge of the screen (including
+ // "dragging upwards" when the button is close to the bottom of the screen).
+ scoped_nsobject<NSPopUpButtonCell> popUpCell(
+ [[NSPopUpButtonCell alloc] initTextCell:@""
+ pullsDown:YES]);
+ DCHECK(popUpCell.get());
+ [popUpCell setMenu:menu_];
+ [popUpCell selectItem:nil];
+ [popUpCell attachPopUpWithFrame:frame
+ inView:self];
+ [popUpCell performClickWithFrame:frame
+ inView:self];
+}
+
+// Called when the button is clicked and released. (Shouldn't happen with
+// timeout of 0, though there may be some strange pointing devices out there.)
+- (void)clickShowMenu:(id)sender {
+ [self showMenu:NO];
+}
+
+// Called when the button is clicked and dragged/held.
+- (void)dragShowMenu:(id)sender {
+ [self showMenu:YES];
+}
+
+@end // @implementation MenuButton (Private)
diff --git a/chrome/browser/cocoa/menu_button_unittest.mm b/chrome/browser/cocoa/menu_button_unittest.mm
new file mode 100644
index 0000000..1861974
--- /dev/null
+++ b/chrome/browser/cocoa/menu_button_unittest.mm
@@ -0,0 +1,64 @@
+// 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.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/clickhold_button_cell.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/cocoa/menu_button.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class MenuButtonTest : public PlatformTest {
+ public:
+ MenuButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ button_.reset([[MenuButton alloc] initWithFrame:frame]);
+ scoped_nsobject<ClickHoldButtonCell> cell(
+ [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
+ [button_ setCell:cell.get()];
+ [cocoa_helper_.contentView() addSubview:button_.get()];
+ }
+
+ scoped_nsobject<MenuButton> button_;
+ CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc.
+};
+
+// Test adding/removing from the view hierarchy, mostly to ensure nothing leaks
+// or crashes.
+TEST_F(MenuButtonTest, AddRemove) {
+ EXPECT_EQ(cocoa_helper_.contentView(), [button_ superview]);
+ [button_.get() removeFromSuperview];
+ EXPECT_FALSE([button_ superview]);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(MenuButtonTest, Display) {
+ [button_ display];
+}
+
+// Test assigning a menu, again mostly to ensure nothing leaks or crashes.
+TEST_F(MenuButtonTest, MenuAssign) {
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+ ASSERT_TRUE(menu.get());
+
+ [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
+ [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
+ [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
+ [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
+
+ [button_ setMenu:menu];
+ EXPECT_TRUE([button_ menu]);
+
+ // TODO(viettrungluu): Display the menu. (The tough part is closing the menu,
+ // not opening it!)
+
+ // Since |button_| doesn't retain menu, we should probably unset it here.
+ [button_ setMenu:nil];
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h
index f5819a5..a442d88 100644
--- a/chrome/browser/cocoa/toolbar_controller.h
+++ b/chrome/browser/cocoa/toolbar_controller.h
@@ -18,8 +18,9 @@
class AutocompletePopupPositioner;
@class AutocompleteTextField;
@class AutocompleteTextFieldEditor;
-@class DelayedMenuButton;
@class BackForwardMenuController;
+@class DelayedMenuButton;
+@class MenuButton;
class Browser;
class CommandUpdater;
class LocationBar;
@@ -69,9 +70,6 @@ class ToolbarView;
scoped_nsobject<NSTrackingArea> trackingArea_;
NSButton* hoveredButton_; // weak. Button under the mouse cursor.
- IBOutlet NSMenu* pageMenu_;
- IBOutlet NSMenu* wrenchMenu_;
-
// The ordering is important for unit tests. If new items are added or the
// ordering is changed, make sure to update |-toolbarViews| and the
// corresponding enum in the unit tests.
@@ -81,8 +79,8 @@ class ToolbarView;
IBOutlet NSButton* homeButton_;
IBOutlet NSButton* starButton_;
IBOutlet NSButton* goButton_;
- IBOutlet NSButton* pageButton_;
- IBOutlet NSButton* wrenchButton_;
+ IBOutlet MenuButton* pageButton_;
+ IBOutlet MenuButton* wrenchButton_;
IBOutlet AutocompleteTextField* locationBar_;
}
@@ -130,11 +128,6 @@ class ToolbarView;
// Return the bookmark bar controller.
- (BookmarkBarController*)bookmarkBarController;
-// Actions for the optional menu buttons for the page and wrench menus. These
-// will show a menu while the mouse is down.
-- (IBAction)showPageMenu:(id)sender;
-- (IBAction)showWrenchMenu:(id)sender;
-
// The bookmark bubble (when you click the star) needs to know where to go.
// Somewhere near the star button seems like a good start.
- (NSRect)starButtonInWindowCoordinates;
diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm
index 5db38fb..4127615 100644
--- a/chrome/browser/cocoa/toolbar_controller.mm
+++ b/chrome/browser/cocoa/toolbar_controller.mm
@@ -14,6 +14,7 @@
#import "chrome/browser/cocoa/back_forward_menu_controller.h"
#import "chrome/browser/cocoa/gradient_button_cell.h"
#import "chrome/browser/cocoa/location_bar_view_mac.h"
+#import "chrome/browser/cocoa/menu_button.h"
#include "chrome/browser/cocoa/nsimage_cache.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/toolbar_model.h"
@@ -425,18 +426,6 @@ class PrefObserverBridge : public NotificationObserver {
}
}
-- (IBAction)showPageMenu:(id)sender {
- [NSMenu popUpContextMenu:pageMenu_
- withEvent:[NSApp currentEvent]
- forView:pageButton_];
-}
-
-- (IBAction)showWrenchMenu:(id)sender {
- [NSMenu popUpContextMenu:wrenchMenu_
- withEvent:[NSApp currentEvent]
- forView:wrenchButton_];
-}
-
- (NSRect)starButtonInWindowCoordinates {
return [[[starButton_ window] contentView] convertRect:[starButton_ bounds]
fromView:starButton_];