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