Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/menu/menu_controller.h" | 5 #include "ui/views/controls/menu/menu_controller.h" |
| 6 | 6 |
| 7 #include "base/i18n/case_conversion.h" | 7 #include "base/i18n/case_conversion.h" |
| 8 #include "base/i18n/rtl.h" | 8 #include "base/i18n/rtl.h" |
| 9 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 551 | 551 |
| 552 current_mouse_pressed_state_ |= event.changed_button_flags(); | 552 current_mouse_pressed_state_ |= event.changed_button_flags(); |
| 553 | 553 |
| 554 if (forward_to_root) { | 554 if (forward_to_root) { |
| 555 ui::MouseEvent event_for_root(event); | 555 ui::MouseEvent event_for_root(event); |
| 556 // Reset hot-tracking if a different view is getting a mouse press. | 556 // Reset hot-tracking if a different view is getting a mouse press. |
| 557 ConvertLocatedEventForRootView(source, forward_to_root, &event_for_root); | 557 ConvertLocatedEventForRootView(source, forward_to_root, &event_for_root); |
| 558 View* view = | 558 View* view = |
| 559 forward_to_root->GetEventHandlerForPoint(event_for_root.location()); | 559 forward_to_root->GetEventHandlerForPoint(event_for_root.location()); |
| 560 CustomButton* button = CustomButton::AsCustomButton(view); | 560 CustomButton* button = CustomButton::AsCustomButton(view); |
| 561 if (hot_button_ && hot_button_ != button) | 561 MenuItemView* item = static_cast<MenuItemView*>( |
| 562 SetHotTrackedButton(nullptr); | 562 button->GetAncestorWithClassName(MenuItemView::kViewClassName)); |
|
sky
2016/03/08 16:45:37
What if button is null?
varkha
2016/03/23 21:16:01
Acknowledged (this is no longer necessary if I don
| |
| 563 if (item && item->hot_button() != button) | |
| 564 item->SetHotTrackedButton(nullptr); | |
| 563 | 565 |
| 564 // Empty menu items are always handled by the menu controller. | 566 // Empty menu items are always handled by the menu controller. |
| 565 if (!view || view->id() != MenuItemView::kEmptyMenuItemViewID) { | 567 if (!view || view->id() != MenuItemView::kEmptyMenuItemViewID) { |
| 566 bool processed = forward_to_root->ProcessMousePressed(event_for_root); | 568 bool processed = forward_to_root->ProcessMousePressed(event_for_root); |
| 567 // If the event was processed, the root view becomes our current mouse | 569 // If the event was processed, the root view becomes our current mouse |
| 568 // handler... | 570 // handler... |
| 569 if (processed && !current_mouse_event_target_) { | 571 if (processed && !current_mouse_event_target_) { |
| 570 current_mouse_event_target_ = forward_to_root; | 572 current_mouse_event_target_ = forward_to_root; |
| 571 } | 573 } |
| 572 | 574 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 const ui::MouseEvent& event) { | 713 const ui::MouseEvent& event) { |
| 712 if (current_mouse_event_target_) { | 714 if (current_mouse_event_target_) { |
| 713 ui::MouseEvent event_for_root(event); | 715 ui::MouseEvent event_for_root(event); |
| 714 ConvertLocatedEventForRootView(source, current_mouse_event_target_, | 716 ConvertLocatedEventForRootView(source, current_mouse_event_target_, |
| 715 &event_for_root); | 717 &event_for_root); |
| 716 current_mouse_event_target_->ProcessMouseMoved(event_for_root); | 718 current_mouse_event_target_->ProcessMouseMoved(event_for_root); |
| 717 return; | 719 return; |
| 718 } | 720 } |
| 719 | 721 |
| 720 MenuHostRootView* root_view = GetRootView(source, event.location()); | 722 MenuHostRootView* root_view = GetRootView(source, event.location()); |
| 721 if (root_view) { | 723 if (root_view) |
| 722 root_view->ProcessMouseMoved(event); | 724 root_view->ProcessMouseMoved(event); |
| 723 | 725 |
| 726 HandleMouseLocation(source, event.location()); | |
| 727 if (pending_state_.item && root_view) { | |
| 724 // Update hot-tracked button when a button state is changed with a mouse | 728 // Update hot-tracked button when a button state is changed with a mouse |
| 725 // event. It is necessary to track it for accurate hot-tracking when both | 729 // event. It is necessary to track it for accurate hot-tracking when both |
| 726 // mouse and keyboard are used to navigate the menu. | 730 // mouse and keyboard are used to navigate the menu. |
| 727 ui::MouseEvent event_for_root(event); | 731 ui::MouseEvent event_for_root(event); |
| 728 ConvertLocatedEventForRootView(source, root_view, &event_for_root); | 732 ConvertLocatedEventForRootView(source, root_view, &event_for_root); |
| 729 View* view = | 733 View* view = |
| 730 root_view->GetEventHandlerForPoint(event_for_root.location()); | 734 root_view->GetEventHandlerForPoint(event_for_root.location()); |
| 731 CustomButton* button = CustomButton::AsCustomButton(view); | 735 CustomButton* button = CustomButton::AsCustomButton(view); |
| 732 if (button && button->IsHotTracked()) | 736 if (button && button->IsHotTracked() && |
| 733 SetHotTrackedButton(button); | 737 button->GetAncestorWithClassName(MenuItemView::kViewClassName) == |
| 738 pending_state_.item) { | |
| 739 pending_state_.item->SetHotTrackedButton(button); | |
| 740 } | |
| 734 } | 741 } |
| 735 | |
| 736 HandleMouseLocation(source, event.location()); | |
| 737 } | 742 } |
| 738 | 743 |
| 739 void MenuController::OnMouseEntered(SubmenuView* source, | 744 void MenuController::OnMouseEntered(SubmenuView* source, |
| 740 const ui::MouseEvent& event) { | 745 const ui::MouseEvent& event) { |
| 741 // MouseEntered is always followed by a mouse moved, so don't need to | 746 // MouseEntered is always followed by a mouse moved, so don't need to |
| 742 // do anything here. | 747 // do anything here. |
| 743 } | 748 } |
| 744 | 749 |
| 745 bool MenuController::OnMouseWheel(SubmenuView* source, | 750 bool MenuController::OnMouseWheel(SubmenuView* source, |
| 746 const ui::MouseWheelEvent& event) { | 751 const ui::MouseWheelEvent& event) { |
| 747 MenuPart part = GetMenuPart(source, event.location()); | 752 MenuPart part = GetMenuPart(source, event.location()); |
| 748 return part.submenu && part.submenu->OnMouseWheel(event); | 753 return part.submenu && part.submenu->OnMouseWheel(event); |
| 749 } | 754 } |
| 750 | 755 |
| 751 void MenuController::OnGestureEvent(SubmenuView* source, | 756 void MenuController::OnGestureEvent(SubmenuView* source, |
| 752 ui::GestureEvent* event) { | 757 ui::GestureEvent* event) { |
| 753 MenuHostRootView* root_view = GetRootView(source, event->location()); | 758 MenuHostRootView* root_view = GetRootView(source, event->location()); |
| 754 if (root_view) { | 759 if (root_view) { |
| 755 // Reset hot-tracking if a different view is getting a touch event. | 760 // Reset hot-tracking if a different view is getting a touch event. |
| 756 ui::GestureEvent event_for_root(*event); | 761 ui::GestureEvent event_for_root(*event); |
| 757 ConvertLocatedEventForRootView(source, root_view, &event_for_root); | 762 ConvertLocatedEventForRootView(source, root_view, &event_for_root); |
| 758 View* view = | 763 View* view = |
| 759 root_view->GetEventHandlerForPoint(event_for_root.location()); | 764 root_view->GetEventHandlerForPoint(event_for_root.location()); |
| 760 CustomButton* button = CustomButton::AsCustomButton(view); | 765 CustomButton* button = CustomButton::AsCustomButton(view); |
| 761 if (hot_button_ && hot_button_ != button) | 766 MenuItemView* item = static_cast<MenuItemView*>( |
| 762 SetHotTrackedButton(nullptr); | 767 button->GetAncestorWithClassName(MenuItemView::kViewClassName)); |
| 768 if (item && item->hot_button() != button) | |
| 769 item->SetHotTrackedButton(nullptr); | |
| 763 } | 770 } |
| 764 | 771 |
| 765 MenuPart part = GetMenuPart(source, event->location()); | 772 MenuPart part = GetMenuPart(source, event->location()); |
| 766 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | 773 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { |
| 767 SetSelectionOnPointerDown(source, event); | 774 SetSelectionOnPointerDown(source, event); |
| 768 event->StopPropagation(); | 775 event->StopPropagation(); |
| 769 } else if (event->type() == ui::ET_GESTURE_LONG_PRESS) { | 776 } else if (event->type() == ui::ET_GESTURE_LONG_PRESS) { |
| 770 if (part.type == MenuPart::MENU_ITEM && part.menu) { | 777 if (part.type == MenuPart::MENU_ITEM && part.menu) { |
| 771 gfx::Point screen_location(event->location()); | 778 gfx::Point screen_location(event->location()); |
| 772 View::ConvertPointToScreen(source->GetScrollViewContainer(), | 779 View::ConvertPointToScreen(source->GetScrollViewContainer(), |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 827 | 834 |
| 828 void MenuController::ViewHierarchyChanged( | 835 void MenuController::ViewHierarchyChanged( |
| 829 SubmenuView* source, | 836 SubmenuView* source, |
| 830 const View::ViewHierarchyChangedDetails& details) { | 837 const View::ViewHierarchyChangedDetails& details) { |
| 831 if (!details.is_add) { | 838 if (!details.is_add) { |
| 832 // If the current mouse handler is removed, remove it as the handler. | 839 // If the current mouse handler is removed, remove it as the handler. |
| 833 if (details.child == current_mouse_event_target_) { | 840 if (details.child == current_mouse_event_target_) { |
| 834 current_mouse_event_target_ = nullptr; | 841 current_mouse_event_target_ = nullptr; |
| 835 current_mouse_pressed_state_ = 0; | 842 current_mouse_pressed_state_ = 0; |
| 836 } | 843 } |
| 837 // Update |hot_button_| if it gets removed while a menu is up. | |
| 838 if (details.child == hot_button_) | |
| 839 hot_button_ = nullptr; | |
| 840 } | 844 } |
| 841 } | 845 } |
| 842 | 846 |
| 843 bool MenuController::GetDropFormats( | 847 bool MenuController::GetDropFormats( |
| 844 SubmenuView* source, | 848 SubmenuView* source, |
| 845 int* formats, | 849 int* formats, |
| 846 std::set<ui::Clipboard::FormatType>* format_types) { | 850 std::set<ui::Clipboard::FormatType>* format_types) { |
| 847 return source->GetMenuItem()->GetDelegate()->GetDropFormats( | 851 return source->GetMenuItem()->GetDelegate()->GetDropFormats( |
| 848 source->GetMenuItem(), formats, format_types); | 852 source->GetMenuItem(), formats, format_types); |
| 849 } | 853 } |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1057 size_t paths_differ_at = 0; | 1061 size_t paths_differ_at = 0; |
| 1058 std::vector<MenuItemView*> current_path; | 1062 std::vector<MenuItemView*> current_path; |
| 1059 std::vector<MenuItemView*> new_path; | 1063 std::vector<MenuItemView*> new_path; |
| 1060 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, ¤t_path, | 1064 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, ¤t_path, |
| 1061 &new_path, &paths_differ_at); | 1065 &new_path, &paths_differ_at); |
| 1062 | 1066 |
| 1063 size_t current_size = current_path.size(); | 1067 size_t current_size = current_path.size(); |
| 1064 size_t new_size = new_path.size(); | 1068 size_t new_size = new_path.size(); |
| 1065 | 1069 |
| 1066 bool pending_item_changed = pending_state_.item != menu_item; | 1070 bool pending_item_changed = pending_state_.item != menu_item; |
| 1067 if (pending_item_changed && pending_state_.item) | |
| 1068 SetHotTrackedButton(nullptr); | |
| 1069 | 1071 |
| 1070 // Notify the old path it isn't selected. | 1072 // Notify the old path it isn't selected. |
| 1071 MenuDelegate* current_delegate = | 1073 MenuDelegate* current_delegate = |
| 1072 current_path.empty() ? NULL : current_path.front()->GetDelegate(); | 1074 current_path.empty() ? NULL : current_path.front()->GetDelegate(); |
| 1073 for (size_t i = paths_differ_at; i < current_size; ++i) { | 1075 for (size_t i = paths_differ_at; i < current_size; ++i) { |
| 1074 if (current_delegate && | 1076 if (current_delegate && |
| 1075 current_path[i]->GetType() == MenuItemView::SUBMENU) { | 1077 current_path[i]->GetType() == MenuItemView::SUBMENU) { |
| 1076 current_delegate->WillHideMenu(current_path[i]); | 1078 current_delegate->WillHideMenu(current_path[i]); |
| 1077 } | 1079 } |
| 1078 current_path[i]->SetSelected(false); | 1080 current_path[i]->SetSelected(false); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1309 drop_target_(NULL), | 1311 drop_target_(NULL), |
| 1310 drop_position_(MenuDelegate::DROP_UNKNOWN), | 1312 drop_position_(MenuDelegate::DROP_UNKNOWN), |
| 1311 owner_(NULL), | 1313 owner_(NULL), |
| 1312 possible_drag_(false), | 1314 possible_drag_(false), |
| 1313 drag_in_progress_(false), | 1315 drag_in_progress_(false), |
| 1314 did_initiate_drag_(false), | 1316 did_initiate_drag_(false), |
| 1315 valid_drop_coordinates_(false), | 1317 valid_drop_coordinates_(false), |
| 1316 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), | 1318 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), |
| 1317 showing_submenu_(false), | 1319 showing_submenu_(false), |
| 1318 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), | 1320 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), |
| 1319 hot_button_(nullptr), | |
| 1320 delegate_(delegate), | 1321 delegate_(delegate), |
| 1321 message_loop_depth_(0), | 1322 message_loop_depth_(0), |
| 1322 closing_event_time_(base::TimeDelta()), | 1323 closing_event_time_(base::TimeDelta()), |
| 1323 menu_start_time_(base::TimeTicks()), | 1324 menu_start_time_(base::TimeTicks()), |
| 1324 async_run_(false), | 1325 async_run_(false), |
| 1325 is_combobox_(false), | 1326 is_combobox_(false), |
| 1326 item_selected_by_touch_(false), | 1327 item_selected_by_touch_(false), |
| 1327 current_mouse_event_target_(nullptr), | 1328 current_mouse_event_target_(nullptr), |
| 1328 current_mouse_pressed_state_(0), | 1329 current_mouse_pressed_state_(0), |
| 1329 message_loop_(MenuMessageLoop::Create()) { | 1330 message_loop_(MenuMessageLoop::Create()) { |
| 1330 delegate_stack_.push_back(std::make_pair(delegate_, async_run_)); | 1331 delegate_stack_.push_back(std::make_pair(delegate_, async_run_)); |
| 1331 active_instance_ = this; | 1332 active_instance_ = this; |
| 1332 } | 1333 } |
| 1333 | 1334 |
| 1334 MenuController::~MenuController() { | 1335 MenuController::~MenuController() { |
| 1335 DCHECK(!showing_); | 1336 DCHECK(!showing_); |
| 1336 if (owner_) | 1337 if (owner_) |
| 1337 owner_->RemoveObserver(this); | 1338 owner_->RemoveObserver(this); |
| 1338 if (active_instance_ == this) | 1339 if (active_instance_ == this) |
| 1339 active_instance_ = NULL; | 1340 active_instance_ = NULL; |
| 1340 StopShowTimer(); | 1341 StopShowTimer(); |
| 1341 StopCancelAllTimer(); | 1342 StopCancelAllTimer(); |
| 1342 } | 1343 } |
| 1343 | 1344 |
| 1344 void MenuController::RunMessageLoop(bool nested_menu) { | 1345 void MenuController::RunMessageLoop(bool nested_menu) { |
| 1345 message_loop_->Run(this, owner_, nested_menu); | 1346 message_loop_->Run(this, owner_, nested_menu); |
| 1346 } | 1347 } |
| 1347 | 1348 |
| 1348 bool MenuController::SendAcceleratorToHotTrackedView() { | 1349 bool MenuController::SendAcceleratorToHotTrackedView() { |
| 1349 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item); | 1350 MenuItemView* item = pending_state_.item; |
| 1351 CustomButton* hot_view = GetFirstHotTrackedView(item); | |
| 1350 if (!hot_view) | 1352 if (!hot_view) |
| 1351 return false; | 1353 return false; |
| 1352 | |
| 1353 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); | 1354 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); |
| 1354 hot_view->AcceleratorPressed(accelerator); | 1355 hot_view->AcceleratorPressed(accelerator); |
| 1355 CustomButton* button = static_cast<CustomButton*>(hot_view); | 1356 CustomButton* button = static_cast<CustomButton*>(hot_view); |
| 1356 SetHotTrackedButton(button); | 1357 item->SetHotTrackedButton(button); |
| 1357 return true; | 1358 return true; |
| 1358 } | 1359 } |
| 1359 | 1360 |
| 1360 void MenuController::UpdateInitialLocation(const gfx::Rect& bounds, | 1361 void MenuController::UpdateInitialLocation(const gfx::Rect& bounds, |
| 1361 MenuAnchorPosition position, | 1362 MenuAnchorPosition position, |
| 1362 bool context_menu) { | 1363 bool context_menu) { |
| 1363 pending_state_.context_menu = context_menu; | 1364 pending_state_.context_menu = context_menu; |
| 1364 pending_state_.initial_bounds = bounds; | 1365 pending_state_.initial_bounds = bounds; |
| 1365 if (bounds.height() > 1) { | 1366 if (bounds.height() > 1) { |
| 1366 // Inset the bounds slightly, otherwise drag coordinates don't line up | 1367 // Inset the bounds slightly, otherwise drag coordinates don't line up |
| (...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2116 if (item->GetSubmenu()->GetMenuItemCount()) { | 2117 if (item->GetSubmenu()->GetMenuItemCount()) { |
| 2117 MenuItemView* to_select = FindInitialSelectableMenuItem(item, direction); | 2118 MenuItemView* to_select = FindInitialSelectableMenuItem(item, direction); |
| 2118 SetInitialHotTrackedView(to_select, direction); | 2119 SetInitialHotTrackedView(to_select, direction); |
| 2119 return; | 2120 return; |
| 2120 } | 2121 } |
| 2121 } | 2122 } |
| 2122 | 2123 |
| 2123 if (item->has_children()) { | 2124 if (item->has_children()) { |
| 2124 CustomButton* button = GetFirstHotTrackedView(item); | 2125 CustomButton* button = GetFirstHotTrackedView(item); |
| 2125 if (button) { | 2126 if (button) { |
| 2126 DCHECK_EQ(hot_button_, button); | 2127 DCHECK_EQ(item->hot_button(), button); |
| 2127 SetHotTrackedButton(nullptr); | 2128 item->SetHotTrackedButton(nullptr); |
| 2128 } | 2129 } |
| 2129 bool direction_is_down = direction == INCREMENT_SELECTION_DOWN; | 2130 bool direction_is_down = direction == INCREMENT_SELECTION_DOWN; |
| 2130 View* to_make_hot = button | 2131 View* to_make_hot = button |
| 2131 ? GetNextFocusableView(item, button, direction_is_down) | 2132 ? GetNextFocusableView(item, button, direction_is_down) |
| 2132 : GetInitialFocusableView(item, direction_is_down); | 2133 : GetInitialFocusableView(item, direction_is_down); |
| 2133 CustomButton* hot_button = CustomButton::AsCustomButton(to_make_hot); | 2134 CustomButton* hot_button = CustomButton::AsCustomButton(to_make_hot); |
| 2134 if (hot_button) { | 2135 if (hot_button) { |
| 2135 SetHotTrackedButton(hot_button); | 2136 item->SetHotTrackedButton(hot_button); |
| 2136 return; | 2137 return; |
| 2137 } | 2138 } |
| 2138 } | 2139 } |
| 2139 | 2140 |
| 2140 MenuItemView* parent = item->GetParentMenuItem(); | 2141 MenuItemView* parent = item->GetParentMenuItem(); |
| 2141 if (parent) { | 2142 if (parent) { |
| 2142 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); | 2143 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); |
| 2143 if (parent_count > 1) { | 2144 if (parent_count > 1) { |
| 2144 for (int i = 0; i < parent_count; ++i) { | 2145 for (int i = 0; i < parent_count; ++i) { |
| 2145 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { | 2146 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2627 } | 2628 } |
| 2628 | 2629 |
| 2629 void MenuController::SetInitialHotTrackedView( | 2630 void MenuController::SetInitialHotTrackedView( |
| 2630 MenuItemView* item, | 2631 MenuItemView* item, |
| 2631 SelectionIncrementDirectionType direction) { | 2632 SelectionIncrementDirectionType direction) { |
| 2632 if (!item) | 2633 if (!item) |
| 2633 return; | 2634 return; |
| 2634 SetSelection(item, SELECTION_DEFAULT); | 2635 SetSelection(item, SELECTION_DEFAULT); |
| 2635 View* hot_view = | 2636 View* hot_view = |
| 2636 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN); | 2637 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN); |
| 2637 SetHotTrackedButton(CustomButton::AsCustomButton(hot_view)); | 2638 item->SetHotTrackedButton(CustomButton::AsCustomButton(hot_view)); |
| 2638 } | |
| 2639 | |
| 2640 void MenuController::SetHotTrackedButton(CustomButton* hot_button) { | |
| 2641 if (hot_button == hot_button_) { | |
| 2642 // Hot-tracked state may change outside of the MenuController. Correct it. | |
| 2643 if (hot_button && !hot_button->IsHotTracked()) | |
| 2644 hot_button->SetHotTracked(true); | |
| 2645 return; | |
| 2646 } | |
| 2647 if (hot_button_) | |
| 2648 hot_button_->SetHotTracked(false); | |
| 2649 hot_button_ = hot_button; | |
| 2650 if (hot_button) | |
| 2651 hot_button->SetHotTracked(true); | |
| 2652 } | 2639 } |
| 2653 | 2640 |
| 2654 } // namespace views | 2641 } // namespace views |
| OLD | NEW |