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

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 (comments) 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 843 matching lines...) Expand 10 before | Expand all | Expand 10 after
1889 pref.height() / 2 - y + y_old); 1889 pref.height() / 2 - y + y_old);
1890 } 1890 }
1891 return gfx::Rect(x, y, pref.width(), pref.height()); 1891 return gfx::Rect(x, y, pref.width(), pref.height());
1892 } 1892 }
1893 1893
1894 // static 1894 // static
1895 int MenuController::MenuDepth(MenuItemView* item) { 1895 int MenuController::MenuDepth(MenuItemView* item) {
1896 return item ? (MenuDepth(item->GetParentMenuItem()) + 1) : 0; 1896 return item ? (MenuDepth(item->GetParentMenuItem()) + 1) : 0;
1897 } 1897 }
1898 1898
1899 void MenuController::IncrementSelection(int delta) { 1899 void MenuController::IncrementSelection(
1900 SelectionIncrementDirectionType direction) {
1900 MenuItemView* item = pending_state_.item; 1901 MenuItemView* item = pending_state_.item;
1901 DCHECK(item); 1902 DCHECK(item);
1902 if (pending_state_.submenu_open && item->HasSubmenu() && 1903 if (pending_state_.submenu_open && item->HasSubmenu() &&
1903 item->GetSubmenu()->IsShowing()) { 1904 item->GetSubmenu()->IsShowing()) {
1904 // A menu is selected and open, but none of its children are selected, 1905 // A menu is selected and open, but none of its children are selected,
1905 // select the first menu item that is visible and enabled. 1906 // select the first menu item that is visible and enabled.
1906 if (item->GetSubmenu()->GetMenuItemCount()) { 1907 if (item->GetSubmenu()->GetMenuItemCount()) {
1907 MenuItemView* to_select = FindFirstSelectableMenuItem(item); 1908 MenuItemView* to_select = FindInitialSelectableMenuItem(item, direction);
1908 if (to_select) 1909 if (to_select)
1909 SetSelection(to_select, SELECTION_DEFAULT); 1910 SetSelection(to_select, SELECTION_DEFAULT);
1910 return; 1911 return;
1911 } 1912 }
1912 } 1913 }
1913 1914
1914 if (item->has_children()) { 1915 if (item->has_children()) {
1915 CustomButton* button = GetFirstHotTrackedView(item); 1916 CustomButton* button = GetFirstHotTrackedView(item);
1916 if (button) { 1917 if (button) {
1917 button->SetHotTracked(false); 1918 button->SetHotTracked(false);
1918 View* to_make_hot = GetNextFocusableView(item, button, delta == 1); 1919 View* to_make_hot = GetNextFocusableView(
1920 item, button, direction == INCREMENT_SELECTION_DOWN);
1919 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); 1921 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot);
1920 if (button_hot) { 1922 if (button_hot) {
1921 button_hot->SetHotTracked(true); 1923 button_hot->SetHotTracked(true);
1922 return; 1924 return;
1923 } 1925 }
1924 } else { 1926 } else {
1925 View* to_make_hot = GetInitialFocusableView(item, delta == 1); 1927 View* to_make_hot =
1928 GetInitialFocusableView(item, direction == INCREMENT_SELECTION_DOWN);
1926 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); 1929 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot);
1927 if (button_hot) { 1930 if (button_hot) {
1928 button_hot->SetHotTracked(true); 1931 button_hot->SetHotTracked(true);
1929 return; 1932 return;
1930 } 1933 }
1931 } 1934 }
1932 } 1935 }
1933 1936
1934 MenuItemView* parent = item->GetParentMenuItem(); 1937 MenuItemView* parent = item->GetParentMenuItem();
1935 if (parent) { 1938 if (parent) {
1936 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); 1939 int parent_count = parent->GetSubmenu()->GetMenuItemCount();
1937 if (parent_count > 1) { 1940 if (parent_count > 1) {
1938 for (int i = 0; i < parent_count; ++i) { 1941 for (int i = 0; i < parent_count; ++i) {
1939 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { 1942 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) {
1940 MenuItemView* to_select = 1943 MenuItemView* to_select =
1941 FindNextSelectableMenuItem(parent, i, delta); 1944 FindNextSelectableMenuItem(parent, i, direction);
1942 if (!to_select) 1945 if (!to_select)
1943 break; 1946 break;
1944 SetSelection(to_select, SELECTION_DEFAULT); 1947 SetSelection(to_select, SELECTION_DEFAULT);
1945 View* to_make_hot = GetInitialFocusableView(to_select, delta == 1); 1948 View* to_make_hot = GetInitialFocusableView(
1949 to_select, direction == INCREMENT_SELECTION_DOWN);
1946 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot); 1950 CustomButton* button_hot = CustomButton::AsCustomButton(to_make_hot);
1947 if (button_hot) 1951 if (button_hot)
1948 button_hot->SetHotTracked(true); 1952 button_hot->SetHotTracked(true);
1949 break; 1953 break;
1950 } 1954 }
1951 } 1955 }
1952 } 1956 }
1953 } 1957 }
1954 } 1958 }
1955 1959
1956 MenuItemView* MenuController::FindFirstSelectableMenuItem( 1960 MenuItemView* MenuController::FindInitialSelectableMenuItem(
1957 MenuItemView* parent) { 1961 MenuItemView* parent,
1958 MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(0); 1962 SelectionIncrementDirectionType direction) {
1959 if (!child->visible() || !child->enabled()) 1963 return FindNextSelectableMenuItem(
1960 child = FindNextSelectableMenuItem(parent, 0, 1); 1964 parent, direction == INCREMENT_SELECTION_DOWN ? -1 : 0, direction);
1961 return child;
1962 } 1965 }
1963 1966
1964 MenuItemView* MenuController::FindNextSelectableMenuItem(MenuItemView* parent, 1967 MenuItemView* MenuController::FindNextSelectableMenuItem(
1965 int index, 1968 MenuItemView* parent,
1966 int delta) { 1969 int index,
1967 int start_index = index; 1970 SelectionIncrementDirectionType direction) {
1968 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); 1971 int parent_count = parent->GetSubmenu()->GetMenuItemCount();
1972 int stop_index = (index + parent_count) % parent_count;
1973 bool include_all_items =
1974 (index == -1 && direction == INCREMENT_SELECTION_DOWN) ||
1975 (index == 0 && direction == INCREMENT_SELECTION_UP);
1976 int delta = direction == INCREMENT_SELECTION_UP ? -1 : 1;
1969 // Loop through the menu items skipping any invisible menus. The loop stops 1977 // Loop through the menu items skipping any invisible menus. The loop stops
1970 // when we wrap or find a visible and enabled child. 1978 // when we wrap or find a visible and enabled child.
1971 do { 1979 do {
1972 index = (index + delta + parent_count) % parent_count; 1980 index = (index + delta + parent_count) % parent_count;
1973 if (index == start_index) 1981 if (index == stop_index && !include_all_items)
1974 return NULL; 1982 return NULL;
1975 MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(index); 1983 MenuItemView* child = parent->GetSubmenu()->GetMenuItemAt(index);
1976 if (child->visible() && child->enabled()) 1984 if (child->visible() && child->enabled())
1977 return child; 1985 return child;
1978 } while (index != start_index); 1986 } while (index != stop_index);
1979 return NULL; 1987 return NULL;
1980 } 1988 }
1981 1989
1982 void MenuController::OpenSubmenuChangeSelectionIfCan() { 1990 void MenuController::OpenSubmenuChangeSelectionIfCan() {
1983 MenuItemView* item = pending_state_.item; 1991 MenuItemView* item = pending_state_.item;
1984 if (!item->HasSubmenu() || !item->enabled()) 1992 if (!item->HasSubmenu() || !item->enabled())
1985 return; 1993 return;
1986 MenuItemView* to_select = NULL; 1994 MenuItemView* to_select = NULL;
1987 if (item->GetSubmenu()->GetMenuItemCount() > 0) 1995 if (item->GetSubmenu()->GetMenuItemCount() > 0)
1988 to_select = FindFirstSelectableMenuItem(item); 1996 to_select = FindInitialSelectableMenuItem(item, INCREMENT_SELECTION_DOWN);
1989 if (to_select) { 1997 if (to_select) {
1990 SetSelection(to_select, SELECTION_UPDATE_IMMEDIATELY); 1998 SetSelection(to_select, SELECTION_UPDATE_IMMEDIATELY);
1991 return; 1999 return;
1992 } 2000 }
1993 // No menu items, just show the sub-menu. 2001 // No menu items, just show the sub-menu.
1994 SetSelection(item, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY); 2002 SetSelection(item, SELECTION_OPEN_SUBMENU | SELECTION_UPDATE_IMMEDIATELY);
1995 } 2003 }
1996 2004
1997 void MenuController::CloseSubmenu() { 2005 void MenuController::CloseSubmenu() {
1998 MenuItemView* item = state_.item; 2006 MenuItemView* item = state_.item;
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
2357 } 2365 }
2358 } 2366 }
2359 2367
2360 gfx::Screen* MenuController::GetScreen() { 2368 gfx::Screen* MenuController::GetScreen() {
2361 Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL; 2369 Widget* root = owner_ ? owner_->GetTopLevelWidget() : NULL;
2362 return root ? gfx::Screen::GetScreenFor(root->GetNativeView()) 2370 return root ? gfx::Screen::GetScreenFor(root->GetNativeView())
2363 : gfx::Screen::GetNativeScreen(); 2371 : gfx::Screen::GetNativeScreen();
2364 } 2372 }
2365 2373
2366 } // namespace views 2374 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698