• 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/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