18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci#include "animation_state.h" 178bf80f4bSopenharmony_ci 188bf80f4bSopenharmony_ci#include <meta/api/make_callback.h> 198bf80f4bSopenharmony_ci#include <meta/api/util.h> 208bf80f4bSopenharmony_ci#include <meta/interface/animation/intf_animation_modifier.h> 218bf80f4bSopenharmony_ci#include <meta/interface/builtin_objects.h> 228bf80f4bSopenharmony_ci#include <meta/interface/interface_macros.h> 238bf80f4bSopenharmony_ci#include <meta/interface/intf_attachment_container.h> 248bf80f4bSopenharmony_ci#include <meta/interface/property/property_events.h> 258bf80f4bSopenharmony_ci 268bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE() 278bf80f4bSopenharmony_ci 288bf80f4bSopenharmony_cinamespace Internal { 298bf80f4bSopenharmony_ci 308bf80f4bSopenharmony_cibool AnimationState::Initialize(AnimationStateParams&& params) 318bf80f4bSopenharmony_ci{ 328bf80f4bSopenharmony_ci params_ = BASE_NS::move(params); 338bf80f4bSopenharmony_ci auto owner = GetOwner(); 348bf80f4bSopenharmony_ci if (!owner) { 358bf80f4bSopenharmony_ci CORE_LOG_F("AnimationState: Invalid target animation"); 368bf80f4bSopenharmony_ci return false; 378bf80f4bSopenharmony_ci } 388bf80f4bSopenharmony_ci auto controllerProp = owner->Controller(); 398bf80f4bSopenharmony_ci if (!controllerProp) { 408bf80f4bSopenharmony_ci return false; 418bf80f4bSopenharmony_ci } 428bf80f4bSopenharmony_ci if (!controllerProp->GetValue().lock()) { 438bf80f4bSopenharmony_ci // No controller set, init to default 448bf80f4bSopenharmony_ci controllerProp->SetValue(META_NS::GetAnimationController()); 458bf80f4bSopenharmony_ci } 468bf80f4bSopenharmony_ci 478bf80f4bSopenharmony_ci updateTotalDuration_ = MakeCallback<IOnChanged>(this, &AnimationState::UpdateTotalDuration); 488bf80f4bSopenharmony_ci if (auto timed = interface_cast<ITimedAnimation>(owner)) { 498bf80f4bSopenharmony_ci timed->Duration()->OnChanged()->AddHandler(updateTotalDuration_, uintptr_t(this)); 508bf80f4bSopenharmony_ci } 518bf80f4bSopenharmony_ci 528bf80f4bSopenharmony_ci auto updateController = MakeCallback<IOnChanged>(this, &AnimationState::UpdateController); 538bf80f4bSopenharmony_ci controllerProp->OnChanged()->AddHandler(updateController); 548bf80f4bSopenharmony_ci state_.clock_ = META_NS::GetObjectRegistry().Create<META_NS::IManualClock>(META_NS::ClassId::ManualClock); 558bf80f4bSopenharmony_ci CORE_ASSERT(state_.clock_); 568bf80f4bSopenharmony_ci UpdateTotalDuration(); 578bf80f4bSopenharmony_ci UpdateController(); 588bf80f4bSopenharmony_ci return true; 598bf80f4bSopenharmony_ci} 608bf80f4bSopenharmony_ci 618bf80f4bSopenharmony_civoid AnimationState::Uninitialize() 628bf80f4bSopenharmony_ci{ 638bf80f4bSopenharmony_ci if (auto timed = interface_pointer_cast<ITimedAnimation>(GetOwner())) { 648bf80f4bSopenharmony_ci timed->Duration()->OnChanged()->RemoveHandler(uintptr_t(this)); 658bf80f4bSopenharmony_ci } 668bf80f4bSopenharmony_ci} 678bf80f4bSopenharmony_ci 688bf80f4bSopenharmony_civoid AnimationState::NotifyEvaluationNeeded() const 698bf80f4bSopenharmony_ci{ 708bf80f4bSopenharmony_ci if (auto internal = interface_pointer_cast<IAnimationInternal>(GetOwner())) { 718bf80f4bSopenharmony_ci internal->OnEvaluationNeeded(); 728bf80f4bSopenharmony_ci } 738bf80f4bSopenharmony_ci} 748bf80f4bSopenharmony_ci 758bf80f4bSopenharmony_civoid AnimationState::NotifyStateChanged(const IAnimationInternal::AnimationStateChangedInfo& info) const 768bf80f4bSopenharmony_ci{ 778bf80f4bSopenharmony_ci if (auto internal = interface_pointer_cast<IAnimationInternal>(GetOwner())) { 788bf80f4bSopenharmony_ci internal->OnAnimationStateChanged(info); 798bf80f4bSopenharmony_ci // Need also evaluation 808bf80f4bSopenharmony_ci internal->OnEvaluationNeeded(); 818bf80f4bSopenharmony_ci } 828bf80f4bSopenharmony_ci} 838bf80f4bSopenharmony_ci 848bf80f4bSopenharmony_civoid AnimationState::UpdateController() 858bf80f4bSopenharmony_ci{ 868bf80f4bSopenharmony_ci IAnimation::Ptr animation = GetOwner(); 878bf80f4bSopenharmony_ci if (!animation) { 888bf80f4bSopenharmony_ci CORE_LOG_E("Invalid target animation"); 898bf80f4bSopenharmony_ci return; 908bf80f4bSopenharmony_ci } 918bf80f4bSopenharmony_ci auto oldController = controller_.lock(); 928bf80f4bSopenharmony_ci auto newController = animation->Controller()->GetValue().lock(); 938bf80f4bSopenharmony_ci 948bf80f4bSopenharmony_ci if (oldController != newController) { 958bf80f4bSopenharmony_ci if (oldController) { 968bf80f4bSopenharmony_ci oldController->RemoveAnimation(animation); 978bf80f4bSopenharmony_ci } 988bf80f4bSopenharmony_ci if (newController) { 998bf80f4bSopenharmony_ci newController->AddAnimation(animation); 1008bf80f4bSopenharmony_ci } 1018bf80f4bSopenharmony_ci controller_ = newController; 1028bf80f4bSopenharmony_ci } 1038bf80f4bSopenharmony_ci} 1048bf80f4bSopenharmony_ci 1058bf80f4bSopenharmony_civoid AnimationState::ResetClock() 1068bf80f4bSopenharmony_ci{ 1078bf80f4bSopenharmony_ci state_.ResetLastTick(); 1088bf80f4bSopenharmony_ci state_.SetTime(TimeSpan::Zero()); 1098bf80f4bSopenharmony_ci} 1108bf80f4bSopenharmony_ci 1118bf80f4bSopenharmony_ciAnimationState::StepStatus AnimationState::Step(const IClock::ConstPtr& clock) 1128bf80f4bSopenharmony_ci{ 1138bf80f4bSopenharmony_ci if (!IsRunning()) { 1148bf80f4bSopenharmony_ci return {}; 1158bf80f4bSopenharmony_ci } 1168bf80f4bSopenharmony_ci 1178bf80f4bSopenharmony_ci const auto time = clock ? clock->GetTime() : TimeSpan::Zero(); 1188bf80f4bSopenharmony_ci float progress = static_cast<float>(state_.Tick(time).ToMilliseconds()) / 1198bf80f4bSopenharmony_ci static_cast<float>(state_.GetBaseDuration().ToMilliseconds()); 1208bf80f4bSopenharmony_ci 1218bf80f4bSopenharmony_ci return Move(IAnimationInternal::MoveParams::FromProgress(progress)); 1228bf80f4bSopenharmony_ci} 1238bf80f4bSopenharmony_ci 1248bf80f4bSopenharmony_ciconstexpr IAnimationInternal::AnimationTargetState GetTargetState(const IAnimationInternal::MoveParams& move) noexcept 1258bf80f4bSopenharmony_ci{ 1268bf80f4bSopenharmony_ci using AnimationTargetState = IAnimationInternal::AnimationTargetState; 1278bf80f4bSopenharmony_ci const auto& step = move.step; 1288bf80f4bSopenharmony_ci const auto& state = move.state; 1298bf80f4bSopenharmony_ci if (state == AnimationTargetState::UNDEFINED) { 1308bf80f4bSopenharmony_ci // Figure out target state based on step data automatically 1318bf80f4bSopenharmony_ci const float progress = step.progress; 1328bf80f4bSopenharmony_ci const bool reverse = step.reverse; 1338bf80f4bSopenharmony_ci if (progress >= 1.f) { 1348bf80f4bSopenharmony_ci return reverse ? AnimationTargetState::RUNNING : AnimationTargetState::FINISHED; 1358bf80f4bSopenharmony_ci } 1368bf80f4bSopenharmony_ci if (progress <= 0.f) { 1378bf80f4bSopenharmony_ci return reverse ? AnimationTargetState::FINISHED : AnimationTargetState::RUNNING; 1388bf80f4bSopenharmony_ci } 1398bf80f4bSopenharmony_ci return AnimationTargetState::RUNNING; 1408bf80f4bSopenharmony_ci } 1418bf80f4bSopenharmony_ci 1428bf80f4bSopenharmony_ci // Just go to the state defined by the caller 1438bf80f4bSopenharmony_ci return state; 1448bf80f4bSopenharmony_ci} 1458bf80f4bSopenharmony_ci 1468bf80f4bSopenharmony_ciAnimationState::StepStatus AnimationState::Move(const IAnimationInternal::MoveParams& move) 1478bf80f4bSopenharmony_ci{ 1488bf80f4bSopenharmony_ci using AnimationTargetState = IAnimationInternal::AnimationTargetState; 1498bf80f4bSopenharmony_ci auto animationState = GetTargetState(move); 1508bf80f4bSopenharmony_ci const auto& step = move.step; 1518bf80f4bSopenharmony_ci float progress = step.progress; 1528bf80f4bSopenharmony_ci 1538bf80f4bSopenharmony_ci if (state_.shouldInit_) { 1548bf80f4bSopenharmony_ci state_.loops = state_.duration.loopCount; 1558bf80f4bSopenharmony_ci state_.shouldInit_ = false; 1568bf80f4bSopenharmony_ci } 1578bf80f4bSopenharmony_ci 1588bf80f4bSopenharmony_ci if (animationState == AnimationTargetState::FINISHED) { 1598bf80f4bSopenharmony_ci // Check if we need to loop 1608bf80f4bSopenharmony_ci if (state_.loops && (state_.loops < 0 || --state_.loops)) { 1618bf80f4bSopenharmony_ci animationState = AnimationTargetState::RUNNING; 1628bf80f4bSopenharmony_ci const auto overflow = progress - BASE_NS::Math::floor(progress); 1638bf80f4bSopenharmony_ci state_.SetTime(overflow * state_.GetBaseDuration()); 1648bf80f4bSopenharmony_ci if (overflow > 0.f) { 1658bf80f4bSopenharmony_ci // If progress based on clock would be e.g. 1.2, jump to 0.2 to not jank the animation 1668bf80f4bSopenharmony_ci progress = overflow; 1678bf80f4bSopenharmony_ci } 1688bf80f4bSopenharmony_ci } 1698bf80f4bSopenharmony_ci } 1708bf80f4bSopenharmony_ci 1718bf80f4bSopenharmony_ci AnimationState::StepStatus status; 1728bf80f4bSopenharmony_ci if (progress = BASE_NS::Math::clamp01(progress); progress != GetProgress()) { 1738bf80f4bSopenharmony_ci SetProgress(progress); 1748bf80f4bSopenharmony_ci status.changed = true; 1758bf80f4bSopenharmony_ci } 1768bf80f4bSopenharmony_ci 1778bf80f4bSopenharmony_ci status.changed |= SetState(animationState); 1788bf80f4bSopenharmony_ci status.state = state_.animationState_; 1798bf80f4bSopenharmony_ci status.progress = GetProgress(); 1808bf80f4bSopenharmony_ci if (status.changed) { 1818bf80f4bSopenharmony_ci NotifyEvaluationNeeded(); 1828bf80f4bSopenharmony_ci } 1838bf80f4bSopenharmony_ci return status; 1848bf80f4bSopenharmony_ci} 1858bf80f4bSopenharmony_ci 1868bf80f4bSopenharmony_civoid AnimationState::Seek(float position) 1878bf80f4bSopenharmony_ci{ 1888bf80f4bSopenharmony_ci auto animation = GetOwner(); 1898bf80f4bSopenharmony_ci if (!animation) { 1908bf80f4bSopenharmony_ci CORE_LOG_E("Invalid target animation"); 1918bf80f4bSopenharmony_ci return; 1928bf80f4bSopenharmony_ci } 1938bf80f4bSopenharmony_ci 1948bf80f4bSopenharmony_ci position = BASE_NS::Math::clamp01(position); 1958bf80f4bSopenharmony_ci state_.ResetLastTick(); 1968bf80f4bSopenharmony_ci const auto seekedTime = state_.GetBaseDuration().ToSecondsFloat() * position; 1978bf80f4bSopenharmony_ci state_.SetTime(TimeSpan::Seconds(seekedTime)); 1988bf80f4bSopenharmony_ci auto state = state_.animationState_; 1998bf80f4bSopenharmony_ci if (position >= 1.f) { 2008bf80f4bSopenharmony_ci state = IAnimationInternal::AnimationTargetState::FINISHED; 2018bf80f4bSopenharmony_ci } 2028bf80f4bSopenharmony_ci Move(IAnimationInternal::MoveParams::FromProgress(position, state)); 2038bf80f4bSopenharmony_ci} 2048bf80f4bSopenharmony_ci 2058bf80f4bSopenharmony_cibool AnimationState::Pause() 2068bf80f4bSopenharmony_ci{ 2078bf80f4bSopenharmony_ci return SetState(IAnimationInternal::AnimationTargetState::PAUSED); 2088bf80f4bSopenharmony_ci} 2098bf80f4bSopenharmony_ci 2108bf80f4bSopenharmony_cibool AnimationState::Start() 2118bf80f4bSopenharmony_ci{ 2128bf80f4bSopenharmony_ci return SetState(IAnimationInternal::AnimationTargetState::RUNNING); 2138bf80f4bSopenharmony_ci} 2148bf80f4bSopenharmony_ci 2158bf80f4bSopenharmony_cibool AnimationState::Stop() 2168bf80f4bSopenharmony_ci{ 2178bf80f4bSopenharmony_ci return Move(IAnimationInternal::MoveParams::FromProgress(0.f, IAnimationInternal::AnimationTargetState::STOPPED)) 2188bf80f4bSopenharmony_ci .StatusChanged(); 2198bf80f4bSopenharmony_ci} 2208bf80f4bSopenharmony_ci 2218bf80f4bSopenharmony_cibool AnimationState::Finish() 2228bf80f4bSopenharmony_ci{ 2238bf80f4bSopenharmony_ci return Move(IAnimationInternal::MoveParams::FromProgress(1.f, IAnimationInternal::AnimationTargetState::FINISHED)) 2248bf80f4bSopenharmony_ci .StatusChanged(); 2258bf80f4bSopenharmony_ci} 2268bf80f4bSopenharmony_ci 2278bf80f4bSopenharmony_cibool AnimationState::Restart() 2288bf80f4bSopenharmony_ci{ 2298bf80f4bSopenharmony_ci if (Stop()) { 2308bf80f4bSopenharmony_ci return Start(); 2318bf80f4bSopenharmony_ci } 2328bf80f4bSopenharmony_ci return false; 2338bf80f4bSopenharmony_ci} 2348bf80f4bSopenharmony_ci 2358bf80f4bSopenharmony_ciIAnimation::Ptr AnimationState::GetOwner() const noexcept 2368bf80f4bSopenharmony_ci{ 2378bf80f4bSopenharmony_ci return params_.owner.lock(); 2388bf80f4bSopenharmony_ci} 2398bf80f4bSopenharmony_ci 2408bf80f4bSopenharmony_cibool AnimationState::IsRunning() const noexcept 2418bf80f4bSopenharmony_ci{ 2428bf80f4bSopenharmony_ci return GetValue(params_.runningProperty, false); 2438bf80f4bSopenharmony_ci} 2448bf80f4bSopenharmony_ci 2458bf80f4bSopenharmony_cibool AnimationState::IsPaused() const noexcept 2468bf80f4bSopenharmony_ci{ 2478bf80f4bSopenharmony_ci return state_.animationState_ == IAnimationInternal::AnimationTargetState::PAUSED; 2488bf80f4bSopenharmony_ci} 2498bf80f4bSopenharmony_ci 2508bf80f4bSopenharmony_civoid AnimationState::SetRunning(bool running) noexcept 2518bf80f4bSopenharmony_ci{ 2528bf80f4bSopenharmony_ci SetValue(params_.runningProperty, running); 2538bf80f4bSopenharmony_ci} 2548bf80f4bSopenharmony_ci 2558bf80f4bSopenharmony_cifloat AnimationState::GetProgress() const noexcept 2568bf80f4bSopenharmony_ci{ 2578bf80f4bSopenharmony_ci return GetValue(params_.progressProperty, 0.f); 2588bf80f4bSopenharmony_ci} 2598bf80f4bSopenharmony_ci 2608bf80f4bSopenharmony_civoid AnimationState::SetProgress(float progress) noexcept 2618bf80f4bSopenharmony_ci{ 2628bf80f4bSopenharmony_ci SetValue(params_.progressProperty, progress); 2638bf80f4bSopenharmony_ci} 2648bf80f4bSopenharmony_ci 2658bf80f4bSopenharmony_cibool AnimationState::SetState(IAnimationInternal::AnimationTargetState state) 2668bf80f4bSopenharmony_ci{ 2678bf80f4bSopenharmony_ci using AnimationTargetState = IAnimationInternal::AnimationTargetState; 2688bf80f4bSopenharmony_ci const auto previous = state_.animationState_; 2698bf80f4bSopenharmony_ci if (previous == state) { 2708bf80f4bSopenharmony_ci return false; 2718bf80f4bSopenharmony_ci } 2728bf80f4bSopenharmony_ci if (const auto owner = GetOwner()) { 2738bf80f4bSopenharmony_ci bool notifyStarted = false; 2748bf80f4bSopenharmony_ci switch (state) { 2758bf80f4bSopenharmony_ci case AnimationTargetState::RUNNING: 2768bf80f4bSopenharmony_ci if (previous != AnimationTargetState::PAUSED) { 2778bf80f4bSopenharmony_ci state_.shouldInit_ = true; 2788bf80f4bSopenharmony_ci notifyStarted = true; 2798bf80f4bSopenharmony_ci if (previous == AnimationTargetState::FINISHED) { 2808bf80f4bSopenharmony_ci SetProgress(0.f); 2818bf80f4bSopenharmony_ci ResetClock(); 2828bf80f4bSopenharmony_ci } 2838bf80f4bSopenharmony_ci } 2848bf80f4bSopenharmony_ci break; 2858bf80f4bSopenharmony_ci case AnimationTargetState::PAUSED: 2868bf80f4bSopenharmony_ci state_.ResetLastTick(); 2878bf80f4bSopenharmony_ci break; 2888bf80f4bSopenharmony_ci case AnimationTargetState::FINISHED: 2898bf80f4bSopenharmony_ci [[fallthrough]]; 2908bf80f4bSopenharmony_ci case AnimationTargetState::STOPPED: 2918bf80f4bSopenharmony_ci ResetClock(); 2928bf80f4bSopenharmony_ci break; 2938bf80f4bSopenharmony_ci default: 2948bf80f4bSopenharmony_ci CORE_LOG_E("Invalid target state for animation: AnimationTargetState::UNDEFINED"); 2958bf80f4bSopenharmony_ci ResetClock(); 2968bf80f4bSopenharmony_ci break; 2978bf80f4bSopenharmony_ci } 2988bf80f4bSopenharmony_ci SetRunning(state == AnimationTargetState::RUNNING); 2998bf80f4bSopenharmony_ci 3008bf80f4bSopenharmony_ci state_.animationState_ = state; 3018bf80f4bSopenharmony_ci IAnimationInternal::AnimationStateChangedInfo info; 3028bf80f4bSopenharmony_ci info.source = GetOwner(); 3038bf80f4bSopenharmony_ci info.state = state; 3048bf80f4bSopenharmony_ci info.previous = previous; 3058bf80f4bSopenharmony_ci NotifyStateChanged(info); 3068bf80f4bSopenharmony_ci 3078bf80f4bSopenharmony_ci if (state == AnimationTargetState::FINISHED) { 3088bf80f4bSopenharmony_ci Invoke<IOnChanged>(owner->OnFinished()); 3098bf80f4bSopenharmony_ci } 3108bf80f4bSopenharmony_ci if (notifyStarted) { 3118bf80f4bSopenharmony_ci Invoke<IOnChanged>(owner->OnStarted()); 3128bf80f4bSopenharmony_ci } 3138bf80f4bSopenharmony_ci return true; 3148bf80f4bSopenharmony_ci } 3158bf80f4bSopenharmony_ci return false; 3168bf80f4bSopenharmony_ci} 3178bf80f4bSopenharmony_ci 3188bf80f4bSopenharmony_ciBASE_NS::vector<IAnimationModifier::Ptr> AnimationState::GetModifiers() const 3198bf80f4bSopenharmony_ci{ 3208bf80f4bSopenharmony_ci if (!modifierCache_.HasTarget()) { 3218bf80f4bSopenharmony_ci // Do not create an attachment container unless one has already been created by someone 3228bf80f4bSopenharmony_ci if (const auto attach = interface_pointer_cast<IAttach>(params_.owner)) { 3238bf80f4bSopenharmony_ci if (const auto container = attach->GetAttachmentContainer(false)) { 3248bf80f4bSopenharmony_ci modifierCache_.SetTarget( 3258bf80f4bSopenharmony_ci container, { "", TraversalType::NO_HIERARCHY, { IAnimationModifier::UID }, true }); 3268bf80f4bSopenharmony_ci } 3278bf80f4bSopenharmony_ci } 3288bf80f4bSopenharmony_ci } 3298bf80f4bSopenharmony_ci 3308bf80f4bSopenharmony_ci return modifierCache_.FindAll(); 3318bf80f4bSopenharmony_ci} 3328bf80f4bSopenharmony_ci 3338bf80f4bSopenharmony_ciIAnimationModifier::StepData AnimationState::ApplyStepModifiers(float progress) const 3348bf80f4bSopenharmony_ci{ 3358bf80f4bSopenharmony_ci IAnimationModifier::StepData step(progress); 3368bf80f4bSopenharmony_ci for (auto&& mod : GetModifiers()) { 3378bf80f4bSopenharmony_ci mod->ProcessOnStep(step); 3388bf80f4bSopenharmony_ci } 3398bf80f4bSopenharmony_ci return step; 3408bf80f4bSopenharmony_ci} 3418bf80f4bSopenharmony_ci 3428bf80f4bSopenharmony_ciIAnimationModifier::DurationData AnimationState::ApplyDurationModifiers(TimeSpan duration) const 3438bf80f4bSopenharmony_ci{ 3448bf80f4bSopenharmony_ci using DurationData = IAnimationModifier::DurationData; 3458bf80f4bSopenharmony_ci DurationData durationData; 3468bf80f4bSopenharmony_ci durationData.duration = duration; 3478bf80f4bSopenharmony_ci for (auto&& mod : GetModifiers()) { 3488bf80f4bSopenharmony_ci DurationData data = durationData; 3498bf80f4bSopenharmony_ci if (mod->ProcessOnGetDuration(data)) { 3508bf80f4bSopenharmony_ci durationData = data; 3518bf80f4bSopenharmony_ci } 3528bf80f4bSopenharmony_ci } 3538bf80f4bSopenharmony_ci return durationData; 3548bf80f4bSopenharmony_ci} 3558bf80f4bSopenharmony_ci 3568bf80f4bSopenharmony_ciTimeSpan AnimationState::GetAnimationBaseDuration() const 3578bf80f4bSopenharmony_ci{ 3588bf80f4bSopenharmony_ci if (auto timed = interface_cast<ITimedAnimation>(GetOwner())) { 3598bf80f4bSopenharmony_ci return GetValue(timed->Duration()); 3608bf80f4bSopenharmony_ci } 3618bf80f4bSopenharmony_ci CORE_LOG_W("Cannot update total duration of an animation that does not implement ITimedAnimation"); 3628bf80f4bSopenharmony_ci return TimeSpan::Zero(); 3638bf80f4bSopenharmony_ci} 3648bf80f4bSopenharmony_ci 3658bf80f4bSopenharmony_civoid AnimationState::UpdateTotalDuration() 3668bf80f4bSopenharmony_ci{ 3678bf80f4bSopenharmony_ci if (!params_.totalDuration) { 3688bf80f4bSopenharmony_ci return; 3698bf80f4bSopenharmony_ci } 3708bf80f4bSopenharmony_ci auto durationData = ApplyDurationModifiers(GetAnimationBaseDuration()); 3718bf80f4bSopenharmony_ci state_.duration = durationData; 3728bf80f4bSopenharmony_ci state_.totalDuration = 3738bf80f4bSopenharmony_ci durationData.loopCount > 0 ? durationData.duration * durationData.loopCount : TimeSpan::Infinite(); 3748bf80f4bSopenharmony_ci SetValue(params_.totalDuration, state_.totalDuration); 3758bf80f4bSopenharmony_ci} 3768bf80f4bSopenharmony_ci 3778bf80f4bSopenharmony_cibool AnimationState::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext) 3788bf80f4bSopenharmony_ci{ 3798bf80f4bSopenharmony_ci bool success = false; 3808bf80f4bSopenharmony_ci if (auto attach = interface_pointer_cast<IAttach>(params_.owner)) { 3818bf80f4bSopenharmony_ci if (const auto attachments = interface_cast<IAttachmentContainer>(attach->GetAttachmentContainer(true))) { 3828bf80f4bSopenharmony_ci if (const auto modifier = interface_cast<IAnimationModifier>(attachment)) { 3838bf80f4bSopenharmony_ci if (success = attachments->Attach(attachment, dataContext); success) { 3848bf80f4bSopenharmony_ci if (auto notifyChanged = interface_cast<INotifyOnChange>(modifier)) { 3858bf80f4bSopenharmony_ci notifyChanged->OnChanged()->AddHandler(updateTotalDuration_, uintptr_t(this)); 3868bf80f4bSopenharmony_ci } 3878bf80f4bSopenharmony_ci } 3888bf80f4bSopenharmony_ci UpdateTotalDuration(); 3898bf80f4bSopenharmony_ci } else { 3908bf80f4bSopenharmony_ci // Attaching something else than a modifier 3918bf80f4bSopenharmony_ci return attachments->Attach(attachment, dataContext); 3928bf80f4bSopenharmony_ci } 3938bf80f4bSopenharmony_ci } 3948bf80f4bSopenharmony_ci } 3958bf80f4bSopenharmony_ci return success; 3968bf80f4bSopenharmony_ci} 3978bf80f4bSopenharmony_ci 3988bf80f4bSopenharmony_cibool AnimationState::Detach(const IObject::Ptr& attachment) 3998bf80f4bSopenharmony_ci{ 4008bf80f4bSopenharmony_ci bool success = false; 4018bf80f4bSopenharmony_ci if (auto attach = interface_pointer_cast<IAttach>(params_.owner)) { 4028bf80f4bSopenharmony_ci success = attach->Detach(attachment); 4038bf80f4bSopenharmony_ci if (const auto modifier = interface_cast<IAnimationModifier>(attachment)) { 4048bf80f4bSopenharmony_ci if (auto notifyChanged = interface_cast<INotifyOnChange>(modifier)) { 4058bf80f4bSopenharmony_ci notifyChanged->OnChanged()->RemoveHandler(uintptr_t(this)); 4068bf80f4bSopenharmony_ci } 4078bf80f4bSopenharmony_ci } 4088bf80f4bSopenharmony_ci UpdateTotalDuration(); 4098bf80f4bSopenharmony_ci } 4108bf80f4bSopenharmony_ci return success; 4118bf80f4bSopenharmony_ci} 4128bf80f4bSopenharmony_ci 4138bf80f4bSopenharmony_ci// PropertyAnimationState 4148bf80f4bSopenharmony_ci 4158bf80f4bSopenharmony_ciIInterpolator::Ptr PropertyAnimationState::GetInterpolator() const 4168bf80f4bSopenharmony_ci{ 4178bf80f4bSopenharmony_ci return interpolator_; 4188bf80f4bSopenharmony_ci} 4198bf80f4bSopenharmony_ci 4208bf80f4bSopenharmony_cibool PropertyAnimationState::SetInterpolator(const TypeId& id) 4218bf80f4bSopenharmony_ci{ 4228bf80f4bSopenharmony_ci interpolator_ = id != TypeId {} ? GetObjectRegistry().CreateInterpolator(id) : nullptr; 4238bf80f4bSopenharmony_ci return interpolator_ != nullptr; 4248bf80f4bSopenharmony_ci} 4258bf80f4bSopenharmony_ci 4268bf80f4bSopenharmony_ciAnyReturnValue PropertyAnimationState::EvaluateValue(const EvaluationData& data) const 4278bf80f4bSopenharmony_ci{ 4288bf80f4bSopenharmony_ci if (!data.IsValid()) { 4298bf80f4bSopenharmony_ci return AnyReturn::FAIL; 4308bf80f4bSopenharmony_ci } 4318bf80f4bSopenharmony_ci 4328bf80f4bSopenharmony_ci auto step = ApplyStepModifiers(data.progress); 4338bf80f4bSopenharmony_ci auto progress = step.progress; 4348bf80f4bSopenharmony_ci 4358bf80f4bSopenharmony_ci if (progress <= 0.f) { 4368bf80f4bSopenharmony_ci return data.target->CopyFrom(*data.from); 4378bf80f4bSopenharmony_ci } 4388bf80f4bSopenharmony_ci if (progress >= 1.f) { 4398bf80f4bSopenharmony_ci return data.target->CopyFrom(*data.to); 4408bf80f4bSopenharmony_ci } 4418bf80f4bSopenharmony_ci if (data.curve) { 4428bf80f4bSopenharmony_ci progress = data.curve->Transform(progress); 4438bf80f4bSopenharmony_ci } 4448bf80f4bSopenharmony_ci if (interpolator_) { 4458bf80f4bSopenharmony_ci return interpolator_->Interpolate(*data.target, *data.from, *data.to, progress); 4468bf80f4bSopenharmony_ci } 4478bf80f4bSopenharmony_ci CORE_LOG_W("No interpolator set for animation state"); 4488bf80f4bSopenharmony_ci return AnyReturn::FAIL; 4498bf80f4bSopenharmony_ci} 4508bf80f4bSopenharmony_ci 4518bf80f4bSopenharmony_ci} // namespace Internal 4528bf80f4bSopenharmony_ci 4538bf80f4bSopenharmony_ciMETA_END_NAMESPACE() 454