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.
5 #ifndef UI_VIEWS_CONTROLS_MENU_MENU_ITEM_VIEW_H_
6 #define UI_VIEWS_CONTROLS_MENU_MENU_ITEM_VIEW_H_
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/strings/string16.h"
14 #include "build/build_config.h"
15 #include "ui/base/models/menu_separator_types.h"
16 #include "ui/gfx/image/image_skia.h"
17 #include "ui/views/controls/menu/menu_config.h"
18 #include "ui/views/view.h"
23 #include "ui/native_theme/native_theme.h"
40 // MenuItemView --------------------------------------------------------------
42 // MenuItemView represents a single menu item with a label and optional icon.
43 // Each MenuItemView may also contain a submenu, which in turn may contain
44 // any number of child MenuItemViews.
46 // To use a menu create an initial MenuItemView using the constructor that
47 // takes a MenuDelegate, then create any number of child menu items by way
48 // of the various AddXXX methods.
50 // MenuItemView is itself a View, which means you can add Views to each
51 // MenuItemView. This is normally NOT want you want, rather add other child
52 // Views to the submenu of the MenuItemView. Any child views of the MenuItemView
53 // that are focusable can be navigated to by way of the up/down arrow and can be
54 // activated by way of space/return keys. Activating a focusable child results
55 // in |AcceleratorPressed| being invoked. Note, that as menus try not to steal
56 // focus from the hosting window child views do not actually get focus. Instead
57 // |SetHotTracked| is used as the user navigates around.
59 // To show the menu use MenuRunner. See MenuRunner for details on how to run
60 // (show) the menu as well as for details on the life time of the menu.
62 class VIEWS_EXPORT MenuItemView : public View {
64 friend class MenuController;
66 // The menu item view's class name.
67 static const char kViewClassName[];
69 // ID used to identify menu items.
70 static const int kMenuItemViewID;
72 // ID used to identify empty menu items.
73 static const int kEmptyMenuItemViewID;
75 // Different types of menu items. EMPTY is a special type for empty
76 // menus that is only used internally.
86 // Where the menu should be anchored to for non-RTL languages. The
87 // opposite position will be used if base::i18n:IsRTL() is true.
88 // The BUBBLE flags are used when the menu should get enclosed by a bubble.
89 // Note that BUBBLE flags should only be used with menus which have no
101 // Where the menu should be drawn, above or below the bounds (when
102 // the bounds is non-empty). POSITION_BEST_FIT (default) positions
103 // the menu below the bounds unless the menu does not fit on the
104 // screen and the re is more space above.
107 POSITION_ABOVE_BOUNDS,
108 POSITION_BELOW_BOUNDS
111 // The data structure which is used for the menu size
112 struct MenuItemDimensions {
119 // Width of everything except the accelerator and children views.
121 // The width of all contained views of the item.
123 // The amount of space needed to accommodate the subtext.
124 int minor_text_width;
125 // The height of the menu item.
129 // Constructor for use with the top level menu item. This menu is never
130 // shown to the user, rather its use as the parent for all menu items.
131 explicit MenuItemView(MenuDelegate* delegate);
133 // Overridden from View:
134 virtual bool GetTooltipText(const gfx::Point& p,
135 base::string16* tooltip) const OVERRIDE;
136 virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
138 // Returns the preferred height of menu items. This is only valid when the
139 // menu is about to be shown.
140 static int pref_menu_height() { return pref_menu_height_; }
142 // X-coordinate of where the label starts.
143 static int label_start() { return label_start_; }
145 // Returns if a given |anchor| is a bubble or not.
146 static bool IsBubble(MenuItemView::AnchorPosition anchor);
148 // Returns the accessible name to be used with screen readers. Mnemonics are
149 // removed and the menu item accelerator text is appended.
150 static base::string16 GetAccessibleNameForMenuItem(
151 const base::string16& item_text, const base::string16& accelerator_text);
153 // Hides and cancels the menu. This does nothing if the menu is not open.
156 // Add an item to the menu at a specified index. ChildrenChanged() should
157 // called after adding menu items if the menu may be active.
158 MenuItemView* AddMenuItemAt(int index,
160 const base::string16& label,
161 const base::string16& sublabel,
162 const base::string16& minor_text,
163 const gfx::ImageSkia& icon,
165 ui::MenuSeparatorType separator_style);
167 // Remove an item from the menu at a specified index. The removed MenuItemView
168 // is deleted when ChildrenChanged() is invoked.
169 void RemoveMenuItemAt(int index);
171 // Appends an item to this menu.
172 // item_id The id of the item, used to identify it in delegate callbacks
173 // or (if delegate is NULL) to identify the command associated
174 // with this item with the controller specified in the ctor. Note
175 // that this value should not be 0 as this has a special meaning
176 // ("NULL command, no item selected")
177 // label The text label shown.
178 // type The type of item.
179 MenuItemView* AppendMenuItem(int item_id,
180 const base::string16& label,
183 // Append a submenu to this menu.
184 // The returned pointer is owned by this menu.
185 MenuItemView* AppendSubMenu(int item_id,
186 const base::string16& label);
188 // Append a submenu with an icon to this menu.
189 // The returned pointer is owned by this menu.
190 MenuItemView* AppendSubMenuWithIcon(int item_id,
191 const base::string16& label,
192 const gfx::ImageSkia& icon);
194 // This is a convenience for standard text label menu items where the label
195 // is provided with this call.
196 MenuItemView* AppendMenuItemWithLabel(int item_id,
197 const base::string16& label);
199 // This is a convenience for text label menu items where the label is
200 // provided by the delegate.
201 MenuItemView* AppendDelegateMenuItem(int item_id);
203 // Adds a separator to this menu
204 void AppendSeparator();
206 // Appends a menu item with an icon. This is for the menu item which
207 // needs an icon. Calling this function forces the Menu class to draw
208 // the menu, instead of relying on Windows.
209 MenuItemView* AppendMenuItemWithIcon(int item_id,
210 const base::string16& label,
211 const gfx::ImageSkia& icon);
213 // All the AppendXXX methods funnel into this.
214 MenuItemView* AppendMenuItemImpl(int item_id,
215 const base::string16& label,
216 const base::string16& sublabel,
217 const base::string16& minor_text,
218 const gfx::ImageSkia& icon,
220 ui::MenuSeparatorType separator_style);
222 // Returns the view that contains child menu items. If the submenu has
223 // not been creates, this creates it.
224 virtual SubmenuView* CreateSubmenu();
226 // Returns true if this menu item has a submenu.
227 virtual bool HasSubmenu() const;
229 // Returns the view containing child menu items.
230 virtual SubmenuView* GetSubmenu() const;
232 // Returns the parent menu item.
233 MenuItemView* GetParentMenuItem() { return parent_menu_item_; }
234 const MenuItemView* GetParentMenuItem() const { return parent_menu_item_; }
236 // Sets/Gets the title.
237 void SetTitle(const base::string16& title);
238 const base::string16& title() const { return title_; }
240 // Sets the subtitle.
241 void SetSubtitle(const base::string16& subtitle);
243 // Sets the minor text.
244 void SetMinorText(const base::string16& minor_text);
246 // Returns the type of this menu.
247 const Type& GetType() const { return type_; }
249 // Sets whether this item is selected. This is invoked as the user moves
250 // the mouse around the menu while open.
251 void SetSelected(bool selected);
253 // Returns true if the item is selected.
254 bool IsSelected() const { return selected_; }
256 // Sets the |tooltip| for a menu item view with |item_id| identifier.
257 void SetTooltip(const base::string16& tooltip, int item_id);
259 // Sets the icon for the descendant identified by item_id.
260 void SetIcon(const gfx::ImageSkia& icon, int item_id);
262 // Sets the icon of this menu item.
263 void SetIcon(const gfx::ImageSkia& icon);
265 // Sets the view used to render the icon. This clobbers any icon set via
266 // SetIcon(). MenuItemView takes ownership of |icon_view|.
267 void SetIconView(View* icon_view);
268 View* icon_view() { return icon_view_; }
270 // Sets the command id of this menu item.
271 void SetCommand(int command) { command_ = command; }
273 // Returns the command id of this item.
274 int GetCommand() const { return command_; }
276 // Paints the menu item.
277 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
279 // Returns the preferred size of this item.
280 virtual gfx::Size GetPreferredSize() OVERRIDE;
282 // Return the preferred dimensions of the item in pixel.
283 const MenuItemDimensions& GetDimensions();
285 // Returns the object responsible for controlling showing the menu.
286 MenuController* GetMenuController();
287 const MenuController* GetMenuController() const;
289 // Returns the delegate. This returns the delegate of the root menu item.
290 MenuDelegate* GetDelegate();
291 const MenuDelegate* GetDelegate() const;
292 void set_delegate(MenuDelegate* delegate) { delegate_ = delegate; }
294 // Returns the root parent, or this if this has no parent.
295 MenuItemView* GetRootMenuItem();
296 const MenuItemView* GetRootMenuItem() const;
298 // Returns the mnemonic for this MenuItemView, or 0 if this MenuItemView
299 // doesn't have a mnemonic.
300 base::char16 GetMnemonic();
302 // Do we have icons? This only has effect on the top menu. Turning this on
303 // makes the menus slightly wider and taller.
304 void set_has_icons(bool has_icons) {
305 has_icons_ = has_icons;
307 bool has_icons() const { return has_icons_; }
309 // Returns the descendant with the specified command.
310 MenuItemView* GetMenuItemByID(int id);
312 // Invoke if you remove/add children to the menu while it's showing. This
313 // recalculates the bounds.
314 void ChildrenChanged();
316 // Sizes any child views.
317 virtual void Layout() OVERRIDE;
319 // Returns true if the menu has mnemonics. This only useful on the root menu
321 bool has_mnemonics() const { return has_mnemonics_; }
323 // Set top and bottom margins in pixels. If no margin is set or a
324 // negative margin is specified then MenuConfig values are used.
325 void SetMargins(int top_margin, int bottom_margin);
327 // Suppress the right margin if this is set to false.
328 void set_use_right_margin(bool use_right_margin) {
329 use_right_margin_ = use_right_margin;
332 // Returns a reference to MenuConfig to be used with this menu.
333 const MenuConfig& GetMenuConfig() const;
336 // Creates a MenuItemView. This is used by the various AddXXX methods.
337 MenuItemView(MenuItemView* parent, int command, Type type);
339 // MenuRunner owns MenuItemView and should be the only one deleting it.
340 virtual ~MenuItemView();
342 virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
344 virtual const char* GetClassName() const OVERRIDE;
346 // Returns the preferred size (and padding) of any children.
347 virtual gfx::Size GetChildPreferredSize();
349 // Returns the various margins.
351 int GetBottomMargin();
354 friend class internal::MenuRunnerImpl; // For access to ~MenuItemView.
356 enum PaintButtonMode { PB_NORMAL, PB_FOR_DRAG };
358 // Calculates all sizes that we can from the OS.
360 // This is invoked prior to Running a menu.
361 void UpdateMenuPartSizes();
363 // Called by the two constructors to initialize this menu item.
364 void Init(MenuItemView* parent,
366 MenuItemView::Type type,
367 MenuDelegate* delegate);
369 // The RunXXX methods call into this to set up the necessary state before
370 // running. |is_first_menu| is true if no menus are currently showing.
371 void PrepareForRun(bool is_first_menu,
373 bool show_mnemonics);
375 // Returns the flags passed to DrawStringRect.
376 int GetDrawStringFlags();
378 // Returns the font list to use for menu text.
379 const gfx::FontList& GetFontList();
381 // If this menu item has no children a child is added showing it has no
382 // children. Otherwise AddEmtpyMenus is recursively invoked on child menu
383 // items that have children.
384 void AddEmptyMenus();
386 // Undoes the work of AddEmptyMenus.
387 void RemoveEmptyMenus();
389 // Given bounds within our View, this helper routine mirrors the bounds if
391 void AdjustBoundsForRTLUI(gfx::Rect* rect) const;
393 // Actual paint implementation. If mode is PB_FOR_DRAG, portions of the menu
395 void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
397 // Paints the right-side text.
398 void PaintMinorText(gfx::Canvas* canvas, bool render_selection);
400 // Destroys the window used to display this menu and recursively destroys
401 // the windows used to display all descendants.
402 void DestroyAllMenuHosts();
404 // Returns the text that should be displayed on the end (right) of the menu
405 // item. This will be the accelerator (if one exists), otherwise |subtitle_|.
406 base::string16 GetMinorText();
408 // Calculates and returns the MenuItemDimensions.
409 MenuItemDimensions CalculateDimensions();
411 // Get the horizontal position at which to draw the menu item's label.
412 int GetLabelStartForThisItem();
414 // Used by MenuController to cache the menu position in use by the
416 MenuPosition actual_menu_position() const { return actual_menu_position_; }
417 void set_actual_menu_position(MenuPosition actual_menu_position) {
418 actual_menu_position_ = actual_menu_position;
421 void set_controller(MenuController* controller) { controller_ = controller; }
423 // Returns true if this MenuItemView contains a single child
424 // that is responsible for rendering the content.
425 bool IsContainer() const;
427 // Returns number of child views excluding icon_view.
428 int NonIconChildViewsCount() const;
430 // Returns the max icon width; recurses over submenus.
431 int GetMaxIconViewWidth() const;
433 // Returns true if the menu has items with a checkbox or a radio button.
434 bool HasChecksOrRadioButtons() const;
436 void invalidate_dimensions() { dimensions_.height = 0; }
437 bool is_dimensions_valid() const { return dimensions_.height > 0; }
439 // The delegate. This is only valid for the root menu item. You shouldn't
440 // use this directly, instead use GetDelegate() which walks the tree as
442 MenuDelegate* delegate_;
444 // The controller for the run operation, or NULL if the menu isn't showing.
445 MenuController* controller_;
447 // Used to detect when Cancel was invoked.
451 MenuItemView* parent_menu_item_;
453 // Type of menu. NOTE: MenuItemView doesn't itself represent SEPARATOR,
454 // that is handled by an entirely different view class.
457 // Whether we're selected.
463 // Submenu, created via CreateSubmenu.
464 SubmenuView* submenu_;
467 base::string16 title_;
469 // Subtitle/sublabel.
470 base::string16 subtitle_;
473 base::string16 minor_text_;
475 // Does the title have a mnemonic? Only useful on the root menu item.
478 // Should we show the mnemonic? Mnemonics are shown if this is true or
479 // MenuConfig says mnemonics should be shown. Only used on the root menu item.
480 bool show_mnemonics_;
482 // Set if menu has icons or icon_views (applies to root menu item only).
485 // Pointer to a view with a menu icon.
488 // The tooltip to show on hover for this menu item.
489 base::string16 tooltip_;
491 // Width of a menu icon area.
492 static int icon_area_width_;
494 // X-coordinate of where the label starts.
495 static int label_start_;
497 // Margins between the right of the item and the label.
498 static int item_right_margin_;
500 // Preferred height of menu items. Reset every time a menu is run.
501 static int pref_menu_height_;
503 // Cached dimensions. This is cached as text sizing calculations are quite
505 MenuItemDimensions dimensions_;
507 // Removed items to be deleted in ChildrenChanged().
508 std::vector<View*> removed_items_;
510 // Margins in pixels.
514 // Horizontal icon margins in pixels, which can differ between MenuItems.
515 // These values will be set in the layout process.
516 int left_icon_margin_;
517 int right_icon_margin_;
519 // |menu_position_| is the requested position with respect to the bounds.
520 // |actual_menu_position_| is used by the controller to cache the
521 // position of the menu being shown.
522 MenuPosition requested_menu_position_;
523 MenuPosition actual_menu_position_;
525 // If set to false, the right margin will be removed for menu lines
526 // containing other elements.
527 bool use_right_margin_;
529 DISALLOW_COPY_AND_ASSIGN(MenuItemView);
534 #endif // UI_VIEWS_CONTROLS_MENU_MENU_ITEM_VIEW_H_