1 /*
2 * Copyright (c) 2021-2022 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/scroll_bar/scroll_bar_proxy.h"
17
18 #include "core/components/scroll/render_scroll.h"
19 #include "core/components/scroll_bar/render_scroll_bar.h"
20 #include "core/components_v2/grid/render_grid_scroll.h"
21 #include "core/components_v2/list/render_list.h"
22 #include "core/components_v2/water_flow/render_water_flow.h"
23
24 namespace OHOS::Ace {
25
RegisterScrollableNode(const ScrollableNodeInfo & scrollableNode)26 void ScrollBarProxy::RegisterScrollableNode(const ScrollableNodeInfo& scrollableNode)
27 {
28 if (std::find(scrollableNodes_.begin(), scrollableNodes_.end(), scrollableNode) != scrollableNodes_.end()) {
29 LOGE("scrollable node is already exist.");
30 return;
31 }
32 scrollableNodes_.emplace_back(scrollableNode);
33 }
34
RegisterScrollBar(const WeakPtr<RenderScrollBar> & scrollBar)35 void ScrollBarProxy::RegisterScrollBar(const WeakPtr<RenderScrollBar>& scrollBar)
36 {
37 if (std::find(scrollBars_.begin(), scrollBars_.end(), scrollBar) != scrollBars_.end()) {
38 LOGE("scroll bar is already exist.");
39 return;
40 }
41 scrollBars_.emplace_back(scrollBar);
42 }
43
UnRegisterScrollableNode(const WeakPtr<RenderNode> & scrollableNode)44 void ScrollBarProxy::UnRegisterScrollableNode(const WeakPtr<RenderNode>& scrollableNode)
45 {
46 auto iter = std::find_if(scrollableNodes_.begin(), scrollableNodes_.end(),
47 [&scrollableNode](const ScrollableNodeInfo& info) { return scrollableNode == info.scrollableNode; });
48 if (iter != scrollableNodes_.end()) {
49 scrollableNodes_.erase(iter);
50 }
51 }
52
UnRegisterScrollBar(const WeakPtr<RenderScrollBar> & scrollBar)53 void ScrollBarProxy::UnRegisterScrollBar(const WeakPtr<RenderScrollBar>& scrollBar)
54 {
55 auto iter = std::find(scrollBars_.begin(), scrollBars_.end(), scrollBar);
56 if (iter != scrollBars_.end()) {
57 scrollBars_.erase(iter);
58 }
59 }
60
NotifyScrollableNode(double distance,const WeakPtr<RenderScrollBar> & weakScrollBar) const61 void ScrollBarProxy::NotifyScrollableNode(double distance, const WeakPtr<RenderScrollBar>& weakScrollBar) const
62 {
63 auto scrollBar = weakScrollBar.Upgrade();
64 if (!scrollBar) {
65 LOGE("ScrollBar has been released.");
66 return;
67 }
68
69 auto scrollBarChild = scrollBar->GetLastChild();
70 if (!scrollBarChild) {
71 LOGE("ScrollBar has no child.");
72 return;
73 }
74
75 for (const auto& [weakScrollableNode, onPositionChanged] : scrollableNodes_) {
76 if (!onPositionChanged) {
77 continue;
78 }
79 auto scrollable = weakScrollableNode.Upgrade();
80 if (!scrollable || !CheckScrollable(scrollable)) {
81 LOGE("Node is not scrollable node.");
82 continue;
83 }
84
85 auto scrollableChild = scrollable->GetLastChild();
86 if (!scrollableChild) {
87 LOGE("Scrollable node has no child.");
88 continue;
89 }
90
91 auto scrollBarAxis = scrollBar->GetAxis();
92 Size scrollableSize = scrollable->GetLayoutSize();
93 Size scrollableChildSize = GetScrollableChildSize(scrollable, scrollableChild->GetLayoutSize(), scrollBarAxis);
94 Size scrollBarSize = scrollBar->GetLayoutSize();
95 Size scrollBarChildSize = scrollBarChild->GetLayoutSize();
96 auto scrollableAxis = GetScrollableAxis(scrollable);
97 if (scrollableAxis != Axis::FREE && scrollBarAxis != Axis::FREE && scrollableAxis != scrollBarAxis) {
98 LOGE("Axis of ScrollBar and Scroll is not match.");
99 continue;
100 }
101
102 double value = 0.0;
103 auto scrollableDeltaSize = scrollableChildSize - scrollableSize;
104 auto scrollBarDeltaSize = scrollBarSize - scrollBarChildSize;
105 if (scrollBarAxis == Axis::VERTICAL) {
106 if (!NearZero(scrollBarDeltaSize.Height())) {
107 value = distance * scrollableDeltaSize.Height() / scrollBarDeltaSize.Height();
108 }
109 } else {
110 if (!NearZero(scrollBarDeltaSize.Width())) {
111 value = distance * scrollableDeltaSize.Width() / scrollBarDeltaSize.Width();
112 }
113 }
114 constexpr int32_t SCROLL_FROM_BAR = 6; // Source type of scroll.
115 onPositionChanged(value, SCROLL_FROM_BAR);
116 }
117 }
118
NotifyScrollBar(const WeakPtr<RenderNode> & weakScrollableNode) const119 void ScrollBarProxy::NotifyScrollBar(const WeakPtr<RenderNode>& weakScrollableNode) const
120 {
121 auto scrollable = weakScrollableNode.Upgrade();
122 if (!scrollable || !CheckScrollable(scrollable)) {
123 LOGE("Node is not scrollable node.");
124 return;
125 }
126
127 auto scrollableChild = scrollable->GetLastChild();
128 if (!scrollableChild) {
129 LOGE("child of scrollable node is null");
130 return;
131 }
132
133 for (const auto& weakScrollBar : scrollBars_) {
134 auto scrollBar = weakScrollBar.Upgrade();
135 if (!scrollBar) {
136 LOGE("ScrollBar is released.");
137 continue;
138 }
139 auto scrollBarChild = scrollBar->GetLastChild();
140 if (!scrollBarChild) {
141 LOGE("ScrollBar has no child.");
142 continue;
143 }
144 auto scrollBarAxis = scrollBar->GetAxis();
145 Axis scrollableAxis = Axis::NONE;
146 Offset scrollableChildPosition = scrollableChild->GetPosition();
147 Size scrollableSize = scrollable->GetLayoutSize();
148 Size scrollableChildSize = scrollableChild->GetLayoutSize();
149 Size scrollBarSize = scrollBar->GetLayoutSize();
150 Size scrollBarChildSize = scrollBarChild->GetLayoutSize();
151 AdjustParam(scrollable, scrollBarAxis, scrollableAxis, scrollableChildSize, scrollableChildPosition);
152
153 if (scrollBarAxis != Axis::FREE && scrollableAxis != Axis::FREE && scrollBarAxis != scrollableAxis) {
154 LOGE("Axis of ScrollBar and Scroll is not match.");
155 continue;
156 }
157
158 Offset position;
159 if (scrollBarAxis == Axis::VERTICAL) {
160 if (LessOrEqual((scrollableChildSize - scrollableSize).Height(), 0.0) ||
161 LessOrEqual((scrollBarSize - scrollBarChildSize).Height(), 0.0)) {
162 continue;
163 }
164 auto positionY = scrollableChildPosition.GetY() * (scrollBarSize - scrollBarChildSize).Height() /
165 (scrollableChildSize - scrollableSize).Height();
166 positionY = std::clamp(positionY, 0.0, (scrollBarSize - scrollBarChildSize).Height());
167 position.SetY(positionY);
168 } else {
169 if (LessOrEqual((scrollableChildSize - scrollableSize).Width(), 0.0) ||
170 LessOrEqual((scrollBarSize - scrollBarChildSize).Width(), 0.0)) {
171 continue;
172 }
173 auto positionX = scrollableChildPosition.GetX() * (scrollBarSize - scrollBarChildSize).Width() /
174 (scrollableChildSize - scrollableSize).Width();
175 positionX = std::clamp(positionX, 0.0, (scrollBarSize - scrollBarChildSize).Width());
176 position.SetX(positionX);
177 }
178 scrollBar->SetChildPosition(position);
179 scrollBarChild->SetPosition(position);
180 scrollBar->MarkNeedRender();
181 }
182 }
183
StartScrollBarAnimator() const184 void ScrollBarProxy::StartScrollBarAnimator() const
185 {
186 for (const auto& weakScrollBar : scrollBars_) {
187 auto scrollBar = weakScrollBar.Upgrade();
188 if (!scrollBar) {
189 LOGE("ScrollBar is released.");
190 continue;
191 }
192 if (scrollBar->GetDisplayMode() == DisplayMode::AUTO) {
193 scrollBar->StartAnimator();
194 }
195 }
196 }
197
StopScrollBarAnimator() const198 void ScrollBarProxy::StopScrollBarAnimator() const
199 {
200 for (const auto& weakScrollBar : scrollBars_) {
201 auto scrollBar = weakScrollBar.Upgrade();
202 if (!scrollBar) {
203 LOGE("ScrollBar is released.");
204 continue;
205 }
206 scrollBar->StopAnimator();
207 }
208 }
209
CheckScrollable(const RefPtr<RenderNode> & node) const210 bool ScrollBarProxy::CheckScrollable(const RefPtr<RenderNode>& node) const
211 {
212 return AceType::InstanceOf<RenderScroll>(node) || AceType::InstanceOf<V2::RenderGridScroll>(node) ||
213 AceType::InstanceOf<V2::RenderList>(node) || AceType::InstanceOf<V2::RenderWaterFlow>(node);
214 }
215
GetScrollableAxis(const RefPtr<RenderNode> & node) const216 Axis ScrollBarProxy::GetScrollableAxis(const RefPtr<RenderNode>& node) const
217 {
218 auto renderScroll = AceType::DynamicCast<RenderScroll>(node);
219 if (renderScroll) {
220 return renderScroll->GetAxis();
221 }
222 auto renderGridScroll = AceType::DynamicCast<V2::RenderGridScroll>(node);
223 if (renderGridScroll) {
224 return renderGridScroll->GetAxis();
225 }
226 auto renderList = AceType::DynamicCast<V2::RenderList>(node);
227 if (renderList) {
228 return renderList->GetAxis();
229 }
230 auto renderWaterFlow = AceType::DynamicCast<V2::RenderWaterFlow>(node);
231 if (renderWaterFlow) {
232 return renderWaterFlow->GetAxis();
233 }
234 return Axis::NONE;
235 }
236
GetScrollableChildSize(const RefPtr<RenderNode> & scrollable,const Size & scrollableChildSize,Axis scrollBarAxis) const237 Size ScrollBarProxy::GetScrollableChildSize(
238 const RefPtr<RenderNode>& scrollable, const Size& scrollableChildSize, Axis scrollBarAxis) const
239 {
240 Size result = scrollableChildSize;
241 auto renderScroll = AceType::DynamicCast<RenderScroll>(scrollable);
242 if (renderScroll) {
243 scrollBarAxis == Axis::VERTICAL ? result.SetHeight(renderScroll->GetEstimatedHeight())
244 : result.SetWidth(renderScroll->GetEstimatedHeight());
245 return result;
246 }
247 auto renderGridScroll = AceType::DynamicCast<V2::RenderGridScroll>(scrollable);
248 if (renderGridScroll) {
249 scrollBarAxis == Axis::VERTICAL ? result.SetHeight(renderGridScroll->GetEstimatedHeight())
250 : result.SetWidth(renderGridScroll->GetEstimatedHeight());
251 return result;
252 }
253 auto renderList = AceType::DynamicCast<V2::RenderList>(scrollable);
254 if (renderList) {
255 scrollBarAxis == Axis::VERTICAL ? result.SetHeight(renderList->GetEstimatedHeight())
256 : result.SetWidth(renderList->GetEstimatedHeight());
257 return result;
258 }
259 auto renderWaterFlow = AceType::DynamicCast<V2::RenderWaterFlow>(scrollable);
260 if (renderWaterFlow) {
261 scrollBarAxis == Axis::VERTICAL ? result.SetHeight(renderWaterFlow->GetEstimatedHeight())
262 : result.SetWidth(renderWaterFlow->GetEstimatedHeight());
263 return result;
264 }
265 return result;
266 }
267
AdjustParam(const RefPtr<RenderNode> & scrollable,Axis scrollBarAxis,Axis & scrollableAxis,Size & scrollableChildSize,Offset & scrollableChildPosition) const268 void ScrollBarProxy::AdjustParam(const RefPtr<RenderNode>& scrollable, Axis scrollBarAxis, Axis& scrollableAxis,
269 Size& scrollableChildSize, Offset& scrollableChildPosition) const
270 {
271 auto renderScroll = AceType::DynamicCast<RenderScroll>(scrollable);
272 if (renderScroll) {
273 scrollBarAxis == Axis::VERTICAL ? scrollableChildSize.SetHeight(renderScroll->GetEstimatedHeight())
274 : scrollableChildSize.SetWidth(renderScroll->GetEstimatedHeight());
275 scrollableAxis = renderScroll->GetAxis();
276 scrollableChildPosition = renderScroll->GetLastOffset();
277 return;
278 }
279
280 auto renderGridScroll = AceType::DynamicCast<V2::RenderGridScroll>(scrollable);
281 if (renderGridScroll) {
282 scrollBarAxis == Axis::VERTICAL ? scrollableChildSize.SetHeight(renderGridScroll->GetEstimatedHeight())
283 : scrollableChildSize.SetWidth(renderGridScroll->GetEstimatedHeight());
284 scrollableAxis = renderGridScroll->GetAxis();
285 scrollableChildPosition = renderGridScroll->GetLastOffset();
286 return;
287 }
288
289 auto renderList = AceType::DynamicCast<V2::RenderList>(scrollable);
290 if (renderList) {
291 scrollBarAxis == Axis::VERTICAL ? scrollableChildSize.SetHeight(renderList->GetEstimatedHeight())
292 : scrollableChildSize.SetWidth(renderList->GetEstimatedHeight());
293 scrollableAxis = renderList->GetAxis();
294 scrollableChildPosition = renderList->GetLastOffset();
295 }
296
297 auto renderWaterFlow = AceType::DynamicCast<V2::RenderWaterFlow>(scrollable);
298 if (renderWaterFlow) {
299 scrollBarAxis == Axis::VERTICAL ? scrollableChildSize.SetHeight(renderWaterFlow->GetEstimatedHeight())
300 : scrollableChildSize.SetWidth(renderWaterFlow->GetEstimatedHeight());
301 scrollableAxis = renderWaterFlow->GetAxis();
302 scrollableChildPosition = renderWaterFlow->GetLastOffset();
303 return;
304 }
305 }
306
307 } // namespace OHOS::Ace