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