| Index: views/controls/menu/menu_controller.cc
|
| ===================================================================
|
| --- views/controls/menu/menu_controller.cc (revision 29776)
|
| +++ views/controls/menu/menu_controller.cc (working copy)
|
| @@ -9,6 +9,7 @@
|
| #include "app/os_exchange_data.h"
|
| #include "base/keyboard_codes.h"
|
| #include "base/time.h"
|
| +#include "views/controls/button/menu_button.h"
|
| #include "views/controls/menu/menu_scroll_view_container.h"
|
| #include "views/controls/menu/submenu_view.h"
|
| #include "views/drag_utils.h"
|
| @@ -143,6 +144,7 @@
|
| #endif
|
|
|
| MenuItemView* MenuController::Run(gfx::NativeWindow parent,
|
| + MenuButton* button,
|
| MenuItemView* root,
|
| const gfx::Rect& bounds,
|
| MenuItemView::AnchorPosition position,
|
| @@ -168,20 +170,10 @@
|
| // Reset current state.
|
| pending_state_ = State();
|
| state_ = State();
|
| - pending_state_.initial_bounds = bounds;
|
| - if (bounds.height() > 1) {
|
| - // Inset the bounds slightly, otherwise drag coordinates don't line up
|
| - // nicely and menus close prematurely.
|
| - pending_state_.initial_bounds.Inset(0, 1);
|
| - }
|
| - pending_state_.anchor = position;
|
| + UpdateInitialLocation(bounds, position);
|
| +
|
| owner_ = parent;
|
|
|
| - // Calculate the bounds of the monitor we'll show menus on. Do this once to
|
| - // avoid repeated system queries for the info.
|
| - pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
|
| - bounds.origin());
|
| -
|
| // Set the selection, which opens the initial menu.
|
| SetSelection(root, true, true);
|
|
|
| @@ -190,6 +182,8 @@
|
| // notification when the drag has finished.
|
| StartCancelAllTimer();
|
| return NULL;
|
| + } else if (button) {
|
| + menu_button_ = button;
|
| }
|
|
|
| #ifdef DEBUG_MENU
|
| @@ -245,6 +239,11 @@
|
| exit_all_ = true;
|
| }
|
|
|
| + if (menu_button_) {
|
| + menu_button_->SetState(CustomButton::BS_NORMAL);
|
| + menu_button_->SchedulePaint();
|
| + }
|
| +
|
| return result;
|
| }
|
|
|
| @@ -316,8 +315,7 @@
|
| if (!blocking_run_)
|
| return;
|
|
|
| - MenuPart part =
|
| - GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| + MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| if (part.is_scroll())
|
| return; // Ignore presses on scroll buttons.
|
|
|
| @@ -362,8 +360,7 @@
|
| #ifdef DEBUG_MENU
|
| DLOG(INFO) << "OnMouseDragged source=" << source;
|
| #endif
|
| - MenuPart part =
|
| - GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| + MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| UpdateScrolling(part);
|
|
|
| if (!blocking_run_)
|
| @@ -409,6 +406,8 @@
|
| if (!part.menu)
|
| part.menu = source->GetMenuItem();
|
| SetSelection(part.menu ? part.menu : state_.item, true, false);
|
| + } else if (part.type == MenuPart::NONE) {
|
| + ShowSiblingMenu(source, event);
|
| }
|
| }
|
|
|
| @@ -423,8 +422,7 @@
|
| DCHECK(state_.item);
|
| possible_drag_ = false;
|
| DCHECK(blocking_run_);
|
| - MenuPart part =
|
| - GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| + MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
|
| part.menu)) {
|
| // Set the selection immediately, making sure the submenu is only open
|
| @@ -460,14 +458,16 @@
|
| if (showing_submenu_)
|
| return;
|
|
|
| - MenuPart part =
|
| - GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
| + MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
|
|
|
| UpdateScrolling(part);
|
|
|
| if (!blocking_run_)
|
| return;
|
|
|
| + if (part.type == MenuPart::NONE && ShowSiblingMenu(source, event))
|
| + return;
|
| +
|
| if (part.type == MenuPart::MENU_ITEM && part.menu) {
|
| SetSelection(part.menu, true, false);
|
| } else if (!part.is_scroll() && pending_state_.item &&
|
| @@ -803,7 +803,8 @@
|
| owner_(NULL),
|
| possible_drag_(false),
|
| valid_drop_coordinates_(false),
|
| - showing_submenu_(false) {
|
| + showing_submenu_(false),
|
| + menu_button_(NULL) {
|
| #ifdef DEBUG_MENU
|
| instance_count++;
|
| DLOG(INFO) << "created MC, count=" << instance_count;
|
| @@ -820,6 +821,23 @@
|
| #endif
|
| }
|
|
|
| +void MenuController::UpdateInitialLocation(
|
| + const gfx::Rect& bounds,
|
| + MenuItemView::AnchorPosition position) {
|
| + pending_state_.initial_bounds = bounds;
|
| + if (bounds.height() > 1) {
|
| + // Inset the bounds slightly, otherwise drag coordinates don't line up
|
| + // nicely and menus close prematurely.
|
| + pending_state_.initial_bounds.Inset(0, 1);
|
| + }
|
| + pending_state_.anchor = position;
|
| +
|
| + // Calculate the bounds of the monitor we'll show menus on. Do this once to
|
| + // avoid repeated system queries for the info.
|
| + pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
|
| + bounds.origin());
|
| +}
|
| +
|
| void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
|
| DCHECK(IsBlockingRun());
|
| result_ = item;
|
| @@ -827,6 +845,63 @@
|
| result_mouse_event_flags_ = mouse_event_flags;
|
| }
|
|
|
| +bool MenuController::ShowSiblingMenu(SubmenuView* source, const MouseEvent& e) {
|
| + if (!menu_stack_.empty() || !menu_button_)
|
| + return false;
|
| +
|
| + View* source_view = source->GetScrollViewContainer();
|
| + if (e.x() >= 0 && e.x() < source_view->width() && e.y() >= 0 &&
|
| + e.y() < source_view->height()) {
|
| + // The mouse is over the menu, no need to continue.
|
| + return false;
|
| + }
|
| +
|
| + gfx::NativeWindow window_under_mouse = Screen::GetWindowAtCursorScreenPoint();
|
| + if (window_under_mouse != owner_)
|
| + return false;
|
| +
|
| + // The user moved the mouse outside the menu and over the owning window. See
|
| + // if there is a sibling menu we should show.
|
| + gfx::Point screen_point(e.location());
|
| + View::ConvertPointToScreen(source_view, &screen_point);
|
| + MenuItemView::AnchorPosition anchor;
|
| + bool has_mnemonics;
|
| + MenuButton* button = NULL;
|
| + MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()->
|
| + GetSiblingMenu(source->GetMenuItem()->GetRootMenuItem(),
|
| + screen_point, &anchor, &has_mnemonics, &button);
|
| + if (!alt_menu || alt_menu == state_.item)
|
| + return false;
|
| +
|
| + if (!button) {
|
| + // If the delegate returns a menu, they must also return a button.
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +
|
| + // There is a sibling menu, update the button state, hide the current menu
|
| + // and show the new one.
|
| + menu_button_->SetState(CustomButton::BS_NORMAL);
|
| + menu_button_->SchedulePaint();
|
| + menu_button_ = button;
|
| + menu_button_->SetState(CustomButton::BS_PUSHED);
|
| + menu_button_->SchedulePaint();
|
| +
|
| + // Need to reset capture when we show the menu again, otherwise we aren't
|
| + // going to get any events.
|
| + did_capture_ = false;
|
| + gfx::Point screen_menu_loc;
|
| + View::ConvertPointToScreen(button, &screen_menu_loc);
|
| + // Subtract 1 from the height to make the popup flush with the button border.
|
| + UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(),
|
| + button->width(), button->height() - 1),
|
| + anchor);
|
| + alt_menu->PrepareForRun(has_mnemonics);
|
| + alt_menu->controller_ = this;
|
| + SetSelection(alt_menu, true, true);
|
| + return true;
|
| +}
|
| +
|
| void MenuController::CloseAllNestedMenus() {
|
| for (std::list<State>::iterator i = menu_stack_.begin();
|
| i != menu_stack_.end(); ++i) {
|
|
|