• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
6 #define UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
7 
8 #include "build/build_config.h"
9 
10 #include <list>
11 #include <set>
12 #include <vector>
13 
14 #include "base/compiler_specific.h"
15 #include "base/memory/linked_ptr.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/timer/timer.h"
18 #include "ui/events/event.h"
19 #include "ui/events/event_constants.h"
20 #include "ui/events/platform/platform_event_dispatcher.h"
21 #include "ui/views/controls/button/menu_button.h"
22 #include "ui/views/controls/menu/menu_config.h"
23 #include "ui/views/controls/menu/menu_delegate.h"
24 #include "ui/views/widget/widget_observer.h"
25 
26 namespace base {
27 class MessagePumpDispatcher;
28 }
29 namespace gfx {
30 class Screen;
31 }
32 namespace ui {
33 class NativeTheme;
34 class OSExchangeData;
35 class ScopedEventDispatcher;
36 }
37 namespace views {
38 
39 class MenuButton;
40 class MenuHostRootView;
41 class MenuItemView;
42 class MenuMessageLoop;
43 class MouseEvent;
44 class SubmenuView;
45 class View;
46 
47 namespace internal {
48 class MenuControllerDelegate;
49 class MenuEventDispatcher;
50 class MenuMessagePumpDispatcher;
51 class MenuRunnerImpl;
52 }
53 
54 // MenuController -------------------------------------------------------------
55 
56 // MenuController is used internally by the various menu classes to manage
57 // showing, selecting and drag/drop for menus. All relevant events are
58 // forwarded to the MenuController from SubmenuView and MenuHost.
59 class VIEWS_EXPORT MenuController : public WidgetObserver {
60  public:
61   // Enumeration of how the menu should exit.
62   enum ExitType {
63     // Don't exit.
64     EXIT_NONE,
65 
66     // All menus, including nested, should be exited.
67     EXIT_ALL,
68 
69     // Only the outermost menu should be exited.
70     EXIT_OUTERMOST,
71 
72     // This is set if the menu is being closed as the result of one of the menus
73     // being destroyed.
74     EXIT_DESTROYED
75   };
76 
77   // If a menu is currently active, this returns the controller for it.
78   static MenuController* GetActiveInstance();
79 
80   // Runs the menu at the specified location. If the menu was configured to
81   // block, the selected item is returned. If the menu does not block this
82   // returns NULL immediately.
83   MenuItemView* Run(Widget* parent,
84                     MenuButton* button,
85                     MenuItemView* root,
86                     const gfx::Rect& bounds,
87                     MenuAnchorPosition position,
88                     bool context_menu,
89                     bool is_nested_drag,
90                     int* event_flags);
91 
92   // Whether or not Run blocks.
IsBlockingRun()93   bool IsBlockingRun() const { return blocking_run_; }
94 
in_nested_run()95   bool in_nested_run() const { return !menu_stack_.empty(); }
96 
97   // Whether or not drag operation is in progress.
drag_in_progress()98   bool drag_in_progress() const { return drag_in_progress_; }
99 
100   // Whether the MenuController initiated the drag in progress. False if there
101   // is no drag in progress.
did_initiate_drag()102   bool did_initiate_drag() const { return did_initiate_drag_; }
103 
104   // Returns the owner of child windows.
105   // WARNING: this may be NULL.
owner()106   Widget* owner() { return owner_; }
107 
108   // Get the anchor position wich is used to show this menu.
GetAnchorPosition()109   MenuAnchorPosition GetAnchorPosition() { return state_.anchor; }
110 
111   // Cancels the current Run. See ExitType for a description of what happens
112   // with the various parameters.
113   void Cancel(ExitType type);
114 
115   // An alternative to Cancel(EXIT_ALL) that can be used with a OneShotTimer.
CancelAll()116   void CancelAll() { Cancel(EXIT_ALL); }
117 
118   // Returns the current exit type. This returns a value other than EXIT_NONE if
119   // the menu is being canceled.
exit_type()120   ExitType exit_type() const { return exit_type_; }
121 
122   // Returns the time from the event which closed the menu - or 0.
closing_event_time()123   base::TimeDelta closing_event_time() const { return closing_event_time_; }
124 
set_is_combobox(bool is_combobox)125   void set_is_combobox(bool is_combobox) { is_combobox_ = is_combobox; }
126 
127   // Various events, forwarded from the submenu.
128   //
129   // NOTE: the coordinates of the events are in that of the
130   // MenuScrollViewContainer.
131   void OnMousePressed(SubmenuView* source, const ui::MouseEvent& event);
132   void OnMouseDragged(SubmenuView* source, const ui::MouseEvent& event);
133   void OnMouseReleased(SubmenuView* source, const ui::MouseEvent& event);
134   void OnMouseMoved(SubmenuView* source, const ui::MouseEvent& event);
135   void OnMouseEntered(SubmenuView* source, const ui::MouseEvent& event);
136   bool OnMouseWheel(SubmenuView* source, const ui::MouseWheelEvent& event);
137   void OnGestureEvent(SubmenuView* source, ui::GestureEvent* event);
138 
139   bool GetDropFormats(
140       SubmenuView* source,
141       int* formats,
142       std::set<ui::OSExchangeData::CustomFormat>* custom_formats);
143   bool AreDropTypesRequired(SubmenuView* source);
144   bool CanDrop(SubmenuView* source, const ui::OSExchangeData& data);
145   void OnDragEntered(SubmenuView* source, const ui::DropTargetEvent& event);
146   int OnDragUpdated(SubmenuView* source, const ui::DropTargetEvent& event);
147   void OnDragExited(SubmenuView* source);
148   int OnPerformDrop(SubmenuView* source, const ui::DropTargetEvent& event);
149 
150   // Invoked from the scroll buttons of the MenuScrollViewContainer.
151   void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
152   void OnDragExitedScrollButton(SubmenuView* source);
153 
154   // Called by the Widget when a drag is about to start on a child view. This
155   // could be initiated by one of our MenuItemViews, or could be through another
156   // child View.
157   void OnDragWillStart();
158 
159   // Called by the Widget when the drag has completed. |should_close|
160   // corresponds to whether or not the menu should close.
161   void OnDragComplete(bool should_close);
162 
163   // Update the submenu's selection based on the current mouse location
164   void UpdateSubmenuSelection(SubmenuView* source);
165 
166   // WidgetObserver overrides:
167   virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
168 
169   // Only used for testing.
170   bool IsCancelAllTimerRunningForTest();
171 
172   // Only used for testing.
173   static void TurnOffMenuSelectionHoldForTest();
174 
175  private:
176   friend class internal::MenuEventDispatcher;
177   friend class internal::MenuMessagePumpDispatcher;
178   friend class internal::MenuRunnerImpl;
179   friend class MenuControllerTest;
180   friend class MenuHostRootView;
181   friend class MenuItemView;
182   friend class SubmenuView;
183 
184   class MenuScrollTask;
185 
186   struct SelectByCharDetails;
187 
188   // Values supplied to SetSelection.
189   enum SetSelectionTypes {
190     SELECTION_DEFAULT               = 0,
191 
192     // If set submenus are opened immediately, otherwise submenus are only
193     // openned after a timer fires.
194     SELECTION_UPDATE_IMMEDIATELY    = 1 << 0,
195 
196     // If set and the menu_item has a submenu, the submenu is shown.
197     SELECTION_OPEN_SUBMENU          = 1 << 1,
198 
199     // SetSelection is being invoked as the result exiting or cancelling the
200     // menu. This is used for debugging.
201     SELECTION_EXIT                  = 1 << 2,
202   };
203 
204   // Result type for SendAcceleratorToHotTrackedView
205   enum SendAcceleratorResultType {
206     // Accelerator is not sent because of no hot tracked views.
207     ACCELERATOR_NOT_PROCESSED,
208 
209     // Accelerator is sent to the hot tracked views.
210     ACCELERATOR_PROCESSED,
211 
212     // Same as above and the accelerator causes the exit of the menu.
213     ACCELERATOR_PROCESSED_EXIT
214   };
215 
216   // Tracks selection information.
217   struct State {
218     State();
219     ~State();
220 
221     // The selected menu item.
222     MenuItemView* item;
223 
224     // If item has a submenu this indicates if the submenu is showing.
225     bool submenu_open;
226 
227     // Bounds passed to the run menu. Used for positioning the first menu.
228     gfx::Rect initial_bounds;
229 
230     // Position of the initial menu.
231     MenuAnchorPosition anchor;
232 
233     // The direction child menus have opened in.
234     std::list<bool> open_leading;
235 
236     // Bounds for the monitor we're showing on.
237     gfx::Rect monitor_bounds;
238 
239     // Is the current menu a context menu.
240     bool context_menu;
241   };
242 
243   // Used by GetMenuPart to indicate the menu part at a particular location.
244   struct MenuPart {
245     // Type of part.
246     enum Type {
247       NONE,
248       MENU_ITEM,
249       SCROLL_UP,
250       SCROLL_DOWN
251     };
252 
MenuPartMenuPart253     MenuPart() : type(NONE), menu(NULL), parent(NULL), submenu(NULL) {}
254 
255     // Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP.
is_scrollMenuPart256     bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; }
257 
258     // Type of part.
259     Type type;
260 
261     // If type is MENU_ITEM, this is the menu item the mouse is over, otherwise
262     // this is NULL.
263     // NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item
264     //       but is over a menu (for example, the mouse is over a separator or
265     //       empty menu), this is NULL and parent is the menu the mouse was
266     //       clicked on.
267     MenuItemView* menu;
268 
269     // If type is MENU_ITEM but the mouse is not over a menu item this is the
270     // parent of the menu item the user clicked on. Otherwise this is NULL.
271     MenuItemView* parent;
272 
273     // This is the submenu the mouse is over.
274     SubmenuView* submenu;
275   };
276 
277   // Sets the selection to |menu_item|. A value of NULL unselects
278   // everything. |types| is a bitmask of |SetSelectionTypes|.
279   //
280   // Internally this updates pending_state_ immediatley. state_ is only updated
281   // immediately if SELECTION_UPDATE_IMMEDIATELY is set. If
282   // SELECTION_UPDATE_IMMEDIATELY is not set CommitPendingSelection is invoked
283   // to show/hide submenus and update state_.
284   void SetSelection(MenuItemView* menu_item, int types);
285 
286   void SetSelectionOnPointerDown(SubmenuView* source,
287                                  const ui::LocatedEvent& event);
288   void StartDrag(SubmenuView* source, const gfx::Point& location);
289 
290   // Key processing. The return value of this is returned from Dispatch.
291   // In other words, if this returns false (which happens if escape was
292   // pressed, or a matching mnemonic was found) the message loop returns.
293   bool OnKeyDown(ui::KeyboardCode key_code);
294 
295   // Creates a MenuController. If |blocking| is true a nested message loop is
296   // started in |Run|.
297   MenuController(ui::NativeTheme* theme,
298                  bool blocking,
299                  internal::MenuControllerDelegate* delegate);
300 
301   virtual ~MenuController();
302 
303   // Runs the platform specific bits of the message loop. If |nested_menu| is
304   // true we're being asked to run a menu from within a menu (eg a context
305   // menu).
306   void RunMessageLoop(bool nested_menu);
307 
308   // AcceleratorPressed is invoked on the hot tracked view if it exists.
309   SendAcceleratorResultType SendAcceleratorToHotTrackedView();
310 
311   void UpdateInitialLocation(const gfx::Rect& bounds,
312                              MenuAnchorPosition position,
313                              bool context_menu);
314 
315   // Invoked when the user accepts the selected item. This is only used
316   // when blocking. This schedules the loop to quit.
317   void Accept(MenuItemView* item, int event_flags);
318 
319   bool ShowSiblingMenu(SubmenuView* source, const gfx::Point& mouse_location);
320 
321   // Shows a context menu for |menu_item| as a result of a located event if
322   // appropriate. This is invoked on long press and releasing the right mouse
323   // button. Returns whether a context menu was shown.
324   bool ShowContextMenu(MenuItemView* menu_item,
325                        SubmenuView* source,
326                        const ui::LocatedEvent& event,
327                        ui::MenuSourceType source_type);
328 
329   // Closes all menus, including any menus of nested invocations of Run.
330   void CloseAllNestedMenus();
331 
332   // Gets the enabled menu item at the specified location.
333   // If over_any_menu is non-null it is set to indicate whether the location
334   // is over any menu. It is possible for this to return NULL, but
335   // over_any_menu to be true. For example, the user clicked on a separator.
336   MenuItemView* GetMenuItemAt(View* menu, int x, int y);
337 
338   // If there is an empty menu item at the specified location, it is returned.
339   MenuItemView* GetEmptyMenuItemAt(View* source, int x, int y);
340 
341   // Returns true if the coordinate is over the scroll buttons of the
342   // SubmenuView's MenuScrollViewContainer. If true is returned, part is set to
343   // indicate which scroll button the coordinate is.
344   bool IsScrollButtonAt(SubmenuView* source,
345                         int x,
346                         int y,
347                         MenuPart::Type* part);
348 
349   // Returns the target for the mouse event. The coordinates are in terms of
350   // source's scroll view container.
351   MenuPart GetMenuPart(SubmenuView* source, const gfx::Point& source_loc);
352 
353   // Returns the target for mouse events. The search is done through |item| and
354   // all its parents.
355   MenuPart GetMenuPartByScreenCoordinateUsingMenu(MenuItemView* item,
356                                                   const gfx::Point& screen_loc);
357 
358   // Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns
359   // true if the supplied SubmenuView contains the location in terms of the
360   // screen. If it does, part is set appropriately and true is returned.
361   bool GetMenuPartByScreenCoordinateImpl(SubmenuView* menu,
362                                          const gfx::Point& screen_loc,
363                                          MenuPart* part);
364 
365   // Returns true if the SubmenuView contains the specified location. This does
366   // NOT included the scroll buttons, only the submenu view.
367   bool DoesSubmenuContainLocation(SubmenuView* submenu,
368                                   const gfx::Point& screen_loc);
369 
370   // Opens/Closes the necessary menus such that state_ matches that of
371   // pending_state_. This is invoked if submenus are not opened immediately,
372   // but after a delay.
373   void CommitPendingSelection();
374 
375   // If item has a submenu, it is closed. This does NOT update the selection
376   // in anyway.
377   void CloseMenu(MenuItemView* item);
378 
379   // If item has a submenu, it is opened. This does NOT update the selection
380   // in anyway.
381   void OpenMenu(MenuItemView* item);
382 
383   // Implementation of OpenMenu. If |show| is true, this invokes show on the
384   // menu, otherwise Reposition is invoked.
385   void OpenMenuImpl(MenuItemView* item, bool show);
386 
387   // Invoked when the children of a menu change and the menu is showing.
388   // This closes any submenus and resizes the submenu.
389   void MenuChildrenChanged(MenuItemView* item);
390 
391   // Builds the paths of the two menu items into the two paths, and
392   // sets first_diff_at to the location of the first difference between the
393   // two paths.
394   void BuildPathsAndCalculateDiff(MenuItemView* old_item,
395                                   MenuItemView* new_item,
396                                   std::vector<MenuItemView*>* old_path,
397                                   std::vector<MenuItemView*>* new_path,
398                                   size_t* first_diff_at);
399 
400   // Builds the path for the specified item.
401   void BuildMenuItemPath(MenuItemView* item, std::vector<MenuItemView*>* path);
402 
403   // Starts/stops the timer that commits the pending state to state
404   // (opens/closes submenus).
405   void StartShowTimer();
406   void StopShowTimer();
407 
408   // Starts/stops the timer cancel the menu. This is used during drag and
409   // drop when the drop enters/exits the menu.
410   void StartCancelAllTimer();
411   void StopCancelAllTimer();
412 
413   // Calculates the bounds of the menu to show. is_leading is set to match the
414   // direction the menu opened in.
415   gfx::Rect CalculateMenuBounds(MenuItemView* item,
416                                 bool prefer_leading,
417                                 bool* is_leading);
418 
419   // Calculates the bubble bounds of the menu to show. is_leading is set to
420   // match the direction the menu opened in.
421   gfx::Rect CalculateBubbleMenuBounds(MenuItemView* item,
422                                       bool prefer_leading,
423                                       bool* is_leading);
424 
425   // Returns the depth of the menu.
426   static int MenuDepth(MenuItemView* item);
427 
428   // Selects the next/previous menu item.
429   void IncrementSelection(int delta);
430 
431   // Returns the next selectable child menu item of |parent| starting at |index|
432   // and incrementing index by |delta|. If there are no more selected menu items
433   // NULL is returned.
434   MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent,
435                                            int index,
436                                            int delta);
437 
438   // If the selected item has a submenu and it isn't currently open, the
439   // the selection is changed such that the menu opens immediately.
440   void OpenSubmenuChangeSelectionIfCan();
441 
442   // If possible, closes the submenu.
443   void CloseSubmenu();
444 
445   // Returns details about which menu items match the mnemonic |key|.
446   // |match_function| is used to determine which menus match.
447   SelectByCharDetails FindChildForMnemonic(
448       MenuItemView* parent,
449       base::char16 key,
450       bool (*match_function)(MenuItemView* menu, base::char16 mnemonic));
451 
452   // Selects or accepts the appropriate menu item based on |details|. Returns
453   // true if |Accept| was invoked (which happens if there aren't multiple item
454   // with the same mnemonic and the item to select does not have a submenu).
455   bool AcceptOrSelect(MenuItemView* parent, const SelectByCharDetails& details);
456 
457   // Selects by mnemonic, and if that doesn't work tries the first character of
458   // the title. Returns true if a match was selected and the menu should exit.
459   bool SelectByChar(base::char16 key);
460 
461   // For Windows and Aura we repost an event for some events that dismiss
462   // the context menu. The event is then reprocessed to cause its result
463   // if the context menu had not been present.
464   // On non-aura Windows, a new mouse event is generated and posted to
465   // the window (if there is one) at the location of the event. On
466   // aura, the event is reposted on the RootWindow.
467   void RepostEvent(SubmenuView* source, const ui::LocatedEvent& event);
468 
469   // Sets the drop target to new_item.
470   void SetDropMenuItem(MenuItemView* new_item,
471                        MenuDelegate::DropPosition position);
472 
473   // Starts/stops scrolling as appropriate. part gives the part the mouse is
474   // over.
475   void UpdateScrolling(const MenuPart& part);
476 
477   // Stops scrolling.
478   void StopScrolling();
479 
480   // Updates active mouse view from the location of the event and sends it
481   // the appropriate events. This is used to send mouse events to child views so
482   // that they react to click-drag-release as if the user clicked on the view
483   // itself.
484   void UpdateActiveMouseView(SubmenuView* event_source,
485                              const ui::MouseEvent& event,
486                              View* target_menu);
487 
488   // Sends a mouse release event to the current active mouse view and sets
489   // it to null.
490   void SendMouseReleaseToActiveView(SubmenuView* event_source,
491                                     const ui::MouseEvent& event);
492 
493   // Sends a mouse capture lost event to the current active mouse view and sets
494   // it to null.
495   void SendMouseCaptureLostToActiveView();
496 
497   // Sets/gets the active mouse view. See UpdateActiveMouseView() for details.
498   void SetActiveMouseView(View* view);
499   View* GetActiveMouseView();
500 
501   // Sets exit type. Calling this can terminate the active nested message-loop.
502   void SetExitType(ExitType type);
503 
504   // Terminates the current nested message-loop.
505   void TerminateNestedMessageLoop();
506 
507   // Returns true if SetExitType() should quit the message loop.
508   bool ShouldQuitNow() const;
509 
510   // Handles the mouse location event on the submenu |source|.
511   void HandleMouseLocation(SubmenuView* source,
512                            const gfx::Point& mouse_location);
513 
514   // Retrieve an appropriate Screen.
515   gfx::Screen* GetScreen();
516 
517   // The active instance.
518   static MenuController* active_instance_;
519 
520   // If true, Run blocks. If false, Run doesn't block and this is used for
521   // drag and drop. Note that the semantics for drag and drop are slightly
522   // different: cancel timer is kicked off any time the drag moves outside the
523   // menu, mouse events do nothing...
524   bool blocking_run_;
525 
526   // If true, we're showing.
527   bool showing_;
528 
529   // Indicates what to exit.
530   ExitType exit_type_;
531 
532   // Whether we did a capture. We do a capture only if we're blocking and
533   // the mouse was down when Run.
534   bool did_capture_;
535 
536   // As the user drags the mouse around pending_state_ changes immediately.
537   // When the user stops moving/dragging the mouse (or clicks the mouse)
538   // pending_state_ is committed to state_, potentially resulting in
539   // opening or closing submenus. This gives a slight delayed effect to
540   // submenus as the user moves the mouse around. This is done so that as the
541   // user moves the mouse all submenus don't immediately pop.
542   State pending_state_;
543   State state_;
544 
545   // If the user accepted the selection, this is the result.
546   MenuItemView* result_;
547 
548   // The event flags when the user selected the menu.
549   int accept_event_flags_;
550 
551   // If not empty, it means we're nested. When Run is invoked from within
552   // Run, the current state (state_) is pushed onto menu_stack_. This allows
553   // MenuController to restore the state when the nested run returns.
554   typedef std::pair<State, linked_ptr<MenuButton::PressedLock> > NestedState;
555   std::list<NestedState> menu_stack_;
556 
557   // As the mouse moves around submenus are not opened immediately. Instead
558   // they open after this timer fires.
559   base::OneShotTimer<MenuController> show_timer_;
560 
561   // Used to invoke CancelAll(). This is used during drag and drop to hide the
562   // menu after the mouse moves out of the of the menu. This is necessitated by
563   // the lack of an ability to detect when the drag has completed from the drop
564   // side.
565   base::OneShotTimer<MenuController> cancel_all_timer_;
566 
567   // Drop target.
568   MenuItemView* drop_target_;
569   MenuDelegate::DropPosition drop_position_;
570 
571   // Owner of child windows.
572   // WARNING: this may be NULL.
573   Widget* owner_;
574 
575   // Indicates a possible drag operation.
576   bool possible_drag_;
577 
578   // True when drag operation is in progress.
579   bool drag_in_progress_;
580 
581   // True when the drag operation in progress was initiated by the
582   // MenuController for a child MenuItemView (as opposed to initiated separately
583   // by a child View).
584   bool did_initiate_drag_;
585 
586   // Location the mouse was pressed at. Used to detect d&d.
587   gfx::Point press_pt_;
588 
589   // We get a slew of drag updated messages as the mouse is over us. To avoid
590   // continually processing whether we can drop, we cache the coordinates.
591   bool valid_drop_coordinates_;
592   gfx::Point drop_pt_;
593   int last_drop_operation_;
594 
595   // If true, we're in the middle of invoking ShowAt on a submenu.
596   bool showing_submenu_;
597 
598   // Task for scrolling the menu. If non-null indicates a scroll is currently
599   // underway.
600   scoped_ptr<MenuScrollTask> scroll_task_;
601 
602   // The lock to keep the menu button pressed while a menu is visible.
603   scoped_ptr<MenuButton::PressedLock> pressed_lock_;
604 
605   // ViewStorage id used to store the view mouse drag events are forwarded to.
606   // See UpdateActiveMouseView() for details.
607   const int active_mouse_view_id_;
608 
609   internal::MenuControllerDelegate* delegate_;
610 
611   // How deep we are in nested message loops. This should be at most 2 (when
612   // showing a context menu from a menu).
613   int message_loop_depth_;
614 
615   views::MenuConfig menu_config_;
616 
617   // The timestamp of the event which closed the menu - or 0 otherwise.
618   base::TimeDelta closing_event_time_;
619 
620   // Time when the menu is first shown.
621   base::TimeTicks menu_start_time_;
622 
623   // If a mouse press triggered this menu, this will have its location (in
624   // screen coordinates). Otherwise this will be (0, 0).
625   gfx::Point menu_start_mouse_press_loc_;
626 
627   // Controls behavior differences between a combobox and other types of menu
628   // (like a context menu).
629   bool is_combobox_;
630 
631   // Set to true if the menu item was selected by touch.
632   bool item_selected_by_touch_;
633 
634   scoped_ptr<MenuMessageLoop> message_loop_;
635 
636   DISALLOW_COPY_AND_ASSIGN(MenuController);
637 };
638 
639 }  // namespace views
640 
641 #endif  // UI_VIEWS_CONTROLS_MENU_MENU_CONTROLLER_H_
642