summaryrefslogtreecommitdiff
path: root/chromium/ui/views/animation/ink_drop_impl.h
blob: 82061d7e778f1d7fcff45599e86deae59e064541 (plain)
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
// Copyright 2015 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_ANIMATION_INK_DROP_IMPL_H_
#define UI_VIEWS_ANIMATION_INK_DROP_IMPL_H_

#include <memory>

#include "base/macros.h"
#include "base/optional.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/animation/ink_drop_highlight_observer.h"
#include "ui/views/animation/ink_drop_ripple_observer.h"
#include "ui/views/views_export.h"

namespace views {
namespace test {
class InkDropImplTestApi;
}  // namespace test

class InkDropRipple;
class InkDropHostView;
class InkDropHighlight;

// A functional implementation of an InkDrop.
class VIEWS_EXPORT InkDropImpl : public InkDrop,
                                 public InkDropRippleObserver,
                                 public InkDropHighlightObserver {
 public:
  // The different auto highlight behaviors.
  enum class AutoHighlightMode {
    // No auto-highlighting is done. The highlight will only be shown/hidden as
    // per the hover/focus settings.
    NONE,
    // The highlight will be hidden when a ripple becomes visible. After the
    // ripple is hidden the highlight will be made visible again if the
    // hover/focus settings deem it should be.
    HIDE_ON_RIPPLE,
    // The highlight is made visible when the ripple becomes visible. After the
    // ripple is hidden the highlight will be hidden again if the hover/focus
    // settings deem it should be.
    SHOW_ON_RIPPLE,
  };

  // Constructs an ink drop that will attach the ink drop to the given
  // |ink_drop_host|. |host_size| is used to set the size of the ink drop layer.
  //
  // By default the highlight will be made visible while |this| is hovered but
  // not focused and the NONE AutoHighlightMode will be used.
  InkDropImpl(InkDropHostView* ink_drop_host, const gfx::Size& host_size);
  ~InkDropImpl() override;

  // Auto highlighting is a mechanism to show/hide the highlight based on the
  // visibility of the ripple. See the documentation of the AutoHighlightMode
  // for more info on the different modes.
  //
  // This method is intended as a configuration option to be used after
  // construction. Behavior is undefined if |this| has already handled any
  // InkDrop inherited functions.
  void SetAutoHighlightMode(AutoHighlightMode auto_highlight_mode);

  // Sets the AutoHighlightMode as per the platform. Platforms that show ripples
  // will be set to HIDE_ON_RIPPLE, and platforms that don't show ripples are
  // set to SHOW_ON_RIPPLE highlight behavior.
  void SetAutoHighlightModeForPlatform();

  const base::Optional<int>& hover_highlight_fade_duration_ms() const {
    return hover_highlight_fade_duration_ms_;
  }

  // InkDrop:
  void HostSizeChanged(const gfx::Size& new_size) override;
  InkDropState GetTargetInkDropState() const override;
  void AnimateToState(InkDropState ink_drop_state) override;
  void SetHoverHighlightFadeDurationMs(int duration_ms) override;
  void UseDefaultHoverHighlightFadeDuration() override;
  void SnapToActivated() override;
  void SnapToHidden() override;
  void SetHovered(bool is_hovered) override;
  void SetFocused(bool is_focused) override;
  bool IsHighlightFadingInOrVisible() const override;
  void SetShowHighlightOnHover(bool show_highlight_on_hover) override;
  void SetShowHighlightOnFocus(bool show_highlight_on_focus) override;

 private:
  friend class InkDropImplTest;
  friend class test::InkDropImplTestApi;

  // Forward declaration for use by the HighlightState class definition.
  class HighlightStateFactory;

  // Base HighlightState defines functions to handle all state changes that may
  // affect the highlight state.
  //
  // Subclasses are expected to handle state changes and transition the
  // InkDropImpl::highlight_state_ to new states as desired via the
  // InkDropImpl::SetHighlightState() method.
  //
  // New states should be created via the HighlightStateFactory and not
  // directly. This makes it possible for highlighting strategies to extend the
  // behavior of existing states and re-use existing state behavior.
  //
  // Subclasses are also expected to trigger the appropriate highlight
  // animations (e.g. fade in/out) via GetInkDrop()->SetHighlight(). Typically
  // this is done in the Enter()/Exit() functions. Triggering animations
  // anywhere else may be a sign that a new state should exist.
  class HighlightState {
   public:
    virtual ~HighlightState() {}

    // Called when |this| becomes the current state. Allows subclasses to
    // perform any work that should not be done in the constructor. It is ok for
    // subclass implementations to trigger state changes from within Enter().
    virtual void Enter() {}

    // Called just before |this| is removed as the current state. Allows
    // subclasses to perform any work that should not be done in the destructor
    // but is required before exiting |this| state (e.g. releasing resources).
    //
    // Subclass implementations should NOT do any work that may trigger another
    // state change since a state change is already in progress. They must also
    // avoid triggering any animations since Exit() will be called during
    // InkDropImpl destruction.
    virtual void Exit() {}

    // Input state change handlers.

    // Called when the value of InkDropImpl::show_highlight_on_hover_ changes.
    virtual void ShowOnHoverChanged() = 0;

    // Called when the value of InkDropImpl::is_hovered_ changes.
    virtual void OnHoverChanged() = 0;

    // Called when the value of InkDropImpl::show_highlight_on_focus_ changes.
    virtual void ShowOnFocusChanged() = 0;

    // Called when the value of InkDropImpl::is_focused_ changes.
    virtual void OnFocusChanged() = 0;

    // Called when an ink drop ripple animation is started.
    virtual void AnimationStarted(InkDropState ink_drop_state) = 0;

    // Called when an ink drop ripple animation has ended.
    virtual void AnimationEnded(InkDropState ink_drop_state,
                                InkDropAnimationEndedReason reason) = 0;

   protected:
    explicit HighlightState(HighlightStateFactory* state_factory)
        : state_factory_(state_factory) {}

    HighlightStateFactory* state_factory() { return state_factory_; }

    // Returns the ink drop that has |this| as the current state.
    InkDropImpl* GetInkDrop();

   private:
    // Used by |this| to create the new states to transition to.
    HighlightStateFactory* state_factory_;

    DISALLOW_COPY_AND_ASSIGN(HighlightState);
  };

  // Creates the different HighlightStates instances. A factory is used to make
  // it easier for states to extend and re-use existing state logic.
  class HighlightStateFactory {
   public:
    HighlightStateFactory(AutoHighlightMode highlight_mode,
                          InkDropImpl* ink_drop);

    // Returns the initial state.
    std::unique_ptr<HighlightState> CreateStartState();

    std::unique_ptr<HighlightState> CreateHiddenState(
        base::TimeDelta animation_duration,
        bool explode);

    std::unique_ptr<HighlightState> CreateVisibleState(
        base::TimeDelta animation_duration,
        bool explode);

    InkDropImpl* ink_drop() { return ink_drop_; }

   private:
    // Defines which concrete state types to create.
    AutoHighlightMode highlight_mode_;

    // The ink drop to invoke highlight changes on.
    InkDropImpl* ink_drop_;

    DISALLOW_COPY_AND_ASSIGN(HighlightStateFactory);
  };

  class DestroyingHighlightState;

  // AutoHighlightMode::NONE
  class NoAutoHighlightHiddenState;
  class NoAutoHighlightVisibleState;

  // AutoHighlightMode::HIDE_ON_RIPPLE
  class HideHighlightOnRippleHiddenState;
  class HideHighlightOnRippleVisibleState;

  // AutoHighlightMode::SHOW_ON_RIPPLE states
  class ShowHighlightOnRippleHiddenState;
  class ShowHighlightOnRippleVisibleState;

  // Destroys |ink_drop_ripple_| if it's targeted to the HIDDEN state.
  void DestroyHiddenTargetedAnimations();

  // Creates a new InkDropRipple and sets it to |ink_drop_ripple_|. If
  // |ink_drop_ripple_| wasn't null then it will be destroyed using
  // DestroyInkDropRipple().
  void CreateInkDropRipple();

  // Destroys the current |ink_drop_ripple_|.
  void DestroyInkDropRipple();

  // Creates a new InkDropHighlight and assigns it to |highlight_|. If
  // |highlight_| wasn't null then it will be destroyed using
  // DestroyInkDropHighlight().
  void CreateInkDropHighlight();

  // Destroys the current |highlight_|.
  void DestroyInkDropHighlight();

  // Adds the |root_layer_| to the |ink_drop_host_| if it hasn't already been
  // added.
  void AddRootLayerToHostIfNeeded();

  // Removes the |root_layer_| from the |ink_drop_host_| if no ink drop ripple
  // or highlight is active.
  void RemoveRootLayerFromHostIfNeeded();

  // views::InkDropRippleObserver:
  void AnimationStarted(InkDropState ink_drop_state) override;
  void AnimationEnded(InkDropState ink_drop_state,
                      InkDropAnimationEndedReason reason) override;

  // views::InkDropHighlightObserver:
  void AnimationStarted(
      InkDropHighlight::AnimationType animation_type) override;
  void AnimationEnded(InkDropHighlight::AnimationType animation_type,
                      InkDropAnimationEndedReason reason) override;

  // Enables or disables the highlight state based on |should_highlight| and if
  // an animation is triggered it will be scheduled to have the given
  // |animation_duration|. If |explode| is true the highlight will expand as it
  // fades out. |explode| is ignored when |should_higlight| is true.
  void SetHighlight(bool should_highlight,
                    base::TimeDelta animation_duration,
                    bool explode);

  // Returns true if |this| the highlight should be visible based on the
  // hover/focus status.
  bool ShouldHighlight() const;

  // Returns true if |this| the hilight should be visible based on the focus
  // status.
  bool ShouldHighlightBasedOnFocus() const;

  // Updates the current |highlight_state_|. Calls Exit()/Enter() on the
  // previous/new state to notify them of the transition.
  //
  // Uses ExitHighlightState() to exit the current state.
  void SetHighlightState(std::unique_ptr<HighlightState> highlight_state);

  // Exits the current |highlight_state_| and sets it to null. Ensures state
  // transitions are not triggered during HighlightStatae::Exit() calls on debug
  // builds.
  void ExitHighlightState();

  // The host of the ink drop. Used to create the ripples and highlights, and to
  // add/remove the root layer to/from it.
  InkDropHostView* ink_drop_host_;

  // The root Layer that parents the InkDropRipple layers and the
  // InkDropHighlight layers. The |root_layer_| is the one that is added and
  // removed from the |ink_drop_host_|.
  std::unique_ptr<ui::Layer> root_layer_;

  // True when the |root_layer_| has been added to the |ink_drop_host_|.
  bool root_layer_added_to_host_;

  // The current InkDropHighlight. Lazily created using
  // CreateInkDropHighlight();
  std::unique_ptr<InkDropHighlight> highlight_;

  // True denotes the highlight should be shown when |this| is hovered.
  bool show_highlight_on_hover_;

  // True denotes the highlight should be shown when |this| is focused.
  bool show_highlight_on_focus_;

  // Tracks the logical hovered state of |this| as manipulated by the public
  // SetHovered() function.
  bool is_hovered_;

  // Tracks the logical focused state of |this| as manipulated by the public
  // SetFocused() function.
  bool is_focused_;

  // The current InkDropRipple. Created on demand using CreateInkDropRipple().
  std::unique_ptr<InkDropRipple> ink_drop_ripple_;

  // Used by |this| to initialize the starting |highlight_state_| and by the
  // current |highlight_state_| to create the next state.
  std::unique_ptr<HighlightStateFactory> highlight_state_factory_;

  // The current state object that handles all inputs that affect the visibility
  // of the |highlight_|.
  std::unique_ptr<HighlightState> highlight_state_;

  // Overrides the default hover highlight fade durations when set.
  base::Optional<int> hover_highlight_fade_duration_ms_;

  // Used to ensure highlight state transitions are not triggered when exiting
  // the current state.
  bool exiting_highlight_state_;

  // Used to fail DCHECKS to catch unexpected behavior during tear down.
  bool destroying_;

  DISALLOW_COPY_AND_ASSIGN(InkDropImpl);
};

}  // namespace views

#endif  // UI_VIEWS_ANIMATION_INK_DROP_IMPL_H_