blob: 98ce67bc673082145dee732bbf750362aa325933 [file] [log] [blame]
// Copyright (c) 2006-2008 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 CHROME_VIEWS_CHROME_MENU_H__
#define CHROME_VIEWS_CHROME_MENU_H__
#include <list>
#include "base/gfx/point.h"
#include "base/gfx/rect.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "chrome/common/drag_drop_types.h"
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/views/controller.h"
#include "chrome/views/view.h"
#include "skia/include/SkBitmap.h"
namespace views {
class WidgetWin;
class MenuController;
class MenuItemView;
class SubmenuView;
namespace {
class MenuHost;
class MenuHostRootView;
class MenuScrollTask;
class MenuScrollViewContainer;
}
// MenuDelegate --------------------------------------------------------------
// Delegate for the menu.
class MenuDelegate : Controller {
public:
// Used during drag and drop to indicate where the drop indicator should
// be rendered.
enum DropPosition {
// Indicates a drop is not allowed here.
DROP_NONE,
// Indicates the drop should occur before the item.
DROP_BEFORE,
// Indicates the drop should occur after the item.
DROP_AFTER,
// Indicates the drop should occur on the item.
DROP_ON
};
// Whether or not an item should be shown as checked.
// TODO(sky): need checked support.
virtual bool IsItemChecked(int id) const {
return false;
}
// The string shown for the menu item. This is only invoked when an item is
// added with an empty label.
virtual std::wstring GetLabel(int id) const {
return std::wstring();
}
// Shows the context menu with the specified id. This is invoked when the
// user does the appropriate gesture to show a context menu. The id
// identifies the id of the menu to show the context menu for.
// is_mouse_gesture is true if this is the result of a mouse gesture.
// If this is not the result of a mouse gesture x/y is the recommended
// location to display the content menu at. In either case, x/y is in
// screen coordinates.
// Returns true if a context menu was displayed, otherwise false
virtual bool ShowContextMenu(MenuItemView* source,
int id,
int x,
int y,
bool is_mouse_gesture) {
return false;
}
// Controller
virtual bool SupportsCommand(int id) const {
return true;
}
virtual bool IsCommandEnabled(int id) const {
return true;
}
virtual bool GetContextualLabel(int id, std::wstring* out) const {
return false;
}
virtual void ExecuteCommand(int id) {
}
// Executes the specified command. mouse_event_flags give the flags of the
// mouse event that triggered this to be invoked (views::MouseEvent
// flags). mouse_event_flags is 0 if this is triggered by a user gesture
// other than a mouse event.
virtual void ExecuteCommand(int id, int mouse_event_flags) {
ExecuteCommand(id);
}
// Returns true if the specified mouse event is one the user can use
// to trigger, or accept, the mouse. Defaults to left or right mouse buttons.
virtual bool IsTriggerableEvent(const MouseEvent& e) {
return e.IsLeftMouseButton() || e.IsRightMouseButton();
}
// Invoked to determine if drops can be accepted for a submenu. This is
// ONLY invoked for menus that have submenus and indicates whether or not
// a drop can occur on any of the child items of the item. For example,
// consider the following menu structure:
//
// A
// B
// C
//
// Where A has a submenu with children B and C. This is ONLY invoked for
// A, not B and C.
//
// To restrict which children can be dropped on override GetDropOperation.
virtual bool CanDrop(MenuItemView* menu, const OSExchangeData& data) {
return false;
}
// Returns the drop operation for the specified target menu item. This is
// only invoked if CanDrop returned true for the parent menu. position
// is set based on the location of the mouse, reset to specify a different
// position.
//
// If a drop should not be allowed, returned DragDropTypes::DRAG_NONE.
virtual int GetDropOperation(MenuItemView* item,
const DropTargetEvent& event,
DropPosition* position) {
NOTREACHED() << "If you override CanDrop, you need to override this too";
return DragDropTypes::DRAG_NONE;
}
// Invoked to perform the drop operation. This is ONLY invoked if
// canDrop returned true for the parent menu item, and GetDropOperation
// returned an operation other than DragDropTypes::DRAG_NONE.
//
// menu indicates the menu the drop occurred on.
virtual int OnPerformDrop(MenuItemView* menu,
DropPosition position,
const DropTargetEvent& event) {
NOTREACHED() << "If you override CanDrop, you need to override this too";
return DragDropTypes::DRAG_NONE;
}
// Invoked to determine if it is possible for the user to drag the specified
// menu item.
virtual bool CanDrag(MenuItemView* menu) {
return false;
}
// Invoked to write the data for a drag operation to data. sender is the
// MenuItemView being dragged.
virtual void WriteDragData(MenuItemView* sender, OSExchangeData* data) {
NOTREACHED() << "If you override CanDrag, you must override this too.";
}
// Invoked to determine the drag operations for a drag session of sender.
// See DragDropTypes for possible values.
virtual int GetDragOperations(MenuItemView* sender) {
NOTREACHED() << "If you override CanDrag, you must override this too.";
return 0;
}
// Notification the menu has closed. This is only sent when running the
// menu for a drop.
virtual void DropMenuClosed(MenuItemView* menu) {
}
// Notification that the user has highlighted the specified item.
virtual void SelectionChanged(MenuItemView* menu) {
}
};
// MenuItemView --------------------------------------------------------------
// MenuItemView represents a single menu item with a label and optional icon.
// Each MenuItemView may also contain a submenu, which in turn may contain
// any number of child MenuItemViews.
//
// To use a menu create an initial MenuItemView using the constructor that
// takes a MenuDelegate, then create any number of child menu items by way
// of the various AddXXX methods.
//
// MenuItemView is itself a View, which means you can add Views to each
// MenuItemView. This normally NOT want you want, rather add other child Views
// to the submenu of the MenuItemView.
//
// There are two ways to show a MenuItemView:
// 1. Use RunMenuAt. This blocks the caller, executing the selected command
// on success.
// 2. Use RunMenuForDropAt. This is intended for use during a drop session
// and does NOT block the caller. Instead the delegate is notified when the
// menu closes via the DropMenuClosed method.
class MenuItemView : public View {
friend class MenuController;
public:
// ID used to identify menu items.
static const int kMenuItemViewID;
// If true SetNestableTasksAllowed(true) is invoked before MessageLoop::Run
// is invoked. This is only useful for testing and defaults to false.
static bool allow_task_nesting_during_run_;
// Different types of menu items.
enum Type {
NORMAL,
SUBMENU,
CHECKBOX,
RADIO,
SEPARATOR
};
// Where the menu should be anchored to.
enum AnchorPosition {
TOPLEFT,
TOPRIGHT
};
// Constructor for use with the top level menu item. This menu is never
// shown to the user, rather its use as the parent for all menu items.
explicit MenuItemView(MenuDelegate* delegate);
virtual ~MenuItemView();
// Run methods. See description above class for details. Both Run methods take
// a rectangle, which is used to position the menu. |has_mnemonics| indicates
// whether the items have mnemonics. Mnemonics are identified by way of the
// character following the '&'.
void RunMenuAt(HWND parent,
const gfx::Rect& bounds,
AnchorPosition anchor,
bool has_mnemonics);
void RunMenuForDropAt(HWND parent,
const gfx::Rect& bounds,
AnchorPosition anchor);
// Hides and cancels the menu. This does nothing if the menu is not open.
void Cancel();
// Adds an item to this menu.
// item_id The id of the item, used to identify it in delegate callbacks
// or (if delegate is NULL) to identify the command associated
// with this item with the controller specified in the ctor. Note
// that this value should not be 0 as this has a special meaning
// ("NULL command, no item selected")
// label The text label shown.
// type The type of item.
void AppendMenuItem(int item_id,
const std::wstring& label,
Type type) {
AppendMenuItemInternal(item_id, label, SkBitmap(), type);
}
// Append a submenu to this menu.
// The returned pointer is owned by this menu.
MenuItemView* AppendSubMenu(int item_id,
const std::wstring& label) {
return AppendMenuItemInternal(item_id, label, SkBitmap(), SUBMENU);
}
// Append a submenu with an icon to this menu.
// The returned pointer is owned by this menu.
MenuItemView* AppendSubMenuWithIcon(int item_id,
const std::wstring& label,
const SkBitmap& icon) {
return AppendMenuItemInternal(item_id, label, icon, SUBMENU);
}
// This is a convenience for standard text label menu items where the label
// is provided with this call.
void AppendMenuItemWithLabel(int item_id,
const std::wstring& label) {
AppendMenuItem(item_id, label, NORMAL);
}
// This is a convenience for text label menu items where the label is
// provided by the delegate.
void AppendDelegateMenuItem(int item_id) {
AppendMenuItem(item_id, std::wstring(), NORMAL);
}
// Adds a separator to this menu
void AppendSeparator() {
AppendMenuItemInternal(0, std::wstring(), SkBitmap(), SEPARATOR);
}
// Appends a menu item with an icon. This is for the menu item which
// needs an icon. Calling this function forces the Menu class to draw
// the menu, instead of relying on Windows.
void AppendMenuItemWithIcon(int item_id,
const std::wstring& label,
const SkBitmap& icon) {
AppendMenuItemInternal(item_id, label, icon, NORMAL);
}
// Returns the view that contains child menu items. If the submenu has
// not been creates, this creates it.
virtual SubmenuView* CreateSubmenu();
// Returns true if this menu item has a submenu.
virtual bool HasSubmenu() const { return (submenu_ != NULL); }
// Returns the view containing child menu items.
virtual SubmenuView* GetSubmenu() const { return submenu_; }
// Returns the parent menu item.
MenuItemView* GetParentMenuItem() const { return parent_menu_item_; }
// Sets the font.
void SetFont(const ChromeFont& font) { font_ = font; }
// Sets the title
void SetTitle(const std::wstring& title) {
title_ = title;
}
// Returns the title.
const std::wstring& GetTitle() const { return title_; }
// Sets whether this item is selected. This is invoked as the user moves
// the mouse around the menu while open.
void SetSelected(bool selected);
// Returns true if the item is selected.
bool IsSelected() const { return selected_; }
// Sets the icon for the descendant identified by item_id.
void SetIcon(const SkBitmap& icon, int item_id);
// Sets the icon of this menu item.
void SetIcon(const SkBitmap& icon);
// Returns the icon.
const SkBitmap& GetIcon() const { return icon_; }
// Sets the command id of this menu item.
void SetCommand(int command) { command_ = command; }
// Returns the command id of this item.
int GetCommand() const { return command_; }
// Paints the menu item.
virtual void Paint(ChromeCanvas* canvas);
// Returns the preferred size of this item.
virtual gfx::Size GetPreferredSize();
// Returns the object responsible for controlling showing the menu.
MenuController* GetMenuController();
// Returns the delegate. This returns the delegate of the root menu item.
MenuDelegate* GetDelegate();
// Returns the root parent, or this if this has no parent.
MenuItemView* GetRootMenuItem();
// Returns the mnemonic for this MenuItemView, or 0 if this MenuItemView
// doesn't have a mnemonic.
wchar_t GetMnemonic();
// Do we have icons? This only has effect on the top menu. Turning this on
// makes the menus slightly wider and taller.
void set_has_icons(bool has_icons) {
has_icons_ = has_icons;
}
protected:
// Creates a MenuItemView. This is used by the various AddXXX methods.
MenuItemView(MenuItemView* parent, int command, Type type);
private:
// Called by the two constructors to initialize this menu item.
void Init(MenuItemView* parent,
int command,
MenuItemView::Type type,
MenuDelegate* delegate);
// All the AddXXX methods funnel into this.
MenuItemView* AppendMenuItemInternal(int item_id,
const std::wstring& label,
const SkBitmap& icon,
Type type);
// Returns the descendant with the specified command.
MenuItemView* GetDescendantByID(int id);
// Invoked by the MenuController when the menu closes as the result of
// drag and drop run.
void DropMenuClosed(bool notify_delegate);
// The RunXXX methods call into this to set up the necessary state before
// running.
void PrepareForRun(bool has_mnemonics);
// Returns the flags passed to DrawStringInt.
int GetDrawStringFlags();
// If this menu item has no children a child is added showing it has no
// children. Otherwise AddEmtpyMenuIfNecessary is recursively invoked on
// child menu items that have children.
void AddEmptyMenus();
// Undoes the work of AddEmptyMenus.
void RemoveEmptyMenus();
// Given bounds within our View, this helper routine mirrors the bounds if
// necessary.
void AdjustBoundsForRTLUI(RECT* rect) const;
// Actual paint implementation. If for_drag is true, portions of the menu
// are not rendered.
void Paint(ChromeCanvas* canvas, bool for_drag);
// Destroys the window used to display this menu and recursively destroys
// the windows used to display all descendants.
void DestroyAllMenuHosts();
// Returns the various margins.
int GetTopMargin();
int GetBottomMargin();
// The delegate. This is only valid for the root menu item. You shouldn't
// use this directly, instead use GetDelegate() which walks the tree as
// as necessary.
MenuDelegate* delegate_;
// Returns the controller for the run operation, or NULL if the menu isn't
// showing.
MenuController* controller_;
// Used to detect when Cancel was invoked.
bool canceled_;
// Our parent.
MenuItemView* parent_menu_item_;
// Type of menu. NOTE: MenuItemView doesn't itself represent SEPARATOR,
// that is handled by an entirely different view class.
Type type_;
// Whether we're selected.
bool selected_;
// Command id.
int command_;
// Submenu, created via CreateSubmenu.
SubmenuView* submenu_;
// Font.
ChromeFont font_;
// Title.
std::wstring title_;
// Icon.
SkBitmap icon_;
// Does the title have a mnemonic?
bool has_mnemonics_;
bool has_icons_;
DISALLOW_EVIL_CONSTRUCTORS(MenuItemView);
};
// SubmenuView ----------------------------------------------------------------
// SubmenuView is the parent of all menu items.
//
// SubmenuView has the following responsibilities:
// . It positions and sizes all child views (any type of View may be added,
// not just MenuItemViews).
// . Forwards the appropriate events to the MenuController. This allows the
// MenuController to update the selection as the user moves the mouse around.
// . Renders the drop indicator during a drop operation.
// . Shows and hides the window (a WidgetWin) when the menu is shown on
// screen.
//
// SubmenuView is itself contained in a MenuScrollViewContainer.
// MenuScrollViewContainer handles showing as much of the SubmenuView as the
// screen allows. If the SubmenuView is taller than the screen, scroll buttons
// are provided that allow the user to see all the menu items.
class SubmenuView : public View {
public:
// Creates a SubmenuView for the specified menu item.
explicit SubmenuView(MenuItemView* parent);
~SubmenuView();
// Returns the number of child views that are MenuItemViews.
// MenuItemViews are identified by ID.
int GetMenuItemCount();
// Returns the MenuItemView at the specified index.
MenuItemView* GetMenuItemAt(int index);
// Positions and sizes the child views. This tiles the views vertically,
// giving each child the available width.
virtual void Layout();
virtual gfx::Size GetPreferredSize();
// View method. Overriden to schedule a paint. We do this so that when
// scrolling occurs, everything is repainted correctly.
virtual void DidChangeBounds(const gfx::Rect& previous,
const gfx::Rect& current);
// Painting.
void PaintChildren(ChromeCanvas* canvas);
// Drag and drop methods. These are forwarded to the MenuController.
virtual bool CanDrop(const OSExchangeData& data);
virtual void OnDragEntered(const DropTargetEvent& event);
virtual int OnDragUpdated(const DropTargetEvent& event);
virtual void OnDragExited();
virtual int OnPerformDrop(const DropTargetEvent& event);
// Scrolls on menu item boundaries.
virtual bool OnMouseWheel(const MouseWheelEvent& e);
// Returns true if the menu is showing.
bool IsShowing();
// Shows the menu at the specified location. Coordinates are in screen
// coordinates. max_width gives the max width the view should be.
void ShowAt(HWND parent, const gfx::Rect& bounds, bool do_capture);
// Closes the menu, destroying the host.
void Close();
// Hides the hosting window.
//
// The hosting window is hidden first, then deleted (Close) when the menu is
// done running. This is done to avoid deletion ordering dependencies. In
// particular, during drag and drop (and when a modal dialog is shown as
// a result of choosing a context menu) it is possible that an event is
// being processed by the host, so that host is on the stack when we need to
// close the window. If we closed the window immediately (and deleted it),
// when control returned back to host we would crash as host was deleted.
void Hide();
// If mouse capture was grabbed, it is released. Does nothing if mouse was
// not captured.
void ReleaseCapture();
// Returns the parent menu item we're showing children for.
MenuItemView* GetMenuItem() const { return parent_menu_item_; }
// Overriden to return true. This prevents tab from doing anything.
virtual bool CanProcessTabKeyEvents() { return true; }
// Set the drop item and position.
void SetDropMenuItem(MenuItemView* item,
MenuDelegate::DropPosition position);
// Returns whether the selection should be shown for the specified item.
// The selection is NOT shown during drag and drop when the drop is over
// the menu.
bool GetShowSelection(MenuItemView* item);
// Returns the container for the SubmenuView.
MenuScrollViewContainer* GetScrollViewContainer();
// Returns the host of the menu. Returns NULL if not showing.
MenuHost* host() const { return host_; }
private:
// Paints the drop indicator. This is only invoked if item is non-NULL and
// position is not DROP_NONE.
void PaintDropIndicator(ChromeCanvas* canvas,
MenuItemView* item,
MenuDelegate::DropPosition position);
void SchedulePaintForDropIndicator(MenuItemView* item,
MenuDelegate::DropPosition position);
// Calculates the location of th edrop indicator.
gfx::Rect CalculateDropIndicatorBounds(MenuItemView* item,
MenuDelegate::DropPosition position);
// Parent menu item.
MenuItemView* parent_menu_item_;
// WidgetWin subclass used to show the children.
MenuHost* host_;
// If non-null, indicates a drop is in progress and drop_item is the item
// the drop is over.
MenuItemView* drop_item_;
// Position of the drop.
MenuDelegate::DropPosition drop_position_;
// Ancestor of the SubmenuView, lazily created.
MenuScrollViewContainer* scroll_view_container_;
DISALLOW_EVIL_CONSTRUCTORS(SubmenuView);
};
// MenuController -------------------------------------------------------------
// MenuController manages showing, selecting and drag/drop for menus.
// All relevant events are forwarded to the MenuController from SubmenuView
// and MenuHost.
class MenuController : public MessageLoopForUI::Dispatcher {
public:
friend class MenuHostRootView;
friend class MenuItemView;
friend class MenuScrollTask;
// If a menu is currently active, this returns the controller for it.
static MenuController* GetActiveInstance();
// Runs the menu at the specified location. If the menu was configured to
// block, the selected item is returned. If the menu does not block this
// returns NULL immediately.
MenuItemView* Run(HWND parent,
MenuItemView* root,
const gfx::Rect& bounds,
MenuItemView::AnchorPosition position,
int* mouse_event_flags);
// Whether or not Run blocks.
bool IsBlockingRun() const { return blocking_run_; }
// Sets the selection to menu_item, a value of NULL unselects everything.
// If open_submenu is true and menu_item has a submenu, the submenu is shown.
// If update_immediately is true, submenus are opened immediately, otherwise
// submenus are only opened after a timer fires.
//
// Internally this updates pending_state_ immediatley, and if
// update_immediately is true, CommitPendingSelection is invoked to
// show/hide submenus and update state_.
void SetSelection(MenuItemView* menu_item,
bool open_submenu,
bool update_immediately);
// Cancels the current Run. If all is true, any nested loops are canceled
// as well. This immediately hides all menus.
void Cancel(bool all);
// An alternative to Cancel(true) that can be used with a OneShotTimer.
void CancelAll() { return Cancel(true); }
// Various events, forwarded from the submenu.
//
// NOTE: the coordinates of the events are in that of the
// MenuScrollViewContainer.
void OnMousePressed(SubmenuView* source, const MouseEvent& event);
void OnMouseDragged(SubmenuView* source, const MouseEvent& event);
void OnMouseReleased(SubmenuView* source, const MouseEvent& event);
void OnMouseMoved(SubmenuView* source, const MouseEvent& event);
void OnMouseEntered(SubmenuView* source, const MouseEvent& event);
bool CanDrop(SubmenuView* source, const OSExchangeData& data);
void OnDragEntered(SubmenuView* source, const DropTargetEvent& event);
int OnDragUpdated(SubmenuView* source, const DropTargetEvent& event);
void OnDragExited(SubmenuView* source);
int OnPerformDrop(SubmenuView* source, const DropTargetEvent& event);
// Invoked from the scroll buttons of the MenuScrollViewContainer.
void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
void OnDragExitedScrollButton(SubmenuView* source);
private:
// Tracks selection information.
struct State {
State() : item(NULL), submenu_open(false) {}
// The selected menu item.
MenuItemView* item;
// If item has a submenu this indicates if the submenu is showing.
bool submenu_open;
// Bounds passed to the run menu. Used for positioning the first menu.
gfx::Rect initial_bounds;
// Position of the initial menu.
MenuItemView::AnchorPosition anchor;
// The direction child menus have opened in.
std::list<bool> open_leading;
// Bounds for the monitor we're showing on.
gfx::Rect monitor_bounds;
};
// Used by GetMenuPartByScreenCoordinate to indicate the menu part at a
// particular location.
struct MenuPart {
// Type of part.
enum Type {
NONE,
MENU_ITEM,
SCROLL_UP,
SCROLL_DOWN
};
MenuPart() : type(NONE), menu(NULL), submenu(NULL) {}
// Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP.
bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; }
// Type of part.
Type type;
// If type is MENU_ITEM, this is the menu item the mouse is over, otherwise
// this is NULL.
// NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item
// but is over a menu (for example, the mouse is over a separator or
// empty menu), this is NULL.
MenuItemView* menu;
// If type is SCROLL_*, this is the submenu the mouse is over.
SubmenuView* submenu;
};
// Sets the active MenuController.
static void SetActiveInstance(MenuController* controller);
// Dispatcher method. This returns true if the menu was canceled, or
// if the message is such that the menu should be closed.
virtual bool Dispatch(const MSG& msg);
// Key processing. The return value of these is returned from Dispatch.
// In other words, if these return false (which they do if escape was
// pressed, or a matching mnemonic was found) the message loop returns.
bool OnKeyDown(const MSG& msg);
bool OnChar(const MSG& msg);
// Creates a MenuController. If blocking is true, Run blocks the caller
explicit MenuController(bool blocking);
~MenuController();
// Invoked when the user accepts the selected item. This is only used
// when blocking. This schedules the loop to quit.
void Accept(MenuItemView* item, int mouse_event_flags);
// Closes all menus, including any menus of nested invocations of Run.
void CloseAllNestedMenus();
// Gets the enabled menu item at the specified location.
// If over_any_menu is non-null it is set to indicate whether the location
// is over any menu. It is possible for this to return NULL, but
// over_any_menu to be true. For example, the user clicked on a separator.
MenuItemView* GetMenuItemAt(View* menu, int x, int y);
// If there is an empty menu item at the specified location, it is returned.
MenuItemView* GetEmptyMenuItemAt(View* source, int x, int y);
// Returns true if the coordinate is over the scroll buttons of the
// SubmenuView's MenuScrollViewContainer. If true is returned, part is set to
// indicate which scroll button the coordinate is.
bool IsScrollButtonAt(SubmenuView* source,
int x,
int y,
MenuPart::Type* part);
// Returns the target for the mouse event.
MenuPart GetMenuPartByScreenCoordinate(SubmenuView* source,
int source_x,
int source_y);
// Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns
// true if the supplied SubmenuView contains the location in terms of the
// screen. If it does, part is set appropriately and true is returned.
bool GetMenuPartByScreenCoordinateImpl(SubmenuView* menu,
const gfx::Point& screen_loc,
MenuPart* part);
// Returns true if the SubmenuView contains the specified location. This does
// NOT included the scroll buttons, only the submenu view.
bool DoesSubmenuContainLocation(SubmenuView* submenu,
const gfx::Point& screen_loc);
// Opens/Closes the necessary menus such that state_ matches that of
// pending_state_. This is invoked if submenus are not opened immediately,
// but after a delay.
void CommitPendingSelection();
// If item has a submenu, it is closed. This does NOT update the selection
// in anyway.
void CloseMenu(MenuItemView* item);
// If item has a submenu, it is opened. This does NOT update the selection
// in anyway.
void OpenMenu(MenuItemView* item);
// Builds the paths of the two menu items into the two paths, and
// sets first_diff_at to the location of the first difference between the
// two paths.
void BuildPathsAndCalculateDiff(MenuItemView* old_item,
MenuItemView* new_item,
std::vector<MenuItemView*>* old_path,
std::vector<MenuItemView*>* new_path,
size_t* first_diff_at);
// Builds the path for the specified item.
void BuildMenuItemPath(MenuItemView* item, std::vector<MenuItemView*>* path);
// Starts/stops the timer that commits the pending state to state
// (opens/closes submenus).
void StartShowTimer();
void StopShowTimer();
// Starts/stops the timer cancel the menu. This is used during drag and
// drop when the drop enters/exits the menu.
void StartCancelAllTimer();
void StopCancelAllTimer();
// Calculates the bounds of the menu to show. is_leading is set to match the
// direction the menu opened in.
gfx::Rect CalculateMenuBounds(MenuItemView* item,
bool prefer_leading,
bool* is_leading);
// Returns the depth of the menu.
static int MenuDepth(MenuItemView* item);
// Selects the next/previous menu item.
void IncrementSelection(int delta);
// If the selected item has a submenu and it isn't currently open, the
// the selection is changed such that the menu opens immediately.
void OpenSubmenuChangeSelectionIfCan();
// If possible, closes the submenu.
void CloseSubmenu();
// Returns true if window is the window used to show item, or any of
// items ancestors.
bool IsMenuWindow(MenuItemView* item, HWND window);
// Selects by mnemonic, and if that doesn't work tries the first character of
// the title. Returns true if a match was selected and the menu should exit.
bool SelectByChar(wchar_t key);
// If there is a window at the location of the event, a new mouse event is
// generated and posted to it.
void RepostEvent(SubmenuView* source, const MouseEvent& event);
// Sets the drop target to new_item.
void SetDropMenuItem(MenuItemView* new_item,
MenuDelegate::DropPosition position);
// Starts/stops scrolling as appropriate. part gives the part the mouse is
// over.
void UpdateScrolling(const MenuPart& part);
// Stops scrolling.
void StopScrolling();
// The active instance.
static MenuController* active_instance_;
// If true, Run blocks. If false, Run doesn't block and this is used for
// drag and drop. Note that the semantics for drag and drop are slightly
// different: cancel timer is kicked off any time the drag moves outside the
// menu, mouse events do nothing...
bool blocking_run_;
// If true, we're showing.
bool showing_;
// If true, all nested run loops should be exited.
bool exit_all_;
// Whether we did a capture. We do a capture only if we're blocking and
// the mouse was down when Run.
bool did_capture_;
// As the user drags the mouse around pending_state_ changes immediately.
// When the user stops moving/dragging the mouse (or clicks the mouse)
// pending_state_ is committed to state_, potentially resulting in
// opening or closing submenus. This gives a slight delayed effect to
// submenus as the user moves the mouse around. This is done so that as the
// user moves the mouse all submenus don't immediately pop.
State pending_state_;
State state_;
// If the user accepted the selection, this is the result.
MenuItemView* result_;
// The mouse event flags when the user clicked on a menu. Is 0 if the
// user did not use the mousee to select the menu.
int result_mouse_event_flags_;
// If not empty, it means we're nested. When Run is invoked from within
// Run, the current state (state_) is pushed onto menu_stack_. This allows
// MenuController to restore the state when the nested run returns.
std::list<State> menu_stack_;
// As the mouse moves around submenus are not opened immediately. Instead
// they open after this timer fires.
base::OneShotTimer<MenuController> show_timer_;
// Used to invoke CancelAll(). This is used during drag and drop to hide the
// menu after the mouse moves out of the of the menu. This is necessitated by
// the lack of an ability to detect when the drag has completed from the drop
// side.
base::OneShotTimer<MenuController> cancel_all_timer_;
// Drop target.
MenuItemView* drop_target_;
MenuDelegate::DropPosition drop_position_;
// Owner of child windows.
HWND owner_;
// Indicates a possible drag operation.
bool possible_drag_;
// Location the mouse was pressed at. Used to detect d&d.
int press_x_;
int press_y_;
// We get a slew of drag updated messages as the mouse is over us. To avoid
// continually processing whether we can drop, we cache the coordinates.
bool valid_drop_coordinates_;
int drop_x_;
int drop_y_;
int last_drop_operation_;
// If true, the mouse is over some menu.
bool any_menu_contains_mouse_;
// If true, we're in the middle of invoking ShowAt on a submenu.
bool showing_submenu_;
// Task for scrolling the menu. If non-null indicates a scroll is currently
// underway.
scoped_ptr<MenuScrollTask> scroll_task_;
DISALLOW_EVIL_CONSTRUCTORS(MenuController);
};
} // namespace views
#endif // CHROME_VIEWS_CHROME_MENU_H__