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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
#define UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
#include <memory>
#include "base/bind.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/animation/animation_delegate_views.h"
#include "ui/views/animation/ink_drop_host_view.h"
#include "ui/views/animation/ink_drop_state.h"
#include "ui/views/controls/button/button_controller_delegate.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/painter.h"
#include "ui/views/widget/widget_observer.h"
namespace views {
namespace test {
class ButtonTestApi;
}
class Button;
class ButtonController;
class ButtonObserver;
class Event;
// An interface implemented by an object to let it know that a button was
// pressed.
class VIEWS_EXPORT ButtonListener {
public:
virtual void ButtonPressed(Button* sender, const ui::Event& event) = 0;
protected:
virtual ~ButtonListener() = default;
};
// A View representing a button. A Button is not focusable by default and will
// not be part of the focus chain, unless in accessibility mode (see
// SetFocusForPlatform()).
class VIEWS_EXPORT Button : public InkDropHostView,
public AnimationDelegateViews {
public:
METADATA_HEADER(Button);
~Button() override;
// Button states for various button sub-types.
enum ButtonState {
STATE_NORMAL = 0,
STATE_HOVERED,
STATE_PRESSED,
STATE_DISABLED,
STATE_COUNT,
};
static constexpr ButtonState kButtonStates[STATE_COUNT] = {
ButtonState::STATE_NORMAL, ButtonState::STATE_HOVERED,
ButtonState::STATE_PRESSED, ButtonState::STATE_DISABLED};
// An enum describing the events on which a button should be clicked for a
// given key event.
enum class KeyClickAction {
kOnKeyPress,
kOnKeyRelease,
kNone,
};
// TODO(cyan): Consider having Button implement ButtonControllerDelegate.
class VIEWS_EXPORT DefaultButtonControllerDelegate
: public ButtonControllerDelegate {
public:
explicit DefaultButtonControllerDelegate(Button* button);
~DefaultButtonControllerDelegate() override;
// views::ButtonControllerDelegate:
void RequestFocusFromEvent() override;
void NotifyClick(const ui::Event& event) override;
void OnClickCanceled(const ui::Event& event) override;
bool IsTriggerableEvent(const ui::Event& event) override;
bool ShouldEnterPushedState(const ui::Event& event) override;
bool ShouldEnterHoveredState() override;
InkDrop* GetInkDrop() override;
int GetDragOperations(const gfx::Point& press_pt) override;
bool InDrag() override;
private:
DISALLOW_COPY_AND_ASSIGN(DefaultButtonControllerDelegate);
};
static const Button* AsButton(const View* view);
static Button* AsButton(View* view);
static ButtonState GetButtonStateFrom(ui::NativeTheme::State state);
// Make the button focusable as per the platform.
void SetFocusForPlatform();
void SetTooltipText(const base::string16& tooltip_text);
int tag() const { return tag_; }
void set_tag(int tag) { tag_ = tag; }
void SetAccessibleName(const base::string16& name);
const base::string16& GetAccessibleName() const;
// Get/sets the current display state of the button.
ButtonState state() const { return state_; }
// Clients passing in STATE_DISABLED should consider calling
// SetEnabled(false) instead because the enabled flag can affect other things
// like event dispatching, focus traversals, etc. Calling SetEnabled(false)
// will also set the state of |this| to STATE_DISABLED.
void SetState(ButtonState state);
// Returns the visual appearance state of the button. This takes into account
// both the button's display state and the state of the containing widget.
ButtonState GetVisualState() const;
// Starts throbbing. See HoverAnimation for a description of cycles_til_stop.
// This method does nothing if |animate_on_state_change_| is false.
void StartThrobbing(int cycles_til_stop);
// Stops throbbing immediately.
void StopThrobbing();
// Set how long the hover animation will last for.
void SetAnimationDuration(base::TimeDelta duration);
void set_triggerable_event_flags(int triggerable_event_flags) {
triggerable_event_flags_ = triggerable_event_flags;
}
int triggerable_event_flags() const { return triggerable_event_flags_; }
// Sets whether |RequestFocus| should be invoked on a mouse press. The default
// is false.
void set_request_focus_on_press(bool value) {
// On Mac, buttons should not request focus on a mouse press. Hence keep the
// default value i.e. false.
#if !defined(OS_MACOSX)
request_focus_on_press_ = value;
#endif
}
bool request_focus_on_press() const { return request_focus_on_press_; }
// See description above field.
void set_animate_on_state_change(bool value) {
animate_on_state_change_ = value;
}
bool hide_ink_drop_when_showing_context_menu() const {
return hide_ink_drop_when_showing_context_menu_;
}
void set_hide_ink_drop_when_showing_context_menu(
bool hide_ink_drop_when_showing_context_menu) {
hide_ink_drop_when_showing_context_menu_ =
hide_ink_drop_when_showing_context_menu;
}
void set_show_ink_drop_when_hot_tracked(bool show_ink_drop_when_hot_tracked) {
show_ink_drop_when_hot_tracked_ = show_ink_drop_when_hot_tracked;
}
void set_ink_drop_base_color(SkColor color) { ink_drop_base_color_ = color; }
void set_has_ink_drop_action_on_click(bool has_ink_drop_action_on_click) {
has_ink_drop_action_on_click_ = has_ink_drop_action_on_click;
}
void SetInstallFocusRingOnFocus(bool install_focus_ring_on_focus);
void SetHotTracked(bool is_hot_tracked);
bool IsHotTracked() const;
void SetFocusPainter(std::unique_ptr<Painter> focus_painter);
// Highlights the ink drop for the button.
void SetHighlighted(bool bubble_visible);
void AddButtonObserver(ButtonObserver* observer);
void RemoveButtonObserver(ButtonObserver* observer);
// Overridden from View:
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
void OnMouseCaptureLost() override;
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
void OnMouseMoved(const ui::MouseEvent& event) override;
bool OnKeyPressed(const ui::KeyEvent& event) override;
bool OnKeyReleased(const ui::KeyEvent& event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
base::string16 GetTooltipText(const gfx::Point& p) const override;
void ShowContextMenu(const gfx::Point& p,
ui::MenuSourceType source_type) override;
void OnDragDone() override;
// Instead of overriding this, subclasses that want custom painting should use
// PaintButtonContents.
void OnPaint(gfx::Canvas* canvas) final;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
void VisibilityChanged(View* starting_from, bool is_visible) override;
void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) override;
void OnFocus() override;
void OnBlur() override;
void AddedToWidget() override;
void RemovedFromWidget() override;
// Overridden from InkDropHostView:
std::unique_ptr<InkDrop> CreateInkDrop() override;
SkColor GetInkDropBaseColor() const override;
// Overridden from views::AnimationDelegateViews:
void AnimationProgressed(const gfx::Animation* animation) override;
// Returns the click action for the given key event.
// Subclasses may override this method to support default actions for key
// events.
// TODO(cyan): Move this into the ButtonController.
virtual KeyClickAction GetKeyClickActionForEvent(const ui::KeyEvent& event);
ButtonController* button_controller() const {
return button_controller_.get();
}
void SetButtonController(std::unique_ptr<ButtonController> button_controller);
gfx::Point GetMenuPosition() const;
protected:
// Construct the Button with a Listener. The listener can be null. This can be
// true of buttons that don't have a listener - e.g. menubuttons where there's
// no default action and checkboxes.
explicit Button(ButtonListener* listener);
// Called when the button has been clicked or tapped and should request focus
// if necessary.
virtual void RequestFocusFromEvent();
// Cause the button to notify the listener that a click occurred.
virtual void NotifyClick(const ui::Event& event);
// Called when a button gets released without triggering an action.
// Note: This is only wired up for mouse button events and not gesture
// events.
virtual void OnClickCanceled(const ui::Event& event);
// Called when the tooltip is set.
virtual void OnSetTooltipText(const base::string16& tooltip_text);
// Invoked from SetState() when SetState() is passed a value that differs from
// the current node_data. Button's implementation of StateChanged() does
// nothing; this method is provided for subclasses that wish to do something
// on state changes.
virtual void StateChanged(ButtonState old_state);
// Returns true if the event is one that can trigger notifying the listener.
// This implementation returns true if the left mouse button is down.
// TODO(cyan): Remove this method and move the implementation into
// ButtonController.
virtual bool IsTriggerableEvent(const ui::Event& event);
// Returns true if the ink drop should be updated by Button when
// OnClickCanceled() is called. This method is provided for subclasses.
// If the method is overriden and returns false, the subclass is responsible
// will be responsible for updating the ink drop.
virtual bool ShouldUpdateInkDropOnClickCanceled() const;
// Returns true if the button should become pressed when the user
// holds the mouse down over the button. For this implementation,
// we simply return IsTriggerableEvent(event).
virtual bool ShouldEnterPushedState(const ui::Event& event);
// Override to paint custom button contents. Any background or border set on
// the view will be painted before this is called and |focus_painter_| will be
// painted afterwards.
virtual void PaintButtonContents(gfx::Canvas* canvas);
// Returns true if the button should enter hovered state; that is, if the
// mouse is over the button, and no other window has capture (which would
// prevent the button from receiving MouseExited events and updating its
// node_data). This does not take into account enabled node_data.
bool ShouldEnterHoveredState();
const gfx::ThrobAnimation& hover_animation() const {
return hover_animation_;
}
FocusRing* focus_ring() { return focus_ring_.get(); }
// The button's listener. Notified when clicked.
ButtonListener* listener_;
private:
friend class test::ButtonTestApi;
FRIEND_TEST_ALL_PREFIXES(BlueButtonTest, Border);
// Bridge class to allow Button to observe a Widget without being a
// WidgetObserver. This is desirable because many Button subclasses are
// themselves WidgetObservers, and if Button is a WidgetObserver, any change
// to its WidgetObserver overrides requires updating all the subclasses as
// well.
class WidgetObserverButtonBridge : public WidgetObserver {
public:
explicit WidgetObserverButtonBridge(Button* owner);
~WidgetObserverButtonBridge() override;
// WidgetObserver:
void OnWidgetPaintAsActiveChanged(Widget* widget,
bool paint_as_active) override;
void OnWidgetDestroying(Widget* widget) override;
private:
Button* owner_;
DISALLOW_COPY_AND_ASSIGN(WidgetObserverButtonBridge);
};
void OnEnabledChanged();
void WidgetPaintAsActiveChanged(Widget* widget, bool active);
// The text shown in a tooltip.
base::string16 tooltip_text_;
// Accessibility data.
base::string16 accessible_name_;
// The id tag associated with this button. Used to disambiguate buttons in
// the ButtonListener implementation.
int tag_ = -1;
ButtonState state_ = STATE_NORMAL;
gfx::ThrobAnimation hover_animation_{this};
// Should we animate when the state changes?
bool animate_on_state_change_ = false;
// Is the hover animation running because StartThrob was invoked?
bool is_throbbing_ = false;
// Mouse event flags which can trigger button actions.
int triggerable_event_flags_ = ui::EF_LEFT_MOUSE_BUTTON;
// See description above setter.
bool request_focus_on_press_ = false;
// True when a button click should trigger an animation action on
// ink_drop_delegate().
bool has_ink_drop_action_on_click_ = false;
// When true, the ink drop ripple and hover will be hidden prior to showing
// the context menu.
bool hide_ink_drop_when_showing_context_menu_ = true;
// When true, the ink drop ripple will be shown when setting state to hot
// tracked with SetHotTracked().
bool show_ink_drop_when_hot_tracked_ = false;
// The color of the ripple and hover.
SkColor ink_drop_base_color_;
// The focus ring for this Button.
std::unique_ptr<FocusRing> focus_ring_;
std::unique_ptr<Painter> focus_painter_;
std::unique_ptr<WidgetObserverButtonBridge> widget_observer_;
// ButtonController is responsible for handling events sent to the Button and
// related state changes from the events.
// TODO(cyan): Make sure all state changes are handled within
// ButtonController.
std::unique_ptr<ButtonController> button_controller_;
PropertyChangedSubscription enabled_changed_subscription_{
AddEnabledChangedCallback(base::BindRepeating(&Button::OnEnabledChanged,
base::Unretained(this)))};
base::ObserverList<ButtonObserver> button_observers_;
DISALLOW_COPY_AND_ASSIGN(Button);
};
} // namespace views
#endif // UI_VIEWS_CONTROLS_BUTTON_BUTTON_H_
|