blob: 967f6f2202110c0db0a43832ca3d84de17d60e4d [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
#define UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_
#include <stdint.h>
#include <memory>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/menu/menu_types.h"
#include "ui/views/views_export.h"
namespace base {
class TimeTicks;
}
namespace gfx {
class Rect;
}
namespace ui {
class MenuModel;
}
namespace views {
class MenuButton;
class MenuItemView;
class MenuRunnerHandler;
class Widget;
namespace internal {
class DisplayChangeListener;
class MenuRunnerImplInterface;
}
namespace test {
class MenuRunnerTestAPI;
}
// MenuRunner is responsible for showing (running) the menu and additionally
// owning the MenuItemView. It is safe to delete MenuRunner at any point, but
// MenuRunner will not notify you of the closure caused by a deletion.
// If MenuRunner is deleted while the menu is showing the delegate of the menu
// is reset. This is done to ensure delegates aren't notified after they may
// have been deleted.
//
// Similarly you should avoid creating MenuRunner on the stack. Doing so means
// MenuRunner may not be immediately destroyed if your object is destroyed,
// resulting in possible callbacks to your now deleted object. Instead you
// should define MenuRunner as a scoped_ptr in your class so that when your
// object is destroyed MenuRunner initiates the proper cleanup and ensures your
// object isn't accessed again.
class VIEWS_EXPORT MenuRunner {
public:
enum RunTypes {
// The menu has mnemonics.
HAS_MNEMONICS = 1 << 0,
// The menu is a nested context menu. For example, click a folder on the
// bookmark bar, then right click an entry to get its context menu.
IS_NESTED = 1 << 1,
// Used for showing a menu during a drop operation. This does NOT block the
// caller, instead the delegate is notified when the menu closes via the
// DropMenuClosed method.
FOR_DROP = 1 << 2,
// The menu is a context menu (not necessarily nested), for example right
// click on a link on a website in the browser.
CONTEXT_MENU = 1 << 3,
// The menu should behave like a Windows native Combobox dropdow menu.
// This behavior includes accepting the pending item and closing on F4.
COMBOBOX = 1 << 4,
// A child view is performing a drag-and-drop operation, so the menu should
// stay open (even if it doesn't receive drag updated events). In this case,
// the caller is responsible for closing the menu upon completion of the
// drag-and-drop.
NESTED_DRAG = 1 << 5,
// Menu with fixed anchor position, so |MenuRunner| will not attempt to
// adjust the anchor point. For example the context menu of shelf item.
FIXED_ANCHOR = 1 << 6,
// The menu's owner could be in the middle of a gesture when the menu opens
// and can use this flag to continue the gesture. For example, Chrome OS's
// shelf uses the flag to continue dragging an item without lifting the
// finger after the context menu of the item is opened.
SEND_GESTURE_EVENTS_TO_OWNER = 1 << 7,
// Whether to use the touchable layout for this context menu.
USE_TOUCHABLE_LAYOUT = 1 << 8,
// Similar to COMBOBOX, but does not capture the mouse and lets some keys
// propagate back to the parent so the combobox content can be edited even
// while the menu is open.
EDITABLE_COMBOBOX = 1 << 9,
};
// Creates a new MenuRunner, which may use a native menu if available.
// |run_types| is a bitmask of RunTypes. If provided,
// |on_menu_closed_callback| is invoked when the menu is closed.
// Note that with a native menu (e.g. on Mac), the ASYNC flag in |run_types|
// may be ignored. See http://crbug.com/682544.
// The MenuModelDelegate of |menu_model| will be overwritten by this call.
MenuRunner(ui::MenuModel* menu_model,
int32_t run_types,
const base::Closure& on_menu_closed_callback = base::Closure());
// Creates a runner for a custom-created toolkit-views menu.
MenuRunner(MenuItemView* menu, int32_t run_types);
~MenuRunner();
// Runs the menu. MenuDelegate::OnMenuClosed will be notified of the results.
// If |anchor| uses a |BUBBLE_..| type, the bounds will get determined by
// using |bounds| as the thing to point at in screen coordinates.
void RunMenuAt(Widget* parent,
MenuButton* button,
const gfx::Rect& bounds,
MenuAnchorPosition anchor,
ui::MenuSourceType source_type);
// Returns true if we're in a nested run loop running the menu.
bool IsRunning() const;
// Hides and cancels the menu. This does nothing if the menu is not open.
void Cancel();
// Returns the time from the event which closed the menu - or 0.
base::TimeTicks closing_event_time() const;
private:
friend class test::MenuRunnerTestAPI;
// Sets an implementation of RunMenuAt. This is intended to be used at test.
void SetRunnerHandler(std::unique_ptr<MenuRunnerHandler> runner_handler);
const int32_t run_types_;
// We own this. No scoped_ptr because it is destroyed by calling Release().
internal::MenuRunnerImplInterface* impl_;
// An implementation of RunMenuAt. This is usually NULL and ignored. If this
// is not NULL, this implementation will be used.
std::unique_ptr<MenuRunnerHandler> runner_handler_;
std::unique_ptr<internal::DisplayChangeListener> display_change_listener_;
DISALLOW_COPY_AND_ASSIGN(MenuRunner);
};
namespace internal {
// DisplayChangeListener is intended to listen for changes in the display size
// and cancel the menu. DisplayChangeListener is created when the menu is
// shown.
class DisplayChangeListener {
public:
virtual ~DisplayChangeListener() {}
// Creates the platform specified DisplayChangeListener, or NULL if there
// isn't one. Caller owns the returned value.
static DisplayChangeListener* Create(Widget* parent,
MenuRunner* runner);
protected:
DisplayChangeListener() {}
};
} // namespace internal
} // namespace views
#endif // UI_VIEWS_CONTROLS_MENU_MENU_RUNNER_H_