1 /*
2  * Copyright (c) 2023 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_ANIMATION_BEZIER_VARIABLE_VELOCITY_MOTION_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_ANIMATION_BEZIER_VARIABLE_VELOCITY_MOTION_H
18 #include "base/geometry/dimension.h"
19 #include "core/animation/curves.h"
20 #include "core/animation/motion.h"
21 
22 namespace OHOS::Ace {
23 
24 static constexpr Dimension HOT_ZONE_HEIGHT_VP_DIM = 59.0_vp;
25 static constexpr Dimension HOT_ZONE_WIDTH_VP_DIM = 26.0_vp;
26 using MotionCompleteCallbck = std::function<bool(float)>;
27 constexpr float UNIT_CONVERT = 1000.0f;
28 constexpr float MAX_SPEED = 2400.0f;
29 
30 class ACE_EXPORT BezierVariableVelocityMotion : public Motion {
31     DECLARE_ACE_TYPE(BezierVariableVelocityMotion, Motion);
32 
33 public:
BezierVariableVelocityMotion(float offsetPct,MotionCompleteCallbck && complete)34     BezierVariableVelocityMotion(float offsetPct, MotionCompleteCallbck&& complete)
35         : complete_(complete), offsetPct_(offsetPct)
36     {
37         Reset(offsetPct_, true);
38     }
39     /**
40      * @description: Get the roll distance
41      * @return The scroll distance notified to the listener
42      */
GetCurrentPosition()43     double GetCurrentPosition() override
44     {
45         return Positive(offsetPct_) ? scrollOffset_ : Negative(offsetPct_) ? -scrollOffset_ : 0;
46     }
47 
GetCurrentVelocity()48     double GetCurrentVelocity() override
49     {
50         return velocity_;
51     }
52     /**
53      * @description: By adding a callback, it is up to the listener to decide whether to stop the motion
54      * @return True stop
55      */
IsCompleted()56     bool IsCompleted() override
57     {
58         if (complete_) {
59             return complete_(offsetPct_);
60         }
61         return true;
62     }
63 
64     /**
65      * @description: The ratio of the hot zone offset to the maximum hot zone offset is used as an input parameter of
66      * bezier, resulting in an output, which is the proportion of velocity.
67      * The farther away you are from the outer edge of the hot zone, the greater the velocity
68      * @param {float} offsetPct
69      * @return Scroll speed
70      */
ComputeVelocity(float offsetPct)71     double ComputeVelocity(float offsetPct)
72     {
73         return Curves::SHARP->MoveInternal(std::abs(offsetPct)) * MAX_SPEED;
74     }
75 
GetMotionType()76     std::string GetMotionType() const override
77     {
78         return "bezier variable velocity";
79     }
80 
81     /**
82      * @description: Each subclass of scrollable component should override this method to perform motion in each
83      * timestamp. This function is called in motion's OnTimestampChanged function, where inform the listener of the
84      * distance of rolling
85      * @param {float} offsetTime Time offset, continuously growing, with irregular intervals
86      * @return None
87      */
Move(float offsetTime)88     void Move(float offsetTime) override
89     {
90         scrollOffset_ = velocity_ * (offsetTime - lastOffsetTime_) / UNIT_CONVERT;
91         lastOffsetTime_ = offsetTime;
92     }
93 
94     /**
95      * @description: Resets the hot spot offset to change the current speed, ultimately for variable speed scrolling
96      * @param {float} offsetPct Hot Spot Offset percent. The ratio of its maximum offset to the hot zone is used as an
97      * input parameter to bezier
98      * @param {float} reset_time. When the animation starts, it needs to be reset
99      * @return None
100      */
101     void Reset(float offsetPct, bool reset_time = false)
102     {
103         offsetPct_ = offsetPct;
104         velocity_ = ComputeVelocity(offsetPct_);
105         if (reset_time) {
106             lastOffsetTime_ = 0.0f;
107         }
108     }
109 
110     /**
111      * @description:  reinitialize BezierVariableVelocityMotion
112      * @param {float} offsetPct
113      * @return {*}
114      */
ReInit(float offsetPct)115     void ReInit(float offsetPct)
116     {
117         Reset(offsetPct, true);
118     }
119 
120 private:
121     // Tells the listener how far they need to roll, in px
122     float scrollOffset_ = 0.0f;
123     MotionCompleteCallbck complete_;
124     // It is used to record the current speed, and different speeds can be passed in through the reset function, so that
125     // the speed can be changed
126     float velocity_ = 0.0f;
127     // The hot zone offset corresponds to a fixed velocity one-to-one by the bezier.
128     // It is also possible to implement a generic class with velocity as an input parameter, but this is not necessary
129     // at the moment
130     float offsetPct_ = 0.0f;
131     // Record the last time given by the move function
132     float lastOffsetTime_ = 0.0f;
133 };
134 } // namespace OHOS::Ace
135 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_ANIMATION_BEZIER_VARIABLE_VELOCITY_MOTION_H