#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_pump_dispatcher.h"
#include "base/timer/timer.h"
+#include "ui/events/event.h"
#include "ui/events/event_constants.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/controls/menu/menu_delegate.h"
-#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/widget/widget_observer.h"
-namespace ui {
-class NativeTheme;
-class OSExchangeData;
+namespace base {
+class MessagePumpDispatcher;
}
namespace gfx {
class Screen;
}
+namespace ui {
+class NativeTheme;
+class OSExchangeData;
+class ScopedEventDispatcher;
+}
namespace views {
class MenuButton;
class MenuHostRootView;
+class MenuItemView;
+class MenuMessageLoop;
class MouseEvent;
class SubmenuView;
class View;
namespace internal {
class MenuControllerDelegate;
+class MenuEventDispatcher;
+class MenuMessagePumpDispatcher;
class MenuRunnerImpl;
}
// MenuController is used internally by the various menu classes to manage
// showing, selecting and drag/drop for menus. All relevant events are
// forwarded to the MenuController from SubmenuView and MenuHost.
-class VIEWS_EXPORT MenuController : public base::MessagePumpDispatcher,
- public WidgetObserver {
+class VIEWS_EXPORT MenuController : public WidgetObserver {
public:
// Enumeration of how the menu should exit.
enum ExitType {
MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu,
+ bool is_nested_drag,
int* event_flags);
// Whether or not Run blocks.
bool IsBlockingRun() const { return blocking_run_; }
+ bool in_nested_run() const { return !menu_stack_.empty(); }
+
// Whether or not drag operation is in progress.
bool drag_in_progress() const { return drag_in_progress_; }
+ // Whether the MenuController initiated the drag in progress. False if there
+ // is no drag in progress.
+ bool did_initiate_drag() const { return did_initiate_drag_; }
+
+ // Returns the owner of child windows.
+ // WARNING: this may be NULL.
+ Widget* owner() { return owner_; }
+
// Get the anchor position wich is used to show this menu.
- MenuItemView::AnchorPosition GetAnchorPosition() { return state_.anchor; }
+ MenuAnchorPosition GetAnchorPosition() { return state_.anchor; }
// Cancels the current Run. See ExitType for a description of what happens
// with the various parameters.
// Returns the time from the event which closed the menu - or 0.
base::TimeDelta closing_event_time() const { return closing_event_time_; }
- void set_accept_on_f4(bool accept_on_f4) { accept_on_f4_ = accept_on_f4; }
+ void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
// Various events, forwarded from the submenu.
//
void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
-#if defined(USE_AURA)
bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
-#endif
void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
bool GetDropFormats(
void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
void OnDragExitedScrollButton(SubmenuView* source);
+ // Called by the Widget when a drag is about to start on a child view. This
+ // could be initiated by one of our MenuItemViews, or could be through another
+ // child View.
+ void OnDragWillStart();
+
+ // Called by the Widget when the drag has completed. |should_close|
+ // corresponds to whether or not the menu should close.
+ void OnDragComplete(bool should_close);
+
// Update the submenu's selection based on the current mouse location
void UpdateSubmenuSelection(SubmenuView* source);
virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
// Only used for testing.
+ bool IsCancelAllTimerRunningForTest();
+
+ // Only used for testing.
static void TurnOffMenuSelectionHoldForTest();
private:
+ friend class internal::MenuEventDispatcher;
+ friend class internal::MenuMessagePumpDispatcher;
friend class internal::MenuRunnerImpl;
+ friend class MenuControllerTest;
friend class MenuHostRootView;
friend class MenuItemView;
friend class SubmenuView;
gfx::Rect initial_bounds;
// Position of the initial menu.
- MenuItemView::AnchorPosition anchor;
+ MenuAnchorPosition anchor;
// The direction child menus have opened in.
std::list<bool> open_leading;
const ui::LocatedEvent& event);
void StartDrag(SubmenuView* source, const gfx::Point& location);
- // 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 base::NativeEvent& event) OVERRIDE;
-
// Key processing. The return value of this is returned from Dispatch.
// In other words, if this returns false (which happens if escape was
// pressed, or a matching mnemonic was found) the message loop returns.
SendAcceleratorResultType SendAcceleratorToHotTrackedView();
void UpdateInitialLocation(const gfx::Rect& bounds,
- MenuItemView::AnchorPosition position,
+ MenuAnchorPosition position,
bool context_menu);
// Invoked when the user accepts the selected item. This is only used
void SetActiveMouseView(View* view);
View* GetActiveMouseView();
- // Sets exit type.
+ // Sets exit type. Calling this can terminate the active nested message-loop.
void SetExitType(ExitType type);
+ // Terminates the current nested message-loop.
+ void TerminateNestedMessageLoop();
+
// Returns true if SetExitType() should quit the message loop.
bool ShouldQuitNow() const;
// True when drag operation is in progress.
bool drag_in_progress_;
+ // True when the drag operation in progress was initiated by the
+ // MenuController for a child MenuItemView (as opposed to initiated separately
+ // by a child View).
+ bool did_initiate_drag_;
+
// Location the mouse was pressed at. Used to detect d&d.
gfx::Point press_pt_;
// screen coordinates). Otherwise this will be (0, 0).
gfx::Point menu_start_mouse_press_loc_;
- // Whether the menu should accept on F4, like Windows native Combobox menus.
- bool accept_on_f4_;
+ // Controls behavior differences between a combobox and other types of menu
+ // (like a context menu).
+ bool is_combobox_;
// Set to true if the menu item was selected by touch.
bool item_selected_by_touch_;
+ scoped_ptr<MenuMessageLoop> message_loop_;
+
DISALLOW_COPY_AND_ASSIGN(MenuController);
};