• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/select_overlay/select_overlay_modifier.h"
17 
18 #include <vector>
19 
20 #include "base/geometry/ng/offset_t.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/properties/color.h"
23 #include "core/components/text_overlay/text_overlay_theme.h"
24 #include "core/components_ng/base/modifier.h"
25 #include "core/components_ng/render/drawing.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr Dimension COORDINATE_X = 8.13_vp;
30 constexpr Dimension COORDINATE_Y = 8.13_vp;
31 constexpr Dimension MORE_ANIMATION_LINEEND_X = -8.9_vp;
32 constexpr Dimension MORE_ANIMATION_LINEEND_Y = 0.6_vp;
33 constexpr Dimension MORE_ANIMATION_OTHER_CIRCLE_X = 1.25_vp;
34 constexpr Dimension MORE_ANIMATION_OTHER_CIRCLE_Y = 8.25_vp;
35 constexpr Dimension MORE_ANIMATION_END_CIRCLE_X = 9.0_vp;
36 constexpr Dimension MORE_ANIMATION_TOP_CIRCLE_Y = -0.25_vp;
37 constexpr Dimension MASK_OFFSET_Y = 1.75_vp;
38 constexpr Dimension MASK_WIDTH = 24.0_vp;
39 constexpr Dimension MASK_HEIGHT = 10.25_vp;
40 
41 constexpr int32_t ICON_MICRO_ANIMATION_DURATION1 = 300;
42 constexpr int32_t ICON_MICRO_ANIMATION_DURATION2 = 200;
43 constexpr int32_t ROUND_NUMBER = 4;
44 
45 constexpr float ROTATION_ANGLE = 45.0f;
46 
47 std::vector<int32_t> circle_x { -1, 0, 1, 0 };
48 std::vector<int32_t> circle_Y { 0, -1, 0, 1 };
49 } // namespace
50 
SelectOverlayModifier(const OffsetF & menuOptionOffset)51 SelectOverlayModifier::SelectOverlayModifier(const OffsetF& menuOptionOffset)
52 {
53     pointRadius_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(Dimension(1.75_vp).ConvertToPx());
54     AttachProperty(pointRadius_);
55 
56     headPointRadius_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(Dimension(1.75_vp).ConvertToPx());
57     AttachProperty(headPointRadius_);
58 
59     menuOptionOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
60     AttachProperty(menuOptionOffset_);
61 
62     rotationAngle_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(ROTATION_ANGLE);
63     AttachProperty(rotationAngle_);
64 
65     circlesAndBackArrowOpacity_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0);
66     AttachProperty(circlesAndBackArrowOpacity_);
67 
68     firstHandleIsShow_ = AceType::MakeRefPtr<PropertyBool>(false);
69     AttachProperty(firstHandleIsShow_);
70 
71     secondHandleIsShow_ = AceType::MakeRefPtr<PropertyBool>(false);
72     AttachProperty(secondHandleIsShow_);
73 
74     SetDefaultCircleAndLineEndOffset();
75 }
76 
SetDefaultCircleAndLineEndOffset()77 void SelectOverlayModifier::SetDefaultCircleAndLineEndOffset()
78 {
79     for (int32_t i = 0; i < ROUND_NUMBER; i++) {
80         auto coordinate = OffsetF(COORDINATE_X.ConvertToPx() * circle_x[i], COORDINATE_Y.ConvertToPx() * circle_Y[i]);
81         auto circleOffset = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(coordinate);
82         auto lineEndCoordinate = coordinate;
83         auto lineEndOffset = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(lineEndCoordinate);
84         circleOffset_.emplace_back(circleOffset);
85         if (i > 0) {
86             lineEndOffset_.emplace_back(lineEndOffset);
87             AttachProperty(lineEndOffset_[i - 1]);
88         }
89         AttachProperty(circleOffset_[i]);
90     }
91 }
92 
SetOtherPointRadius(const Dimension & radius)93 void SelectOverlayModifier::SetOtherPointRadius(const Dimension& radius)
94 {
95     if (pointRadius_) {
96         AnimationOption option = AnimationOption();
97         option.SetDuration(ICON_MICRO_ANIMATION_DURATION2);
98         option.SetCurve(Curves::FRICTION);
99         AnimationUtils::Animate(
100             option, [weakPointRadius = AceType::WeakClaim(AceType::RawPtr(pointRadius_)), radius]() {
101                 auto pointRadius = weakPointRadius.Upgrade();
102                 pointRadius->Set(radius.ConvertToPx());
103             });
104     }
105 }
106 
SetHeadPointRadius(const Dimension & radius)107 void SelectOverlayModifier::SetHeadPointRadius(const Dimension& radius)
108 {
109     if (headPointRadius_) {
110         AnimationOption option = AnimationOption();
111         option.SetDuration(ICON_MICRO_ANIMATION_DURATION2);
112         option.SetCurve(Curves::FRICTION);
113         AnimationUtils::Animate(
114             option, [weakHeadPointRadius = AceType::WeakClaim(AceType::RawPtr(headPointRadius_)), radius]() {
115                 auto headPointRadius = weakHeadPointRadius.Upgrade();
116                 headPointRadius->Set(radius.ConvertToPx());
117             });
118     }
119 }
120 
SetLineEndOffset(bool isMore)121 void SelectOverlayModifier::SetLineEndOffset(bool isMore)
122 {
123     for (int32_t i = 0; i < ROUND_NUMBER; i++) {
124         CHECK_NULL_VOID(circleOffset_[i]);
125         if (i < ROUND_NUMBER - 1) {
126             CHECK_NULL_VOID(lineEndOffset_[i]);
127         }
128     }
129     CHECK_NULL_VOID(rotationAngle_);
130     AnimationOption option = AnimationOption();
131     option.SetDuration(ICON_MICRO_ANIMATION_DURATION1);
132     option.SetCurve(Curves::FRICTION);
133     if (isMore) {
134         AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this),
135                                             weakRotationAngle = AceType::WeakClaim(AceType::RawPtr(rotationAngle_))]() {
136             auto overlayModifier = weak.Upgrade();
137             auto rotationAngle = weakRotationAngle.Upgrade();
138             overlayModifier->circleOffset_[0]->Set(
139                 OffsetF(MORE_ANIMATION_LINEEND_X.ConvertToPx(), MORE_ANIMATION_TOP_CIRCLE_Y.ConvertToPx()));
140             overlayModifier->circleOffset_[1]->Set(
141                 OffsetF(-MORE_ANIMATION_OTHER_CIRCLE_X.ConvertToPx(), -MORE_ANIMATION_OTHER_CIRCLE_Y.ConvertToPx()));
142             overlayModifier->circleOffset_[2]->Set(OffsetF(MORE_ANIMATION_END_CIRCLE_X.ConvertToPx(), 0));
143             overlayModifier->circleOffset_[3]->Set(
144                 OffsetF(-MORE_ANIMATION_OTHER_CIRCLE_X.ConvertToPx(), MORE_ANIMATION_OTHER_CIRCLE_Y.ConvertToPx()));
145             overlayModifier->lineEndOffset_[0]->Set(
146                 OffsetF(MORE_ANIMATION_LINEEND_X.ConvertToPx(), -MORE_ANIMATION_LINEEND_Y.ConvertToPx()));
147             overlayModifier->lineEndOffset_[1]->Set(
148                 OffsetF(MORE_ANIMATION_LINEEND_X.ConvertToPx(), Dimension(0, DimensionUnit::VP).ConvertToPx()));
149             overlayModifier->lineEndOffset_[2]->Set(
150                 OffsetF(MORE_ANIMATION_LINEEND_X.ConvertToPx(), MORE_ANIMATION_LINEEND_Y.ConvertToPx()));
151             rotationAngle->Set(0);
152         });
153     } else {
154         for (int32_t i = 0; i < ROUND_NUMBER; i++) {
155             auto coordinate =
156                 OffsetF(COORDINATE_X.ConvertToPx() * circle_x[i], COORDINATE_Y.ConvertToPx() * circle_Y[i]);
157             AnimationUtils::Animate(
158                 option, [weak = AceType::WeakClaim(this),
159                             weakRotationAngle = AceType::WeakClaim(AceType::RawPtr(rotationAngle_)), i, coordinate]() {
160                     auto overlayModifier = weak.Upgrade();
161                     auto rotationAngle = weakRotationAngle.Upgrade();
162                     overlayModifier->circleOffset_[i]->Set(coordinate);
163                     rotationAngle->Set(ROTATION_ANGLE);
164                     if (i > 0) {
165                         overlayModifier->lineEndOffset_[i - 1]->Set(coordinate);
166                     };
167                 });
168         }
169     }
170 }
171 
onDraw(DrawingContext & drawingContext)172 void SelectOverlayModifier::onDraw(DrawingContext& drawingContext)
173 {
174     for (int32_t i = 0; i < ROUND_NUMBER; i++) {
175         CHECK_NULL_VOID(circleOffset_[i]);
176         if (i < ROUND_NUMBER - 1) {
177             CHECK_NULL_VOID(lineEndOffset_[i]);
178         }
179     }
180     CHECK_NULL_VOID(rotationAngle_);
181     CHECK_NULL_VOID(menuOptionOffset_);
182     CHECK_NULL_VOID(pointRadius_);
183     CHECK_NULL_VOID(headPointRadius_);
184     CHECK_NULL_VOID(firstHandleIsShow_);
185     CHECK_NULL_VOID(secondHandleIsShow_);
186 
187     if (!isNewAvoid_ && !firstHandleIsShow_->Get() && !secondHandleIsShow_->Get()) {
188         return;
189     }
190 
191     auto pipeline = PipelineContext::GetCurrentContext();
192     CHECK_NULL_VOID(pipeline);
193     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
194     CHECK_NULL_VOID(textOverlayTheme);
195     iconColor_ = textOverlayTheme->GetMoreOrBackIconColor();
196     DrawbBackArrow(drawingContext);
197     DrawbCircles(drawingContext);
198 }
199 
DrawbBackArrow(DrawingContext & drawingContext)200 void SelectOverlayModifier::DrawbBackArrow(DrawingContext& drawingContext)
201 {
202     auto& canvas = drawingContext.canvas;
203     // Draw a back arrow.
204     canvas.Save();
205     canvas.Rotate(rotationAngle_->Get(), menuOptionOffset_->Get().GetX(), menuOptionOffset_->Get().GetY());
206 
207     Color iconColor = iconColor_;
208     iconColor = iconColor.BlendOpacity(circlesAndBackArrowOpacity_->Get());
209     for (int32_t i = 0; i < ROUND_NUMBER - 2; i++) {
210         RSPen pen;
211         pen.SetAntiAlias(true);
212         pen.SetColor(iconColor.GetValue());
213         pen.SetWidth(pointRadius_->Get() * 2);
214         pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
215         canvas.AttachPen(pen);
216         auto coordinate = menuOptionOffset_->Get() + circleOffset_[i + 1]->Get();
217         auto endOffset = menuOptionOffset_->Get() + lineEndOffset_[i]->Get();
218         canvas.DrawLine({ coordinate.GetX(), coordinate.GetY() }, { endOffset.GetX(), endOffset.GetY() });
219         canvas.DetachPen();
220     }
221 
222     auto sideWidth = MASK_WIDTH.ConvertToPx();
223     auto maskOffset = menuOptionOffset_->Get() + OffsetF(-sideWidth / 2.0, MASK_OFFSET_Y.ConvertToPx());
224     RSRect clipInnerRect = RSRect(maskOffset.GetX(), maskOffset.GetY(), sideWidth + maskOffset.GetX(),
225         maskOffset.GetY() + MASK_HEIGHT.ConvertToPx());
226     canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
227     RSPen pen;
228     pen.SetAntiAlias(true);
229     pen.SetColor(iconColor.GetValue());
230     pen.SetWidth(pointRadius_->Get() * 2);
231     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
232     canvas.AttachPen(pen);
233     auto coordinate = menuOptionOffset_->Get() + circleOffset_[3]->Get();
234     auto endOffset = menuOptionOffset_->Get() + lineEndOffset_[2]->Get();
235     canvas.DrawLine({ coordinate.GetX(), coordinate.GetY() }, { endOffset.GetX(), endOffset.GetY() });
236     canvas.DetachPen();
237     canvas.Restore();
238 }
239 
DrawbCircles(DrawingContext & drawingContext)240 void SelectOverlayModifier::DrawbCircles(DrawingContext& drawingContext)
241 {
242     auto& canvas = drawingContext.canvas;
243     // Paint other circles.
244     Color iconColor = iconColor_;
245     iconColor = iconColor.BlendOpacity(circlesAndBackArrowOpacity_->Get());
246     for (int32_t i = 0; i < ROUND_NUMBER; i++) {
247         canvas.Save();
248         canvas.Rotate(rotationAngle_->Get(), menuOptionOffset_->Get().GetX(), menuOptionOffset_->Get().GetY());
249         auto coordinate = menuOptionOffset_->Get() + circleOffset_[i]->Get();
250         canvas.Translate(coordinate.GetX(), coordinate.GetY());
251         RSBrush brush;
252         brush.SetAntiAlias(true);
253         brush.SetColor(iconColor.GetValue());
254         canvas.AttachBrush(brush);
255         // The radius UX effect of the top circle is different from other circles.
256         if (i == 0) {
257             canvas.DrawCircle({ 0.0, 0.0 }, headPointRadius_->Get());
258         } else {
259             canvas.DrawCircle({ 0.0, 0.0 }, pointRadius_->Get());
260         }
261         canvas.DetachBrush();
262         canvas.Restore();
263     }
264 }
265 } // namespace OHOS::Ace::NG
266