| Index: views/controls/menu/menu_controller.cc
|
| diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc
|
| index 27b059e33dd0abe956c5014578b24992c89a3f62..e43890a26fefed36b2327a969287bfffab1718a0 100644
|
| --- a/views/controls/menu/menu_controller.cc
|
| +++ b/views/controls/menu/menu_controller.cc
|
| @@ -287,7 +287,7 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
|
| owner_ = parent;
|
|
|
| // Set the selection, which opens the initial menu.
|
| - SetSelection(root, true, true);
|
| + SetSelection(root, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
|
|
|
| if (!blocking_run_) {
|
| // Start the timer to hide the menu. This is needed as we get no
|
| @@ -316,7 +316,7 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
|
| ViewsDelegate::views_delegate->ReleaseRef();
|
|
|
| // Close any open menus.
|
| - SetSelection(NULL, false, true);
|
| + SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
|
|
|
| if (nested_menu) {
|
| DCHECK(!menu_stack_.empty());
|
| @@ -362,54 +362,6 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
|
| return result;
|
| }
|
|
|
| -void MenuController::SetSelection(MenuItemView* menu_item,
|
| - bool open_submenu,
|
| - bool update_immediately) {
|
| - size_t paths_differ_at = 0;
|
| - std::vector<MenuItemView*> current_path;
|
| - std::vector<MenuItemView*> new_path;
|
| - BuildPathsAndCalculateDiff(pending_state_.item, menu_item, ¤t_path,
|
| - &new_path, &paths_differ_at);
|
| -
|
| - size_t current_size = current_path.size();
|
| - size_t new_size = new_path.size();
|
| -
|
| - if (pending_state_.item != menu_item && pending_state_.item) {
|
| - View* current_hot_view = GetFirstHotTrackedView(pending_state_.item);
|
| - if (current_hot_view)
|
| - current_hot_view->SetHotTracked(false);
|
| - }
|
| -
|
| - // Notify the old path it isn't selected.
|
| - for (size_t i = paths_differ_at; i < current_size; ++i)
|
| - current_path[i]->SetSelected(false);
|
| -
|
| - // Notify the new path it is selected.
|
| - for (size_t i = paths_differ_at; i < new_size; ++i)
|
| - new_path[i]->SetSelected(true);
|
| -
|
| - if (menu_item && menu_item->GetDelegate())
|
| - menu_item->GetDelegate()->SelectionChanged(menu_item);
|
| -
|
| - pending_state_.item = menu_item;
|
| - pending_state_.submenu_open = open_submenu;
|
| -
|
| - // Stop timers.
|
| - StopShowTimer();
|
| - StopCancelAllTimer();
|
| -
|
| - if (update_immediately)
|
| - CommitPendingSelection();
|
| - else
|
| - StartShowTimer();
|
| -
|
| - // Notify an accessibility focus event on all menu items except for the root.
|
| - if (menu_item &&
|
| - (MenuDepth(menu_item) != 1 ||
|
| - menu_item->GetType() != MenuItemView::SUBMENU))
|
| - menu_item->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS);
|
| -}
|
| -
|
| void MenuController::Cancel(ExitType type) {
|
| if (!showing_) {
|
| // This occurs if we're in the process of notifying the delegate for a drop
|
| @@ -423,7 +375,7 @@ void MenuController::Cancel(ExitType type) {
|
| SendMouseReleaseToActiveView();
|
|
|
| // Hide windows immediately.
|
| - SetSelection(NULL, false, true);
|
| + SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
|
|
|
| if (!blocking_run_) {
|
| // If we didn't block the caller we need to notify the menu, which
|
| @@ -465,21 +417,21 @@ void MenuController::OnMousePressed(SubmenuView* source,
|
| return;
|
| }
|
|
|
| - bool open_submenu = false;
|
| + // On a press we immediately commit the selection, that way a submenu
|
| + // pops up immediately rather than after a delay.
|
| + int selection_types = SELECTION_UPDATE_IMMEDIATELY;
|
| if (!part.menu) {
|
| part.menu = part.parent;
|
| - open_submenu = true;
|
| + selection_types |= SELECTION_OPEN_SUBMENU;
|
| } else {
|
| if (part.menu->GetDelegate()->CanDrag(part.menu)) {
|
| possible_drag_ = true;
|
| press_pt_ = event.location();
|
| }
|
| if (part.menu->HasSubmenu())
|
| - open_submenu = true;
|
| + selection_types |= SELECTION_OPEN_SUBMENU;
|
| }
|
| - // On a press we immediately commit the selection, that way a submenu
|
| - // pops up immediately rather than after a delay.
|
| - SetSelection(part.menu, open_submenu, true);
|
| + SetSelection(part.menu, selection_types);
|
| }
|
|
|
| void MenuController::OnMouseDragged(SubmenuView* source,
|
| @@ -532,7 +484,7 @@ void MenuController::OnMouseDragged(SubmenuView* source,
|
| part.menu = source->GetMenuItem();
|
| else
|
| mouse_menu = part.menu;
|
| - SetSelection(part.menu ? part.menu : state_.item, true, false);
|
| + SetSelection(part.menu ? part.menu : state_.item, SELECTION_OPEN_SUBMENU);
|
| } else if (part.type == MenuPart::NONE) {
|
| ShowSiblingMenu(source, event);
|
| }
|
| @@ -552,9 +504,10 @@ void MenuController::OnMouseReleased(SubmenuView* source,
|
| part.menu)) {
|
| // Set the selection immediately, making sure the submenu is only open
|
| // if it already was.
|
| - bool open_submenu = (state_.item == pending_state_.item &&
|
| - state_.submenu_open);
|
| - SetSelection(pending_state_.item, open_submenu, true);
|
| + int selection_types = SELECTION_UPDATE_IMMEDIATELY;
|
| + if (state_.item == pending_state_.item && state_.submenu_open)
|
| + selection_types |= SELECTION_OPEN_SUBMENU;
|
| + SetSelection(pending_state_.item, selection_types);
|
| gfx::Point loc(event.location());
|
| View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc);
|
|
|
| @@ -582,7 +535,8 @@ void MenuController::OnMouseReleased(SubmenuView* source,
|
| }
|
| } else if (part.type == MenuPart::MENU_ITEM) {
|
| // User either clicked on empty space, or a menu that has children.
|
| - SetSelection(part.menu ? part.menu : state_.item, true, true);
|
| + SetSelection(part.menu ? part.menu : state_.item,
|
| + SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
|
| }
|
| SendMouseReleaseToActiveView(source, event, true);
|
| }
|
| @@ -603,13 +557,14 @@ void MenuController::OnMouseMoved(SubmenuView* source,
|
| return;
|
|
|
| if (part.type == MenuPart::MENU_ITEM && part.menu) {
|
| - SetSelection(part.menu, true, false);
|
| + SetSelection(part.menu, SELECTION_OPEN_SUBMENU);
|
| } else if (!part.is_scroll() && pending_state_.item &&
|
| (!pending_state_.item->HasSubmenu() ||
|
| !pending_state_.item->GetSubmenu()->IsShowing())) {
|
| // On exit if the user hasn't selected an item with a submenu, move the
|
| // selection back to the parent menu item.
|
| - SetSelection(pending_state_.item->GetParentMenuItem(), true, false);
|
| + SetSelection(pending_state_.item->GetParentMenuItem(),
|
| + SELECTION_OPEN_SUBMENU);
|
| }
|
| }
|
|
|
| @@ -686,13 +641,14 @@ int MenuController::OnDragUpdated(SubmenuView* source,
|
| query_menu_item, event, &drop_position);
|
|
|
| // If the menu has a submenu, schedule the submenu to open.
|
| - SetSelection(menu_item, menu_item->HasSubmenu(), false);
|
| + SetSelection(menu_item, menu_item->HasSubmenu() ? SELECTION_OPEN_SUBMENU :
|
| + SELECTION_DEFAULT);
|
|
|
| if (drop_position == MenuDelegate::DROP_NONE ||
|
| drop_operation == DragDropTypes::DRAG_NONE)
|
| menu_item = NULL;
|
| } else {
|
| - SetSelection(source->GetMenuItem(), true, false);
|
| + SetSelection(source->GetMenuItem(), SELECTION_OPEN_SUBMENU);
|
| }
|
| SetDropMenuItem(menu_item, drop_position);
|
| last_drop_operation_ = drop_operation;
|
| @@ -721,7 +677,7 @@ int MenuController::OnPerformDrop(SubmenuView* source,
|
| MenuDelegate::DropPosition drop_position = drop_position_;
|
|
|
| // Close all menus, including any nested menus.
|
| - SetSelection(NULL, false, true);
|
| + SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
|
| CloseAllNestedMenus();
|
|
|
| // Set state such that we exit.
|
| @@ -760,6 +716,55 @@ void MenuController::OnDragExitedScrollButton(SubmenuView* source) {
|
| StopScrolling();
|
| }
|
|
|
| +void MenuController::SetSelection(MenuItemView* menu_item,
|
| + int selection_types) {
|
| + size_t paths_differ_at = 0;
|
| + std::vector<MenuItemView*> current_path;
|
| + std::vector<MenuItemView*> new_path;
|
| + BuildPathsAndCalculateDiff(pending_state_.item, menu_item, ¤t_path,
|
| + &new_path, &paths_differ_at);
|
| +
|
| + size_t current_size = current_path.size();
|
| + size_t new_size = new_path.size();
|
| +
|
| + if (pending_state_.item != menu_item && pending_state_.item) {
|
| + View* current_hot_view = GetFirstHotTrackedView(pending_state_.item);
|
| + if (current_hot_view)
|
| + current_hot_view->SetHotTracked(false);
|
| + }
|
| +
|
| + // Notify the old path it isn't selected.
|
| + for (size_t i = paths_differ_at; i < current_size; ++i)
|
| + current_path[i]->SetSelected(false);
|
| +
|
| + // Notify the new path it is selected.
|
| + for (size_t i = paths_differ_at; i < new_size; ++i)
|
| + new_path[i]->SetSelected(true);
|
| +
|
| + if (menu_item && menu_item->GetDelegate())
|
| + menu_item->GetDelegate()->SelectionChanged(menu_item);
|
| +
|
| + CHECK(menu_item || (selection_types & SELECTION_EXIT) != 0);
|
| +
|
| + pending_state_.item = menu_item;
|
| + pending_state_.submenu_open = (selection_types & SELECTION_OPEN_SUBMENU) != 0;
|
| +
|
| + // Stop timers.
|
| + StopShowTimer();
|
| + StopCancelAllTimer();
|
| +
|
| + if (selection_types & SELECTION_UPDATE_IMMEDIATELY)
|
| + CommitPendingSelection();
|
| + else
|
| + StartShowTimer();
|
| +
|
| + // Notify an accessibility focus event on all menu items except for the root.
|
| + if (menu_item &&
|
| + (MenuDepth(menu_item) != 1 ||
|
| + menu_item->GetType() != MenuItemView::SUBMENU))
|
| + menu_item->NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS);
|
| +}
|
| +
|
| // static
|
| void MenuController::SetActiveInstance(MenuController* controller) {
|
| active_instance_ = controller;
|
| @@ -1068,7 +1073,7 @@ bool MenuController::ShowSiblingMenu(SubmenuView* source, const MouseEvent& e) {
|
| has_mnemonics,
|
| source->GetMenuItem()->GetRootMenuItem()->show_mnemonics_);
|
| alt_menu->controller_ = this;
|
| - SetSelection(alt_menu, true, true);
|
| + SetSelection(alt_menu, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
|
| return true;
|
| }
|
|
|
| @@ -1315,7 +1320,8 @@ void MenuController::MenuChildrenChanged(MenuItemView* item) {
|
| // Make sure the submenu isn't showing for the current item (the position may
|
| // have changed or the menu removed). This also moves the selection back to
|
| // the parent, which handles the case where the selected item was removed.
|
| - SetSelection(state_.item->GetParentMenuItem(), true, true);
|
| + SetSelection(state_.item->GetParentMenuItem(),
|
| + SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
|
|
|
| OpenMenuImpl(item, false);
|
| }
|
| @@ -1480,7 +1486,7 @@ void MenuController::IncrementSelection(int delta) {
|
| // A menu is selected and open, but none of its children are selected,
|
| // select the first menu item.
|
| if (item->GetSubmenu()->GetMenuItemCount()) {
|
| - SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, false);
|
| + SetSelection(item->GetSubmenu()->GetMenuItemAt(0), SELECTION_DEFAULT);
|
| ScrollToVisible(item->GetSubmenu()->GetMenuItemAt(0));
|
| return;
|
| }
|
| @@ -1515,7 +1521,7 @@ void MenuController::IncrementSelection(int delta) {
|
| if (!to_select)
|
| break;
|
| ScrollToVisible(to_select);
|
| - SetSelection(to_select, false, false);
|
| + SetSelection(to_select, SELECTION_DEFAULT);
|
| View* to_make_hot = GetInitialFocusableView(to_select, delta == 1);
|
| if (to_make_hot)
|
| to_make_hot->SetHotTracked(true);
|
| @@ -1548,10 +1554,11 @@ void MenuController::OpenSubmenuChangeSelectionIfCan() {
|
| MenuItemView* item = pending_state_.item;
|
| if (item->HasSubmenu()) {
|
| if (item->GetSubmenu()->GetMenuItemCount() > 0) {
|
| - SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, true);
|
| + SetSelection(item->GetSubmenu()->GetMenuItemAt(0),
|
| + SELECTION_UPDATE_IMMEDIATELY);
|
| } else {
|
| // No menu items, just show the sub-menu.
|
| - SetSelection(item, true, true);
|
| + SetSelection(item, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
|
| }
|
| }
|
| }
|
| @@ -1562,9 +1569,9 @@ void MenuController::CloseSubmenu() {
|
| if (!item->GetParentMenuItem())
|
| return;
|
| if (item->HasSubmenu() && item->GetSubmenu()->IsShowing()) {
|
| - SetSelection(item, false, true);
|
| + SetSelection(item, SELECTION_UPDATE_IMMEDIATELY);
|
| } else if (item->GetParentMenuItem()->GetParentMenuItem()) {
|
| - SetSelection(item->GetParentMenuItem(), false, true);
|
| + SetSelection(item->GetParentMenuItem(), SELECTION_UPDATE_IMMEDIATELY);
|
| }
|
| }
|
|
|
| @@ -1606,15 +1613,18 @@ bool MenuController::AcceptOrSelect(MenuItemView* parent,
|
| if (!details.has_multiple) {
|
| // There's only one match, activate it (or open if it has a submenu).
|
| if (submenu->GetMenuItemAt(details.first_match)->HasSubmenu()) {
|
| - SetSelection(submenu->GetMenuItemAt(details.first_match), true, false);
|
| + SetSelection(submenu->GetMenuItemAt(details.first_match),
|
| + SELECTION_OPEN_SUBMENU);
|
| } else {
|
| Accept(submenu->GetMenuItemAt(details.first_match), 0);
|
| return true;
|
| }
|
| } else if (details.index_of_item == -1 || details.next_match == -1) {
|
| - SetSelection(submenu->GetMenuItemAt(details.first_match), false, false);
|
| + SetSelection(submenu->GetMenuItemAt(details.first_match),
|
| + SELECTION_DEFAULT);
|
| } else {
|
| - SetSelection(submenu->GetMenuItemAt(details.next_match), false, false);
|
| + SetSelection(submenu->GetMenuItemAt(details.next_match),
|
| + SELECTION_DEFAULT);
|
| }
|
| return false;
|
| }
|
| @@ -1653,6 +1663,14 @@ bool MenuController::SelectByChar(wchar_t character) {
|
| #if defined(OS_WIN)
|
| void MenuController::RepostEvent(SubmenuView* source,
|
| const MouseEvent& event) {
|
| + if (!state_.item) {
|
| + // We some times get an event after closing all the menus. Ignore it.
|
| + // Make sure the menu is in fact not visible. If the menu is visible, then
|
| + // we're in a bad state where we think the menu isn't visibile but it is.
|
| + CHECK(!source->GetWidget()->IsVisible());
|
| + return;
|
| + }
|
| +
|
| gfx::Point screen_loc(event.location());
|
| View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
|
| HWND window = WindowFromPoint(screen_loc.ToPOINT());
|
|
|