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