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/search/search_layout_algorithm.h"
17
18 #include <algorithm>
19
20 #include "base/utils/utils.h"
21 #include "core/components/search/search_theme.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/layout/layout_algorithm.h"
24 #include "core/components_ng/pattern/button/button_layout_property.h"
25 #include "core/components_ng/pattern/button/button_pattern.h"
26 #include "core/components_ng/pattern/image/image_layout_property.h"
27 #include "core/components_ng/pattern/image/image_pattern.h"
28 #include "core/components_ng/pattern/search/search_layout_property.h"
29 #include "core/components_ng/pattern/text/text_layout_property.h"
30 #include "core/components_ng/pattern/text_field/text_field_layout_algorithm.h"
31 #include "core/components_ng/property/layout_constraint.h"
32 #include "core/components_ng/property/measure_utils.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34
35 namespace OHOS::Ace::NG {
36 namespace {
37 constexpr int32_t TEXTFIELD_INDEX = 0;
38 constexpr int32_t IMAGE_INDEX = 1;
39 constexpr int32_t CANCEL_IMAGE_INDEX = 2;
40 constexpr int32_t CANCEL_BUTTON_INDEX = 3;
41 constexpr int32_t BUTTON_INDEX = 4;
42 constexpr int32_t MULTIPLE_2 = 2;
43 constexpr float MAX_SEARCH_BUTTON_RATE = 0.4f;
44 } // namespace
45
IsFixedHeightMode(LayoutWrapper * layoutWrapper)46 bool SearchLayoutAlgorithm::IsFixedHeightMode(LayoutWrapper* layoutWrapper)
47 {
48 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
49 CHECK_NULL_RETURN(layoutProperty, false);
50
51 auto constraint = layoutProperty->GetLayoutConstraint();
52 return constraint->selfIdealSize.Height().has_value();
53 }
54
CancelImageMeasure(LayoutWrapper * layoutWrapper)55 void SearchLayoutAlgorithm::CancelImageMeasure(LayoutWrapper* layoutWrapper)
56 {
57 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
58 CHECK_NULL_VOID(layoutProperty);
59 auto cancelImageWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_IMAGE_INDEX);
60 CHECK_NULL_VOID(cancelImageWrapper);
61 auto cancelImageGeometryNode = cancelImageWrapper->GetGeometryNode();
62 CHECK_NULL_VOID(cancelImageGeometryNode);
63 auto imageLayoutProperty = cancelImageWrapper->GetLayoutProperty();
64 CHECK_NULL_VOID(imageLayoutProperty);
65 auto pipeline = PipelineBase::GetCurrentContext();
66 CHECK_NULL_VOID(pipeline);
67 auto searchTheme = pipeline->GetTheme<SearchTheme>();
68 CHECK_NULL_VOID(searchTheme);
69 auto constraint = layoutProperty->GetLayoutConstraint();
70 auto imageConstraint = imageLayoutProperty->GetLayoutConstraint();
71 auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
72 auto defaultImageHeight =
73 imageConstraint->selfIdealSize.Height().value_or(searchTheme->GetIconSize().ConvertToPx());
74 auto iconStretchSize = (NearZero(defaultImageHeight) || !imageConstraint->maxSize.IsPositive()) &&
75 !layoutProperty->HasCancelButtonUDSize();
76 auto imageHeight =
77 std::min(iconStretchSize ? static_cast<float>(searchTheme->GetIconSize().ConvertToPx()) : defaultImageHeight,
78 static_cast<float>(searchHeight));
79 CalcSize imageCalcSize;
80 if (iconStretchSize) {
81 imageCalcSize.SetWidth(CalcLength(imageHeight));
82 }
83 imageCalcSize.SetHeight(CalcLength(imageHeight));
84 imageLayoutProperty->UpdateUserDefinedIdealSize(imageCalcSize);
85 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
86 cancelImageWrapper->Measure(childLayoutConstraint);
87 cancelIconSizeMeasure_ = cancelImageGeometryNode->GetFrameSize();
88 }
89
CancelButtonMeasure(LayoutWrapper * layoutWrapper)90 void SearchLayoutAlgorithm::CancelButtonMeasure(LayoutWrapper* layoutWrapper)
91 {
92 auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
93 CHECK_NULL_VOID(cancelButtonWrapper);
94 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
95 CHECK_NULL_VOID(layoutProperty);
96 auto cancelButtonLayoutProperty =
97 AceType::DynamicCast<ButtonLayoutProperty>(cancelButtonWrapper->GetLayoutProperty());
98 CHECK_NULL_VOID(cancelButtonLayoutProperty);
99 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
100 CHECK_NULL_VOID(cancelButtonGeometryNode);
101 auto pipeline = PipelineBase::GetCurrentContext();
102 CHECK_NULL_VOID(pipeline);
103 auto searchTheme = pipeline->GetTheme<SearchTheme>();
104 CHECK_NULL_VOID(searchTheme);
105
106 // calculate theme space from cancel button to cancel image
107 auto spaceHeight = searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx() -
108 searchTheme->GetIconHeight().ConvertToPx();
109
110 // calculate cancel button height
111 auto cancelButtonHeight =
112 layoutProperty->GetCancelButtonUDSizeValue(Dimension(cancelIconSizeMeasure_.Height())).ConvertToPx() +
113 spaceHeight;
114 CalcSize cancelButtonCalcSize((CalcLength(cancelButtonHeight)), CalcLength(cancelButtonHeight));
115 cancelButtonLayoutProperty->UpdateUserDefinedIdealSize(cancelButtonCalcSize);
116
117 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
118 cancelButtonWrapper->Measure(childLayoutConstraint);
119 cancelBtnSizeMeasure_ = cancelButtonGeometryNode->GetFrameSize();
120 }
121
TextFieldMeasure(LayoutWrapper * layoutWrapper)122 void SearchLayoutAlgorithm::TextFieldMeasure(LayoutWrapper* layoutWrapper)
123 {
124 auto pipeline = PipelineBase::GetCurrentContext();
125 CHECK_NULL_VOID(pipeline);
126 auto searchTheme = pipeline->GetTheme<SearchTheme>();
127 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
128 CHECK_NULL_VOID(layoutProperty);
129 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
130 CHECK_NULL_VOID(textFieldWrapper);
131 auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
132 CHECK_NULL_VOID(cancelButtonWrapper);
133 auto textFieldGeometryNode = textFieldWrapper->GetGeometryNode();
134 CHECK_NULL_VOID(textFieldGeometryNode);
135
136 auto buttonWidth = searchButtonSizeMeasure_.Width();
137 auto cancelButtonWidth = cancelBtnSizeMeasure_.Width();
138 auto iconRenderWidth =
139 layoutProperty->GetSearchIconUDSizeValue(Dimension(searchIconSizeMeasure_.Width())).ConvertToPx();
140 auto constraint = layoutProperty->GetLayoutConstraint();
141 auto searchWidthMax = CalcSearchWidth(constraint.value(), layoutWrapper);
142
143 auto searchWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
144 auto searchButtonNode = searchWrapper->GetHostNode();
145 auto searchButtonEvent = searchButtonNode->GetEventHub<ButtonEventHub>();
146 auto padding = layoutProperty->CreatePaddingAndBorder();
147 float leftPadding = padding.left.value_or(0.0f);
148 float rightPadding = padding.right.value_or(0.0f);
149 auto textFieldWidth = searchWidthMax - searchTheme->GetSearchIconLeftSpace().ConvertToPx() - iconRenderWidth -
150 searchTheme->GetSearchIconRightSpace().ConvertToPx() - leftPadding - rightPadding;
151 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
152 textFieldWidth = searchWidthMax - searchTheme->GetSearchIconLeftSpace().ConvertToPx() - iconRenderWidth -
153 searchTheme->GetSearchIconRightSpace().ConvertToPx();
154 }
155 if (searchButtonEvent->IsEnabled()) {
156 textFieldWidth = textFieldWidth - buttonWidth - searchTheme->GetSearchDividerWidth().ConvertToPx() -
157 MULTIPLE_2 * searchTheme->GetDividerSideSpace().ConvertToPx();
158 }
159
160 auto style = layoutProperty->GetCancelButtonStyle().value_or(CancelButtonStyle::INPUT);
161 if (style != CancelButtonStyle::INVISIBLE) {
162 textFieldWidth = textFieldWidth - cancelButtonWidth;
163 }
164 auto themeHeight = searchTheme->GetHeight().ConvertToPx();
165 auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
166 auto textFieldHeight = std::min(themeHeight, searchHeight - 0.0f);
167 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
168 childLayoutConstraint.selfIdealSize.SetWidth(textFieldWidth);
169 childLayoutConstraint.selfIdealSize.SetHeight(textFieldHeight);
170 textFieldWrapper->Measure(childLayoutConstraint);
171 textFieldSizeMeasure_ = textFieldGeometryNode->GetFrameSize();
172 }
173
ImageMeasure(LayoutWrapper * layoutWrapper)174 void SearchLayoutAlgorithm::ImageMeasure(LayoutWrapper* layoutWrapper)
175 {
176 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
177 CHECK_NULL_VOID(layoutProperty);
178 auto imageWrapper = layoutWrapper->GetOrCreateChildByIndex(IMAGE_INDEX);
179 CHECK_NULL_VOID(imageWrapper);
180 auto imageGeometryNode = imageWrapper->GetGeometryNode();
181 CHECK_NULL_VOID(imageGeometryNode);
182 auto imageLayoutProperty = imageWrapper->GetLayoutProperty();
183 CHECK_NULL_VOID(imageLayoutProperty);
184 auto pipeline = PipelineBase::GetCurrentContext();
185 CHECK_NULL_VOID(pipeline);
186 auto searchTheme = pipeline->GetTheme<SearchTheme>();
187 CHECK_NULL_VOID(searchTheme);
188 auto constraint = layoutProperty->GetLayoutConstraint();
189 auto imageConstraint = imageLayoutProperty->GetLayoutConstraint();
190 auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
191 auto defaultImageHeight = searchTheme->GetIconSize().ConvertToPx();
192 auto iconStretchSize = (NearZero(defaultImageHeight) || !imageConstraint->maxSize.IsPositive()) &&
193 !layoutProperty->HasSearchIconUDSize();
194 auto imageHeight = static_cast<float>(std::min(layoutProperty->HasSearchIconUDSize() ?
195 layoutProperty->GetSearchIconUDSizeValue().ConvertToPx() : defaultImageHeight,
196 searchHeight));
197 CalcSize imageCalcSize;
198 if (iconStretchSize) {
199 imageCalcSize.SetWidth(CalcLength(imageHeight));
200 }
201 imageCalcSize.SetHeight(CalcLength(imageHeight));
202 imageLayoutProperty->UpdateUserDefinedIdealSize(imageCalcSize);
203
204 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
205 imageWrapper->Measure(childLayoutConstraint);
206 searchIconSizeMeasure_ = imageGeometryNode->GetFrameSize();
207 }
208
SearchButtonMeasure(LayoutWrapper * layoutWrapper)209 void SearchLayoutAlgorithm::SearchButtonMeasure(LayoutWrapper* layoutWrapper)
210 {
211 auto buttonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
212 CHECK_NULL_VOID(buttonWrapper);
213 auto buttonLayoutProperty = AceType::DynamicCast<ButtonLayoutProperty>(buttonWrapper->GetLayoutProperty());
214 CHECK_NULL_VOID(buttonLayoutProperty);
215 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
216 CHECK_NULL_VOID(layoutProperty);
217 auto buttonGeometryNode = buttonWrapper->GetGeometryNode();
218 CHECK_NULL_VOID(buttonGeometryNode);
219 auto pipeline = PipelineBase::GetCurrentContext();
220 CHECK_NULL_VOID(pipeline);
221 auto searchTheme = pipeline->GetTheme<SearchTheme>();
222 CHECK_NULL_VOID(searchTheme);
223
224 // calculate theme space from search button to font
225 auto spaceHeight = searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx() -
226 searchTheme->GetFontSize().ConvertToPx();
227
228 // calculate search button height
229 auto defaultButtonHeight =
230 searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx();
231 auto searchButtonHeight = std::max(defaultButtonHeight,
232 layoutProperty->GetSearchButtonFontSizeValue(searchTheme->GetFontSize()).ConvertToPx() + spaceHeight);
233 auto constraint = layoutProperty->GetLayoutConstraint();
234 auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
235 searchButtonHeight = std::min(searchButtonHeight, searchHeight - 0.0f);
236 CalcSize searchButtonCalcSize;
237 searchButtonCalcSize.SetHeight(CalcLength(searchButtonHeight));
238 buttonLayoutProperty->UpdateUserDefinedIdealSize(searchButtonCalcSize);
239
240 // searchButton Measure
241 auto buttonLayoutConstraint = layoutProperty->CreateChildConstraint();
242 buttonWrapper->Measure(buttonLayoutConstraint);
243
244 // deal with pixel round
245 auto pixelRound = static_cast<uint8_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
246 static_cast<uint8_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM) |
247 static_cast<uint8_t>(PixelRoundPolicy::FORCE_CEIL_END) |
248 static_cast<uint8_t>(PixelRoundPolicy::FORCE_CEIL_START);
249 buttonLayoutProperty->UpdatePixelRound(pixelRound);
250
251 // compute searchButton width
252 auto searchWidthMax = CalcSearchWidth(constraint.value(), layoutWrapper);
253 double searchButtonWidth = searchWidthMax * MAX_SEARCH_BUTTON_RATE;
254 double curSearchButtonWidth = buttonGeometryNode->GetFrameSize().Width();
255 searchButtonWidth = std::min(searchButtonWidth, curSearchButtonWidth);
256 buttonLayoutConstraint.selfIdealSize.SetWidth(searchButtonWidth);
257 buttonWrapper->Measure(buttonLayoutConstraint);
258 searchButtonSizeMeasure_ = buttonGeometryNode->GetFrameSize();
259 }
260
CalcSearchAdaptHeight(LayoutWrapper * layoutWrapper)261 double SearchLayoutAlgorithm::CalcSearchAdaptHeight(LayoutWrapper* layoutWrapper)
262 {
263 double searchHeightAdapt = 0;
264 auto pipeline = PipelineBase::GetCurrentContext();
265 CHECK_NULL_RETURN(pipeline, 0);
266 auto searchTheme = pipeline->GetTheme<SearchTheme>();
267 CHECK_NULL_RETURN(searchTheme, 0);
268 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
269 CHECK_NULL_RETURN(layoutProperty, 0);
270 auto searchBtnWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
271 CHECK_NULL_RETURN(searchBtnWrapper, 0);
272 auto cancelBtnLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
273 CHECK_NULL_RETURN(cancelBtnLayoutWrapper, 0);
274
275 // search button height
276 auto buttonNode = searchBtnWrapper->GetHostNode();
277 CHECK_NULL_RETURN(buttonNode, true);
278 auto searchButtonEvent = buttonNode->GetEventHub<ButtonEventHub>();
279 CHECK_NULL_RETURN(searchButtonEvent, true);
280 auto searchButtonHeight = searchButtonSizeMeasure_.Height() + 2 * searchTheme->GetSearchButtonSpace().ConvertToPx();
281 searchButtonHeight = (!searchButtonEvent->IsEnabled()) ? 0.0f : searchButtonHeight;
282
283 // search icon height
284 auto searchIconFrameHight = searchIconSizeMeasure_.Height();
285 auto searchIconHeight = layoutProperty->GetSearchIconUDSizeValue(Dimension(searchIconFrameHight)).ConvertToPx();
286 searchIconHeight += searchTheme->GetHeight().ConvertToPx() - searchTheme->GetIconHeight().ConvertToPx();
287
288 // cancel button height
289 auto cancelButtonNode = cancelBtnLayoutWrapper->GetHostNode();
290 CHECK_NULL_RETURN(cancelButtonNode, 0);
291 auto cancelButtonEvent = cancelButtonNode->GetEventHub<ButtonEventHub>();
292 CHECK_NULL_RETURN(cancelButtonEvent, 0);
293 auto cancelBtnHight = cancelBtnSizeMeasure_.Height() + 2 * searchTheme->GetSearchButtonSpace().ConvertToPx();
294 cancelBtnHight = (!cancelButtonEvent->IsEnabled()) ? 0.0f : cancelBtnHight;
295
296 // textfield height
297 auto padding = layoutProperty->CreatePaddingAndBorder();
298 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
299 auto textfieldHeight = textFieldSizeMeasure_.Height() + verticalPadding;
300
301 // calculate the highest
302 searchHeightAdapt = std::max(searchIconHeight, searchButtonHeight);
303 searchHeightAdapt = std::max(searchHeightAdapt, cancelBtnHight);
304 searchHeightAdapt = std::max(searchHeightAdapt, static_cast<double>(textfieldHeight));
305
306 return searchHeightAdapt;
307 }
308
SelfMeasure(LayoutWrapper * layoutWrapper)309 void SearchLayoutAlgorithm::SelfMeasure(LayoutWrapper* layoutWrapper)
310 {
311 auto geometryNode = layoutWrapper->GetGeometryNode();
312 CHECK_NULL_VOID(geometryNode);
313 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
314 CHECK_NULL_VOID(layoutProperty);
315 auto constraint = layoutProperty->GetLayoutConstraint();
316 auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
317 // update search height
318 constraint->selfIdealSize.SetHeight(searchHeight);
319 auto searchWidth = CalcSearchWidth(constraint.value(), layoutWrapper);
320 SizeF idealSize(searchWidth, searchHeight);
321 if (GreaterOrEqualToInfinity(idealSize.Width()) || GreaterOrEqualToInfinity(idealSize.Height())) {
322 geometryNode->SetFrameSize(SizeF());
323 return;
324 }
325
326 // update search height
327 geometryNode->SetFrameSize(idealSize);
328 geometryNode->SetContentSize(idealSize);
329 }
330
CalcSearchWidth(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)331 double SearchLayoutAlgorithm::CalcSearchWidth(
332 const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
333 {
334 auto searchConstraint = contentConstraint;
335 auto idealWidth = contentConstraint.selfIdealSize.Width().value_or(contentConstraint.maxSize.Width());
336 auto idealHeight = contentConstraint.selfIdealSize.Height().value_or(contentConstraint.maxSize.Height());
337 auto maxIdealSize = SizeF { idealWidth, idealHeight };
338 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
339 auto frameIdealSize = maxIdealSize;
340 auto finalSize = UpdateOptionSizeByCalcLayoutConstraint(static_cast<OptionalSize<float>>(frameIdealSize),
341 layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint(),
342 layoutWrapper->GetLayoutProperty()->GetLayoutConstraint()->percentReference);
343 finalSize.SetWidth(finalSize.Width().value_or(frameIdealSize.Width()));
344 finalSize.SetHeight(finalSize.Height().value_or(frameIdealSize.Height()));
345 maxIdealSize.UpdateSizeWhenSmaller(finalSize.ConvertToSizeT());
346 }
347 searchConstraint.maxSize = maxIdealSize;
348 auto searchWidth = (searchConstraint.selfIdealSize.Width().has_value())
349 ? std::min(searchConstraint.selfIdealSize.Width().value(), searchConstraint.maxSize.Width())
350 : std::min(searchConstraint.percentReference.Width(), searchConstraint.maxSize.Width());
351
352 const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
353 CHECK_NULL_RETURN(calcLayoutConstraint, searchWidth);
354 auto hasMinSize = calcLayoutConstraint->minSize->Width().has_value();
355 auto hasMaxSize = calcLayoutConstraint->maxSize->Width().has_value();
356 auto hasWidth = calcLayoutConstraint->selfIdealSize->Width().has_value();
357 if (hasMinSize && ((hasMaxSize && searchConstraint.minSize.Width() >= searchConstraint.maxSize.Width())
358 || (!hasMaxSize && !hasWidth))) {
359 return searchConstraint.minSize.Width();
360 }
361 if (hasMinSize) {
362 searchWidth = std::max(searchConstraint.minSize.Width(), static_cast<float>(searchWidth));
363 }
364 if (hasMaxSize) {
365 searchWidth = std::min(searchConstraint.maxSize.Width(), static_cast<float>(searchWidth));
366 }
367 return searchWidth;
368 }
369
CalcSearchHeight(const LayoutConstraintF & constraint,LayoutWrapper * layoutWrapper)370 double SearchLayoutAlgorithm::CalcSearchHeight(
371 const LayoutConstraintF& constraint, LayoutWrapper* layoutWrapper)
372 {
373 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
374 CHECK_NULL_RETURN(layoutProperty, 0.0);
375 auto host = layoutWrapper->GetHostNode();
376 CHECK_NULL_RETURN(host, 0.0);
377 auto pipeline = PipelineBase::GetCurrentContext();
378 CHECK_NULL_RETURN(pipeline, 0.0);
379 auto renderContext = host->GetRenderContext();
380 CHECK_NULL_RETURN(renderContext, 0.0);
381 auto searchTheme = pipeline->GetTheme<SearchTheme>();
382 CHECK_NULL_RETURN(searchTheme, 0.0);
383 auto themeHeight = searchTheme->GetHeight().ConvertToPx();
384 auto searchHeight =
385 (constraint.selfIdealSize.Height().has_value()) ? constraint.selfIdealSize.Height().value() : themeHeight;
386 auto padding = layoutProperty->CreatePaddingAndBorder();
387 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
388 searchHeight = std::max(verticalPadding, static_cast<float>(searchHeight));
389 auto searchHeightAdapt = searchHeight;
390 if (!IsFixedHeightMode(layoutWrapper)) {
391 searchHeightAdapt = std::max(searchHeightAdapt, CalcSearchAdaptHeight(layoutWrapper));
392 renderContext->SetClipToBounds(false);
393 } else {
394 renderContext->SetClipToBounds(true);
395 }
396
397 const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
398 CHECK_NULL_RETURN(calcLayoutConstraint, searchHeightAdapt);
399 auto hasMinSize = calcLayoutConstraint->minSize.has_value() &&
400 calcLayoutConstraint->minSize->Height().has_value();
401 auto hasMaxSize = calcLayoutConstraint->maxSize.has_value() &&
402 calcLayoutConstraint->maxSize->Height().has_value();
403 auto hasHeight = calcLayoutConstraint->selfIdealSize.has_value() &&
404 calcLayoutConstraint->selfIdealSize->Height().has_value();
405 if (hasMinSize && ((hasMaxSize && constraint.minSize.Height() >= constraint.maxSize.Height())
406 || (!hasMaxSize && !hasHeight))) {
407 return constraint.minSize.Height();
408 }
409 if (hasMinSize) {
410 searchHeightAdapt = std::max(constraint.minSize.Height(),
411 static_cast<float>(searchHeightAdapt));
412 }
413 if (hasMaxSize) {
414 searchHeightAdapt = std::min(constraint.maxSize.Height(),
415 static_cast<float>(searchHeightAdapt));
416 }
417 return searchHeightAdapt;
418 }
419
Measure(LayoutWrapper * layoutWrapper)420 void SearchLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
421 {
422 auto host = layoutWrapper->GetHostNode();
423 CHECK_NULL_VOID(host);
424 auto children = host->GetChildren();
425 if (children.empty()) {
426 return;
427 }
428
429 SearchButtonMeasure(layoutWrapper);
430 ImageMeasure(layoutWrapper);
431 CancelImageMeasure(layoutWrapper);
432 CancelButtonMeasure(layoutWrapper);
433 TextFieldMeasure(layoutWrapper);
434 SelfMeasure(layoutWrapper);
435 }
436
CalcChildrenHotZone(LayoutWrapper * layoutWrapper)437 void SearchLayoutAlgorithm::CalcChildrenHotZone(LayoutWrapper* layoutWrapper)
438 {
439 // search info
440 auto searchGeometryNode = layoutWrapper->GetGeometryNode();
441 CHECK_NULL_VOID(searchGeometryNode);
442 auto searchHeight = searchGeometryNode->GetFrameSize().Height();
443
444 // cancel button info
445 auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
446 CHECK_NULL_VOID(cancelButtonWrapper);
447 auto cancelButtonFrameNode = cancelButtonWrapper->GetHostNode();
448 CHECK_NULL_VOID(cancelButtonFrameNode);
449 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
450 CHECK_NULL_VOID(cancelButtonGeometryNode);
451 auto cancelButtonFrameSize = cancelButtonGeometryNode->GetFrameSize();
452 auto cancelButtonWidth = cancelButtonFrameSize.Width();
453 auto cancelButtonHeight = cancelButtonFrameSize.Height();
454
455 // search button info
456 auto searchButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
457 CHECK_NULL_VOID(searchButtonWrapper);
458 auto searchButtonFrameNode = searchButtonWrapper->GetHostNode();
459 CHECK_NULL_VOID(searchButtonFrameNode);
460 auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
461 CHECK_NULL_VOID(searchButtonGeometryNode);
462 auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
463 auto searchButtonWidth = searchButtonFrameSize.Width();
464 auto searchButtonHeight = searchButtonFrameSize.Height();
465
466 auto pipeline = PipelineBase::GetCurrentContext();
467 CHECK_NULL_VOID(pipeline);
468 auto searchTheme = pipeline->GetTheme<SearchTheme>();
469 auto buttonSpace = searchTheme->GetSearchButtonSpace().ConvertToPx();
470 // calculate cancel button hot zone
471 cancelButtonFrameNode->RemoveLastHotZoneRect();
472 DimensionRect cancelButtonHotZone;
473 if (cancelButtonHeight > searchHeight) {
474 cancelButtonHotZone.SetSize(DimensionSize(Dimension(cancelButtonWidth), Dimension(searchHeight)));
475 double hotZoneOffsetY = (cancelButtonHeight - searchHeight) / 2;
476 cancelButtonHotZone.SetOffset(DimensionOffset(Dimension(0), Dimension(hotZoneOffsetY)));
477 } else {
478 cancelButtonHotZone.SetSize(DimensionSize(
479 Dimension(cancelButtonWidth + 2 * buttonSpace), Dimension(cancelButtonHeight + 2 * buttonSpace)));
480 cancelButtonHotZone.SetOffset(
481 DimensionOffset(Offset(static_cast<float>(-buttonSpace), static_cast<float>(-buttonSpace))));
482 }
483 cancelButtonFrameNode->AddHotZoneRect(cancelButtonHotZone);
484
485 // calculate search button hot zone
486 searchButtonFrameNode->RemoveLastHotZoneRect();
487 DimensionRect searchButtonHotZone;
488 if (searchButtonHeight > searchHeight) {
489 searchButtonHotZone.SetSize(DimensionSize(Dimension(searchButtonWidth), Dimension(searchHeight)));
490 double hotZoneOffsetY = (searchButtonHeight - searchHeight) / 2;
491 searchButtonHotZone.SetOffset(DimensionOffset(Dimension(0), Dimension(hotZoneOffsetY)));
492 } else {
493 searchButtonHotZone.SetSize(DimensionSize(
494 Dimension(searchButtonWidth + 2 * buttonSpace), Dimension(searchButtonHeight + 2 * buttonSpace)));
495 searchButtonHotZone.SetOffset(
496 DimensionOffset(Offset(static_cast<float>(-buttonSpace), static_cast<float>(-buttonSpace))));
497 }
498 searchButtonFrameNode->AddHotZoneRect(searchButtonHotZone);
499 }
500
Layout(LayoutWrapper * layoutWrapper)501 void SearchLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
502 {
503 auto host = layoutWrapper->GetHostNode();
504 CHECK_NULL_VOID(host);
505 auto children = host->GetChildren();
506 if (children.empty()) {
507 return;
508 }
509
510 auto layoutProperty = DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
511 CHECK_NULL_VOID(layoutProperty);
512
513 // search theme
514 auto pipeline = PipelineBase::GetCurrentContext();
515 CHECK_NULL_VOID(pipeline);
516 auto searchTheme = pipeline->GetTheme<SearchTheme>();
517 auto searchIconLeftSpace = searchTheme->GetSearchIconLeftSpace().ConvertToPx();
518 auto searchIconRightSpace = searchTheme->GetSearchIconRightSpace().ConvertToPx();
519 auto searchButtonSpace = searchTheme->GetSearchButtonSpace().ConvertToPx();
520 auto dividerSideSpace = searchTheme->GetDividerSideSpace().ConvertToPx();
521 auto dividerWidth = searchTheme->GetSearchDividerWidth().ConvertToPx();
522
523 // search size
524 auto geometryNode = layoutWrapper->GetGeometryNode();
525 CHECK_NULL_VOID(geometryNode);
526 auto searchSize = geometryNode->GetFrameSize();
527 auto searchFrameWidth = searchSize.Width();
528 auto searchFrameHeight = searchSize.Height();
529
530 // search icon size
531 auto imageWrapper = layoutWrapper->GetOrCreateChildByIndex(IMAGE_INDEX);
532 CHECK_NULL_VOID(imageWrapper);
533 auto imageGeometryNode = imageWrapper->GetGeometryNode();
534 CHECK_NULL_VOID(imageGeometryNode);
535 auto iconFrameWidth = searchIconSizeMeasure_.Width();
536 auto iconFrameHeight = searchIconSizeMeasure_.Height();
537 auto iconRenderWidth = layoutProperty->GetSearchIconUDSizeValue(Dimension(iconFrameWidth)).ConvertToPx();
538
539 // layout search icon
540 auto padding = layoutProperty->CreatePaddingAndBorder();
541 float topPadding = padding.top.value_or(0.0f);
542 float bottomPadding = padding.bottom.value_or(0.0f);
543 float leftOffset = padding.left.value_or(0.0f);
544 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
545 leftOffset = 0.0f;
546 }
547 float iconHorizontalOffset = leftOffset + searchIconLeftSpace + (iconRenderWidth - iconFrameWidth) / 2;
548 auto searchIconConstraint = imageWrapper->GetLayoutProperty()->GetLayoutConstraint();
549 auto iconUserHeight =
550 searchIconConstraint->selfIdealSize.Height().value_or(searchTheme->GetIconHeight().ConvertToPx());
551 float imageVerticalOffset = topPadding;
552 if (NearEqual(iconUserHeight, iconFrameHeight)) {
553 auto iconInterval = (searchFrameHeight - iconUserHeight) / 2;
554 if (topPadding <= iconInterval && bottomPadding <= iconInterval) {
555 imageVerticalOffset = iconInterval;
556 } else if (topPadding <= iconInterval && bottomPadding > iconInterval) {
557 imageVerticalOffset = searchFrameHeight - (bottomPadding + iconFrameHeight);
558 }
559 }
560 auto centerVerticalOffset = imageVerticalOffset + iconFrameHeight / 2;
561 OffsetF imageOffset(iconHorizontalOffset, imageVerticalOffset);
562 imageGeometryNode->SetMarginFrameOffset(imageOffset);
563 imageWrapper->Layout();
564
565 // layout textfield
566 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
567 CHECK_NULL_VOID(textFieldWrapper);
568 auto textFieldGeometryNode = textFieldWrapper->GetGeometryNode();
569 CHECK_NULL_VOID(textFieldGeometryNode);
570 float textFieldHorizontalOffset = leftOffset + searchIconLeftSpace + iconRenderWidth + searchIconRightSpace;
571 float textFieldVerticalOffset = centerVerticalOffset - textFieldGeometryNode->GetFrameSize().Height() / 2;
572 textFieldGeometryNode->SetMarginFrameOffset(OffsetF(textFieldHorizontalOffset, textFieldVerticalOffset));
573 textFieldWrapper->Layout();
574
575 // cancel button size
576 auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
577 CHECK_NULL_VOID(cancelButtonWrapper);
578 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
579 CHECK_NULL_VOID(cancelButtonGeometryNode);
580 auto cancelButtonFrameSize = cancelButtonGeometryNode->GetFrameSize();
581 auto cancelButtonFrameWidth = cancelButtonFrameSize.Width();
582 auto cancelButtonFrameHeight = cancelButtonFrameSize.Height();
583
584 // cancel image size
585 auto cancelImageWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_IMAGE_INDEX);
586 CHECK_NULL_VOID(cancelImageWrapper);
587 auto cancelImageGeometryNode = cancelImageWrapper->GetGeometryNode();
588 CHECK_NULL_VOID(cancelImageGeometryNode);
589 auto cancelImageFrameSize = cancelImageGeometryNode->GetFrameSize();
590 auto cancelImageFrameWidth = cancelImageFrameSize.Width();
591 auto cancelImageFrameHeight = cancelImageFrameSize.Height();
592
593 // layout search button
594 auto searchButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
595 CHECK_NULL_VOID(searchButtonWrapper);
596 auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
597 CHECK_NULL_VOID(searchButtonGeometryNode);
598 auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
599 float searchButtonVerticalOffset = centerVerticalOffset - searchButtonFrameSize.Height() / 2;
600 float rightOffset = padding.right.value_or(0.0f);
601 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
602 rightOffset = 0.0f;
603 }
604 float searchButtonHorizontalOffset =
605 searchFrameWidth - searchButtonFrameSize.Width() - searchButtonSpace - rightOffset;
606 searchButtonHorizontalOffset = std::max(searchButtonHorizontalOffset, 0.0f);
607 OffsetF searchButtonOffset = OffsetF(searchButtonHorizontalOffset, searchButtonVerticalOffset);
608 searchButtonGeometryNode->SetMarginFrameOffset(searchButtonOffset);
609 searchButtonWrapper->Layout();
610
611 // layout cancel button
612 float cancelButtonHorizontalOffset = 0;
613 float cancelButtonVerticalOffset = centerVerticalOffset - cancelButtonFrameHeight / 2;
614 auto searchButtonNode = searchButtonWrapper->GetHostNode();
615 auto searchButtonEvent = searchButtonNode->GetEventHub<ButtonEventHub>();
616 if (searchButtonEvent->IsEnabled()) {
617 auto cancelButtonOffsetToSearchButton = cancelButtonFrameWidth + 2 * dividerSideSpace + dividerWidth;
618 cancelButtonHorizontalOffset = std::max(searchButtonOffset.GetX() - cancelButtonOffsetToSearchButton, 0.0);
619 } else {
620 cancelButtonHorizontalOffset = searchFrameWidth - cancelButtonFrameWidth - searchButtonSpace - rightOffset;
621 }
622 OffsetF cancelButtonOffset = OffsetF(cancelButtonHorizontalOffset, cancelButtonVerticalOffset);
623 cancelButtonGeometryNode->SetMarginFrameOffset(cancelButtonOffset);
624 cancelButtonWrapper->Layout();
625
626 // layout cancel image
627 float cancelImageVerticalOffset = centerVerticalOffset - cancelImageFrameHeight / 2;
628 float cancelButtonImageCenterOffset = (cancelButtonFrameWidth - cancelImageFrameWidth) / 2;
629 float cancelImageHorizontalOffset = cancelButtonHorizontalOffset + cancelButtonImageCenterOffset;
630 OffsetF cancelImageOffset = OffsetF(cancelImageHorizontalOffset, cancelImageVerticalOffset);
631 cancelImageGeometryNode->SetMarginFrameOffset(cancelImageOffset);
632 cancelImageWrapper->Layout();
633 CalcChildrenHotZone(layoutWrapper);
634 }
635
636 } // namespace OHOS::Ace::NG
637