/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef META_SRC_ANIMATION_H #define META_SRC_ANIMATION_H #include #include #include #include #include #include "../object.h" #include "animation_state.h" #include "staggered_animation_state.h" META_BEGIN_NAMESPACE() namespace Internal { /** * @brief A base class which can be used by generic animation implementations. */ template class BaseAnimationFwd : public Internal::ObjectFwd { static_assert(BASE_NS::is_convertible_v, "BaseAnimationInterface of BaseAnimationFwd must inherit from IAnimation"); using Super = Internal::ObjectFwd; protected: BaseAnimationFwd() = default; ~BaseAnimationFwd() override = default; protected: // IObject BASE_NS::string GetName() const override { return META_ACCESS_PROPERTY_VALUE(Name); } protected: // ILifecycle bool Build(const IMetadata::Ptr& data) override { if (Super::Build(data)) { META_ACCESS_PROPERTY(Name)->SetDefaultValue(Super::GetName()); return GetState().Initialize(BASE_NS::move(GetParams())); } return false; } void Destroy() override { GetState().Uninitialize(); Super::Destroy(); } virtual AnimationState::AnimationStateParams GetParams() = 0; protected: // IContainable IObject::Ptr GetParent() const override { return parent_.lock(); } protected: // IMutableContainable void SetParent(const IObject::Ptr& parent) override { parent_ = parent; } protected: // INamed META_IMPLEMENT_INTERFACE_PROPERTY(INamed, BASE_NS::string, Name) protected: // IAttach bool Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext) override { return GetState().Attach(attachment, dataContext); } bool Detach(const IObject::Ptr& attachment) override { return GetState().Detach(attachment); } protected: // IAnimationInternal void ResetClock() override { GetState().ResetClock(); } bool Move(const IAnimationInternal::MoveParams& move) override { return GetState().Move(move).changed; } void OnAnimationStateChanged(const IAnimationInternal::AnimationStateChangedInfo& info) override { Evaluate(); } void OnEvaluationNeeded() override { Evaluate(); } protected: // IAttachment META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAttachment, IObject::WeakPtr, DataContext) META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAttachment, IAttach::WeakPtr, AttachedTo) bool Attaching(const IAttach::Ptr& target, const IObject::Ptr& dataContext) override { SetValue(META_ACCESS_PROPERTY(AttachedTo), target); SetValue(META_ACCESS_PROPERTY(DataContext), dataContext); return true; } bool Detaching(const IAttach::Ptr& target) override { SetValue(META_ACCESS_PROPERTY(AttachedTo), {}); SetValue(META_ACCESS_PROPERTY(DataContext), {}); return true; } protected: // IAnimation META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, bool, Enabled, true) META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Valid, {}, DEFAULT_PROPERTY_FLAGS_NO_SER) META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, TimeSpan, TotalDuration, {}, DEFAULT_PROPERTY_FLAGS_NO_SER) META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Running, {}, DEFAULT_PROPERTY_FLAGS_NO_SER) META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, float, Progress, {}, DEFAULT_PROPERTY_FLAGS_NO_SER) META_IMPLEMENT_INTERFACE_PROPERTY( IAnimation, IAnimationController::WeakPtr, Controller, {}, DEFAULT_PROPERTY_FLAGS_NO_SER) META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, ICurve1D::Ptr, Curve) void Step(const IClock::ConstPtr& clock) override { GetState().Step(clock); } META_IMPLEMENT_INTERFACE_EVENT(IAnimation, IOnChanged, OnFinished) META_IMPLEMENT_INTERFACE_EVENT(IAnimation, IOnChanged, OnStarted) protected: // INotifyOnChange META_IMPLEMENT_INTERFACE_EVENT(INotifyOnChange, IOnChanged, OnChanged) void NotifyChanged() { META_ACCESS_EVENT(OnChanged)->Invoke(); } protected: virtual void Evaluate() = 0; virtual Internal::AnimationState& GetState() noexcept = 0; private: IObject::WeakPtr parent_; }; template class BaseStartableAnimationFwd : public BaseAnimationFwd { using Super = BaseAnimationFwd; using Super::GetState; protected: // IStartableAnimation void Pause() override { GetState().Pause(); } void Restart() override { GetState().Restart(); } void Seek(float position) override { GetState().Seek(position); } void Start() override { GetState().Start(); } void Stop() override { GetState().Stop(); } void Finish() override { GetState().Finish(); } }; /** * @brief A base class which can be used by animation container implementations. */ template class BaseAnimationContainerFwd : public BaseStartableAnimationFwd { static_assert(BASE_NS::is_convertible_v, "BaseAnimationInterface of BaseAnimationContainerFwd must inherit from IStaggeredAnimation"); using Super = BaseStartableAnimationFwd; using IContainer::SizeType; public: // ILockable void Lock() const override { if (auto lockable = interface_cast(&GetContainer())) { lockable->Lock(); } } void Unlock() const override { if (auto lockable = interface_cast(&GetContainer())) { lockable->Unlock(); } } void LockShared() const override { if (auto lockable = interface_cast(&GetContainer())) { lockable->LockShared(); } } void UnlockShared() const override { if (auto lockable = interface_cast(&GetContainer())) { lockable->UnlockShared(); } } protected: Internal::StaggeredAnimationState& GetState() noexcept override = 0; ReturnError Finalize(IImportFunctions&) override { GetState().ChildrenChanged(); return GenericError::SUCCESS; } public: // IIterable IterationResult Iterate(const IterationParameters& params) override { auto iterable = interface_cast(&GetContainer()); return iterable ? iterable->Iterate(params) : IterationResult::FAILED; } IterationResult Iterate(const IterationParameters& params) const override { const auto iterable = interface_cast(&GetContainer()); return iterable ? iterable->Iterate(params) : IterationResult::FAILED; } public: // IContainer bool Add(const IObject::Ptr& object) override { return GetContainer().Add(object); } bool Insert(SizeType index, const IObject::Ptr& object) override { return GetContainer().Insert(index, object); } bool Remove(SizeType index) override { return GetContainer().Remove(index); } bool Remove(const IObject::Ptr& child) override { return GetContainer().Remove(child); } bool Move(SizeType fromIndex, SizeType toIndex) override { return GetContainer().Move(fromIndex, toIndex); } bool Move(const IObject::Ptr& child, SizeType toIndex) override { return GetContainer().Move(child, toIndex); } bool Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways) override { return GetContainer().Replace(child, replaceWith, addAlways); } BASE_NS::vector GetAll() const override { return GetContainer().GetAll(); } void RemoveAll() override { GetContainer().RemoveAll(); } IObject::Ptr GetAt(SizeType index) const override { return GetContainer().GetAt(index); } SizeType GetSize() const override { return GetContainer().GetSize(); } BASE_NS::vector FindAll(const IContainer::FindOptions& options) const override { return GetContainer().FindAll(options); } IObject::Ptr FindAny(const IContainer::FindOptions& options) const override { return GetContainer().FindAny(options); } IObject::Ptr FindByName(BASE_NS::string_view name) const override { return GetContainer().FindByName(name); } bool IsAncestorOf(const IObject::ConstPtr& object) const override { return GetContainer().IsAncestorOf(object); } META_FORWARD_EVENT(IOnChanged, OnAdded, GetContainer().EventOnAdded()); META_FORWARD_EVENT(IOnChanged, OnRemoved, GetContainer().EventOnRemoved()); META_FORWARD_EVENT(IOnChanged, OnMoved, GetContainer().EventOnMoved()); protected: // IStaggeredAnimation void AddAnimation(const IAnimation::Ptr& animation) override { GetContainer().Add(animation); } void RemoveAnimation(const IAnimation::Ptr& animation) override { GetContainer().Remove(animation); } BASE_NS::vector GetAnimations() const override { return GetContainer().template GetAll(); } protected: virtual IContainer& GetContainer() noexcept = 0; virtual const IContainer& GetContainer() const noexcept = 0; }; /** * @brief A base class which can be used by property animation implementations. */ template class BasePropertyAnimationFwd : public BaseAnimationFwd { static_assert(BASE_NS::is_convertible_v, "BaseAnimationInterface of BasePropertyAnimationFwd must inherit from ITimedAnimation"); using Super = BaseAnimationFwd; protected: BasePropertyAnimationFwd() = default; ~BasePropertyAnimationFwd() override = default; protected: // ILifecycle bool Build(const IMetadata::Ptr& data) override { if (Super::Build(data)) { META_ACCESS_PROPERTY(Property)->OnChanged()->AddHandler( MakeCallback(this, &BasePropertyAnimationFwd::PropertyChanged)); return true; } return false; } protected: // IPropertyAnimation META_IMPLEMENT_INTERFACE_PROPERTY(IPropertyAnimation, IProperty::WeakPtr, Property); protected: // ITimedAnimation META_IMPLEMENT_INTERFACE_PROPERTY(ITimedAnimation, TimeSpan, Duration) protected: // IModifier EvaluationResult ProcessOnGet(IAny& value) override { return EvaluationResult::EVAL_CONTINUE; } EvaluationResult ProcessOnSet(IAny& value, const IAny& current) override { return EvaluationResult::EVAL_CONTINUE; } bool IsCompatible(const TypeId& id) const override { if (auto p = GetTargetProperty()) { return META_NS::IsCompatible(p.property->GetValue(), id); } return false; } Internal::PropertyAnimationState& GetState() noexcept override = 0; protected: ReturnError Finalize(IImportFunctions&) override { GetState().UpdateTotalDuration(); auto p = GetTargetProperty(); GetState().SetInterpolator(p ? p.property->GetTypeId() : TypeId {}); SetValue(Super::META_ACCESS_PROPERTY(Valid), p); return GenericError::SUCCESS; } protected: struct TargetProperty { IProperty::Ptr property; IStackProperty::Ptr stack; /* NOLINTNEXTLINE(google-explicit-constructor) */ operator bool() const noexcept { return property && stack; } }; void PropertyChanged() { auto p = GetTargetProperty(); this->GetState().SetInterpolator(p ? p.property->GetTypeId() : TypeId {}); SetValue(Super::META_ACCESS_PROPERTY(Valid), p); OnPropertyChanged(p, property_.lock()); property_ = p.stack; } virtual void OnPropertyChanged(const TargetProperty& property, const IStackProperty::Ptr& previous) = 0; TargetProperty GetTargetProperty() const noexcept { auto p = META_ACCESS_PROPERTY_VALUE(Property).lock(); return { p, interface_pointer_cast(p) }; } private: IStackProperty::WeakPtr property_; }; /** * @brief A base class which can be used by property animation implementations. */ template class PropertyAnimationFwd : public BasePropertyAnimationFwd { using Super = BasePropertyAnimationFwd; protected: PropertyAnimationFwd() = default; ~PropertyAnimationFwd() override = default; protected: // Note covariance Internal::PropertyAnimationState& GetState() noexcept override { return state_; } private: Internal::PropertyAnimationState state_; }; } // namespace Internal META_END_NAMESPACE() #endif // META_SRC_ANIMATION_H