File: submenu_view.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (277 lines) | stat: -rw-r--r-- 10,455 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_CONTROLS_MENU_SUBMENU_VIEW_H_
#define UI_VIEWS_CONTROLS_MENU_SUBMENU_VIEW_H_

#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "ui/views/animation/scroll_animator.h"
#include "ui/views/controls/menu/menu_delegate.h"
#include "ui/views/controls/menu/menu_host.h"
#include "ui/views/controls/prefix_delegate.h"
#include "ui/views/controls/prefix_selector.h"
#include "ui/views/view.h"

namespace ui {
struct OwnedWindowAnchor;
}  // namespace ui

namespace views {

class MenuControllerTest;
class MenuItemView;
class MenuScrollViewContainer;

// SubmenuView is the parent of all menu items.
//
// SubmenuView has the following responsibilities:
// . It positions and sizes all child views (any type of View may be added,
//   not just MenuItemViews).
// . Forwards the appropriate events to the MenuController. This allows the
//   MenuController to update the selection as the user moves the mouse around.
// . Renders the drop indicator during a drop operation.
// . Shows and hides the window (a NativeWidget) when the menu is shown on
//   screen.
//
// SubmenuView is itself contained in a MenuScrollViewContainer.
// MenuScrollViewContainer handles showing as much of the SubmenuView as the
// screen allows. If the SubmenuView is taller than the screen, scroll buttons
// are provided that allow the user to see all the menu items.
class VIEWS_EXPORT SubmenuView : public View,
                                 public PrefixDelegate,
                                 public ScrollDelegate {
  METADATA_HEADER(SubmenuView, View)

 public:
  // Creates a SubmenuView for the specified menu item.
  explicit SubmenuView(MenuItemView* parent);

  SubmenuView(const SubmenuView&) = delete;
  SubmenuView& operator=(const SubmenuView&) = delete;

  ~SubmenuView() override;

  // Returns the children which are menu items.
  std::vector<MenuItemView*> GetMenuItems();
  std::vector<const MenuItemView*> GetMenuItems() const;

  // Returns the MenuItemView at the specified index.
  MenuItemView* GetMenuItemAt(size_t index);

  // The preferred height, in DIPs, of a "standard" (i.e. empty) menu item.
  int GetPreferredItemHeight() const;

  PrefixSelector* GetPrefixSelector();

  // Sets various menu metrics based on the current children. For example, this
  // reserves space for menu icons iff any children have icons.
  void UpdateMenuPartSizes();

  // Positions and sizes the child views. This tiles the views vertically,
  // giving each child the available width.
  void Layout(PassKey) override;

  // TODO(crbug.com/40232718): Respect `available_size`.
  gfx::Size CalculatePreferredSize(
      const SizeBounds& /*available_size*/) const override;

  // Painting.
  void PaintChildren(const PaintInfo& paint_info) override;

  // Drag and drop methods. These are forwarded to the MenuController.
  bool GetDropFormats(int* formats,
                      std::set<ui::ClipboardFormatType>* format_types) override;
  bool AreDropTypesRequired() override;
  bool CanDrop(const OSExchangeData& data) override;
  void OnDragEntered(const ui::DropTargetEvent& event) override;
  int OnDragUpdated(const ui::DropTargetEvent& event) override;
  void OnDragExited() override;
  views::View::DropCallback GetDropCallback(
      const ui::DropTargetEvent& event) override;

  // Scrolls on menu item boundaries.
  bool OnMouseWheel(const ui::MouseWheelEvent& e) override;

  // Overridden from ui::EventHandler.
  // Scrolls on menu item boundaries.
  void OnGestureEvent(ui::GestureEvent* event) override;

  // Overridden from PrefixDelegate.
  size_t GetRowCount() override;
  std::optional<size_t> GetSelectedRow() override;
  void SetSelectedRow(std::optional<size_t> row) override;
  std::u16string GetTextForRow(size_t row) override;

  // Returns true if the menu is showing.
  virtual bool IsShowing() const;

  // Shows the menu using the specified |init_params|. |init_params.bounds| are
  // in screen coordinates.
  void ShowAt(const MenuHost::InitParams& init_params);

  // Resets the bounds of the submenu to |bounds| and its anchor to |anchor|.
  void Reposition(const gfx::Rect& bounds, const ui::OwnedWindowAnchor& anchor);

  // Closes the menu, destroying the host.
  void Close();

  // Hides the hosting window.
  //
  // The hosting window is hidden first, then deleted (Close) when the menu is
  // done running. This is done to avoid deletion ordering dependencies. In
  // particular, during drag and drop (and when a modal dialog is shown as
  // a result of choosing a context menu) it is possible that an event is
  // being processed by the host, so that host is on the stack when we need to
  // close the window. If we closed the window immediately (and deleted it),
  // when control returned back to host we would crash as host was deleted.
  void Hide();

  // If mouse capture was grabbed, it is released. Does nothing if mouse was
  // not captured.
  void ReleaseCapture();

  // Overriden from View to prevent tab from doing anything.
  bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) override;

