1 /*
2 * Copyright (c) 2022-2025 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 #include "core/components_ng/pattern/search/search_pattern.h"
18
19 #include "core/components_ng/pattern/button/button_pattern.h"
20 #include "core/components_ng/pattern/image/image_pattern.h"
21 #include "core/components_ng/pattern/text_field/text_field_layout_algorithm.h"
22
23 namespace OHOS::Ace::NG {
24 namespace {
25 constexpr int32_t TEXTFIELD_INDEX = 0;
26 constexpr int32_t IMAGE_INDEX = 1;
27 constexpr int32_t CANCEL_IMAGE_INDEX = 2;
28 constexpr int32_t CANCEL_BUTTON_INDEX = 3;
29 constexpr int32_t BUTTON_INDEX = 4;
30 constexpr int32_t DIVIDER_INDEX = 5;
31 constexpr int32_t MULTIPLE_2 = 2;
32 constexpr float MAX_SEARCH_BUTTON_RATE = 0.4f;
33 constexpr float AGING_MIN_SCALE = 1.75f;
34 constexpr float MAX_FONT_SCALE = 2.0f;
35 constexpr int TWO = 2;
36 constexpr Dimension DEFAULT_DIVIDER_HEIGHT = 12.0_vp;
37 } // namespace
38
IsFixedHeightMode(LayoutWrapper * layoutWrapper)39 bool SearchLayoutAlgorithm::IsFixedHeightMode(LayoutWrapper* layoutWrapper)
40 {
41 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
42 CHECK_NULL_RETURN(layoutProperty, false);
43
44 auto constraint = layoutProperty->GetLayoutConstraint();
45 return constraint->selfIdealSize.Height().has_value();
46 }
47
CalculateMaxFontScale(LayoutWrapper * layoutWrapper)48 float SearchLayoutAlgorithm::CalculateMaxFontScale(LayoutWrapper* layoutWrapper)
49 {
50 auto searchHost = layoutWrapper->GetHostNode();
51 CHECK_NULL_RETURN(searchHost, MAX_FONT_SCALE);
52 auto pipeline = searchHost->GetContext();
53 CHECK_NULL_RETURN(pipeline, MAX_FONT_SCALE);
54 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
55 CHECK_NULL_RETURN(textFieldWrapper, MAX_FONT_SCALE);
56 auto textFieldLayoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
57 CHECK_NULL_RETURN(textFieldLayoutProperty, MAX_FONT_SCALE);
58 auto maxScale = MAX_FONT_SCALE;
59 if (textFieldLayoutProperty->HasMaxFontScale()) {
60 maxScale = std::min(textFieldLayoutProperty->GetMaxFontScale().value(), maxScale);
61 } else {
62 maxScale = std::min(pipeline->GetMaxAppFontScale(), maxScale);
63 }
64 return maxScale;
65 }
66
CalculateMinFontScale(LayoutWrapper * layoutWrapper)67 float SearchLayoutAlgorithm::CalculateMinFontScale(LayoutWrapper* layoutWrapper)
68 {
69 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
70 CHECK_NULL_RETURN(textFieldWrapper, 0.0f);
71 auto textFieldLayoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
72 CHECK_NULL_RETURN(textFieldLayoutProperty, 0.0f);
73 auto minScale = 0.0f;
74 if (textFieldLayoutProperty->HasMinFontScale()) {
75 minScale = textFieldLayoutProperty->GetMinFontScale().value();
76 }
77 return minScale;
78 }
79
CancelImageMeasure(LayoutWrapper * layoutWrapper)80 void SearchLayoutAlgorithm::CancelImageMeasure(LayoutWrapper* layoutWrapper)
81 {
82 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
83 CHECK_NULL_VOID(layoutProperty);
84 auto cancelImageWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_IMAGE_INDEX);
85 CHECK_NULL_VOID(cancelImageWrapper);
86 auto cancelImageGeometryNode = cancelImageWrapper->GetGeometryNode();
87 CHECK_NULL_VOID(cancelImageGeometryNode);
88 auto imageLayoutProperty = cancelImageWrapper->GetLayoutProperty();
89 CHECK_NULL_VOID(imageLayoutProperty);
90 auto searchHost = layoutWrapper->GetHostNode();
91 CHECK_NULL_VOID(searchHost);
92 auto pipeline = searchHost->GetContext();
93 CHECK_NULL_VOID(pipeline);
94 auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
95 CHECK_NULL_VOID(searchTheme);
96 auto defaultImageHeight = static_cast<float>(searchTheme->GetIconSize().ConvertToPxDistribute(
97 minFontScale_, maxFontScale_));
98 auto imageHeight = static_cast<float>(std::min(layoutProperty->HasCancelButtonUDSize() ?
99 layoutProperty->GetCancelButtonUDSizeValue().ConvertToPxDistribute(
100 minFontScale_, maxFontScale_) : defaultImageHeight,
101 searchHeight_));
102 if (cancelImageWrapper->GetHostTag() == V2::SYMBOL_ETS_TAG) {
103 imageHeight = CalcSymbolIconHeight(layoutWrapper, CANCEL_IMAGE_INDEX, defaultImageHeight);
104 }
105 CalcSize imageCalcSize;
106 imageCalcSize.SetWidth(CalcLength(imageHeight));
107 imageCalcSize.SetHeight(CalcLength(imageHeight));
108 imageLayoutProperty->UpdateUserDefinedIdealSize(imageCalcSize);
109 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
110 cancelImageWrapper->Measure(childLayoutConstraint);
111 cancelIconSizeMeasure_ = cancelImageGeometryNode->GetFrameSize();
112 }
113
CancelButtonMeasure(LayoutWrapper * layoutWrapper)114 void SearchLayoutAlgorithm::CancelButtonMeasure(LayoutWrapper* layoutWrapper)
115 {
116 auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
117 CHECK_NULL_VOID(cancelButtonWrapper);
118 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
119 CHECK_NULL_VOID(layoutProperty);
120 auto cancelButtonLayoutProperty =
121 AceType::DynamicCast<ButtonLayoutProperty>(cancelButtonWrapper->GetLayoutProperty());
122 CHECK_NULL_VOID(cancelButtonLayoutProperty);
123 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
124 CHECK_NULL_VOID(cancelButtonGeometryNode);
125 auto searchHost = layoutWrapper->GetHostNode();
126 CHECK_NULL_VOID(searchHost);
127 auto pipeline = searchHost->GetContext();
128 CHECK_NULL_VOID(pipeline);
129 auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
130 CHECK_NULL_VOID(searchTheme);
131
132 // calculate theme space from cancel button to cancel image
133 auto spaceHeight = searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx() -
134 searchTheme->GetIconHeight().ConvertToPx();
135
136 // calculate cancel button height
137 auto cancelButtonHeight =
138 layoutProperty->GetCancelButtonUDSizeValue(Dimension(cancelIconSizeMeasure_.Height())).ConvertToPx() +
139 spaceHeight;
140
141 // cancel button height should be less than searchHeight
142 cancelButtonHeight = std::min(cancelButtonHeight, searchHeight_);
143
144 CalcSize cancelButtonCalcSize((CalcLength(cancelButtonHeight)), CalcLength(cancelButtonHeight));
145 cancelButtonLayoutProperty->UpdateUserDefinedIdealSize(cancelButtonCalcSize);
146
147 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
148 cancelButtonWrapper->Measure(childLayoutConstraint);
149 cancelBtnSizeMeasure_ = cancelButtonGeometryNode->GetFrameSize();
150 }
151
TextFieldMeasure(LayoutWrapper * layoutWrapper)152 void SearchLayoutAlgorithm::TextFieldMeasure(LayoutWrapper* layoutWrapper)
153 {
154 auto searchHost = layoutWrapper->GetHostNode();
155 CHECK_NULL_VOID(searchHost);
156 auto pipeline = searchHost->GetContext();
157 CHECK_NULL_VOID(pipeline);
158 auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
159 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
160 CHECK_NULL_VOID(layoutProperty);
161 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
162 CHECK_NULL_VOID(textFieldWrapper);
163
164 UpdateFontFeature(layoutWrapper);
165 auto constraint = layoutProperty->GetLayoutConstraint();
166 auto searchWidthMax = CalcSearchWidth(constraint.value(), layoutWrapper);
167
168 auto textFieldWidth = CalculateTextFieldWidth(layoutWrapper, searchWidthMax, searchTheme);
169 auto textFieldHeight = searchHeight_;
170 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
171 childLayoutConstraint.selfIdealSize.SetWidth(textFieldWidth);
172 if (LessNotEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
173 SetTextFieldLayoutConstraintHeight(childLayoutConstraint, textFieldHeight, layoutWrapper);
174 }
175 textFieldWrapper->Measure(childLayoutConstraint);
176 UpdateTextFieldSize(layoutWrapper);
177 }
178
CalculateTextFieldWidth(LayoutWrapper * layoutWrapper,float searchWidthMax,const RefPtr<SearchTheme> & searchTheme)179 float SearchLayoutAlgorithm::CalculateTextFieldWidth(
180 LayoutWrapper* layoutWrapper, float searchWidthMax, const RefPtr<SearchTheme>& searchTheme)
181 {
182 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
183 CHECK_NULL_RETURN(layoutProperty, 0.0f);
184 auto buttonWidth = searchButtonSizeMeasure_.Width();
185 auto cancelButtonWidth = cancelBtnSizeMeasure_.Width();
186 auto iconRenderWidth =
187 layoutProperty->GetSearchIconUDSizeValue(Dimension(searchIconSizeMeasure_.Width())).ConvertToPx();
188 auto padding = layoutProperty->CreatePaddingAndBorder();
189 float leftPadding = padding.left.value_or(0.0f);
190 float rightPadding = padding.right.value_or(0.0f);
191 auto textFieldWidth = searchWidthMax - searchTheme->GetSearchIconLeftSpace().ConvertToPx() - iconRenderWidth -
192 searchTheme->GetSearchIconRightSpace().ConvertToPx() - leftPadding - rightPadding;
193 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TEN)) {
194 textFieldWidth = searchWidthMax - searchTheme->GetSearchIconLeftSpace().ConvertToPx() - iconRenderWidth -
195 searchTheme->GetSearchIconRightSpace().ConvertToPx();
196 }
197
198 auto searchWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
199 auto searchButtonNode = searchWrapper->GetHostNode();
200 auto searchButtonEvent = searchButtonNode->GetEventHub<ButtonEventHub>();
201 auto searchButtonLayoutProperty = searchButtonNode->GetLayoutProperty<ButtonLayoutProperty>();
202 CHECK_NULL_RETURN(searchButtonLayoutProperty, 0.0f);
203 auto needToDisable = searchButtonLayoutProperty->GetAutoDisable().value_or(false);
204 if (searchButtonEvent->IsEnabled() || needToDisable) {
205 textFieldWidth = textFieldWidth - buttonWidth - searchTheme->GetSearchDividerWidth().ConvertToPx() -
206 MULTIPLE_2 * searchTheme->GetDividerSideSpace().ConvertToPx();
207 }
208
209 auto style = layoutProperty->GetCancelButtonStyle().value_or(CancelButtonStyle::INPUT);
210 if (style != CancelButtonStyle::INVISIBLE) {
211 textFieldWidth = textFieldWidth - cancelButtonWidth;
212 }
213 if (style == CancelButtonStyle::INVISIBLE && !searchButtonEvent->IsEnabled()) {
214 // right padding without cancel button and search button
215 auto rightPadding = searchTheme->GetRightPaddingWithoutButton();
216 textFieldWidth = textFieldWidth - rightPadding.ConvertToPx();
217 }
218
219 return textFieldWidth;
220 }
221
UpdateFontFeature(LayoutWrapper * layoutWrapper)222 void SearchLayoutAlgorithm::UpdateFontFeature(LayoutWrapper* layoutWrapper)
223 {
224 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
225 CHECK_NULL_VOID(layoutProperty);
226 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
227 CHECK_NULL_VOID(textFieldWrapper);
228
229 auto textFieldLayoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
230 CHECK_NULL_VOID(textFieldLayoutProperty);
231 if (layoutProperty->HasFontFeature()) {
232 textFieldLayoutProperty->UpdateFontFeature(layoutProperty->GetFontFeature().value());
233 }
234 }
235
UpdateTextFieldSize(LayoutWrapper * layoutWrapper)236 void SearchLayoutAlgorithm::UpdateTextFieldSize(LayoutWrapper* layoutWrapper)
237 {
238 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
239 CHECK_NULL_VOID(layoutProperty);
240 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
241 CHECK_NULL_VOID(textFieldWrapper);
242
243 auto textFieldGeometryNode = textFieldWrapper->GetGeometryNode();
244 CHECK_NULL_VOID(textFieldGeometryNode);
245 textFieldSizeMeasure_ = textFieldGeometryNode->GetFrameSize();
246 }
247
SetTextFieldLayoutConstraintHeight(LayoutConstraintF & contentConstraint,double textFieldHeight,LayoutWrapper * layoutWrapper)248 void SearchLayoutAlgorithm::SetTextFieldLayoutConstraintHeight(LayoutConstraintF& contentConstraint,
249 double textFieldHeight, LayoutWrapper* layoutWrapper)
250 {
251 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
252 auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
253 auto textFieldLayoutProperty =
254 AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
255 if ((textFieldLayoutProperty == nullptr) || (!textFieldLayoutProperty->HasLineHeight())) {
256 contentConstraint.selfIdealSize.SetHeight(textFieldHeight);
257 }
258 return;
259 }
260 contentConstraint.selfIdealSize.SetHeight(textFieldHeight);
261 }
262
ImageMeasure(LayoutWrapper * layoutWrapper)263 void SearchLayoutAlgorithm::ImageMeasure(LayoutWrapper* layoutWrapper)
264 {
265 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
266 CHECK_NULL_VOID(layoutProperty);
267 auto imageWrapper = layoutWrapper->GetOrCreateChildByIndex(IMAGE_INDEX);
268 CHECK_NULL_VOID(imageWrapper);
269 auto imageGeometryNode = imageWrapper->GetGeometryNode();
270 CHECK_NULL_VOID(imageGeometryNode);
271 auto imageLayoutProperty = imageWrapper->GetLayoutProperty();
272 CHECK_NULL_VOID(imageLayoutProperty);
273 auto searchHost = layoutWrapper->GetHostNode();
274 CHECK_NULL_VOID(searchHost);
275 auto pipeline = searchHost->GetContext();
276 CHECK_NULL_VOID(pipeline);
277 auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
278 CHECK_NULL_VOID(searchTheme);
279 auto defaultImageHeight = searchTheme->GetIconSize().ConvertToPx();
280 auto imageHeight = static_cast<float>(std::min(layoutProperty->HasSearchIconUDSize() ?
281 layoutProperty->GetSearchIconUDSizeValue().ConvertToPx() : defaultImageHeight,
282 searchHeight_));
283 if (imageWrapper->GetHostTag() == V2::SYMBOL_ETS_TAG) {
284 imageHeight = CalcSymbolIconHeight(layoutWrapper, IMAGE_INDEX, defaultImageHeight);
285 }
286 CalcSize imageCalcSize;
287 imageCalcSize.SetWidth(CalcLength(imageHeight));
288 imageCalcSize.SetHeight(CalcLength(imageHeight));
289 imageLayoutProperty->UpdateUserDefinedIdealSize(imageCalcSize);
290
291 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
292 imageWrapper->Measure(childLayoutConstraint);
293 searchIconSizeMeasure_ = imageGeometryNode->GetFrameSize();
294 }
295
searchButtonCalcSize(const RefPtr<SearchTheme> & searchTheme,RefPtr<SearchLayoutProperty> layoutProperty,LayoutWrapper * layoutWrapper,float maxFontScale,float minFontScale)296 CalcSize SearchLayoutAlgorithm::searchButtonCalcSize(const RefPtr<SearchTheme>& searchTheme,
297 RefPtr<SearchLayoutProperty> layoutProperty, LayoutWrapper* layoutWrapper, float maxFontScale, float minFontScale)
298 {
299 // calculate theme space from search button to font
300 auto spaceHeight = searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx() -
301 searchTheme->GetButtonFontSize().ConvertToPxDistribute(minFontScale, maxFontScale);
302 // calculate search button height
303 auto defaultButtonHeight =
304 searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx();
305 auto searchButtonHeight = std::max(defaultButtonHeight,
306 layoutProperty->GetSearchButtonFontSizeValue(searchTheme->GetButtonFontSize()).ConvertToPxDistribute(
307 minFontScale, maxFontScale) + spaceHeight);
308 searchButtonHeight = std::min(searchButtonHeight, searchHeight_);
309 CalcSize searchButtonCalcSize;
310 searchButtonCalcSize.SetHeight(CalcLength(searchButtonHeight));
311 return searchButtonCalcSize;
312 }
313
SearchButtonMeasure(LayoutWrapper * layoutWrapper)314 void SearchLayoutAlgorithm::SearchButtonMeasure(LayoutWrapper* layoutWrapper)
315 {
316 auto buttonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
317 CHECK_NULL_VOID(buttonWrapper);
318 auto buttonLayoutProperty = AceType::DynamicCast<ButtonLayoutProperty>(buttonWrapper->GetLayoutProperty());
319 CHECK_NULL_VOID(buttonLayoutProperty);
320 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
321 CHECK_NULL_VOID(layoutProperty);
322 auto buttonGeometryNode = buttonWrapper->GetGeometryNode();
323 CHECK_NULL_VOID(buttonGeometryNode);
324 auto searchHost = layoutWrapper->GetHostNode();
325 CHECK_NULL_VOID(searchHost);
326 auto pipeline = searchHost->GetContext();
327 CHECK_NULL_VOID(pipeline);
328 auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
329 CHECK_NULL_VOID(searchTheme);
330 buttonLayoutProperty->UpdateUserDefinedIdealSize(searchButtonCalcSize(searchTheme, layoutProperty, layoutWrapper,
331 maxFontScale_, minFontScale_));
332 auto textWrapper = buttonWrapper->GetChildByIndex(0);
333 if (textWrapper) {
334 auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
335 CHECK_NULL_VOID(textLayoutProperty);
336 textLayoutProperty->UpdateMaxFontScale(maxFontScale_);
337 textLayoutProperty->UpdateMinFontScale(minFontScale_);
338 }
339 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
340 buttonLayoutProperty->ClearUserDefinedIdealSize(false, true);
341 }
342
343 // searchButton Measure
344 auto buttonLayoutConstraint = layoutProperty->CreateChildConstraint();
345 buttonWrapper->Measure(buttonLayoutConstraint);
346
347 // deal with pixel round
348 auto pixelRound = static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
349 static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM);
350 buttonLayoutProperty->UpdatePixelRound(pixelRound);
351
352 // compute searchButton width
353 auto searchWidthMax = CalcSearchWidth(layoutProperty->GetLayoutConstraint().value(), layoutWrapper);
354 double searchButtonWidth = searchWidthMax * MAX_SEARCH_BUTTON_RATE;
355 double curSearchButtonWidth = buttonGeometryNode->GetFrameSize().Width();
356 searchButtonWidth = std::min(searchButtonWidth, curSearchButtonWidth);
357 buttonLayoutConstraint.selfIdealSize.SetWidth(searchButtonWidth);
358 buttonWrapper->Measure(buttonLayoutConstraint);
359 searchButtonSizeMeasure_ = buttonGeometryNode->GetFrameSize();
360 }
361
DividerMeasure(LayoutWrapper * layoutWrapper)362 void SearchLayoutAlgorithm::DividerMeasure(LayoutWrapper* layoutWrapper)
363 {
364 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
365 CHECK_NULL_VOID(layoutProperty);
366 auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(DIVIDER_INDEX);
367 CHECK_NULL_VOID(dividerWrapper);
368 auto dividerGeometryNode = dividerWrapper->GetGeometryNode();
369 CHECK_NULL_VOID(dividerGeometryNode);
370 auto dividerLayoutProperty = dividerWrapper->GetLayoutProperty();
371 CHECK_NULL_VOID(dividerLayoutProperty);
372 auto host = layoutWrapper->GetHostNode();
373 CHECK_NULL_VOID(host);
374 auto pipeline = host->GetContext();
375 CHECK_NULL_VOID(pipeline);
376 auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
377 CHECK_NULL_VOID(searchTheme);
378
379 auto iconHeight = searchTheme->GetIconHeight().ConvertToPx();
380 auto dividerHeight = std::min(static_cast<float>(searchHeight_), static_cast<float>(iconHeight));
381 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
382 auto defaultDividerHeight = DEFAULT_DIVIDER_HEIGHT.ConvertToPx();
383 dividerHeight = std::min(static_cast<float>(searchHeight_), static_cast<float>(defaultDividerHeight));
384 }
385 auto dividerWidth = searchTheme->GetSearchDividerWidth();
386
387 CalcSize dividerSize;
388 dividerSize.SetWidth(CalcLength(dividerWidth));
389 dividerSize.SetHeight(CalcLength(dividerHeight));
390 dividerLayoutProperty->UpdateUserDefinedIdealSize(dividerSize);
391
392 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
393 dividerWrapper->Measure(childLayoutConstraint);
394 dividerSizeMeasure_ = dividerGeometryNode->GetFrameSize();
395 }
396
CalcSearchAdaptHeight(LayoutWrapper * layoutWrapper)397 double SearchLayoutAlgorithm::CalcSearchAdaptHeight(LayoutWrapper* layoutWrapper)
398 {
399 double searchHeightAdapt = 0;
400 auto host = layoutWrapper->GetHostNode();
401 CHECK_NULL_RETURN(host, 0);
402 auto pipeline = host->GetContext();
403 CHECK_NULL_RETURN(pipeline, 0);
404 auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
405 CHECK_NULL_RETURN(searchTheme, 0);
406 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
407 CHECK_NULL_RETURN(layoutProperty, 0);
408 auto searchBtnWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
409 CHECK_NULL_RETURN(searchBtnWrapper, 0);
410 auto cancelBtnLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
411 CHECK_NULL_RETURN(cancelBtnLayoutWrapper, 0);
412 // search button height
413 auto buttonNode = searchBtnWrapper->GetHostNode();
414 CHECK_NULL_RETURN(buttonNode, true);
415 auto searchButtonEvent = buttonNode->GetEventHub<ButtonEventHub>();
416 CHECK_NULL_RETURN(searchButtonEvent, true);
417 auto searchButtonHeight = searchButtonSizeMeasure_.Height() + 2 *
418 searchTheme->GetSearchButtonSpace().ConvertToPxDistribute(minFontScale_, maxFontScale_);
419 searchButtonHeight = (!searchButtonEvent->IsEnabled()) ? 0.0f : searchButtonHeight;
420 // search icon height
421 auto searchIconFrameHight = searchIconSizeMeasure_.Height();
422 auto searchIconHeight = layoutProperty->GetSearchIconUDSizeValue(
423 Dimension(searchIconFrameHight)).ConvertToPxDistribute(minFontScale_, maxFontScale_);
424 searchIconHeight += searchTheme->GetHeight().ConvertToPxDistribute(minFontScale_, maxFontScale_) -
425 searchTheme->GetIconHeight().ConvertToPxDistribute(minFontScale_, maxFontScale_);
426 // cancel button height
427 auto cancelButtonNode = cancelBtnLayoutWrapper->GetHostNode();
428 CHECK_NULL_RETURN(cancelButtonNode, 0);
429 auto cancelButtonEvent = cancelButtonNode->GetEventHub<ButtonEventHub>();
430 CHECK_NULL_RETURN(cancelButtonEvent, 0);
431 auto cancelBtnHight = cancelBtnSizeMeasure_.Height() + 2 *
432 searchTheme->GetSearchButtonSpace().ConvertToPxDistribute(minFontScale_, maxFontScale_);
433 cancelBtnHight = (!cancelButtonEvent->IsEnabled()) ? 0.0f : cancelBtnHight;
434 // textfield height
435 auto padding = layoutProperty->CreatePaddingAndBorder();
436 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
437 auto textfieldHeight = textFieldSizeMeasure_.Height() + verticalPadding;
438 // calculate the highest
439 searchHeightAdapt = std::max(searchIconHeight, searchButtonHeight);
440 searchHeightAdapt = std::max(searchHeightAdapt, cancelBtnHight);
441 searchHeightAdapt = std::max(searchHeightAdapt, static_cast<double>(textfieldHeight));
442 return searchHeightAdapt;
443 }
444
SelfMeasure(LayoutWrapper * layoutWrapper)445 void SearchLayoutAlgorithm::SelfMeasure(LayoutWrapper* layoutWrapper)
446 {
447 auto geometryNode = layoutWrapper->GetGeometryNode();
448 CHECK_NULL_VOID(geometryNode);
449 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
450 CHECK_NULL_VOID(layoutProperty);
451 auto constraint = layoutProperty->GetLayoutConstraint();
452 auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
453 UpdateClipBounds(layoutWrapper, searchHeight);
454 // update search height
455 constraint->selfIdealSize.SetHeight(searchHeight);
456 auto searchWidth = CalcSearchWidth(constraint.value(), layoutWrapper);
457 SizeF idealSize(searchWidth, searchHeight);
458 if (GreaterOrEqualToInfinity(idealSize.Width()) || GreaterOrEqualToInfinity(idealSize.Height())) {
459 geometryNode->SetFrameSize(SizeF());
460 return;
461 }
462
463 // update search height
464 geometryNode->SetFrameSize(idealSize);
465 geometryNode->SetContentSize(idealSize);
466 }
467
CalcSearchWidth(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)468 double SearchLayoutAlgorithm::CalcSearchWidth(
469 const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
470 {
471 auto searchConstraint = contentConstraint;
472 auto idealWidth = contentConstraint.selfIdealSize.Width().value_or(contentConstraint.maxSize.Width());
473 auto idealHeight = contentConstraint.selfIdealSize.Height().value_or(contentConstraint.maxSize.Height());
474 auto maxIdealSize = SizeF { idealWidth, idealHeight };
475 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
476 auto frameIdealSize = maxIdealSize;
477 auto finalSize = UpdateOptionSizeByCalcLayoutConstraint(static_cast<OptionalSize<float>>(frameIdealSize),
478 layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint(),
479 layoutWrapper->GetLayoutProperty()->GetLayoutConstraint()->percentReference);
480 finalSize.SetWidth(finalSize.Width().value_or(frameIdealSize.Width()));
481 finalSize.SetHeight(finalSize.Height().value_or(frameIdealSize.Height()));
482 maxIdealSize.UpdateSizeWhenSmaller(finalSize.ConvertToSizeT());
483 }
484 searchConstraint.maxSize = maxIdealSize;
485 auto searchWidth = (searchConstraint.selfIdealSize.Width().has_value())
486 ? std::min(searchConstraint.selfIdealSize.Width().value(), searchConstraint.maxSize.Width())
487 : std::min(searchConstraint.percentReference.Width(), searchConstraint.maxSize.Width());
488
489 const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
490 CHECK_NULL_RETURN(calcLayoutConstraint, searchWidth);
491 auto hasMinSize = calcLayoutConstraint->minSize->Width().has_value();
492 auto hasMaxSize = calcLayoutConstraint->maxSize->Width().has_value();
493 auto hasWidth = calcLayoutConstraint->selfIdealSize->Width().has_value();
494 if (hasMinSize && ((hasMaxSize && searchConstraint.minSize.Width() >= searchConstraint.maxSize.Width())
495 || (!hasMaxSize && !hasWidth))) {
496 return searchConstraint.minSize.Width();
497 }
498 if (hasMinSize) {
499 searchWidth = std::max(searchConstraint.minSize.Width(), static_cast<float>(searchWidth));
500 }
501 if (hasMaxSize) {
502 searchWidth = std::min(searchConstraint.maxSize.Width(), static_cast<float>(searchWidth));
503 }
504 return searchWidth;
505 }
506
CalcSearchHeight(const LayoutConstraintF & constraint,LayoutWrapper * layoutWrapper)507 double SearchLayoutAlgorithm::CalcSearchHeight(
508 const LayoutConstraintF& constraint, LayoutWrapper* layoutWrapper)
509 {
510 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
511 CHECK_NULL_RETURN(layoutProperty, 0.0);
512 auto host = layoutWrapper->GetHostNode();
513 CHECK_NULL_RETURN(host, 0.0);
514 auto pipeline = host->GetContext();
515 CHECK_NULL_RETURN(pipeline, 0.0);
516 auto renderContext = host->GetRenderContext();
517 CHECK_NULL_RETURN(renderContext, 0.0);
518 auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
519 CHECK_NULL_RETURN(searchTheme, 0.0);
520 auto themeHeight = searchTheme->GetHeight().ConvertToPx();
521 auto searchHeight =
522 (constraint.selfIdealSize.Height().has_value()) ? constraint.selfIdealSize.Height().value() : themeHeight;
523 auto padding = layoutProperty->CreatePaddingAndBorder();
524 auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
525 searchHeight = std::max(verticalPadding, static_cast<float>(searchHeight));
526 auto searchHeightAdapt = searchHeight;
527 if (!IsFixedHeightMode(layoutWrapper)) {
528 searchHeightAdapt = std::max(searchHeightAdapt, CalcSearchAdaptHeight(layoutWrapper));
529 renderContext->SetClipToBounds(false);
530 } else {
531 renderContext->SetClipToBounds(true);
532 }
533
534 const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
535 CHECK_NULL_RETURN(calcLayoutConstraint, searchHeightAdapt);
536 auto hasMinSize = calcLayoutConstraint->minSize.has_value() &&
537 calcLayoutConstraint->minSize->Height().has_value();
538 auto hasMaxSize = calcLayoutConstraint->maxSize.has_value() &&
539 calcLayoutConstraint->maxSize->Height().has_value();
540 auto hasHeight = calcLayoutConstraint->selfIdealSize.has_value() &&
541 calcLayoutConstraint->selfIdealSize->Height().has_value();
542 if (hasMinSize && ((hasMaxSize && constraint.minSize.Height() >= constraint.maxSize.Height())
543 || (!hasMaxSize && !hasHeight))) {
544 return constraint.minSize.Height();
545 }
546 if (hasMinSize) {
547 searchHeightAdapt = std::max(constraint.minSize.Height(),
548 static_cast<float>(searchHeightAdapt));
549 }
550 if (hasMaxSize) {
551 searchHeightAdapt = std::min(constraint.maxSize.Height(),
552 static_cast<float>(searchHeightAdapt));
553 }
554 return searchHeightAdapt;
555 }
556
Measure(LayoutWrapper * layoutWrapper)557 void SearchLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
558 {
559 auto host = layoutWrapper->GetHostNode();
560 CHECK_NULL_VOID(host);
561 auto children = host->GetChildren();
562 if (children.empty()) {
563 return;
564 }
565
566 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
567 CHECK_NULL_VOID(layoutProperty);
568 auto constraint = layoutProperty->GetLayoutConstraint();
569 CHECK_NULL_VOID(constraint);
570 searchHeight_ = CalcSearchHeight(constraint.value(), layoutWrapper);
571 maxFontScale_ = CalculateMaxFontScale(layoutWrapper);
572 minFontScale_ = CalculateMinFontScale(layoutWrapper);
573
574 SearchButtonMeasure(layoutWrapper);
575 DividerMeasure(layoutWrapper);
576 ImageMeasure(layoutWrapper);
577 CancelImageMeasure(layoutWrapper);
578 CancelButtonMeasure(layoutWrapper);
579 TextFieldMeasure(layoutWrapper);
580 SelfMeasure(layoutWrapper);
581 }
582
CalcChildrenHotZone(LayoutWrapper * layoutWrapper)583 void SearchLayoutAlgorithm::CalcChildrenHotZone(LayoutWrapper* layoutWrapper)
584 {
585 // search info
586 auto searchGeometryNode = layoutWrapper->GetGeometryNode();
587 CHECK_NULL_VOID(searchGeometryNode);
588 auto searchHeight = searchGeometryNode->GetFrameSize().Height();
589
590 // cancel button info
591 auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
592 CHECK_NULL_VOID(cancelButtonWrapper);
593 auto cancelButtonFrameNode = cancelButtonWrapper->GetHostNode();
594 CHECK_NULL_VOID(cancelButtonFrameNode);
595 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
596 CHECK_NULL_VOID(cancelButtonGeometryNode);
597 auto cancelButtonFrameSize = cancelButtonGeometryNode->GetFrameSize();
598 auto cancelButtonWidth = cancelButtonFrameSize.Width();
599 auto cancelButtonHeight = cancelButtonFrameSize.Height();
600
601 // search button info
602 auto searchButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
603 CHECK_NULL_VOID(searchButtonWrapper);
604 auto searchButtonFrameNode = searchButtonWrapper->GetHostNode();
605 CHECK_NULL_VOID(searchButtonFrameNode);
606 auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
607 CHECK_NULL_VOID(searchButtonGeometryNode);
608 auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
609 auto searchButtonWidth = searchButtonFrameSize.Width();
610 auto searchButtonHeight = searchButtonFrameSize.Height();
611
612 auto pipeline = searchButtonFrameNode->GetContext();
613 CHECK_NULL_VOID(pipeline);
614 auto searchTheme = pipeline->GetTheme<SearchTheme>(searchButtonFrameNode->GetThemeScopeId());
615 auto buttonSpace = searchTheme->GetSearchButtonSpace().ConvertToPx();
616 // calculate cancel button hot zone
617 cancelButtonFrameNode->RemoveLastHotZoneRect();
618 DimensionRect cancelButtonHotZone;
619 if (cancelButtonHeight > searchHeight) {
620 cancelButtonHotZone.SetSize(DimensionSize(Dimension(cancelButtonWidth), Dimension(searchHeight)));
621 double hotZoneOffsetY = (cancelButtonHeight - searchHeight) / 2;
622 cancelButtonHotZone.SetOffset(DimensionOffset(Dimension(0), Dimension(hotZoneOffsetY)));
623 } else {
624 cancelButtonHotZone.SetSize(DimensionSize(
625 Dimension(cancelButtonWidth + 2 * buttonSpace), Dimension(cancelButtonHeight + 2 * buttonSpace)));
626 cancelButtonHotZone.SetOffset(
627 DimensionOffset(Offset(static_cast<float>(-buttonSpace), static_cast<float>(-buttonSpace))));
628 }
629 cancelButtonFrameNode->AddHotZoneRect(cancelButtonHotZone);
630
631 // calculate search button hot zone
632 searchButtonFrameNode->RemoveLastHotZoneRect();
633 DimensionRect searchButtonHotZone;
634 if (searchButtonHeight > searchHeight) {
635 searchButtonHotZone.SetSize(DimensionSize(Dimension(searchButtonWidth), Dimension(searchHeight)));
636 double hotZoneOffsetY = (searchButtonHeight - searchHeight) / 2;
637 searchButtonHotZone.SetOffset(DimensionOffset(Dimension(0), Dimension(hotZoneOffsetY)));
638 } else {
639 searchButtonHotZone.SetSize(DimensionSize(
640 Dimension(searchButtonWidth + 2 * buttonSpace), Dimension(searchButtonHeight + 2 * buttonSpace)));
641 searchButtonHotZone.SetOffset(
642 DimensionOffset(Offset(static_cast<float>(-buttonSpace), static_cast<float>(-buttonSpace))));
643 }
644 searchButtonFrameNode->AddHotZoneRect(searchButtonHotZone);
645 }
646
Layout(LayoutWrapper * layoutWrapper)647 void SearchLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
648 {
649 auto host = layoutWrapper->GetHostNode();
650 CHECK_NULL_VOID(host);
651 auto children = host->GetChildren();
652 if (children.empty()) {
653 return;
654 }
655
656 auto layoutProperty = DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
657 CHECK_NULL_VOID(layoutProperty);
658 auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
659
660
661 auto pipeline = host->GetContext();
662 CHECK_NULL_VOID(pipeline);
663 auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
664
665 auto geometryNode = layoutWrapper->GetGeometryNode();
666 CHECK_NULL_VOID(geometryNode);
667 auto searchSize = geometryNode->GetFrameSize();
668 auto searchFrameWidth = searchSize.Width();
669 auto searchFrameHeight = searchSize.Height();
670
671 LayoutSearchParams params = {
672 .layoutWrapper = layoutWrapper,
673 .layoutProperty = layoutProperty,
674 .searchTheme = searchTheme,
675 .searchFrameWidth = searchFrameWidth,
676 .searchFrameHeight = searchFrameHeight,
677 .isRTL = isRTL
678 };
679
680 LayoutSearchIcon(params);
681 LayoutSearchButton(params);
682 LayoutDivider(params);
683 LayoutCancelButton(params);
684 LayoutCancelImage(params);
685 LayoutTextField(params);
686
687 CalcChildrenHotZone(layoutWrapper);
688 }
689
LayoutSearchIcon(const LayoutSearchParams & params)690 void SearchLayoutAlgorithm::LayoutSearchIcon(const LayoutSearchParams& params)
691 {
692 auto searchIconLeftSpace = params.searchTheme->GetSearchIconLeftSpace().ConvertToPx();
693 auto imageWrapper = params.layoutWrapper->GetOrCreateChildByIndex(IMAGE_INDEX);
694 CHECK_NULL_VOID(imageWrapper);
695 auto imageGeometryNode = imageWrapper->GetGeometryNode();
696 CHECK_NULL_VOID(imageGeometryNode);
697 auto iconFrameWidth = searchIconSizeMeasure_.Width();
698 auto iconFrameHeight = searchIconSizeMeasure_.Height();
699 auto layoutProperty = params.layoutProperty;
700 auto iconRenderWidth = layoutProperty->GetSearchIconUDSizeValue(Dimension(iconFrameWidth)).ConvertToPx();
701
702 auto padding = layoutProperty->CreatePaddingAndBorder();
703 float topPadding = padding.top.value_or(0.0f);
704 auto bottomPadding = padding.bottom.value_or(0.0f);
705 auto leftOffset = padding.left.value_or(0.0f);
706 auto rightOffset = padding.right.value_or(0.0f);
707 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
708 leftOffset = 0.0f;
709 }
710 float iconHorizontalOffset = params.isRTL ?
711 params.searchFrameWidth - searchIconLeftSpace - iconRenderWidth - rightOffset :
712 leftOffset + searchIconLeftSpace + (iconRenderWidth - iconFrameWidth) / 2.0f;
713
714 auto searchIconConstraint = imageWrapper->GetLayoutProperty()->GetLayoutConstraint();
715 auto iconUserHeight =
716 searchIconConstraint->selfIdealSize.Height().value_or(params.searchTheme->GetIconHeight().ConvertToPx());
717 float imageVerticalOffset = topPadding;
718 auto host = params.layoutWrapper->GetHostNode();
719 if (host) {
720 auto pipeline = host->GetContext();
721 if (pipeline && pipeline->GetPixelRoundMode() == PixelRoundMode::PIXEL_ROUND_AFTER_MEASURE) {
722 // height is rounded in framenode's measure function, iconFrameHeight has no fractional part
723 iconUserHeight = std::floor(iconUserHeight + 0.5f);
724 }
725 }
726 if (NearEqual(iconUserHeight, iconFrameHeight)) {
727 float iconInterval = (params.searchFrameHeight - iconUserHeight) / 2;
728 if (topPadding <= iconInterval && bottomPadding <= iconInterval) {
729 imageVerticalOffset = iconInterval;
730 } else if (topPadding <= iconInterval && bottomPadding > iconInterval) {
731 imageVerticalOffset = params.searchFrameHeight - (bottomPadding + iconFrameHeight);
732 }
733 }
734 OffsetF imageOffset(iconHorizontalOffset, imageVerticalOffset);
735 imageGeometryNode->SetMarginFrameOffset(imageOffset);
736 imageWrapper->Layout();
737 }
738
LayoutSearchButton(const LayoutSearchParams & params)739 void SearchLayoutAlgorithm::LayoutSearchButton(const LayoutSearchParams& params)
740 {
741 auto searchButtonSpace = params.searchTheme->GetSearchButtonSpace().ConvertToPx();
742
743 auto searchButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
744 CHECK_NULL_VOID(searchButtonWrapper);
745 auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
746 CHECK_NULL_VOID(searchButtonGeometryNode);
747 auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
748 float searchButtonVerticalOffset = (params.searchFrameHeight - searchButtonFrameSize.Height()) / TWO;
749
750 auto padding = params.layoutProperty->CreatePaddingAndBorder();
751 auto leftOffset = padding.left.value_or(0.0f);
752 auto rightOffset = padding.right.value_or(0.0f);
753 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
754 rightOffset = 0.0f;
755 }
756 float searchButtonHorizontalOffset = 0.0f;
757 if (params.isRTL) {
758 searchButtonHorizontalOffset = leftOffset + searchButtonSpace;
759 } else {
760 searchButtonHorizontalOffset =
761 params.searchFrameWidth - searchButtonFrameSize.Width() - searchButtonSpace - rightOffset;
762 searchButtonHorizontalOffset = std::max(searchButtonHorizontalOffset, 0.0f);
763 }
764 auto searchButtonOffset = OffsetF(searchButtonHorizontalOffset, searchButtonVerticalOffset);
765 searchButtonGeometryNode->SetMarginFrameOffset(searchButtonOffset);
766 searchButtonWrapper->Layout();
767 }
768
LayoutDivider(const LayoutSearchParams & params)769 void SearchLayoutAlgorithm::LayoutDivider(const LayoutSearchParams& params)
770 {
771 auto searchButtonSpace = params.searchTheme->GetSearchButtonSpace().ConvertToPx();
772 auto dividerSpace = params.searchTheme->GetDividerSideSpace().ConvertToPx();
773
774 auto dividerWrapper = params.layoutWrapper->GetOrCreateChildByIndex(DIVIDER_INDEX);
775 CHECK_NULL_VOID(dividerWrapper);
776 auto dividerGeometryNode = dividerWrapper->GetGeometryNode();
777 CHECK_NULL_VOID(dividerGeometryNode);
778 auto dividerFrameSize = dividerGeometryNode->GetFrameSize();
779
780 auto padding = params.layoutProperty->CreatePaddingAndBorder();
781 auto leftOffset = padding.left.value_or(0.0f);
782 auto rightOffset = padding.right.value_or(0.0f);
783 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
784 rightOffset = 0.0f;
785 }
786 auto buttonWidth = searchButtonSizeMeasure_.Width();
787
788 float dividerHorizontalOffset = 0.0f;
789 if (params.isRTL) {
790 dividerHorizontalOffset =
791 leftOffset + buttonWidth + dividerSpace + searchButtonSpace + dividerFrameSize.Width() / 2.0f;
792 } else {
793 dividerHorizontalOffset = params.searchFrameWidth - buttonWidth - dividerSpace - searchButtonSpace -
794 dividerFrameSize.Width() / 2.0f - rightOffset;
795 }
796 dividerHorizontalOffset = std::max(dividerHorizontalOffset, 0.0f);
797 auto dividerVerticalOffset = (params.searchFrameHeight - dividerFrameSize.Height()) / 2.0f;
798 auto dividerOffset = OffsetF(dividerHorizontalOffset, dividerVerticalOffset);
799 dividerGeometryNode->SetMarginFrameOffset(dividerOffset);
800 dividerWrapper->Layout();
801 }
802
803
LayoutCancelButton(const LayoutSearchParams & params)804 void SearchLayoutAlgorithm::LayoutCancelButton(const LayoutSearchParams& params)
805 {
806 auto searchTheme = params.searchTheme;
807 CHECK_NULL_VOID(searchTheme);
808 auto dividerSideSpace = searchTheme->GetDividerSideSpace().ConvertToPx();
809 auto dividerWidth = searchTheme->GetSearchDividerWidth().ConvertToPx();
810 auto borderWidth = searchTheme->GetBorderWidth().ConvertToPx();
811
812 auto cancelButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
813 CHECK_NULL_VOID(cancelButtonWrapper);
814 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
815 CHECK_NULL_VOID(cancelButtonGeometryNode);
816 auto cancelButtonFrameSize = cancelButtonGeometryNode->GetFrameSize();
817 auto cancelButtonFrameWidth = cancelButtonFrameSize.Width();
818 auto cancelButtonFrameHeight = cancelButtonFrameSize.Height();
819
820 auto searchButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
821 CHECK_NULL_VOID(searchButtonWrapper);
822 auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
823 CHECK_NULL_VOID(searchButtonGeometryNode);
824 auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
825 auto searchButtonHorizontalOffset = searchButtonGeometryNode->GetMarginFrameOffset().GetX();
826
827 auto cancelButtonHorizontalOffset = 0;
828 auto cancelButtonVerticalOffset = (params.searchFrameHeight - cancelButtonFrameHeight) / 2;
829 auto searchButtonNode = searchButtonWrapper->GetHostNode();
830 auto searchButtonEvent = searchButtonNode->GetEventHub<ButtonEventHub>();
831 auto buttonSpace = params.searchTheme->GetSearchButtonSpace().ConvertToPx();
832 auto searchButtonLayoutProperty = searchButtonNode->GetLayoutProperty<ButtonLayoutProperty>();
833 CHECK_NULL_VOID(searchButtonLayoutProperty);
834 auto needToDisable = searchButtonLayoutProperty->GetAutoDisable().value_or(false);
835 if (params.isRTL) {
836 if (searchButtonEvent->IsEnabled() || needToDisable) {
837 cancelButtonHorizontalOffset =
838 searchButtonHorizontalOffset + (searchButtonFrameSize.Width() + TWO * dividerSideSpace + dividerWidth);
839 } else {
840 cancelButtonHorizontalOffset = searchButtonHorizontalOffset;
841 }
842 } else {
843 if (searchButtonEvent->IsEnabled() || needToDisable) {
844 auto cancelButtonOffsetToSearchButton = cancelButtonFrameWidth + 2 * dividerSideSpace + dividerWidth;
845 cancelButtonHorizontalOffset =
846 std::max(searchButtonHorizontalOffset - cancelButtonOffsetToSearchButton, 0.0);
847 } else {
848 cancelButtonHorizontalOffset = params.searchFrameWidth - cancelButtonFrameWidth - buttonSpace - borderWidth;
849 }
850 }
851 auto cancelButtonOffset = OffsetF(cancelButtonHorizontalOffset, cancelButtonVerticalOffset);
852 cancelButtonGeometryNode->SetMarginFrameOffset(cancelButtonOffset);
853 cancelButtonWrapper->Layout();
854 }
855
LayoutCancelImage(const LayoutSearchParams & params)856 void SearchLayoutAlgorithm::LayoutCancelImage(const LayoutSearchParams& params)
857 {
858 auto cancelImageWrapper = params.layoutWrapper->GetOrCreateChildByIndex(CANCEL_IMAGE_INDEX);
859 CHECK_NULL_VOID(cancelImageWrapper);
860 auto cancelImageGeometryNode = cancelImageWrapper->GetGeometryNode();
861 CHECK_NULL_VOID(cancelImageGeometryNode);
862 auto cancelImageFrameSize = cancelImageGeometryNode->GetFrameSize();
863 auto cancelImageFrameWidth = cancelImageFrameSize.Width();
864 auto cancelImageFrameHeight = cancelImageFrameSize.Height();
865
866 auto cancelButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
867 CHECK_NULL_VOID(cancelButtonWrapper);
868 auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
869 CHECK_NULL_VOID(cancelButtonGeometryNode);
870 auto cancelButtonHorizontalOffset = cancelButtonGeometryNode->GetMarginFrameOffset().GetX();
871 auto cancelButtonFrameWidth = cancelButtonGeometryNode->GetFrameSize().Width();
872
873 auto cancelImageVerticalOffset = (params.searchFrameHeight - cancelImageFrameHeight) / 2;
874 auto cancelButtonImageCenterOffset = (cancelButtonFrameWidth - cancelImageFrameWidth) / 2;
875 auto cancelImageHorizontalOffset = cancelButtonHorizontalOffset + cancelButtonImageCenterOffset;
876 auto cancelImageOffset = OffsetF(cancelImageHorizontalOffset, cancelImageVerticalOffset);
877 cancelImageGeometryNode->SetMarginFrameOffset(cancelImageOffset);
878 cancelImageWrapper->Layout();
879 }
880
LayoutTextField(const LayoutSearchParams & params)881 void SearchLayoutAlgorithm::LayoutTextField(const LayoutSearchParams& params)
882 {
883 auto searchIconLeftSpace = params.searchTheme->GetSearchIconLeftSpace().ConvertToPx();
884 auto searchIconRightSpace = params.searchTheme->GetSearchIconRightSpace().ConvertToPx();
885 auto searchIconWidth = searchIconSizeMeasure_.Width();
886 auto layoutProperty = DynamicCast<SearchLayoutProperty>(params.layoutWrapper->GetLayoutProperty());
887 CHECK_NULL_VOID(layoutProperty);
888 auto padding = layoutProperty->CreatePaddingAndBorder();
889
890 auto textFieldWrapper = params.layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
891 CHECK_NULL_VOID(textFieldWrapper);
892 auto textFieldGeometryNode = textFieldWrapper->GetGeometryNode();
893 CHECK_NULL_VOID(textFieldGeometryNode);
894
895 auto hostGeometryNode = params.layoutWrapper->GetGeometryNode();
896 CHECK_NULL_VOID(hostGeometryNode);
897
898 auto textFieldHorizontalOffset = 0;
899 if (params.isRTL) {
900 auto rightOffset = searchIconWidth + searchIconLeftSpace
901 + searchIconRightSpace + padding.right.value_or(0.0f);
902 textFieldHorizontalOffset = hostGeometryNode->GetFrameSize().Width()
903 - rightOffset - textFieldGeometryNode->GetFrameSize().Width();
904 } else {
905 textFieldHorizontalOffset = searchIconWidth + searchIconLeftSpace
906 + searchIconRightSpace + padding.left.value_or(0.0f);
907 }
908
909 auto textFieldVerticalOffset = (params.searchFrameHeight - textFieldGeometryNode->GetFrameSize().Height()) / 2;
910 textFieldGeometryNode->SetMarginFrameOffset(OffsetF(textFieldHorizontalOffset, textFieldVerticalOffset));
911 textFieldWrapper->Layout();
912 }
913
UpdateClipBounds(LayoutWrapper * layoutWrapper,float height)914 void SearchLayoutAlgorithm::UpdateClipBounds(LayoutWrapper* layoutWrapper, float height)
915 {
916 if (!IsFixedHeightMode(layoutWrapper)) {
917 return;
918 }
919 auto host = layoutWrapper->GetHostNode();
920 CHECK_NULL_VOID(host);
921 auto renderContext = host->GetRenderContext();
922 CHECK_NULL_VOID(renderContext);
923 auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
924 CHECK_NULL_VOID(layoutProperty);
925 if (!layoutProperty->HasSearchIconUDSize() && !layoutProperty->HasCancelButtonUDSize()) {
926 auto pipeline = host->GetContext();
927 CHECK_NULL_VOID(pipeline);
928 auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
929 CHECK_NULL_VOID(searchTheme);
930 auto defaultImageHeight = searchTheme->GetIconSize().ConvertToPx();
931 auto isClip = LessNotEqual(height, defaultImageHeight);
932 renderContext->SetClipToBounds(isClip);
933 return;
934 }
935 auto isClip = false;
936 if (layoutProperty->HasSearchIconUDSize()) {
937 isClip = isClip || LessNotEqual(height, layoutProperty->GetSearchIconUDSizeValue().ConvertToPx());
938 }
939 if (layoutProperty->HasCancelButtonUDSize()) {
940 isClip = isClip || LessNotEqual(height, layoutProperty->GetCancelButtonUDSizeValue().ConvertToPx());
941 }
942 renderContext->SetClipToBounds(isClip);
943 }
CalcSymbolIconHeight(LayoutWrapper * layoutWrapper,int32_t index,double defaultImageHeight)944 double SearchLayoutAlgorithm::CalcSymbolIconHeight(
945 LayoutWrapper* layoutWrapper, int32_t index, double defaultImageHeight)
946 {
947 auto hostNode = layoutWrapper->GetHostNode();
948 CHECK_NULL_RETURN(hostNode, defaultImageHeight);
949 auto pipeline = hostNode->GetContext();
950 CHECK_NULL_RETURN(pipeline, defaultImageHeight);
951 auto searchPattern = hostNode->GetPattern<SearchPattern>();
952 CHECK_NULL_RETURN(searchPattern, defaultImageHeight);
953 auto searchNode = searchPattern->GetSearchNode();
954 CHECK_NULL_RETURN(searchNode, defaultImageHeight);
955
956 auto iconNode = AceType::DynamicCast<FrameNode>(hostNode->GetChildAtIndex(index));
957 CHECK_NULL_RETURN(iconNode, defaultImageHeight);
958 auto symbolLayoutProperty = iconNode->GetLayoutProperty<TextLayoutProperty>();
959 CHECK_NULL_RETURN(symbolLayoutProperty, defaultImageHeight);
960 symbolLayoutProperty->UpdateMaxFontScale(maxFontScale_);
961 symbolLayoutProperty->UpdateMinFontScale(minFontScale_);
962 auto defaultSymbolIconSize =
963 (index == IMAGE_INDEX ? searchNode->GetSearchSymbolIconSize() : searchNode->GetCancelSymbolIconSize());
964 auto iconSize = symbolLayoutProperty->GetFontSize().value_or(defaultSymbolIconSize);
965
966 return iconSize.ConvertToPxDistribute(minFontScale_, maxFontScale_);
967 }
968 } // namespace OHOS::Ace::NG
969