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