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/dot_indicator/overlength_dot_indicator_paint_method.h"
17 
18 #include <valarray>
19 
20 #include "core/components_ng/render/paint_property.h"
21 #include "core/pipeline/pipeline_base.h"
22 
23 namespace OHOS::Ace::NG {
24 namespace {
25 // for indicator
26 constexpr Dimension INDICATOR_ITEM_SPACE = 8.0_vp;
27 constexpr Dimension INDICATOR_PADDING_DEFAULT = 12.0_vp;
28 constexpr uint32_t ITEM_HALF_WIDTH = 0;
29 constexpr uint32_t SELECTED_ITEM_HALF_WIDTH = 2;
30 constexpr int TWOFOLD = 2;
31 constexpr Dimension INDICATOR_OFFSET_UNIT = 18.0_vp;
32 constexpr int32_t NUM_0 = 0;
33 constexpr int32_t NUM_1 = 1;
34 constexpr int32_t NUM_2 = 2;
35 constexpr int32_t NUM_3 = 3;
36 constexpr float HALF_FLOAT = 0.5f;
37 } // namespace
38 
UpdateContentModifier(PaintWrapper * paintWrapper)39 void OverlengthDotIndicatorPaintMethod::UpdateContentModifier(PaintWrapper* paintWrapper)
40 {
41     CHECK_NULL_VOID(dotIndicatorModifier_);
42     CHECK_NULL_VOID(paintWrapper);
43 
44     auto pipelineContext = PipelineBase::GetCurrentContext();
45     CHECK_NULL_VOID(pipelineContext);
46     auto swiperTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
47     CHECK_NULL_VOID(swiperTheme);
48 
49     const auto& geometryNode = paintWrapper->GetGeometryNode();
50     CHECK_NULL_VOID(geometryNode);
51 
52     auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
53     IsCustomSizeValue_ = paintProperty->GetIsCustomSizeValue(false);
54     dotIndicatorModifier_->SetAxis(axis_);
55     dotIndicatorModifier_->SetCurrentIndex(currentIndex_);
56     dotIndicatorModifier_->SetMaxDisplayCount(maxDisplayCount_);
57     dotIndicatorModifier_->SetRealItemCount(realItemCount_);
58     dotIndicatorModifier_->SetUnselectedColor(paintProperty->GetColorValue(swiperTheme->GetColor()));
59     dotIndicatorModifier_->SetSelectedColor(paintProperty->GetSelectedColorValue(swiperTheme->GetSelectedColor()));
60     dotIndicatorModifier_->SetIndicatorMask(paintProperty->GetIndicatorMaskValue(false));
61     dotIndicatorModifier_->SetIsIndicatorCustomSize(IsCustomSizeValue_);
62     dotIndicatorModifier_->SetOffset(geometryNode->GetContentOffset());
63     dotIndicatorModifier_->SetAnimationStartIndex(animationStartIndex_);
64     dotIndicatorModifier_->SetAnimationEndIndex(animationEndIndex_);
65     dotIndicatorModifier_->SetKeepStatus(keepStatus_);
66     dotIndicatorModifier_->SetIsHorizontalAndRTL(isHorizontalAndRightToLeft_);
67 
68     SizeF contentSize = geometryNode->GetFrameSize();
69     centerY_ = (axis_ == Axis::HORIZONTAL ? contentSize.Height() : contentSize.Width()) * HALF_FLOAT;
70     dotIndicatorModifier_->SetCenterY(centerY_);
71 
72     if (dotIndicatorModifier_->GetCurrentOverlongType() == OverlongType::NONE) {
73         dotIndicatorModifier_->InitOverlongStatus(currentIndex_);
74     }
75 
76     if (touchBottomType_ == TouchBottomType::NONE && !isPressed_ && !isHover_) {
77         PaintNormalIndicator(paintWrapper);
78         dotIndicatorModifier_->SetIsHover(false);
79         dotIndicatorModifier_->SetIsPressed(false);
80     }
81 }
82 
UpdateNormalIndicator(LinearVector<float> & itemHalfSizes,const PaintWrapper * paintWrapper)83 void OverlengthDotIndicatorPaintMethod::UpdateNormalIndicator(
84     LinearVector<float>& itemHalfSizes, const PaintWrapper* paintWrapper)
85 {
86     dotIndicatorModifier_->SetTurnPageRate(turnPageRate_);
87     dotIndicatorModifier_->SetGestureState(gestureState_);
88     dotIndicatorModifier_->SetIsCustomSizeValue(IsCustomSizeValue_);
89     dotIndicatorModifier_->SetTouchBottomTypeLoop(touchBottomTypeLoop_);
90     if (gestureState_ == GestureState::GESTURE_STATE_RELEASE_LEFT ||
91         gestureState_ == GestureState::GESTURE_STATE_RELEASE_RIGHT) {
92         dotIndicatorModifier_->PlayIndicatorAnimation(
93             normalMargin_, itemHalfSizes, gestureState_, touchBottomTypeLoop_);
94     } else {
95         const auto [blackPointCenterMoveRate, longPointLeftCenterMoveRate, longPointRightCenterMoveRate] =
96             GetMoveRate();
97         dotIndicatorModifier_->SetBlackPointCenterMoveRate(blackPointCenterMoveRate);
98         dotIndicatorModifier_->SetLongPointLeftCenterMoveRate(longPointLeftCenterMoveRate);
99         dotIndicatorModifier_->SetLongPointRightCenterMoveRate(longPointRightCenterMoveRate);
100         dotIndicatorModifier_->UpdateNormalPaintProperty(normalMargin_, itemHalfSizes, overlongSelectedCenterX_);
101     }
102 }
103 
PaintNormalIndicator(const PaintWrapper * paintWrapper)104 void OverlengthDotIndicatorPaintMethod::PaintNormalIndicator(const PaintWrapper* paintWrapper)
105 {
106     auto [longPointCenterX, itemHalfSizes] = CalculateLongPointCenterX(paintWrapper);
107     longPointCenterX_ = longPointCenterX;
108     if (dotIndicatorModifier_->GetIsHover()) {
109         dotIndicatorModifier_->UpdateHoverToNormalPaintProperty(
110             normalMargin_, itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
111     } else if (dotIndicatorModifier_->GetIsPressed()) {
112         dotIndicatorModifier_->UpdatePressToNormalPaintProperty(
113             normalMargin_, itemHalfSizes, vectorBlackPointCenterX_, longPointCenterX_);
114     } else {
115         UpdateNormalIndicator(itemHalfSizes, paintWrapper);
116     }
117 }
CalculatePointCenterX(const LinearVector<float> & itemHalfSizes,float margin,float padding,float space,int32_t index)118 std::pair<float, float> OverlengthDotIndicatorPaintMethod::CalculatePointCenterX(
119     const LinearVector<float>& itemHalfSizes, float margin, float padding, float space, int32_t index)
120 {
121     if (itemCount_ == 0) {
122         return { 0, 0 };
123     }
124     float startCenterX = margin + padding;
125     float endCenterX = margin + padding;
126     if (Positive(turnPageRate_)) {
127         auto itemWidth = itemHalfSizes[ITEM_HALF_WIDTH] * TWOFOLD;
128         auto selectedItemWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * TWOFOLD;
129         float allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ + NUM_1);
130         if (IsCustomSizeValue_) {
131             allPointDiameterSum = itemWidth * static_cast<float>(itemCount_ - NUM_1) + selectedItemWidth;
132         }
133         auto allPointSpaceSum = static_cast<float>(INDICATOR_ITEM_SPACE.ConvertToPx() * (itemCount_ - NUM_1));
134         float rectWidth = padding + allPointDiameterSum + allPointSpaceSum + padding;
135         startCenterX = rectWidth - startCenterX;
136         endCenterX = rectWidth - endCenterX;
137         return BackwardCalculation(itemHalfSizes, startCenterX, endCenterX, space, index);
138     }
139     return ForwardCalculation(itemHalfSizes, startCenterX, endCenterX, space, index);
140 }
141 
CalculateLongPointCenterX(const PaintWrapper * paintWrapper)142 std::tuple<std::pair<float, float>, LinearVector<float>> OverlengthDotIndicatorPaintMethod::CalculateLongPointCenterX(
143     const PaintWrapper* paintWrapper)
144 {
145     std::tuple<std::pair<float, float>, LinearVector<float>> tmp;
146     CHECK_NULL_RETURN(paintWrapper, tmp);
147     const auto& geometryNode = paintWrapper->GetGeometryNode();
148     CHECK_NULL_RETURN(geometryNode, tmp);
149     auto paintProperty = DynamicCast<DotIndicatorPaintProperty>(paintWrapper->GetPaintProperty());
150     CHECK_NULL_RETURN(paintProperty, tmp);
151     auto swiperTheme = GetSwiperIndicatorTheme();
152     CHECK_NULL_RETURN(swiperTheme, tmp);
153     SizeF frameSize = geometryNode->GetFrameSize();
154     // diameter calculation
155     auto itemWidth = static_cast<float>(paintProperty->GetItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
156     auto itemHeight = static_cast<float>(paintProperty->GetItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
157     auto selectedItemWidth =
158         static_cast<float>(paintProperty->GetSelectedItemWidthValue(swiperTheme->GetSize()).ConvertToPx());
159     auto selectedItemHeight =
160         static_cast<float>(paintProperty->GetSelectedItemHeightValue(swiperTheme->GetSize()).ConvertToPx());
161 
162     int32_t displayCount = itemCount_;
163     // use radius calculation
164     auto itemSpace = INDICATOR_ITEM_SPACE.ConvertToPx();
165     if (maxDisplayCount_ > 0) {
166         displayCount = maxDisplayCount_;
167     }
168     LinearVector<float> itemHalfSizes;
169     itemHalfSizes.emplace_back(itemWidth * HALF_FLOAT);
170     itemHalfSizes.emplace_back(itemHeight * HALF_FLOAT);
171     itemHalfSizes.emplace_back(selectedItemWidth * HALF_FLOAT);
172     itemHalfSizes.emplace_back(selectedItemHeight * HALF_FLOAT);
173     CalculateNormalMargin(itemHalfSizes, frameSize, displayCount);
174 
175     auto longPointCenterX = CalculatePointCenterX(itemHalfSizes, normalMargin_.GetX(),
176         static_cast<float>(INDICATOR_PADDING_DEFAULT.ConvertToPx()), static_cast<float>(itemSpace), currentIndex_);
177     return { longPointCenterX, itemHalfSizes };
178 }
179 
CalculatePointCenterX(const StarAndEndPointCenter & starAndEndPointCenter,const LinearVector<float> & startVectorBlackPointCenterX,const LinearVector<float> & endVectorBlackPointCenterX)180 std::pair<float, float> OverlengthDotIndicatorPaintMethod::CalculatePointCenterX(
181     const StarAndEndPointCenter& starAndEndPointCenter, const LinearVector<float>& startVectorBlackPointCenterX,
182     const LinearVector<float>& endVectorBlackPointCenterX)
183 {
184     const auto [blackPointCenterMoveRate, longPointLeftCenterMoveRate, longPointRightCenterMoveRate] = GetMoveRate();
185     vectorBlackPointBegCenterX_.resize(itemCount_);
186     vectorBlackPointCenterX_.resize(itemCount_);
187     for (int32_t i = 0; i < itemCount_; ++i) {
188         vectorBlackPointCenterX_[i] =
189             startVectorBlackPointCenterX[i] +
190             (endVectorBlackPointCenterX[i] - startVectorBlackPointCenterX[i]) * blackPointCenterMoveRate;
191         if (currentIndex_ > (maxDisplayCount_ - NUM_3)) {
192             if (currentIndex_ < realItemCount_ - NUM_2) {
193                 vectorBlackPointBegCenterX_[i] =
194                     startVectorBlackPointCenterX[i] -
195                     (currentIndex_ - (maxDisplayCount_ - NUM_3)) * (INDICATOR_OFFSET_UNIT.ConvertToPx()) +
196                     (endVectorBlackPointCenterX[i] - startVectorBlackPointCenterX[i]) * blackPointCenterMoveRate;
197             } else {
198                 vectorBlackPointBegCenterX_[i] =
199                     startVectorBlackPointCenterX[i] -
200                     (realItemCount_ - maxDisplayCount_) * (INDICATOR_OFFSET_UNIT.ConvertToPx()) +
201                     (endVectorBlackPointCenterX[i] - startVectorBlackPointCenterX[i]) * blackPointCenterMoveRate;
202             }
203         } else {
204             vectorBlackPointBegCenterX_[i] =
205                 startVectorBlackPointCenterX[i] +
206                 (endVectorBlackPointCenterX[i] - startVectorBlackPointCenterX[i]) * blackPointCenterMoveRate;
207         }
208     }
209     std::pair<float, float> longPointCenterX;
210     longPointCenterX.first =
211         starAndEndPointCenter.startLongPointLeftCenterX +
212         (starAndEndPointCenter.endLongPointLeftCenterX - starAndEndPointCenter.startLongPointLeftCenterX) *
213             longPointLeftCenterMoveRate;
214     longPointCenterX.second =
215         starAndEndPointCenter.startLongPointRightCenterX +
216         (starAndEndPointCenter.endLongPointRightCenterX - starAndEndPointCenter.startLongPointRightCenterX) *
217             longPointRightCenterMoveRate;
218     return longPointCenterX;
219 }
ForwardCalculation(const LinearVector<float> & itemHalfSizes,float startCenterX,float endCenterX,float space,int32_t index)220 std::pair<float, float> OverlengthDotIndicatorPaintMethod::ForwardCalculation(
221     const LinearVector<float>& itemHalfSizes, float startCenterX, float endCenterX, float space, int32_t index)
222 {
223     auto selectedItemWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * TWOFOLD;
224     StarAndEndPointCenter pointCenter;
225     // Calculate the data required for the current pages
226     LinearVector<float> startVectorBlackPointCenterX(itemCount_);
227     // Calculate the data required for subsequent pages
228     LinearVector<float> endVectorBlackPointCenterX(itemCount_);
229 
230     int32_t nposStation = 0;
231     AnalysisIndexRange(nposStation);
232     auto [startCurrentIndex, endCurrentIndex] = GetStartAndEndIndex(index);
233     for (int32_t i = 0; i < itemCount_; ++i) {
234         float item_width = itemHalfSizes[ITEM_HALF_WIDTH];
235         if (i != startCurrentIndex) {
236             startVectorBlackPointCenterX[i] = startCenterX + item_width;
237             startCenterX += item_width * TWOFOLD;
238         } else {
239             if (IsCustomSizeValue_) {
240                 startVectorBlackPointCenterX[i] = startCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
241                 pointCenter.startLongPointLeftCenterX = startCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
242                 pointCenter.startLongPointRightCenterX = pointCenter.startLongPointLeftCenterX;
243                 startCenterX += selectedItemWidth;
244             } else {
245                 startVectorBlackPointCenterX[i] = startCenterX + selectedItemWidth;
246                 pointCenter.startLongPointLeftCenterX = startCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
247                 pointCenter.startLongPointRightCenterX = pointCenter.startLongPointLeftCenterX + selectedItemWidth;
248                 startCenterX += selectedItemWidth * TWOFOLD;
249             }
250         }
251         if (i != endCurrentIndex) {
252             endVectorBlackPointCenterX[i] = endCenterX + item_width;
253             endCenterX += item_width * TWOFOLD;
254         } else {
255             if (IsCustomSizeValue_) {
256                 endVectorBlackPointCenterX[i] = endCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
257                 pointCenter.endLongPointLeftCenterX = endCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
258                 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX;
259                 endCenterX += selectedItemWidth;
260             } else {
261                 endVectorBlackPointCenterX[i] = endCenterX + selectedItemWidth;
262                 pointCenter.endLongPointLeftCenterX = endCenterX + itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
263                 pointCenter.endLongPointRightCenterX = pointCenter.endLongPointLeftCenterX + selectedItemWidth;
264                 endCenterX += selectedItemWidth * TWOFOLD;
265             }
266         }
267         startCenterX += space;
268         endCenterX += space;
269     }
270 
271     AdjustPointCenterXForTouchBottom(
272         pointCenter, endVectorBlackPointCenterX, startCurrentIndex, endCurrentIndex, selectedItemWidth, index);
273     return CalculatePointCenterX(pointCenter, startVectorBlackPointCenterX, endVectorBlackPointCenterX);
274 }
AnalysisIndexRange(int32_t & nposStation)275 void OverlengthDotIndicatorPaintMethod::AnalysisIndexRange(int32_t& nposStation)
276 {
277     if (currentIndex_ == NUM_0 || currentIndex_ == NUM_1) {
278         nposStation = NUM_1;
279     } else if (currentIndex_ >= NUM_2 && currentIndex_ < realItemCount_ - NUM_2) {
280         nposStation = NUM_2;
281     } else if (currentIndex_ >= realItemCount_ - NUM_2) {
282         nposStation = NUM_3;
283     }
284 }
285 } // namespace OHOS::Ace::NG
286