• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 #include "core/components_ng/pattern/scroll/inner/scroll_bar_2d.h"
16 
17 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
18 #include "core/components_ng/pattern/scrollable/scrollable_paint_property.h"
19 namespace OHOS::Ace::NG {
InitGestures(ScrollBar & bar,Axis axis)20 void ScrollBar2D::InitGestures(ScrollBar& bar, Axis axis)
21 {
22     bar.SetAxis(axis);
23     bar.SetMarkNeedRenderFunc([weak = WeakPtr(pattern_.GetHost())]() {
24         auto node = weak.Upgrade();
25         if (node) {
26             node->MarkNeedRenderOnly();
27         }
28     });
29     auto scrollCallback = [weak = WeakClaim(&pattern_), axis](double offset, int32_t source, bool isMouseWheelScroll) {
30         auto pattern = weak.Upgrade();
31         CHECK_NULL_RETURN(pattern, false);
32         pattern->FreeScrollBy(axis == Axis::VERTICAL ? OffsetF { 0.0f, offset } : OffsetF { offset, 0.0f });
33         return true;
34     };
35     bar.SetScrollPositionCallback(std::move(scrollCallback));
36     auto scrollEnd = [weak = WeakClaim(&pattern_)]() {
37         auto pattern = weak.Upgrade();
38         CHECK_NULL_VOID(pattern);
39         pattern->OnScrollEndCallback();
40     };
41     bar.SetScrollEndCallback(std::move(scrollEnd));
42 
43     auto gestureHub = pattern_.GetGestureHub();
44     CHECK_NULL_VOID(gestureHub);
45     auto inputHub = pattern_.GetInputHub();
46     CHECK_NULL_VOID(inputHub);
47     bar.SetGestureEvent();
48     bar.SetMouseEvent();
49     bar.SetHoverEvent();
50     gestureHub->AddTouchEvent(bar.GetTouchEvent());
51     inputHub->AddOnMouseEvent(bar.GetMouseEvent());
52     inputHub->AddOnHoverEvent(bar.GetHoverEvent());
53 }
54 
ScrollBar2D(ScrollPattern & pattern)55 ScrollBar2D::ScrollBar2D(ScrollPattern& pattern) : pattern_(pattern)
56 {
57     CHECK_NULL_VOID(vertical_ && horizontal_);
58     vertical_->SetAxis(Axis::VERTICAL);
59     horizontal_->SetAxis(Axis::HORIZONTAL);
60     horizontal_->SetPositionMode(PositionMode::BOTTOM);
61     vertical_->SetPositionMode(PositionMode::RIGHT);
62 
63     InitGestures(*vertical_, Axis::VERTICAL);
64     InitGestures(*horizontal_, Axis::HORIZONTAL);
65 
66     auto scrollableEvent = pattern_.GetScrollableEvent();
67     CHECK_NULL_VOID(scrollableEvent);
68     scrollableEvent->SetInBarRegionCallback([weak = WeakClaim(this)](const PointF& point, SourceType source) {
69         auto self = weak.Upgrade();
70         CHECK_NULL_RETURN(self && self->vertical_ && self->horizontal_, false);
71         const Point pointDouble { point.GetX(), point.GetY() };
72         if (source == SourceType::MOUSE) {
73             return self->vertical_->InBarHoverRegion(pointDouble) || self->horizontal_->InBarHoverRegion(pointDouble);
74         }
75         return self->vertical_->InBarTouchRegion(pointDouble) || self->horizontal_->InBarTouchRegion(pointDouble);
76     });
77     scrollableEvent->SetInBarRectRegionCallback([weak = WeakClaim(this)](const PointF& point, SourceType source) {
78         auto self = weak.Upgrade();
79         CHECK_NULL_RETURN(self && self->vertical_ && self->horizontal_, false);
80         const Point pointDouble { point.GetX(), point.GetY() };
81         return self->vertical_->InBarRectRegion(pointDouble) || self->horizontal_->InBarRectRegion(pointDouble);
82     });
83     scrollableEvent->SetBarCollectTouchTargetCallback(
84         [weak = WeakClaim(this)](const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
85             TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
86             ResponseLinkResult& responseLinkResult) {
87             auto self = weak.Upgrade();
88             CHECK_NULL_VOID(self && self->vertical_ && self->horizontal_);
89             self->vertical_->OnCollectTouchTarget(
90                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
91             self->horizontal_->OnCollectTouchTarget(
92                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
93         });
94     scrollableEvent->SetBarCollectClickAndLongPressTargetCallback(
95         [weak = WeakClaim(this)](const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
96             TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
97             ResponseLinkResult& responseLinkResult) {
98             auto self = weak.Upgrade();
99             CHECK_NULL_VOID(self && self->vertical_ && self->horizontal_);
100             self->vertical_->OnCollectLongPressTarget(
101                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
102             self->horizontal_->OnCollectLongPressTarget(
103                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
104         });
105 }
106 
RemoveGestures(ScrollBar & bar)107 void ScrollBar2D::RemoveGestures(ScrollBar& bar)
108 {
109     auto gestureHub = pattern_.GetGestureHub();
110     CHECK_NULL_VOID(gestureHub);
111     auto inputHub = pattern_.GetInputHub();
112     CHECK_NULL_VOID(inputHub);
113     gestureHub->RemoveTouchEvent(bar.GetTouchEvent());
114     inputHub->RemoveOnMouseEvent(bar.GetMouseEvent());
115     inputHub->RemoveOnHoverEvent(bar.GetHoverEvent());
116 }
117 
~ScrollBar2D()118 ScrollBar2D::~ScrollBar2D()
119 {
120     CHECK_NULL_VOID(vertical_ && horizontal_);
121     RemoveGestures(*vertical_);
122     RemoveGestures(*horizontal_);
123 
124     auto* ctx = pattern_.GetRenderContext();
125     CHECK_NULL_VOID(ctx);
126     ctx->RemoveOverlayModifier(painter_);
127 }
128 
129 namespace {
ConfigureScrollBar(const std::unique_ptr<ScrollBarProperty> & property,ScrollBar & bar)130 void ConfigureScrollBar(const std::unique_ptr<ScrollBarProperty>& property, ScrollBar& bar)
131 {
132     const auto mode = property->GetScrollBarMode().value_or(DisplayMode::AUTO);
133     if (mode != bar.GetDisplayMode()) {
134         bar.SetDisplayMode(mode);
135         if (mode == DisplayMode::AUTO) {
136             bar.ScheduleDisappearDelayTask();
137         }
138     }
139 
140     const auto& barWidth = property->GetScrollBarWidth();
141     if (barWidth) {
142         bar.SetActiveWidth(*barWidth);
143         bar.SetTouchWidth(*barWidth);
144         bar.SetInactiveWidth(*barWidth);
145         bar.SetNormalWidth(*barWidth);
146         bar.SetIsUserNormalWidth(true);
147     } else {
148         bar.SetIsUserNormalWidth(false);
149     }
150     const auto& barColor = property->GetScrollBarColor();
151     if (barColor) {
152         bar.SetForegroundColor(*barColor, false);
153     }
154     const auto margin = property->GetScrollBarMargin().value_or(ScrollBar2D::DEFAULT_MARGIN);
155     if (bar.GetScrollBarMargin() != margin) {
156         bar.SetScrollBarMargin(margin);
157         bar.FlushBarWidth();
158     }
159 }
160 
UpdateBorderRadius(ScrollBar & bar,const RenderContext * ctx)161 void UpdateBorderRadius(ScrollBar& bar, const RenderContext* ctx)
162 {
163     CHECK_NULL_VOID(ctx);
164     const auto radius = ctx->GetBorderRadius();
165     if (radius && radius != bar.GetHostBorderRadius()) {
166         bar.SetHostBorderRadius(*radius);
167         bar.CalcReservedHeight();
168     }
169 }
170 
GetOverScroll(float offset,float scrollableDistance)171 inline float GetOverScroll(float offset, float scrollableDistance)
172 {
173     return Positive(offset) ? offset : std::max(-(scrollableDistance + offset), 0.0f);
174 }
175 } // namespace
176 
Update(const std::unique_ptr<ScrollBarProperty> & props)177 void ScrollBar2D::Update(const std::unique_ptr<ScrollBarProperty>& props)
178 {
179     CHECK_NULL_VOID(vertical_ && horizontal_);
180     ConfigureScrollBar(props, *vertical_);
181     ConfigureScrollBar(props, *horizontal_);
182 
183     const PositionMode verticalMode = pattern_.IsRTL() ? PositionMode::LEFT : PositionMode::RIGHT;
184     vertical_->SetPositionMode(verticalMode);
185 
186     const auto* renderContext = pattern_.GetRenderContext();
187     UpdateBorderRadius(*vertical_, renderContext);
188     UpdateBorderRadius(*horizontal_, renderContext);
189 }
190 
191 namespace {
192 struct LayoutData {
193     SizeF viewSize;
194     Axis axis;
195     OffsetF offset;
196     float contentLength = 0.0f;
197 };
SyncScrollBarLayout(ScrollBar & bar,const LayoutData & data)198 void SyncScrollBarLayout(ScrollBar& bar, const LayoutData& data)
199 {
200     const float scrollableArea = data.contentLength - data.viewSize.MainSize(data.axis);
201     bar.SetScrollable(Positive(scrollableArea));
202     bar.ScheduleDisappearDelayTask();
203     bar.SetOutBoundary(GetOverScroll(data.offset.GetMainOffset(data.axis), scrollableArea));
204 
205     bar.UpdateScrollBarRegion({}, { data.viewSize.Width(), data.viewSize.Height() },
206         { -data.offset.GetX(), -data.offset.GetY() }, data.contentLength, 0);
207     bar.MarkNeedRender();
208 }
209 } // namespace
210 
SyncLayout(const OffsetF & offset,const SizeF & viewSize,const SizeF & content)211 void ScrollBar2D::SyncLayout(const OffsetF& offset, const SizeF& viewSize, const SizeF& content)
212 {
213     CHECK_NULL_VOID(vertical_ && horizontal_);
214     SyncScrollBarLayout(*vertical_, { viewSize, Axis::VERTICAL, offset, content.Height() });
215     SyncScrollBarLayout(*horizontal_, { viewSize, Axis::HORIZONTAL, offset, content.Width() });
216 }
217 
ResetAnimationSignals()218 void ScrollBar2D::ResetAnimationSignals()
219 {
220     CHECK_NULL_VOID(vertical_ && horizontal_);
221     vertical_->SetHoverAnimationType(HoverAnimationType::NONE);
222     vertical_->SetOpacityAnimationType(OpacityAnimationType::NONE);
223     horizontal_->SetHoverAnimationType(HoverAnimationType::NONE);
224     horizontal_->SetOpacityAnimationType(OpacityAnimationType::NONE);
225 }
226 
OnScrollStart()227 void ScrollBar2D::OnScrollStart()
228 {
229     CHECK_NULL_VOID(vertical_ && horizontal_);
230     vertical_->PlayScrollBarAppearAnimation();
231     horizontal_->PlayScrollBarAppearAnimation();
232 }
OnScrollEnd()233 void ScrollBar2D::OnScrollEnd()
234 {
235     CHECK_NULL_VOID(vertical_ && horizontal_);
236     vertical_->ScheduleDisappearDelayTask();
237     horizontal_->ScheduleDisappearDelayTask();
238 }
239 } // namespace OHOS::Ace::NG
240