• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/slider/slider_layout_algorithm.h"
17 
18 #include "core/components_ng/pattern/slider/slider_pattern.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr float HALF = 0.5f;
JudgeTrackness(Axis direction,float blockDiameter,float trackThickness,float width,float height)24 bool JudgeTrackness(Axis direction, float blockDiameter, float trackThickness, float width, float height)
25 {
26     if (direction == Axis::HORIZONTAL) {
27         return blockDiameter > height || trackThickness > height;
28     }
29     return blockDiameter > width || trackThickness > width;
30 }
31 
GetTheme()32 RefPtr<SliderTheme> GetTheme()
33 {
34     auto pipeline = PipelineBase::GetCurrentContext();
35     CHECK_NULL_RETURN(pipeline, nullptr);
36     return pipeline->GetTheme<SliderTheme>();
37 }
38 } // namespace
39 
CalculateHotSize(LayoutWrapper * layoutWrapper,const SizeF & blockSize,float themeBlockHotSize)40 SizeF SliderLayoutAlgorithm::CalculateHotSize(
41     LayoutWrapper* layoutWrapper, const SizeF& blockSize, float themeBlockHotSize)
42 {
43     auto frameNode = layoutWrapper->GetHostNode();
44     CHECK_NULL_RETURN(frameNode, SizeF());
45     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutWrapper->GetLayoutProperty());
46     CHECK_NULL_RETURN(sliderLayoutProperty, SizeF());
47     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
48     SizeF blockHotSize = blockSize;
49     if (sliderMode == SliderModel::SliderMode::NONE) {
50         auto hotSize = std::max(themeBlockHotSize, trackThickness_);
51         blockHotSize = SizeF(hotSize, hotSize);
52     } else {
53         if (LessNotEqual(blockHotSize.Width(), themeBlockHotSize)) {
54             blockHotSize.SetWidth(themeBlockHotSize);
55         }
56         if (LessNotEqual(blockHotSize.Height(), themeBlockHotSize)) {
57             blockHotSize.SetHeight(themeBlockHotSize);
58         }
59     }
60     return blockHotSize;
61 }
62 
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)63 std::optional<SizeF> SliderLayoutAlgorithm::MeasureContent(
64     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
65 {
66     auto frameNode = layoutWrapper->GetHostNode();
67     CHECK_NULL_RETURN(frameNode, std::nullopt);
68     auto pattern = frameNode->GetPattern<SliderPattern>();
69     CHECK_NULL_RETURN(pattern, std::nullopt);
70     if (pattern->UseContentModifier()) {
71         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
72             frameNode->GetGeometryNode()->ResetContent();
73         } else {
74             frameNode->GetGeometryNode()->Reset();
75         }
76         return std::nullopt;
77     }
78     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutWrapper->GetLayoutProperty());
79     CHECK_NULL_RETURN(sliderLayoutProperty, std::nullopt);
80     auto theme = GetTheme();
81     CHECK_NULL_RETURN(theme, std::nullopt);
82 
83     float width = contentConstraint.selfIdealSize.Width().value_or(contentConstraint.maxSize.Width());
84     float height = contentConstraint.selfIdealSize.Height().value_or(contentConstraint.maxSize.Height());
85     Axis direction = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
86     if (direction == Axis::HORIZONTAL && GreaterOrEqualToInfinity(width)) {
87         width = static_cast<float>(theme->GetLayoutMaxLength().ConvertToPx());
88     }
89     if (direction == Axis::VERTICAL && GreaterOrEqualToInfinity(height)) {
90         height = static_cast<float>(theme->GetLayoutMaxLength().ConvertToPx());
91     }
92 
93     Dimension themeTrackThickness;
94     Dimension themeBlockSize;
95     Dimension hotBlockShadowWidth;
96     Dimension themeBlockHotSize;
97     GetStyleThemeValue(layoutWrapper, themeTrackThickness, themeBlockSize, hotBlockShadowWidth, themeBlockHotSize);
98     auto thickness = sliderLayoutProperty->GetThickness().value_or(themeTrackThickness);
99     trackThickness_ =
100         static_cast<float>(thickness.Unit() == DimensionUnit::PERCENT
101                                ? thickness.ConvertToPxWithSize(direction == Axis::HORIZONTAL ? height : width)
102                                : thickness.ConvertToPx());
103     // this scaleValue ensure that the size ratio of the block and trackThickness is consistent
104     float scaleValue = trackThickness_ / static_cast<float>(themeTrackThickness.ConvertToPx());
105     auto blockDiameter = scaleValue * static_cast<float>(themeBlockSize.ConvertToPx());
106     // trackThickness and blockDiameter will get from theme when they are greater than slider component height or width
107     if (JudgeTrackness(direction, blockDiameter, trackThickness_, width, height)) {
108         trackThickness_ = static_cast<float>(themeTrackThickness.ConvertToPx());
109         scaleValue = 1.0;
110         blockDiameter = static_cast<float>(themeBlockSize.ConvertToPx());
111     }
112     blockSize_ = sliderLayoutProperty->GetBlockSizeValue(SizeF(blockDiameter, blockDiameter));
113     blockHotSize_ = CalculateHotSize(layoutWrapper, blockSize_, static_cast<float>(themeBlockHotSize.ConvertToPx()));
114     auto mode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
115     auto sliderWidth = CalculateSliderWidth(width, height, direction, hotBlockShadowWidth, mode);
116     float sliderLength = direction == Axis::HORIZONTAL ? width : height;
117     return direction == Axis::HORIZONTAL ? SizeF(sliderLength, sliderWidth) : SizeF(sliderWidth, sliderLength);
118 }
119 
CalculateSliderWidth(float width,float height,Axis direction,const Dimension & hotBlockShadowWidth,SliderModel::SliderMode mode)120 float SliderLayoutAlgorithm::CalculateSliderWidth(
121     float width, float height, Axis direction, const Dimension& hotBlockShadowWidth, SliderModel::SliderMode mode)
122 {
123     auto theme = GetTheme();
124     CHECK_NULL_RETURN(theme, 0.0f);
125     auto blockWidth = direction == Axis::HORIZONTAL ? blockSize_.Height() : blockSize_.Width();
126     auto blockHotWidth = direction == Axis::HORIZONTAL ? blockHotSize_.Height() : blockHotSize_.Width();
127     auto sliderWidth = static_cast<float>(theme->GetMeasureContentDefaultWidth().ConvertToPx());
128     if (mode == SliderModel::SliderMode::NONE || mode == SliderModel::SliderMode::OUTSET) {
129         sliderWidth = static_cast<float>(theme->GetMeasureContentOutsetWidth().ConvertToPx());
130     }
131     sliderWidth = std::max(sliderWidth, trackThickness_);
132     if (mode == SliderModel::SliderMode::OUTSET) {
133         sliderWidth = std::max(sliderWidth, blockHotWidth);
134         sliderWidth = std::max(sliderWidth, blockWidth + static_cast<float>(hotBlockShadowWidth.ConvertToPx()) / HALF);
135     }
136     sliderWidth = std::clamp(sliderWidth, 0.0f, direction == Axis::HORIZONTAL ? height : width);
137     return sliderWidth;
138 }
139 
GetStyleThemeValue(LayoutWrapper * layoutWrapper,Dimension & themeTrackThickness,Dimension & themeBlockSize,Dimension & hotBlockShadowWidth,Dimension & themeBlockHotSize)140 void SliderLayoutAlgorithm::GetStyleThemeValue(LayoutWrapper* layoutWrapper, Dimension& themeTrackThickness,
141     Dimension& themeBlockSize, Dimension& hotBlockShadowWidth, Dimension& themeBlockHotSize)
142 {
143     auto frameNode = layoutWrapper->GetHostNode();
144     CHECK_NULL_VOID(frameNode);
145     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutWrapper->GetLayoutProperty());
146     CHECK_NULL_VOID(sliderLayoutProperty);
147     auto pipeline = frameNode->GetContext();
148     CHECK_NULL_VOID(pipeline);
149     auto theme = pipeline->GetTheme<SliderTheme>();
150     CHECK_NULL_VOID(theme);
151     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
152     if (sliderMode == SliderModel::SliderMode::OUTSET) {
153         themeTrackThickness = theme->GetOutsetTrackThickness();
154         themeBlockSize = theme->GetOutsetBlockSize();
155         hotBlockShadowWidth = theme->GetOutsetHotBlockShadowWidth();
156         themeBlockHotSize = theme->GetOutsetBlockHotSize();
157     } else if (sliderMode == SliderModel::SliderMode::INSET) {
158         themeTrackThickness = theme->GetInsetTrackThickness();
159         themeBlockSize = theme->GetInsetBlockSize();
160         hotBlockShadowWidth = theme->GetInsetHotBlockShadowWidth();
161         themeBlockHotSize = theme->GetInsetBlockHotSize();
162     } else {
163         themeTrackThickness = theme->GetNoneTrackThickness();
164         themeBlockSize = Dimension(0);
165         hotBlockShadowWidth = Dimension(0);
166         themeBlockHotSize = theme->GetNoneBlockHotSize();
167     }
168 }
169 
Measure(LayoutWrapper * layoutWrapper)170 void SliderLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
171 {
172     auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
173     auto frameNode = layoutWrapper->GetHostNode();
174     CHECK_NULL_VOID(frameNode);
175     auto pattern = frameNode->GetPattern<SliderPattern>();
176     CHECK_NULL_VOID(pattern);
177     if (!pattern->UseContentModifier()) {
178         layoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(blockSize_.Width(), blockSize_.Height()));
179     }
180     if (layoutWrapper->GetTotalChildCount() != 0) {
181         auto child = layoutWrapper->GetOrCreateChildByIndex(0);
182         child->Measure(layoutConstraint);
183     }
184     PerformMeasureSelf(layoutWrapper);
185 }
186 
Layout(LayoutWrapper * layoutWrapper)187 void SliderLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
188 {
189     auto host = layoutWrapper->GetHostNode();
190     CHECK_NULL_VOID(host);
191     auto pattern = DynamicCast<SliderPattern>(host->GetPattern());
192     CHECK_NULL_VOID(pattern);
193     if (pattern->UseContentModifier()) {
194         BoxLayoutAlgorithm::Layout(layoutWrapper);
195         return;
196     }
197     PerformLayout(layoutWrapper);
198     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
199     if (children.empty()) {
200         return;
201     }
202 
203     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
204     CHECK_NULL_VOID(sliderLayoutProperty);
205     auto pipeline = host->GetContext();
206     CHECK_NULL_VOID(pipeline);
207     auto theme = pipeline->GetTheme<SliderTheme>();
208     CHECK_NULL_VOID(theme);
209 
210     auto contentRect = layoutWrapper->GetGeometryNode()->GetContentRect();
211     auto axis = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
212     auto paintReverse = sliderLayoutProperty->GetReverseValue(false);
213     auto direction = sliderLayoutProperty->GetLayoutDirection();
214     if (axis == Axis::HORIZONTAL) {
215         auto isRTL = direction == TextDirection::AUTO ? AceApplicationInfo::GetInstance().IsRightToLeft()
216                                                       : direction == TextDirection::RTL;
217         paintReverse = isRTL ? !paintReverse : paintReverse;
218     }
219     auto mode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
220     Dimension hotBlockShadowWidth = mode == SliderModel::SliderMode::OUTSET ? theme->GetOutsetHotBlockShadowWidth()
221                                                                             : theme->GetInsetHotBlockShadowWidth();
222     auto length = axis == Axis::HORIZONTAL ? contentRect.Width() : contentRect.Height();
223     float BlockShadowWidth = static_cast<float>(hotBlockShadowWidth.ConvertToPx());
224     auto blockSize = axis == Axis::HORIZONTAL ? blockSize_.Width() : blockSize_.Height();
225     auto borderBlank = std::max(trackThickness_, blockSize + BlockShadowWidth / HALF);
226     auto sliderLength = length >= borderBlank ? length - borderBlank : 1;
227     borderBlank = (length - sliderLength) * HALF;
228     auto selectOffset = borderBlank + pattern->GetValueRatio() * sliderLength;
229 
230     CalculateBlockOffset(layoutWrapper, contentRect, selectOffset, axis, paintReverse);
231 }
232 
CalculateBlockOffset(LayoutWrapper * layoutWrapper,const RectF & contentRect,float selectOffset,Axis axis,bool reverse)233 void SliderLayoutAlgorithm::CalculateBlockOffset(
234     LayoutWrapper* layoutWrapper, const RectF& contentRect, float selectOffset, Axis axis, bool reverse)
235 {
236     auto host = layoutWrapper->GetHostNode();
237     CHECK_NULL_VOID(host);
238     auto pattern = DynamicCast<SliderPattern>(host->GetPattern());
239     CHECK_NULL_VOID(pattern);
240 
241     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
242     auto child = children.front();
243     auto childSize_ = child->GetGeometryNode()->GetMarginFrameSize();
244     OffsetF circleCenter;
245     auto animatableBlockCenter = pattern->GetAnimatableBlockCenter();
246     if (animatableBlockCenter.has_value()) {
247         circleCenter = animatableBlockCenter.value();
248     } else {
249         if (!reverse) {
250             if (axis == Axis::HORIZONTAL) {
251                 circleCenter.SetX(selectOffset);
252                 circleCenter.SetY(contentRect.Height() * HALF);
253             } else {
254                 circleCenter.SetX(contentRect.Width() * HALF);
255                 circleCenter.SetY(selectOffset);
256             }
257         } else {
258             if (axis == Axis::HORIZONTAL) {
259                 circleCenter.SetX(contentRect.Width() - selectOffset);
260                 circleCenter.SetY(contentRect.Height() * HALF);
261             } else {
262                 circleCenter.SetX(contentRect.Width() * HALF);
263                 circleCenter.SetY(contentRect.Height() - selectOffset);
264             }
265         }
266         circleCenter += OffsetF(contentRect.GetX(), contentRect.GetY());
267     }
268 
269     OffsetF imageNodeOffset(
270         circleCenter.GetX() - childSize_.Width() * HALF, circleCenter.GetY() - childSize_.Height() * HALF);
271 
272     child->GetGeometryNode()->SetMarginFrameOffset(imageNodeOffset);
273     child->Layout();
274 }
275 
276 } // namespace OHOS::Ace::NG
277