1a3e0fd82Sopenharmony_ci/*
2a3e0fd82Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3a3e0fd82Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4a3e0fd82Sopenharmony_ci * you may not use this file except in compliance with the License.
5a3e0fd82Sopenharmony_ci * You may obtain a copy of the License at
6a3e0fd82Sopenharmony_ci *
7a3e0fd82Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8a3e0fd82Sopenharmony_ci *
9a3e0fd82Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10a3e0fd82Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11a3e0fd82Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a3e0fd82Sopenharmony_ci * See the License for the specific language governing permissions and
13a3e0fd82Sopenharmony_ci * limitations under the License.
14a3e0fd82Sopenharmony_ci */
15a3e0fd82Sopenharmony_ci
16a3e0fd82Sopenharmony_ci#include "components/ui_abstract_scroll.h"
17a3e0fd82Sopenharmony_ci
18a3e0fd82Sopenharmony_ci#include "securec.h"
19a3e0fd82Sopenharmony_ci
20a3e0fd82Sopenharmony_ci#include "animator/interpolation.h"
21a3e0fd82Sopenharmony_ci#include "common/screen.h"
22a3e0fd82Sopenharmony_ci#include "components/ui_abstract_scroll_bar.h"
23a3e0fd82Sopenharmony_ci#include "components/ui_arc_scroll_bar.h"
24a3e0fd82Sopenharmony_ci#include "components/ui_box_scroll_bar.h"
25a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
26a3e0fd82Sopenharmony_ci#include "graphic_timer.h"
27a3e0fd82Sopenharmony_ci#endif
28a3e0fd82Sopenharmony_ci
29a3e0fd82Sopenharmony_cinamespace OHOS {
30a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
31a3e0fd82Sopenharmony_ciclass BarEaseInOutAnimator final : public AnimatorCallback {
32a3e0fd82Sopenharmony_cipublic:
33a3e0fd82Sopenharmony_ci    BarEaseInOutAnimator() = delete;
34a3e0fd82Sopenharmony_ci    BarEaseInOutAnimator(const BarEaseInOutAnimator&) = delete;
35a3e0fd82Sopenharmony_ci    BarEaseInOutAnimator& operator=(const BarEaseInOutAnimator&) = delete;
36a3e0fd82Sopenharmony_ci    BarEaseInOutAnimator(BarEaseInOutAnimator&&) = delete;
37a3e0fd82Sopenharmony_ci    BarEaseInOutAnimator& operator=(BarEaseInOutAnimator&&) = delete;
38a3e0fd82Sopenharmony_ci
39a3e0fd82Sopenharmony_ci    explicit BarEaseInOutAnimator(UIAbstractScroll& scrollView)
40a3e0fd82Sopenharmony_ci        : scrollView_(scrollView),
41a3e0fd82Sopenharmony_ci          timer_(APPEAR_PERIOD, TimerCb, this),
42a3e0fd82Sopenharmony_ci          animator_(this, nullptr, ANIMATOR_DURATION, false)
43a3e0fd82Sopenharmony_ci    {
44a3e0fd82Sopenharmony_ci    }
45a3e0fd82Sopenharmony_ci
46a3e0fd82Sopenharmony_ci    ~BarEaseInOutAnimator()
47a3e0fd82Sopenharmony_ci    {
48a3e0fd82Sopenharmony_ci        timer_.Stop();
49a3e0fd82Sopenharmony_ci        animator_.Stop();
50a3e0fd82Sopenharmony_ci    }
51a3e0fd82Sopenharmony_ci
52a3e0fd82Sopenharmony_ci    void RefreshBar()
53a3e0fd82Sopenharmony_ci    {
54a3e0fd82Sopenharmony_ci        if (animator_.GetState() == Animator::START) {
55a3e0fd82Sopenharmony_ci            if (!isEaseIn_) {
56a3e0fd82Sopenharmony_ci                animator_.SetRunTime(ANIMATOR_DURATION - animator_.GetRunTime());
57a3e0fd82Sopenharmony_ci            }
58a3e0fd82Sopenharmony_ci        } else if (scrollView_.yScrollBar_->GetOpacity() == OPA_TRANSPARENT) {
59a3e0fd82Sopenharmony_ci            animator_.Start();
60a3e0fd82Sopenharmony_ci        } else {
61a3e0fd82Sopenharmony_ci            timer_.Start(); // updates the start time of timer, ensuring that timer is triggered two seconds after the
62a3e0fd82Sopenharmony_ci                            // last operation
63a3e0fd82Sopenharmony_ci        }
64a3e0fd82Sopenharmony_ci        isEaseIn_ = true;
65a3e0fd82Sopenharmony_ci    }
66a3e0fd82Sopenharmony_ci
67a3e0fd82Sopenharmony_ciprivate:
68a3e0fd82Sopenharmony_ci    void Callback(UIView* view) override
69a3e0fd82Sopenharmony_ci    {
70a3e0fd82Sopenharmony_ci        uint8_t opa = OPA_OPAQUE * animator_.GetRunTime() / ANIMATOR_DURATION;
71a3e0fd82Sopenharmony_ci        if (!isEaseIn_) {
72a3e0fd82Sopenharmony_ci            opa = OPA_OPAQUE - opa;
73a3e0fd82Sopenharmony_ci        }
74a3e0fd82Sopenharmony_ci        float bezielY = opa;
75a3e0fd82Sopenharmony_ci        bezielY =
76a3e0fd82Sopenharmony_ci            Interpolation::GetBezierY(bezielY / OPA_OPAQUE, BEZIER_CONTROL_POINT_X_1, 0, BEZIER_CONTROL_POINT_X_2, 1);
77a3e0fd82Sopenharmony_ci        opa = static_cast<uint8_t>(bezielY * opa);
78a3e0fd82Sopenharmony_ci        if (scrollView_.yScrollBarVisible_) {
79a3e0fd82Sopenharmony_ci            scrollView_.yScrollBar_->SetOpacity(opa);
80a3e0fd82Sopenharmony_ci        }
81a3e0fd82Sopenharmony_ci        if (scrollView_.xScrollBarVisible_) {
82a3e0fd82Sopenharmony_ci            scrollView_.xScrollBar_->SetOpacity(opa);
83a3e0fd82Sopenharmony_ci        }
84a3e0fd82Sopenharmony_ci        scrollView_.Invalidate();
85a3e0fd82Sopenharmony_ci    }
86a3e0fd82Sopenharmony_ci
87a3e0fd82Sopenharmony_ci    void OnStop(UIView& view) override
88a3e0fd82Sopenharmony_ci    {
89a3e0fd82Sopenharmony_ci        if (isEaseIn_) {
90a3e0fd82Sopenharmony_ci            if (scrollView_.yScrollBarVisible_) {
91a3e0fd82Sopenharmony_ci                scrollView_.yScrollBar_->SetOpacity(OPA_OPAQUE);
92a3e0fd82Sopenharmony_ci            }
93a3e0fd82Sopenharmony_ci            if (Screen::GetInstance().GetScreenShape() == ScreenShape::RECTANGLE && scrollView_.xScrollBarVisible_) {
94a3e0fd82Sopenharmony_ci                scrollView_.xScrollBar_->SetOpacity(OPA_OPAQUE);
95a3e0fd82Sopenharmony_ci            }
96a3e0fd82Sopenharmony_ci            timer_.Start(); // The timer is triggered when animation stops.
97a3e0fd82Sopenharmony_ci        } else {
98a3e0fd82Sopenharmony_ci            if (scrollView_.yScrollBarVisible_) {
99a3e0fd82Sopenharmony_ci                scrollView_.yScrollBar_->SetOpacity(OPA_TRANSPARENT);
100a3e0fd82Sopenharmony_ci            }
101a3e0fd82Sopenharmony_ci            if (scrollView_.xScrollBarVisible_) {
102a3e0fd82Sopenharmony_ci                scrollView_.xScrollBar_->SetOpacity(OPA_TRANSPARENT);
103a3e0fd82Sopenharmony_ci            }
104a3e0fd82Sopenharmony_ci        }
105a3e0fd82Sopenharmony_ci        scrollView_.Invalidate();
106a3e0fd82Sopenharmony_ci    }
107a3e0fd82Sopenharmony_ci
108a3e0fd82Sopenharmony_ci    static void TimerCb(void* arg)
109a3e0fd82Sopenharmony_ci    {
110a3e0fd82Sopenharmony_ci        BarEaseInOutAnimator* barAnimator = reinterpret_cast<BarEaseInOutAnimator*>(arg);
111a3e0fd82Sopenharmony_ci        barAnimator->isEaseIn_ = false;
112a3e0fd82Sopenharmony_ci        barAnimator->animator_.Start();
113a3e0fd82Sopenharmony_ci    }
114a3e0fd82Sopenharmony_ci    static constexpr uint16_t ANIMATOR_DURATION = 250;
115a3e0fd82Sopenharmony_ci    static constexpr uint16_t APPEAR_PERIOD = 2000;
116a3e0fd82Sopenharmony_ci    static constexpr float BEZIER_CONTROL_POINT_X_1 = 0.33f;
117a3e0fd82Sopenharmony_ci    static constexpr float BEZIER_CONTROL_POINT_X_2 = 0.67f;
118a3e0fd82Sopenharmony_ci    UIAbstractScroll& scrollView_;
119a3e0fd82Sopenharmony_ci    GraphicTimer timer_;
120a3e0fd82Sopenharmony_ci    Animator animator_;
121a3e0fd82Sopenharmony_ci    bool isEaseIn_ = true;
122a3e0fd82Sopenharmony_ci};
123a3e0fd82Sopenharmony_ci#endif
124a3e0fd82Sopenharmony_ci
125a3e0fd82Sopenharmony_ciUIAbstractScroll::UIAbstractScroll()
126a3e0fd82Sopenharmony_ci    : direction_(VERTICAL),
127a3e0fd82Sopenharmony_ci      deltaIndex_(0),
128a3e0fd82Sopenharmony_ci      rotateIndex_(0),
129a3e0fd82Sopenharmony_ci      reserve_(0),
130a3e0fd82Sopenharmony_ci      easingFunc_(EasingEquation::CubicEaseOut),
131a3e0fd82Sopenharmony_ci      scrollAnimator_(&animatorCallback_, this, 0, true),
132a3e0fd82Sopenharmony_ci      scrollBarSide_(SCROLL_BAR_RIGHT_SIDE),
133a3e0fd82Sopenharmony_ci      scrollBarCenter_({0, 0}),
134a3e0fd82Sopenharmony_ci      scrollBarCenterSetFlag_(false)
135a3e0fd82Sopenharmony_ci{
136a3e0fd82Sopenharmony_ci#if defined(ENABLE_FOCUS_MANAGER) && ENABLE_FOCUS_MANAGER
137a3e0fd82Sopenharmony_ci    focusable_ = true;
138a3e0fd82Sopenharmony_ci#endif
139a3e0fd82Sopenharmony_ci#if defined(ENABLE_ROTATE_INPUT) && ENABLE_ROTATE_INPUT
140a3e0fd82Sopenharmony_ci    rotateFactor_ = DEFAULT_SCROLL_VIEW_ROTATE_FACTOR;
141a3e0fd82Sopenharmony_ci    rotateThrowthreshold_ = ABSTRACT_ROTATE_THROW_THRESHOLD;
142a3e0fd82Sopenharmony_ci    rotateAccCoefficient_ = ABSTRACT_ROTATE_DISTANCE_COEFF;
143a3e0fd82Sopenharmony_ci    isRotating_ = false;
144a3e0fd82Sopenharmony_ci#endif
145a3e0fd82Sopenharmony_ci    isViewGroup_ = true;
146a3e0fd82Sopenharmony_ci    touchable_ = true;
147a3e0fd82Sopenharmony_ci    draggable_ = true;
148a3e0fd82Sopenharmony_ci    dragParentInstead_ = false;
149a3e0fd82Sopenharmony_ci}
150a3e0fd82Sopenharmony_ci
151a3e0fd82Sopenharmony_ciUIAbstractScroll::~UIAbstractScroll()
152a3e0fd82Sopenharmony_ci{
153a3e0fd82Sopenharmony_ci#if defined(DEFAULT_ANIMATION) && DEFAULT_ANIMATION
154a3e0fd82Sopenharmony_ci    if (barEaseInOutAnimator_ != nullptr) {
155a3e0fd82Sopenharmony_ci        delete barEaseInOutAnimator_;
156a3e0fd82Sopenharmony_ci        barEaseInOutAnimator_ = nullptr;
157a3e0fd82Sopenharmony_ci    }
158a3e0fd82Sopenharmony_ci#endif
159a3e0fd82Sopenharmony_ci    if (xScrollBar_ != nullptr) {
160a3e0fd82Sopenharmony_ci        delete xScrollBar_;
161a3e0fd82Sopenharmony_ci        xScrollBar_ = nullptr;
162a3e0fd82Sopenharmony_ci    }
163a3e0fd82Sopenharmony_ci    if (yScrollBar_ != nullptr) {
164a3e0fd82Sopenharmony_ci        delete yScrollBar_;
165a3e0fd82Sopenharmony_ci        yScrollBar_ = nullptr;
166a3e0fd82Sopenharmony_ci    }
167a3e0fd82Sopenharmony_ci}
168a3e0fd82Sopenharmony_ci
169a3e0fd82Sopenharmony_civoid UIAbstractScroll::MoveChildByOffset(int16_t offsetX, int16_t offsetY)
170a3e0fd82Sopenharmony_ci{
171a3e0fd82Sopenharmony_ci    if ((offsetX == 0) && (offsetY == 0)) {
172a3e0fd82Sopenharmony_ci        return;
173a3e0fd82Sopenharmony_ci    }
174a3e0fd82Sopenharmony_ci    UIView* view = GetChildrenHead();
175a3e0fd82Sopenharmony_ci    while (view != nullptr) {
176a3e0fd82Sopenharmony_ci        int16_t x = view->GetX() + offsetX;
177a3e0fd82Sopenharmony_ci        int16_t y = view->GetY() + offsetY;
178a3e0fd82Sopenharmony_ci        view->SetPosition(x, y);
179a3e0fd82Sopenharmony_ci        view = view->GetNextSibling();
180a3e0fd82Sopenharmony_ci    }
181a3e0fd82Sopenharmony_ci    Invalidate();
182a3e0fd82Sopenharmony_ci}
183a3e0fd82Sopenharmony_ci
184a3e0fd82Sopenharmony_ciint16_t UIAbstractScroll::GetMaxDelta() const
185a3e0fd82Sopenharmony_ci{
186a3e0fd82Sopenharmony_ci    int16_t result = 0;
187a3e0fd82Sopenharmony_ci    for (int16_t i = 0; i < MAX_DELTA_SIZE; i++) {
188a3e0fd82Sopenharmony_ci        if (result < MATH_ABS(lastDelta_[i])) {
189a3e0fd82Sopenharmony_ci            result = MATH_ABS(lastDelta_[i]);
190a3e0fd82Sopenharmony_ci        }
191a3e0fd82Sopenharmony_ci    }
192a3e0fd82Sopenharmony_ci    return result;
193a3e0fd82Sopenharmony_ci}
194a3e0fd82Sopenharmony_ci
195a3e0fd82Sopenharmony_ciint16_t UIAbstractScroll::GetMaxRotate() const
196a3e0fd82Sopenharmony_ci{
197a3e0fd82Sopenharmony_ci    int16_t result = 0;
198a3e0fd82Sopenharmony_ci    for (int16_t i = 0; i < MAX_DELTA_SIZE; i++) {
199a3e0fd82Sopenharmony_ci        if (MATH_ABS(result) < MATH_ABS(lastRotate_[i])) {
200a3e0fd82Sopenharmony_ci            result = lastRotate_[i];
201a3e0fd82Sopenharmony_ci        }
202a3e0fd82Sopenharmony_ci    }
203a3e0fd82Sopenharmony_ci    return result;
204a3e0fd82Sopenharmony_ci}
205a3e0fd82Sopenharmony_ci
206a3e0fd82Sopenharmony_civoid UIAbstractScroll::InitDelta()
207a3e0fd82Sopenharmony_ci{
208a3e0fd82Sopenharmony_ci    if (memset_s(lastDelta_, sizeof(lastDelta_), 0, sizeof(lastDelta_)) != EOK) {
209a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("memset_s error");
210a3e0fd82Sopenharmony_ci    }
211a3e0fd82Sopenharmony_ci}
212a3e0fd82Sopenharmony_ci
213a3e0fd82Sopenharmony_civoid UIAbstractScroll::InitRotate()
214a3e0fd82Sopenharmony_ci{
215a3e0fd82Sopenharmony_ci    if (memset_s(lastRotate_, sizeof(lastRotate_), 0, sizeof(lastRotate_)) != EOK) {
216a3e0fd82Sopenharmony_ci        GRAPHIC_LOGE("memset_s error");
217a3e0fd82Sopenharmony_ci    }
218a3e0fd82Sopenharmony_ci}
219a3e0fd82Sopenharmony_ci
220a3e0fd82Sopenharmony_civoid UIAbstractScroll::StopAnimator()
221a3e0fd82Sopenharmony_ci{
222a3e0fd82Sopenharmony_ci    scrollAnimator_.Stop();
223a3e0fd82Sopenharmony_ci    animatorCallback_.ResetCallback();
224a3e0fd82Sopenharmony_ci    isDragging_ = false;
225a3e0fd82Sopenharmony_ci}
226a3e0fd82Sopenharmony_ci
227a3e0fd82Sopenharmony_cibool UIAbstractScroll::DragThrowAnimator(Point currentPos, Point lastPos, uint8_t dragDirection, bool dragBack)
228a3e0fd82Sopenharmony_ci{
229a3e0fd82Sopenharmony_ci    if (!throwDrag_ && (reboundSize_ == 0)) {
230a3e0fd82Sopenharmony_ci        return false;
231a3e0fd82Sopenharmony_ci    }
232a3e0fd82Sopenharmony_ci    int16_t dragDistanceX = 0;
233a3e0fd82Sopenharmony_ci    int16_t dragDistanceY = 0;
234a3e0fd82Sopenharmony_ci    if (throwDrag_) {
235a3e0fd82Sopenharmony_ci        CalculateDragDistance(currentPos, lastPos, dragDirection, dragDistanceX, dragDistanceY);
236a3e0fd82Sopenharmony_ci    }
237a3e0fd82Sopenharmony_ci    if (reboundSize_ != 0) {
238a3e0fd82Sopenharmony_ci        CalculateReboundDistance(dragDistanceX, dragDistanceY);
239a3e0fd82Sopenharmony_ci    }
240a3e0fd82Sopenharmony_ci
241a3e0fd82Sopenharmony_ci    if (!dragBack) {
242a3e0fd82Sopenharmony_ci        FixDistance(dragDistanceX, dragDistanceY);
243a3e0fd82Sopenharmony_ci    }
244a3e0fd82Sopenharmony_ci
245a3e0fd82Sopenharmony_ci    StartAnimator(dragDistanceX, dragDistanceY);
246a3e0fd82Sopenharmony_ci    return true;
247a3e0fd82Sopenharmony_ci}
248a3e0fd82Sopenharmony_ci
249a3e0fd82Sopenharmony_civoid UIAbstractScroll::StartAnimator(int16_t dragDistanceX, int16_t dragDistanceY)
250a3e0fd82Sopenharmony_ci{
251a3e0fd82Sopenharmony_ci    int16_t dragTimes = MATH_MAX(MATH_ABS(dragDistanceX), MATH_ABS(dragDistanceY)) / DRAG_TIMES_COEFFICIENT;
252a3e0fd82Sopenharmony_ci    if (dragTimes < MIN_DRAG_TIMES) {
253a3e0fd82Sopenharmony_ci        dragTimes = MIN_DRAG_TIMES;
254a3e0fd82Sopenharmony_ci    }
255a3e0fd82Sopenharmony_ci    animatorCallback_.ResetCallback();
256a3e0fd82Sopenharmony_ci    animatorCallback_.SetDragStartValue(0, 0);
257a3e0fd82Sopenharmony_ci    animatorCallback_.SetDragEndValue(dragDistanceX, dragDistanceY);
258a3e0fd82Sopenharmony_ci    animatorCallback_.SetDragTimes(dragTimes * DRAG_ACC_FACTOR / GetDragACCLevel());
259a3e0fd82Sopenharmony_ci    scrollAnimator_.Start();
260a3e0fd82Sopenharmony_ci}
261a3e0fd82Sopenharmony_ci
262a3e0fd82Sopenharmony_civoid UIAbstractScroll::CalculateDragDistance(Point currentPos,
263a3e0fd82Sopenharmony_ci                                             Point lastPos,
264a3e0fd82Sopenharmony_ci                                             uint8_t dragDirection,
265a3e0fd82Sopenharmony_ci                                             int16_t& dragDistanceX,
266a3e0fd82Sopenharmony_ci                                             int16_t& dragDistanceY)
267a3e0fd82Sopenharmony_ci{
268a3e0fd82Sopenharmony_ci    if ((direction_ == VERTICAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
269a3e0fd82Sopenharmony_ci        dragDistanceY = currentPos.y - lastPos.y;
270a3e0fd82Sopenharmony_ci        if (isRotating_) {
271a3e0fd82Sopenharmony_ci            dragDistanceY *= rotateAccCoefficient_;
272a3e0fd82Sopenharmony_ci        } else {
273a3e0fd82Sopenharmony_ci            dragDistanceY *= DRAG_DISTANCE_COEFFICIENT;
274a3e0fd82Sopenharmony_ci            if (dragDistanceY > 0 || (dragDistanceY == 0 && dragDirection == DragEvent::DIRECTION_TOP_TO_BOTTOM)) {
275a3e0fd82Sopenharmony_ci                dragDistanceY += GetMaxDelta() * GetSwipeACCLevel() / DRAG_ACC_FACTOR;
276a3e0fd82Sopenharmony_ci            } else if (dragDistanceY < 0 ||
277a3e0fd82Sopenharmony_ci                       (dragDistanceY == 0 && dragDirection == DragEvent::DIRECTION_BOTTOM_TO_TOP)) {
278a3e0fd82Sopenharmony_ci                dragDistanceY -= GetMaxDelta() * GetSwipeACCLevel() / DRAG_ACC_FACTOR;
279a3e0fd82Sopenharmony_ci            }
280a3e0fd82Sopenharmony_ci        }
281a3e0fd82Sopenharmony_ci    }
282a3e0fd82Sopenharmony_ci
283a3e0fd82Sopenharmony_ci    if ((direction_ == HORIZONTAL) || (direction_ == HORIZONTAL_AND_VERTICAL)) {
284a3e0fd82Sopenharmony_ci        dragDistanceX = currentPos.x - lastPos.x;
285a3e0fd82Sopenharmony_ci        if (isRotating_) {
286a3e0fd82Sopenharmony_ci            dragDistanceX *= rotateAccCoefficient_;
287a3e0fd82Sopenharmony_ci        } else {
288a3e0fd82Sopenharmony_ci            dragDistanceX *= DRAG_DISTANCE_COEFFICIENT;
289a3e0fd82Sopenharmony_ci            if (dragDistanceX > 0 || (dragDistanceX == 0 && dragDirection == DragEvent::DIRECTION_LEFT_TO_RIGHT)) {
290a3e0fd82Sopenharmony_ci                dragDistanceX += GetMaxDelta() * GetSwipeACCLevel() / DRAG_ACC_FACTOR;
291a3e0fd82Sopenharmony_ci            } else if (dragDistanceX < 0 ||
292a3e0fd82Sopenharmony_ci                       (dragDistanceX == 0 && dragDirection == DragEvent::DIRECTION_RIGHT_TO_LEFT)) {
293a3e0fd82Sopenharmony_ci                dragDistanceX -= GetMaxDelta() * GetSwipeACCLevel() / DRAG_ACC_FACTOR;
294a3e0fd82Sopenharmony_ci            }
295a3e0fd82Sopenharmony_ci        }
296a3e0fd82Sopenharmony_ci    }
297a3e0fd82Sopenharmony_ci
298a3e0fd82Sopenharmony_ci    if (maxScrollDistance_ != 0) {
299a3e0fd82Sopenharmony_ci        if (MATH_ABS(dragDistanceY) > maxScrollDistance_) {
300a3e0fd82Sopenharmony_ci            int16_t calculatedValue = (dragDistanceY > 0) ? 1 : -1;
301a3e0fd82Sopenharmony_ci            dragDistanceY = calculatedValue * maxScrollDistance_;
302a3e0fd82Sopenharmony_ci        }
303a3e0fd82Sopenharmony_ci        if (MATH_ABS(dragDistanceX) > maxScrollDistance_) {
304a3e0fd82Sopenharmony_ci            int16_t calculatedValue = (dragDistanceX > 0) ? 1 : -1;
305a3e0fd82Sopenharmony_ci            dragDistanceX = calculatedValue * maxScrollDistance_;
306a3e0fd82Sopenharmony_ci        }
307a3e0fd82Sopenharmony_ci    }
308a3e0fd82Sopenharmony_ci}
309a3e0fd82Sopenharmony_ci
310a3e0fd82Sopenharmony_civoid UIAbstractScroll::ListAnimatorCallback::Callback(UIView* view)
311a3e0fd82Sopenharmony_ci{
312a3e0fd82Sopenharmony_ci    if (view == nullptr) {
313a3e0fd82Sopenharmony_ci        return;
314a3e0fd82Sopenharmony_ci    }
315a3e0fd82Sopenharmony_ci
316a3e0fd82Sopenharmony_ci    UIAbstractScroll* scrollView = static_cast<UIAbstractScroll*>(view);
317a3e0fd82Sopenharmony_ci    scrollView->isDragging_ = true;
318a3e0fd82Sopenharmony_ci    curtTime_++;
319a3e0fd82Sopenharmony_ci    if (curtTime_ <= dragTimes_) {
320a3e0fd82Sopenharmony_ci        bool needStopX = false;
321a3e0fd82Sopenharmony_ci        bool needStopY = false;
322a3e0fd82Sopenharmony_ci        if (startValueY_ != endValueY_) {
323a3e0fd82Sopenharmony_ci            int16_t actY = scrollView->easingFunc_(startValueY_, endValueY_, curtTime_, dragTimes_);
324a3e0fd82Sopenharmony_ci            if (!scrollView->DragYInner(actY - previousValueY_)) {
325a3e0fd82Sopenharmony_ci                needStopY = true;
326a3e0fd82Sopenharmony_ci            }
327a3e0fd82Sopenharmony_ci            previousValueY_ = actY;
328a3e0fd82Sopenharmony_ci        } else {
329a3e0fd82Sopenharmony_ci            needStopY = true;
330a3e0fd82Sopenharmony_ci        }
331a3e0fd82Sopenharmony_ci        if (startValueX_ != endValueX_) {
332a3e0fd82Sopenharmony_ci            int16_t actX = scrollView->easingFunc_(startValueX_, endValueX_, curtTime_, dragTimes_);
333a3e0fd82Sopenharmony_ci            if (!scrollView->DragXInner(actX - previousValueX_)) {
334a3e0fd82Sopenharmony_ci                needStopX = true;
335a3e0fd82Sopenharmony_ci            }
336a3e0fd82Sopenharmony_ci            previousValueX_ = actX;
337a3e0fd82Sopenharmony_ci        } else {
338a3e0fd82Sopenharmony_ci            needStopX = true;
339a3e0fd82Sopenharmony_ci        }
340a3e0fd82Sopenharmony_ci        if (needStopX && needStopY) {
341a3e0fd82Sopenharmony_ci            scrollView->StopAnimator();
342a3e0fd82Sopenharmony_ci        }
343a3e0fd82Sopenharmony_ci    } else {
344a3e0fd82Sopenharmony_ci        scrollView->StopAnimator();
345a3e0fd82Sopenharmony_ci    }
346a3e0fd82Sopenharmony_ci}
347a3e0fd82Sopenharmony_ci
348a3e0fd82Sopenharmony_ci#if ENABLE_ROTATE_INPUT
349a3e0fd82Sopenharmony_cibool UIAbstractScroll::OnRotateStartEvent(const RotateEvent& event)
350a3e0fd82Sopenharmony_ci{
351a3e0fd82Sopenharmony_ci    isRotating_ = true;
352a3e0fd82Sopenharmony_ci    if (scrollAnimator_.GetState() != Animator::STOP) {
353a3e0fd82Sopenharmony_ci        UIAbstractScroll::StopAnimator();
354a3e0fd82Sopenharmony_ci    }
355a3e0fd82Sopenharmony_ci    return UIView::OnRotateStartEvent(event);
356a3e0fd82Sopenharmony_ci}
357a3e0fd82Sopenharmony_ci
358a3e0fd82Sopenharmony_cibool UIAbstractScroll::OnRotateEvent(const RotateEvent& event)
359a3e0fd82Sopenharmony_ci{
360a3e0fd82Sopenharmony_ci    int16_t rotateLen = static_cast<int16_t>(event.GetRotate() * rotateFactor_);
361a3e0fd82Sopenharmony_ci    RefreshRotate(rotateLen);
362a3e0fd82Sopenharmony_ci    if (direction_ == HORIZONTAL) {
363a3e0fd82Sopenharmony_ci        DragXInner(rotateLen);
364a3e0fd82Sopenharmony_ci    } else {
365a3e0fd82Sopenharmony_ci        DragYInner(rotateLen);
366a3e0fd82Sopenharmony_ci    }
367a3e0fd82Sopenharmony_ci    return UIView::OnRotateEvent(event);
368a3e0fd82Sopenharmony_ci}
369a3e0fd82Sopenharmony_ci
370a3e0fd82Sopenharmony_cibool UIAbstractScroll::OnRotateEndEvent(const RotateEvent& event)
371a3e0fd82Sopenharmony_ci{
372a3e0fd82Sopenharmony_ci    InitDelta();
373a3e0fd82Sopenharmony_ci
374a3e0fd82Sopenharmony_ci    uint8_t dir;
375a3e0fd82Sopenharmony_ci    int16_t lastRotateLen = GetMaxRotate();
376a3e0fd82Sopenharmony_ci    if (direction_ == HORIZONTAL) {
377a3e0fd82Sopenharmony_ci        dir = (lastRotateLen >= 0) ? DragEvent::DIRECTION_LEFT_TO_RIGHT : DragEvent::DIRECTION_RIGHT_TO_LEFT;
378a3e0fd82Sopenharmony_ci    } else {
379a3e0fd82Sopenharmony_ci        dir = (lastRotateLen >= 0) ? DragEvent::DIRECTION_TOP_TO_BOTTOM : DragEvent::DIRECTION_BOTTOM_TO_TOP;
380a3e0fd82Sopenharmony_ci    }
381a3e0fd82Sopenharmony_ci    bool triggerAnimator = (MATH_ABS(lastRotateLen) >= rotateThrowthreshold_);
382a3e0fd82Sopenharmony_ci    if (throwDrag_ && triggerAnimator) {
383a3e0fd82Sopenharmony_ci        Point current;
384a3e0fd82Sopenharmony_ci        if (direction_ == HORIZONTAL) {
385a3e0fd82Sopenharmony_ci            current = {lastRotateLen, 0};
386a3e0fd82Sopenharmony_ci        } else {
387a3e0fd82Sopenharmony_ci            current = {0, lastRotateLen};
388a3e0fd82Sopenharmony_ci        }
389a3e0fd82Sopenharmony_ci        DragThrowAnimator(current, {0, 0}, dir, dragBack_);
390a3e0fd82Sopenharmony_ci    } else {
391a3e0fd82Sopenharmony_ci        DragThrowAnimator({0, 0}, {0, 0}, dir, dragBack_);
392a3e0fd82Sopenharmony_ci    }
393a3e0fd82Sopenharmony_ci    isRotating_ = false;
394a3e0fd82Sopenharmony_ci    InitRotate();
395a3e0fd82Sopenharmony_ci    return UIView::OnRotateEndEvent(event);
396a3e0fd82Sopenharmony_ci}
397a3e0fd82Sopenharmony_ci#endif
398a3e0fd82Sopenharmony_ci
399a3e0fd82Sopenharmony_civoid UIAbstractScroll::SetXScrollBarVisible(bool visible)
400a3e0fd82Sopenharmony_ci{
401a3e0fd82Sopenharmony_ci    if (Screen::GetInstance().GetScreenShape() == ScreenShape::CIRCLE) {
402a3e0fd82Sopenharmony_ci        return;
403a3e0fd82Sopenharmony_ci    } else if (visible && xScrollBar_ == nullptr) {
404a3e0fd82Sopenharmony_ci        xScrollBar_ = new UIBoxScrollBar();
405a3e0fd82Sopenharmony_ci    }
406a3e0fd82Sopenharmony_ci    xScrollBarVisible_ = visible;
407a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
408a3e0fd82Sopenharmony_ci    if (xScrollBarVisible_ && barEaseInOutAnimator_ == nullptr) {
409a3e0fd82Sopenharmony_ci        barEaseInOutAnimator_ = new BarEaseInOutAnimator(*this);
410a3e0fd82Sopenharmony_ci    }
411a3e0fd82Sopenharmony_ci#endif
412a3e0fd82Sopenharmony_ci}
413a3e0fd82Sopenharmony_ci
414a3e0fd82Sopenharmony_civoid UIAbstractScroll::SetYScrollBarVisible(bool visible)
415a3e0fd82Sopenharmony_ci{
416a3e0fd82Sopenharmony_ci    yScrollBarVisible_ = visible;
417a3e0fd82Sopenharmony_ci    if (yScrollBarVisible_ && yScrollBar_ == nullptr) {
418a3e0fd82Sopenharmony_ci        if (Screen::GetInstance().GetScreenShape() == ScreenShape::CIRCLE) {
419a3e0fd82Sopenharmony_ci            yScrollBar_ = new UIArcScrollBar();
420a3e0fd82Sopenharmony_ci        } else {
421a3e0fd82Sopenharmony_ci            yScrollBar_ = new UIBoxScrollBar();
422a3e0fd82Sopenharmony_ci        }
423a3e0fd82Sopenharmony_ci    }
424a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
425a3e0fd82Sopenharmony_ci    if (yScrollBarVisible_ && barEaseInOutAnimator_ == nullptr) {
426a3e0fd82Sopenharmony_ci        barEaseInOutAnimator_ = new BarEaseInOutAnimator(*this);
427a3e0fd82Sopenharmony_ci    }
428a3e0fd82Sopenharmony_ci#endif
429a3e0fd82Sopenharmony_ci}
430a3e0fd82Sopenharmony_ci
431a3e0fd82Sopenharmony_civoid UIAbstractScroll::OnPostDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
432a3e0fd82Sopenharmony_ci{
433a3e0fd82Sopenharmony_ci    Rect scrollRect = GetRect();
434a3e0fd82Sopenharmony_ci    uint8_t opa = GetMixOpaScale();
435a3e0fd82Sopenharmony_ci    if (Screen::GetInstance().GetScreenShape() == ScreenShape::RECTANGLE) {
436a3e0fd82Sopenharmony_ci        if (yScrollBarVisible_) {
437a3e0fd82Sopenharmony_ci            if (scrollBarSide_ == SCROLL_BAR_RIGHT_SIDE) {
438a3e0fd82Sopenharmony_ci                yScrollBar_->SetPosition(scrollRect.GetRight() - SCROLL_BAR_WIDTH + 1, scrollRect.GetTop(),
439a3e0fd82Sopenharmony_ci                                         SCROLL_BAR_WIDTH, scrollRect.GetHeight());
440a3e0fd82Sopenharmony_ci            } else {
441a3e0fd82Sopenharmony_ci                yScrollBar_->SetPosition(scrollRect.GetLeft(), scrollRect.GetTop(), SCROLL_BAR_WIDTH,
442a3e0fd82Sopenharmony_ci                                         scrollRect.GetHeight());
443a3e0fd82Sopenharmony_ci            }
444a3e0fd82Sopenharmony_ci            yScrollBar_->OnDraw(gfxDstBuffer, invalidatedArea, opa);
445a3e0fd82Sopenharmony_ci        }
446a3e0fd82Sopenharmony_ci        if (xScrollBarVisible_) {
447a3e0fd82Sopenharmony_ci            if (scrollBarSide_ == SCROLL_BAR_RIGHT_SIDE) {
448a3e0fd82Sopenharmony_ci                xScrollBar_->SetPosition(scrollRect.GetLeft(), scrollRect.GetBottom() - SCROLL_BAR_WIDTH + 1,
449a3e0fd82Sopenharmony_ci                                         scrollRect.GetWidth() - SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH);
450a3e0fd82Sopenharmony_ci            } else {
451a3e0fd82Sopenharmony_ci                xScrollBar_->SetPosition(scrollRect.GetLeft() + SCROLL_BAR_WIDTH,
452a3e0fd82Sopenharmony_ci                                         scrollRect.GetBottom() - SCROLL_BAR_WIDTH + 1,
453a3e0fd82Sopenharmony_ci                                         scrollRect.GetWidth() - SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH);
454a3e0fd82Sopenharmony_ci            }
455a3e0fd82Sopenharmony_ci            xScrollBar_->OnDraw(gfxDstBuffer, invalidatedArea, opa);
456a3e0fd82Sopenharmony_ci        }
457a3e0fd82Sopenharmony_ci    } else {
458a3e0fd82Sopenharmony_ci        if (yScrollBarVisible_) {
459a3e0fd82Sopenharmony_ci            yScrollBar_->SetScrollBarSide(scrollBarSide_);
460a3e0fd82Sopenharmony_ci            int16_t x;
461a3e0fd82Sopenharmony_ci            int16_t y;
462a3e0fd82Sopenharmony_ci            if (scrollBarCenterSetFlag_) {
463a3e0fd82Sopenharmony_ci                x = scrollRect.GetX() + scrollBarCenter_.x;
464a3e0fd82Sopenharmony_ci                y = scrollRect.GetY() + scrollBarCenter_.y;
465a3e0fd82Sopenharmony_ci            } else {
466a3e0fd82Sopenharmony_ci                x = scrollRect.GetX() + (GetWidth() / 2);  // 2: half
467a3e0fd82Sopenharmony_ci                y = scrollRect.GetY() + (GetHeight() / 2); // 2: half
468a3e0fd82Sopenharmony_ci            }
469a3e0fd82Sopenharmony_ci            yScrollBar_->SetPosition(x, y, SCROLL_BAR_WIDTH, GetWidth() / 2); // 2: half
470a3e0fd82Sopenharmony_ci            yScrollBar_->OnDraw(gfxDstBuffer, invalidatedArea, opa);
471a3e0fd82Sopenharmony_ci        }
472a3e0fd82Sopenharmony_ci    }
473a3e0fd82Sopenharmony_ci    UIView::OnPostDraw(gfxDstBuffer, invalidatedArea);
474a3e0fd82Sopenharmony_ci}
475a3e0fd82Sopenharmony_ci
476a3e0fd82Sopenharmony_civoid UIAbstractScroll::RefreshAnimator()
477a3e0fd82Sopenharmony_ci{
478a3e0fd82Sopenharmony_ci#if DEFAULT_ANIMATION
479a3e0fd82Sopenharmony_ci    barEaseInOutAnimator_->RefreshBar();
480a3e0fd82Sopenharmony_ci#endif
481a3e0fd82Sopenharmony_ci}
482a3e0fd82Sopenharmony_ci} // namespace OHOS
483