• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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/swiper_indicator/indicator_common/arc_swiper_indicator_pattern.h"
17 #include "core/pipeline/base/constants.h"
18 
19 namespace OHOS::Ace::NG {
20 namespace {
21 constexpr double QUARTER_CIRCLE_ANGLE = 90.0;
22 constexpr double HALF_CIRCLE_ANGLE = 180.0;
23 constexpr double THREE_QUARTER_CIRCLE_ANGLE = 270.0;
24 constexpr double FULL_CIRCLE_ANGLE = 360.0;
25 constexpr float ITEM_PADDING = 5.0f;
26 constexpr int32_t OFFSET_ANGLE = 5;
27 constexpr float ACTIVE_ITEM_ANGLE = 4.0f;
28 constexpr float ADD_HOT_REG_ANGLE = 8.0f;
29 constexpr Dimension CIRCLE_DIAMETER_OFFSET = 16.0_vp;
30 constexpr float DIVIDE_NUM = 0.5f; // The number 0.5 represents equal division
31 } // namespace
SetArcIndicatorHotRegion(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)32 bool ArcSwiperIndicatorPattern::SetArcIndicatorHotRegion(
33     const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
34 {
35     if (config.skipMeasure && config.skipLayout) {
36         return false;
37     }
38 
39     const auto& indicatorGeometryNode = dirty->GetGeometryNode();
40     CHECK_NULL_RETURN(indicatorGeometryNode, false);
41     const auto& frameRect = indicatorGeometryNode->GetFrameRect();
42     if (NonPositive(frameRect.Width()) || NonPositive(frameRect.Height())) {
43         return false;
44     }
45     return CalculateArcIndicatorHotRegion(frameRect, indicatorGeometryNode->GetContentOffset());
46 }
47 
InitAccessibilityFocusEvent()48 void ArcSwiperIndicatorPattern::InitAccessibilityFocusEvent()
49 {
50     auto host = GetHost();
51     CHECK_NULL_VOID(host);
52     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
53     CHECK_NULL_VOID(accessibilityProperty);
54     accessibilityProperty->SetOnAccessibilityFocusCallback([weak = WeakClaim(this)](bool focus) {
55         auto indicator = weak.Upgrade();
56         CHECK_NULL_VOID(indicator);
57         indicator->SetAccessibilityFocusd(focus);
58     });
59 }
60 
CalculateArcIndicatorHotRegion(const RectF & frameRect,const OffsetF & contentOffset)61 bool ArcSwiperIndicatorPattern::CalculateArcIndicatorHotRegion(const RectF& frameRect, const OffsetF& contentOffset)
62 {
63     auto host = GetHost();
64     CHECK_NULL_RETURN(host, false);
65     auto gestureHub = host->GetOrCreateGestureEventHub();
66     CHECK_NULL_RETURN(gestureHub, false);
67     auto swiperNode = DynamicCast<FrameNode>(host->GetParent());
68     CHECK_NULL_RETURN(swiperNode, false);
69     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
70     CHECK_NULL_RETURN(swiperPattern, false);
71     int32_t itemCount = swiperPattern->RealTotalCount();
72     if (itemCount <= 0) {
73         return false;
74     }
75     auto allPointArcAngle = (itemCount - 1) * ITEM_PADDING + ACTIVE_ITEM_ANGLE + ADD_HOT_REG_ANGLE;
76     auto centerX = frameRect.Width() * DIVIDE_NUM + contentOffset.GetX();
77     auto centerY = frameRect.Height() * DIVIDE_NUM + contentOffset.GetY();
78     auto minEdgeLength = LessNotEqual(frameRect.Width(), frameRect.Height()) ? frameRect.Width() : frameRect.Height();
79     if (LessOrEqual(minEdgeLength, CIRCLE_DIAMETER_OFFSET.ConvertToPx())) {
80         return false;
81     }
82     auto radius = (minEdgeLength - CIRCLE_DIAMETER_OFFSET.ConvertToPx()) * DIVIDE_NUM;
83     const auto& parameter = swiperPattern->GetSwiperArcDotParameters();
84     CHECK_NULL_RETURN(parameter, false);
85     SwiperArcDirection arcDirection = parameter->arcDirection.value_or(SwiperArcDirection::SIX_CLOCK_DIRECTION);
86     std::vector<DimensionRect> responseRegion;
87     int32_t allAngleCount = static_cast<int32_t>(allPointArcAngle);
88     for (int32_t i = 0; i <= allAngleCount; i++) {
89         double angle = 0.0;
90         if (arcDirection == SwiperArcDirection::THREE_CLOCK_DIRECTION) {
91             angle = - allPointArcAngle * DIVIDE_NUM + i;
92         } else if (arcDirection == SwiperArcDirection::NINE_CLOCK_DIRECTION) {
93             angle = HALF_CIRCLE_ANGLE - allPointArcAngle * DIVIDE_NUM + i;
94         } else {
95             angle = QUARTER_CIRCLE_ANGLE - allPointArcAngle * DIVIDE_NUM + i;
96         }
97         if (LessNotEqual(angle, 0.0)) {
98             angle = FULL_CIRCLE_ANGLE + angle;
99         }
100 
101         OffsetF angleOffset = CalculateAngleOffset(centerX, centerY, radius, angle);
102         Dimension width;
103         Dimension height;
104         OffsetF hotRegionOffset = CalculateRectLayout(angle, radius, angleOffset, width, height);
105 
106         DimensionRect responseRect(width, height, DimensionOffset(hotRegionOffset));
107         responseRegion.emplace_back(responseRect);
108     }
109 
110     gestureHub->SetResponseRegion(responseRegion);
111     return true;
112 }
113 
GetCenterPointF()114 PointF ArcSwiperIndicatorPattern::GetCenterPointF()
115 {
116     auto center = PointF(0.0, 0.0);
117     auto swiperNode = GetSwiperNode();
118     CHECK_NULL_RETURN(swiperNode, center);
119     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
120     CHECK_NULL_RETURN(swiperPattern, center);
121 
122     const auto& geometryNode = swiperNode->GetGeometryNode();
123     const auto& contentSize = geometryNode->GetFrameSize();
124     float centerY_ = (swiperPattern->GetDirection() == Axis::HORIZONTAL ?
125         contentSize.Height() : contentSize.Width()) * DIVIDE_NUM;
126     float centerX_ = (swiperPattern->GetDirection() == Axis::HORIZONTAL ?
127         contentSize.Width() : contentSize.Height()) * DIVIDE_NUM;
128     center = PointF(centerX_, centerY_);
129     return center;
130 }
131 
GetAngleWithPoint(const PointF & conter,const PointF & point)132 float ArcSwiperIndicatorPattern::GetAngleWithPoint(const PointF& conter, const PointF& point)
133 {
134     float angle = 0.0;
135     auto swiperNode = GetSwiperNode();
136     CHECK_NULL_RETURN(swiperNode, angle);
137     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
138     CHECK_NULL_RETURN(swiperPattern, angle);
139 
140     float centerX = swiperPattern->GetDirection() == Axis::HORIZONTAL ? conter.GetX() : conter.GetY();
141     float centerY = swiperPattern->GetDirection() == Axis::HORIZONTAL ? conter.GetY() : conter.GetX();
142     float pointX = swiperPattern->GetDirection() == Axis::HORIZONTAL ? point.GetX() : point.GetY();
143     float pointY = swiperPattern->GetDirection() == Axis::HORIZONTAL ? point.GetY() : point.GetX();
144     const auto& arcDotParameters = swiperPattern->GetSwiperArcDotParameters();
145     CHECK_NULL_RETURN(arcDotParameters, angle);
146     std::optional<SwiperArcDirection> swiperArcDirection = arcDotParameters->arcDirection;
147     CHECK_NULL_RETURN(swiperArcDirection.has_value(), angle);
148     auto arcDirection = swiperArcDirection.value();
149     if (NearEqual(centerY, pointY) && LessOrEqual(centerX, pointX)) {
150         angle = -QUARTER_CIRCLE_ANGLE;
151     } else if (NearEqual(centerX, pointX) && pointY > centerY) {
152         angle = 0.0;
153     } else if (NearEqual(centerY, pointY) && pointX < centerX) {
154         angle = QUARTER_CIRCLE_ANGLE;
155     } else if (NearEqual(centerX, pointX) && pointY < centerY) {
156         angle = HALF_CIRCLE_ANGLE;
157     } else if (pointX > centerX && pointY > centerY) {
158         angle = atan((pointY - centerY) / (pointX - centerX)) * HALF_CIRCLE_ANGLE / ACE_PI - QUARTER_CIRCLE_ANGLE;
159     } else if (pointX < centerX && pointY > centerY) {
160         angle = QUARTER_CIRCLE_ANGLE - atan((pointY - centerY) / (centerX - pointX)) * HALF_CIRCLE_ANGLE / ACE_PI;
161     } else if (pointX < centerX && pointY < centerY) {
162         angle = QUARTER_CIRCLE_ANGLE + atan((centerY - pointY) / (centerX - pointX)) * HALF_CIRCLE_ANGLE / ACE_PI;
163     } else {
164         angle = -QUARTER_CIRCLE_ANGLE - atan((centerY - pointY) / (pointX - centerX)) * HALF_CIRCLE_ANGLE / ACE_PI;
165     }
166 
167     return ConvertAngleWithArcDirection(arcDirection, angle);
168 }
169 
ConvertAngleWithArcDirection(SwiperArcDirection arcDirection,const float & angle)170 float ArcSwiperIndicatorPattern::ConvertAngleWithArcDirection(SwiperArcDirection arcDirection, const float& angle)
171 {
172     float result = 0.0;
173     if (arcDirection == SwiperArcDirection::SIX_CLOCK_DIRECTION) {
174         result = angle;
175     } else if (arcDirection == SwiperArcDirection::THREE_CLOCK_DIRECTION) {
176         if (angle > QUARTER_CIRCLE_ANGLE) {
177             result = -THREE_QUARTER_CIRCLE_ANGLE + angle;
178         } else {
179             result  = angle + QUARTER_CIRCLE_ANGLE;
180         }
181         result = -result;
182     } else {
183         if (angle < -QUARTER_CIRCLE_ANGLE) {
184             result = THREE_QUARTER_CIRCLE_ANGLE + angle;
185         } else {
186             result = angle - QUARTER_CIRCLE_ANGLE;
187         }
188     }
189 
190     return result;
191 }
192 
CalculateCycle(float angle,float startAngle,const PointF & conter,const PointF & point)193 void ArcSwiperIndicatorPattern::CalculateCycle(float angle, float startAngle, const PointF& conter, const PointF& point)
194 {
195     if (direction_ == SwiperDirection::LEFT) {
196         if (angle < startAngle && !isUpdateCycle_ && CheckPointLocation(conter, point)) {
197             dragCycle_ += static_cast<int32_t>(FULL_CIRCLE_ANGLE);
198             isUpdateCycle_ = true;
199         } else if (angle > startAngle) {
200             isUpdateCycle_ = false;
201         }
202     }
203     if (direction_ == SwiperDirection::RIGHT) {
204         if (angle > startAngle && !isUpdateCycle_ && CheckPointLocation(conter, point)) {
205             dragCycle_ -= static_cast<int32_t>(FULL_CIRCLE_ANGLE);
206             isUpdateCycle_ = true;
207         } else if (angle < startAngle) {
208             isUpdateCycle_ = false;
209         }
210     }
211 }
212 
GetEndAngle(const PointF & conter,const PointF & point,float startAngle)213 float ArcSwiperIndicatorPattern::GetEndAngle(const PointF& conter, const PointF& point, float startAngle)
214 {
215     float angle = GetAngleWithPoint(conter, point);
216     if (isUpageStartAngle_) {
217         if (angle > startAngle + OFFSET_ANGLE) {
218             direction_ = SwiperDirection::LEFT;
219         } else if (angle < startAngle - OFFSET_ANGLE) {
220             direction_ = SwiperDirection::RIGHT;
221         }
222     }
223     CalculateCycle(angle, startAngle, conter, point);
224     angle += dragCycle_;
225     if (isUpageStartAngle_ && direction_!= SwiperDirection::UNKNOWN) {
226         oldEndAngle_ = angle;
227         isUpageStartAngle_ = false;
228     }
229     if (((direction_ == SwiperDirection::LEFT) && angle < oldEndAngle_ - OFFSET_ANGLE) ||
230         ((direction_ == SwiperDirection::RIGHT) && angle > oldEndAngle_ + OFFSET_ANGLE)) {
231         float angle = GetAngleWithPoint(conter, point);
232         if ((direction_ == SwiperDirection::LEFT) && angle < startAngle) {
233             UpadateStartAngle();
234         }
235         if ((direction_ == SwiperDirection::RIGHT) && angle > startAngle) {
236             UpadateStartAngle();
237         }
238     }
239     if ((direction_ == SwiperDirection::LEFT) && (angle > oldEndAngle_)) {
240         oldEndAngle_ = angle;
241     }
242     if ((direction_ == SwiperDirection::RIGHT) && (angle < oldEndAngle_)) {
243         oldEndAngle_ = angle;
244     }
245     if (direction_ == SwiperDirection::UNKNOWN) {
246         angle = startAngle;
247     }
248     return angle;
249 }
250 
UpadateStartAngle()251 void ArcSwiperIndicatorPattern::UpadateStartAngle()
252 {
253     dragCycle_ = 0;
254     direction_ = SwiperDirection::UNKNOWN;
255     isUpageStartAngle_ = true;
256     isUpdateCycle_ = false;
257     oldEndAngle_ = 0;
258 }
259 
CheckPointLocation(const PointF & conter,const PointF & point)260 bool ArcSwiperIndicatorPattern::CheckPointLocation(const PointF& conter, const PointF& point)
261 {
262     auto swiperNode = GetSwiperNode();
263     CHECK_NULL_RETURN(swiperNode, false);
264     auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
265     CHECK_NULL_RETURN(swiperPattern, false);
266 
267     float centerX = swiperPattern->GetDirection() == Axis::HORIZONTAL ? conter.GetX() : conter.GetY();
268     float centerY = swiperPattern->GetDirection() == Axis::HORIZONTAL ? conter.GetY() : conter.GetX();
269     float pointX = swiperPattern->GetDirection() == Axis::HORIZONTAL ? point.GetX() : point.GetY();
270     float pointY = swiperPattern->GetDirection() == Axis::HORIZONTAL ? point.GetY() : point.GetX();
271     if ((direction_ == SwiperDirection::LEFT) && pointX > centerX && pointY < centerY) {
272         return true;
273     }
274     if ((direction_ == SwiperDirection::RIGHT) && pointX < centerX && pointY < centerY) {
275         return true;
276     }
277 
278     return false;
279 }
280 } // namespace OHOS::Ace::NG