  // Returns the parent menu item we're showing children for.
  const MenuItemView* GetMenuItem() const;
  MenuItemView* GetMenuItem() {
    return const_cast<MenuItemView*>(std::as_const(*this).GetMenuItem());
  }

  // Set the drop item and position.
  void SetDropMenuItem(MenuItemView* item, MenuDelegate::DropPosition position);

  // Returns whether the selection should be shown for the specified item.
  // The selection is NOT shown during drag and drop when the drop is over
  // the menu.
  bool GetShowSelection(const MenuItemView* item) const;

  // Returns the container for the SubmenuView.
  MenuScrollViewContainer* GetScrollViewContainer();

  // Returns the last MenuItemView in this submenu.
  MenuItemView* GetLastItem();

  // Invoked if the menu is prematurely destroyed. This can happen if the window
  // closes while the menu is shown. If invoked the SubmenuView must drop all
  // references to the MenuHost as the MenuHost is about to be deleted.
  void MenuHostDestroyed();

  int icon_area_width() const { return icon_area_width_; }
  int min_icon_height() const { return min_icon_height_; }
  int label_start() const { return label_start_; }
  int trailing_padding() const { return trailing_padding_; }

  // Max width of minor text (accelerator or subtitle) in child menu items. This
  // doesn't include children's children, only direct children.
  int max_minor_text_width() const { return max_minor_text_width_; }

  // Minimum width of menu in pixels (default 0).  This becomes the smallest
  // width returned by GetPreferredSize().
  void set_minimum_preferred_width(int minimum_preferred_width) {
    minimum_preferred_width_ = minimum_preferred_width;
  }

  // Automatically resize menu if a subview's preferred size changes.
  bool resize_open_menu() const { return resize_open_menu_; }
  void set_resize_open_menu(bool resize_open_menu) {
    resize_open_menu_ = resize_open_menu;
  }
  MenuHost* host() { return host_; }
  const MenuHost* host() const { return host_; }

  void SetBorderColorId(std::optional<ui::ColorId> color_id);

 protected:
  // View method. Overridden to schedule a paint. We do this so that when
  // scrolling occurs, everything is repainted correctly.
  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;

  void ChildPreferredSizeChanged(View* child) override;

 private:
  friend class MenuControllerTest;

  void SchedulePaintForDropIndicator(MenuItemView* item,
                                     MenuDelegate::DropPosition position);

  // Calculates the location of th edrop indicator.
  gfx::Rect CalculateDropIndicatorBounds(MenuItemView* item,
                                         MenuDelegate::DropPosition position);

  // Implementation of ScrollDelegate
  bool OnScroll(float dx, float dy) override;

  // Parent menu item.
  raw_ptr<MenuItemView> parent_menu_item_;

  // Widget subclass used to show the children. This is deleted when we invoke
  // |DestroyMenuHost|, or |MenuHostDestroyed| is invoked back on us.
  raw_ptr<MenuHost> host_ = nullptr;

  // If non-null, indicates a drop is in progress and drop_item is the item
  // the drop is over.
  raw_ptr<MenuItemView> drop_item_ = nullptr;

  // Position of the drop.
  MenuDelegate::DropPosition drop_position_ = MenuDelegate::DropPosition::kNone;

  // Ancestor of the SubmenuView, lazily created.
  std::unique_ptr<MenuScrollViewContainer> scroll_view_container_;

  // Width of a menu icon area.
  int icon_area_width_ = 0;

  // The minimum height items should reserve for icons. If any item has icons,
  // checks, or radios, this is set to kMenuCheckSize, which is also the
  // common-case size for icons. This ensures that
  //   * When no items have icons etc., we don't add unnecessary padding.
  //   * When some items have icons, we make ~all items "the same size"; but --
  //   * If any items have especially large icons, we don't add _too_ much
  //     padding to every item.
  // In other words, this tries to "have roughly consistent height" without
  // incurring a lot of extra padding that makes the menu look spaced-out.
  int min_icon_height_ = 0;

  // X-coordinate of where the label starts.
  int label_start_ = 0;

  // The width of the padding after the minor text. If there is a dedicated
  // submenu arrow column, it fits inside this.
  int trailing_padding_ = 0;

  // See description above getter.
  mutable int max_minor_text_width_ = 0;

  // Minimum width returned in GetPreferredSize().
  int minimum_preferred_width_ = 0;

  // Reposition open menu when contained views change size.
  bool resize_open_menu_ = false;

  // The submenu's scroll animator
  std::unique_ptr<ScrollAnimator> scroll_animator_{
      std::make_unique<ScrollAnimator>(this)};

  // Difference between current position and cumulative deltas passed to
  // OnScroll.
  // TODO(tdresser): This should be removed when raw pixel scrolling for views
  // is enabled. See crbug.com/329354.
  float roundoff_error_ = 0;

  PrefixSelector prefix_selector_{this, this};

  std::optional<ui::ColorId> border_color_id_;
};

}  // namespace views

#endif  // UI_VIEWS_CONTROLS_MENU_SUBMENU_VIEW_H_