1 /*
2 * Copyright (c) 2022 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/button/button_layout_algorithm.h"
17
18 #include "core/components/toggle/toggle_theme.h"
19 #include "core/components_ng/pattern/button/button_pattern.h"
20 #include "core/components_ng/property/measure_utils.h"
21
22 namespace OHOS::Ace::NG {
23 namespace {
checkNegativeBorderRadius(std::optional<Dimension> & radius,const float defaultBorderRadius)24 void checkNegativeBorderRadius(std::optional<Dimension>& radius, const float defaultBorderRadius)
25 {
26 // Change the borderRadius size of a negative number to the default.
27 if (!radius.has_value() || LessNotEqual(radius.value().ConvertToPx(), 0.0)) {
28 radius = Dimension(defaultBorderRadius);
29 }
30 }
31 }
Measure(LayoutWrapper * layoutWrapper)32 void ButtonLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
33 {
34 auto host = layoutWrapper->GetHostNode();
35 CHECK_NULL_VOID(host);
36 auto pattern = host->GetPattern<ButtonPattern>();
37 CHECK_NULL_VOID(pattern);
38 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
39 CHECK_NULL_VOID(buttonLayoutProperty);
40 bool isEnableChildrenMatchParent = pattern->IsEnableChildrenMatchParent();
41 if (buttonLayoutProperty->HasType() && buttonLayoutProperty->GetType() == ButtonType::CIRCLE &&
42 !pattern->GetHasCustomPadding()) {
43 NG::PaddingProperty paddings;
44 paddings.top = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
45 paddings.bottom = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
46 paddings.left = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
47 paddings.right = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
48 buttonLayoutProperty->UpdatePadding(paddings);
49 }
50 if (pattern->UseContentModifier()) {
51 const auto& childList = layoutWrapper->GetAllChildrenWithBuild();
52 std::list<RefPtr<LayoutWrapper>> builderChildList;
53 for (const auto& child : childList) {
54 if (child->GetHostNode()->GetId() != pattern->GetBuilderId()) {
55 child->GetGeometryNode()->Reset();
56 child->GetGeometryNode()->SetContentSize(SizeF());
57 } else {
58 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
59 child->Measure(layoutConstraint);
60 builderChildList.push_back(child);
61 }
62 }
63 BoxLayoutAlgorithm::PerformMeasureSelfWithChildList(layoutWrapper, builderChildList);
64 return;
65 }
66 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
67 HandleChildLayoutConstraint(layoutWrapper, layoutConstraint);
68 if (buttonLayoutProperty->HasLabel()) {
69 // If the button has label, according to whether the font size is set to do the corresponding expansion button,
70 // font reduction, truncation and other operations.
71 HandleAdaptiveText(layoutWrapper, layoutConstraint);
72 } else {
73 // If the button has not label, measure the child directly.
74 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
75 auto childLayoutProperty = child->GetLayoutProperty();
76 CHECK_NULL_CONTINUE(childLayoutProperty);
77 if (isEnableChildrenMatchParent &&
78 ProcessLayoutPolicyIsNotNoMatch(childLayoutProperty->GetLayoutPolicyProperty())) {
79 layoutPolicyChildren_.emplace_back(child);
80 continue;
81 }
82 child->Measure(layoutConstraint);
83 }
84 }
85 PerformMeasureSelf(layoutWrapper);
86 if (isEnableChildrenMatchParent) {
87 auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
88 MeasureAdaptiveLayoutChildren(layoutWrapper, frameSize);
89 }
90 }
91
ProcessLayoutPolicyIsNotNoMatch(std::optional<NG::LayoutPolicyProperty> layoutPolicy)92 bool ButtonLayoutAlgorithm::ProcessLayoutPolicyIsNotNoMatch(std::optional<NG::LayoutPolicyProperty> layoutPolicy)
93 {
94 if (layoutPolicy.has_value()) {
95 auto widthLayoutPolicy = layoutPolicy.value().widthLayoutPolicy_;
96 auto heightLayoutPolicy = layoutPolicy.value().heightLayoutPolicy_;
97 if (widthLayoutPolicy.value_or(LayoutCalPolicy::NO_MATCH) != LayoutCalPolicy::NO_MATCH ||
98 heightLayoutPolicy.value_or(LayoutCalPolicy::NO_MATCH) != LayoutCalPolicy::NO_MATCH) {
99 return true;
100 }
101 return false;
102 }
103 return false;
104 }
105
HandleChildLayoutConstraint(LayoutWrapper * layoutWrapper,LayoutConstraintF & layoutConstraint)106 void ButtonLayoutAlgorithm::HandleChildLayoutConstraint(
107 LayoutWrapper* layoutWrapper, LayoutConstraintF& layoutConstraint)
108 {
109 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
110 CHECK_NULL_VOID(buttonLayoutProperty);
111 if (!buttonLayoutProperty->HasLabel()) {
112 return;
113 }
114 auto buttonType = buttonLayoutProperty->GetType().value_or(ButtonType::CAPSULE);
115 if (buttonType == ButtonType::CIRCLE) {
116 layoutConstraint.maxSize = HandleLabelCircleButtonConstraint(layoutWrapper).value_or(SizeF());
117 return;
118 }
119 const auto& selfLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
120 // If height is not set, apply the default height.
121 if (selfLayoutConstraint && !selfLayoutConstraint->selfIdealSize.Height().has_value()) {
122 auto maxHeight = selfLayoutConstraint->maxSize.Height();
123 if (IsAging(layoutWrapper)) {
124 layoutConstraint.maxSize.SetHeight(maxHeight);
125 return;
126 }
127 auto defaultHeight = GetDefaultHeight(layoutWrapper);
128 layoutConstraint.maxSize.SetHeight(maxHeight > defaultHeight ? defaultHeight : maxHeight);
129 }
130 }
131
132 // If the ButtonType is CIRCLE, then omit text by the smaller edge.
HandleLabelCircleButtonConstraint(LayoutWrapper * layoutWrapper)133 std::optional<SizeF> ButtonLayoutAlgorithm::HandleLabelCircleButtonConstraint(LayoutWrapper* layoutWrapper)
134 {
135 SizeF constraintSize;
136 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
137 CHECK_NULL_RETURN(buttonLayoutProperty, constraintSize);
138 const auto& selfLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
139 CHECK_NULL_RETURN(selfLayoutConstraint, constraintSize);
140 auto host = layoutWrapper->GetHostNode();
141 CHECK_NULL_RETURN(host, constraintSize);
142 auto* context = host->GetContextWithCheck();
143 CHECK_NULL_RETURN(context, constraintSize);
144 auto buttonTheme = context->GetTheme<ButtonTheme>();
145 CHECK_NULL_RETURN(buttonTheme, constraintSize);
146 const auto& padding = buttonLayoutProperty->CreatePaddingAndBorder();
147 auto defaultHeight = GetDefaultHeight(layoutWrapper);
148 float minLength = 0.0f;
149 if (selfLayoutConstraint->selfIdealSize.IsNull()) {
150 // Width and height are not set.
151 minLength = defaultHeight;
152 } else if (selfLayoutConstraint->selfIdealSize.Width().has_value() &&
153 !selfLayoutConstraint->selfIdealSize.Height().has_value()) {
154 // Only width is set.
155 minLength = selfLayoutConstraint->selfIdealSize.Width().value();
156 } else if (selfLayoutConstraint->selfIdealSize.Height().has_value() &&
157 !selfLayoutConstraint->selfIdealSize.Width().has_value()) {
158 // Only height is set.
159 minLength = selfLayoutConstraint->selfIdealSize.Height().value();
160 } else {
161 // Both width and height are set.
162 auto buttonWidth = selfLayoutConstraint->selfIdealSize.Width().value();
163 auto buttonHeight = selfLayoutConstraint->selfIdealSize.Height().value();
164 minLength = std::min(buttonWidth, buttonHeight);
165 }
166 if (buttonLayoutProperty->HasBorderRadius() && selfLayoutConstraint->selfIdealSize.IsNull()) {
167 auto radius =
168 static_cast<float>(GetFirstValidRadius(buttonLayoutProperty->GetBorderRadius().value()).ConvertToPx());
169 minLength = 2 * radius;
170 }
171 constraintSize.SetSizeT(SizeF(minLength, minLength));
172 MinusPaddingToSize(padding, constraintSize);
173 return ConstrainSize(constraintSize, selfLayoutConstraint->minSize, selfLayoutConstraint->maxSize);
174 }
175
HandleAdaptiveText(LayoutWrapper * layoutWrapper,LayoutConstraintF & layoutConstraint)176 void ButtonLayoutAlgorithm::HandleAdaptiveText(LayoutWrapper* layoutWrapper, LayoutConstraintF& layoutConstraint)
177 {
178 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
179 CHECK_NULL_VOID(buttonLayoutProperty);
180 auto host = layoutWrapper->GetHostNode();
181 CHECK_NULL_VOID(host);
182 auto* context = host->GetContextWithCheck();
183 CHECK_NULL_VOID(context);
184 auto buttonTheme = context->GetTheme<ButtonTheme>();
185 CHECK_NULL_VOID(buttonTheme);
186 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
187 CHECK_NULL_VOID(childWrapper);
188 if (buttonLayoutProperty->HasFontSize() || buttonLayoutProperty->HasControlSize()) {
189 auto childConstraint = layoutWrapper->GetLayoutProperty()->GetContentLayoutConstraint();
190 childWrapper->Measure(childConstraint);
191 auto textSize = childWrapper->GetGeometryNode()->GetContentSize();
192 // Fonsize is set. When the font height is larger than the button height, make the button fit the font
193 // height.
194 if (GreatOrEqual(textSize.Height(), layoutConstraint.maxSize.Height())) {
195 layoutConstraint.maxSize.SetHeight(textSize.Height());
196 }
197 } else {
198 // Fonsize is not set. When the font width is greater than the button width, dynamically change the font
199 // size to no less than 9sp.
200 auto textLayoutProperty = DynamicCast<TextLayoutProperty>(childWrapper->GetLayoutProperty());
201 CHECK_NULL_VOID(textLayoutProperty);
202 if (buttonTheme->GetIsApplyTextFontSize() && !buttonLayoutProperty->GetMaxFontSize().has_value() &&
203 !buttonLayoutProperty->GetMinFontSize().has_value()) {
204 textLayoutProperty->ResetAdaptMaxFontSize();
205 textLayoutProperty->ResetAdaptMinFontSize();
206 } else {
207 textLayoutProperty->UpdateAdaptMaxFontSize(
208 buttonLayoutProperty->GetMaxFontSize().value_or(buttonTheme->GetMaxFontSize()));
209 textLayoutProperty->UpdateAdaptMinFontSize(
210 buttonLayoutProperty->GetMinFontSize().value_or(buttonTheme->GetMinFontSize()));
211 }
212 }
213 childWrapper->Measure(layoutConstraint);
214 childSize_ = childWrapper->GetGeometryNode()->GetContentSize();
215 }
216
HandleBorderRadius(LayoutWrapper * layoutWrapper)217 void ButtonLayoutAlgorithm::HandleBorderRadius(LayoutWrapper* layoutWrapper)
218 {
219 auto host = layoutWrapper->GetHostNode();
220 CHECK_NULL_VOID(host);
221 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
222 CHECK_NULL_VOID(buttonLayoutProperty);
223 auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
224 auto renderContext = host->GetRenderContext();
225 CHECK_NULL_VOID(renderContext);
226 auto buttonType = buttonLayoutProperty->GetType().value_or(ButtonType::CAPSULE);
227 if (buttonType == ButtonType::CIRCLE) {
228 auto minSize = std::min(frameSize.Height(), frameSize.Width());
229 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
230 if (buttonLayoutProperty->HasBorderRadius() && layoutConstraint.parentIdealSize.IsNull()) {
231 auto borderRadius = buttonLayoutProperty->GetBorderRadius().value_or(NG::BorderRadiusProperty());
232 minSize = static_cast<float>(GetFirstValidRadius(borderRadius).ConvertToPx() * 2);
233 }
234 renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(minSize / 2)));
235 MeasureCircleButton(layoutWrapper);
236 } else if (buttonType == ButtonType::CAPSULE) {
237 renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(frameSize.Height() / 2)));
238 } else if (buttonType == ButtonType::NORMAL) {
239 auto normalRadius = buttonLayoutProperty->GetBorderRadiusValue(BorderRadiusProperty(Dimension()));
240 renderContext->UpdateBorderRadius(normalRadius);
241 } else if (buttonType == ButtonType::ROUNDED_RECTANGLE) {
242 auto defaultBorderRadius = GetDefaultBorderRadius(layoutWrapper);
243 auto roundedRectRadius =
244 buttonLayoutProperty->GetBorderRadiusValue(BorderRadiusProperty(Dimension(defaultBorderRadius)));
245 checkNegativeBorderRadius(roundedRectRadius.radiusTopLeft, defaultBorderRadius);
246 checkNegativeBorderRadius(roundedRectRadius.radiusTopRight, defaultBorderRadius);
247 checkNegativeBorderRadius(roundedRectRadius.radiusBottomLeft, defaultBorderRadius);
248 checkNegativeBorderRadius(roundedRectRadius.radiusBottomRight, defaultBorderRadius);
249 renderContext->UpdateBorderRadius(roundedRectRadius);
250 }
251 }
252
IsMatchParentWidthOrHeight(LayoutConstraintF & layoutConstraint,std::optional<NG::LayoutPolicyProperty> layoutPolicy,LayoutWrapper * layoutWrapper)253 void IsMatchParentWidthOrHeight(LayoutConstraintF& layoutConstraint,
254 std::optional<NG::LayoutPolicyProperty> layoutPolicy, LayoutWrapper* layoutWrapper)
255 {
256 auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
257 if (layoutPolicy.has_value() && layoutPolicy->IsMatch()) {
258 if (layoutPolicy->IsWidthMatch()) {
259 layoutConstraint.parentIdealSize.SetWidth(frameSize.Width());
260 }
261 if (layoutPolicy->IsHeightMatch()) {
262 layoutConstraint.parentIdealSize.SetHeight(frameSize.Height());
263 }
264 }
265 }
266
UpdateHeightIfMatchPolicy(std::optional<NG::LayoutPolicyProperty> layoutPolicy,SizeF & frameSize,float matchParentHeight)267 void UpdateHeightIfMatchPolicy(std::optional<NG::LayoutPolicyProperty> layoutPolicy, SizeF& frameSize,
268 float matchParentHeight)
269 {
270 if (layoutPolicy.has_value() && layoutPolicy->IsHeightMatch()) {
271 frameSize.SetHeight(matchParentHeight);
272 }
273 }
274
275 // Called to perform measure current render node.
PerformMeasureSelf(LayoutWrapper * layoutWrapper)276 void ButtonLayoutAlgorithm::PerformMeasureSelf(LayoutWrapper* layoutWrapper)
277 {
278 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
279 CHECK_NULL_VOID(buttonLayoutProperty);
280 BoxLayoutAlgorithm::PerformMeasureSelf(layoutWrapper);
281 auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
282 auto matchParentHeight = frameSize.Height();
283 if (NeedAgingMeasure(layoutWrapper)) {
284 return;
285 }
286 auto layoutPolicy = buttonLayoutProperty->GetLayoutPolicyProperty();
287 if (buttonLayoutProperty->HasLabel()) {
288 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
289 const auto& selfLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
290 auto padding = buttonLayoutProperty->CreatePaddingAndBorder();
291 auto topPadding = padding.top.value_or(0.0);
292 auto bottomPadding = padding.bottom.value_or(0.0);
293 auto host = layoutWrapper->GetHostNode();
294 CHECK_NULL_VOID(host);
295 auto* context = host->GetContextWithCheck();
296 CHECK_NULL_VOID(context);
297 auto buttonTheme = context->GetTheme<ButtonTheme>();
298 CHECK_NULL_VOID(buttonTheme);
299
300 auto defaultHeight = GetDefaultHeight(layoutWrapper);
301 auto buttonType = buttonLayoutProperty->GetType().value_or(ButtonType::CAPSULE);
302 if (buttonType == ButtonType::CIRCLE) {
303 IsMatchParentWidthOrHeight(layoutConstraint, layoutPolicy, layoutWrapper);
304 HandleLabelCircleButtonFrameSize(layoutConstraint, frameSize, defaultHeight);
305 } else {
306 if (selfLayoutConstraint && !selfLayoutConstraint->selfIdealSize.Height().has_value()) {
307 auto layoutContraint = buttonLayoutProperty->GetLayoutConstraint();
308 CHECK_NULL_VOID(layoutContraint);
309 auto maxHeight = layoutContraint->maxSize.Height();
310 auto minHeight = layoutContraint->minSize.Height();
311 auto actualHeight = static_cast<float>(childSize_.Height() + topPadding + bottomPadding);
312 actualHeight = std::min(actualHeight, maxHeight);
313 actualHeight = std::max(actualHeight, minHeight);
314 frameSize.SetHeight(maxHeight > defaultHeight ? std::max(defaultHeight, actualHeight) : maxHeight);
315 UpdateHeightIfMatchPolicy(layoutPolicy, frameSize, matchParentHeight);
316 }
317 }
318 // Determine if the button needs to fit the font size.
319 if (buttonLayoutProperty->HasFontSize()) {
320 if (GreatOrEqual(childSize_.Height() + topPadding + bottomPadding, frameSize.Height())) {
321 frameSize = SizeF(frameSize.Width(), childSize_.Height() + topPadding + bottomPadding);
322 }
323 }
324 layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize);
325 }
326 HandleBorderRadius(layoutWrapper);
327 }
328
HandleLabelCircleButtonFrameSize(const LayoutConstraintF & layoutConstraint,SizeF & frameSize,const float & defaultHeight)329 void ButtonLayoutAlgorithm::HandleLabelCircleButtonFrameSize(
330 const LayoutConstraintF& layoutConstraint, SizeF& frameSize, const float& defaultHeight)
331 {
332 float minLength = 0.0f;
333 if (layoutConstraint.parentIdealSize.IsNull()) {
334 minLength = static_cast<float>(defaultHeight);
335 } else if (layoutConstraint.parentIdealSize.Width().has_value() &&
336 !layoutConstraint.parentIdealSize.Height().has_value()) {
337 minLength = frameSize.Width();
338 } else if (layoutConstraint.parentIdealSize.Height().has_value() &&
339 !layoutConstraint.parentIdealSize.Width().has_value()) {
340 minLength = frameSize.Height();
341 } else {
342 minLength = std::min(frameSize.Width(), frameSize.Height());
343 }
344 frameSize.SetWidth(minLength);
345 frameSize.SetHeight(minLength);
346 }
347
MeasureCircleButton(LayoutWrapper * layoutWrapper)348 void ButtonLayoutAlgorithm::MeasureCircleButton(LayoutWrapper* layoutWrapper)
349 {
350 auto frameNode = layoutWrapper->GetHostNode();
351 CHECK_NULL_VOID(frameNode);
352 auto context = frameNode->GetRenderContext();
353 CHECK_NULL_VOID(context);
354 const auto& radius = context->GetBorderRadius();
355 SizeF frameSize = { -1, -1 };
356 if (radius.has_value()) {
357 auto radiusTopMax = std::max(radius->radiusTopLeft, radius->radiusTopRight);
358 auto radiusBottomMax = std::max(radius->radiusBottomLeft, radius->radiusBottomRight);
359 auto radiusMax = std::max(radiusTopMax, radiusBottomMax);
360 auto rrectRadius = radiusMax.value_or(0.0_vp).ConvertToPx();
361 frameSize.SetSizeT(SizeF { static_cast<float>(rrectRadius * 2), static_cast<float>(rrectRadius * 2) });
362 }
363 frameSize.UpdateIllegalSizeWithCheck(SizeF { 0.0f, 0.0f });
364 layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize);
365 }
366
GetFirstValidRadius(const BorderRadiusProperty & borderRadius)367 Dimension ButtonLayoutAlgorithm::GetFirstValidRadius(const BorderRadiusProperty& borderRadius)
368 {
369 if (borderRadius.radiusTopLeft.has_value()) {
370 return borderRadius.radiusTopLeft.value();
371 }
372 if (borderRadius.radiusTopRight.has_value()) {
373 return borderRadius.radiusTopRight.value();
374 }
375 if (borderRadius.radiusBottomLeft.has_value()) {
376 return borderRadius.radiusBottomLeft.value();
377 }
378 if (borderRadius.radiusBottomRight.has_value()) {
379 return borderRadius.radiusBottomRight.value();
380 }
381 return 0.0_vp;
382 }
383
GetDefaultHeight(LayoutWrapper * layoutWrapper)384 float ButtonLayoutAlgorithm::GetDefaultHeight(LayoutWrapper* layoutWrapper)
385 {
386 auto layoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
387 CHECK_NULL_RETURN(layoutProperty, 0.0);
388 auto frameNode = layoutWrapper->GetHostNode();
389 CHECK_NULL_RETURN(frameNode, 0.0);
390 auto* context = frameNode->GetContext();
391 CHECK_NULL_RETURN(context, 0.0);
392 auto buttonTheme = context->GetTheme<ButtonTheme>();
393 CHECK_NULL_RETURN(buttonTheme, 0.0);
394 if (frameNode->GetTag() == V2::TOGGLE_ETS_TAG) {
395 auto toggleTheme = context->GetTheme<ToggleTheme>();
396 CHECK_NULL_RETURN(toggleTheme, 0.0);
397 return static_cast<float>(toggleTheme->GetButtonHeight().ConvertToPx());
398 }
399 ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
400 return static_cast<float>(buttonTheme->GetHeight(controlSize).ConvertToPx());
401 }
402
GetDefaultBorderRadius(LayoutWrapper * layoutWrapper)403 float ButtonLayoutAlgorithm::GetDefaultBorderRadius(LayoutWrapper* layoutWrapper)
404 {
405 auto layoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
406 CHECK_NULL_RETURN(layoutProperty, 0.0f);
407 auto frameNode = layoutWrapper->GetHostNode();
408 CHECK_NULL_RETURN(frameNode, 0.0f);
409 auto* context = frameNode->GetContext();
410 CHECK_NULL_RETURN(context, 0.0f);
411 auto buttonTheme = context->GetTheme<ButtonTheme>();
412 CHECK_NULL_RETURN(buttonTheme, 0.0f);
413 ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
414 return static_cast<float>(buttonTheme->GetBorderRadius(controlSize).ConvertToPx());
415 }
416
NeedAgingMeasure(LayoutWrapper * layoutWrapper)417 bool ButtonLayoutAlgorithm::NeedAgingMeasure(LayoutWrapper* layoutWrapper)
418 {
419 if (!IsAging(layoutWrapper)) {
420 return false;
421 }
422 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
423 CHECK_NULL_RETURN(buttonLayoutProperty, false);
424 auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
425 CHECK_NULL_RETURN(pipeline, false);
426 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
427 float agingPadding = buttonTheme->GetAgingNormalPadding().ConvertToPx() * 2.0f;
428 if (buttonLayoutProperty->HasControlSize() && buttonLayoutProperty->GetControlSize() == ControlSize::SMALL) {
429 agingPadding = buttonTheme->GetAgingSmallPadding().ConvertToPx() * 2.0f;
430 }
431 auto host = layoutWrapper->GetHostNode();
432 CHECK_NULL_RETURN(host, false);
433 auto pattern = host->GetPattern<ButtonPattern>();
434 CHECK_NULL_RETURN(pattern, false);
435 if (!pattern->GetHasCustomPadding()) {
436 auto geometryNode = layoutWrapper->GetGeometryNode();
437 CHECK_NULL_RETURN(geometryNode, false);
438 auto frameSize = geometryNode->GetFrameSize();
439 if (buttonLayoutProperty->HasLabel()) {
440 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
441 CHECK_NULL_RETURN(childWrapper, false);
442 auto childGeometryNode = childWrapper->GetGeometryNode();
443 CHECK_NULL_RETURN(childGeometryNode, false);
444 auto childFrameSize = childGeometryNode->GetContentSize();
445 frameSize.SetHeight(childFrameSize.Height() + agingPadding);
446 } else {
447 frameSize.SetHeight(frameSize.Height() + agingPadding);
448 }
449 auto layoutContraint = buttonLayoutProperty->GetLayoutConstraint();
450 CHECK_NULL_RETURN(layoutContraint, false);
451 auto maxHeight = layoutContraint->maxSize.Height();
452 auto minHeight = layoutContraint->minSize.Height();
453 auto actualHeight = frameSize.Height();
454 actualHeight = std::min(actualHeight, maxHeight);
455 actualHeight = std::max(actualHeight, minHeight);
456 frameSize.SetHeight(actualHeight);
457 geometryNode->SetFrameSize(frameSize);
458 }
459 HandleBorderRadius(layoutWrapper);
460 return true;
461 }
462
IsAging(LayoutWrapper * layoutWrapper)463 bool ButtonLayoutAlgorithm::IsAging(LayoutWrapper* layoutWrapper)
464 {
465 auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
466 CHECK_NULL_RETURN(buttonLayoutProperty, false);
467
468 if (buttonLayoutProperty->HasType() && buttonLayoutProperty->GetType() == ButtonType::CIRCLE) {
469 return false;
470 }
471
472 if (buttonLayoutProperty->HasLabel() && buttonLayoutProperty->GetLabel()->empty()) {
473 return false;
474 }
475
476 if (buttonLayoutProperty->HasFontSize() && buttonLayoutProperty->GetFontSize()->Unit() != DimensionUnit::FP) {
477 return false;
478 }
479 const auto& calcConstraint = buttonLayoutProperty->GetCalcLayoutConstraint();
480 if (calcConstraint && calcConstraint->selfIdealSize->Height().has_value() &&
481 calcConstraint->selfIdealSize->Width().has_value()) {
482 return false;
483 }
484 auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
485 CHECK_NULL_RETURN(pipeline, false);
486 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
487 CHECK_NULL_RETURN(buttonTheme, false);
488 auto fontScale = pipeline->GetFontScale();
489 if (!(NearEqual(fontScale, buttonTheme->GetBigFontSizeScale()) ||
490 NearEqual(fontScale, buttonTheme->GetLargeFontSizeScale()) ||
491 NearEqual(fontScale, buttonTheme->GetMaxFontSizeScale()))) {
492 return false;
493 }
494 return true;
495 }
496 } // namespace OHOS::Ace::NG
497