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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 #endif | 46 #endif |
| 47 | 47 |
| 48 #if defined(USE_AURA) | 48 #if defined(USE_AURA) |
| 49 #include "ui/views/controls/menu/menu_key_event_handler.h" | 49 #include "ui/views/controls/menu/menu_key_event_handler.h" |
| 50 #endif | 50 #endif |
| 51 | 51 |
| 52 using base::Time; | 52 using base::Time; |
| 53 using base::TimeDelta; | 53 using base::TimeDelta; |
| 54 using ui::OSExchangeData; | 54 using ui::OSExchangeData; |
| 55 | 55 |
| 56 // Period of the scroll timer (in milliseconds). | |
| 57 static const int kScrollTimerMS = 30; | |
| 58 | |
| 59 // Amount of time from when the drop exits the menu and the menu is hidden. | |
| 60 static const int kCloseOnExitTime = 1200; | |
| 61 | |
| 62 // If a context menu is invoked by touch, we shift the menu by this offset so | |
| 63 // that the finger does not obscure the menu. | |
| 64 static const int kCenteredContextMenuYOffset = -15; | |
| 65 | |
| 66 namespace views { | 56 namespace views { |
| 67 | 57 |
| 68 namespace { | 58 namespace { |
| 69 | 59 |
| 70 // When showing context menu on mouse down, the user might accidentally select | 60 // When showing context menu on mouse down, the user might accidentally select |
| 71 // the menu item on the subsequent mouse up. To prevent this, we add the | 61 // the menu item on the subsequent mouse up. To prevent this, we add the |
| 72 // following delay before the user is able to select an item. | 62 // following delay before the user is able to select an item. |
| 73 static int menu_selection_hold_time_ms = kMinimumMsPressedToActivate; | 63 int menu_selection_hold_time_ms = kMinimumMsPressedToActivate; |
| 64 | |
| 65 // Period of the scroll timer (in milliseconds). | |
| 66 const int kScrollTimerMS = 30; | |
| 67 | |
| 68 // Amount of time from when the drop exits the menu and the menu is hidden. | |
| 69 const int kCloseOnExitTime = 1200; | |
| 70 | |
| 71 // If a context menu is invoked by touch, we shift the menu by this offset so | |
| 72 // that the finger does not obscure the menu. | |
| 73 const int kCenteredContextMenuYOffset = -15; | |
| 74 | 74 |
| 75 // The spacing offset for the bubble tip. | 75 // The spacing offset for the bubble tip. |
| 76 const int kBubbleTipSizeLeftRight = 12; | 76 const int kBubbleTipSizeLeftRight = 12; |
| 77 const int kBubbleTipSizeTopBottom = 11; | 77 const int kBubbleTipSizeTopBottom = 11; |
| 78 | 78 |
| 79 // The maximum distance (in DIPS) that the mouse can be moved before it should | 79 // The maximum distance (in DIPS) that the mouse can be moved before it should |
| 80 // trigger a mouse menu item activation (regardless of how long the menu has | 80 // trigger a mouse menu item activation (regardless of how long the menu has |
| 81 // been showing). | 81 // been showing). |
| 82 const float kMaximumLengthMovedToActivate = 4.0f; | 82 const float kMaximumLengthMovedToActivate = 4.0f; |
| 83 | 83 |
| 84 // Returns true if the mnemonic of |menu| matches key. | 84 // Returns true if the mnemonic of |menu| matches key. |
| 85 bool MatchesMnemonic(MenuItemView* menu, base::char16 key) { | 85 bool MatchesMnemonic(MenuItemView* menu, base::char16 key) { |
| 86 return key != 0 && menu->GetMnemonic() == key; | 86 return key != 0 && menu->GetMnemonic() == key; |
| 87 } | 87 } |
| 88 | 88 |
| 89 // Returns true if |menu| doesn't have a mnemonic and first character of the its | 89 // Returns true if |menu| doesn't have a mnemonic and first character of the its |
| 90 // title is |key|. | 90 // title is |key|. |
| 91 bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) { | 91 bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) { |
| 92 if (menu->GetMnemonic()) | 92 if (menu->GetMnemonic()) |
| 93 return false; | 93 return false; |
| 94 | 94 |
| 95 base::string16 lower_title = base::i18n::ToLower(menu->title()); | 95 base::string16 lower_title = base::i18n::ToLower(menu->title()); |
| 96 return !lower_title.empty() && lower_title[0] == key; | 96 return !lower_title.empty() && lower_title[0] == key; |
| 97 } | 97 } |
| 98 | 98 |
| 99 // Returns the first descendant of |view| that is hot tracked. | 99 // Returns the first descendant of |view| that is hot tracked. |
| 100 static CustomButton* GetFirstHotTrackedView(View* view) { | 100 CustomButton* GetFirstHotTrackedView(View* view) { |
| 101 if (!view) | 101 if (!view) |
| 102 return NULL; | 102 return NULL; |
| 103 CustomButton* button = CustomButton::AsCustomButton(view); | 103 CustomButton* button = CustomButton::AsCustomButton(view); |
| 104 if (button) { | 104 if (button) { |
| 105 if (button->IsHotTracked()) | 105 if (button->IsHotTracked()) |
| 106 return button; | 106 return button; |
| 107 } | 107 } |
| 108 | 108 |
| 109 for (int i = 0; i < view->child_count(); ++i) { | 109 for (int i = 0; i < view->child_count(); ++i) { |
| 110 CustomButton* hot_view = GetFirstHotTrackedView(view->child_at(i)); | 110 CustomButton* hot_view = GetFirstHotTrackedView(view->child_at(i)); |
| 111 if (hot_view) | 111 if (hot_view) |
| 112 return hot_view; | 112 return hot_view; |
| 113 } | 113 } |
| 114 return NULL; | 114 return NULL; |
| 115 } | 115 } |
| 116 | 116 |
| 117 // Returns a CustomButton descendant of |view| that is (a) hot-tracked and | |
| 118 // (b) not equal to |hot_button|. Returns null if such descendant is not found. | |
| 119 // This allows a caller to detect when a button is set to be hot-tracked by a | |
| 120 // mouse event and its |hot_button_| indicator becomes stale. | |
| 121 CustomButton* GetFirstHotTrackedViewDifferingFrom(View* view, | |
| 122 CustomButton* hot_button) { | |
| 123 if (!view) | |
| 124 return nullptr; | |
| 125 CustomButton* button = CustomButton::AsCustomButton(view); | |
| 126 if (button && button != hot_button && button->IsHotTracked()) | |
| 127 return button; | |
| 128 | |
| 129 for (int i = 0; i < view->child_count(); ++i) { | |
| 130 button = GetFirstHotTrackedViewDifferingFrom(view->child_at(i), hot_button); | |
| 131 if (button) | |
| 132 return button; | |
| 133 } | |
| 134 return nullptr; | |
| 135 } | |
| 136 | |
| 117 // Recurses through the child views of |view| returning the first view starting | 137 // Recurses through the child views of |view| returning the first view starting |
| 118 // at |start| that is focusable. A value of -1 for |start| indicates to start at | 138 // at |start| that is focusable. A value of -1 for |start| indicates to start at |
| 119 // the first view (if |forward| is false, iterating starts at the last view). If | 139 // the first view (if |forward| is false, iterating starts at the last view). If |
| 120 // |forward| is true the children are considered first to last, otherwise last | 140 // |forward| is true the children are considered first to last, otherwise last |
| 121 // to first. | 141 // to first. |
| 122 static View* GetFirstFocusableView(View* view, int start, bool forward) { | 142 View* GetFirstFocusableView(View* view, int start, bool forward) { |
| 123 if (forward) { | 143 if (forward) { |
| 124 for (int i = start == -1 ? 0 : start; i < view->child_count(); ++i) { | 144 for (int i = start == -1 ? 0 : start; i < view->child_count(); ++i) { |
| 125 View* deepest = GetFirstFocusableView(view->child_at(i), -1, forward); | 145 View* deepest = GetFirstFocusableView(view->child_at(i), -1, forward); |
| 126 if (deepest) | 146 if (deepest) |
| 127 return deepest; | 147 return deepest; |
| 128 } | 148 } |
| 129 } else { | 149 } else { |
| 130 for (int i = start == -1 ? view->child_count() - 1 : start; i >= 0; --i) { | 150 for (int i = start == -1 ? view->child_count() - 1 : start; i >= 0; --i) { |
| 131 View* deepest = GetFirstFocusableView(view->child_at(i), -1, forward); | 151 View* deepest = GetFirstFocusableView(view->child_at(i), -1, forward); |
| 132 if (deepest) | 152 if (deepest) |
| 133 return deepest; | 153 return deepest; |
| 134 } | 154 } |
| 135 } | 155 } |
| 136 return view->IsFocusable() ? view : NULL; | 156 return view->IsFocusable() ? view : NULL; |
| 137 } | 157 } |
| 138 | 158 |
| 139 // Returns the first child of |start| that is focusable. | 159 // Returns the first child of |start| that is focusable. |
| 140 static View* GetInitialFocusableView(View* start, bool forward) { | 160 View* GetInitialFocusableView(View* start, bool forward) { |
| 141 return GetFirstFocusableView(start, -1, forward); | 161 return GetFirstFocusableView(start, -1, forward); |
| 142 } | 162 } |
| 143 | 163 |
| 144 // Returns the next view after |start_at| that is focusable. Returns NULL if | 164 // Returns the next view after |start_at| that is focusable. Returns NULL if |
| 145 // there are no focusable children of |ancestor| after |start_at|. | 165 // there are no focusable children of |ancestor| after |start_at|. |
| 146 static View* GetNextFocusableView(View* ancestor, | 166 View* GetNextFocusableView(View* ancestor, View* start_at, bool forward) { |
| 147 View* start_at, | |
| 148 bool forward) { | |
| 149 DCHECK(ancestor->Contains(start_at)); | 167 DCHECK(ancestor->Contains(start_at)); |
| 150 View* parent = start_at; | 168 View* parent = start_at; |
| 151 do { | 169 do { |
| 152 View* new_parent = parent->parent(); | 170 View* new_parent = parent->parent(); |
| 153 int index = new_parent->GetIndexOf(parent); | 171 int index = new_parent->GetIndexOf(parent); |
| 154 index += forward ? 1 : -1; | 172 index += forward ? 1 : -1; |
| 155 if (forward || index != -1) { | 173 if (forward || index != -1) { |
| 156 View* next = GetFirstFocusableView(new_parent, index, forward); | 174 View* next = GetFirstFocusableView(new_parent, index, forward); |
| 157 if (next) | 175 if (next) |
| 158 return next; | 176 return next; |
| (...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 793 View* MenuController::GetTooltipHandlerForPoint(SubmenuView* source, | 811 View* MenuController::GetTooltipHandlerForPoint(SubmenuView* source, |
| 794 const gfx::Point& point) { | 812 const gfx::Point& point) { |
| 795 MenuHostRootView* root_view = GetRootView(source, point); | 813 MenuHostRootView* root_view = GetRootView(source, point); |
| 796 return root_view ? root_view->ProcessGetTooltipHandlerForPoint(point) | 814 return root_view ? root_view->ProcessGetTooltipHandlerForPoint(point) |
| 797 : nullptr; | 815 : nullptr; |
| 798 } | 816 } |
| 799 | 817 |
| 800 void MenuController::ViewHierarchyChanged( | 818 void MenuController::ViewHierarchyChanged( |
| 801 SubmenuView* source, | 819 SubmenuView* source, |
| 802 const View::ViewHierarchyChangedDetails& details) { | 820 const View::ViewHierarchyChangedDetails& details) { |
| 803 // If the current mouse handler is removed, remove it as the handler. | 821 if (!details.is_add) { |
| 804 if (!details.is_add && details.child == current_mouse_event_target_) { | 822 // If the current mouse handler is removed, remove it as the handler. |
| 805 current_mouse_event_target_ = nullptr; | 823 if (details.child == current_mouse_event_target_) { |
| 806 current_mouse_pressed_state_ = 0; | 824 current_mouse_event_target_ = nullptr; |
| 825 current_mouse_pressed_state_ = 0; | |
| 826 } | |
| 827 // Update |hot_button_| if it gets deleted while a menu is up. | |
| 828 if (details.child == hot_button_) | |
| 829 hot_button_ = nullptr; | |
| 807 } | 830 } |
| 808 } | 831 } |
| 809 | 832 |
| 810 bool MenuController::GetDropFormats( | 833 bool MenuController::GetDropFormats( |
| 811 SubmenuView* source, | 834 SubmenuView* source, |
| 812 int* formats, | 835 int* formats, |
| 813 std::set<ui::Clipboard::FormatType>* format_types) { | 836 std::set<ui::Clipboard::FormatType>* format_types) { |
| 814 return source->GetMenuItem()->GetDelegate()->GetDropFormats( | 837 return source->GetMenuItem()->GetDelegate()->GetDropFormats( |
| 815 source->GetMenuItem(), formats, format_types); | 838 source->GetMenuItem(), formats, format_types); |
| 816 } | 839 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1027 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, ¤t_path, | 1050 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, ¤t_path, |
| 1028 &new_path, &paths_differ_at); | 1051 &new_path, &paths_differ_at); |
| 1029 | 1052 |
| 1030 size_t current_size = current_path.size(); | 1053 size_t current_size = current_path.size(); |
| 1031 size_t new_size = new_path.size(); | 1054 size_t new_size = new_path.size(); |
| 1032 | 1055 |
| 1033 bool pending_item_changed = pending_state_.item != menu_item; | 1056 bool pending_item_changed = pending_state_.item != menu_item; |
| 1034 if (pending_item_changed && pending_state_.item) { | 1057 if (pending_item_changed && pending_state_.item) { |
| 1035 CustomButton* button = GetFirstHotTrackedView(pending_state_.item); | 1058 CustomButton* button = GetFirstHotTrackedView(pending_state_.item); |
| 1036 if (button) | 1059 if (button) |
| 1037 button->SetHotTracked(false); | 1060 SetHotTrackedButton(button, false); |
| 1061 } | |
| 1062 // A button could become hot-tracked when a mouse is moved without changing | |
|
sky
2016/02/23 20:11:13
I still don't get what case you are hitting that i
varkha
2016/02/23 21:01:39
This scenario:
1. Open app menu with extension but
| |
| 1063 // which MenuItem is selected. When a menu item selection is updated, presence | |
| 1064 // of a hot-tracked button that is not |hot_button_| can mean only that a new | |
| 1065 // hot-tracked button was set. In this case update |hot_button_| to match. | |
| 1066 // This allows correct hot-tracked button to be used when alternating between | |
| 1067 // keyboard and mouse navigation in the menu. | |
| 1068 CustomButton* new_hot_button = | |
| 1069 GetFirstHotTrackedViewDifferingFrom(menu_item, hot_button_); | |
| 1070 if (new_hot_button) { | |
| 1071 if (hot_button_) | |
| 1072 SetHotTrackedButton(hot_button_, false); | |
| 1073 SetHotTrackedButton(new_hot_button, true); | |
| 1038 } | 1074 } |
| 1039 | 1075 |
| 1040 // Notify the old path it isn't selected. | 1076 // Notify the old path it isn't selected. |
| 1041 MenuDelegate* current_delegate = | 1077 MenuDelegate* current_delegate = |
| 1042 current_path.empty() ? NULL : current_path.front()->GetDelegate(); | 1078 current_path.empty() ? NULL : current_path.front()->GetDelegate(); |
| 1043 for (size_t i = paths_differ_at; i < current_size; ++i) { | 1079 for (size_t i = paths_differ_at; i < current_size; ++i) { |
| 1044 if (current_delegate && | 1080 if (current_delegate && |
| 1045 current_path[i]->GetType() == MenuItemView::SUBMENU) { | 1081 current_path[i]->GetType() == MenuItemView::SUBMENU) { |
| 1046 current_delegate->WillHideMenu(current_path[i]); | 1082 current_delegate->WillHideMenu(current_path[i]); |
| 1047 } | 1083 } |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1279 drop_target_(NULL), | 1315 drop_target_(NULL), |
| 1280 drop_position_(MenuDelegate::DROP_UNKNOWN), | 1316 drop_position_(MenuDelegate::DROP_UNKNOWN), |
| 1281 owner_(NULL), | 1317 owner_(NULL), |
| 1282 possible_drag_(false), | 1318 possible_drag_(false), |
| 1283 drag_in_progress_(false), | 1319 drag_in_progress_(false), |
| 1284 did_initiate_drag_(false), | 1320 did_initiate_drag_(false), |
| 1285 valid_drop_coordinates_(false), | 1321 valid_drop_coordinates_(false), |
| 1286 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), | 1322 last_drop_operation_(MenuDelegate::DROP_UNKNOWN), |
| 1287 showing_submenu_(false), | 1323 showing_submenu_(false), |
| 1288 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), | 1324 active_mouse_view_id_(ViewStorage::GetInstance()->CreateStorageID()), |
| 1325 hot_button_(nullptr), | |
| 1289 delegate_(delegate), | 1326 delegate_(delegate), |
| 1290 message_loop_depth_(0), | 1327 message_loop_depth_(0), |
| 1291 closing_event_time_(base::TimeDelta()), | 1328 closing_event_time_(base::TimeDelta()), |
| 1292 menu_start_time_(base::TimeTicks()), | 1329 menu_start_time_(base::TimeTicks()), |
| 1293 async_run_(false), | 1330 async_run_(false), |
| 1294 is_combobox_(false), | 1331 is_combobox_(false), |
| 1295 item_selected_by_touch_(false), | 1332 item_selected_by_touch_(false), |
| 1296 current_mouse_event_target_(nullptr), | 1333 current_mouse_event_target_(nullptr), |
| 1297 current_mouse_pressed_state_(0), | 1334 current_mouse_pressed_state_(0), |
| 1298 message_loop_(MenuMessageLoop::Create()) { | 1335 message_loop_(MenuMessageLoop::Create()) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1314 message_loop_->Run(this, owner_, nested_menu); | 1351 message_loop_->Run(this, owner_, nested_menu); |
| 1315 } | 1352 } |
| 1316 | 1353 |
| 1317 bool MenuController::SendAcceleratorToHotTrackedView() { | 1354 bool MenuController::SendAcceleratorToHotTrackedView() { |
| 1318 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item); | 1355 CustomButton* hot_view = GetFirstHotTrackedView(pending_state_.item); |
| 1319 if (!hot_view) | 1356 if (!hot_view) |
| 1320 return false; | 1357 return false; |
| 1321 | 1358 |
| 1322 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); | 1359 ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); |
| 1323 hot_view->AcceleratorPressed(accelerator); | 1360 hot_view->AcceleratorPressed(accelerator); |
| 1324 CustomButton* button = static_cast<CustomButton*>(hot_view); | 1361 SetHotTrackedButton(hot_view, true); |
| 1325 button->SetHotTracked(true); | |
| 1326 return true; | 1362 return true; |
| 1327 } | 1363 } |
| 1328 | 1364 |
| 1329 void MenuController::UpdateInitialLocation(const gfx::Rect& bounds, | 1365 void MenuController::UpdateInitialLocation(const gfx::Rect& bounds, |
| 1330 MenuAnchorPosition position, | 1366 MenuAnchorPosition position, |
| 1331 bool context_menu) { | 1367 bool context_menu) { |
| 1332 pending_state_.context_menu = context_menu; | 1368 pending_state_.context_menu = context_menu; |
| 1333 pending_state_.initial_bounds = bounds; | 1369 pending_state_.initial_bounds = bounds; |
| 1334 if (bounds.height() > 1) { | 1370 if (bounds.height() > 1) { |
| 1335 // Inset the bounds slightly, otherwise drag coordinates don't line up | 1371 // Inset the bounds slightly, otherwise drag coordinates don't line up |
| (...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2077 void MenuController::IncrementSelection( | 2113 void MenuController::IncrementSelection( |
| 2078 SelectionIncrementDirectionType direction) { | 2114 SelectionIncrementDirectionType direction) { |
| 2079 MenuItemView* item = pending_state_.item; | 2115 MenuItemView* item = pending_state_.item; |
| 2080 DCHECK(item); | 2116 DCHECK(item); |
| 2081 if (pending_state_.submenu_open && item->HasSubmenu() && | 2117 if (pending_state_.submenu_open && item->HasSubmenu() && |
| 2082 item->GetSubmenu()->IsShowing()) { | 2118 item->GetSubmenu()->IsShowing()) { |
| 2083 // A menu is selected and open, but none of its children are selected, | 2119 // A menu is selected and open, but none of its children are selected, |
| 2084 // select the first menu item that is visible and enabled. | 2120 // select the first menu item that is visible and enabled. |
| 2085 if (item->GetSubmenu()->GetMenuItemCount()) { | 2121 if (item->GetSubmenu()->GetMenuItemCount()) { |
| 2086 MenuItemView* to_select = FindInitialSelectableMenuItem(item, direction); | 2122 MenuItemView* to_select = FindInitialSelectableMenuItem(item, direction); |
| 2087 if (to_select) | 2123 SetInitialHotTrackedView(to_select, direction); |
| 2088 SetSelection(to_select, SELECTION_DEFAULT); | |
| 2089 return; | 2124 return; |
| 2090 } | 2125 } |
| 2091 } | 2126 } |
| 2092 | 2127 |
| 2093 if (item->has_children()) { | 2128 if (item->has_children()) { |
| 2094 CustomButton* button = GetFirstHotTrackedView(item); | 2129 CustomButton* button = GetFirstHotTrackedView(item); |
| 2095 if (button) { | 2130 if (button) { |
| 2096 button->SetHotTracked(false); | 2131 SetHotTrackedButton(button, false); |
| 2097 View* to_make_hot = GetNextFocusableView( | 2132 View* hot_view = GetNextFocusableView( |
| 2098 item, button, direction == INCREMENT_SELECTION_DOWN); | 2133 item, button, direction == INCREMENT_SELECTION_DOWN); |
| 2099 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); | 2134 CustomButton* hot_button = CustomButton::AsCustomButton(hot_view); |
| 2100 if (button_hot) { | 2135 if (hot_button) { |
| 2101 button_hot->SetHotTracked(true); | 2136 SetHotTrackedButton(hot_button, true); |
| 2102 return; | 2137 return; |
| 2103 } | 2138 } |
| 2104 } else { | 2139 } else { |
| 2105 View* to_make_hot = | 2140 View* hot_view = |
| 2106 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN); | 2141 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN); |
| 2107 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); | 2142 CustomButton* hot_button = CustomButton::AsCustomButton(hot_view); |
| 2108 if (button_hot) { | 2143 if (hot_button) { |
| 2109 button_hot->SetHotTracked(true); | 2144 SetHotTrackedButton(hot_button, true); |
| 2110 return; | 2145 return; |
| 2111 } | 2146 } |
| 2112 } | 2147 } |
| 2113 } | 2148 } |
| 2114 | 2149 |
| 2115 MenuItemView* parent = item->GetParentMenuItem(); | 2150 MenuItemView* parent = item->GetParentMenuItem(); |
| 2116 if (parent) { | 2151 if (parent) { |
| 2117 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); | 2152 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); |
| 2118 if (parent_count > 1) { | 2153 if (parent_count > 1) { |
| 2119 for (int i = 0; i < parent_count; ++i) { | 2154 for (int i = 0; i < parent_count; ++i) { |
| 2120 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { | 2155 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { |
| 2121 MenuItemView* to_select = | 2156 MenuItemView* to_select = |
| 2122 FindNextSelectableMenuItem(parent, i, direction); | 2157 FindNextSelectableMenuItem(parent, i, direction); |
| 2123 if (!to_select) | 2158 SetInitialHotTrackedView(to_select, direction); |
| 2124 break; | |
| 2125 SetSelection(to_select, SELECTION_DEFAULT); | |
| 2126 View* to_make_hot = GetInitialFocusableView( | |
| 2127 to_select, direction == INCREMENT_SELECTION_DOWN); | |
| 2128 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); | |
| 2129 if (button_hot) | |
| 2130 button_hot->SetHotTracked(true); | |
| 2131 break; | 2159 break; |
| 2132 } | 2160 } |
| 2133 } | 2161 } |
| 2134 } | 2162 } |
| 2135 } | 2163 } |
| 2136 } | 2164 } |
| 2137 | 2165 |
| 2138 MenuItemView* MenuController::FindInitialSelectableMenuItem( | 2166 MenuItemView* MenuController::FindInitialSelectableMenuItem( |
| 2139 MenuItemView* parent, | 2167 MenuItemView* parent, |
| 2140 SelectionIncrementDirectionType direction) { | 2168 SelectionIncrementDirectionType direction) { |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2602 pending_state_.item->GetParentMenuItem() && | 2630 pending_state_.item->GetParentMenuItem() && |
| 2603 (!pending_state_.item->HasSubmenu() || | 2631 (!pending_state_.item->HasSubmenu() || |
| 2604 !pending_state_.item->GetSubmenu()->IsShowing())) { | 2632 !pending_state_.item->GetSubmenu()->IsShowing())) { |
| 2605 // On exit if the user hasn't selected an item with a submenu, move the | 2633 // On exit if the user hasn't selected an item with a submenu, move the |
| 2606 // selection back to the parent menu item. | 2634 // selection back to the parent menu item. |
| 2607 SetSelection(pending_state_.item->GetParentMenuItem(), | 2635 SetSelection(pending_state_.item->GetParentMenuItem(), |
| 2608 SELECTION_OPEN_SUBMENU); | 2636 SELECTION_OPEN_SUBMENU); |
| 2609 } | 2637 } |
| 2610 } | 2638 } |
| 2611 | 2639 |
| 2640 void MenuController::SetHotTrackedButton(CustomButton* hot_button, | |
| 2641 bool is_hot_tracked) { | |
| 2642 DCHECK(hot_button); | |
|
sky
2016/02/23 20:11:13
The constraints on calling this function are not o
varkha
2016/02/23 21:01:39
Yes, will try that.
varkha
2016/02/24 01:42:21
Done.
| |
| 2643 hot_button->SetHotTracked(is_hot_tracked); | |
| 2644 DCHECK(is_hot_tracked || (hot_button_ == hot_button)); | |
| 2645 hot_button_ = is_hot_tracked ? hot_button : nullptr; | |
| 2646 } | |
| 2647 | |
| 2648 void MenuController::SetInitialHotTrackedView( | |
| 2649 MenuItemView* item, | |
| 2650 SelectionIncrementDirectionType direction) { | |
| 2651 if (!item) | |
| 2652 return; | |
| 2653 SetSelection(item, SELECTION_DEFAULT); | |
| 2654 View* hot_view = | |
| 2655 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN); | |
| 2656 CustomButton* hot_button = CustomButton::AsCustomButton(hot_view); | |
| 2657 if (hot_button) | |
| 2658 SetHotTrackedButton(hot_button, true); | |
| 2659 } | |
| 2660 | |
| 2612 } // namespace views | 2661 } // namespace views |
| OLD | NEW |