1 /*
2 * Copyright (c) 2023 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_ng/pattern/scroll/inner/scroll_bar_overlay_modifier.h"
17
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/utils/utils.h"
20 #include "core/components_ng/base/modifier.h"
21 #include "core/components_ng/render/drawing.h"
22 #include "core/components_ng/render/drawing_prop_convertor.h"
23
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr double FULL_ALPHA = 255.0;
27 constexpr float HALF = 0.5f;
28 constexpr int32_t BAR_END_DURATION = 400; // 400ms
29 constexpr int32_t BAR_APPEAR_DURATION = 100; // 100ms
30 constexpr int32_t BAR_GROW_DURATION = 150; // 150ms, scroll bar width expands from 4dp to 8dp
31 constexpr int32_t BAR_SHRINK_DURATION = 250; // 250ms, scroll bar width shrinks from 8dp to 4dp
32 } // namespace
33
ScrollBarOverlayModifier(const OffsetF & fgOffset,const OffsetF & bgOffset,const SizeF & fgSize,const SizeF & bgSize)34 ScrollBarOverlayModifier::ScrollBarOverlayModifier(
35 const OffsetF& fgOffset, const OffsetF& bgOffset, const SizeF& fgSize, const SizeF& bgSize)
36 {
37 fgOffset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(fgOffset);
38 AttachProperty(fgOffset_);
39 fgSize_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(fgSize);
40 AttachProperty(fgSize_);
41 bgOffset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(bgOffset);
42 AttachProperty(bgOffset_);
43 bgSize_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(bgSize);
44 AttachProperty(bgSize_);
45
46 opacity_ = AceType::MakeRefPtr<AnimatablePropertyUint8>(UINT8_MAX);
47 AttachProperty(opacity_);
48 fgColor_ = AceType::MakeRefPtr<PropertyColor>(Color());
49 AttachProperty(fgColor_);
50 bgColor_ = AceType::MakeRefPtr<PropertyColor>(Color());
51 AttachProperty(bgColor_);
52 }
53
onDraw(DrawingContext & drawingContext)54 void ScrollBarOverlayModifier::onDraw(DrawingContext& drawingContext)
55 {
56 CHECK_NULL_VOID_NOLOG(opacity_);
57 CHECK_NULL_VOID_NOLOG(fgOffset_);
58 CHECK_NULL_VOID_NOLOG(fgSize_);
59 CHECK_NULL_VOID_NOLOG(bgOffset_);
60 CHECK_NULL_VOID_NOLOG(bgSize_);
61 CHECK_NULL_VOID_NOLOG(fgColor_);
62 CHECK_NULL_VOID_NOLOG(bgColor_);
63
64 auto fgSize = fgSize_->Get();
65 auto bgSize = bgSize_->Get();
66 auto fgOffset = fgOffset_->Get();
67 auto bgOffset = bgOffset_->Get();
68 if (!NearZero(fgSize.Height()) && !NearZero(bgSize.Height())) {
69 auto& canvas = drawingContext.canvas;
70 RSBrush brush;
71 brush.SetBlendMode(RSBlendMode::SRC_OVER);
72 brush.SetAntiAlias(true);
73 RSRect bgRect(
74 bgOffset.GetX(), bgOffset.GetY(), bgOffset.GetX() + bgSize.Width(), bgOffset.GetY() + bgSize.Height());
75 RSColor bgColor = ToRSColor(bgColor_->Get());
76 brush.SetColor(bgColor);
77 double filletRadius = bgRect.GetWidth() * HALF;
78 canvas.AttachBrush(brush);
79 canvas.DrawRoundRect({ bgRect, filletRadius, filletRadius });
80 canvas.DetachBrush();
81
82 RSRect fgRect(
83 fgOffset.GetX(), fgOffset.GetY(), fgOffset.GetX() + fgSize.Width(), fgOffset.GetY() + fgSize.Height());
84 RSColor fgColor = ToRSColor(fgColor_->Get().BlendOpacity(opacity_->Get() / FULL_ALPHA));
85 brush.SetColor(fgColor);
86 canvas.AttachBrush(brush);
87 canvas.DrawRoundRect({ fgRect, filletRadius, filletRadius });
88 }
89 }
90
StartOpacityAnimation(OpacityAnimationType opacityAnimationType)91 void ScrollBarOverlayModifier::StartOpacityAnimation(OpacityAnimationType opacityAnimationType)
92 {
93 CHECK_NULL_VOID_NOLOG(opacity_);
94 if (opacityAnimationType == OpacityAnimationType::NONE) {
95 return;
96 }
97 if (opacityAnimationType != opacityAnimatingType_) {
98 StopBarOpacityAnimation();
99 } else {
100 return;
101 }
102 AnimationOption option;
103 option.SetCurve(Curves::SHARP);
104 if (opacityAnimationType == OpacityAnimationType::DISAPPEAR) {
105 option.SetDuration(BAR_END_DURATION);
106 } else if (opacityAnimationType == OpacityAnimationType::APPEAR) {
107 option.SetDuration(BAR_APPEAR_DURATION);
108 }
109 opacityAnimatingType_ = opacityAnimationType;
110 opacityAnimation_ = AnimationUtils::StartAnimation(
111 option,
112 [&]() {
113 if (opacityAnimatingType_ == OpacityAnimationType::DISAPPEAR) {
114 opacity_->Set(0);
115 } else if (opacityAnimatingType_ == OpacityAnimationType::APPEAR) {
116 opacity_->Set(UINT8_MAX);
117 }
118 },
119 [weak = WeakClaim(this)]() {
120 auto modifier = weak.Upgrade();
121 CHECK_NULL_VOID_NOLOG(modifier);
122 modifier->SetOpacityAnimatingType(OpacityAnimationType::NONE);
123 });
124 }
125
StopBarOpacityAnimation()126 void ScrollBarOverlayModifier::StopBarOpacityAnimation()
127 {
128 if (opacityAnimation_) {
129 AnimationUtils::StopAnimation(opacityAnimation_);
130 }
131 }
132
SetOffset(const OffsetF & fgOffset,const OffsetF & bgOffset)133 void ScrollBarOverlayModifier::SetOffset(const OffsetF& fgOffset, const OffsetF& bgOffset)
134 {
135 CHECK_NULL_VOID_NOLOG(fgOffset_);
136 CHECK_NULL_VOID_NOLOG(bgOffset_);
137 fgOffset_->Set(fgOffset);
138 bgOffset_->Set(bgOffset);
139 }
140
SetSize(const SizeF & fgSize,const SizeF & bgSize)141 void ScrollBarOverlayModifier::SetSize(const SizeF& fgSize, const SizeF& bgSize)
142 {
143 CHECK_NULL_VOID(fgSize_);
144 CHECK_NULL_VOID(bgSize_);
145 fgSize_->Set(fgSize);
146 bgSize_->Set(bgSize);
147 }
148
SetRect(const Rect & fgRect,const Rect & bgRect)149 void ScrollBarOverlayModifier::SetRect(const Rect& fgRect, const Rect& bgRect)
150 {
151 SetOffset(OffsetF(fgRect.Left(), fgRect.Top()), OffsetF(bgRect.Left(), bgRect.Top()));
152 SetSize(SizeF(fgRect.Width(), fgRect.Height()), SizeF(bgRect.Width(), bgRect.Height()));
153 }
154
StartHoverAnimation(const SizeF & fgSize,const SizeF & bgSize,const OffsetF & fgOffset,const OffsetF & bgOffset,HoverAnimationType hoverAnimationType)155 void ScrollBarOverlayModifier::StartHoverAnimation(const SizeF& fgSize, const SizeF& bgSize, const OffsetF& fgOffset,
156 const OffsetF& bgOffset, HoverAnimationType hoverAnimationType)
157 {
158 CHECK_NULL_VOID_NOLOG(fgSize_);
159 CHECK_NULL_VOID_NOLOG(bgSize_);
160 CHECK_NULL_VOID_NOLOG(fgOffset_);
161 CHECK_NULL_VOID_NOLOG(bgOffset_);
162 if (hoverAnimationType == HoverAnimationType::NONE) {
163 if (hoverAnimatingType_ == HoverAnimationType::NONE) {
164 fgSize_->Set(fgSize);
165 bgSize_->Set(bgSize);
166 fgOffset_->Set(fgOffset);
167 bgOffset_->Set(bgOffset);
168 }
169 return;
170 }
171 if (hoverAnimationType != hoverAnimatingType_) {
172 StopBarHoverAnimation();
173 }
174 AnimationOption option;
175 option.SetCurve(Curves::SHARP);
176 hoverAnimatingType_ = hoverAnimationType;
177 if (hoverAnimatingType_ == HoverAnimationType::GROW) {
178 option.SetDuration(BAR_GROW_DURATION);
179 } else if (hoverAnimatingType_ == HoverAnimationType::SHRINK) {
180 option.SetDuration(BAR_SHRINK_DURATION);
181 }
182
183 hoverAnimation_ = AnimationUtils::StartAnimation(
184 option,
185 [&]() {
186 fgSize_->Set(fgSize);
187 bgSize_->Set(bgSize);
188 fgOffset_->Set(fgOffset);
189 bgOffset_->Set(bgOffset);
190 },
191 [weak = WeakClaim(this)]() {
192 auto modifier = weak.Upgrade();
193 CHECK_NULL_VOID_NOLOG(modifier);
194 modifier->SetHoverAnimatingType(HoverAnimationType::NONE);
195 });
196 }
197
StopBarHoverAnimation()198 void ScrollBarOverlayModifier::StopBarHoverAnimation()
199 {
200 if (hoverAnimation_) {
201 AnimationUtils::StopAnimation(hoverAnimation_);
202 }
203 }
204
SetFgColor(Color fgColor)205 void ScrollBarOverlayModifier::SetFgColor(Color fgColor)
206 {
207 CHECK_NULL_VOID_NOLOG(fgColor_);
208 fgColor_->Set(fgColor);
209 }
210
SetBgColor(Color bgColor)211 void ScrollBarOverlayModifier::SetBgColor(Color bgColor)
212 {
213 CHECK_NULL_VOID_NOLOG(bgColor_);
214 bgColor_->Set(bgColor);
215 }
216 } // namespace OHOS::Ace::NG