1 /*
2 * Copyright (c) 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/digit_indicator/digit_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 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr Dimension INDICATOR_PADDING = 8.0_vp;
29 constexpr int32_t DOUBLE = 2;
30 } // namespace
31
CalcFrameHeight(const RefPtr<FrameNode> & frameNode,float indicatorHeight,float indicatorDigitPadding)32 float DigitIndicatorLayoutAlgorithm::CalcFrameHeight(const RefPtr<FrameNode>& frameNode, float indicatorHeight,
33 float indicatorDigitPadding)
34 {
35 CHECK_NULL_RETURN(frameNode, indicatorHeight);
36 auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
37 CHECK_NULL_RETURN(indicatorlayoutProperty, indicatorHeight);
38 auto ignoreSize = indicatorlayoutProperty->GetIgnoreSize();
39 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
40 CHECK_NULL_RETURN(indicatorPattern, indicatorHeight);
41 bool isHorizontal = false;
42 auto direction = indicatorPattern->GetDirection();
43 if (direction == Axis::HORIZONTAL) {
44 isHorizontal = true;
45 }
46 auto frameHeight = indicatorHeight;
47 if (ignoreSize.has_value() && ignoreSize.value() == true && isHorizontal) {
48 frameHeight = indicatorHeight + indicatorDigitPadding * DOUBLE;
49 }
50 return frameHeight;
51 }
52
Measure(LayoutWrapper * layoutWrapper)53 void DigitIndicatorLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
54 {
55 CHECK_NULL_VOID(layoutWrapper);
56 auto frameNode = layoutWrapper->GetHostNode();
57 CHECK_NULL_VOID(frameNode);
58 auto layoutPropertyConstraint = layoutWrapper->GetLayoutProperty();
59 CHECK_NULL_VOID(layoutPropertyConstraint);
60 auto layoutConstraint = layoutPropertyConstraint->CreateChildConstraint();
61 auto indicatorWidth = INDICATOR_PADDING.ConvertToPx() * 2;
62 auto indicatorHeight = 0.0f;
63 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
64 child->Measure(layoutConstraint);
65 auto textGeometryNode = child->GetGeometryNode();
66 CHECK_NULL_VOID(textGeometryNode);
67 auto textFrameSize = textGeometryNode->GetFrameSize();
68 indicatorWidth += textFrameSize.Width();
69 if (indicatorHeight < textFrameSize.Height()) {
70 indicatorHeight = textFrameSize.Height();
71 }
72 }
73
74 auto pipelineContext = PipelineBase::GetCurrentContext();
75 CHECK_NULL_VOID(pipelineContext);
76 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
77 CHECK_NULL_VOID(swiperIndicatorTheme);
78
79 if (LessNotEqual(indicatorHeight, swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx())) {
80 indicatorHeight = swiperIndicatorTheme->GetIndicatorDigitHeight().ConvertToPx();
81 }
82
83 const auto& calcLayoutConstraint = layoutPropertyConstraint->GetCalcLayoutConstraint();
84 if (isSingle_ && calcLayoutConstraint && calcLayoutConstraint->selfIdealSize) {
85 const auto& constraint = layoutPropertyConstraint->GetLayoutConstraint();
86 CHECK_NULL_VOID(constraint);
87 auto idealSize =
88 CreateIdealSize(constraint.value(), Axis::HORIZONTAL, layoutPropertyConstraint->GetMeasureType(), true);
89 auto width = calcLayoutConstraint->selfIdealSize->Width();
90 auto height = calcLayoutConstraint->selfIdealSize->Height();
91 if (width) {
92 indicatorWidth = std::max(static_cast<float>(indicatorWidth), idealSize.Width());
93 }
94
95 if (height) {
96 indicatorHeight = std::max(static_cast<float>(indicatorHeight), idealSize.Height());
97 }
98 }
99
100 auto indicatorDigitPadding = swiperIndicatorTheme->GetIndicatorDigitPadding().ConvertToPx();
101 indicatorDigitPadding_ = indicatorDigitPadding;
102 auto frameHeight = CalcFrameHeight(frameNode, indicatorHeight, indicatorDigitPadding);
103 SizeF frameSize = { indicatorWidth, frameHeight };
104 auto geometryNode = layoutWrapper->GetGeometryNode();
105 CHECK_NULL_VOID(geometryNode);
106 geometryNode->SetFrameSize(frameSize);
107 }
108
SetBackTextOffset(const ChildrenListWithGuard & textWrapperList,const SizeF & frameSize,const std::optional<bool> & ignoreSize)109 void DigitIndicatorLayoutAlgorithm::SetBackTextOffset(const ChildrenListWithGuard& textWrapperList,
110 const SizeF& frameSize, const std::optional<bool>& ignoreSize)
111 {
112 auto backTextWrapper = textWrapperList.back();
113 CHECK_NULL_VOID(backTextWrapper);
114 auto backTextGeometryNode = backTextWrapper->GetGeometryNode();
115 CHECK_NULL_VOID(backTextGeometryNode);
116 auto width = frameSize.Width();
117 auto height = frameSize.Height();
118 auto backOffsetHeight = backTextGeometryNode->GetMarginFrameSize().Height();
119 if (ignoreSize.has_value() && ignoreSize.value() == true) {
120 backOffsetHeight = backOffsetHeight - indicatorDigitPadding_ * DOUBLE;
121 }
122 auto backTextCurrentOffset =
123 OffsetF { width - backTextGeometryNode->GetMarginFrameSize().Width() - INDICATOR_PADDING.ConvertToPx(),
124 (height - backOffsetHeight) * 0.5 };
125 backTextGeometryNode->SetMarginFrameOffset(backTextCurrentOffset);
126 backTextWrapper->Layout();
127 }
128
Layout(LayoutWrapper * layoutWrapper)129 void DigitIndicatorLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
130 {
131 CHECK_NULL_VOID(layoutWrapper);
132 auto frameNode = layoutWrapper->GetHostNode();
133 CHECK_NULL_VOID(frameNode);
134
135 auto children = frameNode->GetChildren();
136 if (children.empty()) {
137 return;
138 }
139 auto textWrapperList = layoutWrapper->GetAllChildrenWithBuild();
140 auto frontTextWrapper = textWrapperList.front();
141 CHECK_NULL_VOID(frontTextWrapper);
142 auto frontTextGeometryNode = frontTextWrapper->GetGeometryNode();
143 CHECK_NULL_VOID(frontTextGeometryNode);
144 auto layoutGeometryNode = layoutWrapper->GetGeometryNode();
145 CHECK_NULL_VOID(layoutGeometryNode);
146
147 auto indicatorPattern = frameNode->GetPattern<SwiperIndicatorPattern>();
148 CHECK_NULL_VOID(indicatorPattern);
149 SizeF frameSize = { 0.0f, 0.0f };
150 auto success = indicatorPattern->GetDigitFrameSize(layoutGeometryNode, frameSize);
151 CHECK_NULL_VOID(success);
152 auto height = frameSize.Height();
153
154 auto indicatorlayoutProperty = frameNode->GetLayoutProperty<SwiperIndicatorLayoutProperty>();
155 CHECK_NULL_VOID(indicatorlayoutProperty);
156
157 float frontOffsetHeight = frontTextGeometryNode->GetMarginFrameSize().Height();
158 auto ignoreSize = indicatorlayoutProperty->GetIgnoreSize();
159 if (ignoreSize.has_value() && ignoreSize.value() == true) {
160 frontOffsetHeight = frontOffsetHeight - indicatorDigitPadding_ * DOUBLE;
161 }
162 auto frontCurrentOffset = OffsetF { INDICATOR_PADDING.ConvertToPx(),
163 (height - frontOffsetHeight) * 0.5 };
164 frontTextGeometryNode->SetMarginFrameOffset(frontCurrentOffset);
165 frontTextWrapper->Layout();
166
167 SetBackTextOffset(textWrapperList, frameSize, ignoreSize);
168 }
169 } // namespace OHOS::Ace::NG
170