diff options
author | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-27 04:55:57 +0000 |
---|---|---|
committer | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-27 04:55:57 +0000 |
commit | e578e76354f5838edb54dc1d9457561030002123 (patch) | |
tree | c13ba5657921756bed0a167aa56edbec68730823 | |
parent | 7d767625372cad11adca0789531753bd56e40e0e (diff) | |
download | chromium_src-e578e76354f5838edb54dc1d9457561030002123.zip chromium_src-e578e76354f5838edb54dc1d9457561030002123.tar.gz chromium_src-e578e76354f5838edb54dc1d9457561030002123.tar.bz2 |
Add overflow menu to the browser action container (part 2 of
supporting resize for the container).
Also improved RTL support a bit (the divider wasn't drawn on
the right side of the container and resizing was reversed).
BUG=32101
TEST=Overflow menu for browser action container should now work.
Make sure to test also right-clicking on a menu item in the overflow
menu to bring up a context menu for that item. And resizing the
container in RTL locales should work.
Review URL: http://codereview.chromium.org/557006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37232 0039d316-1c4b-4281-b951-d872f2087c98
9 files changed, 228 insertions, 29 deletions
diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index 6aaa387..02c213a 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -19,6 +19,7 @@ #include "chrome/browser/profile.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/detachable_toolbar_view.h" +#include "chrome/browser/views/extensions/browser_action_overflow_menu_controller.h" #include "chrome/browser/views/extensions/extension_popup.h" #include "chrome/browser/views/toolbar_view.h" #include "chrome/common/notification_source.h" @@ -30,6 +31,7 @@ #include "third_party/skia/include/effects/SkGradientShader.h" #include "views/controls/button/menu_button.h" #include "views/controls/button/text_button.h" +#include "views/window/window.h" #include "grit/theme_resources.h" @@ -311,6 +313,7 @@ BrowserActionsContainer::BrowserActionsContainer( } BrowserActionsContainer::~BrowserActionsContainer() { + CloseOverflowMenu(); HidePopup(); DeleteBrowserActionViews(); } @@ -357,11 +360,7 @@ void BrowserActionsContainer::AddBrowserAction(Extension* extension) { return; // Before we change anything, determine the number of visible browser actions. - size_t visible_actions = 0; - for (size_t i = 0; i < browser_action_views_.size(); ++i) { - if (browser_action_views_[i]->IsVisible()) - ++visible_actions; - } + size_t visible_actions = VisibleBrowserActions(); // Add the new browser action to the vector and the view hierarchy. BrowserActionView* view = new BrowserActionView(extension, this); @@ -401,11 +400,7 @@ void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { } // Before we change anything, determine the number of visible browser actions. - int visible_actions = 0; - for (size_t i = 0; i < browser_action_views_.size(); ++i) { - if (browser_action_views_[i]->IsVisible()) - ++visible_actions; - } + int visible_actions = VisibleBrowserActions(); for (std::vector<BrowserActionView*>::iterator iter = browser_action_views_.begin(); iter != browser_action_views_.end(); @@ -435,6 +430,12 @@ void BrowserActionsContainer::RemoveBrowserAction(Extension* extension) { } } +void BrowserActionsContainer::CloseOverflowMenu() { + // Close the overflow menu if open (and the context menu off of that). + if (overflow_menu_.get()) + overflow_menu_->CancelMenu(); +} + void BrowserActionsContainer::DeleteBrowserActionViews() { if (!browser_action_views_.empty()) { for (size_t i = 0; i < browser_action_views_.size(); ++i) @@ -495,9 +496,13 @@ void BrowserActionsContainer::OnBrowserActionExecuted( if (same_showing) return; + // We can get the execute event for browser actions that are not visible, + // since buttons can be activated from the overflow menu (chevron). In that + // case we show the popup as originating from the chevron. + View* reference_view = button->GetParent()->IsVisible() ? button : chevron_; gfx::Point origin; - View::ConvertPointToScreen(button, &origin); - gfx::Rect rect = button->bounds(); + View::ConvertPointToScreen(reference_view, &origin); + gfx::Rect rect = reference_view->bounds(); rect.set_x(origin.x()); rect.set_y(origin.y()); @@ -603,10 +608,11 @@ void BrowserActionsContainer::Layout() { } void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { - // The one pixel themed vertical divider to the right of the browser actions. + // The one-pixel themed vertical divider to the right of the browser actions. + int x = UILayoutIsRightToLeft() ? kDividerHorizontalMargin : + width() - kDividerHorizontalMargin; DetachableToolbarView::PaintVerticalDivider( - canvas, - width() - kDividerHorizontalMargin, height(), kDividerVerticalPadding, + canvas, x, height(), kDividerVerticalPadding, DetachableToolbarView::kEdgeDividerColor, DetachableToolbarView::kMiddleDividerColor, GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); @@ -632,12 +638,14 @@ void BrowserActionsContainer::Observe(NotificationType type, const NotificationDetails& details) { switch (type.value) { case NotificationType::EXTENSION_LOADED: + CloseOverflowMenu(); AddBrowserAction(Details<Extension>(details).ptr()); OnBrowserActionVisibilityChanged(); break; case NotificationType::EXTENSION_UNLOADED: case NotificationType::EXTENSION_UNLOADED_DISABLED: + CloseOverflowMenu(); RemoveBrowserAction(Details<Extension>(details).ptr()); OnBrowserActionVisibilityChanged(); break; @@ -698,7 +706,11 @@ void BrowserActionsContainer::BubbleLostFocus(BrowserBubble* bubble, } void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { - // TODO(finnur): Show menu for all the hidden icons. + if (source == chevron_) { + overflow_menu_.reset(new BrowserActionOverflowMenuController( + this, chevron_, browser_action_views_, VisibleBrowserActions())); + overflow_menu_->RunMenu(GetWindow()->GetNativeWindow()); + } } int BrowserActionsContainer::ClampToNearestIconCount(int pixelWidth) const { @@ -758,6 +770,16 @@ int BrowserActionsContainer::ContainerMinSize() const { return resize_gripper_->width() + chevron_->width() + kChevronRightMargin; } +size_t BrowserActionsContainer::VisibleBrowserActions() const { + size_t visible_actions = 0; + for (size_t i = 0; i < browser_action_views_.size(); ++i) { + if (browser_action_views_[i]->IsVisible()) + ++visible_actions; + } + + return visible_actions; +} + void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { if (!done_resizing) { resize_amount_ = resize_amount; diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h index d2b87a4..c668965 100644 --- a/chrome/browser/views/browser_actions_container.h +++ b/chrome/browser/views/browser_actions_container.h @@ -19,6 +19,7 @@ #include "views/view.h" class BrowserActionsContainer; +class BrowserActionOverflowMenuController; class Extension; class ExtensionAction; class ExtensionPopup; @@ -303,6 +304,9 @@ class BrowserActionsContainer // no such view. void RemoveBrowserAction(Extension* extension); + // Closes the overflow menu if open. + void CloseOverflowMenu(); + // Takes a width in pixels, calculates how many icons fit within that space // (up to the maximum number of icons in our vector) and shaves off the // excess pixels. @@ -321,6 +325,9 @@ class BrowserActionsContainer // all the padding that we normally show if there are icons. int ContainerMinSize() const; + // Returns how many browser actions are visible. + size_t VisibleBrowserActions() const; + // The vector of browser actions (icons/image buttons for each action). std::vector<BrowserActionView*> browser_action_views_; @@ -347,6 +354,9 @@ class BrowserActionsContainer // The chevron for accessing the overflow items. views::MenuButton* chevron_; + // The menu to show for the overflow button (chevron). + scoped_ptr<BrowserActionOverflowMenuController> overflow_menu_; + // The animation that happens when the container snaps to place. scoped_ptr<SlideAnimation> resize_animation_; diff --git a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc new file mode 100644 index 0000000..66b209c --- /dev/null +++ b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc @@ -0,0 +1,82 @@ +// 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. + +#include "chrome/browser/views/extensions/browser_action_overflow_menu_controller.h" + +#include "base/utf_string_conversions.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/views/browser_actions_container.h" +#include "chrome/common/extensions/extension.h" +#include "views/controls/menu/menu_item_view.h" + +BrowserActionOverflowMenuController::BrowserActionOverflowMenuController( + BrowserActionsContainer* owner, + views::MenuButton* menu_button, + const std::vector<BrowserActionView*>& views, + int start_index) + : owner_(owner), + menu_button_(menu_button), + views_(&views), + start_index_(start_index) { + menu_.reset(new views::MenuItemView(this)); + menu_->set_has_icons(true); + + TabContents* tab = BrowserList::GetLastActive()->GetSelectedTabContents(); + int tab_id = tab->controller().session_id().id(); + + size_t command_id = 0; + for (size_t i = start_index; i < views_->size(); ++i) { + BrowserActionView* view = (*views_)[i]; + menu_->AppendMenuItemWithIcon( + command_id, + UTF8ToWide(view->button()->extension()->name()), + view->button()->extension()->browser_action()->GetIcon(tab_id)); + ++command_id; + } +} + +BrowserActionOverflowMenuController::~BrowserActionOverflowMenuController() { +} + +bool BrowserActionOverflowMenuController::RunMenu(gfx::NativeWindow window) { + gfx::Rect bounds = menu_button_->GetBounds( + views::View::IGNORE_MIRRORING_TRANSFORMATION); + gfx::Point screen_loc; + views::View::ConvertPointToScreen(menu_button_, &screen_loc); + bounds.set_x(screen_loc.x()); + bounds.set_y(screen_loc.y()); + + views::MenuItemView::AnchorPosition anchor = + menu_button_->UILayoutIsRightToLeft() ? views::MenuItemView::TOPRIGHT : + views::MenuItemView::TOPLEFT; + menu_->RunMenuAt(window, menu_button_, bounds, anchor, false); + return true; +} + +void BrowserActionOverflowMenuController::CancelMenu() { + if (context_menu_.get()) + context_menu_->Cancel(); + menu_->Cancel(); +} + +void BrowserActionOverflowMenuController::ExecuteCommand(int id) { + BrowserActionView* view = (*views_)[start_index_ + id]; + owner_->OnBrowserActionExecuted(view->button()); +} + +bool BrowserActionOverflowMenuController::ShowContextMenu( + views::MenuItemView* source, int id, int x, int y, bool is_mouse_gesture) { + if (!context_menu_.get()) + context_menu_.reset(new ExtensionActionContextMenu()); + // This blocks until the user choses something or dismisses. + context_menu_->Run((*views_)[start_index_ + id]->button()->extension(), + gfx::Point(x, y)); + + // The user is done with the context menu, so we can close the underlying + // menu. + menu_->Cancel(); + + return true; +} diff --git a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h new file mode 100644 index 0000000..02950a4 --- /dev/null +++ b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.h @@ -0,0 +1,63 @@ +// 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_VIEWS_EXTENSIONS_BROWSER_ACTION_OVERFLOW_MENU_CONTROLLER_H_ +#define CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_OVERFLOW_MENU_CONTROLLER_H_ + +#include <vector> + +#include "views/controls/menu/menu_delegate.h" + +class BrowserActionsContainer; +class BrowserActionView; +class ExtensionActionContextMenu; + +class BrowserActionOverflowMenuController : public views::MenuDelegate { + public: + BrowserActionOverflowMenuController( + BrowserActionsContainer* owner, + views::MenuButton* menu_button, + const std::vector<BrowserActionView*>& views, + int start_index); + virtual ~BrowserActionOverflowMenuController(); + + // Shows the overflow menu. + bool RunMenu(gfx::NativeWindow window); + + // Closes the overflow menu (and its context menu if open as well). + void CancelMenu(); + + // Overridden from views::MenuDelegate: + virtual void ExecuteCommand(int id); + virtual bool ShowContextMenu(views::MenuItemView* source, + int id, + int x, + int y, + bool is_mouse_gesture); + + private: + // A pointer to the browser action container that owns the overflow menu. + BrowserActionsContainer* owner_; + + // A pointer to the overflow menu button that we are showing the menu for. + views::MenuButton* menu_button_; + + // The overflow menu for the menu button. + scoped_ptr<views::MenuItemView> menu_; + + // The context menu (when you right click a menu item in the overflow menu). + scoped_ptr<ExtensionActionContextMenu> context_menu_; + + // The views vector of all the browser actions the container knows about. We + // won't show all items, just the one starting at |start_index| and above. + const std::vector<BrowserActionView*>* views_; + + // The index into the BrowserActionView vector, indicating where to start + // picking browser actions to draw. + int start_index_; + + DISALLOW_COPY_AND_ASSIGN(BrowserActionOverflowMenuController); +}; + +#endif // CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_OVERFLOW_MENU_CONTROLLER_H_ diff --git a/chrome/browser/views/extensions/extension_action_context_menu.cc b/chrome/browser/views/extensions/extension_action_context_menu.cc index 47927fc..eafdf5c 100644 --- a/chrome/browser/views/extensions/extension_action_context_menu.cc +++ b/chrome/browser/views/extensions/extension_action_context_menu.cc @@ -25,3 +25,8 @@ void ExtensionActionContextMenu::Run(Extension* extension, context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get())); context_menu_menu_->RunContextMenuAt(point); } + +void ExtensionActionContextMenu::Cancel() { + if (context_menu_menu_.get()) + context_menu_menu_->CancelMenu(); +} diff --git a/chrome/browser/views/extensions/extension_action_context_menu.h b/chrome/browser/views/extensions/extension_action_context_menu.h index 25d1949..5340a389 100644 --- a/chrome/browser/views/extensions/extension_action_context_menu.h +++ b/chrome/browser/views/extensions/extension_action_context_menu.h @@ -20,6 +20,9 @@ class ExtensionActionContextMenu { // Display the context menu at a given point. void Run(Extension* extension, const gfx::Point& point); + // Closes the context menu if open. + void Cancel(); + private: // The options menu. scoped_ptr<ExtensionActionContextMenuModel> context_menu_contents_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 791c46d..a0a4565 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -697,14 +697,14 @@ 'browser/download/save_types.h', 'browser/encoding_menu_controller.cc', 'browser/encoding_menu_controller.h', - 'browser/extensions/extension_action_context_menu_model.cc', - 'browser/extensions/extension_action_context_menu_model.h', 'browser/extensions/convert_user_script.cc', 'browser/extensions/convert_user_script.h', 'browser/extensions/crashed_extension_infobar.cc', 'browser/extensions/crashed_extension_infobar.h', 'browser/extensions/crx_installer.cc', 'browser/extensions/crx_installer.h', + 'browser/extensions/extension_action_context_menu_model.cc', + 'browser/extensions/extension_action_context_menu_model.h', 'browser/extensions/extension_bookmarks_module.cc', 'browser/extensions/extension_bookmarks_module.h', 'browser/extensions/extension_bookmarks_module_constants.cc', @@ -1709,6 +1709,8 @@ 'browser/views/edit_search_engine_dialog.h', 'browser/views/event_utils.cc', 'browser/views/event_utils.h', + 'browser/views/extensions/browser_action_overflow_menu_controller.cc', + 'browser/views/extensions/browser_action_overflow_menu_controller.h', 'browser/views/extensions/extension_action_context_menu.cc', 'browser/views/extensions/extension_action_context_menu.h', 'browser/views/extensions/extension_install_prompt.cc', @@ -2256,6 +2258,8 @@ ['include', '^browser/views/dropdown_bar_view.h'], ['include', '^browser/views/event_utils.cc'], ['include', '^browser/views/event_utils.h'], + ['include', '^browser/views/extensions/browser_action_overflow_menu_controller.cc'], + ['include', '^browser/views/extensions/browser_action_overflow_menu_controller.h'], ['include', '^browser/views/extensions/extension_action_context_menu.cc'], ['include', '^browser/views/extensions/extension_action_context_menu.h'], ['include', '^browser/views/extensions/extension_install_prompt.cc'], diff --git a/views/controls/resize_gripper.cc b/views/controls/resize_gripper.cc index f443f33..59a13aa 100644 --- a/views/controls/resize_gripper.cc +++ b/views/controls/resize_gripper.cc @@ -64,22 +64,26 @@ bool ResizeGripper::OnMouseDragged(const views::MouseEvent& event) { if (!event.IsLeftMouseButton()) return false; - gfx::Point point(event.x(), 0); - View::ConvertPointToScreen(this, &point); - - delegate_->OnResize(point.x() - initial_position_, false); + ReportResizeAmount(event.x(), false); return true; } void ResizeGripper::OnMouseReleased(const views::MouseEvent& event, bool canceled) { - gfx::Point point(event.x(), 0); - View::ConvertPointToScreen(this, &point); - if (canceled) - delegate_->OnResize(0, true); + ReportResizeAmount(initial_position_, true); else - delegate_->OnResize(point.x() - initial_position_, true); + ReportResizeAmount(event.x(), true); +} + +void ResizeGripper::ReportResizeAmount(int resize_amount, bool last_update) { + gfx::Point point(resize_amount, 0); + View::ConvertPointToScreen(this, &point); + resize_amount = point.x() - initial_position_; + + if (UILayoutIsRightToLeft()) + resize_amount = -1 * resize_amount; + delegate_->OnResize(resize_amount, last_update); } } // namespace views diff --git a/views/controls/resize_gripper.h b/views/controls/resize_gripper.h index 1b65066..204aa9f 100644 --- a/views/controls/resize_gripper.h +++ b/views/controls/resize_gripper.h @@ -27,8 +27,10 @@ class ResizeGripper : public ImageView { public: // OnResize is sent when resizing is detected. |resize_amount| specifies the // number of pixels that the user wants to resize by, and can be negative or - // positive (depending on direction of dragging). |done_resizing| is - // true if the user has released the mouse. + // positive (depending on direction of dragging and flips according to + // locale directionality: dragging to the left in LTR locales gives negative + // |resize_amount| but positive amount for RTL). |done_resizing| is true if + // the user has released the mouse. virtual void OnResize(int resize_amount, bool done_resizing) = 0; }; @@ -46,6 +48,10 @@ class ResizeGripper : public ImageView { static const char kViewClassName[]; private: + // Report the amount the user resized by to the delegate, accounting for + // directionality. + void ReportResizeAmount(int resize_amount, bool last_update); + // The delegate to notify when we have updates. ResizeGripperDelegate* delegate_; |