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

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

Issue 2741004: Makes it so child views of menuitemview can be traversed with the (Closed)
Patch Set: Tweaks Created 10 years, 6 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
« no previous file with comments | « views/controls/menu/menu_controller.h ('k') | views/controls/menu/menu_item_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "views/controls/menu/menu_controller.h" 5 #include "views/controls/menu/menu_controller.h"
6 6
7 #include "app/l10n_util.h" 7 #include "app/l10n_util.h"
8 #include "app/os_exchange_data.h" 8 #include "app/os_exchange_data.h"
9 #include "base/i18n/rtl.h" 9 #include "base/i18n/rtl.h"
10 #include "base/keyboard_codes.h" 10 #include "base/keyboard_codes.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 // Amount to inset submenus. 44 // Amount to inset submenus.
45 static const int kSubmenuHorizontalInset = 3; 45 static const int kSubmenuHorizontalInset = 3;
46 46
47 namespace views { 47 namespace views {
48 48
49 // Convenience for scrolling the view such that the origin is visible. 49 // Convenience for scrolling the view such that the origin is visible.
50 static void ScrollToVisible(View* view) { 50 static void ScrollToVisible(View* view) {
51 view->ScrollRectToVisible(gfx::Rect(gfx::Point(), view->size())); 51 view->ScrollRectToVisible(gfx::Rect(gfx::Point(), view->size()));
52 } 52 }
53 53
54 // Returns the first descendant of |view| that is hot tracked.
55 static View* GetFirstHotTrackedView(View* view) {
56 if (!view)
57 return NULL;
58
59 if (view->IsHotTracked())
60 return view;
61
62 for (int i = 0; i < view->GetChildViewCount(); ++i) {
63 View* hot_view = GetFirstHotTrackedView(view->GetChildViewAt(i));
64 if (hot_view)
65 return hot_view;
66 }
67 return NULL;
68 }
69
70 // Recurses through the child views of |view| returning the first view starting
71 // at |start| that is focusable. A value of -1 for |start| indicates to start at
72 // the first view (if |forward| is false, iterating starts at the last view). If
73 // |forward| is true the children are considered first to last, otherwise last
74 // to first.
75 static View* GetFirstFocusableView(View* view, int start, bool forward) {
76 if (forward) {
77 for (int i = start == -1 ? 0 : start; i < view->GetChildViewCount(); ++i) {
78 View* deepest = GetFirstFocusableView(view->GetChildViewAt(i), -1,
79 forward);
Jay Civelli 2010/06/09 16:03:47 Nit: you could use true instead of forward.
80 if (deepest)
81 return deepest;
82 }
83 } else {
84 for (int i = start == -1 ? view->GetChildViewCount() - 1 : start;
85 i >= 0; --i) {
86 View* deepest = GetFirstFocusableView(view->GetChildViewAt(i), -1,
87 forward);
Jay Civelli 2010/06/09 16:03:47 Nit: you could use false instead of forward.
88 if (deepest)
89 return deepest;
90 }
91 }
92 return view->IsFocusable() ? view : NULL;
93 }
94
95 // Returns the first child of |start| that is focusable.
96 static View* GetInitialFocusableView(View* start, bool forward) {
97 return GetFirstFocusableView(start, -1, forward);
98 }
99
100 // Returns the next view after |start_at| that is focusable. Returns NULL if
101 // there are no focusable children of |ancestor| after |start_at|.
102 static View* GetNextFocusableView(View* ancestor,
103 View* start_at,
104 bool forward) {
105 DCHECK(ancestor->IsParentOf(start_at));
106 View* parent = start_at;
107 do {
108 View* new_parent = parent->GetParent();
109 int index = new_parent->GetChildIndex(parent);
110 index += forward ? 1 : -1;
111 if (forward || index != -1) {
112 View* next = GetFirstFocusableView(new_parent, index, forward);
113 if (next)
114 return next;
115 }
116 parent = new_parent;
117 } while (parent != ancestor);
118 return NULL;
119 }
120
54 // MenuScrollTask -------------------------------------------------------------- 121 // MenuScrollTask --------------------------------------------------------------
55 122
56 // MenuScrollTask is used when the SubmenuView does not all fit on screen and 123 // MenuScrollTask is used when the SubmenuView does not all fit on screen and
57 // the mouse is over the scroll up/down buttons. MenuScrollTask schedules 124 // the mouse is over the scroll up/down buttons. MenuScrollTask schedules
58 // itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls 125 // itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls
59 // appropriately. 126 // appropriately.
60 127
61 class MenuController::MenuScrollTask { 128 class MenuController::MenuScrollTask {
62 public: 129 public:
63 MenuScrollTask() : submenu_(NULL) { 130 MenuScrollTask() : submenu_(NULL) {
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 bool update_immediately) { 335 bool update_immediately) {
269 size_t paths_differ_at = 0; 336 size_t paths_differ_at = 0;
270 std::vector<MenuItemView*> current_path; 337 std::vector<MenuItemView*> current_path;
271 std::vector<MenuItemView*> new_path; 338 std::vector<MenuItemView*> new_path;
272 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path, 339 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path,
273 &new_path, &paths_differ_at); 340 &new_path, &paths_differ_at);
274 341
275 size_t current_size = current_path.size(); 342 size_t current_size = current_path.size();
276 size_t new_size = new_path.size(); 343 size_t new_size = new_path.size();
277 344
345 if (pending_state_.item != menu_item && pending_state_.item) {
346 View* current_hot_view = GetFirstHotTrackedView(pending_state_.item);
347 if (current_hot_view)
348 current_hot_view->SetHotTracked(false);
349 }
350
278 // Notify the old path it isn't selected. 351 // Notify the old path it isn't selected.
279 for (size_t i = paths_differ_at; i < current_size; ++i) 352 for (size_t i = paths_differ_at; i < current_size; ++i)
280 current_path[i]->SetSelected(false); 353 current_path[i]->SetSelected(false);
281 354
282 // Notify the new path it is selected. 355 // Notify the new path it is selected.
283 for (size_t i = paths_differ_at; i < new_size; ++i) 356 for (size_t i = paths_differ_at; i < new_size; ++i)
284 new_path[i]->SetSelected(true); 357 new_path[i]->SetSelected(true);
285 358
286 if (menu_item && menu_item->GetDelegate()) 359 if (menu_item && menu_item->GetDelegate())
287 menu_item->GetDelegate()->SelectionChanged(menu_item); 360 menu_item->GetDelegate()->SelectionChanged(menu_item);
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 OpenSubmenuChangeSelectionIfCan(); 831 OpenSubmenuChangeSelectionIfCan();
759 break; 832 break;
760 833
761 case base::VKEY_LEFT: 834 case base::VKEY_LEFT:
762 if (base::i18n::IsRTL()) 835 if (base::i18n::IsRTL())
763 OpenSubmenuChangeSelectionIfCan(); 836 OpenSubmenuChangeSelectionIfCan();
764 else 837 else
765 CloseSubmenu(); 838 CloseSubmenu();
766 break; 839 break;
767 840
841 case base::VKEY_SPACE:
842 SendAcceleratorToHotTrackedView();
843 break;
844
768 case base::VKEY_RETURN: 845 case base::VKEY_RETURN:
769 if (pending_state_.item) { 846 if (pending_state_.item) {
770 if (pending_state_.item->HasSubmenu()) { 847 if (pending_state_.item->HasSubmenu()) {
771 OpenSubmenuChangeSelectionIfCan(); 848 OpenSubmenuChangeSelectionIfCan();
772 } else if (pending_state_.item->IsEnabled()) { 849 } else if (!SendAcceleratorToHotTrackedView() &&
850 pending_state_.item->IsEnabled()) {
773 Accept(pending_state_.item, 0); 851 Accept(pending_state_.item, 0);
774 return false; 852 return false;
775 } 853 }
776 } 854 }
777 break; 855 break;
778 856
779 case base::VKEY_ESCAPE: 857 case base::VKEY_ESCAPE:
780 if (!state_.item->GetParentMenuItem() || 858 if (!state_.item->GetParentMenuItem() ||
781 (!state_.item->GetParentMenuItem()->GetParentMenuItem() && 859 (!state_.item->GetParentMenuItem()->GetParentMenuItem() &&
782 (!state_.item->HasSubmenu() || 860 (!state_.item->HasSubmenu() ||
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
826 MenuController::~MenuController() { 904 MenuController::~MenuController() {
827 DCHECK(!showing_); 905 DCHECK(!showing_);
828 StopShowTimer(); 906 StopShowTimer();
829 StopCancelAllTimer(); 907 StopCancelAllTimer();
830 #ifdef DEBUG_MENU 908 #ifdef DEBUG_MENU
831 instance_count--; 909 instance_count--;
832 DLOG(INFO) << "destroyed MC, count=" << instance_count; 910 DLOG(INFO) << "destroyed MC, count=" << instance_count;
833 #endif 911 #endif
834 } 912 }
835 913
914 bool MenuController::SendAcceleratorToHotTrackedView() {
915 View* hot_view = GetFirstHotTrackedView(pending_state_.item);
916 if (!hot_view)
917 return false;
918
919 Accelerator accelerator(base::VKEY_RETURN, false, false, false);
920 hot_view->AcceleratorPressed(accelerator);
921 hot_view->SetHotTracked(true);
922 return true;
923 }
924
836 void MenuController::UpdateInitialLocation( 925 void MenuController::UpdateInitialLocation(
837 const gfx::Rect& bounds, 926 const gfx::Rect& bounds,
838 MenuItemView::AnchorPosition position) { 927 MenuItemView::AnchorPosition position) {
839 pending_state_.initial_bounds = bounds; 928 pending_state_.initial_bounds = bounds;
840 if (bounds.height() > 1) { 929 if (bounds.height() > 1) {
841 // Inset the bounds slightly, otherwise drag coordinates don't line up 930 // Inset the bounds slightly, otherwise drag coordinates don't line up
842 // nicely and menus close prematurely. 931 // nicely and menus close prematurely.
843 pending_state_.initial_bounds.Inset(0, 1); 932 pending_state_.initial_bounds.Inset(0, 1);
844 } 933 }
845 pending_state_.anchor = position; 934 pending_state_.anchor = position;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 CloseMenu(item); 1017 CloseMenu(item);
929 last_item = item; 1018 last_item = item;
930 item = item->GetParentMenuItem(); 1019 item = item->GetParentMenuItem();
931 } 1020 }
932 i->submenu_open = false; 1021 i->submenu_open = false;
933 i->item = last_item; 1022 i->item = last_item;
934 } 1023 }
935 } 1024 }
936 1025
937 MenuItemView* MenuController::GetMenuItemAt(View* source, int x, int y) { 1026 MenuItemView* MenuController::GetMenuItemAt(View* source, int x, int y) {
1027 // Walk the view hierarchy until we find a menu item (or the root).
938 View* child_under_mouse = source->GetViewForPoint(gfx::Point(x, y)); 1028 View* child_under_mouse = source->GetViewForPoint(gfx::Point(x, y));
1029 while (child_under_mouse &&
1030 child_under_mouse->GetID() != MenuItemView::kMenuItemViewID) {
1031 child_under_mouse = child_under_mouse->GetParent();
1032 }
939 if (child_under_mouse && child_under_mouse->IsEnabled() && 1033 if (child_under_mouse && child_under_mouse->IsEnabled() &&
940 child_under_mouse->GetID() == MenuItemView::kMenuItemViewID) { 1034 child_under_mouse->GetID() == MenuItemView::kMenuItemViewID) {
941 return static_cast<MenuItemView*>(child_under_mouse); 1035 return static_cast<MenuItemView*>(child_under_mouse);
942 } 1036 }
943 return NULL; 1037 return NULL;
944 } 1038 }
945 1039
946 MenuItemView* MenuController::GetEmptyMenuItemAt(View* source, int x, int y) { 1040 MenuItemView* MenuController::GetEmptyMenuItemAt(View* source, int x, int y) {
947 View* child_under_mouse = source->GetViewForPoint(gfx::Point(x, y)); 1041 View* child_under_mouse = source->GetViewForPoint(gfx::Point(x, y));
948 if (child_under_mouse && 1042 if (child_under_mouse &&
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
1317 void MenuController::IncrementSelection(int delta) { 1411 void MenuController::IncrementSelection(int delta) {
1318 MenuItemView* item = pending_state_.item; 1412 MenuItemView* item = pending_state_.item;
1319 DCHECK(item); 1413 DCHECK(item);
1320 if (pending_state_.submenu_open && item->HasSubmenu() && 1414 if (pending_state_.submenu_open && item->HasSubmenu() &&
1321 item->GetSubmenu()->IsShowing()) { 1415 item->GetSubmenu()->IsShowing()) {
1322 // A menu is selected and open, but none of its children are selected, 1416 // A menu is selected and open, but none of its children are selected,
1323 // select the first menu item. 1417 // select the first menu item.
1324 if (item->GetSubmenu()->GetMenuItemCount()) { 1418 if (item->GetSubmenu()->GetMenuItemCount()) {
1325 SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, false); 1419 SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, false);
1326 ScrollToVisible(item->GetSubmenu()->GetMenuItemAt(0)); 1420 ScrollToVisible(item->GetSubmenu()->GetMenuItemAt(0));
1327 return; // return so else case can fall through. 1421 return;
1328 } 1422 }
1329 } 1423 }
1424
1425 if (item->GetChildViewCount()) {
1426 View* hot_view = GetFirstHotTrackedView(item);
1427 if (hot_view) {
1428 hot_view->SetHotTracked(false);
1429 View* to_make_hot = GetNextFocusableView(item, hot_view, delta == 1);
1430 if (to_make_hot) {
1431 to_make_hot->SetHotTracked(true);
1432 return;
1433 }
1434 } else {
1435 View* to_make_hot = GetInitialFocusableView(item, delta == 1);
1436 if (to_make_hot) {
1437 to_make_hot->SetHotTracked(true);
1438 return;
1439 }
1440 }
1441 }
1442
1330 if (item->GetParentMenuItem()) { 1443 if (item->GetParentMenuItem()) {
1331 MenuItemView* parent = item->GetParentMenuItem(); 1444 MenuItemView* parent = item->GetParentMenuItem();
1332 int parent_count = parent->GetSubmenu()->GetMenuItemCount(); 1445 int parent_count = parent->GetSubmenu()->GetMenuItemCount();
1333 if (parent_count > 1) { 1446 if (parent_count > 1) {
1334 for (int i = 0; i < parent_count; ++i) { 1447 for (int i = 0; i < parent_count; ++i) {
1335 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) { 1448 if (parent->GetSubmenu()->GetMenuItemAt(i) == item) {
1336 int next_index = (i + delta + parent_count) % parent_count; 1449 int next_index = (i + delta + parent_count) % parent_count;
1337 ScrollToVisible(parent->GetSubmenu()->GetMenuItemAt(next_index)); 1450 ScrollToVisible(parent->GetSubmenu()->GetMenuItemAt(next_index));
1338 SetSelection(parent->GetSubmenu()->GetMenuItemAt(next_index), false, 1451 MenuItemView* to_select =
1339 false); 1452 parent->GetSubmenu()->GetMenuItemAt(next_index);
1453 SetSelection(to_select, false, false);
1454 View* to_make_hot = GetInitialFocusableView(to_select, delta == 1);
1455 if (to_make_hot)
1456 to_make_hot->SetHotTracked(true);
1340 break; 1457 break;
1341 } 1458 }
1342 } 1459 }
1343 } 1460 }
1344 } 1461 }
1345 } 1462 }
1346 1463
1347 void MenuController::OpenSubmenuChangeSelectionIfCan() { 1464 void MenuController::OpenSubmenuChangeSelectionIfCan() {
1348 MenuItemView* item = pending_state_.item; 1465 MenuItemView* item = pending_state_.item;
1349 if (item->HasSubmenu()) { 1466 if (item->HasSubmenu()) {
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
1518 if (!scroll_task_.get()) 1635 if (!scroll_task_.get())
1519 scroll_task_.reset(new MenuScrollTask()); 1636 scroll_task_.reset(new MenuScrollTask());
1520 scroll_task_->Update(part); 1637 scroll_task_->Update(part);
1521 } 1638 }
1522 1639
1523 void MenuController::StopScrolling() { 1640 void MenuController::StopScrolling() {
1524 scroll_task_.reset(NULL); 1641 scroll_task_.reset(NULL);
1525 } 1642 }
1526 1643
1527 } // namespace views 1644 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/menu/menu_controller.h ('k') | views/controls/menu/menu_item_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698