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" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_item_view.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace ui { 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MenuModel; 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuButton; 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MenuModelAdapter; 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MenuRunnerHandler; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Widget; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DisplayChangeListener; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MenuRunnerImpl; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace test { 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MenuRunnerTestAPI; 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuRunner is responsible for showing (running) the menu and additionally 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// owning the MenuItemView. RunMenuAt() runs a nested message loop. It is safe 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to delete MenuRunner at any point, but MenuRunner internally only deletes the 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuItemView *after* the nested message loop completes. If MenuRunner is 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleted while the menu is showing the delegate of the menu is reset. This is 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// done to ensure delegates aren't notified after they may have been deleted. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: while you can delete a MenuRunner at any point, the nested message loop 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// won't return immediately. This means if you delete the object that owns 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the MenuRunner while the menu is running, your object is effectively still 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the stack. A return value of MENU_DELETED indicated this. In most cases 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if RunMenuAt() returns MENU_DELETED, you should return immediately. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Similarly you should avoid creating MenuRunner on the stack. Doing so means 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuRunner may not be immediately destroyed if your object is destroyed, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resulting in possible callbacks to your now deleted object. Instead you 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should define MenuRunner as a scoped_ptr in your class so that when your 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object is destroyed MenuRunner initiates the proper cleanup and ensures your 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object isn't accessed again. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VIEWS_EXPORT MenuRunner { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum RunTypes { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The menu has mnemonics. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HAS_MNEMONICS = 1 << 0, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The menu is a nested context menu. For example, click a folder on the 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bookmark bar, then right click an entry to get its context menu. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IS_NESTED = 1 << 1, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Used for showing a menu during a drop operation. This does NOT block the 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // caller, instead the delegate is notified when the menu closes via the 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DropMenuClosed method. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FOR_DROP = 1 << 2, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The menu is a context menu (not necessarily nested), for example right 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // click on a link on a website in the browser. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CONTEXT_MENU = 1 << 3, 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // The menu should behave like a Windows native Combobox dropdow menu. 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // This behavior includes accepting the pending item and closing on F4. 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) COMBOBOX = 1 << 4, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum RunResult { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Indicates RunMenuAt is returning because the MenuRunner was deleted. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MENU_DELETED, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Indicates RunMenuAt returned and MenuRunner was not deleted. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NORMAL_EXIT 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Creates a new MenuRunner. 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) explicit MenuRunner(ui::MenuModel* menu_model); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit MenuRunner(MenuItemView* menu); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MenuRunner(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the menu. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuItemView* GetMenu(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Takes ownership of |menu|, deleting it when MenuRunner is deleted. You 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only need call this if you create additional menus from 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MenuDelegate::GetSiblingMenu. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OwnMenu(MenuItemView* menu); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs the menu. |types| is a bitmask of RunTypes. If this returns 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MENU_DELETED the method is returning because the MenuRunner was deleted. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Typically callers should NOT do any processing if this returns 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MENU_DELETED. 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // using |bounds| as the thing to point at in screen coordinates. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunResult RunMenuAt(Widget* parent, 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuButton* button, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& bounds, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuItemView::AnchorPosition anchor, 1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ui::MenuSourceType source_type, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 types) WARN_UNUSED_RESULT; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if we're in a nested message loop running the menu. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsRunning() const; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hides and cancels the menu. This does nothing if the menu is not open. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Cancel(); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Returns the time from the event which closed the menu - or 0. 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta closing_event_time() const; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) friend class test::MenuRunnerTestAPI; 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Sets an implementation of RunMenuAt. This is intended to be used at test. 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void SetRunnerHandler(scoped_ptr<MenuRunnerHandler> runner_handler); 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<MenuModelAdapter> menu_model_adapter_; 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal::MenuRunnerImpl* holder_; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // An implementation of RunMenuAt. This is usually NULL and ignored. If this 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // is not NULL, this implementation will be used. 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<MenuRunnerHandler> runner_handler_; 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<internal::DisplayChangeListener> display_change_listener_; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MenuRunner); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DisplayChangeListener is intended to listen for changes in the display size 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and cancel the menu. DisplayChangeListener is created when the menu is 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shown. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DisplayChangeListener { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~DisplayChangeListener() {} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Creates the platform specified DisplayChangeListener, or NULL if there 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // isn't one. Caller owns the returned value. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static DisplayChangeListener* Create(Widget* parent, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuRunner* runner); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisplayChangeListener() {} 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_ 161