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 
43 namespace OHOS {
44 class BarEaseInOutAnimator;
45 class 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  */
53 class UIAbstractScroll : public UIViewGroup {
54 public:
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      */
GetViewType()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      */
SetScrollBlankSize(uint16_t size)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      */
GetScrollBlankSize()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      */
SetMaxScrollDistance(uint16_t distance)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      */
SetReboundSize(uint16_t size)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      */
GetReboundSize()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      */
GetMaxScrollDistance()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      */
SetDragFunc(EasingFunc func)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      */
GetDragFunc()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      */
SetThrowDrag(bool throwDrag)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      */
SetDragACCLevel(uint16_t value)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      */
GetDragACCLevel()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      */
SetSwipeACCLevel(uint16_t value)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      */
GetSwipeACCLevel()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      */
SetRotateACCLevel(uint8_t value)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      */
GetRotateACCLevel()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      */
GetRotateFactor()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      */
SetRotateFactor(float factor)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      */
SetRotateThrowThreshold(uint8_t threshold)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      */
GetRotateThrowThreshold()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 
SetScrollBarSide(uint8_t side)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      */
GetScrollBarSide()358     uint8_t GetScrollBarSide()
359     {
360         return scrollBarSide_;
361     }
362 
SetScrollBarCenter(const Point & center)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      */
GetScrollBarCenter()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      */
SetDirection(uint8_t direction)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      */
GetDirection()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 
408 protected:
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:
ListAnimatorCallback()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 
~ListAnimatorCallback()439         virtual ~ListAnimatorCallback() {}
440 
SetDragTimes(uint16_t times)441         void SetDragTimes(uint16_t times)
442         {
443             dragTimes_ = times;
444         }
445 
SetDragStartValue(int16_t startValueX,int16_t startValueY)446         void SetDragStartValue(int16_t startValueX, int16_t startValueY)
447         {
448             startValueX_ = startValueX;
449             previousValueX_ = startValueX;
450             startValueY_ = startValueY;
451             previousValueY_ = startValueY;
452         }
453 
SetDragEndValue(int16_t endValueX,int16_t endValueY)454         void SetDragEndValue(int16_t endValueX, int16_t endValueY)
455         {
456             endValueX_ = endValueX;
457             endValueY_ = endValueY;
458         }
459 
ResetCallback()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 
RefreshDelta(int16_t distance)490     void RefreshDelta(int16_t distance)
491     {
492         lastDelta_[deltaIndex_ % MAX_DELTA_SIZE] = distance;
493         deltaIndex_++;
494     }
495 
496     void InitDelta();
497 
RefreshRotate(int16_t distance)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 
CalculateReboundDistance(int16_t & dragDistanceX,int16_t & dragDistanceY)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 
FixDistance(int16_t & distanceX,int16_t & distanceY)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