15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/base/ui_base_types.h" 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/controls/menu/menu_types.h" 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/views_export.h" 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace base { 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass TimeDelta; 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace gfx { 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass Rect; 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace ui { 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MenuModel; 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuButton; 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass MenuItemView; 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MenuModelAdapter; 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MenuRunnerHandler; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Widget; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DisplayChangeListener; 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass MenuRunnerImplInterface; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace test { 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MenuRunnerTestAPI; 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuRunner is responsible for showing (running) the menu and additionally 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// owning the MenuItemView. RunMenuAt() runs a nested message loop. It is safe 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to delete MenuRunner at any point, but MenuRunner internally only deletes the 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuItemView *after* the nested message loop completes. If MenuRunner is 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleted while the menu is showing the delegate of the menu is reset. This is 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// done to ensure delegates aren't notified after they may have been deleted. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: while you can delete a MenuRunner at any point, the nested message loop 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// won't return immediately. This means if you delete the object that owns 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the MenuRunner while the menu is running, your object is effectively still 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the stack. A return value of MENU_DELETED indicated this. In most cases 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if RunMenuAt() returns MENU_DELETED, you should return immediately. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Similarly you should avoid creating MenuRunner on the stack. Doing so means 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuRunner may not be immediately destroyed if your object is destroyed, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resulting in possible callbacks to your now deleted object. Instead you 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should define MenuRunner as a scoped_ptr in your class so that when your 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object is destroyed MenuRunner initiates the proper cleanup and ensures your 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object isn't accessed again. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VIEWS_EXPORT MenuRunner { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum RunTypes { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The menu has mnemonics. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HAS_MNEMONICS = 1 << 0, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The menu is a nested context menu. For example, click a folder on the 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bookmark bar, then right click an entry to get its context menu. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IS_NESTED = 1 << 1, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Used for showing a menu during a drop operation. This does NOT block the 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // caller, instead the delegate is notified when the menu closes via the 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DropMenuClosed method. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_DROP = 1 << 2, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The menu is a context menu (not necessarily nested), for example right 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // click on a link on a website in the browser. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CONTEXT_MENU = 1 << 3, 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The menu should behave like a Windows native Combobox dropdow menu. 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // This behavior includes accepting the pending item and closing on F4. 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) COMBOBOX = 1 << 4, 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // A child view is performing a drag-and-drop operation, so the menu should 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // stay open (even if it doesn't receive drag updated events). In this case, 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // the caller is responsible for closing the menu upon completion of the 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // drag-and-drop. 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) NESTED_DRAG = 1 << 5, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum RunResult { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Indicates RunMenuAt is returning because the MenuRunner was deleted. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MENU_DELETED, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Indicates RunMenuAt returned and MenuRunner was not deleted. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NORMAL_EXIT 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Creates a new MenuRunner. 102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // |run_types| is a bitmask of RunTypes. 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuRunner(ui::MenuModel* menu_model, int32 run_types); 104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch MenuRunner(MenuItemView* menu, int32 run_types); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MenuRunner(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Runs the menu. If this returns MENU_DELETED the method is returning 108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // because the MenuRunner was deleted. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Typically callers should NOT do any processing if this returns 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MENU_DELETED. 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // using |bounds| as the thing to point at in screen coordinates. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunResult RunMenuAt(Widget* parent, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuButton* button, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& bounds, 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu MenuAnchorPosition anchor, 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ui::MenuSourceType source_type) WARN_UNUSED_RESULT; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if we're in a nested message loop running the menu. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsRunning() const; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hides and cancels the menu. This does nothing if the menu is not open. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Cancel(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns the time from the event which closed the menu - or 0. 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta closing_event_time() const; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) friend class test::MenuRunnerTestAPI; 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Sets an implementation of RunMenuAt. This is intended to be used at test. 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void SetRunnerHandler(scoped_ptr<MenuRunnerHandler> runner_handler); 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const int32 run_types_; 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // We own this. No scoped_ptr because it is destroyed by calling Release(). 137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch internal::MenuRunnerImplInterface* impl_; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // An implementation of RunMenuAt. This is usually NULL and ignored. If this 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // is not NULL, this implementation will be used. 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<MenuRunnerHandler> runner_handler_; 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<internal::DisplayChangeListener> display_change_listener_; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MenuRunner); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DisplayChangeListener is intended to listen for changes in the display size 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and cancel the menu. DisplayChangeListener is created when the menu is 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shown. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DisplayChangeListener { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~DisplayChangeListener() {} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates the platform specified DisplayChangeListener, or NULL if there 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // isn't one. Caller owns the returned value. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static DisplayChangeListener* Create(Widget* parent, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuRunner* runner); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisplayChangeListener() {} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} // namespace internal 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_ 171