1 /* 2 * Copyright (c) 2023 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLLABLE_SCROLLABLE_PATTERN_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLLABLE_SCROLLABLE_PATTERN_H 18 19 #include "base/geometry/axis.h" 20 #include "core/animation/select_motion.h" 21 #include "core/components_ng/pattern/pattern.h" 22 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h" 23 #include "core/components_ng/pattern/scroll/inner/scroll_bar_overlay_modifier.h" 24 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h" 25 #include "core/components_ng/pattern/scrollable/scrollable_coordination_event.h" 26 #include "core/components_ng/pattern/scrollable/scrollable_paint_property.h" 27 #include "core/event/mouse_event.h" 28 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h" 29 30 namespace OHOS::Ace::NG { 31 #ifndef WEARABLE_PRODUCT 32 constexpr double FRICTION = 0.6; 33 #else 34 constexpr double FRICTION = 0.9; 35 #endif 36 class ScrollablePattern : public Pattern { 37 DECLARE_ACE_TYPE(ScrollablePattern, Pattern); 38 39 public: IsAtomicNode()40 bool IsAtomicNode() const override 41 { 42 return false; 43 } 44 45 // scrollable GetAxis()46 Axis GetAxis() const 47 { 48 return axis_; 49 } 50 void SetAxis(Axis axis); 51 virtual bool UpdateCurrentOffset(float delta, int32_t source) = 0; IsScrollable()52 virtual bool IsScrollable() const 53 { 54 return false; 55 } 56 virtual bool IsAtTop() const = 0; 57 virtual bool IsAtBottom() const = 0; OutBoundaryCallback()58 virtual bool OutBoundaryCallback() 59 { 60 return IsAtTop() || IsAtBottom(); 61 } 62 void AddScrollEvent(); GetScrollableEvent()63 RefPtr<ScrollableEvent> GetScrollableEvent() 64 { 65 return scrollableEvent_; 66 } 67 virtual bool OnScrollCallback(float offset, int32_t source); OnScrollEndCallback()68 virtual void OnScrollEndCallback() {}; OnScrollStartCallback()69 virtual void OnScrollStartCallback() {}; ScrollableIdle()70 bool ScrollableIdle() 71 { 72 return !scrollableEvent_ || scrollableEvent_->Idle(); 73 } SetScrollEnable(bool enable)74 void SetScrollEnable(bool enable) 75 { 76 CHECK_NULL_VOID_NOLOG(scrollableEvent_); 77 scrollableEvent_->SetEnabled(enable); 78 if (!enable) { 79 scrollableEvent_->SetAxis(Axis::NONE); 80 } else { 81 scrollableEvent_->SetAxis(axis_); 82 } 83 } 84 void SetScrollableAxis(Axis axis); 85 RefPtr<GestureEventHub> GetGestureHub(); 86 RefPtr<InputEventHub> GetInputHub(); 87 88 // edgeEffect GetScrollEdgeEffect()89 const RefPtr<ScrollEdgeEffect>& GetScrollEdgeEffect() const 90 { 91 return scrollEffect_; 92 } 93 void SetEdgeEffect(EdgeEffect edgeEffect); 94 void AddScrollEdgeEffect(RefPtr<ScrollEdgeEffect> edgeEffect); 95 bool HandleEdgeEffect(float offset, int32_t source, const SizeF& size); SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect> & scrollEffect)96 virtual void SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect) {} IsRestrictBoundary()97 bool IsRestrictBoundary() 98 { 99 return !scrollEffect_ || scrollEffect_->IsRestrictBoundary(); 100 } 101 102 // scrollBar 103 virtual void UpdateScrollBarOffset() = 0; 104 void SetScrollBar(const std::unique_ptr<ScrollBarProperty>& property); 105 void SetScrollBar(DisplayMode displayMode); 106 void SetScrollBarProxy(const RefPtr<ScrollBarProxy>& scrollBarProxy); 107 void CreateScrollBarOverlayModifier(); 108 GetScrollableDistance()109 float GetScrollableDistance() const 110 { 111 return estimatedHeight_; 112 } 113 GetBarOffset()114 float GetBarOffset() const 115 { 116 return barOffset_; 117 } 118 GetScrollBarOutBoundaryExtent()119 double GetScrollBarOutBoundaryExtent() const 120 { 121 return scrollBarOutBoundaryExtent_; 122 } 123 SetScrollBarOutBoundaryExtent(float scrollBarOutBoundaryExtent)124 void SetScrollBarOutBoundaryExtent(float scrollBarOutBoundaryExtent) 125 { 126 scrollBarOutBoundaryExtent_ = scrollBarOutBoundaryExtent; 127 } 128 129 void HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent); 130 GetMainSize(const SizeF & size)131 double GetMainSize(const SizeF& size) const 132 { 133 return axis_ == Axis::HORIZONTAL ? size.Width() : size.Height(); 134 } 135 SetCoordinationEvent(RefPtr<ScrollableCoordinationEvent> coordinationEvent)136 void SetCoordinationEvent(RefPtr<ScrollableCoordinationEvent> coordinationEvent) 137 { 138 coordinationEvent_ = coordinationEvent; 139 } 140 IsScrollableStopped()141 bool IsScrollableStopped() const 142 { 143 CHECK_NULL_RETURN_NOLOG(scrollableEvent_, true); 144 auto scrollable = scrollableEvent_->GetScrollable(); 145 CHECK_NULL_RETURN_NOLOG(scrollable, true); 146 return scrollable->IsStopped(); 147 } 148 StopScrollable()149 void StopScrollable() 150 { 151 CHECK_NULL_VOID_NOLOG(scrollableEvent_); 152 auto scrollable = scrollableEvent_->GetScrollable(); 153 CHECK_NULL_VOID_NOLOG(scrollable); 154 scrollable->StopScrollable(); 155 } 156 StartScrollSnapMotion(float scrollSnapDelta,float scrollSnapVelocity)157 void StartScrollSnapMotion(float scrollSnapDelta, float scrollSnapVelocity) 158 { 159 CHECK_NULL_VOID_NOLOG(scrollableEvent_); 160 auto scrollable = scrollableEvent_->GetScrollable(); 161 CHECK_NULL_VOID_NOLOG(scrollable); 162 scrollable->ProcessScrollSnapSpringMotion(scrollSnapDelta, scrollSnapVelocity); 163 } 164 SetScrollFrameBeginCallback(const ScrollFrameBeginCallback & scrollFrameBeginCallback)165 void SetScrollFrameBeginCallback(const ScrollFrameBeginCallback& scrollFrameBeginCallback) 166 { 167 CHECK_NULL_VOID_NOLOG(scrollableEvent_); 168 auto scrollable = scrollableEvent_->GetScrollable(); 169 CHECK_NULL_VOID_NOLOG(scrollable); 170 scrollable->SetOnScrollFrameBegin(scrollFrameBeginCallback); 171 } 172 IsScrollableSpringEffect()173 bool IsScrollableSpringEffect() const 174 { 175 CHECK_NULL_RETURN_NOLOG(scrollEffect_, false); 176 return scrollEffect_->IsSpringEffect(); 177 } 178 SetCoordEventNeedSpringEffect(bool IsCoordEventNeedSpring)179 void SetCoordEventNeedSpringEffect(bool IsCoordEventNeedSpring) 180 { 181 isCoordEventNeedSpring_ = IsCoordEventNeedSpring; 182 } 183 184 void SetNestedScroll(const NestedScrollOptions& nestedOpt); 185 RefPtr<ScrollablePattern> GetParentScrollable(); 186 void GetParentNavigition(); 187 GetOverScrollOffset(double delta)188 virtual OverScrollOffset GetOverScrollOffset(double delta) const 189 { 190 return { 0, 0 }; 191 } 192 OnScrollSnapCallback(double targetOffset,double velocity)193 virtual bool OnScrollSnapCallback(double targetOffset, double velocity) 194 { 195 return false; 196 } 197 StartScrollBarAnimatorByProxy()198 void StartScrollBarAnimatorByProxy() 199 { 200 if (scrollBarProxy_) { 201 scrollBarProxy_->StartScrollBarAnimator(); 202 } 203 } 204 StopScrollBarAnimatorByProxy()205 void StopScrollBarAnimatorByProxy() 206 { 207 if (scrollBarProxy_) { 208 scrollBarProxy_->StopScrollBarAnimator(); 209 } 210 } 211 212 void SetFriction(double friction); 213 GetFriction()214 double GetFriction() const 215 { 216 return friction_; 217 } 218 219 void StopAnimate(); AnimateRunning()220 bool AnimateRunning() const 221 { 222 return animator_ && animator_->IsRunning(); 223 } AnimateStoped()224 bool AnimateStoped() const 225 { 226 return !animator_ || animator_->IsStopped(); 227 } AbortScrollAnimator()228 void AbortScrollAnimator() 229 { 230 if (animator_ && !animator_->IsStopped()) { 231 scrollAbort_ = true; 232 animator_->Stop(); 233 } 234 } GetScrollAbort()235 bool GetScrollAbort() const 236 { 237 return scrollAbort_; 238 } SetScrollAbort(bool abort)239 void SetScrollAbort(bool abort) 240 { 241 scrollAbort_ = abort; 242 } 243 void PlaySpringAnimation(float position, float velocity, float mass, float stiffness, float damping); GetTotalOffset()244 virtual float GetTotalOffset() const 245 { 246 return 0.0f; 247 } 248 // main size of all children GetTotalHeight()249 virtual float GetTotalHeight() const 250 { 251 return 0.0f; 252 } OnAnimateStop()253 virtual void OnAnimateStop() {} 254 virtual void ScrollTo(float position); 255 virtual void AnimateTo(float position, float duration, const RefPtr<Curve>& curve, bool smooth); CanOverScroll(int32_t source)256 bool CanOverScroll(int32_t source) 257 { 258 return (IsScrollableSpringEffect() && source != SCROLL_FROM_AXIS && source != SCROLL_FROM_BAR && 259 source != SCROLL_FROM_NONE && IsScrollable() && (!ScrollableIdle() || animateOverScroll_)); 260 } 261 void MarkSelectedItems(); 262 bool ShouldSelectScrollBeStopped(); 263 264 // scrollSnap CalePredictSnapOffset(float delta)265 virtual std::optional<float> CalePredictSnapOffset(float delta) 266 { 267 std::optional<float> predictSnapPosition; 268 return predictSnapPosition; 269 } 270 NeedScrollSnapToSide(float delta)271 virtual bool NeedScrollSnapToSide(float delta) 272 { 273 return false; 274 } 275 SetScrollSource(int32_t scrollSource)276 void SetScrollSource(int32_t scrollSource) 277 { 278 if (scrollSource == SCROLL_FROM_JUMP) { 279 if (scrollBar_ && scrollBarOverlayModifier_) { 280 scrollBarOverlayModifier_->SetOpacity(UINT8_MAX); 281 scrollBar_->ScheduleDisapplearDelayTask(); 282 } 283 StopScrollBarAnimatorByProxy(); 284 StartScrollBarAnimatorByProxy(); 285 } 286 287 scrollSource_ = scrollSource; 288 } 289 GetScrollSource()290 int32_t GetScrollSource() const 291 { 292 return scrollSource_; 293 } 294 295 protected: GetScrollBar()296 RefPtr<ScrollBar> GetScrollBar() const 297 { 298 return scrollBar_; 299 } GetScrollBarProxy()300 RefPtr<NG::ScrollBarProxy> GetScrollBarProxy() const 301 { 302 return scrollBarProxy_; 303 } 304 void UpdateScrollBarRegion(float offset, float estimatedHeight, Size viewPort, Offset viewOffset); 305 306 // select with mouse 307 struct ItemSelectedStatus { 308 std::function<void(bool)> onSelected; 309 std::function<void(bool)> selectChangeEvent; 310 RectF rect; 311 bool selected = false; FireSelectChangeEventItemSelectedStatus312 void FireSelectChangeEvent(bool isSelected) 313 { 314 if (selected == isSelected) { 315 return; 316 } 317 selected = isSelected; 318 if (onSelected) { 319 onSelected(isSelected); 320 } 321 if (selectChangeEvent) { 322 selectChangeEvent(isSelected); 323 } 324 } 325 }; 326 void InitMouseEvent(); 327 void UninitMouseEvent(); 328 void DrawSelectedZone(const RectF& selectedZone); 329 void ClearSelectedZone(); 330 bool multiSelectable_ = false; 331 bool isMouseEventInit_ = false; 332 OffsetF mouseStartOffset_; 333 float totalOffsetOfMousePressed_ = 0.0f; 334 std::unordered_map<int32_t, ItemSelectedStatus> itemToBeSelected_; 335 GetScrollBarOverlayModifier()336 RefPtr<ScrollBarOverlayModifier> GetScrollBarOverlayModifier() const 337 { 338 return scrollBarOverlayModifier_; 339 } 340 SetScrollBarOverlayModifier(RefPtr<ScrollBarOverlayModifier> scrollBarOverlayModifier)341 void SetScrollBarOverlayModifier(RefPtr<ScrollBarOverlayModifier> scrollBarOverlayModifier) 342 { 343 scrollBarOverlayModifier_ = scrollBarOverlayModifier; 344 } 345 346 private: 347 void DraggedDownScrollEndProcess(); 348 void RegisterScrollBarEventTask(); 349 void OnScrollEnd(); 350 bool OnScrollPosition(double offset, int32_t source); 351 void SetParentScrollable(); 352 void ProcessNavBarReactOnStart(); 353 bool ProcessNavBarReactOnUpdate(bool isDraggedDown, float offset); 354 void ProcessNavBarReactOnEnd(); 355 356 void OnAttachToFrameNode() override; 357 358 // select with mouse MultiSelectWithoutKeyboard(const RectF & selectedZone)359 virtual void MultiSelectWithoutKeyboard(const RectF& selectedZone) {}; ClearMultiSelect()360 virtual void ClearMultiSelect() {}; IsItemSelected(const MouseInfo & info)361 virtual bool IsItemSelected(const MouseInfo& info) 362 { 363 return false; 364 } 365 void ClearInvisibleItemsSelectedStatus(); 366 void HandleInvisibleItemsSelectedStatus(const RectF& selectedZone); 367 void HandleMouseEventWithoutKeyboard(const MouseInfo& info); 368 void OnMouseRelease(); 369 void SelectWithScroll(); 370 RectF ComputeSelectedZone(const OffsetF& startOffset, const OffsetF& endOffset); 371 float GetOutOfScrollableOffset() const; 372 void SetNavBarVelocity(); 373 374 Axis axis_; 375 RefPtr<ScrollableEvent> scrollableEvent_; 376 RefPtr<ScrollEdgeEffect> scrollEffect_; 377 RefPtr<ScrollableCoordinationEvent> coordinationEvent_; 378 int32_t scrollSource_ = SCROLL_FROM_NONE; 379 // scrollBar 380 RefPtr<ScrollBar> scrollBar_; 381 RefPtr<NG::ScrollBarProxy> scrollBarProxy_; 382 RefPtr<ScrollBarOverlayModifier> scrollBarOverlayModifier_; 383 float barOffset_ = 0.0f; 384 float estimatedHeight_ = 0.0f; 385 bool isReactInParentMovement_ = false; 386 double scrollBarOutBoundaryExtent_ = 0.0; 387 bool isCoordEventNeedSpring_ = true; 388 double friction_ = FRICTION; 389 // scroller 390 RefPtr<Animator> animator_; 391 RefPtr<SpringMotion> springMotion_; 392 bool scrollAbort_ = false; 393 bool animateOverScroll_ = false; 394 395 NestedScrollOptions nestedScroll_; 396 397 // select with mouse 398 bool mousePressed_ = false; 399 OffsetF mouseEndOffset_; 400 OffsetF mousePressOffset_; 401 MouseInfo lastMouseMove_; 402 RefPtr<SelectMotion> selectMotion_; 403 RefPtr<InputEvent> mouseEvent_; 404 RefPtr<NavBarPattern> navBarPattern_; 405 }; 406 } // namespace OHOS::Ace::NG 407 408 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_SCROLL_PATTERN_H 409