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_layout_algorithm.h"
17
18 #include "base/geometry/axis.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/geometry/ng/size_t.h"
21 #include "base/utils/utils.h"
22 #include "core/components_ng/base/frame_node.h"
23 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
24 #include "core/components_ng/pattern/swiper_indicator/dot_indicator/dot_indicator_paint_property.h"
25 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_pattern.h"
26 #include "core/components_ng/pattern/swiper_indicator/indicator_common/swiper_indicator_utils.h"
27
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr float SMALLEST_POINT_RATIO = 1.0f / 3.0f;
31 constexpr float SECOND_SMALLEST_POINT_RATIO = 2.0f / 3.0f;
32 constexpr int32_t OVERLONG_SMALL_COUNT = 2;
33 } // namespace
CalcIndicatorFrameSize(LayoutWrapper * layoutWrapper,float indicatorWidth,float indicatorHeight)34 SizeF DotIndicatorLayoutAlgorithm::CalcIndicatorFrameSize(
35 LayoutWrapper* layoutWrapper, float indicatorWidth, float indicatorHeight)
36 {
37 SizeF frameSize = { -1.0f, -1.0f };
38 CHECK_NULL_RETURN(layoutWrapper, frameSize);
39 auto layoutProperty = layoutWrapper->GetLayoutProperty();
40 CHECK_NULL_RETURN(layoutProperty, frameSize);
41 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
42 CHECK_NULL_RETURN(layoutConstraint, frameSize);
43
44 const auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
45 if (isSingle_ && calcLayoutConstraint && calcLayoutConstraint->selfIdealSize) {
46 auto idealSize =
47 CreateIdealSize(layoutConstraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(), true);
48 auto width = calcLayoutConstraint->selfIdealSize->Width();
49 auto height = calcLayoutConstraint->selfIdealSize->Height();
50 if (width) {
51 indicatorWidth_ = std::max(indicatorWidth_, idealSize.Width());
52 }
53
54 if (height) {
55 indicatorHeight_ = std::max(indicatorHeight_, idealSize.Height());
56 }
57 }
58
59 do {
60 frameSize.SetSizeT(SizeF { indicatorWidth_, indicatorHeight_ });
61 if (frameSize.IsNonNegative()) {
62 break;
63 }
64 frameSize.Constrain(layoutConstraint->minSize, layoutConstraint->maxSize);
65 } while (false);
66
67 return frameSize;
68 }
69
Measure(LayoutWrapper * layoutWrapper)70 void DotIndicatorLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
71 {
72 CHECK_NULL_VOID(layoutWrapper);
73 auto layoutProperty = layoutWrapper->GetLayoutProperty();
74 CHECK_NULL_VOID(layoutProperty);
75 const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
76 CHECK_NULL_VOID(layoutConstraint);
77 auto frameNode = layoutWrapper->GetHostNode();
78 CHECK_NULL_VOID(frameNode);
79 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
80 CHECK_NULL_VOID(indicatorPattern);
81 auto direction = indicatorPattern->GetDirection();
82 auto paintProperty = frameNode->GetPaintProperty<DotIndicatorPaintProperty>();
83 CHECK_NULL_VOID(paintProperty);
84
85 auto pipeline = PipelineBase::GetCurrentContext();
86 CHECK_NULL_VOID(pipeline);
87 auto theme = pipeline->GetTheme<SwiperIndicatorTheme>();
88 CHECK_NULL_VOID(theme);
89
90 // Diameter of a single indicator circle, item or selected-item width and height
91 auto userItemWidth = paintProperty->GetItemWidthValue(theme->GetSize()).ConvertToPx();
92 auto userItemHeight = paintProperty->GetItemHeightValue(theme->GetSize()).ConvertToPx();
93 auto userSelectedItemWidth = paintProperty->GetSelectedItemWidthValue(theme->GetSize()).ConvertToPx();
94 auto userSelectedItemHeight = paintProperty->GetSelectedItemHeightValue(theme->GetSize()).ConvertToPx();
95 if (LessNotEqual(userItemWidth, 0.0) || LessNotEqual(userItemHeight, 0.0) ||
96 LessNotEqual(userSelectedItemWidth, 0.0) || LessNotEqual(userSelectedItemHeight, 0.0)) {
97 userItemWidth = theme->GetSize().ConvertToPx();
98 userItemHeight = theme->GetSize().ConvertToPx();
99 userSelectedItemWidth = theme->GetSize().ConvertToPx();
100 userSelectedItemHeight = theme->GetSize().ConvertToPx();
101 }
102
103 // To the size of the hover after the layout, in order to prevent the components after the hover draw boundaries
104 float indicatorScale = theme->GetIndicatorScale();
105 if (maxDisplayCount_ > 0 || (!indicatorInteractive_ && isBindIndicator_)) {
106 indicatorScale = 1.0f;
107 }
108 userItemWidth *= indicatorScale;
109 userItemHeight *= indicatorScale;
110 userSelectedItemWidth *= indicatorScale;
111 userSelectedItemHeight *= indicatorScale;
112
113 // The width and height of the entire indicator.
114 Dimension indicatorHeightPadding = theme->GetIndicatorBgHeight();
115 auto indicatorHeight =
116 static_cast<float>(((userItemHeight > userSelectedItemHeight) ?
117 userItemHeight : userSelectedItemHeight) + indicatorHeightPadding.ConvertToPx() * 2);
118 auto noPaddingIndicatorHeight = indicatorHeight - indicatorHeightPadding.ConvertToPx();
119 auto allPointDiameterSum = userItemWidth * (indicatorDisplayCount_ + 1);
120 if (paintProperty->GetIsCustomSizeValue(false)) {
121 allPointDiameterSum = userItemWidth * (indicatorDisplayCount_ - 1) + userSelectedItemWidth;
122 }
123
124 auto indicatorDotItemSpace = paintProperty->GetSpaceValue(theme->GetIndicatorDotItemSpace());
125 auto allPointSpaceSum = static_cast<float>(indicatorDotItemSpace.ConvertToPx()) * (indicatorDisplayCount_ - 1);
126 if (maxDisplayCount_ > 0) {
127 allPointSpaceSum = static_cast<float>(indicatorDotItemSpace.ConvertToPx()) * (maxDisplayCount_ - 1);
128 allPointDiameterSum = userItemWidth * (maxDisplayCount_ - OVERLONG_SMALL_COUNT - 1) + userSelectedItemWidth +
129 userItemWidth * SECOND_SMALLEST_POINT_RATIO + userItemWidth * SMALLEST_POINT_RATIO;
130 }
131 auto paddingSide = theme->GetIndicatorPaddingDot().ConvertToPx();
132
133 auto indicatorWidth = paddingSide + allPointDiameterSum + allPointSpaceSum + paddingSide;
134 auto noPaddingIndicatorWidth = indicatorWidth - paddingSide * 1.5;
135 auto ignoreSize = paintProperty->GetIgnoreSizeValue(false);
136 if (direction == Axis::HORIZONTAL) {
137 indicatorWidth_ = indicatorWidth;
138 indicatorHeight_ = indicatorHeight;
139 ignorSizeIndicatorWidth_ = indicatorWidth;
140 ignorSizeIndicatorHeight_ = ignoreSize ? noPaddingIndicatorHeight : indicatorHeight;
141 } else {
142 indicatorWidth_ = indicatorHeight;
143 indicatorHeight_ = indicatorWidth;
144 ignorSizeIndicatorWidth_ = indicatorHeight;
145 ignorSizeIndicatorHeight_ = ignoreSize ? noPaddingIndicatorWidth : indicatorWidth;
146 }
147
148 auto frameSize = CalcIndicatorFrameSize(layoutWrapper, indicatorWidth, indicatorHeight);
149 auto geometryNode = layoutWrapper->GetGeometryNode();
150 CHECK_NULL_VOID(geometryNode);
151 geometryNode->SetFrameSize(frameSize);
152 }
153
Layout(LayoutWrapper * layoutWrapper)154 void DotIndicatorLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
155 {
156 CHECK_NULL_VOID(layoutWrapper);
157 auto frameNode = layoutWrapper->GetHostNode();
158 CHECK_NULL_VOID(frameNode);
159 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
160 CHECK_NULL_VOID(indicatorPattern);
161 OffsetF currentOffset = OffsetF(0.0f, 0.0f);
162 auto needSet = indicatorPattern->GetDotCurrentOffset(currentOffset, ignorSizeIndicatorWidth_,
163 ignorSizeIndicatorHeight_);
164 if (needSet) {
165 auto geometryNode = layoutWrapper->GetGeometryNode();
166 CHECK_NULL_VOID(geometryNode);
167 geometryNode->SetMarginFrameOffset(currentOffset);
168 }
169 }
170
GetValidEdgeLength(float swiperLength,float indicatorLength,const Dimension & edge)171 double DotIndicatorLayoutAlgorithm::GetValidEdgeLength(float swiperLength, float indicatorLength, const Dimension& edge)
172 {
173 return SwiperIndicatorUtils::GetValidEdgeLength(swiperLength, indicatorLength, edge);
174 }
175 } // namespace OHOS::Ace::NG
176