Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(442)

Side by Side Diff: ui/views/controls/menu/menu_controller.cc

Issue 1230163004: Selects last item in a menu when pressing 'up' initially (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Selects last item in a menu when pressing 'up' initially (nits) Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/strings/utf_string_conversions.h" 9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h" 10 #include "base/time/time.h"
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 // Returns true if |menu| doesn't have a mnemonic and first character of the its 82 // Returns true if |menu| doesn't have a mnemonic and first character of the its
83 // title is |key|. 83 // title is |key|.
84 bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) { 84 bool TitleMatchesMnemonic(MenuItemView* menu, base::char16 key) {
85 if (menu->GetMnemonic()) 85 if (menu->GetMnemonic())
86 return false; 86 return false;
87 87
88 base::string16 lower_title = base::i18n::ToLower(menu->title()); 88 base::string16 lower_title = base::i18n::ToLower(menu->title());
89 return !lower_title.empty() && lower_title[0] == key; 89 return !lower_title.empty() && lower_title[0] == key;
90 } 90 }
91 91
92 } // namespace
93
94 // Returns the first descendant of |view| that is hot tracked. 92 // Returns the first descendant of |view| that is hot tracked.
95 static CustomButton* GetFirstHotTrackedView(View* view) { 93 static CustomButton* GetFirstHotTrackedView(View* view) {
96 if (!view) 94 if (!view)
97 return NULL; 95 return NULL;
98 CustomButton* button = CustomButton::AsCustomButton(view); 96 CustomButton* button = CustomButton::AsCustomButton(view);
99 if (button) { 97 if (button) {
100 if (button->IsHotTracked()) 98 if (button->IsHotTracked())
101 return button; 99 return button;
102 } 100 }
103 101
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 if (forward || index != -1) { 148 if (forward || index != -1) {
151 View* next = GetFirstFocusableView(new_parent, index, forward); 149 View* next = GetFirstFocusableView(new_parent, index, forward);
152 if (next) 150 if (next)
153 return next; 151 return next;
154 } 152 }
155 parent = new_parent; 153 parent = new_parent;
156 } while (parent != ancestor); 154 } while (parent != ancestor);
157 return NULL; 155 return NULL;
158 } 156 }
159 157
158 } // namespace
159
160 // MenuScrollTask -------------------------------------------------------------- 160 // MenuScrollTask --------------------------------------------------------------
161 161
162 // MenuScrollTask is used when the SubmenuView does not all fit on screen and 162 // MenuScrollTask is used when the SubmenuView does not all fit on screen and
163 // the mouse is over the scroll up/down buttons. MenuScrollTask schedules 163 // the mouse is over the scroll up/down buttons. MenuScrollTask schedules
164 // itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls 164 // itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls
165 // appropriately. 165 // appropriately.
166 166
167 class MenuController::MenuScrollTask { 167 class MenuController::MenuScrollTask {
168 public: 168 public:
169 MenuScrollTask() : submenu_(NULL), is_scrolling_up_(false), start_y_(0) { 169 MenuScrollTask() : submenu_(NULL), is_scrolling_up_(false), start_y_(0) {
(...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after
1021 item->GetWidget()->RunShellDrag(NULL, data, widget_loc, drag_ops, 1021 item->GetWidget()->RunShellDrag(NULL, data, widget_loc, drag_ops,
1022 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); 1022 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
1023 did_initiate_drag_ = false; 1023 did_initiate_drag_ = false;
1024 } 1024 }
1025 1025
1026 bool MenuController::OnKeyDown(ui::KeyboardCode key_code) { 1026 bool MenuController::OnKeyDown(ui::KeyboardCode key_code) {
1027 DCHECK(blocking_run_); 1027 DCHECK(blocking_run_);
1028 1028
1029 switch (key_code) { 1029 switch (key_code) {
1030 case ui::VKEY_UP: 1030 case ui::VKEY_UP:
1031 IncrementSelection(-1); 1031 IncrementSelection(INCREMENT_SELECTION_UP);
1032 break; 1032 break;
1033 1033
1034 case ui::VKEY_DOWN: 1034 case ui::VKEY_DOWN:
1035 IncrementSelection(1); 1035 IncrementSelection(INCREMENT_SELECTION_DOWN);
1036 break; 1036 break;
1037 1037
1038 // Handling of VK_RIGHT and VK_LEFT is different depending on the UI 1038 // Handling of VK_RIGHT and VK_LEFT is different depending on the UI
1039 // layout. 1039 // layout.
1040 case ui::VKEY_RIGHT: 1040 case ui::VKEY_RIGHT:
1041 if (base::i18n::IsRTL()) 1041 if (base::i18n::IsRTL())
1042 CloseSubmenu(); 1042 CloseSubmenu();
1043 else 1043 else
1044 OpenSubmenuChangeSelectionIfCan(); 1044 OpenSubmenuChangeSelectionIfCan();
1045 break; 1045 break;
(...skipping 850 matching lines...) Expand 10 before | Expand all | Expand 10 after
1896 pref.height() / 2 - y + y_old); 1896 pref.height() / 2 - y + y_old);
1897 } 1897 }
1898 return gfx::Rect(x, y, pref.width(), pref.height()); 1898 return gfx::Rect(x, y, pref.width(), pref.height());
1899 } 1899 }
1900 1900
1901 // static 1901 // static
1902 int MenuController::MenuDepth(MenuItemView* item) { 1902 int MenuController::MenuDepth(MenuItemView* item) {
1903 return item ? (MenuDepth(item->GetParentMenuItem()) + 1) : 0; 1903 return item ? (MenuDepth(item->GetParentMenuItem()) + 1) : 0;
1904 } 1904 }
1905 1905
1906 void MenuController::IncrementSelection(int delta) { 1906 void MenuController::IncrementSelection(
1907 SelectionIncrementDirectionType direction) {
1907 MenuItemView* item = pending_state_.item; 1908 MenuItemView* item = pending_state_.item;
1908 DCHECK(item); 1909 DCHECK(item);
1909 if (pending_state_.submenu_open && item->HasSubmenu() && 1910 if (pending_state_.submenu_open && item->HasSubmenu() &&
1910 item->GetSubmenu()->IsShowing()) { 1911 item->GetSubmenu()->IsShowing()) {
1911 // A menu is selected and open, but none of its children are selected, 1912 // A menu is selected and open, but none of its children are selected,
1912 // select the first menu item that is visible and enabled. 1913 // select the first menu item that is visible and enabled.
1913 if (item->GetSubmenu()->GetMenuItemCount()) { 1914 if (item->GetSubmenu()->GetMenuItemCount()) {
1914 MenuItemView* to_select = FindFirstSelectableMenuItem(item); 1915 MenuItemView* to_select = FindInitialSelectableMenuItem(item, direction);
1915 if (to_select) 1916 if (to_select)
1916 SetSelection(to_select, SELECTION_DEFAULT); 1917 SetSelection(to_select, SELECTION_DEFAULT);
1917 return; 1918 return;
1918 } 1919 }
1919 } 1920 }
1920 1921
1921 if (item->has_children()) { 1922 if (item->has_children()) {
1922 CustomButton* button = GetFirstHotTrackedView(item); 1923 CustomButton* button = GetFirstHotTrackedView(item);
1923 if (button) { 1924 if (button) {
1924 button->SetHotTracked(false); 1925 button->SetHotTracked(false);
1925 View* to_make_hot = GetNextFocusableView(item, button, delta == 1); 1926 View* to_make_hot = GetNextFocusableView(
1927 item, button, direction == INCREMENT_SELECTION_DOWN);
1926 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); 1928 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot);
1927 if (button_hot) { 1929 if (button_hot) {
1928 button_hot->SetHotTracked(true); 1930 button_hot->SetHotTracked(true);
1929 return; 1931 return;
1930 } 1932 }
1931 } else { 1933 } else {
1932 View* to_make_hot = GetInitialFocusableView(item, delta == 1); 1934 View* to_make_hot =
1935 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN);
1933 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); 1936 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot);
1934 if (button_hot) { 1937 if (button_hot) {
1935 button_hot->SetHotTracked(true); 1938 button_hot->SetHotTracked(true);
1936 return; 1939 return;
1937 } 1940 }
1938 } 1941 }
1939 } 1942 }
1940 1943
1941 MenuItemView* parent = item->GetParentMenuItem(); 1944 MenuItemView* parent = item->GetParentMenuItem();
1942 if (parent) { 1945 if (parent) {
1943 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); 1946 int parent_count = parent->GetSubmenu()->GetMenuItemCount();
1944 if (parent_count > 1) { 1947 if (parent_count > 1) {
1945 for (int i = 0; i < parent_count; ++i) { 1948 for (int i = 0; i < parent_count; ++i) {
1946 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { 1949 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) {
1947 MenuItemView* to_select = 1950 MenuItemView* to_select =
1948 FindNextSelectableMenuItem(parent, i, delta); 1951 FindNextSelectableMenuItem(parent, i, direction);
1949 if (!to_select) 1952 if (!to_select)
1950 break; 1953 break;
1951 SetSelection(to_select, SELECTION_DEFAULT); 1954 SetSelection(to_select, SELECTION_DEFAULT);
1952 View* to_make_hot = GetInitialFocusableView(to_select, delta == 1); 1955 View* to_make_hot = GetInitialFocusableView(
1956 to_select, direction == INCREMENT_SELECTION_DOWN);
1953 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); 1957 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot);
1954 if (button_hot) 1958 if (button_hot)
1955 button_hot->SetHotTracked(true); 1959 button_hot->SetHotTracked(true);
1956 break; 1960 break;
1957 } 1961 }
1958 } 1962 }
1959 } 1963 }
1960 } 1964 }
1961 } 1965 }
1962 1966
1963 MenuItemView* MenuController::FindFirstSelectableMenuItem( 1967 MenuItemView* MenuController::FindInitialSelectableMenuItem(
1964 MenuItemView* parent) { 1968 MenuItemView* parent,
1965 MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(0); 1969 SelectionIncrementDirectionType direction) {
1966 if (!child->visible() || !child->enabled()) 1970 return FindNextSelectableMenuItem(
1967 child = FindNextSelectableMenuItem(parent, 0, 1); 1971 parent, direction == INCREMENT_SELECTION_DOWN ? -1 : 0, direction);
1968 return child;
1969 } 1972 }
1970 1973
1971 MenuItemView* MenuController::FindNextSelectableMenuItem(MenuItemView* parent, 1974 MenuItemView* MenuController::FindNextSelectableMenuItem(
1972 int index, 1975 MenuItemView* parent,
1973 int delta) { 1976 int index,
1974 int start_index = index; 1977 SelectionIncrementDirectionType direction) {
1975 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); 1978 int parent_count = parent->GetSubmenu()->GetMenuItemCount();
1979 int stop_index = (index + parent_count) % parent_count;
1980 bool include_all_items =
1981 (index == -1 && direction == INCREMENT_SELECTION_DOWN) ||
1982 (index == 0 && direction == INCREMENT_SELECTION_UP);
1983 int delta = direction == INCREMENT_SELECTION_UP ? -1 : 1;
1976 // Loop through the menu items skipping any invisible menus. The loop stops 1984 // Loop through the menu items skipping any invisible menus. The loop stops
1977 // when we wrap or find a visible and enabled child. 1985 // when we wrap or find a visible and enabled child.
1978 do { 1986 do {
1979 index = (index + delta + parent_count) % parent_count; 1987 index = (index + delta + parent_count) % parent_count;
1980 if (index == start_index) 1988 if (index == stop_index && !include_all_items)
1981 return NULL; 1989 return NULL;
1982 MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(index); 1990 MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(index);
1983 if (child->visible() && child->enabled()) 1991 if (child->visible() && child->enabled())
1984 return child; 1992 return child;
1985 } while (index != start_index); 1993 } while (index != stop_index);
1986 return NULL; 1994 return NULL;
1987 } 1995 }
1988 1996
1989 void MenuController::OpenSubmenuChangeSelectionIfCan() { 1997 void MenuController::OpenSubmenuChangeSelectionIfCan() {
1990 MenuItemView* item = pending_state_.item; 1998 MenuItemView* item = pending_state_.item;
1991 if (!item->HasSubmenu() || !item->enabled()) 1999 if (!item->HasSubmenu() || !item->enabled())
1992 return; 2000 return;
1993 MenuItemView* to_select = NULL; 2001 MenuItemView* to_select = NULL;
1994 if (item->GetSubmenu()->GetMenuItemCount() > 0) 2002 if (item->GetSubmenu()->GetMenuItemCount() > 0)
1995 to_select = FindFirstSelectableMenuItem(item); 2003 to_select = FindInitialSelectableMenuItem(item, INCREMENT_SELECTION_DOWN);
1996 if (to_select) { 2004 if (to_select) {
1997 SetSelection(to_select, SELECTION_UPDATE_IMMEDIATELY); 2005 SetSelection(to_select, SELECTION_UPDATE_IMMEDIATELY);
1998 return; 2006 return;
1999 } 2007 }
2000 // No menu items, just show the sub-menu. 2008 // No menu items, just show the sub-menu.
2001 SetSelection(item, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY); 2009 SetSelection(item, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
2002 } 2010 }
2003 2011
2004 void MenuController::CloseSubmenu() { 2012 void MenuController::CloseSubmenu() {
2005 MenuItemView* item = state_.item; 2013 MenuItemView* item = state_.item;
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
2364 } 2372 }
2365 } 2373 }
2366 2374
2367 gfx::Screen* MenuController::GetScreen() { 2375 gfx::Screen* MenuController::GetScreen() {
2368 Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL; 2376 Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL;
2369 return root ? gfx::Screen::GetScreenFor(root->GetNativeView()) 2377 return root ? gfx::Screen::GetScreenFor(root->GetNativeView())
2370 : gfx::Screen::GetNativeScreen(); 2378 : gfx::Screen::GetNativeScreen();
2371 } 2379 }
2372 2380
2373 } // namespace views 2381 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/menu/menu_controller.h ('k') | ui/views/controls/menu/menu_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698