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 #include "core/components_ng/pattern/swiper_indicator/dot_indicator/dot_indicator_paint_method.h"
17
18 #include <valarray>
19
20 #include "core/components/common/layout/constants.h"
21 #include "core/components/common/properties/color.h"
22 #include "core/components/swiper/render_swiper.h"
23 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
24 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_utils.h"
25 #include "core/components_ng/render/paint_property.h"
26 #include "core/pipeline/pipeline_base.h"
27 namespace OHOS::Ace::NG {
28 namespace {
29 // for indicator
30 constexpr Dimension INDICATOR_ITEM_SPACE = 8.0_vp;
31 constexpr Dimension INDICATOR_PADDING_DEFAULT = 12.0_vp;
32 constexpr Dimension INDICATOR_PADDING_HOVER = 12.0_vp;
33 constexpr float INDICATOR_ZOOM_IN_SCALE = 1.33f;
34
35 constexpr float BLACK_POINT_CENTER_BEZIER_CURVE_VELOCITY = 0.4f;
36 constexpr float LONG_POINT_LEFT_CENTER_BEZIER_CURVE_VELOCITY = 0.2f;
37 constexpr float LONG_POINT_RIGHT_CENTER_BEZIER_CURVE_VELOCITY = 1.0f;
38 constexpr float CENTER_BEZIER_CURVE_MASS = 0.0f;
39 constexpr float CENTER_BEZIER_CURVE_STIFFNESS = 1.0f;
40 constexpr float CENTER_BEZIER_CURVE_DAMPING = 1.0f;
41 constexpr uint32_t ITEM_HALF_WIDTH = 0;
42 constexpr uint32_t ITEM_HALF_HEIGHT = 1;
43 constexpr uint32_t SELECTED_ITEM_HALF_WIDTH = 2;
44 constexpr uint32_t SELECTED_ITEM_HALF_HEIGHT = 3;
45 constexpr float TOUCH_BOTTOM_BACKGROUND_WIDTH_MULTIPLE = 1.225f;
46 constexpr float TOUCH_BOTTOM_DOT_WIDTH_MULTIPLE = 0.0125f;
47 constexpr float LONG_POINT_TAIL_RATIO = 0.5f;
48 constexpr float HALF_SELECTED_WIDTH = 2.0f;
49 constexpr int TWOFOLD = 2;
50 } // namespace
51
UpdateContentModifier(PaintWrapper * paintWrapper)52 void DotIndicatorPaintMethod::UpdateContentModifier(PaintWrapper* paintWrapper)
53 {
54 CHECK_NULL_VOID(dotIndicatorModifier_);
55 CHECK_NULL_VOID(paintWrapper);
56
57 auto pipelineContext = PipelineBase::GetCurrentContext();
58 CHECK_NULL_VOID(pipelineContext);
59 auto swiperTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
60 CHECK_NULL_VOID(swiperTheme);
61
62 const auto& geometryNode = paintWrapper->GetGeometryNode();
63 CHECK_NULL_VOID(geometryNode);
64
65 auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
66 IsCustomSizeValue_ = paintProperty->GetIsCustomSizeValue(false);
67 dotIndicatorModifier_->SetAxis(axis_);
68 dotIndicatorModifier_->SetCurrentIndex(currentIndex_);
69 dotIndicatorModifier_->SetUnselectedColor(paintProperty->GetColorValue(swiperTheme->GetColor()));
70 dotIndicatorModifier_->SetSelectedColor(paintProperty->GetSelectedColorValue(swiperTheme->GetSelectedColor()));
71 dotIndicatorModifier_->SetIndicatorMask(paintProperty->GetIndicatorMaskValue(false));
72 dotIndicatorModifier_->SetIsIndicatorCustomSize(IsCustomSizeValue_);
73 dotIndicatorModifier_->SetOffset(geometryNode->GetContentOffset());
74 SizeF contentSize = geometryNode->GetFrameSize();
75 centerY_ = (axis_ == Axis::HORIZONTAL ? contentSize.Height() : contentSize.Width()) * 0.5;
76 dotIndicatorModifier_->SetCenterY(centerY_);
77 if (touchBottomType_ != TouchBottomType::NONE) {
78 if (!dotIndicatorModifier_->GetIsPressed()) {
79 PaintPressIndicator(paintWrapper);
80 dotIndicatorModifier_->SetIsPressed(true);
81 }
82 UpdateBackground(paintWrapper);
83 } else if (isPressed_) {
84 PaintPressIndicator(paintWrapper);
85 dotIndicatorModifier_->SetIsPressed(true);
86 } else if (isHover_) {
87 PaintHoverIndicator(paintWrapper);
88 dotIndicatorModifier_->SetIsHover(true);
89 } else {
90 PaintNormalIndicator(paintWrapper);
91 dotIndicatorModifier_->SetIsHover(false);
92 dotIndicatorModifier_->SetIsPressed(false);
93 }
94 }
95
GetLongPointAnimationStateSecondCenter(const PaintWrapper * paintWrapper,std::vector<std::pair<float,float>> & pointCenterX)96 void DotIndicatorPaintMethod::GetLongPointAnimationStateSecondCenter(
97 const PaintWrapper* paintWrapper, std::vector<std::pair<float, float>>& pointCenterX)
98 {
99 bool leftBottom = (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT &&
100 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT);
101 bool rightBottom = (gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT &&
102 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT);
103
104 if (leftBottom || rightBottom) {
105 pointAnimationStage_ = PointAnimationStage::STATE_EXPAND_TO_LONG_POINT;
106 auto [longPointCenterX, _] = CalculateLongPointCenterX(paintWrapper);
107 pointAnimationStage_ = PointAnimationStage::STATE_SHRINKT_TO_BLACK_POINT;
108 pointCenterX.push_back(longPointCenterX);
109 }
110 }
111
UpdateNormalIndicator(LinearVector<float> & itemHalfSizes,const PaintWrapper * paintWrapper)112 void DotIndicatorPaintMethod::UpdateNormalIndicator(
113 LinearVector<float>& itemHalfSizes, const PaintWrapper* paintWrapper)
114 {
115 if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
116 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
117 std::vector<std::pair<float, float>> pointCenterX({ longPointCenterX_ });
118 GetLongPointAnimationStateSecondCenter(paintWrapper, pointCenterX);
119 dotIndicatorModifier_->PlayIndicatorAnimation(
120 vectorBlackPointCenterX_, pointCenterX, gestureState_, touchBottomTypeLoop_);
121 } else {
122 dotIndicatorModifier_->UpdateNormalPaintProperty(
123 normalMargin_, itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
124 }
125 }
126
PaintNormalIndicator(const PaintWrapper * paintWrapper)127 void DotIndicatorPaintMethod::PaintNormalIndicator(const PaintWrapper* paintWrapper)
128 {
129 auto [longPointCenterX, itemHalfSizes] = CalculateLongPointCenterX(paintWrapper);
130 longPointCenterX_ = longPointCenterX;
131 if (dotIndicatorModifier_->GetIsHover()) {
132 dotIndicatorModifier_->UpdateHoverToNormalPaintProperty(
133 normalMargin_, itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
134 } else if (dotIndicatorModifier_->GetIsPressed()) {
135 dotIndicatorModifier_->UpdatePressToNormalPaintProperty(
136 normalMargin_, itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
137 } else {
138 UpdateNormalIndicator(itemHalfSizes, paintWrapper);
139 }
140 }
141
PaintHoverIndicator(const PaintWrapper * paintWrapper)142 void DotIndicatorPaintMethod::PaintHoverIndicator(const PaintWrapper* paintWrapper)
143 {
144 CHECK_NULL_VOID(paintWrapper);
145 auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
146 CHECK_NULL_VOID(paintProperty);
147 auto swiperTheme = GetSwiperIndicatorTheme();
148 CHECK_NULL_VOID(swiperTheme);
149 // diameter calculation
150 auto itemWidth = static_cast<float>(paintProperty->GetItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
151 auto itemHeight = static_cast<float>(paintProperty->GetItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
152 auto selectedItemWidth =
153 static_cast<float>(paintProperty->GetSelectedItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
154 auto selectedItemHeight =
155 static_cast<float>(paintProperty->GetSelectedItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
156 // use radius calculation
157 LinearVector<float> itemHalfSizes;
158 itemHalfSizes.emplace_back(itemWidth * 0.5 * INDICATOR_ZOOM_IN_SCALE);
159 itemHalfSizes.emplace_back(itemHeight * 0.5 * INDICATOR_ZOOM_IN_SCALE);
160 itemHalfSizes.emplace_back(selectedItemWidth * 0.5 * INDICATOR_ZOOM_IN_SCALE);
161 itemHalfSizes.emplace_back(selectedItemHeight * 0.5 * INDICATOR_ZOOM_IN_SCALE);
162 longPointCenterX_ =
163 CalculatePointCenterX(itemHalfSizes, 0, static_cast<float>(INDICATOR_PADDING_HOVER.ConvertToPx()),
164 static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()), currentIndex_);
165
166 if (dotIndicatorModifier_->GetIsPressed()) {
167 dotIndicatorModifier_->SetIsPressed(false);
168 dotIndicatorModifier_->UpdateHoverAndPressConversionPaintProperty();
169 } else if (dotIndicatorModifier_->GetIsHover()) {
170 if (!mouseClickIndex_.has_value()) {
171 dotIndicatorModifier_->UpdateHoverPaintProperty(itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
172 }
173 } else {
174 dotIndicatorModifier_->UpdateNormalToHoverPaintProperty(
175 itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
176 }
177
178 CalculateHoverIndex(itemHalfSizes);
179 if (dotIndicatorModifier_->GetNormalToHoverIndex() != hoverIndex_) {
180 dotIndicatorModifier_->SetHoverToNormalIndex(dotIndicatorModifier_->GetNormalToHoverIndex());
181 dotIndicatorModifier_->UpdateHoverToNormalPointDilateRatio();
182 dotIndicatorModifier_->SetNormalToHoverIndex(hoverIndex_);
183 dotIndicatorModifier_->UpdateNormalToHoverPointDilateRatio();
184 }
185
186 if (mouseClickIndex_) {
187 if (currentIndex_ == itemCount_ - displayCount_ && !isLoop_ && mouseClickIndex_ > currentIndex_ &&
188 mouseClickIndex_ < itemCount_) {
189 longPointCenterX_ =
190 CalculatePointCenterX(itemHalfSizes, 0, static_cast<float>(INDICATOR_PADDING_HOVER.ConvertToPx()),
191 static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()), currentIndex_);
192 } else {
193 longPointCenterX_ =
194 CalculatePointCenterX(itemHalfSizes, 0, static_cast<float>(INDICATOR_PADDING_HOVER.ConvertToPx()),
195 static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()), mouseClickIndex_.value());
196 }
197 dotIndicatorModifier_->UpdateAllPointCenterXAnimation(
198 gestureState_, vectorBlackPointCenterX_, longPointCenterX_);
199 longPointIsHover_ = true;
200 mouseClickIndex_ = std::nullopt;
201 }
202 if (dotIndicatorModifier_->GetLongPointIsHover() != longPointIsHover_) {
203 dotIndicatorModifier_->SetLongPointIsHover(longPointIsHover_);
204 dotIndicatorModifier_->UpdateLongPointDilateRatio();
205 }
206 }
207
PaintPressIndicator(const PaintWrapper * paintWrapper)208 void DotIndicatorPaintMethod::PaintPressIndicator(const PaintWrapper* paintWrapper)
209 {
210 CHECK_NULL_VOID(paintWrapper);
211 auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
212 CHECK_NULL_VOID(paintProperty);
213 auto swiperTheme = GetSwiperIndicatorTheme();
214 CHECK_NULL_VOID(swiperTheme);
215 // diameter calculation
216 auto itemWidth = static_cast<float>(paintProperty->GetItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
217 auto itemHeight = static_cast<float>(paintProperty->GetItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
218 auto selectedItemWidth =
219 static_cast<float>(paintProperty->GetSelectedItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
220 auto selectedItemHeight =
221 static_cast<float>(paintProperty->GetSelectedItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
222 // use radius calculation
223 auto itemHalfWidth = itemWidth * 0.5 * INDICATOR_ZOOM_IN_SCALE;
224 auto itemHalfHeight = itemHeight * 0.5 * INDICATOR_ZOOM_IN_SCALE;
225 auto selectedItemHalfWidth = selectedItemWidth * 0.5 * INDICATOR_ZOOM_IN_SCALE;
226 auto selectedItemHalfHeight = selectedItemHeight * 0.5 * INDICATOR_ZOOM_IN_SCALE;
227 LinearVector<float> itemHalfSizes;
228 itemHalfSizes.emplace_back(itemHalfWidth);
229 itemHalfSizes.emplace_back(itemHalfHeight);
230 itemHalfSizes.emplace_back(selectedItemHalfWidth);
231 itemHalfSizes.emplace_back(selectedItemHalfHeight);
232 longPointCenterX_ =
233 CalculatePointCenterX(itemHalfSizes, 0, static_cast<float>(INDICATOR_PADDING_HOVER.ConvertToPx()),
234 static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()), currentIndex_);
235 if (dotIndicatorModifier_->GetIsPressed()) {
236 dotIndicatorModifier_->UpdatePressPaintProperty(itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
237 } else if (dotIndicatorModifier_->GetIsHover()) {
238 dotIndicatorModifier_->SetIsPressed(true);
239 dotIndicatorModifier_->UpdateHoverAndPressConversionPaintProperty();
240 } else {
241 dotIndicatorModifier_->UpdateNormalToPressPaintProperty(
242 itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
243 }
244 }
245
CalculateNormalMargin(const LinearVector<float> & itemHalfSizes,const SizeF & frameSize)246 void DotIndicatorPaintMethod::CalculateNormalMargin(const LinearVector<float>& itemHalfSizes, const SizeF& frameSize)
247 {
248 // diameter calculation
249 auto itemWidth = itemHalfSizes[ITEM_HALF_WIDTH] * 2;
250 auto itemHeight = itemHalfSizes[ITEM_HALF_HEIGHT] * 2;
251 auto selectedItemWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * 2;
252 auto selectedItemHeight = itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT] * 2;
253 auto allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ + 1);
254 if (IsCustomSizeValue_) {
255 allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ - 1) + selectedItemWidth;
256 }
257 auto allPointSpaceSum = static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()) * (itemCount_ - 1);
258 auto indicatorPadding = static_cast<float>(INDICATOR_PADDING_DEFAULT.ConvertToPx());
259 auto contentWidth = indicatorPadding + allPointDiameterSum + allPointSpaceSum + indicatorPadding;
260 auto contentHeight = indicatorPadding + itemHeight + indicatorPadding;
261 if (selectedItemHeight > itemHeight) {
262 contentHeight = indicatorPadding + selectedItemHeight + indicatorPadding;
263 }
264 float marginX = ((axis_ == Axis::HORIZONTAL ? frameSize.Width() : frameSize.Height()) - contentWidth) * 0.5;
265 float marginY = ((axis_ == Axis::HORIZONTAL ? frameSize.Height() : frameSize.Width()) - contentHeight) * 0.5;
266 normalMargin_.SetX(marginX);
267 normalMargin_.SetY(marginY);
268 }
269
CalculatePointCenterX(const LinearVector<float> & itemHalfSizes,float margin,float padding,float space,int32_t index)270 std::pair<float, float> DotIndicatorPaintMethod::CalculatePointCenterX(
271 const LinearVector<float>& itemHalfSizes, float margin, float padding, float space, int32_t index)
272 {
273 if (itemCount_ == 0) {
274 return { 0, 0 };
275 }
276 float startCenterX = margin + padding;
277 float endCenterX = margin + padding;
278 if (Positive(turnPageRate_)) {
279 auto itemWidth = itemHalfSizes[ITEM_HALF_WIDTH] * TWOFOLD;
280 auto selectedItemWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * TWOFOLD;
281 float allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ + 1);
282 if (IsCustomSizeValue_) {
283 allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ - 1) + selectedItemWidth;
284 }
285 auto allPointSpaceSum = static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx() * (itemCount_ - 1));
286 float rectWidth = padding + allPointDiameterSum + allPointSpaceSum + padding;
287 startCenterX = rectWidth - startCenterX;
288 endCenterX = rectWidth - endCenterX;
289 return BackwardCalculation(itemHalfSizes, startCenterX, endCenterX, space, index);
290 }
291 return ForwardCalculation(itemHalfSizes, startCenterX, endCenterX, space, index);
292 }
293
CalculateLongPointCenterX(const PaintWrapper * paintWrapper)294 std::tuple<std::pair<float, float>, LinearVector<float>> DotIndicatorPaintMethod::CalculateLongPointCenterX(
295 const PaintWrapper* paintWrapper)
296 {
297 std::tuple<std::pair<float, float>, LinearVector<float>> tmp;
298 CHECK_NULL_RETURN(paintWrapper, tmp);
299 const auto& geometryNode = paintWrapper->GetGeometryNode();
300 CHECK_NULL_RETURN(geometryNode, tmp);
301 auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
302 CHECK_NULL_RETURN(paintProperty, tmp);
303 auto swiperTheme = GetSwiperIndicatorTheme();
304 CHECK_NULL_RETURN(swiperTheme, tmp);
305 SizeF frameSize = geometryNode->GetFrameSize();
306 // diameter calculation
307 auto itemWidth = static_cast<float>(paintProperty->GetItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
308 auto itemHeight = static_cast<float>(paintProperty->GetItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
309 auto selectedItemWidth =
310 static_cast<float>(paintProperty->GetSelectedItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
311 auto selectedItemHeight =
312 static_cast<float>(paintProperty->GetSelectedItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
313 // use radius calculation
314 LinearVector<float> itemHalfSizes;
315 itemHalfSizes.emplace_back(itemWidth * 0.5);
316 itemHalfSizes.emplace_back(itemHeight * 0.5);
317 itemHalfSizes.emplace_back(selectedItemWidth * 0.5);
318 itemHalfSizes.emplace_back(selectedItemHeight * 0.5);
319 CalculateNormalMargin(itemHalfSizes, frameSize);
320 auto longPointCenterX = CalculatePointCenterX(itemHalfSizes, normalMargin_.GetX(),
321 static_cast<float>(INDICATOR_PADDING_DEFAULT.ConvertToPx()),
322 static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()), currentIndex_);
323 return { longPointCenterX, itemHalfSizes };
324 }
325
GetMoveRate()326 std::tuple<float, float, float> DotIndicatorPaintMethod::GetMoveRate()
327 {
328 float blackPointCenterMoveRate = CubicCurve(BLACK_POINT_CENTER_BEZIER_CURVE_VELOCITY, CENTER_BEZIER_CURVE_MASS,
329 CENTER_BEZIER_CURVE_STIFFNESS, CENTER_BEZIER_CURVE_DAMPING).MoveInternal(std::abs(turnPageRate_));
330 float longPointLeftCenterMoveRate = 0.0f;
331 float longPointRightCenterMoveRate = 0.0f;
332
333 if (isPressed_ && touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_NONE) {
334 longPointLeftCenterMoveRate = CubicCurve(turnPageRate_ > 0 ? LONG_POINT_LEFT_CENTER_BEZIER_CURVE_VELOCITY :
335 LONG_POINT_RIGHT_CENTER_BEZIER_CURVE_VELOCITY, CENTER_BEZIER_CURVE_MASS, CENTER_BEZIER_CURVE_STIFFNESS,
336 CENTER_BEZIER_CURVE_DAMPING).MoveInternal(std::abs(turnPageRate_));
337 longPointRightCenterMoveRate = CubicCurve(turnPageRate_ > 0 ? LONG_POINT_RIGHT_CENTER_BEZIER_CURVE_VELOCITY :
338 LONG_POINT_LEFT_CENTER_BEZIER_CURVE_VELOCITY, CENTER_BEZIER_CURVE_MASS, CENTER_BEZIER_CURVE_STIFFNESS,
339 CENTER_BEZIER_CURVE_DAMPING).MoveInternal(std::abs(turnPageRate_));
340 } else if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
341 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
342 blackPointCenterMoveRate = 1;
343 longPointLeftCenterMoveRate = 1;
344 longPointRightCenterMoveRate = 1;
345 } else if (touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT) {
346 auto rateAbs = std::abs(turnPageRate_);
347 longPointLeftCenterMoveRate = longPointRightCenterMoveRate =
348 // x0:0.33, y0:0, x1:0.67, y1:1
349 CubicCurve(0.33, 0, 0.67, 1).MoveInternal(1.0 - rateAbs);
350 } else if (touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT) {
351 auto rateAbs = std::abs(turnPageRate_);
352 // x0:0.33, y0:0, x1:0.67, y1:1
353 longPointLeftCenterMoveRate = longPointRightCenterMoveRate = CubicCurve(0.33, 0, 0.67, 1).MoveInternal(rateAbs);
354 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_LEFT) {
355 longPointLeftCenterMoveRate =std::abs(turnPageRate_);
356 longPointRightCenterMoveRate = std::abs(turnPageRate_) +
357 ((1 - longPointLeftCenterMoveRate) * LONG_POINT_TAIL_RATIO);
358 } else if (gestureState_ == GestureState::GESTURE_STATE_FOLLOW_RIGHT) {
359 longPointRightCenterMoveRate = std::abs(turnPageRate_);
360 longPointLeftCenterMoveRate = std::abs(turnPageRate_) * LONG_POINT_TAIL_RATIO;
361 }
362 return { blackPointCenterMoveRate, longPointLeftCenterMoveRate, longPointRightCenterMoveRate };
363 }
364
CalculatePointCenterX(const StarAndEndPointCenter & starAndEndPointCenter,const LinearVector<float> & startVectorBlackPointCenterX,const LinearVector<float> & endVectorBlackPointCenterX)365 std::pair<float, float> DotIndicatorPaintMethod::CalculatePointCenterX(
366 const StarAndEndPointCenter& starAndEndPointCenter, const LinearVector<float>& startVectorBlackPointCenterX,
367 const LinearVector<float>& endVectorBlackPointCenterX)
368 {
369 const auto [blackPointCenterMoveRate, longPointLeftCenterMoveRate, longPointRightCenterMoveRate] = GetMoveRate();
370
371 vectorBlackPointCenterX_.resize(itemCount_);
372 for (int32_t i = 0; i < itemCount_; ++i) {
373 vectorBlackPointCenterX_[i] = startVectorBlackPointCenterX[i] +
374 (endVectorBlackPointCenterX[i] - startVectorBlackPointCenterX[i]) * blackPointCenterMoveRate;
375 }
376
377 std::pair<float, float> longPointCenterX;
378 longPointCenterX.first = starAndEndPointCenter.startLongPointLeftCenterX +
379 (starAndEndPointCenter.endLongPointLeftCenterX - starAndEndPointCenter.startLongPointLeftCenterX) *
380 longPointLeftCenterMoveRate;
381 longPointCenterX.second = starAndEndPointCenter.startLongPointRightCenterX +
382 (starAndEndPointCenter.endLongPointRightCenterX - starAndEndPointCenter.startLongPointRightCenterX) *
383 longPointRightCenterMoveRate;
384 return longPointCenterX;
385 }
386
CalculateHoverIndex(const LinearVector<float> & itemHalfSizes)387 void DotIndicatorPaintMethod::CalculateHoverIndex(const LinearVector<float>& itemHalfSizes)
388 {
389 if (!isHover_) {
390 hoverIndex_ = std::nullopt;
391 longPointIsHover_ = false;
392 return;
393 }
394 for (size_t i = 0; i < vectorBlackPointCenterX_.size(); ++i) {
395 OffsetF center = { vectorBlackPointCenterX_[i], centerY_ };
396 if (isHoverPoint(hoverPoint_, center, center, itemHalfSizes)) {
397 hoverIndex_ = i;
398 break;
399 }
400 }
401
402 OffsetF leftCenter = { longPointCenterX_.first, centerY_ };
403 OffsetF rightCenter = { longPointCenterX_.second, centerY_ };
404 longPointIsHover_ = isHoverPoint(hoverPoint_, leftCenter, rightCenter, itemHalfSizes);
405 }
406
isHoverPoint(const PointF & hoverPoint,const OffsetF & leftCenter,const OffsetF & rightCenter,const LinearVector<float> & itemHalfSizes)407 bool DotIndicatorPaintMethod::isHoverPoint(
408 const PointF& hoverPoint, const OffsetF& leftCenter,
409 const OffsetF& rightCenter, const LinearVector<float>& itemHalfSizes)
410 {
411 float tempLeftCenterX = axis_ == Axis::HORIZONTAL ? leftCenter.GetX() : leftCenter.GetY();
412 float tempLeftCenterY = axis_ == Axis::HORIZONTAL ? leftCenter.GetY() : leftCenter.GetX();
413 float tempRightCenterX = axis_ == Axis::HORIZONTAL ? rightCenter.GetX() : rightCenter.GetY();
414 float tempRightCenterY = axis_ == Axis::HORIZONTAL ? rightCenter.GetY() : rightCenter.GetX();
415 float itemHalfWidth = itemHalfSizes[ITEM_HALF_WIDTH];
416 float itemHalfHeight = itemHalfSizes[ITEM_HALF_HEIGHT];
417 if (hoverIndex_ == currentIndex_) {
418 itemHalfWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
419 itemHalfHeight = itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT];
420 }
421 return hoverPoint.GetX() >= (tempLeftCenterX - itemHalfWidth) && (hoverPoint.GetX() <=
422 (tempRightCenterX + itemHalfWidth)) && (hoverPoint.GetY() >= (tempLeftCenterY - itemHalfHeight)) &&
423 (hoverPoint.GetY() <= (tempRightCenterY + itemHalfHeight));
424 }
425
UpdateBackground(const PaintWrapper * paintWrapper)426 void DotIndicatorPaintMethod::UpdateBackground(const PaintWrapper* paintWrapper)
427 {
428 CHECK_NULL_VOID(paintWrapper);
429 auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
430 CHECK_NULL_VOID(paintProperty);
431 auto swiperTheme = GetSwiperIndicatorTheme();
432 CHECK_NULL_VOID(swiperTheme);
433
434 // diameter calculation
435 auto itemWidth = static_cast<float>(paintProperty->GetItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
436 auto itemHeight = static_cast<float>(paintProperty->GetItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
437 auto selectedItemWidth =
438 static_cast<float>(paintProperty->GetSelectedItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
439 auto selectedItemHeight =
440 static_cast<float>(paintProperty->GetSelectedItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
441 // use radius calculation
442 LinearVector<float> itemHalfSizes;
443 itemHalfSizes.emplace_back(itemWidth * 0.5f * INDICATOR_ZOOM_IN_SCALE);
444 itemHalfSizes.emplace_back(itemHeight * 0.5f * INDICATOR_ZOOM_IN_SCALE);
445 itemHalfSizes.emplace_back(selectedItemWidth * 0.5f * INDICATOR_ZOOM_IN_SCALE);
446 itemHalfSizes.emplace_back(selectedItemHeight * 0.5f * INDICATOR_ZOOM_IN_SCALE);
447 if (touchBottomType_ != TouchBottomType::NONE) {
448 float allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ + 1);
449 if (IsCustomSizeValue_) {
450 allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ - 1) + selectedItemWidth;
451 }
452 float allPointSpaceSum = static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx()) * (itemCount_ - 1);
453 float padding = static_cast<float>(INDICATOR_PADDING_DEFAULT.ConvertToPx());
454 float rectWidth = padding + allPointDiameterSum + allPointSpaceSum + padding;
455 float newRectWidth =
456 rectWidth * (TOUCH_BOTTOM_BACKGROUND_WIDTH_MULTIPLE - TOUCH_BOTTOM_DOT_WIDTH_MULTIPLE * itemCount_);
457 auto changeValue = (newRectWidth - rectWidth) * touchBottomRate_;
458
459 float space = static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx());
460 if (itemCount_ > 1) {
461 space = (rectWidth + changeValue - padding * 2 - allPointDiameterSum) / (itemCount_ - 1);
462 }
463 longPointCenterX_ = CalculatePointCenterX(itemHalfSizes, 0, padding, space, currentIndex_);
464 if (touchBottomType_ == TouchBottomType::START) {
465 for (size_t index = 0; index < vectorBlackPointCenterX_.size(); index++) {
466 vectorBlackPointCenterX_[index] = vectorBlackPointCenterX_[index] - changeValue;
467 }
468 longPointCenterX_.first = longPointCenterX_.first - changeValue;
469 longPointCenterX_.second = longPointCenterX_.second - changeValue;
470 }
471 }
472 dotIndicatorModifier_->UpdateTouchBottomAnimation(
473 touchBottomType_, vectorBlackPointCenterX_, longPointCenterX_, touchBottomRate_);
474 }
475
GetIndex(int32_t index)476 std::pair<int32_t, int32_t> DotIndicatorPaintMethod::GetIndex(int32_t index)
477 {
478 if (mouseClickIndex_ || gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
479 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
480 turnPageRate_ = 0;
481 }
482 // item may be invalid in auto linear scene
483 if (nextValidIndex_ >= 0) {
484 int32_t startCurrentIndex = index;
485 int32_t endCurrentIndex = NearEqual(turnPageRate_, 0.0f) || LessOrEqualCustomPrecision(turnPageRate_, -1.0f) ||
486 GreatOrEqualCustomPrecision(turnPageRate_, 1.0f)
487 ? index
488 : nextValidIndex_;
489 // reach edge scene
490 if (startCurrentIndex > endCurrentIndex) {
491 startCurrentIndex = currentIndexActual_;
492 endCurrentIndex = currentIndexActual_;
493 }
494 return { startCurrentIndex, endCurrentIndex };
495 }
496
497 int32_t startCurrentIndex = index;
498 int32_t endCurrentIndex = NearEqual(turnPageRate_, 0.0f) || LessOrEqualCustomPrecision(turnPageRate_, -1.0f) ||
499 GreatOrEqualCustomPrecision(turnPageRate_, 1.0f)
500 ? endCurrentIndex = index
501 : (LessNotEqualCustomPrecision(turnPageRate_, 0.0f) ? index + 1 : index - 1);
502 if (endCurrentIndex == -1) {
503 endCurrentIndex = itemCount_ - 1;
504 } else if (endCurrentIndex == itemCount_) {
505 endCurrentIndex = 0;
506 }
507 return { startCurrentIndex, endCurrentIndex };
508 }
509
GetStartAndEndIndex(int32_t index)510 std::pair<int32_t, int32_t> DotIndicatorPaintMethod::GetStartAndEndIndex(int32_t index)
511 {
512 auto [startCurrentIndex, endCurrentIndex] = GetIndex(index);
513
514 if (pointAnimationStage_ == PointAnimationStage::STATE_EXPAND_TO_LONG_POINT &&
515 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT &&
516 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT) {
517 endCurrentIndex = startCurrentIndex;
518 return { startCurrentIndex, endCurrentIndex };
519 } else if (pointAnimationStage_ == PointAnimationStage::STATE_EXPAND_TO_LONG_POINT &&
520 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT &&
521 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT) {
522 endCurrentIndex = startCurrentIndex = 0;
523 return { startCurrentIndex, endCurrentIndex };
524 }
525
526 if (touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT &&
527 !(endCurrentIndex == startCurrentIndex && startCurrentIndex != 0)) {
528 startCurrentIndex = endCurrentIndex = 0;
529 } else if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT &&
530 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT) {
531 endCurrentIndex = startCurrentIndex = itemCount_ - 1;
532 } else if (touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT) {
533 endCurrentIndex = startCurrentIndex;
534 }
535
536 return { startCurrentIndex, endCurrentIndex };
537 }
538
AdjustPointCenterXForTouchBottom(StarAndEndPointCenter & pointCenter,LinearVector<float> & endVectorBlackPointCenterX,int32_t startCurrentIndex,int32_t endCurrentIndex,float selectedItemWidth,int32_t index)539 void DotIndicatorPaintMethod::AdjustPointCenterXForTouchBottom(StarAndEndPointCenter& pointCenter,
540 LinearVector<float>& endVectorBlackPointCenterX, int32_t startCurrentIndex, int32_t endCurrentIndex,
541 float selectedItemWidth, int32_t index)
542 {
543 auto [startIndex, endIndex] = GetIndex(index);
544 if (touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT &&
545 pointAnimationStage_ != PointAnimationStage::STATE_EXPAND_TO_LONG_POINT &&
546 (!(endIndex == startIndex && startIndex != 0) ||
547 (gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT ||
548 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT))) {
549 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX = endVectorBlackPointCenterX[0];
550 } else if (touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT &&
551 pointAnimationStage_ != PointAnimationStage::STATE_EXPAND_TO_LONG_POINT) {
552 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX =
553 endVectorBlackPointCenterX[startCurrentIndex];
554 }
555
556 if (IsCustomSizeValue_) {
557 selectedItemWidth = 0;
558 }
559
560 if (pointAnimationStage_ == PointAnimationStage::STATE_EXPAND_TO_LONG_POINT &&
561 gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT &&
562 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT) {
563 pointCenter.startLongPointRightCenterX = endVectorBlackPointCenterX[endCurrentIndex];
564 pointCenter.endLongPointLeftCenterX =
565 endVectorBlackPointCenterX[endCurrentIndex] - (selectedItemWidth / HALF_SELECTED_WIDTH);
566 } else if (pointAnimationStage_ == PointAnimationStage::STATE_EXPAND_TO_LONG_POINT &&
567 gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT &&
568 touchBottomTypeLoop_ == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT) {
569 pointCenter.startLongPointRightCenterX = endVectorBlackPointCenterX[0];
570 pointCenter.endLongPointLeftCenterX = endVectorBlackPointCenterX[0] - (selectedItemWidth / HALF_SELECTED_WIDTH);
571 }
572 }
573
ForwardCalculation(const LinearVector<float> & itemHalfSizes,float startCenterX,float endCenterX,float space,int32_t index)574 std::pair<float, float> DotIndicatorPaintMethod::ForwardCalculation(
575 const LinearVector<float>& itemHalfSizes, float startCenterX, float endCenterX, float space, int32_t index)
576 {
577 auto itemWidth = itemHalfSizes[ITEM_HALF_WIDTH] * TWOFOLD;
578 auto selectedItemWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * TWOFOLD;
579 StarAndEndPointCenter pointCenter;
580 // Calculate the data required for the current pages
581 LinearVector<float> startVectorBlackPointCenterX(itemCount_);
582 // Calculate the data required for subsequent pages
583 LinearVector<float> endVectorBlackPointCenterX(itemCount_);
584
585 auto [startCurrentIndex, endCurrentIndex] = GetStartAndEndIndex(index);
586 for (int32_t i = 0; i < itemCount_; ++i) {
587 if (i != startCurrentIndex) {
588 startVectorBlackPointCenterX[i] = startCenterX + itemHalfSizes[ITEM_HALF_WIDTH];
589 startCenterX += itemWidth;
590 } else {
591 if (IsCustomSizeValue_) {
592 startVectorBlackPointCenterX[i] = startCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
593 pointCenter.startLongPointLeftCenterX = startCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
594 pointCenter.startLongPointRightCenterX = pointCenter.startLongPointLeftCenterX;
595 startCenterX += selectedItemWidth;
596 } else {
597 startVectorBlackPointCenterX[i] = startCenterX + selectedItemWidth;
598 pointCenter.startLongPointLeftCenterX = startCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
599 pointCenter.startLongPointRightCenterX = pointCenter.startLongPointLeftCenterX + selectedItemWidth;
600 startCenterX += selectedItemWidth * TWOFOLD;
601 }
602 }
603 if (i != endCurrentIndex) {
604 endVectorBlackPointCenterX[i] = endCenterX + itemHalfSizes[ITEM_HALF_WIDTH];
605 endCenterX += itemWidth;
606 } else {
607 if (IsCustomSizeValue_) {
608 endVectorBlackPointCenterX[i] = endCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
609 pointCenter.endLongPointLeftCenterX = endCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
610 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX;
611 endCenterX += selectedItemWidth;
612 } else {
613 endVectorBlackPointCenterX[i] = endCenterX + selectedItemWidth;
614 pointCenter.endLongPointLeftCenterX = endCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
615 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX + selectedItemWidth;
616 endCenterX += selectedItemWidth * TWOFOLD;
617 }
618 }
619 startCenterX += space;
620 endCenterX += space;
621 }
622
623 AdjustPointCenterXForTouchBottom(
624 pointCenter, endVectorBlackPointCenterX, startCurrentIndex, endCurrentIndex, selectedItemWidth, index);
625 return CalculatePointCenterX(pointCenter, startVectorBlackPointCenterX, endVectorBlackPointCenterX);
626 }
627
BackwardCalculation(const LinearVector<float> & itemHalfSizes,float startCenterX,float endCenterX,float space,int32_t index)628 std::pair<float, float> DotIndicatorPaintMethod::BackwardCalculation(
629 const LinearVector<float>& itemHalfSizes, float startCenterX, float endCenterX, float space, int32_t index)
630 {
631 int32_t startCurrentIndex = index;
632 auto itemWidth = itemHalfSizes[ITEM_HALF_WIDTH] * TWOFOLD;
633 auto selectedItemWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * TWOFOLD;
634 StarAndEndPointCenter pointCenter;
635 // Calculate the data required for the current pages
636 LinearVector<float> startVectorBlackPointCenterX(itemCount_);
637 // Calculate the data required for subsequent pages
638 LinearVector<float> endVectorBlackPointCenterX(itemCount_);
639 int32_t endCurrentIndex = NearEqual(turnPageRate_, 0.0f) || turnPageRate_ <= -1.0f || turnPageRate_ >= 1.0f
640 ? endCurrentIndex = index : (turnPageRate_ < 0.0f ? index + 1 : index - 1);
641 if (endCurrentIndex == -1) {
642 endCurrentIndex = itemCount_ - 1;
643 } else if (endCurrentIndex == itemCount_) {
644 endCurrentIndex = 0;
645 }
646 for (int32_t i = itemCount_ - 1; i >= 0; --i) {
647 if (i != startCurrentIndex) {
648 startVectorBlackPointCenterX[i] = startCenterX - itemHalfSizes[ITEM_HALF_WIDTH];
649 startCenterX -= itemWidth;
650 } else {
651 if (IsCustomSizeValue_) {
652 startVectorBlackPointCenterX[i] = startCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
653 pointCenter.startLongPointLeftCenterX = startCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
654 pointCenter.startLongPointRightCenterX = pointCenter.startLongPointLeftCenterX;
655 startCenterX -= selectedItemWidth;
656 } else {
657 startVectorBlackPointCenterX[i] = startCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
658 pointCenter.startLongPointRightCenterX = startCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
659 pointCenter.startLongPointLeftCenterX = pointCenter.startLongPointRightCenterX - selectedItemWidth;
660 startCenterX -= selectedItemWidth * TWOFOLD;
661 }
662 }
663 if (i != endCurrentIndex) {
664 endVectorBlackPointCenterX[i] = endCenterX - itemHalfSizes[ITEM_HALF_WIDTH];
665 endCenterX -= itemWidth;
666 } else {
667 if (IsCustomSizeValue_) {
668 endVectorBlackPointCenterX[i] = endCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
669 pointCenter.endLongPointLeftCenterX = endCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
670 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX;
671 endCenterX -= selectedItemWidth;
672 } else {
673 endVectorBlackPointCenterX[i] = endCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
674 pointCenter.endLongPointRightCenterX = endCenterX - itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
675 pointCenter.endLongPointLeftCenterX = pointCenter.endLongPointRightCenterX - selectedItemWidth;
676 endCenterX -= selectedItemWidth * TWOFOLD;
677 }
678 }
679 startCenterX -= space;
680 endCenterX -= space;
681 }
682 return CalculatePointCenterX(pointCenter, startVectorBlackPointCenterX, endVectorBlackPointCenterX);
683 }
684 } // namespace OHOS::Ace::NG
685