• 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;
24 const Dimension shrinkWidth = 16.0_vp;
25 const Dimension thresholdWidth = 34.5_vp; //The slider shortens the width of the threshold
JudgeTrackness(Axis direction,float blockDiameter,float trackThickness,float width,float height)26 bool JudgeTrackness(Axis direction, float blockDiameter, float trackThickness, float width, float height)
27 {
28     if (direction == Axis::HORIZONTAL) {
29         return blockDiameter > height || trackThickness > height;
30     }
31     return blockDiameter > width || trackThickness > width;
32 }
33 
GetTheme()34 RefPtr<SliderTheme> GetTheme()
35 {
36     auto pipeline = PipelineBase::GetCurrentContext();
37     CHECK_NULL_RETURN(pipeline, nullptr);
38     return pipeline->GetTheme<SliderTheme>();
39 }
40 } // namespace
41 
CalculateHotSize(LayoutWrapper * layoutWrapper,const SizeF & blockSize,float themeBlockHotSize)42 SizeF SliderLayoutAlgorithm::CalculateHotSize(
43     LayoutWrapper* layoutWrapper, const SizeF& blockSize, float themeBlockHotSize)
44 {
45     CHECK_NULL_RETURN(layoutWrapper, SizeF());
46     auto frameNode = layoutWrapper->GetHostNode();
47     CHECK_NULL_RETURN(frameNode, SizeF());
48     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutWrapper->GetLayoutProperty());
49     CHECK_NULL_RETURN(sliderLayoutProperty, SizeF());
50     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
51     SizeF blockHotSize = blockSize;
52     if (sliderMode == SliderModel::SliderMode::NONE) {
53         auto hotSize = std::max(themeBlockHotSize, trackThickness_);
54         blockHotSize = SizeF(hotSize, hotSize);
55     } else {
56         if (LessNotEqual(blockHotSize.Width(), themeBlockHotSize)) {
57             blockHotSize.SetWidth(themeBlockHotSize);
58         }
59         if (LessNotEqual(blockHotSize.Height(), themeBlockHotSize)) {
60             blockHotSize.SetHeight(themeBlockHotSize);
61         }
62     }
63     return blockHotSize;
64 }
65 
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)66 std::optional<SizeF> SliderLayoutAlgorithm::MeasureContent(
67     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
68 {
69     auto frameNode = layoutWrapper->GetHostNode();
70     CHECK_NULL_RETURN(frameNode, std::nullopt);
71     auto pattern = frameNode->GetPattern<SliderPattern>();
72     CHECK_NULL_RETURN(pattern, std::nullopt);
73     if (pattern->UseContentModifier()) {
74         if (frameNode->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
75             frameNode->GetGeometryNode()->ResetContent();
76         } else {
77             frameNode->GetGeometryNode()->Reset();
78         }
79         return std::nullopt;
80     }
81     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutWrapper->GetLayoutProperty());
82     CHECK_NULL_RETURN(sliderLayoutProperty, std::nullopt);
83     auto theme = GetTheme();
84     CHECK_NULL_RETURN(theme, std::nullopt);
85 
86     float width = contentConstraint.selfIdealSize.Width().value_or(contentConstraint.maxSize.Width());
87     float height = contentConstraint.selfIdealSize.Height().value_or(contentConstraint.maxSize.Height());
88     auto layoutPolicy = GetLayoutPolicy(layoutWrapper);
89     if (layoutPolicy.has_value() && layoutPolicy->IsMatch()) {
90         if (layoutPolicy->IsWidthMatch()) {
91             width = contentConstraint.parentIdealSize.Width().value();
92         }
93         if (layoutPolicy->IsHeightMatch()) {
94             height = contentConstraint.parentIdealSize.Height().value();
95         }
96     }
97     Axis direction = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
98     if (direction == Axis::HORIZONTAL && GreaterOrEqualToInfinity(width)) {
99         width = static_cast<float>(theme->GetLayoutMaxLength().ConvertToPx());
100     }
101     if (direction == Axis::VERTICAL && GreaterOrEqualToInfinity(height)) {
102         height = static_cast<float>(theme->GetLayoutMaxLength().ConvertToPx());
103     }
104 
105     Dimension themeTrackThickness;
106     Dimension themeBlockSize;
107     Dimension hotBlockShadowWidth;
108     Dimension themeBlockHotSize;
109     GetStyleThemeValue(layoutWrapper, themeTrackThickness, themeBlockSize, hotBlockShadowWidth, themeBlockHotSize);
110     auto thickness = sliderLayoutProperty->GetThickness().value_or(themeTrackThickness);
111     trackThickness_ =
112         static_cast<float>(thickness.Unit() == DimensionUnit::PERCENT
113                                ? thickness.ConvertToPxWithSize(direction == Axis::HORIZONTAL ? height : width)
114                                : thickness.ConvertToPx());
115     // this scaleValue ensure that the size ratio of the block and trackThickness is consistent
116     float scaleValue = trackThickness_ / static_cast<float>(themeTrackThickness.ConvertToPx());
117     auto blockDiameter = scaleValue * static_cast<float>(themeBlockSize.ConvertToPx());
118     // trackThickness and blockDiameter will get from theme when they are greater than slider component height or width
119     if (JudgeTrackness(direction, blockDiameter, trackThickness_, width, height)) {
120         trackThickness_ = static_cast<float>(themeTrackThickness.ConvertToPx());
121         scaleValue = 1.0;
122         blockDiameter = static_cast<float>(themeBlockSize.ConvertToPx());
123     }
124     blockSize_ = sliderLayoutProperty->GetBlockSizeValue(SizeF(blockDiameter, blockDiameter));
125     blockHotSize_ = CalculateHotSize(layoutWrapper, blockSize_, static_cast<float>(themeBlockHotSize.ConvertToPx()));
126     pattern->UpdateSliderParams(trackThickness_, blockSize_, blockHotSize_);
127     auto mode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
128     auto sliderWidth = CalculateSliderWidth(width, height, direction, hotBlockShadowWidth, mode);
129     float sliderLength =
130         CalculateSliderLength(width, height, direction, mode, (pattern->HasPrefix() || pattern->HasSuffix()));
131     return direction == Axis::HORIZONTAL ? SizeF(sliderLength, sliderWidth) : SizeF(sliderWidth, sliderLength);
132 }
133 
CalculateSliderLength(float width,float height,Axis direction,SliderModel::SliderMode mode,bool Ends)134 float SliderLayoutAlgorithm::CalculateSliderLength(
135     float width, float height, Axis direction, SliderModel::SliderMode mode, bool Ends)
136 {
137     auto sliderLength = direction == Axis::HORIZONTAL ? width : height;
138     if (mode == SliderModel::SliderMode::OUTSET && Ends) {
139         sliderLength = sliderLength - static_cast<float>(shrinkWidth.ConvertToPx()) / HALF -
140                        static_cast<float>(thresholdWidth.ConvertToPx());
141     }
142     return sliderLength;
143 }
144 
CalculateSliderWidth(float width,float height,Axis direction,const Dimension & hotBlockShadowWidth,SliderModel::SliderMode mode)145 float SliderLayoutAlgorithm::CalculateSliderWidth(
146     float width, float height, Axis direction, const Dimension& hotBlockShadowWidth, SliderModel::SliderMode mode)
147 {
148     auto theme = GetTheme();
149     CHECK_NULL_RETURN(theme, 0.0f);
150     auto blockWidth = direction == Axis::HORIZONTAL ? blockSize_.Height() : blockSize_.Width();
151     auto blockHotWidth = direction == Axis::HORIZONTAL ? blockHotSize_.Height() : blockHotSize_.Width();
152     auto sliderWidth = static_cast<float>(theme->GetMeasureContentDefaultWidth().ConvertToPx());
153     if (mode == SliderModel::SliderMode::NONE || mode == SliderModel::SliderMode::OUTSET) {
154         sliderWidth = static_cast<float>(theme->GetMeasureContentOutsetWidth().ConvertToPx());
155     }
156     sliderWidth = std::max(sliderWidth, trackThickness_);
157     if (mode == SliderModel::SliderMode::OUTSET) {
158         sliderWidth = std::max(sliderWidth, blockHotWidth);
159         sliderWidth = std::max(sliderWidth, blockWidth + static_cast<float>(hotBlockShadowWidth.ConvertToPx()) / HALF);
160     }
161     sliderWidth = std::clamp(sliderWidth, 0.0f, direction == Axis::HORIZONTAL ? height : width);
162     return sliderWidth;
163 }
164 
GetStyleThemeValue(LayoutWrapper * layoutWrapper,Dimension & themeTrackThickness,Dimension & themeBlockSize,Dimension & hotBlockShadowWidth,Dimension & themeBlockHotSize)165 void SliderLayoutAlgorithm::GetStyleThemeValue(LayoutWrapper* layoutWrapper, Dimension& themeTrackThickness,
166     Dimension& themeBlockSize, Dimension& hotBlockShadowWidth, Dimension& themeBlockHotSize)
167 {
168     CHECK_NULL_VOID(layoutWrapper);
169     auto frameNode = layoutWrapper->GetHostNode();
170     CHECK_NULL_VOID(frameNode);
171     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutWrapper->GetLayoutProperty());
172     CHECK_NULL_VOID(sliderLayoutProperty);
173     auto pipeline = frameNode->GetContext();
174     CHECK_NULL_VOID(pipeline);
175     auto theme = pipeline->GetTheme<SliderTheme>();
176     CHECK_NULL_VOID(theme);
177     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
178     if (sliderMode == SliderModel::SliderMode::OUTSET) {
179         themeTrackThickness = theme->GetOutsetTrackThickness();
180         themeBlockSize = theme->GetOutsetBlockSize();
181         hotBlockShadowWidth = theme->GetOutsetHotBlockShadowWidth();
182         themeBlockHotSize = theme->GetOutsetBlockHotSize();
183     } else if (sliderMode == SliderModel::SliderMode::INSET) {
184         themeTrackThickness = theme->GetInsetTrackThickness();
185         themeBlockSize = theme->GetInsetBlockSize();
186         hotBlockShadowWidth = theme->GetInsetHotBlockShadowWidth();
187         themeBlockHotSize = theme->GetInsetBlockHotSize();
188     } else {
189         themeTrackThickness = theme->GetNoneTrackThickness();
190         themeBlockSize = Dimension(0);
191         hotBlockShadowWidth = Dimension(0);
192         themeBlockHotSize = theme->GetNoneBlockHotSize();
193     }
194 }
195 
Measure(LayoutWrapper * layoutWrapper)196 void SliderLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
197 {
198     CHECK_NULL_VOID(layoutWrapper);
199     auto layoutProperty = layoutWrapper->GetLayoutProperty();
200     CHECK_NULL_VOID(layoutProperty);
201     auto layoutConstraint = layoutProperty->CreateChildConstraint();
202     auto sliderLayoutProperty = DynamicCast<SliderLayoutProperty>(layoutProperty);
203     CHECK_NULL_VOID(sliderLayoutProperty);
204     auto frameNode = layoutWrapper->GetHostNode();
205     CHECK_NULL_VOID(frameNode);
206     auto pattern = frameNode->GetPattern<SliderPattern>();
207     CHECK_NULL_VOID(pattern);
208     if (!pattern->UseContentModifier()) {
209         layoutConstraint.UpdateSelfMarginSizeWithCheck(OptionalSizeF(blockSize_.Width(), blockSize_.Height()));
210     }
211     if (pattern->HasPrefix() || pattern->HasSuffix()) {
212         const auto& children = layoutWrapper->GetAllChildrenWithBuild();
213         auto contentRect = layoutWrapper->GetGeometryNode()->GetContentRect();
214         auto axis = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
215         if (axis == Axis::HORIZONTAL) {
216             maxWidth = contentRect.Width() * langRatio;
217             maxHeight = maxWidth * shortRatio;
218         } else {
219             maxHeight = contentRect.Height() * langRatio;
220             maxWidth = maxHeight * shortRatio;
221         }
222         if (pattern->HasPrefix()) {
223             auto prefixChild = layoutWrapper->GetOrCreateChildByIndex(0);
224             CHECK_NULL_VOID(prefixChild);
225             SetChildConstraint(prefixChild, maxWidth, maxHeight);
226         }
227         if (pattern->HasSuffix()) {
228             auto suffixChild = layoutWrapper->GetOrCreateChildByIndex(0);
229             if (pattern->HasPrefix()) {
230                 suffixChild = layoutWrapper->GetOrCreateChildByIndex(1);
231             }
232             CHECK_NULL_VOID(suffixChild);
233             SetChildConstraint(suffixChild, maxWidth, maxHeight);
234         }
235     } else {
236         if (layoutWrapper->GetTotalChildCount() != 0) {
237             auto child = layoutWrapper->GetOrCreateChildByIndex(0);
238             CHECK_NULL_VOID(child);
239             child->Measure(layoutConstraint);
240         }
241     }
242     PerformMeasureSelf(layoutWrapper);
243 }
244 
SetChildConstraint(RefPtr<LayoutWrapper> child,float maxWidth,float maxHeight)245 void SliderLayoutAlgorithm::SetChildConstraint(RefPtr<LayoutWrapper> child, float maxWidth, float maxHeight)
246 {
247     auto childLayoutProperty = child->GetLayoutProperty();
248     CHECK_NULL_VOID(childLayoutProperty);
249     LayoutConstraintF childConstraint = childLayoutProperty->CreateChildConstraint();
250     childConstraint.maxSize.SetWidth(maxWidth);
251     childConstraint.maxSize.SetHeight(maxHeight);
252     child->Measure(childConstraint);
253 }
254 
Layout(LayoutWrapper * layoutWrapper)255 void SliderLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
256 {
257     auto host = layoutWrapper->GetHostNode();
258     CHECK_NULL_VOID(host);
259     auto pattern = DynamicCast<SliderPattern>(host->GetPattern());
260     CHECK_NULL_VOID(pattern);
261     if (pattern->UseContentModifier()) {
262         BoxLayoutAlgorithm::Layout(layoutWrapper);
263         return;
264     }
265     PerformLayout(layoutWrapper);
266     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
267     if (children.empty()) {
268         return;
269     }
270 
271     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
272     CHECK_NULL_VOID(sliderLayoutProperty);
273     auto pipeline = host->GetContext();
274     CHECK_NULL_VOID(pipeline);
275     auto theme = pipeline->GetTheme<SliderTheme>();
276     CHECK_NULL_VOID(theme);
277 
278     auto contentRect = layoutWrapper->GetGeometryNode()->GetContentRect();
279     auto axis = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
280     auto paintReverse = sliderLayoutProperty->GetReverseValue(false);
281     auto direction = sliderLayoutProperty->GetLayoutDirection();
282     if (axis == Axis::HORIZONTAL) {
283         auto isRTL = direction == TextDirection::AUTO ? AceApplicationInfo::GetInstance().IsRightToLeft()
284                                                       : direction == TextDirection::RTL;
285         paintReverse = isRTL ? !paintReverse : paintReverse;
286     }
287     auto mode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
288     Dimension hotBlockShadowWidth = mode == SliderModel::SliderMode::OUTSET ? theme->GetOutsetHotBlockShadowWidth()
289                                                                             : theme->GetInsetHotBlockShadowWidth();
290     auto length = axis == Axis::HORIZONTAL ? contentRect.Width() : contentRect.Height();
291     float BlockShadowWidth = static_cast<float>(hotBlockShadowWidth.ConvertToPx());
292     auto blockSize = axis == Axis::HORIZONTAL ? blockSize_.Width() : blockSize_.Height();
293     auto borderBlank = std::max(trackThickness_, blockSize + BlockShadowWidth / HALF);
294     auto sliderLength = length >= borderBlank ? length - borderBlank : 1;
295     borderBlank = (length - sliderLength) * HALF;
296     auto selectOffset = borderBlank + pattern->GetValueRatio() * sliderLength;
297     auto insetModeOffset = borderBlank + blockSize * HALF;
298 
299     CalculateBlockOffset(layoutWrapper, contentRect, selectOffset, axis, paintReverse);
300     if (pattern->HasPrefix()) {
301         CalculatePrefixOffset(layoutWrapper, contentRect, insetModeOffset, axis, paintReverse);
302     }
303     if (pattern->HasSuffix()) {
304         CalculateSuffixOffset(layoutWrapper, contentRect, insetModeOffset, axis, paintReverse);
305     }
306 }
307 
CalculatePrefixOffset(LayoutWrapper * layoutWrapper,const RectF & contentRect,float borderBlank,Axis axis,bool reverse)308 void SliderLayoutAlgorithm::CalculatePrefixOffset(
309     LayoutWrapper* layoutWrapper, const RectF& contentRect, float borderBlank, Axis axis, bool reverse)
310 {
311     auto host = layoutWrapper->GetHostNode();
312     CHECK_NULL_VOID(host);
313     auto pattern = DynamicCast<SliderPattern>(host->GetPattern());
314     CHECK_NULL_VOID(pattern);
315 
316     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
317     if (children.size() < 1) {
318         return;
319     }
320     auto prefixIter = std::next(children.begin(), 0);
321     auto prefixChild = *prefixIter;
322     prefixChild->Layout();
323 }
324 
CalculateSuffixOffset(LayoutWrapper * layoutWrapper,const RectF & contentRect,float borderBlank,Axis axis,bool reverse)325 void SliderLayoutAlgorithm::CalculateSuffixOffset(
326     LayoutWrapper* layoutWrapper, const RectF& contentRect, float borderBlank, Axis axis, bool reverse)
327 {
328     auto host = layoutWrapper->GetHostNode();
329     CHECK_NULL_VOID(host);
330     auto pattern = DynamicCast<SliderPattern>(host->GetPattern());
331     CHECK_NULL_VOID(pattern);
332 
333     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
334     if (children.size() < 1) {
335         return;
336     }
337     auto suffixIter = std::next(children.begin(), 0);
338     if (children.size() > 1) {
339         suffixIter = std::next(children.begin(), 1);
340     }
341     auto suffixChild = *suffixIter;
342     suffixChild->Layout();
343 }
344 
CalculateBlockOffset(LayoutWrapper * layoutWrapper,const RectF & contentRect,float selectOffset,Axis axis,bool reverse)345 void SliderLayoutAlgorithm::CalculateBlockOffset(
346     LayoutWrapper* layoutWrapper, const RectF& contentRect, float selectOffset, Axis axis, bool reverse)
347 {
348     auto host = layoutWrapper->GetHostNode();
349     CHECK_NULL_VOID(host);
350     auto pattern = DynamicCast<SliderPattern>(host->GetPattern());
351     CHECK_NULL_VOID(pattern);
352 
353     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
354     auto child = children.front();
355     auto childSize_ = child->GetGeometryNode()->GetMarginFrameSize();
356     OffsetF circleCenter;
357     auto animatableBlockCenter = pattern->GetAnimatableBlockCenter();
358     if (animatableBlockCenter.has_value()) {
359         circleCenter = animatableBlockCenter.value();
360     } else {
361         if (!reverse) {
362             if (axis == Axis::HORIZONTAL) {
363                 circleCenter.SetX(selectOffset);
364                 circleCenter.SetY(contentRect.Height() * HALF);
365             } else {
366                 circleCenter.SetX(contentRect.Width() * HALF);
367                 circleCenter.SetY(selectOffset);
368             }
369         } else {
370             if (axis == Axis::HORIZONTAL) {
371                 circleCenter.SetX(contentRect.Width() - selectOffset);
372                 circleCenter.SetY(contentRect.Height() * HALF);
373             } else {
374                 circleCenter.SetX(contentRect.Width() * HALF);
375                 circleCenter.SetY(contentRect.Height() - selectOffset);
376             }
377         }
378         circleCenter += OffsetF(contentRect.GetX(), contentRect.GetY());
379     }
380 
381     OffsetF imageNodeOffset(
382         circleCenter.GetX() - childSize_.Width() * HALF, circleCenter.GetY() - childSize_.Height() * HALF);
383 
384     child->GetGeometryNode()->SetMarginFrameOffset(imageNodeOffset);
385     child->Layout();
386 }
387 
GetLayoutPolicy(LayoutWrapper * layoutWrapper)388 std::optional<NG::LayoutPolicyProperty> SliderLayoutAlgorithm::GetLayoutPolicy(LayoutWrapper* layoutWrapper)
389 {
390     CHECK_NULL_RETURN(layoutWrapper, NG::LayoutPolicyProperty());
391     auto layoutProperty = layoutWrapper->GetLayoutProperty();
392     CHECK_NULL_RETURN(layoutProperty, NG::LayoutPolicyProperty());
393     auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
394     CHECK_NULL_RETURN(layoutPolicy, NG::LayoutPolicyProperty());
395     return layoutPolicy;
396 }
397 } // namespace OHOS::Ace::NG
398