1 /*
2 * Copyright (c) 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 "core/components/common/properties/scroll_bar.h"
17
18 #include "core/animation/curve_animation.h"
19
20 namespace OHOS::Ace {
21
InBarRegion(const Point & point) const22 bool ScrollBar::InBarRegion(const Point& point) const
23 {
24 if (NeedScrollBar() && shapeMode_ == ShapeMode::RECT) {
25 return touchRegion_.IsInRegion(point);
26 }
27 return false;
28 }
29
UpdateScrollBarRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)30 void ScrollBar::UpdateScrollBarRegion(
31 const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
32 {
33 if (!NearZero(estimatedHeight)) {
34 SetBarRegion(offset, size);
35 if (shapeMode_ == ShapeMode::RECT) {
36 SetRectTrickRegion(offset, size, lastOffset, estimatedHeight);
37 } else {
38 SetRoundTrickRegion(offset, size, lastOffset, estimatedHeight);
39 }
40 }
41 }
42
SetBarRegion(const Offset & offset,const Size & size)43 void ScrollBar::SetBarRegion(const Offset& offset, const Size& size)
44 {
45 double normalWidth = NormalizeToPx(normalWidth_);
46 if (shapeMode_ == ShapeMode::RECT) {
47 double height = std::max(size.Height() - NormalizeToPx(reservedHeight_), 0.0);
48 if (positionMode_ == PositionMode::LEFT) {
49 barRect_ = Rect(0.0, 0.0, normalWidth, height) + offset;
50 } else if (positionMode_ == PositionMode::RIGHT) {
51 barRect_ = Rect(size.Width() - normalWidth - NormalizeToPx(padding_.Right()), 0.0,
52 normalWidth, height) + offset;
53 } else if (positionMode_ == PositionMode::BOTTOM) {
54 auto scrollBarWidth = std::max(size.Width() - NormalizeToPx(reservedHeight_), 0.0);
55 barRect_ = Rect(0.0, size.Height() - normalWidth - NormalizeToPx(padding_.Bottom()),
56 scrollBarWidth, normalWidth) + offset;
57 }
58 }
59 }
60
SetRectTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)61 void ScrollBar::SetRectTrickRegion(const Offset& offset, const Size& size,
62 const Offset& lastOffset, double estimatedHeight)
63 {
64 double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
65 double barRegionSize = std::max(mainSize - NormalizeToPx(reservedHeight_), 0.0);
66 double activeSize = barRegionSize * mainSize / estimatedHeight - outBoundary_;
67 if (!NearEqual(mainSize, estimatedHeight)) {
68 if (!NearZero(outBoundary_)) {
69 activeSize = std::max(
70 std::max(activeSize, NormalizeToPx(minHeight_) - outBoundary_), NormalizeToPx(minDynamicHeight_));
71 } else {
72 activeSize = std::max(activeSize, NormalizeToPx(minHeight_));
73 }
74 double lastMainOffset =
75 std::max(positionMode_ == PositionMode::BOTTOM ? lastOffset.GetX() : lastOffset.GetY(), 0.0);
76 double activeMainOffset = (mainSize - activeSize) * lastMainOffset / (estimatedHeight - mainSize);
77 activeMainOffset = std::min(activeMainOffset, barRegionSize - activeSize);
78 double normalWidth = NormalizeToPx(normalWidth_);
79 if (positionMode_ == PositionMode::LEFT) {
80 activeRect_ = Rect(-NormalizeToPx(position_), activeMainOffset, normalWidth, activeSize) + offset;
81 touchRegion_ = activeRect_ + Size(NormalizeToPx(touchWidth_), 0);
82 } else if (positionMode_ == PositionMode::RIGHT) {
83 double x = size.Width() - normalWidth - NormalizeToPx(padding_.Right()) + NormalizeToPx(position_);
84 activeRect_ = Rect(x, activeMainOffset, normalWidth, activeSize) + offset;
85 // Update the hot region
86 touchRegion_ =
87 activeRect_ -
88 Offset(NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Right()),
89 0.0) +
90 Size(NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_), 0);
91 } else if (positionMode_ == PositionMode::BOTTOM) {
92 auto positionY =
93 size.Height() - normalWidth - NormalizeToPx(padding_.Bottom()) + NormalizeToPx(position_);
94 activeRect_ = Rect(activeMainOffset, positionY, activeSize, normalWidth) + offset;
95 auto hotRegionOffset =
96 Offset(0.0, NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_)
97 - NormalizeToPx(padding_.Bottom()));
98 auto hotRegionSize = Size(0, NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_));
99 touchRegion_ = activeRect_ - hotRegionOffset + hotRegionSize;
100 }
101 }
102 }
103
SetRoundTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)104 void ScrollBar::SetRoundTrickRegion(const Offset& offset, const Size& size,
105 const Offset& lastOffset, double estimatedHeight)
106 {
107 double diameter = std::min(size.Width(), size.Height());
108 if (!NearEqual(estimatedHeight, diameter)) {
109 double maxAngle = bottomAngle_ - topAngle_;
110 trickSweepAngle_ = std::max(diameter * maxAngle / estimatedHeight, minAngle_);
111 double lastOffsetY = std::max(lastOffset.GetY(), 0.0);
112 double trickStartAngle = (maxAngle - trickSweepAngle_) * lastOffsetY / (estimatedHeight - diameter);
113 trickStartAngle = std::clamp(0.0, trickStartAngle, maxAngle) - maxAngle * FACTOR_HALF;
114 if (positionMode_ == PositionMode::LEFT) {
115 if (trickStartAngle > 0.0) {
116 trickStartAngle_ = STRAIGHT_ANGLE - trickStartAngle;
117 } else {
118 trickStartAngle_ = -(trickStartAngle + STRAIGHT_ANGLE);
119 }
120 trickSweepAngle_ = -trickSweepAngle_;
121 } else {
122 trickStartAngle_ = trickStartAngle;
123 }
124 }
125 }
126
NeedScrollBar() const127 bool ScrollBar::NeedScrollBar() const
128 {
129 return displayMode_ == DisplayMode::AUTO || displayMode_ == DisplayMode::ON;
130 }
131
NeedPaint() const132 bool ScrollBar::NeedPaint() const
133 {
134 return NeedScrollBar() && isScrollable_;
135 }
136
GetNormalWidthToPx() const137 double ScrollBar::GetNormalWidthToPx() const
138 {
139 return NormalizeToPx(normalWidth_);
140 }
141
InitScrollBar(const WeakPtr<RenderNode> & scroll,const WeakPtr<PipelineContext> & context)142 void ScrollBar::InitScrollBar(const WeakPtr<RenderNode>& scroll, const WeakPtr<PipelineContext>& context)
143 {
144 pipelineContext_ = context;
145 if (NeedScrollBar()) {
146 if (!barController_) {
147 barController_ = AceType::MakeRefPtr<ScrollBarController>();
148 }
149 bool isVertical = (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT);
150 barController_->Initialize(context, isVertical);
151 barController_->SetScrollNode(scroll);
152 barController_->SetActiveWidth(activeWidth_);
153 barController_->SetInactiveWidth(inactiveWidth_);
154 }
155 }
156
NormalizeToPx(const Dimension & dimension) const157 double ScrollBar::NormalizeToPx(const Dimension& dimension) const
158 {
159 auto pipelineContext = pipelineContext_.Upgrade();
160 if (!pipelineContext) {
161 LOGE("NormalizeToPx failed");
162 return 0.0;
163 }
164 return pipelineContext->NormalizeToPx(dimension);
165 }
166
SetCallBack(const ScrollBarPositionCallback & callback,const ScrollBarEndCallback & barEndCallback,const ScrollBarEventCallback & scrollEndCallback)167 void ScrollBar::SetCallBack(const ScrollBarPositionCallback& callback, const ScrollBarEndCallback& barEndCallback,
168 const ScrollBarEventCallback& scrollEndCallback)
169 {
170 if (barController_) {
171 barController_->SetCallback(callback);
172 barController_->SetBarEndCallback(barEndCallback);
173 barController_->SetScrollEndCallback(scrollEndCallback);
174 barController_->SetTouchDownCallback([weakScrollBar = AceType::WeakClaim(this)](double value) {
175 auto scrollBar = weakScrollBar.Upgrade();
176 if (!scrollBar) {
177 LOGE("scrollBar is released");
178 return;
179 }
180 // value is normalized before animation
181 scrollBar->normalWidth_ = Dimension(value, DimensionUnit::PX);
182 });
183 barController_->SetTouchUpCallback([weakScrollBar = AceType::WeakClaim(this)](double value) {
184 auto scrollBar = weakScrollBar.Upgrade();
185 if (!scrollBar) {
186 LOGE("scrollBar is released");
187 return;
188 }
189 // value is normalized before animation
190 scrollBar->normalWidth_ = Dimension(value, DimensionUnit::PX);
191 });
192 }
193 }
194
HandleScrollBarEnd()195 void ScrollBar::HandleScrollBarEnd()
196 {
197 if (displayMode_ == DisplayMode::AUTO) {
198 barController_->HandleScrollBarEnd();
199 }
200 }
201
AddScrollBarController(const Offset & coordinateOffset,TouchTestResult & result)202 void ScrollBar::AddScrollBarController(const Offset& coordinateOffset, TouchTestResult& result)
203 {
204 if (barController_) {
205 barController_->SetCoordinateOffset(coordinateOffset);
206 result.emplace_back(barController_);
207 }
208 }
209
SetActive(bool isActive)210 void ScrollBar::SetActive(bool isActive)
211 {
212 if (barController_) {
213 barController_->SetActive(isActive);
214 }
215 }
216
IsActive() const217 bool ScrollBar::IsActive() const
218 {
219 if (barController_) {
220 return barController_->IsActive();
221 }
222 return false;
223 }
224
GetRootSize() const225 Size ScrollBar::GetRootSize() const
226 {
227 auto context = pipelineContext_.Upgrade();
228 if (context) {
229 auto rootHeight = context->GetRootHeight();
230 auto rootWidth = context->GetRootWidth();
231 return Size(rootWidth, rootHeight);
232 } else {
233 return Size();
234 }
235 }
236
Reset(const RefPtr<ScrollBar> & scrollBar)237 void ScrollBar::Reset(const RefPtr<ScrollBar>& scrollBar)
238 {
239 if (scrollBar) {
240 displayMode_ = scrollBar->GetDisplayMode();
241 backgroundColor_ = scrollBar->GetBackgroundColor();
242 foregroundColor_ = scrollBar->GetForegroundColor();
243 inactiveWidth_ = scrollBar->GetInactiveWidth();
244 normalWidth_ = scrollBar->GetNormalWidth();
245 activeWidth_ = scrollBar->GetActiveWidth();
246 touchWidth_ = scrollBar->GetTouchWidth();
247 }
248 if (!barController_) {
249 return;
250 }
251 if (displayMode_ == DisplayMode::AUTO) {
252 barController_->HandleScrollBarEnd();
253 return;
254 }
255 barController_->Reset();
256 }
257
258 } // namespace OHOS::Ace