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 defined(ENABLE_ROTATE_INPUT) && 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 defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR
33 totalRotateLen_ = 0;
34 lastVibratorRotateLen_ = 0;
35 #endif
36 #if defined(ENABLE_FOCUS_MANAGER) && 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 defined(ENABLE_ROTATE_INPUT) && 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 defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR
97 bool lastIsEdge = false;
98 Rect childRect = GetAllChildRelativeRect();
99 SetIsEdge(lastIsEdge, childRect);
100 #endif
101 RefreshRotate(rotateLen);
102 if (direction_ == HORIZONTAL) {
103 DragXInner(rotateLen);
104 } else {
105 DragYInner(rotateLen);
106 }
107 #if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR
108 totalRotateLen_ += rotateLen;
109 childRect = GetAllChildRelativeRect();
110 bool isEdge = false;
111 if (direction_ == HORIZONTAL) {
112 if (childRect.GetLeft() - scrollBlankSize_ >= 0 || childRect.GetRight() + scrollBlankSize_ <= GetWidth()) {
113 isEdge = true;
114 }
115 } else {
116 if (childRect.GetTop() - scrollBlankSize_ >= 0 || childRect.GetBottom() + scrollBlankSize_ <= GetHeight()) {
117 isEdge = true;
118 }
119 }
120 VibratorFunc vibratorFunc = VibratorManager::GetInstance()->GetVibratorFunc();
121 if (vibratorFunc != nullptr && !isEdge) {
122 rotateLen = MATH_ABS(totalRotateLen_ - lastVibratorRotateLen_);
123 if (rotateLen > DEFAULT_SCROLL_VIEW_VIBRATION_LEN) {
124 uint16_t vibrationCnt = rotateLen / DEFAULT_SCROLL_VIEW_VIBRATION_LEN;
125 for (uint16_t i = 0; i < vibrationCnt; i++) {
126 GRAPHIC_LOGI("UIScrollView::OnRotateEvent calls TYPE_ONE vibrator");
127 vibratorFunc(VibratorType::VIBRATOR_TYPE_ONE);
128 }
129 lastVibratorRotateLen_ = totalRotateLen_;
130 }
131 }
132 if (vibratorFunc != nullptr && (!lastIsEdge && isEdge)) {
133 GRAPHIC_LOGI("UIScrollView::OnRotateEvent calls TYPE_THREE vibrator");
134 vibratorFunc(VibratorType::VIBRATOR_TYPE_THREE);
135 }
136 #endif
137 return UIView::OnRotateEvent(event);
138 }
139
OnRotateEndEvent(const RotateEvent & event)140 bool UIScrollView::OnRotateEndEvent(const RotateEvent& event)
141 {
142 if (direction_ == HORIZONTAL_NOR_VERTICAL) {
143 return UIView::OnRotateEvent(event);
144 }
145 return UIAbstractScroll::OnRotateEndEvent(event);
146 }
147
148 #if defined(ENABLE_VIBRATOR) && ENABLE_VIBRATOR
SetIsEdge(bool & lastIsEdge,Rect childRect)149 void UIScrollView::SetIsEdge(bool& lastIsEdge, Rect childRect)
150 {
151 if (direction_ == HORIZONTAL) {
152 if (childRect.GetLeft() - scrollBlankSize_ >= 0 || childRect.GetRight() + scrollBlankSize_ <= GetWidth()) {
153 lastIsEdge = true;
154 }
155 } else {
156 if (childRect.GetTop() - scrollBlankSize_ >= 0 || childRect.GetBottom() + scrollBlankSize_ <= GetHeight()) {
157 lastIsEdge = true;
158 }
159 }
160 }
161 #endif
162 #endif
163
ScrollBy(int16_t xDistance,int16_t yDistance)164 void UIScrollView::ScrollBy(int16_t xDistance, int16_t yDistance)
165 {
166 if ((direction_ == HORIZONTAL || direction_ == HORIZONTAL_AND_VERTICAL) && xDistance != 0) {
167 DragXInner(xDistance);
168 }
169 if ((direction_ == VERTICAL || direction_ == HORIZONTAL_AND_VERTICAL) && yDistance != 0) {
170 DragYInner(yDistance);
171 }
172 if ((scrollListener_ != nullptr) && (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_MOVE)) {
173 scrollListener_->OnScrollEnd();
174 scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_STOP);
175 }
176 }
177
DragXInner(int16_t distance)178 bool UIScrollView::DragXInner(int16_t distance)
179 {
180 Rect childRect = GetAllChildRelativeRect();
181 int16_t reboundSize = reboundSize_;
182 if (scrollAnimator_.GetState() != Animator::STOP) {
183 reboundSize = 0;
184 }
185
186 if (childRect.GetWidth() <= (GetWidth() - (scrollBlankSize_ << 1)) ||
187 !(direction_ == HORIZONTAL || direction_ == HORIZONTAL_AND_VERTICAL)) {
188 return false;
189 }
190
191 if (distance > 0) {
192 if (childRect.GetLeft() > scrollBlankSize_ + reboundSize) {
193 distance = 0;
194 } else if ((childRect.GetLeft() + distance) > scrollBlankSize_ + reboundSize) {
195 distance = scrollBlankSize_ - childRect.GetLeft() + reboundSize;
196 }
197 } else {
198 int16_t childRight = childRect.GetRight();
199 int16_t scrollWidth = GetWidth();
200 if (childRight < scrollWidth - (scrollBlankSize_ + reboundSize)) {
201 distance = 0;
202 } else if (childRight + distance < scrollWidth - (scrollBlankSize_ + reboundSize)) {
203 distance = scrollWidth - (scrollBlankSize_ + reboundSize) - childRight - 1;
204 }
205 }
206
207 return MoveOffset(distance, 0);
208 }
209
DragYInner(int16_t distance)210 bool UIScrollView::DragYInner(int16_t distance)
211 {
212 Rect childRect = GetAllChildRelativeRect();
213 int16_t reboundSize = reboundSize_;
214 if (scrollAnimator_.GetState() != Animator::STOP) {
215 reboundSize = 0;
216 }
217
218 if (childRect.GetHeight() <= (GetHeight() - (scrollBlankSize_ << 1)) ||
219 !(direction_ == VERTICAL || direction_ == HORIZONTAL_AND_VERTICAL)) {
220 return false;
221 }
222
223 if (distance > 0) {
224 if (childRect.GetTop() > scrollBlankSize_ + reboundSize) {
225 distance = 0;
226 } else if ((childRect.GetTop() + distance) > scrollBlankSize_ + reboundSize) {
227 distance = scrollBlankSize_ - childRect.GetTop() + reboundSize;
228 }
229 } else {
230 int16_t childBottom = childRect.GetBottom();
231 int16_t scrollHeight = GetHeight();
232 if (childBottom < scrollHeight - (scrollBlankSize_ + reboundSize)) {
233 distance = 0;
234 } else if (childBottom + distance < scrollHeight - (scrollBlankSize_ + reboundSize)) {
235 distance = scrollHeight - (scrollBlankSize_ + reboundSize) - childBottom - 1;
236 }
237 }
238
239 return MoveOffset(0, distance);
240 }
241
MoveOffset(int16_t offsetX,int16_t offsetY)242 bool UIScrollView::MoveOffset(int16_t offsetX, int16_t offsetY)
243 {
244 if ((offsetX != 0) || (offsetY != 0)) {
245 if ((scrollListener_ != nullptr) &&
246 (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_STOP)) {
247 scrollListener_->OnScrollStart();
248 scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_MOVE);
249 }
250 UIAbstractScroll::MoveChildByOffset(offsetX, offsetY);
251 if (xScrollBarVisible_ || yScrollBarVisible_) {
252 RefreshScrollBar();
253 }
254 Invalidate();
255 return true;
256 }
257 return false;
258 }
259
RefreshScrollBar()260 void UIScrollView::RefreshScrollBar()
261 {
262 Rect childrenRect = GetAllChildRelativeRect();
263 /* calculate scrollBar's the proportion of foreground */
264 int16_t totalLen = childrenRect.GetHeight() + 2 * scrollBlankSize_; // 2: two blank space on both sizes
265 int16_t len = GetHeight();
266 if (yScrollBarVisible_) {
267 yScrollBar_->SetForegroundProportion(static_cast<float>(len) / totalLen);
268 /* calculate scrolling progress */
269 yScrollBar_->SetScrollProgress(static_cast<float>(scrollBlankSize_ - childrenRect.GetTop()) / (totalLen - len));
270 }
271 if (xScrollBarVisible_) {
272 /* so do x-bar */
273 totalLen = childrenRect.GetWidth() + 2 * scrollBlankSize_; // 2: two blank space on both sizes
274 len = GetWidth();
275 xScrollBar_->SetForegroundProportion(static_cast<float>(len) / totalLen);
276 xScrollBar_->SetScrollProgress(static_cast<float>(scrollBlankSize_ - childrenRect.GetLeft()) /
277 (totalLen - len));
278 }
279 RefreshAnimator();
280 }
281
CalculateReboundDistance(int16_t & dragDistanceX,int16_t & dragDistanceY)282 void UIScrollView::CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dragDistanceY)
283 {
284 Rect rect = GetAllChildRelativeRect();
285 int16_t top = rect.GetTop();
286 int16_t bottom = rect.GetBottom();
287 int16_t scrollHeight = GetHeight();
288 int16_t left = rect.GetLeft();
289 int16_t right = rect.GetRight();
290 int16_t scrollWidth = GetWidth();
291 if (scrollBlankSize_ < top) {
292 dragDistanceY = scrollBlankSize_ - top;
293 } else if (bottom < scrollHeight - 1) {
294 dragDistanceY = scrollHeight - scrollBlankSize_ - bottom - 1;
295 }
296
297 if (scrollBlankSize_ < left) {
298 dragDistanceX = scrollBlankSize_ - left;
299 } else if (right < scrollWidth - 1) {
300 dragDistanceX = scrollWidth - scrollBlankSize_ - right - 1;
301 }
302 }
303
StopAnimator()304 void UIScrollView::StopAnimator()
305 {
306 if ((scrollListener_ != nullptr) && (scrollListener_->GetScrollState() == OnScrollListener::SCROLL_STATE_MOVE)) {
307 scrollListener_->OnScrollEnd();
308 scrollListener_->SetScrollState(OnScrollListener::SCROLL_STATE_STOP);
309 }
310 UIAbstractScroll::StopAnimator();
311 }
312 } // namespace OHOS
313