• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "components/ui_scroll_view.h"
17 
18 #include "components/ui_abstract_scroll_bar.h"
19 #include "dock/focus_manager.h"
20 #include "dock/vibrator_manager.h"
21 #include "draw/draw_rect.h"
22 #include "gfx_utils/graphic_log.h"
23 
24 namespace OHOS {
UIScrollView()25 UIScrollView::UIScrollView() : scrollListener_(nullptr)
26 {
27 #if ENABLE_ROTATE_INPUT
28     rotateFactor_ = DEFAULT_SCROLL_VIEW_ROTATE_FACTOR;
29     rotateThrowthreshold_ = SCROLLVIEW_ROTATE_THROW_THRESHOLD;
30     rotateAccCoefficient_ = SCROLLVIEW_ROTATE_DISTANCE_COEFF;
31 #endif
32 #if ENABLE_VIBRATOR
33     totalRotateLen_ = 0;
34     lastVibratorRotateLen_ = 0;
35 #endif
36 #if ENABLE_FOCUS_MANAGER
37     focusable_ = true;
38 #endif
39     direction_ = HORIZONTAL_AND_VERTICAL;
40 }
41 
OnDragEvent(const DragEvent & event)42 bool UIScrollView::OnDragEvent(const DragEvent& event)
43 {
44     if (scrollAnimator_.GetState() != Animator::STOP) {
45         UIAbstractScroll::StopAnimator();
46     }
47     Drag(event);
48     return UIView::OnDragEvent(event);
49 }
50 
OnDragEndEvent(const DragEvent & event)51 bool UIScrollView::OnDragEndEvent(const DragEvent& event)
52 {
53     Point last = event.GetPreLastPoint();
54     Point current = event.GetLastPoint();
55     if ((last.x == current.x) && (last.y == current.y)) {
56         last = current;
57         current = event.GetCurrentPos();
58     }
59 
60     if (!DragThrowAnimator(current, last, event.GetDragDirection())) {
61         if (scrollListener_ && (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_MOVE)) {
62             scrollListener_->OnScrollEnd();
63             scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_STOP);
64         }
65     }
66     return UIView::OnDragEndEvent(event);
67 }
68 
Drag(const DragEvent & event)69 void UIScrollView::Drag(const DragEvent& event)
70 {
71     int16_t xDistance = event.GetDeltaX();
72     int16_t yDistance = event.GetDeltaY();
73 
74     if ((direction_ == HORIZONTAL || direction_ == HORIZONTAL_AND_VERTICAL) && xDistance != 0) {
75         DragXInner(xDistance);
76     }
77     if ((direction_ == VERTICAL || direction_ == HORIZONTAL_AND_VERTICAL) && yDistance != 0) {
78         RefreshDelta(yDistance);
79         DragYInner(yDistance);
80     }
81 }
82 
OnPressEvent(const PressEvent & event)83 bool UIScrollView::OnPressEvent(const PressEvent& event)
84 {
85     StopAnimator();
86     return UIView::OnPressEvent(event);
87 }
88 
89 #if ENABLE_ROTATE_INPUT
OnRotateEvent(const RotateEvent & event)90 bool UIScrollView::OnRotateEvent(const RotateEvent& event)
91 {
92     if (direction_ == HORIZONTAL_NOR_VERTICAL) {
93         return UIView::OnRotateEvent(event);
94     }
95     int16_t rotateLen = static_cast<int16_t>(event.GetRotate() * rotateFactor_);
96 #if ENABLE_VIBRATOR
97     bool lastIsEdge = false;
98     Rect childRect = GetAllChildRelativeRect();
99     if (direction_ == HORIZONTAL) {
100         if (childRect.GetLeft() - scrollBlankSize_ >= 0 || childRect.GetRight() + scrollBlankSize_ <= GetWidth()) {
101             lastIsEdge = true;
102         }
103     } else {
104         if (childRect.GetTop() - scrollBlankSize_ >= 0 || childRect.GetBottom() + scrollBlankSize_ <= GetHeight()) {
105             lastIsEdge = true;
106         }
107     }
108 #endif
109     RefreshRotate(rotateLen);
110     if (direction_ == HORIZONTAL) {
111         DragXInner(rotateLen);
112     } else {
113         DragYInner(rotateLen);
114     }
115 #if ENABLE_VIBRATOR
116     totalRotateLen_ += rotateLen;
117     childRect = GetAllChildRelativeRect();
118     bool isEdge = false;
119     if (direction_ == HORIZONTAL) {
120         if (childRect.GetLeft() - scrollBlankSize_ >= 0 || childRect.GetRight() + scrollBlankSize_ <= GetWidth()) {
121             isEdge = true;
122         }
123     } else {
124         if (childRect.GetTop() - scrollBlankSize_ >= 0 || childRect.GetBottom() + scrollBlankSize_ <= GetHeight()) {
125             isEdge = true;
126         }
127     }
128     VibratorFunc vibratorFunc = VibratorManager::GetInstance()->GetVibratorFunc();
129     if (vibratorFunc != nullptr && !isEdge) {
130         uint16_t rotateLen = MATH_ABS(totalRotateLen_ - lastVibratorRotateLen_);
131         if (rotateLen > DEFAULT_SCROLL_VIEW_VIBRATION_LEN) {
132             uint16_t vibrationCnt = rotateLen / DEFAULT_SCROLL_VIEW_VIBRATION_LEN;
133             for (uint16_t i = 0; i < vibrationCnt; i++) {
134                 GRAPHIC_LOGI("UIScrollView::OnRotateEvent calls TYPE_ONE vibrator");
135                 vibratorFunc(VibratorType::VIBRATOR_TYPE_ONE);
136             }
137             lastVibratorRotateLen_ = totalRotateLen_;
138         }
139     }
140     if (vibratorFunc != nullptr && (!lastIsEdge && isEdge)) {
141         GRAPHIC_LOGI("UIScrollView::OnRotateEvent calls TYPE_THREE vibrator");
142         vibratorFunc(VibratorType::VIBRATOR_TYPE_THREE);
143     }
144 #endif
145     return UIView::OnRotateEvent(event);
146 }
147 
OnRotateEndEvent(const RotateEvent & event)148 bool UIScrollView::OnRotateEndEvent(const RotateEvent& event)
149 {
150     if (direction_ == HORIZONTAL_NOR_VERTICAL) {
151         return UIView::OnRotateEvent(event);
152     }
153     return UIAbstractScroll::OnRotateEndEvent(event);
154 }
155 #endif
156 
ScrollBy(int16_t xDistance,int16_t yDistance)157 void UIScrollView::ScrollBy(int16_t xDistance, int16_t yDistance)
158 {
159     if ((direction_ == HORIZONTAL || direction_ == HORIZONTAL_AND_VERTICAL) && xDistance != 0) {
160         DragXInner(xDistance);
161     }
162     if ((direction_ == VERTICAL || direction_ == HORIZONTAL_AND_VERTICAL) && yDistance != 0) {
163         DragYInner(yDistance);
164     }
165     if ((scrollListener_ != nullptr) && (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_MOVE)) {
166         scrollListener_->OnScrollEnd();
167         scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_STOP);
168     }
169 }
170 
DragXInner(int16_t distance)171 bool UIScrollView::DragXInner(int16_t distance)
172 {
173     Rect childRect = GetAllChildRelativeRect();
174     int16_t reboundSize = reboundSize_;
175     if (scrollAnimator_.GetState() != Animator::STOP) {
176         reboundSize = 0;
177     }
178 
179     if (childRect.GetWidth() <= (GetWidth() - (scrollBlankSize_ << 1)) ||
180         !(direction_ == HORIZONTAL || direction_ == HORIZONTAL_AND_VERTICAL)) {
181         return false;
182     }
183 
184     if (distance > 0) {
185         if (childRect.GetLeft() > scrollBlankSize_ + reboundSize) {
186             distance = 0;
187         } else if ((childRect.GetLeft() + distance) > scrollBlankSize_ + reboundSize) {
188             distance = scrollBlankSize_ - childRect.GetLeft() + reboundSize;
189         }
190     } else {
191         int16_t childRight = childRect.GetRight();
192         int16_t scrollWidth = GetWidth();
193         if (childRight < scrollWidth - (scrollBlankSize_ + reboundSize)) {
194             distance = 0;
195         } else if (childRight + distance < scrollWidth - (scrollBlankSize_ + reboundSize)) {
196             distance = scrollWidth - (scrollBlankSize_ + reboundSize) - childRight - 1;
197         }
198     }
199 
200     return MoveOffset(distance, 0);
201 }
202 
DragYInner(int16_t distance)203 bool UIScrollView::DragYInner(int16_t distance)
204 {
205     Rect childRect = GetAllChildRelativeRect();
206     int16_t reboundSize = reboundSize_;
207     if (scrollAnimator_.GetState() != Animator::STOP) {
208         reboundSize = 0;
209     }
210 
211     if (childRect.GetHeight() <= (GetHeight() - (scrollBlankSize_ << 1)) ||
212         !(direction_ == VERTICAL || direction_ == HORIZONTAL_AND_VERTICAL)) {
213         return false;
214     }
215 
216     if (distance > 0) {
217         if (childRect.GetTop() > scrollBlankSize_ + reboundSize) {
218             distance = 0;
219         } else if ((childRect.GetTop() + distance) > scrollBlankSize_ + reboundSize) {
220             distance = scrollBlankSize_ - childRect.GetTop() + reboundSize;
221         }
222     } else {
223         int16_t childBottom = childRect.GetBottom();
224         int16_t scrollHeight = GetHeight();
225         if (childBottom < scrollHeight - (scrollBlankSize_ + reboundSize)) {
226             distance = 0;
227         } else if (childBottom + distance < scrollHeight - (scrollBlankSize_ + reboundSize)) {
228             distance = scrollHeight - (scrollBlankSize_ + reboundSize) - childBottom - 1;
229         }
230     }
231 
232     return MoveOffset(0, distance);
233 }
234 
MoveOffset(int16_t offsetX,int16_t offsetY)235 bool UIScrollView::MoveOffset(int16_t offsetX, int16_t offsetY)
236 {
237     if ((offsetX != 0) || (offsetY != 0)) {
238         if ((scrollListener_ != nullptr) &&
239             (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_STOP)) {
240             scrollListener_->OnScrollStart();
241             scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_MOVE);
242         }
243         UIAbstractScroll::MoveChildByOffset(offsetX, offsetY);
244         if (xScrollBarVisible_ || yScrollBarVisible_) {
245             RefreshScrollBar();
246         }
247         Invalidate();
248         return true;
249     }
250     return false;
251 }
252 
RefreshScrollBar()253 void UIScrollView::RefreshScrollBar()
254 {
255     Rect childrenRect = GetAllChildRelativeRect();
256     /* calculate scrollBar's the proportion of foreground */
257     int16_t totalLen = childrenRect.GetHeight() + 2 * scrollBlankSize_; // 2: two blank space on both sizes
258     int16_t len = GetHeight();
259     if (yScrollBarVisible_) {
260         yScrollBar_->SetForegroundProportion(static_cast<float>(len) / totalLen);
261         /* calculate scrolling progress */
262         yScrollBar_->SetScrollProgress(static_cast<float>(scrollBlankSize_ - childrenRect.GetTop()) / (totalLen - len));
263     }
264     if (xScrollBarVisible_) {
265         /* so do x-bar */
266         totalLen = childrenRect.GetWidth() + 2 * scrollBlankSize_; // 2: two blank space on both sizes
267         len = GetWidth();
268         xScrollBar_->SetForegroundProportion(static_cast<float>(len) / totalLen);
269         xScrollBar_->SetScrollProgress(static_cast<float>(scrollBlankSize_ - childrenRect.GetLeft()) /
270                                        (totalLen - len));
271     }
272     RefreshAnimator();
273 }
274 
CalculateReboundDistance(int16_t & dragDistanceX,int16_t & dragDistanceY)275 void UIScrollView::CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dragDistanceY)
276 {
277     Rect rect = GetAllChildRelativeRect();
278     int16_t top = rect.GetTop();
279     int16_t bottom = rect.GetBottom();
280     int16_t scrollHeight = GetHeight();
281     int16_t left = rect.GetLeft();
282     int16_t right = rect.GetRight();
283     int16_t scrollWidth = GetWidth();
284     if (scrollBlankSize_ < top) {
285         dragDistanceY = scrollBlankSize_ - top;
286     } else if (bottom < scrollHeight - 1) {
287         dragDistanceY = scrollHeight - scrollBlankSize_ - bottom - 1;
288     }
289 
290     if (scrollBlankSize_ < left) {
291         dragDistanceX = scrollBlankSize_ - left;
292     } else if (right < scrollWidth - 1) {
293         dragDistanceX = scrollWidth - scrollBlankSize_ - right - 1;
294     }
295 }
296 
StopAnimator()297 void UIScrollView::StopAnimator()
298 {
299     if ((scrollListener_ != nullptr) && (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_MOVE)) {
300         scrollListener_->OnScrollEnd();
301         scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_STOP);
302     }
303     UIAbstractScroll::StopAnimator();
304 }
305 } // namespace OHOS
306