| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_ | |
| 6 #define UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_ | |
| 7 | |
| 8 #include "build/build_config.h" | |
| 9 | |
| 10 #include <list> | |
| 11 #include <set> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/compiler_specific.h" | |
| 15 #include "base/memory/linked_ptr.h" | |
| 16 #include "base/memory/scoped_ptr.h" | |
| 17 #include "base/timer/timer.h" | |
| 18 #include "ui/events/event.h" | |
| 19 #include "ui/events/event_constants.h" | |
| 20 #include "ui/events/platform/platform_event_dispatcher.h" | |
| 21 #include "ui/views/controls/button/menu_button.h" | |
| 22 #include "ui/views/controls/menu/menu_config.h" | |
| 23 #include "ui/views/controls/menu/menu_delegate.h" | |
| 24 #include "ui/views/widget/widget_observer.h" | |
| 25 | |
| 26 namespace base { | |
| 27 class MessagePumpDispatcher; | |
| 28 } | |
| 29 namespace gfx { | |
| 30 class Screen; | |
| 31 } | |
| 32 namespace ui { | |
| 33 class NativeTheme; | |
| 34 class OSExchangeData; | |
| 35 class ScopedEventDispatcher; | |
| 36 } | |
| 37 namespace views { | |
| 38 | |
| 39 class MenuButton; | |
| 40 class MenuHostRootView; | |
| 41 class MenuItemView; | |
| 42 class MenuMessageLoop; | |
| 43 class MouseEvent; | |
| 44 class SubmenuView; | |
| 45 class View; | |
| 46 | |
| 47 namespace internal { | |
| 48 class MenuControllerDelegate; | |
| 49 class MenuEventDispatcher; | |
| 50 class MenuMessagePumpDispatcher; | |
| 51 class MenuRunnerImpl; | |
| 52 } | |
| 53 | |
| 54 // MenuController ------------------------------------------------------------- | |
| 55 | |
| 56 // MenuController is used internally by the various menu classes to manage | |
| 57 // showing, selecting and drag/drop for menus. All relevant events are | |
| 58 // forwarded to the MenuController from SubmenuView and MenuHost. | |
| 59 class VIEWS_EXPORT MenuController : public WidgetObserver { | |
| 60 public: | |
| 61 // Enumeration of how the menu should exit. | |
| 62 enum ExitType { | |
| 63 // Don't exit. | |
| 64 EXIT_NONE, | |
| 65 | |
| 66 // All menus, including nested, should be exited. | |
| 67 EXIT_ALL, | |
| 68 | |
| 69 // Only the outermost menu should be exited. | |
| 70 EXIT_OUTERMOST, | |
| 71 | |
| 72 // This is set if the menu is being closed as the result of one of the menus | |
| 73 // being destroyed. | |
| 74 EXIT_DESTROYED | |
| 75 }; | |
| 76 | |
| 77 // If a menu is currently active, this returns the controller for it. | |
| 78 static MenuController* GetActiveInstance(); | |
| 79 | |
| 80 // Runs the menu at the specified location. If the menu was configured to | |
| 81 // block, the selected item is returned. If the menu does not block this | |
| 82 // returns NULL immediately. | |
| 83 MenuItemView* Run(Widget* parent, | |
| 84 MenuButton* button, | |
| 85 MenuItemView* root, | |
| 86 const gfx::Rect& bounds, | |
| 87 MenuAnchorPosition position, | |
| 88 bool context_menu, | |
| 89 bool is_nested_drag, | |
| 90 int* event_flags); | |
| 91 | |
| 92 // Whether or not Run blocks. | |
| 93 bool IsBlockingRun() const { return blocking_run_; } | |
| 94 | |
| 95 bool in_nested_run() const { return !menu_stack_.empty(); } | |
| 96 | |
| 97 // Whether or not drag operation is in progress. | |
| 98 bool drag_in_progress() const { return drag_in_progress_; } | |
| 99 | |
| 100 // Whether the MenuController initiated the drag in progress. False if there | |
| 101 // is no drag in progress. | |
| 102 bool did_initiate_drag() const { return did_initiate_drag_; } | |
| 103 | |
| 104 // Returns the owner of child windows. | |
| 105 // WARNING: this may be NULL. | |
| 106 Widget* owner() { return owner_; } | |
| 107 | |
| 108 // Get the anchor position wich is used to show this menu. | |
| 109 MenuAnchorPosition GetAnchorPosition() { return state_.anchor; } | |
| 110 | |
| 111 // Cancels the current Run. See ExitType for a description of what happens | |
| 112 // with the various parameters. | |
| 113 void Cancel(ExitType type); | |
| 114 | |
| 115 // An alternative to Cancel(EXIT_ALL) that can be used with a OneShotTimer. | |
| 116 void CancelAll() { Cancel(EXIT_ALL); } | |
| 117 | |
| 118 // Returns the current exit type. This returns a value other than EXIT_NONE if | |
| 119 // the menu is being canceled. | |
| 120 ExitType exit_type() const { return exit_type_; } | |
| 121 | |
| 122 // Returns the time from the event which closed the menu - or 0. | |
| 123 base::TimeDelta closing_event_time() const { return closing_event_time_; } | |
| 124 | |
| 125 void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; } | |
| 126 | |
| 127 // Various events, forwarded from the submenu. | |
| 128 // | |
| 129 // NOTE: the coordinates of the events are in that of the | |
| 130 // MenuScrollViewContainer. | |
| 131 void OnMousePressed(SubmenuView* source, const ui::MouseEvent& event); | |
| 132 void OnMouseDragged(SubmenuView* source, const ui::MouseEvent& event); | |
| 133 void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event); | |
| 134 void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event); | |
| 135 void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event); | |
| 136 bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event); | |
| 137 void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event); | |
| 138 | |
| 139 bool GetDropFormats( | |
| 140 SubmenuView* source, | |
| 141 int* formats, | |
| 142 std::set<ui::OSExchangeData::CustomFormat>* custom_formats); | |
| 143 bool AreDropTypesRequired(SubmenuView* source); | |
| 144 bool CanDrop(SubmenuView* source, const ui::OSExchangeData& data); | |
| 145 void OnDragEntered(SubmenuView* source, const ui::DropTargetEvent& event); | |
| 146 int OnDragUpdated(SubmenuView* source, const ui::DropTargetEvent& event); | |
| 147 void OnDragExited(SubmenuView* source); | |
| 148 int OnPerformDrop(SubmenuView* source, const ui::DropTargetEvent& event); | |
| 149 | |
| 150 // Invoked from the scroll buttons of the MenuScrollViewContainer. | |
| 151 void OnDragEnteredScrollButton(SubmenuView* source, bool is_up); | |
| 152 void OnDragExitedScrollButton(SubmenuView* source); | |
| 153 | |
| 154 // Called by the Widget when a drag is about to start on a child view. This | |
| 155 // could be initiated by one of our MenuItemViews, or could be through another | |
| 156 // child View. | |
| 157 void OnDragWillStart(); | |
| 158 | |
| 159 // Called by the Widget when the drag has completed. |should_close| | |
| 160 // corresponds to whether or not the menu should close. | |
| 161 void OnDragComplete(bool should_close); | |
| 162 | |
| 163 // Update the submenu's selection based on the current mouse location | |
| 164 void UpdateSubmenuSelection(SubmenuView* source); | |
| 165 | |
| 166 // WidgetObserver overrides: | |
| 167 virtual void OnWidgetDestroying(Widget* widget) override; | |
| 168 | |
| 169 // Only used for testing. | |
| 170 bool IsCancelAllTimerRunningForTest(); | |
| 171 | |
| 172 // Only used for testing. | |
| 173 static void TurnOffMenuSelectionHoldForTest(); | |
| 174 | |
| 175 private: | |
| 176 friend class internal::MenuEventDispatcher; | |
| 177 friend class internal::MenuMessagePumpDispatcher; | |
| 178 friend class internal::MenuRunnerImpl; | |
| 179 friend class MenuControllerTest; | |
| 180 friend class MenuHostRootView; | |
| 181 friend class MenuItemView; | |
| 182 friend class SubmenuView; | |
| 183 | |
| 184 class MenuScrollTask; | |
| 185 | |
| 186 struct SelectByCharDetails; | |
| 187 | |
| 188 // Values supplied to SetSelection. | |
| 189 enum SetSelectionTypes { | |
| 190 SELECTION_DEFAULT = 0, | |
| 191 | |
| 192 // If set submenus are opened immediately, otherwise submenus are only | |
| 193 // openned after a timer fires. | |
| 194 SELECTION_UPDATE_IMMEDIATELY = 1 << 0, | |
| 195 | |
| 196 // If set and the menu_item has a submenu, the submenu is shown. | |
| 197 SELECTION_OPEN_SUBMENU = 1 << 1, | |
| 198 | |
| 199 // SetSelection is being invoked as the result exiting or cancelling the | |
| 200 // menu. This is used for debugging. | |
| 201 SELECTION_EXIT = 1 << 2, | |
| 202 }; | |
| 203 | |
| 204 // Result type for SendAcceleratorToHotTrackedView | |
| 205 enum SendAcceleratorResultType { | |
| 206 // Accelerator is not sent because of no hot tracked views. | |
| 207 ACCELERATOR_NOT_PROCESSED, | |
| 208 | |
| 209 // Accelerator is sent to the hot tracked views. | |
| 210 ACCELERATOR_PROCESSED, | |
| 211 | |
| 212 // Same as above and the accelerator causes the exit of the menu. | |
| 213 ACCELERATOR_PROCESSED_EXIT | |
| 214 }; | |
| 215 | |
| 216 // Tracks selection information. | |
| 217 struct State { | |
| 218 State(); | |
| 219 ~State(); | |
| 220 | |
| 221 // The selected menu item. | |
| 222 MenuItemView* item; | |
| 223 | |
| 224 // If item has a submenu this indicates if the submenu is showing. | |
| 225 bool submenu_open; | |
| 226 | |
| 227 // Bounds passed to the run menu. Used for positioning the first menu. | |
| 228 gfx::Rect initial_bounds; | |
| 229 | |
| 230 // Position of the initial menu. | |
| 231 MenuAnchorPosition anchor; | |
| 232 | |
| 233 // The direction child menus have opened in. | |
| 234 std::list<bool> open_leading; | |
| 235 | |
| 236 // Bounds for the monitor we're showing on. | |
| 237 gfx::Rect monitor_bounds; | |
| 238 | |
| 239 // Is the current menu a context menu. | |
| 240 bool context_menu; | |
| 241 }; | |
| 242 | |
| 243 // Used by GetMenuPart to indicate the menu part at a particular location. | |
| 244 struct MenuPart { | |
| 245 // Type of part. | |
| 246 enum Type { | |
| 247 NONE, | |
| 248 MENU_ITEM, | |
| 249 SCROLL_UP, | |
| 250 SCROLL_DOWN | |
| 251 }; | |
| 252 | |
| 253 MenuPart() : type(NONE), menu(NULL), parent(NULL), submenu(NULL) {} | |
| 254 | |
| 255 // Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP. | |
| 256 bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; } | |
| 257 | |
| 258 // Type of part. | |
| 259 Type type; | |
| 260 | |
| 261 // If type is MENU_ITEM, this is the menu item the mouse is over, otherwise | |
| 262 // this is NULL. | |
| 263 // NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item | |
| 264 // but is over a menu (for example, the mouse is over a separator or | |
| 265 // empty menu), this is NULL and parent is the menu the mouse was | |
| 266 // clicked on. | |
| 267 MenuItemView* menu; | |
| 268 | |
| 269 // If type is MENU_ITEM but the mouse is not over a menu item this is the | |
| 270 // parent of the menu item the user clicked on. Otherwise this is NULL. | |
| 271 MenuItemView* parent; | |
| 272 | |
| 273 // This is the submenu the mouse is over. | |
| 274 SubmenuView* submenu; | |
| 275 }; | |
| 276 | |
| 277 // Sets the selection to |menu_item|. A value of NULL unselects | |
| 278 // everything. |types| is a bitmask of |SetSelectionTypes|. | |
| 279 // | |
| 280 // Internally this updates pending_state_ immediatley. state_ is only updated | |
| 281 // immediately if SELECTION_UPDATE_IMMEDIATELY is set. If | |
| 282 // SELECTION_UPDATE_IMMEDIATELY is not set CommitPendingSelection is invoked | |
| 283 // to show/hide submenus and update state_. | |
| 284 void SetSelection(MenuItemView* menu_item, int types); | |
| 285 | |
| 286 void SetSelectionOnPointerDown(SubmenuView* source, | |
| 287 const ui::LocatedEvent& event); | |
| 288 void StartDrag(SubmenuView* source, const gfx::Point& location); | |
| 289 | |
| 290 // Key processing. The return value of this is returned from Dispatch. | |
| 291 // In other words, if this returns false (which happens if escape was | |
| 292 // pressed, or a matching mnemonic was found) the message loop returns. | |
| 293 bool OnKeyDown(ui::KeyboardCode key_code); | |
| 294 | |
| 295 // Creates a MenuController. If |blocking| is true a nested message loop is | |
| 296 // started in |Run|. | |
| 297 MenuController(ui::NativeTheme* theme, | |
| 298 bool blocking, | |
| 299 internal::MenuControllerDelegate* delegate); | |
| 300 | |
| 301 virtual ~MenuController(); | |
| 302 | |
| 303 // Runs the platform specific bits of the message loop. If |nested_menu| is | |
| 304 // true we're being asked to run a menu from within a menu (eg a context | |
| 305 // menu). | |
| 306 void RunMessageLoop(bool nested_menu); | |
| 307 | |
| 308 // AcceleratorPressed is invoked on the hot tracked view if it exists. | |
| 309 SendAcceleratorResultType SendAcceleratorToHotTrackedView(); | |
| 310 | |
| 311 void UpdateInitialLocation(const gfx::Rect& bounds, | |
| 312 MenuAnchorPosition position, | |
| 313 bool context_menu); | |
| 314 | |
| 315 // Invoked when the user accepts the selected item. This is only used | |
| 316 // when blocking. This schedules the loop to quit. | |
| 317 void Accept(MenuItemView* item, int event_flags); | |
| 318 | |
| 319 bool ShowSiblingMenu(SubmenuView* source, const gfx::Point& mouse_location); | |
| 320 | |
| 321 // Shows a context menu for |menu_item| as a result of a located event if | |
| 322 // appropriate. This is invoked on long press and releasing the right mouse | |
| 323 // button. Returns whether a context menu was shown. | |
| 324 bool ShowContextMenu(MenuItemView* menu_item, | |
| 325 SubmenuView* source, | |
| 326 const ui::LocatedEvent& event, | |
| 327 ui::MenuSourceType source_type); | |
| 328 | |
| 329 // Closes all menus, including any menus of nested invocations of Run. | |
| 330 void CloseAllNestedMenus(); | |
| 331 | |
| 332 // Gets the enabled menu item at the specified location. | |
| 333 // If over_any_menu is non-null it is set to indicate whether the location | |
| 334 // is over any menu. It is possible for this to return NULL, but | |
| 335 // over_any_menu to be true. For example, the user clicked on a separator. | |
| 336 MenuItemView* GetMenuItemAt(View* menu, int x, int y); | |
| 337 | |
| 338 // If there is an empty menu item at the specified location, it is returned. | |
| 339 MenuItemView* GetEmptyMenuItemAt(View* source, int x, int y); | |
| 340 | |
| 341 // Returns true if the coordinate is over the scroll buttons of the | |
| 342 // SubmenuView's MenuScrollViewContainer. If true is returned, part is set to | |
| 343 // indicate which scroll button the coordinate is. | |
| 344 bool IsScrollButtonAt(SubmenuView* source, | |
| 345 int x, | |
| 346 int y, | |
| 347 MenuPart::Type* part); | |
| 348 | |
| 349 // Returns the target for the mouse event. The coordinates are in terms of | |
| 350 // source's scroll view container. | |
| 351 MenuPart GetMenuPart(SubmenuView* source, const gfx::Point& source_loc); | |
| 352 | |
| 353 // Returns the target for mouse events. The search is done through |item| and | |
| 354 // all its parents. | |
| 355 MenuPart GetMenuPartByScreenCoordinateUsingMenu(MenuItemView* item, | |
| 356 const gfx::Point& screen_loc); | |
| 357 | |
| 358 // Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns | |
| 359 // true if the supplied SubmenuView contains the location in terms of the | |
| 360 // screen. If it does, part is set appropriately and true is returned. | |
| 361 bool GetMenuPartByScreenCoordinateImpl(SubmenuView* menu, | |
| 362 const gfx::Point& screen_loc, | |
| 363 MenuPart* part); | |
| 364 | |
| 365 // Returns true if the SubmenuView contains the specified location. This does | |
| 366 // NOT included the scroll buttons, only the submenu view. | |
| 367 bool DoesSubmenuContainLocation(SubmenuView* submenu, | |
| 368 const gfx::Point& screen_loc); | |
| 369 | |
| 370 // Opens/Closes the necessary menus such that state_ matches that of | |
| 371 // pending_state_. This is invoked if submenus are not opened immediately, | |
| 372 // but after a delay. | |
| 373 void CommitPendingSelection(); | |
| 374 | |
| 375 // If item has a submenu, it is closed. This does NOT update the selection | |
| 376 // in anyway. | |
| 377 void CloseMenu(MenuItemView* item); | |
| 378 | |
| 379 // If item has a submenu, it is opened. This does NOT update the selection | |
| 380 // in anyway. | |
| 381 void OpenMenu(MenuItemView* item); | |
| 382 | |
| 383 // Implementation of OpenMenu. If |show| is true, this invokes show on the | |
| 384 // menu, otherwise Reposition is invoked. | |
| 385 void OpenMenuImpl(MenuItemView* item, bool show); | |
| 386 | |
| 387 // Invoked when the children of a menu change and the menu is showing. | |
| 388 // This closes any submenus and resizes the submenu. | |
| 389 void MenuChildrenChanged(MenuItemView* item); | |
| 390 | |
| 391 // Builds the paths of the two menu items into the two paths, and | |
| 392 // sets first_diff_at to the location of the first difference between the | |
| 393 // two paths. | |
| 394 void BuildPathsAndCalculateDiff(MenuItemView* old_item, | |
| 395 MenuItemView* new_item, | |
| 396 std::vector<MenuItemView*>* old_path, | |
| 397 std::vector<MenuItemView*>* new_path, | |
| 398 size_t* first_diff_at); | |
| 399 | |
| 400 // Builds the path for the specified item. | |
| 401 void BuildMenuItemPath(MenuItemView* item, std::vector<MenuItemView*>* path); | |
| 402 | |
| 403 // Starts/stops the timer that commits the pending state to state | |
| 404 // (opens/closes submenus). | |
| 405 void StartShowTimer(); | |
| 406 void StopShowTimer(); | |
| 407 | |
| 408 // Starts/stops the timer cancel the menu. This is used during drag and | |
| 409 // drop when the drop enters/exits the menu. | |
| 410 void StartCancelAllTimer(); | |
| 411 void StopCancelAllTimer(); | |
| 412 | |
| 413 // Calculates the bounds of the menu to show. is_leading is set to match the | |
| 414 // direction the menu opened in. | |
| 415 gfx::Rect CalculateMenuBounds(MenuItemView* item, | |
| 416 bool prefer_leading, | |
| 417 bool* is_leading); | |
| 418 | |
| 419 // Calculates the bubble bounds of the menu to show. is_leading is set to | |
| 420 // match the direction the menu opened in. | |
| 421 gfx::Rect CalculateBubbleMenuBounds(MenuItemView* item, | |
| 422 bool prefer_leading, | |
| 423 bool* is_leading); | |
| 424 | |
| 425 // Returns the depth of the menu. | |
| 426 static int MenuDepth(MenuItemView* item); | |
| 427 | |
| 428 // Selects the next/previous menu item. | |
| 429 void IncrementSelection(int delta); | |
| 430 | |
| 431 // Returns the next selectable child menu item of |parent| starting at |index| | |
| 432 // and incrementing index by |delta|. If there are no more selected menu items | |
| 433 // NULL is returned. | |
| 434 MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent, | |
| 435 int index, | |
| 436 int delta); | |
| 437 | |
| 438 // If the selected item has a submenu and it isn't currently open, the | |
| 439 // the selection is changed such that the menu opens immediately. | |
| 440 void OpenSubmenuChangeSelectionIfCan(); | |
| 441 | |
| 442 // If possible, closes the submenu. | |
| 443 void CloseSubmenu(); | |
| 444 | |
| 445 // Returns details about which menu items match the mnemonic |key|. | |
| 446 // |match_function| is used to determine which menus match. | |
| 447 SelectByCharDetails FindChildForMnemonic( | |
| 448 MenuItemView* parent, | |
| 449 base::char16 key, | |
| 450 bool (*match_function)(MenuItemView* menu, base::char16 mnemonic)); | |
| 451 | |
| 452 // Selects or accepts the appropriate menu item based on |details|. Returns | |
| 453 // true if |Accept| was invoked (which happens if there aren't multiple item | |
| 454 // with the same mnemonic and the item to select does not have a submenu). | |
| 455 bool AcceptOrSelect(MenuItemView* parent, const SelectByCharDetails& details); | |
| 456 | |
| 457 // Selects by mnemonic, and if that doesn't work tries the first character of | |
| 458 // the title. Returns true if a match was selected and the menu should exit. | |
| 459 bool SelectByChar(base::char16 key); | |
| 460 | |
| 461 // For Windows and Aura we repost an event for some events that dismiss | |
| 462 // the context menu. The event is then reprocessed to cause its result | |
| 463 // if the context menu had not been present. | |
| 464 // On non-aura Windows, a new mouse event is generated and posted to | |
| 465 // the window (if there is one) at the location of the event. On | |
| 466 // aura, the event is reposted on the RootWindow. | |
| 467 void RepostEvent(SubmenuView* source, const ui::LocatedEvent& event); | |
| 468 | |
| 469 // Sets the drop target to new_item. | |
| 470 void SetDropMenuItem(MenuItemView* new_item, | |
| 471 MenuDelegate::DropPosition position); | |
| 472 | |
| 473 // Starts/stops scrolling as appropriate. part gives the part the mouse is | |
| 474 // over. | |
| 475 void UpdateScrolling(const MenuPart& part); | |
| 476 | |
| 477 // Stops scrolling. | |
| 478 void StopScrolling(); | |
| 479 | |
| 480 // Updates active mouse view from the location of the event and sends it | |
| 481 // the appropriate events. This is used to send mouse events to child views so | |
| 482 // that they react to click-drag-release as if the user clicked on the view | |
| 483 // itself. | |
| 484 void UpdateActiveMouseView(SubmenuView* event_source, | |
| 485 const ui::MouseEvent& event, | |
| 486 View* target_menu); | |
| 487 | |
| 488 // Sends a mouse release event to the current active mouse view and sets | |
| 489 // it to null. | |
| 490 void SendMouseReleaseToActiveView(SubmenuView* event_source, | |
| 491 const ui::MouseEvent& event); | |
| 492 | |
| 493 // Sends a mouse capture lost event to the current active mouse view and sets | |
| 494 // it to null. | |
| 495 void SendMouseCaptureLostToActiveView(); | |
| 496 | |
| 497 // Sets/gets the active mouse view. See UpdateActiveMouseView() for details. | |
| 498 void SetActiveMouseView(View* view); | |
| 499 View* GetActiveMouseView(); | |
| 500 | |
| 501 // Sets exit type. Calling this can terminate the active nested message-loop. | |
| 502 void SetExitType(ExitType type); | |
| 503 | |
| 504 // Terminates the current nested message-loop. | |
| 505 void TerminateNestedMessageLoop(); | |
| 506 | |
| 507 // Returns true if SetExitType() should quit the message loop. | |
| 508 bool ShouldQuitNow() const; | |
| 509 | |
| 510 // Handles the mouse location event on the submenu |source|. | |
| 511 void HandleMouseLocation(SubmenuView* source, | |
| 512 const gfx::Point& mouse_location); | |
| 513 | |
| 514 // Retrieve an appropriate Screen. | |
| 515 gfx::Screen* GetScreen(); | |
| 516 | |
| 517 // The active instance. | |
| 518 static MenuController* active_instance_; | |
| 519 | |
| 520 // If true, Run blocks. If false, Run doesn't block and this is used for | |
| 521 // drag and drop. Note that the semantics for drag and drop are slightly | |
| 522 // different: cancel timer is kicked off any time the drag moves outside the | |
| 523 // menu, mouse events do nothing... | |
| 524 bool blocking_run_; | |
| 525 | |
| 526 // If true, we're showing. | |
| 527 bool showing_; | |
| 528 | |
| 529 // Indicates what to exit. | |
| 530 ExitType exit_type_; | |
| 531 | |
| 532 // Whether we did a capture. We do a capture only if we're blocking and | |
| 533 // the mouse was down when Run. | |
| 534 bool did_capture_; | |
| 535 | |
| 536 // As the user drags the mouse around pending_state_ changes immediately. | |
| 537 // When the user stops moving/dragging the mouse (or clicks the mouse) | |
| 538 // pending_state_ is committed to state_, potentially resulting in | |
| 539 // opening or closing submenus. This gives a slight delayed effect to | |
| 540 // submenus as the user moves the mouse around. This is done so that as the | |
| 541 // user moves the mouse all submenus don't immediately pop. | |
| 542 State pending_state_; | |
| 543 State state_; | |
| 544 | |
| 545 // If the user accepted the selection, this is the result. | |
| 546 MenuItemView* result_; | |
| 547 | |
| 548 // The event flags when the user selected the menu. | |
| 549 int accept_event_flags_; | |
| 550 | |
| 551 // If not empty, it means we're nested. When Run is invoked from within | |
| 552 // Run, the current state (state_) is pushed onto menu_stack_. This allows | |
| 553 // MenuController to restore the state when the nested run returns. | |
| 554 typedef std::pair<State, linked_ptr<MenuButton::PressedLock> > NestedState; | |
| 555 std::list<NestedState> menu_stack_; | |
| 556 | |
| 557 // As the mouse moves around submenus are not opened immediately. Instead | |
| 558 // they open after this timer fires. | |
| 559 base::OneShotTimer<MenuController> show_timer_; | |
| 560 | |
| 561 // Used to invoke CancelAll(). This is used during drag and drop to hide the | |
| 562 // menu after the mouse moves out of the of the menu. This is necessitated by | |
| 563 // the lack of an ability to detect when the drag has completed from the drop | |
| 564 // side. | |
| 565 base::OneShotTimer<MenuController> cancel_all_timer_; | |
| 566 | |
| 567 // Drop target. | |
| 568 MenuItemView* drop_target_; | |
| 569 MenuDelegate::DropPosition drop_position_; | |
| 570 | |
| 571 // Owner of child windows. | |
| 572 // WARNING: this may be NULL. | |
| 573 Widget* owner_; | |
| 574 | |
| 575 // Indicates a possible drag operation. | |
| 576 bool possible_drag_; | |
| 577 | |
| 578 // True when drag operation is in progress. | |
| 579 bool drag_in_progress_; | |
| 580 | |
| 581 // True when the drag operation in progress was initiated by the | |
| 582 // MenuController for a child MenuItemView (as opposed to initiated separately | |
| 583 // by a child View). | |
| 584 bool did_initiate_drag_; | |
| 585 | |
| 586 // Location the mouse was pressed at. Used to detect d&d. | |
| 587 gfx::Point press_pt_; | |
| 588 | |
| 589 // We get a slew of drag updated messages as the mouse is over us. To avoid | |
| 590 // continually processing whether we can drop, we cache the coordinates. | |
| 591 bool valid_drop_coordinates_; | |
| 592 gfx::Point drop_pt_; | |
| 593 int last_drop_operation_; | |
| 594 | |
| 595 // If true, we're in the middle of invoking ShowAt on a submenu. | |
| 596 bool showing_submenu_; | |
| 597 | |
| 598 // Task for scrolling the menu. If non-null indicates a scroll is currently | |
| 599 // underway. | |
| 600 scoped_ptr<MenuScrollTask> scroll_task_; | |
| 601 | |
| 602 // The lock to keep the menu button pressed while a menu is visible. | |
| 603 scoped_ptr<MenuButton::PressedLock> pressed_lock_; | |
| 604 | |
| 605 // ViewStorage id used to store the view mouse drag events are forwarded to. | |
| 606 // See UpdateActiveMouseView() for details. | |
| 607 const int active_mouse_view_id_; | |
| 608 | |
| 609 internal::MenuControllerDelegate* delegate_; | |
| 610 | |
| 611 // How deep we are in nested message loops. This should be at most 2 (when | |
| 612 // showing a context menu from a menu). | |
| 613 int message_loop_depth_; | |
| 614 | |
| 615 views::MenuConfig menu_config_; | |
| 616 | |
| 617 // The timestamp of the event which closed the menu - or 0 otherwise. | |
| 618 base::TimeDelta closing_event_time_; | |
| 619 | |
| 620 // Time when the menu is first shown. | |
| 621 base::TimeTicks menu_start_time_; | |
| 622 | |
| 623 // If a mouse press triggered this menu, this will have its location (in | |
| 624 // screen coordinates). Otherwise this will be (0, 0). | |
| 625 gfx::Point menu_start_mouse_press_loc_; | |
| 626 | |
| 627 // Controls behavior differences between a combobox and other types of menu | |
| 628 // (like a context menu). | |
| 629 bool is_combobox_; | |
| 630 | |
| 631 // Set to true if the menu item was selected by touch. | |
| 632 bool item_selected_by_touch_; | |
| 633 | |
| 634 scoped_ptr<MenuMessageLoop> message_loop_; | |
| 635 | |
| 636 DISALLOW_COPY_AND_ASSIGN(MenuController); | |
| 637 }; | |
| 638 | |
| 639 } // namespace views | |
| 640 | |
| 641 #endif // UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_ | |
| OLD | NEW |