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_SUBMENU_VIEW_H_
6#define UI_VIEWS_CONTROLS_MENU_SUBMENU_VIEW_H_
7
8#include <string>
9
10#include "base/compiler_specific.h"
11#include "ui/views/animation/scroll_animator.h"
12#include "ui/views/controls/menu/menu_delegate.h"
13#include "ui/views/controls/prefix_delegate.h"
14#include "ui/views/controls/prefix_selector.h"
15#include "ui/views/view.h"
16
17namespace views {
18
19class MenuHost;
20class MenuItemView;
21class MenuScrollViewContainer;
22
23// SubmenuView is the parent of all menu items.
24//
25// SubmenuView has the following responsibilities:
26// . It positions and sizes all child views (any type of View may be added,
27//   not just MenuItemViews).
28// . Forwards the appropriate events to the MenuController. This allows the
29//   MenuController to update the selection as the user moves the mouse around.
30// . Renders the drop indicator during a drop operation.
31// . Shows and hides the window (a NativeWidget) when the menu is shown on
32//   screen.
33//
34// SubmenuView is itself contained in a MenuScrollViewContainer.
35// MenuScrollViewContainer handles showing as much of the SubmenuView as the
36// screen allows. If the SubmenuView is taller than the screen, scroll buttons
37// are provided that allow the user to see all the menu items.
38class VIEWS_EXPORT SubmenuView : public PrefixDelegate,
39                                 public ScrollDelegate {
40 public:
41  // The submenu's class name.
42  static const char kViewClassName[];
43
44  // Creates a SubmenuView for the specified menu item.
45  explicit SubmenuView(MenuItemView* parent);
46  virtual ~SubmenuView();
47
48  // Returns the number of child views that are MenuItemViews.
49  // MenuItemViews are identified by ID.
50  int GetMenuItemCount();
51
52  // Returns the MenuItemView at the specified index.
53  MenuItemView* GetMenuItemAt(int index);
54
55  // Positions and sizes the child views. This tiles the views vertically,
56  // giving each child the available width.
57  virtual void Layout() OVERRIDE;
58  virtual gfx::Size GetPreferredSize() const OVERRIDE;
59
60  // Override from View.
61  virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
62  virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
63
64  // Painting.
65  virtual void PaintChildren(gfx::Canvas* canvas,
66                             const views::CullSet& cull_view) OVERRIDE;
67
68  // Drag and drop methods. These are forwarded to the MenuController.
69  virtual bool GetDropFormats(
70      int* formats,
71      std::set<OSExchangeData::CustomFormat>* custom_formats) OVERRIDE;
72  virtual bool AreDropTypesRequired() OVERRIDE;
73  virtual bool CanDrop(const OSExchangeData& data) OVERRIDE;
74  virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
75  virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
76  virtual void OnDragExited() OVERRIDE;
77  virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
78
79  // Scrolls on menu item boundaries.
80  virtual bool OnMouseWheel(const ui::MouseWheelEvent& e) OVERRIDE;
81
82  // Overridden from ui::EventHandler.
83  // Scrolls on menu item boundaries.
84  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
85
86  // Overridden from PrefixDelegate.
87  virtual int GetRowCount() OVERRIDE;
88  virtual int GetSelectedRow() OVERRIDE;
89  virtual void SetSelectedRow(int row) OVERRIDE;
90  virtual base::string16 GetTextForRow(int row) OVERRIDE;
91
92  // Returns true if the menu is showing.
93  bool IsShowing();
94
95  // Shows the menu at the specified location. Coordinates are in screen
96  // coordinates. max_width gives the max width the view should be.
97  void ShowAt(Widget* parent, const gfx::Rect& bounds, bool do_capture);
98
99  // Resets the bounds of the submenu to |bounds|.
100  void Reposition(const gfx::Rect& bounds);
101
102  // Closes the menu, destroying the host.
103  void Close();
104
105  // Hides the hosting window.
106  //
107  // The hosting window is hidden first, then deleted (Close) when the menu is
108  // done running. This is done to avoid deletion ordering dependencies. In
109  // particular, during drag and drop (and when a modal dialog is shown as
110  // a result of choosing a context menu) it is possible that an event is
111  // being processed by the host, so that host is on the stack when we need to
112  // close the window. If we closed the window immediately (and deleted it),
113  // when control returned back to host we would crash as host was deleted.
114  void Hide();
115
116  // If mouse capture was grabbed, it is released. Does nothing if mouse was
117  // not captured.
118  void ReleaseCapture();
119
120  // Overriden from View to prevent tab from doing anything.
121  virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE;
122
123  // Returns the parent menu item we're showing children for.
124  MenuItemView* GetMenuItem() const;
125
126  // Set the drop item and position.
127  void SetDropMenuItem(MenuItemView* item,
128                       MenuDelegate::DropPosition position);
129
130  // Returns whether the selection should be shown for the specified item.
131  // The selection is NOT shown during drag and drop when the drop is over
132  // the menu.
133  bool GetShowSelection(MenuItemView* item);
134
135  // Returns the container for the SubmenuView.
136  MenuScrollViewContainer* GetScrollViewContainer();
137
138  // Invoked if the menu is prematurely destroyed. This can happen if the window
139  // closes while the menu is shown. If invoked the SubmenuView must drop all
140  // references to the MenuHost as the MenuHost is about to be deleted.
141  void MenuHostDestroyed();
142
143  // Max width of minor text (accelerator or subtitle) in child menu items. This
144  // doesn't include children's children, only direct children.
145  int max_minor_text_width() const { return max_minor_text_width_; }
146
147  // Minimum width of menu in pixels (default 0).  This becomes the smallest
148  // width returned by GetPreferredSize().
149  void set_minimum_preferred_width(int minimum_preferred_width) {
150    minimum_preferred_width_ = minimum_preferred_width;
151  }
152
153  // Automatically resize menu if a subview's preferred size changes.
154  bool resize_open_menu() const { return resize_open_menu_; }
155  void set_resize_open_menu(bool resize_open_menu) {
156    resize_open_menu_ = resize_open_menu;
157  }
158
159 protected:
160  // Overridden from View:
161  virtual const char* GetClassName() const OVERRIDE;
162
163  // View method. Overridden to schedule a paint. We do this so that when
164  // scrolling occurs, everything is repainted correctly.
165  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
166
167  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
168
169 private:
170  // Paints the drop indicator. This is only invoked if item is non-NULL and
171  // position is not DROP_NONE.
172  void PaintDropIndicator(gfx::Canvas* canvas,
173                          MenuItemView* item,
174                          MenuDelegate::DropPosition position);
175
176  void SchedulePaintForDropIndicator(MenuItemView* item,
177                                     MenuDelegate::DropPosition position);
178
179  // Calculates the location of th edrop indicator.
180  gfx::Rect CalculateDropIndicatorBounds(MenuItemView* item,
181                                         MenuDelegate::DropPosition position);
182
183  // Implementation of ScrollDelegate
184  virtual bool OnScroll(float dx, float dy) OVERRIDE;
185
186  // Parent menu item.
187  MenuItemView* parent_menu_item_;
188
189  // Widget subclass used to show the children. This is deleted when we invoke
190  // |DestroyMenuHost|, or |MenuHostDestroyed| is invoked back on us.
191  MenuHost* host_;
192
193  // If non-null, indicates a drop is in progress and drop_item is the item
194  // the drop is over.
195  MenuItemView* drop_item_;
196
197  // Position of the drop.
198  MenuDelegate::DropPosition drop_position_;
199
200  // Ancestor of the SubmenuView, lazily created.
201  MenuScrollViewContainer* scroll_view_container_;
202
203  // See description above getter.
204  mutable int max_minor_text_width_;
205
206  // Minimum width returned in GetPreferredSize().
207  int minimum_preferred_width_;
208
209  // Reposition open menu when contained views change size.
210  bool resize_open_menu_;
211
212  // The submenu's scroll animator
213  scoped_ptr<ScrollAnimator> scroll_animator_;
214
215  // Difference between current position and cumulative deltas passed to
216  // OnScroll.
217  // TODO(tdresser): This should be removed when raw pixel scrolling for views
218  // is enabled. See crbug.com/329354.
219  float roundoff_error_;
220
221  PrefixSelector prefix_selector_;
222
223  DISALLOW_COPY_AND_ASSIGN(SubmenuView);
224};
225
226}  // namespace views
227
228#endif  // UI_VIEWS_CONTROLS_MENU_SUBMENU_VIEW_H_
229