• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components_ng/pattern/grid/grid_pattern.h"
20 #include "core/components_ng/pattern/list/list_pattern.h"
21 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
22 #include "core/components_ng/pattern/scroll_bar/scroll_bar_pattern.h"
23 
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t SCROLL_FROM_BAR = 6; // Source type of scroll.
27 
CheckScrollable(const RefPtr<Pattern> & pattern)28 bool CheckScrollable(const RefPtr<Pattern>& pattern)
29 {
30     return AceType::InstanceOf<ScrollablePattern>(pattern);
31 }
32 
GetScrollableNodeDistance(RefPtr<Pattern> pattern)33 float GetScrollableNodeDistance(RefPtr<Pattern> pattern)
34 {
35     auto scrollablePattern = AceType::DynamicCast<ScrollablePattern>(pattern);
36     CHECK_NULL_RETURN(scrollablePattern, 0.0f);
37     return scrollablePattern->GetScrollableDistance();
38 }
39 
GetScrollableNodeOffset(RefPtr<Pattern> pattern)40 float GetScrollableNodeOffset(RefPtr<Pattern> pattern)
41 {
42     auto scrollablePattern = AceType::DynamicCast<ScrollablePattern>(pattern);
43     CHECK_NULL_RETURN(scrollablePattern, 0.0f);
44     return scrollablePattern->GetBarOffset();
45 }
46 
GetScrollBarOutBoundaryExtent(RefPtr<Pattern> pattern)47 double GetScrollBarOutBoundaryExtent(RefPtr<Pattern> pattern)
48 {
49     auto scrollPattern = AceType::DynamicCast<ScrollablePattern>(pattern);
50     CHECK_NULL_RETURN(scrollPattern, 0.0f);
51     return scrollPattern->GetScrollBarOutBoundaryExtent();
52 }
53 } // namespace
54 
RegisterScrollableNode(const ScrollableNodeInfo & scrollableNode)55 void ScrollBarProxy::RegisterScrollableNode(const ScrollableNodeInfo& scrollableNode)
56 {
57     if (std::find(scrollableNodes_.begin(), scrollableNodes_.end(), scrollableNode) != scrollableNodes_.end()) {
58         return;
59     }
60     scrollableNodes_.emplace_back(scrollableNode);
61 }
62 
RegisterScrollBar(const WeakPtr<ScrollBarPattern> & scrollBar)63 void ScrollBarProxy::RegisterScrollBar(const WeakPtr<ScrollBarPattern>& scrollBar)
64 {
65     if (std::find(scrollBars_.begin(), scrollBars_.end(), scrollBar) != scrollBars_.end()) {
66         return;
67     }
68     scrollBars_.emplace_back(scrollBar);
69 }
70 
UnRegisterScrollableNode(const WeakPtr<ScrollablePattern> & scrollableNode)71 void ScrollBarProxy::UnRegisterScrollableNode(const WeakPtr<ScrollablePattern>& scrollableNode)
72 {
73     auto iter = std::find_if(scrollableNodes_.begin(), scrollableNodes_.end(),
74         [&scrollableNode](const ScrollableNodeInfo& info) { return scrollableNode == info.scrollableNode; });
75     if (iter != scrollableNodes_.end()) {
76         scrollableNodes_.erase(iter);
77     }
78 }
79 
UnRegisterScrollBar(const WeakPtr<ScrollBarPattern> & scrollBar)80 void ScrollBarProxy::UnRegisterScrollBar(const WeakPtr<ScrollBarPattern>& scrollBar)
81 {
82     auto iter = std::find(scrollBars_.begin(), scrollBars_.end(), scrollBar);
83     if (iter != scrollBars_.end()) {
84         scrollBars_.erase(iter);
85     }
86 }
87 
NotifyScrollableNode(float distance,int32_t source,const WeakPtr<ScrollBarPattern> & weakScrollBar) const88 void ScrollBarProxy::NotifyScrollableNode(
89     float distance, int32_t source, const WeakPtr<ScrollBarPattern>& weakScrollBar) const
90 {
91     auto scrollBar = weakScrollBar.Upgrade();
92     CHECK_NULL_VOID(scrollBar);
93     float barScrollableDistance  = scrollBar->GetScrollableDistance();
94 
95     for (const auto& node : scrollableNodes_) {
96         if (node.onPositionChanged == nullptr) {
97             continue;
98         }
99         auto scrollable = node.scrollableNode.Upgrade();
100         if (!scrollable || !CheckScrollable(scrollable)) {
101             continue;
102         }
103         float value = CalcPatternOffset(GetScrollableNodeDistance(scrollable), barScrollableDistance, distance);
104         node.onPositionChanged(value, source);
105         if (node.scrollbarFRcallback) {
106             node.scrollbarFRcallback(0, SceneStatus::RUNNING);
107         }
108     }
109 }
110 
NotifyScrollBarNode(float distance,int32_t source) const111 void ScrollBarProxy::NotifyScrollBarNode(float distance, int32_t source) const
112 {
113     for (const auto& node : scrollableNodes_) {
114         if (node.onPositionChanged == nullptr) {
115             continue;
116         }
117         auto scrollable = node.scrollableNode.Upgrade();
118         if (!scrollable || !CheckScrollable(scrollable)) {
119             continue;
120         }
121         node.onPositionChanged(distance, source);
122         if (node.scrollbarFRcallback) {
123             node.scrollbarFRcallback(0, SceneStatus::RUNNING);
124         }
125     }
126 }
127 
NotifyScrollStart() const128 void ScrollBarProxy::NotifyScrollStart() const
129 {
130     for (const auto& node : scrollableNodes_) {
131         if (node.scrollStartCallback == nullptr) {
132             continue;
133         }
134         node.scrollStartCallback(0, SCROLL_FROM_BAR);
135         if (node.scrollbarFRcallback) {
136             node.scrollbarFRcallback(0, SceneStatus::RUNNING);
137         }
138     }
139 }
140 
NotifyScrollStop() const141 void ScrollBarProxy::NotifyScrollStop() const
142 {
143     for (const auto& node : scrollableNodes_) {
144         if (node.scrollEndCallback == nullptr) {
145             continue;
146         }
147         node.scrollEndCallback();
148         if (node.scrollbarFRcallback) {
149             node.scrollbarFRcallback(0, SceneStatus::RUNNING);
150         }
151     }
152 }
153 
NotifyScrollBar(const WeakPtr<ScrollablePattern> & weakScrollableNode) const154 void ScrollBarProxy::NotifyScrollBar(const WeakPtr<ScrollablePattern>& weakScrollableNode) const
155 {
156     auto scrollable = weakScrollableNode.Upgrade();
157     if (!scrollable || !CheckScrollable(scrollable)) {
158         return;
159     }
160 
161     float controlDistance = GetScrollableNodeDistance(scrollable);
162     float scrollableNodeOffset = -GetScrollableNodeOffset(scrollable); // scroll bar direction is reverse
163     double scrollBarOutBoundaryDistance = GetScrollBarOutBoundaryExtent(scrollable);
164     for (const auto& weakScrollBar : scrollBars_) {
165         auto scrollBar = weakScrollBar.Upgrade();
166         if (!scrollBar) {
167             continue;
168         }
169 
170         scrollBar->SetControlDistance(controlDistance);
171         scrollBar->SetReverse(scrollable->IsReverse());
172         scrollBar->HandleScrollBarOutBoundary(scrollBarOutBoundaryDistance);
173         auto host = scrollBar->GetHost();
174         if (!host) {
175             continue;
176         }
177         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) && !scrollBar->HasChild()) {
178             scrollBar->SetScrollableNodeOffset(scrollableNodeOffset);
179             scrollBar->UpdateScrollBarOffset();
180             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
181         } else {
182             scrollBar->SetScrollableNodeOffset(
183                 !scrollable->IsReverse() ? scrollableNodeOffset : controlDistance - scrollableNodeOffset);
184             host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
185         }
186     }
187 }
188 
StartScrollBarAnimator() const189 void ScrollBarProxy::StartScrollBarAnimator() const
190 {
191     for (const auto& weakScrollBar : scrollBars_) {
192         auto scrollBar = weakScrollBar.Upgrade();
193         if (!scrollBar) {
194             continue;
195         }
196         if (scrollBar->GetDisplayMode() == DisplayMode::AUTO) {
197             scrollBar->StartDisappearAnimator();
198         }
199         // AccessibilityEventType::SCROLL_END
200     }
201 }
202 
StopScrollBarAnimator() const203 void ScrollBarProxy::StopScrollBarAnimator() const
204 {
205     for (const auto& weakScrollBar : scrollBars_) {
206         auto scrollBar = weakScrollBar.Upgrade();
207         if (!scrollBar) {
208             continue;
209         }
210         scrollBar->StopDisappearAnimator();
211         scrollBar->StopMotion();
212         // AccessibilityEventType::SCROLL_START
213     }
214 }
215 
NotifySnapScroll(float delta,float velocity,float barScrollableDistance,float dragDistance) const216 bool ScrollBarProxy::NotifySnapScroll(
217     float delta, float velocity, float barScrollableDistance, float dragDistance) const
218 {
219     for (const auto& node : scrollableNodes_) {
220         auto scrollable = node.scrollableNode.Upgrade();
221         if (!scrollable || !CheckScrollable(scrollable) || !node.calePredictSnapOffsetCallback ||
222             !node.startScrollSnapMotionCallback) {
223             continue;
224         }
225         auto controlDistance = GetScrollableNodeDistance(scrollable);
226         auto patternOffset = CalcPatternOffset(controlDistance, barScrollableDistance, delta);
227         dragDistance = CalcPatternOffset(controlDistance, barScrollableDistance, dragDistance);
228         auto predictSnapOffset = node.calePredictSnapOffsetCallback(patternOffset, dragDistance, -velocity);
229         // If snap scrolling, predictSnapOffset will has a value.
230         if (predictSnapOffset.has_value() && !NearZero(predictSnapOffset.value())) {
231             node.startScrollSnapMotionCallback(predictSnapOffset.value(), velocity);
232             // Outer scrollBar can only control one snap scrollable component.
233             return true;
234         }
235     }
236     return false;
237 }
238 
CalcPatternOffset(float controlDistance,float barScrollableDistance,float delta) const239 float ScrollBarProxy::CalcPatternOffset(float controlDistance, float barScrollableDistance, float delta) const
240 {
241     if (!NearZero(barScrollableDistance)) {
242         return delta * controlDistance / barScrollableDistance;
243     } else {
244         return 0.0f;
245     }
246 }
247 
SetScrollEnabled(bool scrollEnabled,const WeakPtr<ScrollablePattern> & weakScrollableNode) const248 void ScrollBarProxy::SetScrollEnabled(bool scrollEnabled, const WeakPtr<ScrollablePattern>& weakScrollableNode) const
249 {
250     auto scrollable = weakScrollableNode.Upgrade();
251     if (!scrollable || !CheckScrollable(scrollable)) {
252         return;
253     }
254 
255     for (const auto& weakScrollBar : scrollBars_) {
256         auto scrollBar = weakScrollBar.Upgrade();
257         if (!scrollBar) {
258             continue;
259         }
260 
261         scrollBar->SetScrollEnabled(scrollEnabled);
262     }
263 }
264 } // namespace OHOS::Ace::NG
265