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 24namespace OHOS { 25UIScrollView::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 42bool 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 51bool 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 69void 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 83bool UIScrollView::OnPressEvent(const PressEvent& event) 84{ 85 StopAnimator(); 86 return UIView::OnPressEvent(event); 87} 88 89#if defined(ENABLE_ROTATE_INPUT) && ENABLE_ROTATE_INPUT 90bool 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 140bool 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 149void 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 164void 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 178bool 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 210bool 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 242bool 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 260void 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 282void 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 304void 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