1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "base/geometry/animatable_matrix4.h"
17
18#include "core/event/ace_event_helper.h"
19
20namespace OHOS::Ace {
21
22AnimatableMatrix4& AnimatableMatrix4::operator=(const Matrix4& newMatrix4)
23{
24    ResetAnimatableMatrix();
25    Matrix4& matrix4 = *this;
26    matrix4 = newMatrix4;
27    return *this;
28}
29
30AnimatableMatrix4& AnimatableMatrix4::operator=(const AnimatableMatrix4& newMatrix4)
31{
32    SetAnimationOption(newMatrix4.GetAnimationOption());
33    auto pipelineContext = context_.Upgrade();
34    if (!animationCallback_ || !pipelineContext) {
35        Matrix4& matrix4 = *this;
36        matrix4 = newMatrix4;
37        return *this;
38    }
39    AnimationOption explicitAnim = pipelineContext->GetExplicitAnimationOption();
40    if (explicitAnim.IsValid()) {
41        SetAnimationOption(explicitAnim);
42        AnimateTo(newMatrix4);
43    } else if (animationOption_.IsValid()) {
44        AnimateTo(newMatrix4);
45    } else {
46        ResetController();
47        Matrix4& matrix4 = *this;
48        matrix4 = newMatrix4;
49    }
50    isFirstAssign_ = false;
51    return *this;
52}
53
54void AnimatableMatrix4::MoveTo(const Matrix4& target)
55{
56    Matrix4& matrix4 = *this;
57    matrix4 = target;
58    isFirstAssign_ = false;
59}
60
61void AnimatableMatrix4::AnimateTo(const Matrix4& endValue)
62{
63    if (isFirstAssign_) {
64        isFirstAssign_ = false;
65        Matrix4& matrix4 = *this;
66        matrix4 = endValue;
67        return;
68    }
69
70    if (*this == endValue && !evaluator_) {
71        return;
72    }
73    ResetController();
74    if (!animationController_) {
75        animationController_ = CREATE_ANIMATOR(context_);
76    }
77
78    TransformOperation operationInit;
79    TransformOperation operationEnd;
80    operationInit.type_ = TransformOperationType::MATRIX;
81    operationEnd.type_ = TransformOperationType::MATRIX;
82    operationInit.matrix4_ = static_cast<Matrix4>(*this);
83    operationEnd.matrix4_ = endValue;
84    RefPtr<CurveAnimation<TransformOperation>> animation = AceType::MakeRefPtr<CurveAnimation<TransformOperation>>(
85        operationInit, operationEnd, animationOption_.GetCurve());
86    if (evaluator_) {
87        animation->SetEvaluator(evaluator_);
88    }
89    animation->AddListener(std::bind(&AnimatableMatrix4::OnAnimationCallback, this, std::placeholders::_1));
90    animationController_->AddInterpolator(animation);
91    auto onFinishEvent = animationOption_.GetOnFinishEvent();
92    if (onFinishEvent) {
93        animationController_->AddStopListener([onFinishEvent, weakContext = context_] {
94            auto context = weakContext.Upgrade();
95            if (context) {
96                context->PostAsyncEvent(onFinishEvent, "ArkUIAnimatableMatrix4FinishEvent");
97            }
98        });
99    }
100    if (stopCallback_) {
101        animationController_->AddStopListener(stopCallback_);
102    }
103    animationController_->SetDuration(animationOption_.GetDuration());
104    animationController_->SetStartDelay(animationOption_.GetDelay());
105    animationController_->SetIteration(animationOption_.GetIteration());
106    animationController_->SetTempo(animationOption_.GetTempo());
107    animationController_->SetAnimationDirection(animationOption_.GetAnimationDirection());
108    animationController_->SetFillMode(FillMode::FORWARDS);
109    animationController_->SetAllowRunningAsynchronously(animationOption_.GetAllowRunningAsynchronously());
110    animationController_->Play();
111}
112
113void AnimatableMatrix4::ResetController()
114{
115    if (animationController_) {
116        if (!animationController_->IsStopped()) {
117            animationController_->Stop();
118        }
119        animationController_->ClearInterpolators();
120        animationController_->ClearAllListeners();
121        animationController_.Reset();
122    }
123}
124
125void AnimatableMatrix4::OnAnimationCallback(const TransformOperation& value)
126{
127    Matrix4& matrix4 = *this;
128    matrix4 = value.matrix4_;
129    if (animationCallback_) {
130        animationCallback_();
131    }
132}
133
134void AnimatableMatrix4::ResetAnimatableMatrix()
135{
136    isFirstAssign_ = true;
137    animationOption_ = AnimationOption();
138    animationController_ = nullptr;
139    context_ = nullptr;
140    animationCallback_ = nullptr;
141}
142
143} // namespace OHOS::Ace
144