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 17 namespace views { 18 19 class MenuHost; 20 class MenuItemView; 21 class 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. 38 class 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. max_minor_text_width()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(). set_minimum_preferred_width(int minimum_preferred_width)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. resize_open_menu()154 bool resize_open_menu() const { return resize_open_menu_; } set_resize_open_menu(bool 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