123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // Copyright 2021 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.
- #include "ui/native_theme/scrollbar_animator_mac.h"
- #include "base/cxx17_backports.h"
- namespace ui {
- ///////////////////////////////////////////////////////////////////////////////
- // ScrollbarAnimationTimerMac
- ScrollbarAnimationTimerMac::ScrollbarAnimationTimerMac(
- base::RepeatingCallback<void(double)> callback,
- double duration,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : start_time_(0.0), duration_(duration), callback_(std::move(callback)) {
- timing_function_ = gfx::CubicBezierTimingFunction::CreatePreset(
- gfx::CubicBezierTimingFunction::EaseType::EASE_IN_OUT);
- }
- ScrollbarAnimationTimerMac::~ScrollbarAnimationTimerMac() {}
- void ScrollbarAnimationTimerMac::Start() {
- start_time_ = base::Time::Now().ToDoubleT();
- // Set the framerate of the animation. NSAnimation uses a default
- // framerate of 60 Hz, so use that here.
- timer_.Start(FROM_HERE, base::Seconds(1.0 / 60.0), this,
- &ScrollbarAnimationTimerMac::TimerFired);
- }
- void ScrollbarAnimationTimerMac::Stop() {
- timer_.Stop();
- }
- void ScrollbarAnimationTimerMac::SetDuration(double duration) {
- duration_ = duration;
- }
- void ScrollbarAnimationTimerMac::TimerFired() {
- double current_time = base::Time::Now().ToDoubleT();
- double delta = current_time - start_time_;
- if (delta >= duration_)
- timer_.Stop();
- double fraction = delta / duration_;
- fraction = base::clamp(fraction, 0.0, 1.0);
- double progress = timing_function_->GetValue(fraction);
- // Note that `this` may be destroyed from within `callback_`, so it is not
- // safe to call any other code after it.
- callback_.Run(progress);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // OverlayScrollbarAnimatorMac
- OverlayScrollbarAnimatorMac::OverlayScrollbarAnimatorMac(
- Client* client,
- int thumb_width_expanded,
- int thumb_width_unexpanded,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : client_(client),
- thumb_width_expanded_(thumb_width_expanded),
- thumb_width_unexpanded_(thumb_width_unexpanded),
- thumb_width_(thumb_width_unexpanded),
- task_runner_(task_runner),
- weak_factory_(this) {}
- OverlayScrollbarAnimatorMac::~OverlayScrollbarAnimatorMac() = default;
- void OverlayScrollbarAnimatorMac::MouseDidEnter() {
- // If the scrollbar is completely hidden, ignore this. We will initialize
- // the `mouse_in_track_` state if there's a scroll.
- if (thumb_alpha_ == 0.f)
- return;
- if (mouse_in_track_)
- return;
- mouse_in_track_ = true;
- // Cancel any in-progress fade-out, and ensure that the fade-out timer be
- // disabled.
- if (fade_out_animation_)
- FadeOutAnimationCancel();
- FadeOutTimerUpdate();
- // Start the fade-in animation (unless it is in progress or has already
- // completed).
- if (!fade_in_track_animation_ && track_alpha_ != 1.f)
- FadeInTrackAnimationStart();
- // Start the expand-thumb animation (unless it is in progress or has already
- // completed).
- if (!expand_thumb_animation_ && thumb_width_ != thumb_width_expanded_)
- ExpandThumbAnimationStart();
- }
- void OverlayScrollbarAnimatorMac::MouseDidExit() {
- // Ensure that the fade-out timer be re-enabled.
- mouse_in_track_ = false;
- FadeOutTimerUpdate();
- }
- void OverlayScrollbarAnimatorMac::DidScroll() {
- // If we were fading out, then immediately return to being fully opaque for
- // both the thumb and track.
- if (fade_out_animation_) {
- FadeOutAnimationCancel();
- FadeOutTimerUpdate();
- return;
- }
- // If the scrollbar was already fully visible, then just update the fade-out
- // timer.
- if (thumb_alpha_ == 1.f) {
- FadeOutTimerUpdate();
- return;
- }
- // This is an initial scroll causing the thumb to appear.
- DCHECK_EQ(thumb_width_, thumb_width_unexpanded_);
- DCHECK_EQ(thumb_alpha_, 0.f);
- DCHECK(!fade_in_track_animation_);
- thumb_width_ = thumb_width_unexpanded_;
- thumb_alpha_ = 1;
- client_->SetThumbNeedsDisplay();
- client_->SetHidden(false);
- // If the initial scroll is done inside the scrollbar's area, then also
- // cause the track to appear and the thumb to enlarge.
- if (client_->IsMouseInScrollbarFrameRect()) {
- mouse_in_track_ = true;
- thumb_width_ = thumb_width_expanded_;
- track_alpha_ = 1;
- client_->SetTrackNeedsDisplay();
- }
- // Update the fade-out timer (now that we know whether or not the mouse
- // is in the track).
- FadeOutTimerUpdate();
- }
- void OverlayScrollbarAnimatorMac::ExpandThumbAnimationStart() {
- DCHECK(!expand_thumb_animation_);
- DCHECK_NE(thumb_width_, thumb_width_expanded_);
- expand_thumb_animation_ = std::make_unique<ScrollbarAnimationTimerMac>(
- base::BindRepeating(
- &OverlayScrollbarAnimatorMac::ExpandThumbAnimationTicked,
- weak_factory_.GetWeakPtr()),
- kAnimationDurationSeconds, task_runner_);
- expand_thumb_animation_->Start();
- }
- void OverlayScrollbarAnimatorMac::ExpandThumbAnimationTicked(double progress) {
- thumb_width_ = (1 - progress) * thumb_width_unexpanded_ +
- progress * thumb_width_expanded_;
- client_->SetThumbNeedsDisplay();
- if (progress == 1)
- expand_thumb_animation_.reset();
- }
- void OverlayScrollbarAnimatorMac::FadeInTrackAnimationStart() {
- DCHECK(!fade_in_track_animation_);
- DCHECK(!fade_out_animation_);
- fade_in_track_animation_ = std::make_unique<ScrollbarAnimationTimerMac>(
- base::BindRepeating(
- &OverlayScrollbarAnimatorMac::FadeInTrackAnimationTicked,
- weak_factory_.GetWeakPtr()),
- kAnimationDurationSeconds, task_runner_);
- fade_in_track_animation_->Start();
- }
- void OverlayScrollbarAnimatorMac::FadeInTrackAnimationTicked(double progress) {
- // Fade-in and fade-out are mutually exclusive.
- DCHECK(!fade_out_animation_);
- track_alpha_ = progress;
- client_->SetTrackNeedsDisplay();
- if (progress == 1) {
- fade_in_track_animation_.reset();
- }
- }
- void OverlayScrollbarAnimatorMac::FadeOutTimerUpdate() {
- if (mouse_in_track_) {
- start_scrollbar_fade_out_timer_.reset();
- return;
- }
- if (!start_scrollbar_fade_out_timer_) {
- start_scrollbar_fade_out_timer_ =
- std::make_unique<base::RetainingOneShotTimer>(
- FROM_HERE, kFadeOutDelay,
- base::BindRepeating(
- &OverlayScrollbarAnimatorMac::FadeOutAnimationStart,
- weak_factory_.GetWeakPtr()));
- start_scrollbar_fade_out_timer_->SetTaskRunner(task_runner_);
- }
- start_scrollbar_fade_out_timer_->Reset();
- }
- void OverlayScrollbarAnimatorMac::FadeOutAnimationStart() {
- start_scrollbar_fade_out_timer_.reset();
- fade_in_track_animation_.reset();
- fade_out_animation_.reset();
- fade_out_animation_ = std::make_unique<ScrollbarAnimationTimerMac>(
- base::BindRepeating(&OverlayScrollbarAnimatorMac::FadeOutAnimationTicked,
- weak_factory_.GetWeakPtr()),
- kAnimationDurationSeconds, task_runner_);
- fade_out_animation_->Start();
- }
- void OverlayScrollbarAnimatorMac::FadeOutAnimationTicked(double progress) {
- DCHECK(!fade_in_track_animation_);
- // Fade out the thumb.
- thumb_alpha_ = 1 - progress;
- client_->SetThumbNeedsDisplay();
- // If the track is not already invisible, fade it out.
- if (track_alpha_ != 0) {
- track_alpha_ = 1 - progress;
- client_->SetTrackNeedsDisplay();
- }
- // Once completely faded out, reset all state.
- if (progress == 1) {
- expand_thumb_animation_.reset();
- fade_out_animation_.reset();
- thumb_width_ = thumb_width_unexpanded_;
- DCHECK_EQ(thumb_alpha_, 0.f);
- DCHECK_EQ(track_alpha_, 0.f);
- // Mark that the scrollbars were hidden.
- client_->SetHidden(true);
- }
- }
- void OverlayScrollbarAnimatorMac::FadeOutAnimationCancel() {
- DCHECK(fade_out_animation_);
- fade_out_animation_.reset();
- thumb_alpha_ = 1;
- client_->SetThumbNeedsDisplay();
- if (track_alpha_ > 0) {
- track_alpha_ = 1;
- client_->SetTrackNeedsDisplay();
- }
- }
- const float OverlayScrollbarAnimatorMac::kAnimationDurationSeconds = 0.25f;
- const base::TimeDelta OverlayScrollbarAnimatorMac::kFadeOutDelay =
- base::Milliseconds(500);
- } // namespace ui
|