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

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

Issue 328012: Makes it so that when a folder is open on the bookmark bar and the... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « views/controls/menu/menu_controller.h ('k') | views/controls/menu/menu_delegate.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) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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/gfx/canvas.h" 7 #include "app/gfx/canvas.h"
8 #include "app/l10n_util.h" 8 #include "app/l10n_util.h"
9 #include "app/os_exchange_data.h" 9 #include "app/os_exchange_data.h"
10 #include "base/keyboard_codes.h" 10 #include "base/keyboard_codes.h"
11 #include "base/time.h" 11 #include "base/time.h"
12 #include "views/controls/button/menu_button.h"
12 #include "views/controls/menu/menu_scroll_view_container.h" 13 #include "views/controls/menu/menu_scroll_view_container.h"
13 #include "views/controls/menu/submenu_view.h" 14 #include "views/controls/menu/submenu_view.h"
14 #include "views/drag_utils.h" 15 #include "views/drag_utils.h"
15 #include "views/screen.h" 16 #include "views/screen.h"
16 #include "views/view_constants.h" 17 #include "views/view_constants.h"
17 #include "views/widget/root_view.h" 18 #include "views/widget/root_view.h"
18 #include "views/widget/widget.h" 19 #include "views/widget/widget.h"
19 20
20 using base::Time; 21 using base::Time;
21 using base::TimeDelta; 22 using base::TimeDelta;
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 MenuController* MenuController::GetActiveInstance() { 137 MenuController* MenuController::GetActiveInstance() {
137 return active_instance_; 138 return active_instance_;
138 } 139 }
139 140
140 #ifdef DEBUG_MENU 141 #ifdef DEBUG_MENU
141 static int instance_count = 0; 142 static int instance_count = 0;
142 static int nested_depth = 0; 143 static int nested_depth = 0;
143 #endif 144 #endif
144 145
145 MenuItemView* MenuController::Run(gfx::NativeWindow parent, 146 MenuItemView* MenuController::Run(gfx::NativeWindow parent,
147 MenuButton* button,
146 MenuItemView* root, 148 MenuItemView* root,
147 const gfx::Rect& bounds, 149 const gfx::Rect& bounds,
148 MenuItemView::AnchorPosition position, 150 MenuItemView::AnchorPosition position,
149 int* result_mouse_event_flags) { 151 int* result_mouse_event_flags) {
150 exit_all_ = false; 152 exit_all_ = false;
151 possible_drag_ = false; 153 possible_drag_ = false;
152 154
153 bool nested_menu = showing_; 155 bool nested_menu = showing_;
154 if (showing_) { 156 if (showing_) {
155 // Only support nesting of blocking_run menus, nesting of 157 // Only support nesting of blocking_run menus, nesting of
156 // blocking/non-blocking shouldn't be needed. 158 // blocking/non-blocking shouldn't be needed.
157 DCHECK(blocking_run_); 159 DCHECK(blocking_run_);
158 160
159 // We're already showing, push the current state. 161 // We're already showing, push the current state.
160 menu_stack_.push_back(state_); 162 menu_stack_.push_back(state_);
161 163
162 // The context menu should be owned by the same parent. 164 // The context menu should be owned by the same parent.
163 DCHECK(owner_ == parent); 165 DCHECK(owner_ == parent);
164 } else { 166 } else {
165 showing_ = true; 167 showing_ = true;
166 } 168 }
167 169
168 // Reset current state. 170 // Reset current state.
169 pending_state_ = State(); 171 pending_state_ = State();
170 state_ = State(); 172 state_ = State();
171 pending_state_.initial_bounds = bounds; 173 UpdateInitialLocation(bounds, position);
172 if (bounds.height() > 1) { 174
173 // Inset the bounds slightly, otherwise drag coordinates don't line up
174 // nicely and menus close prematurely.
175 pending_state_.initial_bounds.Inset(0, 1);
176 }
177 pending_state_.anchor = position;
178 owner_ = parent; 175 owner_ = parent;
179 176
180 // Calculate the bounds of the monitor we'll show menus on. Do this once to
181 // avoid repeated system queries for the info.
182 pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
183 bounds.origin());
184
185 // Set the selection, which opens the initial menu. 177 // Set the selection, which opens the initial menu.
186 SetSelection(root, true, true); 178 SetSelection(root, true, true);
187 179
188 if (!blocking_run_) { 180 if (!blocking_run_) {
189 // Start the timer to hide the menu. This is needed as we get no 181 // Start the timer to hide the menu. This is needed as we get no
190 // notification when the drag has finished. 182 // notification when the drag has finished.
191 StartCancelAllTimer(); 183 StartCancelAllTimer();
192 return NULL; 184 return NULL;
185 } else if (button) {
186 menu_button_ = button;
193 } 187 }
194 188
195 #ifdef DEBUG_MENU 189 #ifdef DEBUG_MENU
196 nested_depth++; 190 nested_depth++;
197 DLOG(INFO) << " entering nested loop, depth=" << nested_depth; 191 DLOG(INFO) << " entering nested loop, depth=" << nested_depth;
198 #endif 192 #endif
199 193
200 MessageLoopForUI* loop = MessageLoopForUI::current(); 194 MessageLoopForUI* loop = MessageLoopForUI::current();
201 if (MenuItemView::allow_task_nesting_during_run_) { 195 if (MenuItemView::allow_task_nesting_during_run_) {
202 bool did_allow_task_nesting = loop->NestableTasksAllowed(); 196 bool did_allow_task_nesting = loop->NestableTasksAllowed();
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 // We're nested and about to return a value. The caller might enter another 232 // We're nested and about to return a value. The caller might enter another
239 // blocking loop. We need to make sure all menus are hidden before that 233 // blocking loop. We need to make sure all menus are hidden before that
240 // happens otherwise the menus will stay on screen. 234 // happens otherwise the menus will stay on screen.
241 CloseAllNestedMenus(); 235 CloseAllNestedMenus();
242 236
243 // Set exit_all_ to true, which makes sure all nested loops exit 237 // Set exit_all_ to true, which makes sure all nested loops exit
244 // immediately. 238 // immediately.
245 exit_all_ = true; 239 exit_all_ = true;
246 } 240 }
247 241
242 if (menu_button_) {
243 menu_button_->SetState(CustomButton::BS_NORMAL);
244 menu_button_->SchedulePaint();
245 }
246
248 return result; 247 return result;
249 } 248 }
250 249
251 void MenuController::SetSelection(MenuItemView* menu_item, 250 void MenuController::SetSelection(MenuItemView* menu_item,
252 bool open_submenu, 251 bool open_submenu,
253 bool update_immediately) { 252 bool update_immediately) {
254 size_t paths_differ_at = 0; 253 size_t paths_differ_at = 0;
255 std::vector<MenuItemView*> current_path; 254 std::vector<MenuItemView*> current_path;
256 std::vector<MenuItemView*> new_path; 255 std::vector<MenuItemView*> new_path;
257 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path, 256 BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path,
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 } 308 }
310 309
311 void MenuController::OnMousePressed(SubmenuView* source, 310 void MenuController::OnMousePressed(SubmenuView* source,
312 const MouseEvent& event) { 311 const MouseEvent& event) {
313 #ifdef DEBUG_MENU 312 #ifdef DEBUG_MENU
314 DLOG(INFO) << "OnMousePressed source=" << source; 313 DLOG(INFO) << "OnMousePressed source=" << source;
315 #endif 314 #endif
316 if (!blocking_run_) 315 if (!blocking_run_)
317 return; 316 return;
318 317
319 MenuPart part = 318 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
320 GetMenuPartByScreenCoordinate(source, event.x(), event.y());
321 if (part.is_scroll()) 319 if (part.is_scroll())
322 return; // Ignore presses on scroll buttons. 320 return; // Ignore presses on scroll buttons.
323 321
324 if (part.type == MenuPart::NONE || 322 if (part.type == MenuPart::NONE ||
325 (part.type == MenuPart::MENU_ITEM && part.menu && 323 (part.type == MenuPart::MENU_ITEM && part.menu &&
326 part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) { 324 part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) {
327 // Mouse wasn't pressed over any menu, or the active menu, cancel. 325 // Mouse wasn't pressed over any menu, or the active menu, cancel.
328 326
329 // We're going to close and we own the mouse capture. We need to repost the 327 // We're going to close and we own the mouse capture. We need to repost the
330 // mouse down, otherwise the window the user clicked on won't get the 328 // mouse down, otherwise the window the user clicked on won't get the
(...skipping 24 matching lines...) Expand all
355 // On a press we immediately commit the selection, that way a submenu 353 // On a press we immediately commit the selection, that way a submenu
356 // pops up immediately rather than after a delay. 354 // pops up immediately rather than after a delay.
357 SetSelection(part.menu, open_submenu, true); 355 SetSelection(part.menu, open_submenu, true);
358 } 356 }
359 357
360 void MenuController::OnMouseDragged(SubmenuView* source, 358 void MenuController::OnMouseDragged(SubmenuView* source,
361 const MouseEvent& event) { 359 const MouseEvent& event) {
362 #ifdef DEBUG_MENU 360 #ifdef DEBUG_MENU
363 DLOG(INFO) << "OnMouseDragged source=" << source; 361 DLOG(INFO) << "OnMouseDragged source=" << source;
364 #endif 362 #endif
365 MenuPart part = 363 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
366 GetMenuPartByScreenCoordinate(source, event.x(), event.y());
367 UpdateScrolling(part); 364 UpdateScrolling(part);
368 365
369 if (!blocking_run_) 366 if (!blocking_run_)
370 return; 367 return;
371 368
372 if (possible_drag_) { 369 if (possible_drag_) {
373 if (View::ExceededDragThreshold(event.x() - press_x_, 370 if (View::ExceededDragThreshold(event.x() - press_x_,
374 event.y() - press_y_)) { 371 event.y() - press_y_)) {
375 MenuItemView* item = state_.item; 372 MenuItemView* item = state_.item;
376 DCHECK(item); 373 DCHECK(item);
(...skipping 25 matching lines...) Expand all
402 Cancel(true); 399 Cancel(true);
403 } // else case, drop was on us. 400 } // else case, drop was on us.
404 } // else case, someone canceled us, don't do anything 401 } // else case, someone canceled us, don't do anything
405 } 402 }
406 return; 403 return;
407 } 404 }
408 if (part.type == MenuPart::MENU_ITEM) { 405 if (part.type == MenuPart::MENU_ITEM) {
409 if (!part.menu) 406 if (!part.menu)
410 part.menu = source->GetMenuItem(); 407 part.menu = source->GetMenuItem();
411 SetSelection(part.menu ? part.menu : state_.item, true, false); 408 SetSelection(part.menu ? part.menu : state_.item, true, false);
409 } else if (part.type == MenuPart::NONE) {
410 ShowSiblingMenu(source, event);
412 } 411 }
413 } 412 }
414 413
415 void MenuController::OnMouseReleased(SubmenuView* source, 414 void MenuController::OnMouseReleased(SubmenuView* source,
416 const MouseEvent& event) { 415 const MouseEvent& event) {
417 #ifdef DEBUG_MENU 416 #ifdef DEBUG_MENU
418 DLOG(INFO) << "OnMouseReleased source=" << source; 417 DLOG(INFO) << "OnMouseReleased source=" << source;
419 #endif 418 #endif
420 if (!blocking_run_) 419 if (!blocking_run_)
421 return; 420 return;
422 421
423 DCHECK(state_.item); 422 DCHECK(state_.item);
424 possible_drag_ = false; 423 possible_drag_ = false;
425 DCHECK(blocking_run_); 424 DCHECK(blocking_run_);
426 MenuPart part = 425 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
427 GetMenuPartByScreenCoordinate(source, event.x(), event.y());
428 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM && 426 if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
429 part.menu)) { 427 part.menu)) {
430 // Set the selection immediately, making sure the submenu is only open 428 // Set the selection immediately, making sure the submenu is only open
431 // if it already was. 429 // if it already was.
432 bool open_submenu = (state_.item == pending_state_.item && 430 bool open_submenu = (state_.item == pending_state_.item &&
433 state_.submenu_open); 431 state_.submenu_open);
434 SetSelection(pending_state_.item, open_submenu, true); 432 SetSelection(pending_state_.item, open_submenu, true);
435 gfx::Point loc(event.location()); 433 gfx::Point loc(event.location());
436 View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc); 434 View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc);
437 435
(...skipping 15 matching lines...) Expand all
453 } 451 }
454 452
455 void MenuController::OnMouseMoved(SubmenuView* source, 453 void MenuController::OnMouseMoved(SubmenuView* source,
456 const MouseEvent& event) { 454 const MouseEvent& event) {
457 #ifdef DEBUG_MENU 455 #ifdef DEBUG_MENU
458 DLOG(INFO) << "OnMouseMoved source=" << source; 456 DLOG(INFO) << "OnMouseMoved source=" << source;
459 #endif 457 #endif
460 if (showing_submenu_) 458 if (showing_submenu_)
461 return; 459 return;
462 460
463 MenuPart part = 461 MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
464 GetMenuPartByScreenCoordinate(source, event.x(), event.y());
465 462
466 UpdateScrolling(part); 463 UpdateScrolling(part);
467 464
468 if (!blocking_run_) 465 if (!blocking_run_)
469 return; 466 return;
470 467
468 if (part.type == MenuPart::NONE && ShowSiblingMenu(source, event))
469 return;
470
471 if (part.type == MenuPart::MENU_ITEM && part.menu) { 471 if (part.type == MenuPart::MENU_ITEM && part.menu) {
472 SetSelection(part.menu, true, false); 472 SetSelection(part.menu, true, false);
473 } else if (!part.is_scroll() && pending_state_.item && 473 } else if (!part.is_scroll() && pending_state_.item &&
474 (!pending_state_.item->HasSubmenu() || 474 (!pending_state_.item->HasSubmenu() ||
475 !pending_state_.item->GetSubmenu()->IsShowing())) { 475 !pending_state_.item->GetSubmenu()->IsShowing())) {
476 // On exit if the user hasn't selected an item with a submenu, move the 476 // On exit if the user hasn't selected an item with a submenu, move the
477 // selection back to the parent menu item. 477 // selection back to the parent menu item.
478 SetSelection(pending_state_.item->GetParentMenuItem(), true, false); 478 SetSelection(pending_state_.item->GetParentMenuItem(), true, false);
479 } 479 }
480 } 480 }
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 : blocking_run_(blocking), 796 : blocking_run_(blocking),
797 showing_(false), 797 showing_(false),
798 exit_all_(false), 798 exit_all_(false),
799 did_capture_(false), 799 did_capture_(false),
800 result_(NULL), 800 result_(NULL),
801 result_mouse_event_flags_(0), 801 result_mouse_event_flags_(0),
802 drop_target_(NULL), 802 drop_target_(NULL),
803 owner_(NULL), 803 owner_(NULL),
804 possible_drag_(false), 804 possible_drag_(false),
805 valid_drop_coordinates_(false), 805 valid_drop_coordinates_(false),
806 showing_submenu_(false) { 806 showing_submenu_(false),
807 menu_button_(NULL) {
807 #ifdef DEBUG_MENU 808 #ifdef DEBUG_MENU
808 instance_count++; 809 instance_count++;
809 DLOG(INFO) << "created MC, count=" << instance_count; 810 DLOG(INFO) << "created MC, count=" << instance_count;
810 #endif 811 #endif
811 } 812 }
812 813
813 MenuController::~MenuController() { 814 MenuController::~MenuController() {
814 DCHECK(!showing_); 815 DCHECK(!showing_);
815 StopShowTimer(); 816 StopShowTimer();
816 StopCancelAllTimer(); 817 StopCancelAllTimer();
817 #ifdef DEBUG_MENU 818 #ifdef DEBUG_MENU
818 instance_count--; 819 instance_count--;
819 DLOG(INFO) << "destroyed MC, count=" << instance_count; 820 DLOG(INFO) << "destroyed MC, count=" << instance_count;
820 #endif 821 #endif
821 } 822 }
822 823
824 void MenuController::UpdateInitialLocation(
825 const gfx::Rect& bounds,
826 MenuItemView::AnchorPosition position) {
827 pending_state_.initial_bounds = bounds;
828 if (bounds.height() > 1) {
829 // Inset the bounds slightly, otherwise drag coordinates don't line up
830 // nicely and menus close prematurely.
831 pending_state_.initial_bounds.Inset(0, 1);
832 }
833 pending_state_.anchor = position;
834
835 // Calculate the bounds of the monitor we'll show menus on. Do this once to
836 // avoid repeated system queries for the info.
837 pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
838 bounds.origin());
839 }
840
823 void MenuController::Accept(MenuItemView* item, int mouse_event_flags) { 841 void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
824 DCHECK(IsBlockingRun()); 842 DCHECK(IsBlockingRun());
825 result_ = item; 843 result_ = item;
826 exit_all_ = true; 844 exit_all_ = true;
827 result_mouse_event_flags_ = mouse_event_flags; 845 result_mouse_event_flags_ = mouse_event_flags;
828 } 846 }
829 847
848 bool MenuController::ShowSiblingMenu(SubmenuView* source, const MouseEvent& e) {
849 if (!menu_stack_.empty() || !menu_button_)
850 return false;
851
852 View* source_view = source->GetScrollViewContainer();
853 if (e.x() >= 0 && e.x() < source_view->width() && e.y() >= 0 &&
854 e.y() < source_view->height()) {
855 // The mouse is over the menu, no need to continue.
856 return false;
857 }
858
859 gfx::NativeWindow window_under_mouse = Screen::GetWindowAtCursorScreenPoint();
860 if (window_under_mouse != owner_)
861 return false;
862
863 // The user moved the mouse outside the menu and over the owning window. See
864 // if there is a sibling menu we should show.
865 gfx::Point screen_point(e.location());
866 View::ConvertPointToScreen(source_view, &screen_point);
867 MenuItemView::AnchorPosition anchor;
868 bool has_mnemonics;
869 MenuButton* button = NULL;
870 MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()->
871 GetSiblingMenu(source->GetMenuItem()->GetRootMenuItem(),
872 screen_point, &anchor, &has_mnemonics, &button);
873 if (!alt_menu || alt_menu == state_.item)
874 return false;
875
876 if (!button) {
877 // If the delegate returns a menu, they must also return a button.
878 NOTREACHED();
879 return false;
880 }
881
882 // There is a sibling menu, update the button state, hide the current menu
883 // and show the new one.
884 menu_button_->SetState(CustomButton::BS_NORMAL);
885 menu_button_->SchedulePaint();
886 menu_button_ = button;
887 menu_button_->SetState(CustomButton::BS_PUSHED);
888 menu_button_->SchedulePaint();
889
890 // Need to reset capture when we show the menu again, otherwise we aren't
891 // going to get any events.
892 did_capture_ = false;
893 gfx::Point screen_menu_loc;
894 View::ConvertPointToScreen(button, &screen_menu_loc);
895 // Subtract 1 from the height to make the popup flush with the button border.
896 UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(),
897 button->width(), button->height() - 1),
898 anchor);
899 alt_menu->PrepareForRun(has_mnemonics);
900 alt_menu->controller_ = this;
901 SetSelection(alt_menu, true, true);
902 return true;
903 }
904
830 void MenuController::CloseAllNestedMenus() { 905 void MenuController::CloseAllNestedMenus() {
831 for (std::list<State>::iterator i = menu_stack_.begin(); 906 for (std::list<State>::iterator i = menu_stack_.begin();
832 i != menu_stack_.end(); ++i) { 907 i != menu_stack_.end(); ++i) {
833 MenuItemView* item = i->item; 908 MenuItemView* item = i->item;
834 MenuItemView* last_item = item; 909 MenuItemView* last_item = item;
835 while (item) { 910 while (item) {
836 CloseMenu(item); 911 CloseMenu(item);
837 last_item = item; 912 last_item = item;
838 item = item->GetParentMenuItem(); 913 item = item->GetParentMenuItem();
839 } 914 }
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
1404 if (!scroll_task_.get()) 1479 if (!scroll_task_.get())
1405 scroll_task_.reset(new MenuScrollTask()); 1480 scroll_task_.reset(new MenuScrollTask());
1406 scroll_task_->Update(part); 1481 scroll_task_->Update(part);
1407 } 1482 }
1408 1483
1409 void MenuController::StopScrolling() { 1484 void MenuController::StopScrolling() {
1410 scroll_task_.reset(NULL); 1485 scroll_task_.reset(NULL);
1411 } 1486 }
1412 1487
1413 } // namespace views 1488 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/menu/menu_controller.h ('k') | views/controls/menu/menu_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698