• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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