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