1 /*
2  * Copyright (c) 2022-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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_SWITCH_SWITCH_PAINT_METHOD_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_SWITCH_SWITCH_PAINT_METHOD_H
18 
19 #include "core/components/checkable/checkable_theme.h"
20 #include "core/components_ng/pattern/toggle/switch_modifier.h"
21 #include "core/components_ng/pattern/toggle/switch_paint_property.h"
22 #include "core/components_ng/render/canvas_image.h"
23 #include "core/components_ng/render/node_paint_method.h"
24 #include "core/components_ng/render/paint_wrapper.h"
25 #include "core/components_ng/render/render_context.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr float SWITCH_ERROR_RADIUS = -1.0f;
30 constexpr double NUM_TWO = 2.0;
31 } // namespace
32 class ACE_EXPORT SwitchPaintMethod : public NodePaintMethod {
33     DECLARE_ACE_TYPE(SwitchPaintMethod, NodePaintMethod)
34 public:
35     SwitchPaintMethod() = default;
36 
37     ~SwitchPaintMethod() override = default;
38 
GetContentModifier(PaintWrapper * paintWrapper)39     RefPtr<Modifier> GetContentModifier(PaintWrapper* paintWrapper) override
40     {
41         if (!switchModifier_) {
42             auto paintProperty = DynamicCast<SwitchPaintProperty>(paintWrapper->GetPaintProperty());
43             auto size = paintWrapper->GetContentSize();
44             auto offset = paintWrapper->GetContentOffset();
45             bool isRtl = direction_ == TextDirection::AUTO ? AceApplicationInfo::GetInstance().IsRightToLeft()
46                                                            : direction_ == TextDirection::RTL;
47             auto pointOffset = isSelect_ ^ isRtl ? size.Width() - size.Height() : 0.0f;
48             auto pipeline = PipelineBase::GetCurrentContext();
49             CHECK_NULL_RETURN(pipeline, nullptr);
50             auto switchTheme = pipeline->GetTheme<SwitchTheme>();
51             auto boardColor = isSelect_ ? paintProperty->GetSelectedColorValue(switchTheme->GetActiveColor())
52                                         : switchTheme->GetInactivePointColor();
53             switchModifier_ =
54                 AceType::MakeRefPtr<SwitchModifier>(size, offset, pointOffset, isSelect_, boardColor, dragOffsetX_);
55             switchModifier_->InitializeParam();
56         }
57         return switchModifier_;
58     }
59 
UpdateBoundsRect(PaintWrapper * paintWrapper,float pointRadius,double actualTrackRadius)60     void UpdateBoundsRect(PaintWrapper* paintWrapper, float pointRadius, double actualTrackRadius)
61     {
62         CHECK_NULL_VOID(switchModifier_);
63         auto size = paintWrapper->GetContentSize();
64         auto offset = paintWrapper->GetContentOffset();
65         auto pipeline = PipelineBase::GetCurrentContext();
66         CHECK_NULL_VOID(pipeline);
67         auto switchTheme = pipeline->GetTheme<SwitchTheme>();
68         auto horizontalPadding = switchTheme->GetHotZoneHorizontalPadding().ConvertToPx();
69         auto verticalPadding = switchTheme->GetHotZoneVerticalPadding().ConvertToPx();
70         auto actualGap = radiusGap_.ConvertToPx() * size.Height() /
71                         (switchTheme->GetHeight().ConvertToPx() - verticalPadding * 2);
72         auto horizontalIncrement = 0.0;
73         auto verticalIncrement = 0.0;
74         auto actualPointRadius = pointRadius == SWITCH_ERROR_RADIUS ? size.Height() / NUM_TWO - actualGap : pointRadius;
75         if (GreatOrEqual(size.Width(), size.Height())) {
76             horizontalIncrement =
77                 (actualPointRadius * NUM_TWO > size.Height()) ? (actualPointRadius - size.Height() / NUM_TWO) : 0.0;
78             verticalIncrement =
79                 (actualPointRadius * NUM_TWO > size.Height()) ? (actualPointRadius - size.Height() / NUM_TWO) : 0.0;
80         } else {
81             horizontalIncrement =
82                 (actualPointRadius > actualTrackRadius) ? (actualPointRadius - actualTrackRadius) : 0.0;
83             verticalIncrement =
84                 (actualPointRadius * NUM_TWO > size.Height()) ? (actualPointRadius - size.Height() / NUM_TWO) : 0.0;
85         }
86         horizontalPadding += horizontalIncrement;
87         verticalPadding += verticalIncrement;
88         float boundsRectOriginX = offset.GetX() - horizontalPadding;
89         float boundsRectOriginY = offset.GetY() - verticalPadding;
90         float boundsRectWidth = size.Width() + 2 * horizontalPadding;
91         float boundsRectHeight = size.Height() + 2 * verticalPadding;
92         RectF boundsRect(boundsRectOriginX, boundsRectOriginY, boundsRectWidth, boundsRectHeight);
93         switchModifier_->SetBoundsRect(boundsRect);
94     }
95 
UpdateContentModifier(PaintWrapper * paintWrapper)96     void UpdateContentModifier(PaintWrapper* paintWrapper) override
97     {
98         CHECK_NULL_VOID(switchModifier_);
99         auto paintProperty = DynamicCast<SwitchPaintProperty>(paintWrapper->GetPaintProperty());
100         switchModifier_->SetUseContentModifier(useContentModifier_);
101         if (paintProperty->HasUnselectedColor()) {
102             switchModifier_->SetInactiveColor(paintProperty->GetUnselectedColor().value());
103         }
104         if (paintProperty->HasSelectedColor()) {
105             switchModifier_->SetUserActiveColor(paintProperty->GetSelectedColor().value());
106         }
107         if (paintProperty->HasSwitchPointColor()) {
108             switchModifier_->SetPointColor(paintProperty->GetSwitchPointColor().value());
109         }
110         auto pointRadius = SWITCH_ERROR_RADIUS;
111         if (paintProperty->HasPointRadius()) {
112             pointRadius = paintProperty->GetPointRadius().value().ConvertToPx();
113         }
114         switchModifier_->SetPointRadius(pointRadius);
115         auto trackRadius = SWITCH_ERROR_RADIUS;
116         if (paintProperty->HasTrackBorderRadius()) {
117             trackRadius = paintProperty->GetTrackBorderRadius().value().ConvertToPx();
118         }
119         switchModifier_->SetTrackRadius(trackRadius);
120         auto size = paintWrapper->GetContentSize();
121         auto offset = paintWrapper->GetContentOffset();
122         switchModifier_->SetSize(size);
123         switchModifier_->SetOffset(offset);
124         switchModifier_->SetEnabled(enabled_);
125         switchModifier_->SetIsSelect(isSelect_);
126         switchModifier_->SetDirection(direction_);
127         switchModifier_->SetTouchHoverAnimationType(touchHoverType_);
128         switchModifier_->SetDragOffsetX(dragOffsetX_);
129         switchModifier_->SetIsDragEvent(isDragEvent_);
130         switchModifier_->SetShowHoverEffect(showHoverEffect_);
131         auto actualTrackRadius = 0.0;
132         if (GreatOrEqual(trackRadius, 0.0) && LessOrEqual(trackRadius, std::min(size.Width(), size.Height()) / 2.0)) {
133             // 2.0f is used to calculate half of the width.
134             actualTrackRadius = trackRadius;
135         } else {
136             actualTrackRadius = size.Width() / 2.0; // 2.0f is used to calculate half of the width.
137         }
138         switchModifier_->SetActualTrackRadius(actualTrackRadius);
139         switchModifier_->UpdateAnimatableProperty();
140         UpdateBoundsRect(paintWrapper, pointRadius, actualTrackRadius);
141         paintWrapper->FlushContentModifier();
142     }
143 
SetHotZoneOffset(OffsetF & hotZoneOffset)144     void SetHotZoneOffset(OffsetF& hotZoneOffset)
145     {
146         hotZoneOffset_ = hotZoneOffset;
147     }
148 
SetHotZoneSize(SizeF & hotZoneSize)149     void SetHotZoneSize(SizeF& hotZoneSize)
150     {
151         hotZoneSize_ = hotZoneSize;
152     }
153 
SetHoverPercent(float hoverPercent)154     void SetHoverPercent(float hoverPercent)
155     {
156         hoverPercent_ = hoverPercent;
157     }
158 
SetEnabled(bool enabled)159     void SetEnabled(bool enabled)
160     {
161         enabled_ = enabled;
162     }
163 
SetDragOffsetX(float dragOffsetX)164     void SetDragOffsetX(float dragOffsetX)
165     {
166         dragOffsetX_ = dragOffsetX;
167     }
168 
SetIsSelect(bool isSelect)169     void SetIsSelect(bool isSelect)
170     {
171         isSelect_ = isSelect;
172     }
173 
SetIsHover(bool isHover)174     void SetIsHover(bool isHover)
175     {
176         isHover_ = isHover;
177     }
178 
SetTouchHoverAnimationType(const TouchHoverAnimationType touchHoverType)179     void SetTouchHoverAnimationType(const TouchHoverAnimationType touchHoverType)
180     {
181         touchHoverType_ = touchHoverType;
182     }
183 
SetIsDragEvent(bool isDragEvent)184     void SetIsDragEvent(bool isDragEvent)
185     {
186         isDragEvent_ = isDragEvent;
187     }
188 
SetShowHoverEffect(bool showHoverEffect)189     void SetShowHoverEffect(bool showHoverEffect)
190     {
191         showHoverEffect_ = showHoverEffect;
192     }
193 
SetDirection(TextDirection direction)194     void SetDirection(TextDirection direction)
195     {
196         direction_ = direction;
197     }
198 
SetUseContentModifier(bool useContentModifier)199     void SetUseContentModifier(bool useContentModifier)
200     {
201         useContentModifier_ = useContentModifier;
202     }
203 
GetSwitchModifier()204     RefPtr<SwitchModifier> GetSwitchModifier()
205     {
206         return switchModifier_;
207     }
208 
209 private:
210     float dragOffsetX_ = 0.0f;
211     float hoverPercent_ = 0.0f;
212     const Dimension radiusGap_ = 2.0_vp;
213     bool enabled_ = true;
214     bool isSelect_ = true;
215     Color clickEffectColor_ = Color::WHITE;
216     Color hoverColor_ = Color::WHITE;
217     Dimension hoverRadius_ = 8.0_vp;
218     bool showHoverEffect_ = true;
219     bool useContentModifier_ = false;
220 
221     bool isHover_ = false;
222     OffsetF hotZoneOffset_;
223     SizeF hotZoneSize_;
224     TouchHoverAnimationType touchHoverType_ = TouchHoverAnimationType::NONE;
225     TextDirection direction_ = TextDirection::AUTO;
226     bool isDragEvent_ = false;
227 
228     RefPtr<SwitchModifier> switchModifier_;
229 
230     ACE_DISALLOW_COPY_AND_MOVE(SwitchPaintMethod);
231 };
232 } // namespace OHOS::Ace::NG
233 
234 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_SWITCH_SWITCH_PAINT_METHOD_H
235