forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 1
/
combobox.h
301 lines (228 loc) · 10.9 KB
/
combobox.h
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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
// 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_COMBOBOX_COMBOBOX_H_
#define UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_H_
#include <memory>
#include <string>
#include <utility>
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/models/combobox_model_observer.h"
#include "ui/base/models/menu_model.h"
#include "ui/color/color_id.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/prefix_delegate.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/style/typography.h"
namespace gfx {
class FontList;
}
namespace ui {
class MenuModel;
}
namespace views {
namespace test {
class ComboboxTestApi;
class InteractionTestUtilSimulatorViews;
}
class MenuRunner;
class PrefixSelector;
// A non-editable combobox (aka a drop-down list or selector).
// Combobox has two distinct parts, the drop down arrow and the text.
class VIEWS_EXPORT Combobox : public View,
public PrefixDelegate,
public ui::ComboboxModelObserver {
METADATA_HEADER(Combobox, View)
public:
using MenuSelectionAtCallback = base::RepeatingCallback<bool(size_t index)>;
using MenuWillShowCallbackList = base::RepeatingClosureList;
using MenuWillShowCallback = MenuWillShowCallbackList::CallbackType;
static constexpr style::TextContext kContext = style::CONTEXT_BUTTON;
static constexpr style::TextStyle kStyle = style::STYLE_PRIMARY;
// A combobox with an empty model.
Combobox();
// |model| is owned by the combobox when using this constructor.
explicit Combobox(std::unique_ptr<ui::ComboboxModel> model);
// |model| is not owned by the combobox when using this constructor.
explicit Combobox(ui::ComboboxModel* model);
Combobox(const Combobox&) = delete;
Combobox& operator=(const Combobox&) = delete;
~Combobox() override;
const gfx::FontList& GetFontList() const;
// Sets the callback which will be called when a selection has been made.
void SetCallback(base::RepeatingClosure callback) {
callback_ = std::move(callback);
}
// Set menu model.
void SetMenuModel(std::unique_ptr<ui::MenuModel> menu_model) {
menu_model_ = std::move(menu_model);
}
// Gets/Sets the selected index.
std::optional<size_t> GetSelectedIndex() const { return selected_index_; }
void SetSelectedIndex(std::optional<size_t> index);
[[nodiscard]] base::CallbackListSubscription AddSelectedIndexChangedCallback(
views::PropertyChangedCallback callback);
// Called when there has been a selection from the menu.
void MenuSelectionAt(size_t index);
// Looks for the first occurrence of |value| in |model()|. If found, selects
// the found index and returns true. Otherwise simply noops and returns false.
bool SelectValue(const std::u16string& value);
void SetOwnedModel(std::unique_ptr<ui::ComboboxModel> model);
void SetModel(ui::ComboboxModel* model);
ui::ComboboxModel* GetModel() const { return model_; }
// Gets/Sets the tooltip text, and the accessible name if it is currently
// empty.
std::u16string GetTooltipTextAndAccessibleName() const;
void SetTooltipTextAndAccessibleName(const std::u16string& tooltip_text);
// Visually marks the combobox as having an invalid value selected.
// When invalid, it paints with white text on a red background.
// Callers are responsible for restoring validity with selection changes.
void SetInvalid(bool invalid);
bool GetInvalid() const { return invalid_; }
void SetBorderColorId(ui::ColorId color_id);
void SetBackgroundColorId(ui::ColorId color_id);
void SetForegroundColorId(ui::ColorId color_id);
void SetForegroundIconColorId(ui::ColorId color_id);
void SetForegroundTextStyle(style::TextStyle text_style);
// Sets whether there should be ink drop highlighting on hover/press.
void SetEventHighlighting(bool should_highlight);
// Whether the combobox should use the largest label as the content size.
void SetSizeToLargestLabel(bool size_to_largest_label);
bool GetSizeToLargestLabel() const { return size_to_largest_label_; }
void SetMenuSelectionAtCallback(MenuSelectionAtCallback callback) {
menu_selection_at_callback_ = std::move(callback);
}
base::CallbackListSubscription AddMenuWillShowCallback(
MenuWillShowCallback callback);
// Set whether the arrow should be shown to the user.
void SetShouldShowArrow(bool should_show_arrow) {
should_show_arrow_ = should_show_arrow;
}
// Use the time when combobox was closed in order for parent view to not
// treat a user event already treated by the combobox.
base::TimeTicks GetClosedTime() { return closed_time_; }
// Returns whether or not the menu is currently running.
bool IsMenuRunning() const;
// Overridden from View:
gfx::Size CalculatePreferredSize() const override;
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) override;
bool OnKeyPressed(const ui::KeyEvent& e) override;
void OnPaint(gfx::Canvas* canvas) override;
void OnFocus() override;
void OnBlur() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
void OnThemeChanged() 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;
protected:
// Overridden from ComboboxModelObserver:
void OnComboboxModelChanged(ui::ComboboxModel* model) override;
void OnComboboxModelDestroying(ui::ComboboxModel* model) override;
// Getters to be used by metadata.
const base::RepeatingClosure& GetCallback() const;
const std::unique_ptr<ui::ComboboxModel>& GetOwnedModel() const;
private:
friend class test::ComboboxTestApi;
friend class test::InteractionTestUtilSimulatorViews;
// Updates the border according to the current node_data.
void UpdateBorder();
// Given bounds within our View, this helper mirrors the bounds if necessary.
void AdjustBoundsForRTLUI(gfx::Rect* rect) const;
// Draws the selected value of the drop down list
void PaintIconAndText(gfx::Canvas* canvas);
// Opens the dropdown menu in response to |event|.
void ArrowButtonPressed(const ui::Event& event);
// Show the drop down list
void ShowDropDownMenu(ui::MenuSourceType source_type);
// Cleans up after the menu as closed
void OnMenuClosed(Button::ButtonState original_button_state);
// Called when the selection is changed by the user.
void OnPerformAction();
// Finds the size of the largest menu label.
gfx::Size GetContentSize() const;
// Returns the width needed to accommodate the provided width and checkmarks
// and padding if checkmarks should be shown.
int MaybeAdjustWidthForCheckmarks(int original_width) const;
void OnContentSizeMaybeChanged();
PrefixSelector* GetPrefixSelector();
const gfx::FontList& GetForegroundFontList() const;
// Optionally used to tie the lifetime of the model to this combobox. See
// constructor.
std::unique_ptr<ui::ComboboxModel> owned_model_;
// Reference to our model, which may be owned or not.
raw_ptr<ui::ComboboxModel> model_ = nullptr;
// Callback notified when the selected index changes.
base::RepeatingClosure callback_;
// Callback notified when the selected index is triggered to change. If set,
// when a selection is made in the combobox this callback is called. If it
// returns true no other action is taken, if it returns false then the model
// will updated based on the selection.
MenuSelectionAtCallback menu_selection_at_callback_;
// Callbacks notified when the dropdown menu is about to show.
MenuWillShowCallbackList on_menu_will_show_;
// The current selected index; nullopt means no selection.
std::optional<size_t> selected_index_ = std::nullopt;
// True when the selection is visually denoted as invalid.
bool invalid_ = false;
// True when there should be ink drop highlighting on hover and press.
bool should_highlight_ = false;
// True when the combobox should display the arrow during paint.
bool should_show_arrow_ = true;
// Overriding ColorId for the combobox border.
std::optional<ui::ColorId> border_color_id_;
// Overriding ColorId for the combobox foreground (text and caret icon).
std::optional<ui::ColorId> foreground_color_id_;
// Attempts to override the color for the combobox foreground icon.
std::optional<ui::ColorId> foreground_icon_color_id_;
std::optional<style::TextStyle> foreground_text_style_;
// A helper used to select entries by keyboard input.
std::unique_ptr<PrefixSelector> selector_;
// The ComboboxModel for use by |menu_runner_|.
std::unique_ptr<ui::MenuModel> menu_model_;
// Like MenuButton, we use a time object in order to keep track of when the
// combobox was closed. The time is used for simulating menu behavior; that
// is, if the menu is shown and the button is pressed, we need to close the
// menu. There is no clean way to get the second click event because the
// menu is displayed using a modal loop and, unlike regular menus in Windows,
// the button is not part of the displayed menu.
base::TimeTicks closed_time_;
// The maximum dimensions of the content in the dropdown.
gfx::Size content_size_;
// A transparent button that handles events and holds button state. Placed on
// top of the combobox as a child view. Doesn't paint itself, but serves as a
// host for inkdrops.
raw_ptr<Button> arrow_button_;
// Set while the dropdown is showing. Ensures the menu is closed if |this| is
// destroyed.
std::unique_ptr<MenuRunner> menu_runner_;
// Called to update background color and border when the combobox is
// enabled/disabled.
base::CallbackListSubscription enabled_changed_subscription_;
// When true, the size of contents is defined by the widest label in the menu.
// If this is set to true, the parent view must relayout in
// ChildPreferredSizeChanged(). When false, the size of contents is defined by
// the selected label
bool size_to_largest_label_ = true;
base::ScopedObservation<ui::ComboboxModel, ui::ComboboxModelObserver>
observation_{this};
};
BEGIN_VIEW_BUILDER(VIEWS_EXPORT, Combobox, View)
VIEW_BUILDER_PROPERTY(base::RepeatingClosure, Callback)
VIEW_BUILDER_PROPERTY(std::unique_ptr<ui::ComboboxModel>, OwnedModel)
VIEW_BUILDER_PROPERTY(ui::ComboboxModel*, Model)
VIEW_BUILDER_PROPERTY(std::optional<size_t>, SelectedIndex)
VIEW_BUILDER_PROPERTY(bool, Invalid)
VIEW_BUILDER_PROPERTY(bool, SizeToLargestLabel)
VIEW_BUILDER_PROPERTY(std::u16string, TooltipTextAndAccessibleName)
END_VIEW_BUILDER
} // namespace views
DEFINE_VIEW_BUILDER(VIEWS_EXPORT, Combobox)
#endif // UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_H_