blob: 22b061603b859e6c6875caec51650802f429c1b6 [file] [log] [blame]
// 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/views/animation/animation_sequence_block.h"
#include <map>
#include <memory>
#include <utility>
#include "base/callback.h"
#include "base/check.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/interpolated_transform.h"
#include "ui/views/animation/animation_builder.h"
#include "ui/views/animation/animation_key.h"
namespace views {
using PassKey = base::PassKey<AnimationSequenceBlock>;
AnimationSequenceBlock::AnimationSequenceBlock(
base::PassKey<AnimationBuilder> builder_key,
AnimationBuilder* owner,
base::TimeDelta start)
: builder_key_(builder_key), owner_(owner), start_(start) {}
AnimationSequenceBlock::AnimationSequenceBlock(AnimationSequenceBlock&&) =
default;
AnimationSequenceBlock& AnimationSequenceBlock::operator=(
AnimationSequenceBlock&&) = default;
AnimationSequenceBlock::~AnimationSequenceBlock() {
if (is_terminal_block_) {
TerminateBlock();
owner_->TerminateSequence(PassKey());
}
}
AnimationSequenceBlock& AnimationSequenceBlock::SetDuration(
base::TimeDelta duration) {
DCHECK(!duration_.has_value()) << "Duration may be set at most once.";
duration_ = duration;
return *this;
}
AnimationSequenceBlock& AnimationSequenceBlock::SetBounds(
ui::LayerOwner* target,
const gfx::Rect& bounds,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::BOUNDS},
Element(bounds, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetBrightness(
ui::LayerOwner* target,
float brightness,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::BRIGHTNESS},
Element(brightness, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetClipRect(
ui::LayerOwner* target,
const gfx::Rect& clip_rect,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::CLIP},
Element(clip_rect, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetColor(
ui::LayerOwner* target,
SkColor color,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::COLOR},
Element(color, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetGrayscale(
ui::LayerOwner* target,
float grayscale,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::GRAYSCALE},
Element(grayscale, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetOpacity(
ui::LayerOwner* target,
float opacity,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::OPACITY},
Element(opacity, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetInterpolatedTransform(
ui::LayerOwner* target,
std::unique_ptr<ui::InterpolatedTransform> interpolated_transform,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::TRANSFORM},
Element(std::move(interpolated_transform), tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetRoundedCorners(
ui::LayerOwner* target,
const gfx::RoundedCornersF& rounded_corners,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::ROUNDED_CORNERS},
Element(rounded_corners, tween_type));
}
AnimationSequenceBlock& AnimationSequenceBlock::SetVisibility(
ui::LayerOwner* target,
bool visible,
gfx::Tween::Type tween_type) {
return AddAnimation({target, ui::LayerAnimationElement::VISIBILITY},
Element(visible, tween_type));
}
AnimationSequenceBlock AnimationSequenceBlock::At(
base::TimeDelta since_sequence_start) {
TerminateBlock();
is_terminal_block_ = false;
return AnimationSequenceBlock(builder_key_, owner_, since_sequence_start);
}
AnimationSequenceBlock AnimationSequenceBlock::Offset(
base::TimeDelta since_last_block_start) {
return At(start_ + since_last_block_start);
}
AnimationSequenceBlock AnimationSequenceBlock::Then() {
return Offset(duration_.value_or(base::TimeDelta()));
}
AnimationSequenceBlock& AnimationSequenceBlock::OnStarted(
base::OnceClosure callback) {
owner_->SetOnStarted(std::move(callback));
return *this;
}
AnimationSequenceBlock& AnimationSequenceBlock::OnEnded(
base::OnceClosure callback) {
owner_->SetOnEnded(std::move(callback));
return *this;
}
AnimationSequenceBlock& AnimationSequenceBlock::OnWillRepeat(
base::RepeatingClosure callback) {
owner_->SetOnWillRepeat(std::move(callback));
return *this;
}
AnimationSequenceBlock& AnimationSequenceBlock::OnAborted(
base::OnceClosure callback) {
owner_->SetOnAborted(std::move(callback));
return *this;
}
AnimationSequenceBlock& AnimationSequenceBlock::OnScheduled(
base::OnceClosure callback) {
owner_->SetOnScheduled(std::move(callback));
return *this;
}
AnimationSequenceBlock::Element::Element(AnimationValue animation_value,
gfx::Tween::Type tween_type)
: animation_value_(std::move(animation_value)), tween_type_(tween_type) {}
AnimationSequenceBlock::Element::~Element() = default;
AnimationSequenceBlock::Element::Element(Element&&) = default;
AnimationSequenceBlock::Element& AnimationSequenceBlock::Element::operator=(
Element&&) = default;
AnimationSequenceBlock& AnimationSequenceBlock::AddAnimation(AnimationKey key,
Element element) {
const auto result =
elements_.insert(std::make_pair(std::move(key), std::move(element)));
DCHECK(result.second) << "Animate (target, property) at most once per block.";
return *this;
}
void AnimationSequenceBlock::TerminateBlock() {
const auto duration = duration_.value_or(base::TimeDelta());
for (auto& pair : elements_) {
std::unique_ptr<ui::LayerAnimationElement> element;
switch (pair.first.property) {
case ui::LayerAnimationElement::TRANSFORM:
element = ui::LayerAnimationElement::CreateInterpolatedTransformElement(
absl::get<std::unique_ptr<ui::InterpolatedTransform>>(
std::move(pair.second.animation_value_)),
duration);
break;
case ui::LayerAnimationElement::BOUNDS:
element = ui::LayerAnimationElement::CreateBoundsElement(
absl::get<gfx::Rect>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::OPACITY:
element = ui::LayerAnimationElement::CreateOpacityElement(
absl::get<float>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::VISIBILITY:
element = ui::LayerAnimationElement::CreateVisibilityElement(
absl::get<bool>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::BRIGHTNESS:
element = ui::LayerAnimationElement::CreateBrightnessElement(
absl::get<float>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::GRAYSCALE:
element = ui::LayerAnimationElement::CreateGrayscaleElement(
absl::get<float>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::COLOR:
element = ui::LayerAnimationElement::CreateColorElement(
absl::get<SkColor>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::CLIP:
element = ui::LayerAnimationElement::CreateClipRectElement(
absl::get<gfx::Rect>(pair.second.animation_value_), duration);
break;
case ui::LayerAnimationElement::ROUNDED_CORNERS:
element = ui::LayerAnimationElement::CreateRoundedCornersElement(
absl::get<gfx::RoundedCornersF>(pair.second.animation_value_),
duration);
break;
default:
NOTREACHED();
}
element->set_tween_type(pair.second.tween_type_);
owner_->AddLayerAnimationElement(PassKey(), pair.first, start_,
std::move(element));
}
owner_->BlockEndedAt(PassKey(), start_ + duration);
elements_.clear();
}
} // namespace views