1/*
2 * Copyright (c) 2020-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/**
17 * @addtogroup UI_Components
18 * @{
19 *
20 * @brief Defines UI components such as buttons, texts, images, lists, and progress bars.
21 *
22 * @since 1.0
23 * @version 1.0
24 */
25
26/**
27 * @file ui_abstract_scroll.h
28 *
29 * @brief Declares the base class used to define the attributes of a scroll. The <b>UIList</b>, <b>UIScrollView</b>, and
30 *        <b>UISwipeView</b> inherit from this class.
31 *
32 * @since 1.0
33 * @version 1.0
34 */
35
36#ifndef GRAPHIC_LITE_UI_ABSTRACT_SCROLL_H
37#define GRAPHIC_LITE_UI_ABSTRACT_SCROLL_H
38
39#include "animator/animator.h"
40#include "animator/easing_equation.h"
41#include "components/ui_view_group.h"
42
43namespace OHOS {
44class BarEaseInOutAnimator;
45class UIAbstractScrollBar;
46/**
47 * @brief Defines the attributes of a scroll, including the scroll direction, blank size of a scroll view, velocity and
48 *        effects of a scroll animation.
49 *
50 * @since 1.0
51 * @version 1.0
52 */
53class UIAbstractScroll : public UIViewGroup {
54public:
55    /**
56     * @brief A constructor used to create a <b>UIAbstractScroll</b> instance.
57     *
58     * @since 1.0
59     * @version 1.0
60     */
61    UIAbstractScroll();
62
63    /**
64     * @brief A destructor used to delete the <b>UIAbstractScroll</b> instance.
65     *
66     * @since 1.0
67     * @version 1.0
68     */
69    virtual ~UIAbstractScroll();
70
71    /**
72     * @brief Obtains the view type.
73     * @return Returns the view type, as defined in {@link UIViewType}.
74     * @since 1.0
75     * @version 1.0
76     */
77    UIViewType GetViewType() const override
78    {
79        return UI_ABSTRACT_SCROLL;
80    }
81
82    /**
83     * @brief Sets the blank size for this scroll view.
84     *
85     *
86     * @param value Indicates the blank size to set. The default value is <b>0</b>. Taking a vertical scroll as an
87     *              example, the value <b>0</b> indicates that the head node can only scroll downwards the top of the
88     *              view and the tail node scroll upwards the bottom; the value <b>10</b> indicates that the head node
89     *              can continue scrolling down by 10 pixels after it reaches the top of the view.
90     * @since 1.0
91     * @version 1.0
92     */
93    void SetScrollBlankSize(uint16_t size)
94    {
95        scrollBlankSize_ = size;
96    }
97
98    /**
99     * @brief Get the blank size for this scroll view.
100     *
101     * @return Returns the blank size for this scroll view
102     */
103    uint16_t GetScrollBlankSize() const
104    {
105        return scrollBlankSize_;
106    }
107
108    /**
109     * @brief Sets the maximum scroll distance after a finger lifts the screen.
110     *
111     * @param distance Indicates the maximum scroll distance to set. The default value is <b>0</b>, indicating that the
112     *                 scroll distance is not limited.
113     * @since 1.0
114     * @version 1.0
115     */
116    void SetMaxScrollDistance(uint16_t distance)
117    {
118        maxScrollDistance_ = distance;
119    }
120
121    /**
122     * @brief Sets the rebound size, which is the distance a knob moves after being released when it reaches the end of
123     *        a scrollbar.
124     *
125     * @param size Indicates the rebound size to set.
126     * @since 1.0
127     * @version 1.0
128     */
129    void SetReboundSize(uint16_t size)
130    {
131        reboundSize_ = size;
132    }
133
134    /**
135     * @brief Get the rebound size, which is the distance a knob moves after being released when it reaches the end of
136     *        a scrollbar.
137     *
138     * @return Returns the rebound size.
139     */
140    uint16_t GetReboundSize() const
141    {
142        return reboundSize_;
143    }
144
145    /**
146     * @brief Obtains the maximum scroll distance after a finger lifts the screen.
147     *
148     * @return Returns the maximum scroll distance. The default value is <b>0</b>, indicating that the scroll distance
149     * is not limited.
150     * @since 1.0
151     * @version 1.0
152     */
153    uint16_t GetMaxScrollDistance() const
154    {
155        return maxScrollDistance_;
156    }
157
158    /**
159     * @brief Sets the easing function that specifies a scroll animation after a finger lifts the screen.
160     *
161     * @param func Indicates the easing function to set. The default function is {@link EasingEquation::CubicEaseOut}.
162     *             For details, see {@link EasingEquation}.
163     * @since 1.0
164     * @version 1.0
165     */
166    void SetDragFunc(EasingFunc func)
167    {
168        easingFunc_ = func;
169    }
170
171    /**
172     * @brief Get the easing function that specifies a scroll animation after a finger lifts the screen.
173     *
174     * @param func Returns the easing function to set. The default function is {@link EasingEquation::CubicEaseOut}.
175     *             For details, see {@link EasingEquation}.
176     */
177    EasingFunc GetDragFunc() const
178    {
179        return easingFunc_;
180    }
181
182    /**
183     * @brief Sets whether to continue scrolling after a finger lifts the screen.
184     *
185     * @param throwDrag Specifies whether to continue scrolling after a finger lifts the screen. <b>true</b> indicates
186     *                  the scroll continues, and <b>false</b> indicates the scroll stops immediately after a finger
187     *                  lifts.
188     * @since 1.0
189     * @version 1.0
190     */
191    void SetThrowDrag(bool throwDrag)
192    {
193        throwDrag_ = throwDrag;
194    }
195
196    /**
197     * @brief Moves the position of all child views.
198     *
199     * @param offsetX Indicates the offset distance by which a child view is moved on the x-axis.
200     * @param offsetY Indicates the offset distance by which a child view is moved on the y-axis.
201     * @since 1.0
202     * @version 1.0
203     */
204    void MoveChildByOffset(int16_t offsetX, int16_t offsetY) override;
205
206    /**
207     * @brief Sets the drag acceleration.
208     *
209     * @param value Indicates the drag acceleration to set. The default value is <b>10</b>. A larger drag acceleration
210     *              indicates a higher inertial scroll velocity.
211     * @since 1.0
212     * @version 1.0
213     */
214    void SetDragACCLevel(uint16_t value)
215    {
216        if (value != 0) {
217            dragAccCoefficient_ = value;
218        }
219    }
220
221    /**
222     * @brief Obtains the drag acceleration.
223     *
224     * @return Returns the drag acceleration.
225     * @since 1.0
226     * @version 1.0
227     */
228    uint8_t GetDragACCLevel() const
229    {
230        return dragAccCoefficient_;
231    }
232
233    /**
234     * @brief Sets the compensation distance after a finger lifts the screen.
235     *
236     * @param value Indicates the compensation distance to set. The default value is <b>0</b>.
237     * @since 1.0
238     * @version 1.0
239     */
240    void SetSwipeACCLevel(uint16_t value)
241    {
242        swipeAccCoefficient_ = value;
243    }
244
245    /**
246     * @brief Obtains the compensation distance after a finger lifts the screen.
247     *
248     * @return Returns the compensation distance.
249     * @since 1.0
250     * @version 1.0
251     */
252    uint8_t GetSwipeACCLevel() const
253    {
254        return swipeAccCoefficient_;
255    }
256
257#if ENABLE_ROTATE_INPUT
258    /**
259     * @brief Sets coefficient for rotation dragthrow animation. The view will roll farther with larger coeffcient.
260     *
261     * @param value Indicates the coefficient to set. The default value is <b>0</b>.
262     * @since 1.0
263     * @version 1.0
264     */
265    void SetRotateACCLevel(uint8_t value)
266    {
267        rotateAccCoefficient_ = value;
268    }
269
270    /**
271     * @brief Obtains the coefficient for rotation drag throw animation.
272     *
273     * @return Returns the coefficient for rotation drag throw animation.
274     * @since 1.0
275     * @version 1.0
276     */
277    uint8_t GetRotateACCLevel() const
278    {
279        return rotateAccCoefficient_;
280    }
281
282    /**
283     * @brief Obtains the rotation factor.
284     *
285     * @return Returns the rotation factor.
286     * @since 5.0
287     * @version 3.0
288     */
289    float GetRotateFactor() const
290    {
291        return rotateFactor_;
292    }
293
294    /**
295     * @brief Sets the rotation factor.
296     *
297     * @param factor Indicates the rotation factor to set.
298     * @since 5.0
299     * @version 3.0
300     */
301    void SetRotateFactor(float factor)
302    {
303        if (MATH_ABS(factor) > MAX_ROTATE_FACTOR) {
304            rotateFactor_ = (factor > 0) ? MAX_ROTATE_FACTOR : -MAX_ROTATE_FACTOR;
305            return;
306        }
307        rotateFactor_ = factor;
308    }
309
310    /**
311     * @brief Sets threshold for rotation drag throw animation. The view will roll easier with larger threshold.
312     *
313     * @param threshold Indicates the rotation factor to set.
314     *
315     * @since 6
316     */
317    void SetRotateThrowThreshold(uint8_t threshold)
318    {
319        if (threshold == 0) {
320            return;
321        }
322        rotateThrowthreshold_ = threshold;
323    }
324
325    /**
326     * @brief Get threshold for rotation drag throw animation. The view will roll easier with larger threshold.
327     *
328     * @param Returns the threshold for rotation drag throw animation. The view will roll easier with larger threshold.
329     *
330     */
331    uint8_t GetRotateThrowThreshold() const
332    {
333        return rotateThrowthreshold_;
334    }
335
336    bool OnRotateStartEvent(const RotateEvent& event) override;
337
338    bool OnRotateEvent(const RotateEvent& event) override;
339
340    bool OnRotateEndEvent(const RotateEvent& event) override;
341#endif
342
343    void SetXScrollBarVisible(bool visible);
344
345    void SetYScrollBarVisible(bool visible);
346
347    void SetScrollBarSide(uint8_t side)
348    {
349        scrollBarSide_ = side;
350    }
351
352    /**
353     * @brief Get ScrollBarSide.
354     *
355     * @param Returns the scrollBarSide_.
356     *
357     */
358    uint8_t GetScrollBarSide()
359    {
360        return scrollBarSide_;
361    }
362
363    void SetScrollBarCenter(const Point& center)
364    {
365        scrollBarCenter_ = center;
366        scrollBarCenterSetFlag_ = true;
367    }
368
369    /**
370     * @brief Get scrollBarCenter.
371     *
372     * @param Returns the scrollBarCenter_.
373     *
374     */
375    Point GetScrollBarCenter()
376    {
377        return scrollBarCenter_;
378    }
379
380    /**
381     * @brief Sets the list direction.
382     *
383     * @param direction Indicates the list direction, either {@link HORIZONTAL} or {@link VERTICAL}.
384     * @since 1.0
385     * @version 1.0
386     */
387    void SetDirection(uint8_t direction)
388    {
389        direction_ = direction;
390    }
391
392    /**
393     * @brief Obtains the list direction.
394     * @return Returns the list direction, either {@link HORIZONTAL} or {@link VERTICAL}.
395     * @since 1.0
396     * @version 1.0
397     */
398    uint8_t GetDirection() const
399    {
400        return direction_;
401    }
402
403    void OnPostDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
404
405    static constexpr uint8_t HORIZONTAL = 0;
406    static constexpr uint8_t VERTICAL = 1;
407
408protected:
409    static constexpr uint8_t HORIZONTAL_AND_VERTICAL = 2;
410    static constexpr uint8_t HORIZONTAL_NOR_VERTICAL = 3;
411    /* calculate drag throw distance, last drag distance in one tick * DRAG_DISTANCE_COEFFICIENT */
412    static constexpr uint8_t DRAG_DISTANCE_COEFFICIENT = 5;
413    /* calculate drag throw times, drag distance / DRAG_TIMES_COEFFICIENT */
414    static constexpr uint8_t DRAG_TIMES_COEFFICIENT = 18;
415    /* the minimum duration of the swipe animator */
416    static constexpr uint8_t MIN_DRAG_TIMES = 5;
417    /* acceleration calculation coefficient */
418    static constexpr uint8_t DRAG_ACC_FACTOR = 10;
419    /* the maximum number of historical drag data */
420    static constexpr uint8_t MAX_DELTA_SIZE = 3;
421
422    static constexpr uint16_t SCROLL_BAR_WIDTH = 4;
423    static constexpr uint8_t MAX_ROTATE_FACTOR = 128;
424
425    class ListAnimatorCallback : public AnimatorCallback {
426    public:
427        ListAnimatorCallback()
428            : curtTime_(0),
429              dragTimes_(0),
430              startValueX_(0),
431              endValueX_(0),
432              previousValueX_(0),
433              startValueY_(0),
434              endValueY_(0),
435              previousValueY_(0)
436        {
437        }
438
439        virtual ~ListAnimatorCallback() {}
440
441        void SetDragTimes(uint16_t times)
442        {
443            dragTimes_ = times;
444        }
445
446        void SetDragStartValue(int16_t startValueX, int16_t startValueY)
447        {
448            startValueX_ = startValueX;
449            previousValueX_ = startValueX;
450            startValueY_ = startValueY;
451            previousValueY_ = startValueY;
452        }
453
454        void SetDragEndValue(int16_t endValueX, int16_t endValueY)
455        {
456            endValueX_ = endValueX;
457            endValueY_ = endValueY;
458        }
459
460        void ResetCallback()
461        {
462            curtTime_ = 0;
463            dragTimes_ = 0;
464            startValueX_ = 0;
465            endValueX_ = 0;
466            startValueY_ = 0;
467            endValueY_ = 0;
468        }
469
470        void Callback(UIView* view) override;
471
472        uint16_t curtTime_;
473        uint16_t dragTimes_;
474        int16_t startValueX_;
475        int16_t endValueX_;
476        int16_t previousValueX_;
477        int16_t startValueY_;
478        int16_t endValueY_;
479        int16_t previousValueY_;
480    };
481
482    bool DragThrowAnimator(Point currentPos, Point lastPos, uint8_t dragDirection, bool dragBack = true);
483
484    virtual void StopAnimator();
485
486    virtual bool DragXInner(int16_t distance) = 0;
487
488    virtual bool DragYInner(int16_t distance) = 0;
489
490    void RefreshDelta(int16_t distance)
491    {
492        lastDelta_[deltaIndex_ % MAX_DELTA_SIZE] = distance;
493        deltaIndex_++;
494    }
495
496    void InitDelta();
497
498    void RefreshRotate(int16_t distance)
499    {
500        lastRotate_[rotateIndex_ % MAX_DELTA_SIZE] = distance;
501        rotateIndex_++;
502    }
503
504    void InitRotate();
505
506    virtual void CalculateDragDistance(Point currentPos,
507                                       Point lastPos,
508                                       uint8_t dragDirection,
509                                       int16_t& dragDistanceX,
510                                       int16_t& dragDistanceY);
511
512    void StartAnimator(int16_t dragDistanceX, int16_t dragDistanceY);
513
514    virtual void CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dragDistanceY) {}
515
516    int16_t GetMaxDelta() const;
517
518    int16_t GetMaxRotate() const;
519
520    void RefreshAnimator();
521
522    virtual void FixDistance(int16_t& distanceX, int16_t& distanceY) {}
523
524    uint16_t scrollBlankSize_ = 0;
525    uint16_t reboundSize_ = 0;
526    uint16_t maxScrollDistance_ = 0;
527    int16_t lastDelta_[MAX_DELTA_SIZE] = {0};
528    int16_t lastRotate_[MAX_DELTA_SIZE] = {0};
529    uint8_t dragAccCoefficient_ = DRAG_ACC_FACTOR;
530    uint8_t swipeAccCoefficient_ = 0;
531    uint8_t direction_ : 2;
532    uint8_t deltaIndex_ : 2;
533    uint8_t rotateIndex_ : 2;
534    uint8_t reserve_ : 2;
535    bool throwDrag_ = false;
536    EasingFunc easingFunc_;
537    ListAnimatorCallback animatorCallback_;
538    Animator scrollAnimator_;
539#if ENABLE_ROTATE_INPUT
540    uint8_t rotateAccCoefficient_ = 0;
541    float rotateFactor_;
542    uint8_t rotateThrowthreshold_;
543    bool isRotating_;
544#endif
545    bool yScrollBarVisible_ = false;
546    UIAbstractScrollBar* yScrollBar_ = nullptr;
547    bool xScrollBarVisible_ = false;
548    UIAbstractScrollBar* xScrollBar_ = nullptr;
549    uint8_t scrollBarSide_;
550    Point scrollBarCenter_;
551    bool scrollBarCenterSetFlag_;
552    bool dragBack_ = true;
553#if DEFAULT_ANIMATION
554    friend class BarEaseInOutAnimator;
555    BarEaseInOutAnimator* barEaseInOutAnimator_ = nullptr;
556#endif
557};
558} // namespace OHOS
559#endif // GRAPHIC_LITE_UI_ABSTRACT_SCROLL_H
560