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