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 SetTrickRegion(offset, size, lastOffset, estimatedHeight);
36 }
37 }
38
SetBarRegion(const Offset & offset,const Size & size)39 void ScrollBar::SetBarRegion(const Offset& offset, const Size& size)
40 {
41 double normalWidth = NormalizeToPx(normalWidth_);
42 if (shapeMode_ == ShapeMode::RECT) {
43 double height = std::max(size.Height() - NormalizeToPx(reservedHeight_), 0.0);
44 if (positionMode_ == PositionMode::LEFT) {
45 barRect_ = Rect(0.0, 0.0, normalWidth, height) + offset;
46 } else {
47 barRect_ = Rect(size.Width() - normalWidth - NormalizeToPx(padding_.Right()), 0.0,
48 normalWidth, height) + offset;
49 }
50 }
51 }
52
SetTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)53 void ScrollBar::SetTrickRegion(const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
54 {
55 if (shapeMode_ == ShapeMode::RECT) {
56 double height = size.Height();
57 double barRegionHeight = std::max(height - NormalizeToPx(reservedHeight_), 0.0);
58 double activeHeight = barRegionHeight * height / estimatedHeight - outBoundary_;
59 if (!NearEqual(height, estimatedHeight)) {
60 double width = size.Width();
61 if (!NearZero(outBoundary_)) {
62 activeHeight = std::max(
63 std::max(activeHeight, NormalizeToPx(minHeight_) - outBoundary_), NormalizeToPx(minDynamicHeight_));
64 } else {
65 activeHeight = std::max(activeHeight, NormalizeToPx(minHeight_));
66 }
67 double lastOffsetY = std::max(lastOffset.GetY(), 0.0);
68 double activeOffsetY = (height - activeHeight) * lastOffsetY / (estimatedHeight - height);
69 activeOffsetY = std::min(activeOffsetY, barRegionHeight - activeHeight);
70 double normalWidth = NormalizeToPx(normalWidth_);
71 if (positionMode_ == PositionMode::LEFT) {
72 activeRect_ = Rect(-NormalizeToPx(position_), activeOffsetY, normalWidth, activeHeight) + offset;
73 touchRegion_ = activeRect_ + Size(NormalizeToPx(touchWidth_), 0);
74 } else {
75 double x = width - normalWidth - NormalizeToPx(padding_.Right()) + NormalizeToPx(position_);
76 activeRect_ = Rect(x, activeOffsetY, normalWidth, activeHeight) + offset;
77 // Update the hot region
78 touchRegion_ =
79 activeRect_ -
80 Offset(NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_) - NormalizeToPx(padding_.Right()),
81 0.0) +
82 Size(NormalizeToPx(touchWidth_) - NormalizeToPx(normalWidth_), 0);
83 }
84 }
85 } else {
86 double diameter = std::min(size.Width(), size.Height());
87 if (!NearEqual(estimatedHeight, diameter)) {
88 double maxAngle = bottomAngle_ - topAngle_;
89 trickSweepAngle_ = std::max(diameter * maxAngle / estimatedHeight, minAngle_);
90 double lastOffsetY = std::max(lastOffset.GetY(), 0.0);
91 double trickStartAngle = (maxAngle - trickSweepAngle_) * lastOffsetY / (estimatedHeight - diameter);
92 trickStartAngle = std::clamp(0.0, trickStartAngle, maxAngle) - maxAngle * FACTOR_HALF;
93 if (positionMode_ == PositionMode::LEFT) {
94 if (trickStartAngle > 0.0) {
95 trickStartAngle_ = STRAIGHT_ANGLE - trickStartAngle;
96 } else {
97 trickStartAngle_ = -(trickStartAngle + STRAIGHT_ANGLE);
98 }
99 trickSweepAngle_ = -trickSweepAngle_;
100 } else {
101 trickStartAngle_ = trickStartAngle;
102 }
103 }
104 }
105 }
106
NeedScrollBar() const107 bool ScrollBar::NeedScrollBar() const
108 {
109 return displayMode_ == DisplayMode::AUTO || displayMode_ == DisplayMode::ON;
110 }
111
NeedPaint() const112 bool ScrollBar::NeedPaint() const
113 {
114 return NeedScrollBar() && isScrollable_;
115 }
116
GetNormalWidthToPx() const117 double ScrollBar::GetNormalWidthToPx() const
118 {
119 return NormalizeToPx(normalWidth_);
120 }
121
InitScrollBar(const WeakPtr<RenderNode> & scroll,const WeakPtr<PipelineContext> & context)122 void ScrollBar::InitScrollBar(const WeakPtr<RenderNode>& scroll, const WeakPtr<PipelineContext>& context)
123 {
124 pipelineContext_ = context;
125 if (NeedScrollBar()) {
126 if (!barController_) {
127 barController_ = AceType::MakeRefPtr<ScrollBarController>();
128 }
129 barController_->Initialize(context);
130 barController_->SetScrollNode(scroll);
131 barController_->SetActiveWidth(activeWidth_);
132 barController_->SetInactiveWidth(inactiveWidth_);
133 }
134 }
135
NormalizeToPx(const Dimension & dimension) const136 double ScrollBar::NormalizeToPx(const Dimension& dimension) const
137 {
138 auto pipelineContext = pipelineContext_.Upgrade();
139 if (!pipelineContext) {
140 LOGE("NormalizeToPx failed");
141 return 0.0;
142 }
143 return pipelineContext->NormalizeToPx(dimension);
144 }
145
SetCallBack(const ScrollBarPositionCallback & callback,const ScrollBarEndCallback & barEndCallback,const ScrollBarEventCallback & scrollEndCallback)146 void ScrollBar::SetCallBack(const ScrollBarPositionCallback& callback, const ScrollBarEndCallback& barEndCallback,
147 const ScrollBarEventCallback& scrollEndCallback)
148 {
149 if (barController_) {
150 barController_->SetCallback(callback);
151 barController_->SetBarEndCallback(barEndCallback);
152 barController_->SetScrollEndCallback(scrollEndCallback);
153 barController_->SetTouchDownCallback([weakScrollBar = AceType::WeakClaim(this)](double value) {
154 auto scrollBar = weakScrollBar.Upgrade();
155 if (!scrollBar) {
156 LOGE("scrollBar is released");
157 return;
158 }
159 // value is normalized before animation
160 scrollBar->normalWidth_ = Dimension(value, DimensionUnit::PX);
161 });
162 barController_->SetTouchUpCallback([weakScrollBar = AceType::WeakClaim(this)](double value) {
163 auto scrollBar = weakScrollBar.Upgrade();
164 if (!scrollBar) {
165 LOGE("scrollBar is released");
166 return;
167 }
168 // value is normalized before animation
169 scrollBar->normalWidth_ = Dimension(value, DimensionUnit::PX);
170 });
171 }
172 }
173
HandleScrollBarEnd()174 void ScrollBar::HandleScrollBarEnd()
175 {
176 if (displayMode_ == DisplayMode::AUTO) {
177 barController_->HandleScrollBarEnd();
178 }
179 }
180
AddScrollBarController(const Offset & coordinateOffset,TouchTestResult & result)181 void ScrollBar::AddScrollBarController(const Offset& coordinateOffset, TouchTestResult& result)
182 {
183 if (barController_) {
184 barController_->SetCoordinateOffset(coordinateOffset);
185 result.emplace_back(barController_);
186 }
187 }
188
SetActive(bool isActive)189 void ScrollBar::SetActive(bool isActive)
190 {
191 if (barController_) {
192 barController_->SetActive(isActive);
193 }
194 }
195
IsActive() const196 bool ScrollBar::IsActive() const
197 {
198 if (barController_) {
199 return barController_->IsActive();
200 }
201 return false;
202 }
203
SetUndisplay()204 void ScrollBar::SetUndisplay()
205 {
206 displayMode_ = DisplayMode::OFF;
207 }
208
GetRootSize() const209 Size ScrollBar::GetRootSize() const
210 {
211 auto context = pipelineContext_.Upgrade();
212 if (context) {
213 auto rootHeight = context->GetRootHeight();
214 auto rootWidth = context->GetRootWidth();
215 return Size(rootWidth, rootHeight);
216 } else {
217 return Size();
218 }
219 }
220
Reset()221 void ScrollBar::Reset()
222 {
223 if (barController_) {
224 barController_->Reset();
225 }
226 }
227
228 } // namespace OHOS::Ace