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