1 /*
2 * Copyright (c) 2022-2024 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/navigation/title_bar_layout_algorithm.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/geometry/ng/size_t.h"
21 #include "base/memory/ace_type.h"
22 #include "base/utils/measure_util.h"
23 #include "base/utils/utils.h"
24 #include "core/common/container.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/pattern/app_bar/app_bar_theme.h"
27 #include "core/components_ng/pattern/image/image_layout_property.h"
28 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
29 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
30 #include "core/components_ng/pattern/navigation/navdestination_node_base.h"
31 #include "core/components_ng/pattern/navigation/navdestination_pattern_base.h"
32 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
33 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
34 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
35 #include "core/components_ng/pattern/navigation/title_bar_node.h"
36 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
37 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
38 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
39 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
40 #include "core/components_ng/pattern/text/text_layout_property.h"
41 #include "core/components_ng/property/layout_constraint.h"
42 #include "core/components_ng/property/measure_property.h"
43 #include "core/components_ng/property/measure_utils.h"
44 #ifdef ENABLE_ROSEN_BACKEND
45 #include "core/components/custom_paint/rosen_render_custom_paint.h"
46 #endif
47
48 namespace OHOS::Ace::NG {
49
50 namespace {
51 constexpr int32_t MENU_OFFSET_RATIO = 9;
52 // maximum radio of the subtitle height to the titlebar height
53 constexpr double SUBTITLE_MAX_HEIGHT_RADIO = 0.35;
54 } // namespace
55
BackButtonLayout(LayoutWrapper * layoutWrapper)56 void TitleBarLayoutAlgorithm::BackButtonLayout(LayoutWrapper* layoutWrapper)
57 {
58 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
59 CHECK_NULL_VOID(titleBarNode);
60 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
61 CHECK_NULL_VOID(backButtonNode);
62 auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty();
63 CHECK_NULL_VOID(backButtonLayoutProperty);
64 PaddingProperty padding;
65 padding.SetEdges(CalcLength(MENU_BUTTON_PADDING));
66 backButtonLayoutProperty->UpdatePadding(padding);
67 }
68
UpdateIconSize(const RefPtr<FrameNode> & backButtonNode)69 void TitleBarLayoutAlgorithm::UpdateIconSize(const RefPtr<FrameNode>& backButtonNode)
70 {
71 auto backButtonImageNode = AceType::DynamicCast<FrameNode>(backButtonNode->GetChildren().front());
72 CHECK_NULL_VOID(backButtonImageNode);
73 auto backButtonImageLayoutProperty = backButtonImageNode->GetLayoutProperty<LayoutProperty>();
74 CHECK_NULL_VOID(backButtonImageLayoutProperty);
75 backButtonImageLayoutProperty->UpdateUserDefinedIdealSize(
76 CalcSize(CalcLength(backIconWidth_), CalcLength(backIconHeight_)));
77 }
78
MeasureBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)79 void TitleBarLayoutAlgorithm::MeasureBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
80 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
81 {
82 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
83 CHECK_NULL_VOID(backButtonNode);
84 auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
85 auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
86 CHECK_NULL_VOID(backButtonWrapper);
87 auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty();
88
89 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
90 // navDestination title bar
91 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
92 TitleBarParentType::NAV_DESTINATION) {
93 if (!showBackButton_) {
94 backButtonLayoutProperty->UpdateVisibility(VisibleType::GONE);
95 return;
96 }
97 backButtonLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
98 PaddingProperty padding;
99 padding.SetEdges(CalcLength(BUTTON_PADDING));
100 backButtonLayoutProperty->UpdatePadding(padding);
101 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
102 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()),
103 static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()));
104 backButtonWrapper->Measure(constraint);
105 return;
106 }
107 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
108 UpdateIconSize(backButtonNode);
109 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(backButtonWidth_.ConvertToPx()),
110 static_cast<float>(backButtonWidth_.ConvertToPx()));
111 backButtonWrapper->Measure(constraint);
112 return;
113 }
114 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()),
115 static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
116 backButtonWrapper->Measure(constraint);
117 return;
118 }
119
120 backButtonLayoutProperty->UpdateVisibility(VisibleType::GONE);
121 // navBar title bar
122 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
123 return;
124 }
125
126 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
127 return;
128 }
129
130 backButtonLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
131 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
132 UpdateIconSize(backButtonNode);
133 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(backButtonWidth_.ConvertToPx()),
134 static_cast<float>(backButtonWidth_.ConvertToPx()));
135 backButtonWrapper->Measure(constraint);
136 return;
137 }
138
139 constraint.selfIdealSize = OptionalSizeF(
140 static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()), static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
141 backButtonWrapper->Measure(constraint);
142 }
143
GetTitleWidth(const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize)144 float TitleBarLayoutAlgorithm::GetTitleWidth(const RefPtr<TitleBarNode>& titleBarNode,
145 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize)
146 {
147 double paddingLeft = maxPaddingStart_.ConvertToPx();
148 double paddingRight = maxPaddingEnd_.ConvertToPx();
149 double horizontalMargin = NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
150 auto backButtonWidth = BACK_BUTTON_ICON_SIZE.ConvertToPx();
151 auto customBackButtonRightPadding = BUTTON_PADDING.ConvertToPx();
152 auto defaultPaddingStart = defaultPaddingStart_.ConvertToPx();
153 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
154 paddingLeft = paddingLeft_;
155 paddingRight = paddingRight_;
156 horizontalMargin = menuCompPadding_.ConvertToPx();
157 backButtonWidth = backButtonWidth_.ConvertToPx();
158 customBackButtonRightPadding = 0.0f;
159 defaultPaddingStart = paddingRight;
160 }
161 // navDestination title bar
162 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
163 TitleBarParentType::NAV_DESTINATION) {
164 // nav destination custom title
165 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
166 CHECK_NULL_RETURN(navDestination, 0.0f);
167 auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
168 float occupiedWidth = 0.0f;
169 // left padding
170 if (showBackButton_) {
171 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
172 occupiedWidth += isCustom ? backButtonWidth_.ConvertToPx() + paddingLeft :
173 backButtonWidth_.ConvertToPx() + paddingLeft + horizontalMargin;
174 } else {
175 occupiedWidth += isCustom ? (BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() + paddingLeft :
176 (BACK_BUTTON_ICON_SIZE).ConvertToPx() + paddingLeft + horizontalMargin;
177 }
178 } else {
179 occupiedWidth += isCustom ? 0.0f : paddingLeft;
180 }
181 // compute right padding
182 if (NearZero(menuWidth_)) {
183 occupiedWidth += isCustom ? 0.0f : paddingRight;
184 } else {
185 occupiedWidth += menuWidth_;
186 if (!navDestination->GetPrevMenuIsCustomValue(false)) {
187 occupiedWidth += paddingLeft;
188 occupiedWidth += isCustom ? 0.0f : horizontalMargin;
189 }
190 }
191 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
192 }
193 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
194 CHECK_NULL_RETURN(navBarNode, 0.0f);
195 float occupiedWidth = 0.0f;
196 auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
197 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
198 // mini mode
199 if (titleBarLayoutProperty->GetHideBackButtonValue(false)) {
200 occupiedWidth += isCustom ? 0.0f : paddingLeft;
201 } else {
202 occupiedWidth += paddingLeft + backButtonWidth;
203 // custom right padding is the back button hot zone
204 occupiedWidth += isCustom ? customBackButtonRightPadding : horizontalMargin;
205 }
206 // compute right padding
207 if (NearZero(menuWidth_)) {
208 occupiedWidth += isCustom ? 0.0f : paddingRight;
209 } else {
210 occupiedWidth += menuWidth_;
211 if (!navBarNode->GetPrevMenuIsCustomValue(false)) {
212 occupiedWidth += defaultPaddingStart;
213 occupiedWidth += isCustom ? 0.0f : horizontalMargin;
214 }
215 }
216 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
217 }
218 // left padding of full and free mode
219 occupiedWidth = isCustom ? 0.0f : paddingLeft;
220 // right padding of full mode
221 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FULL
222 || isCustom) {
223 occupiedWidth += isCustom ? 0.0f : paddingRight;
224 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
225 }
226 // right padding of free mode
227 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
228 if (titleBarPattern && titleBarPattern->IsFreeTitleUpdated() &&
229 titleBarPattern->GetTempTitleOffsetY() < menuHeight_) {
230 if (NearZero(menuWidth_)) {
231 occupiedWidth += isCustom ? 0.0f : paddingRight;
232 } else {
233 occupiedWidth += menuWidth_;
234 if (!navBarNode->GetPrevMenuIsCustomValue(false)) {
235 occupiedWidth += paddingLeft;
236 occupiedWidth += isCustom ? 0.0f : horizontalMargin;
237 }
238 }
239 } else {
240 occupiedWidth += isCustom ? 0.0f : paddingRight;
241 }
242 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
243 }
244
WidthAfterAvoidMenubar(const RefPtr<TitleBarNode> & titleBarNode,float width)245 float TitleBarLayoutAlgorithm::WidthAfterAvoidMenubar(const RefPtr<TitleBarNode>& titleBarNode, float width)
246 {
247 float afterAvoidWidth = width;
248 auto pipeline = PipelineContext::GetCurrentContext();
249 CHECK_NULL_RETURN(pipeline, afterAvoidWidth);
250 if (!pipeline->GetInstallationFree()) {
251 return afterAvoidWidth;
252 }
253
254 auto titlebarRect = titleBarNode->GetParentGlobalOffsetDuringLayout();
255
256 auto container = Container::Current();
257 CHECK_NULL_RETURN(container, afterAvoidWidth);
258 auto appBar = container->GetAppBar();
259 CHECK_NULL_RETURN(appBar, afterAvoidWidth);
260 auto appBarRect = appBar->GetAppBarRect();
261 CHECK_NULL_RETURN(appBarRect, afterAvoidWidth);
262 auto appBarOffset = appBarRect->GetOffset();
263 auto appBarSize = appBarRect->GetSize();
264
265 auto titleBarGeo = titleBarNode->GetGeometryNode();
266 CHECK_NULL_RETURN(titleBarGeo, afterAvoidWidth);
267
268 auto avoidArea = titlebarRect.GetX() + titleBarGeo->GetFrameSize().Width() - appBarOffset.GetX();
269 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
270 avoidArea = appBarOffset.GetX() + appBarSize.Width();
271 }
272 auto buttonTop = appBarOffset.GetY() + appBarSize.Height();
273 if (LessOrEqual(titlebarRect.GetY(), buttonTop) && GreatOrEqual(avoidArea, 0.0)) {
274 afterAvoidWidth = afterAvoidWidth - avoidArea;
275 }
276
277 if (LessOrEqual(afterAvoidWidth, 0.0)) {
278 return 0.0f;
279 }
280 return afterAvoidWidth;
281 }
282
MeasureSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)283 void TitleBarLayoutAlgorithm::MeasureSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
284 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
285 {
286 auto subtitleNode = titleBarNode->GetSubtitle();
287 CHECK_NULL_VOID(subtitleNode);
288 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
289 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
290 CHECK_NULL_VOID(subtitleWrapper);
291 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
292 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
293 // limit the maxHeight of the subtitle to adapt to the scenarios where the text is too high
294 constraint.maxSize.SetHeight(SUBTITLE_MAX_HEIGHT_RADIO * titleBarSize.Height());
295 } else {
296 constraint.maxSize.SetHeight(titleBarSize.Height());
297 }
298 constraint.maxSize.SetWidth(maxWidth);
299 subtitleWrapper->Measure(constraint);
300 }
301
MeasureTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)302 void TitleBarLayoutAlgorithm::MeasureTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
303 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
304 {
305 auto titleNode = titleBarNode->GetTitle();
306 CHECK_NULL_VOID(titleNode);
307 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
308 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
309 CHECK_NULL_VOID(titleWrapper);
310 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
311 constraint.maxSize.SetHeight(titleBarSize.Height());
312
313 // navDestination title bar
314 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
315 TitleBarParentType::NAV_DESTINATION) {
316 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
317 CHECK_NULL_VOID(navDestination);
318 auto isCustomTitle = navDestination->GetPrevTitleIsCustomValue(false);
319 if (isCustomTitle) {
320 constraint.parentIdealSize.SetWidth(maxWidth);
321 constraint.maxSize.SetWidth(maxWidth);
322 // custom title must be single line title
323
324 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
325 constraint.maxSize.SetHeight(titleBarSize.Height());
326 titleWrapper->Measure(constraint);
327 return;
328 }
329 constraint.maxSize.SetWidth(maxWidth);
330 if (!titleBarNode->GetSubtitle()) {
331 constraint.maxSize.SetHeight(titleBarSize.Height());
332 titleWrapper->Measure(constraint);
333 return;
334 }
335 auto subtitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
336 auto subtitleHeight = subtitle->GetGeometryNode()->GetFrameSize().Height();
337 constraint.maxSize.SetHeight(titleBarSize.Height() - subtitleHeight);
338 titleWrapper->Measure(constraint);
339 return;
340 }
341 // NavigationCustomTitle: Custom title + height
342 if (titleBarLayoutProperty->HasTitleHeight()) {
343 constraint.parentIdealSize.SetWidth(maxWidth);
344 constraint.maxSize.SetWidth(maxWidth);
345 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
346 constraint.maxSize.SetHeight(titleBarSize.Height());
347 titleWrapper->Measure(constraint);
348 return;
349 }
350 // subTitle
351 auto titleMode = titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE);
352 auto subTitle = titleBarNode->GetSubtitle();
353 float titleSpaceVertical = 0.0f;
354 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
355 titleSpaceVertical = static_cast<float>(titleSpaceVertical_.ConvertToPx());
356 }
357 if (subTitle) {
358 // common title
359 auto index = titleBarNode->GetChildIndexById(subTitle->GetId());
360 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
361 CHECK_NULL_VOID(subtitleWrapper);
362 auto subtitleHeight = subtitleWrapper->GetGeometryNode()->GetFrameSize().Height();
363 // mini mode double title height is 56vp, free/full mode is 82vp
364 auto maxTitleHeight = titleMode == NavigationTitleMode::MINI ? SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() :
365 DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
366 constraint.maxSize.SetWidth(maxWidth);
367 constraint.maxSize.SetHeight(maxTitleHeight - subtitleHeight - titleSpaceVertical);
368 titleWrapper->Measure(constraint);
369 return;
370 }
371 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
372 CHECK_NULL_VOID(navBarNode);
373 auto isCustomTitle = navBarNode->GetPrevTitleIsCustomValue(false);
374 // single line title and mini mode
375 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
376 if (isCustomTitle) {
377 constraint.parentIdealSize.SetWidth(maxWidth);
378 constraint.maxSize.SetWidth(maxWidth);
379 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
380 constraint.maxSize.SetHeight(titleBarSize.Height());
381 } else {
382 constraint.maxSize.SetWidth(maxWidth);
383 constraint.maxSize.SetHeight(titleBarSize.Height());
384 }
385 titleWrapper->Measure(constraint);
386 return;
387 }
388 // custom builder
389 if (isCustomTitle) {
390 constraint.parentIdealSize.SetWidth(maxWidth);
391 constraint.maxSize.SetWidth(maxWidth);
392 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
393 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
394 } else {
395 auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
396 // if has menu and menu is not custom, max height is single line height
397 auto maxHeight = NearZero(menuWidth_) ? titleBarSize.Height()
398 : isCustomMenu ? titleBarSize.Height() - menuHeight_
399 : SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
400 constraint.parentIdealSize.SetHeight(maxHeight);
401 constraint.maxSize.SetHeight(maxHeight);
402 }
403 titleWrapper->Measure(constraint);
404 return;
405 }
406 // resourceStr title
407 constraint.maxSize.SetWidth(maxWidth);
408 constraint.maxSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
409 titleWrapper->Measure(constraint);
410 }
411
MeasureMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)412 void TitleBarLayoutAlgorithm::MeasureMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
413 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
414 {
415 auto menuNode = titleBarNode->GetMenu();
416 CHECK_NULL_VOID(menuNode);
417 auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
418 auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
419 CHECK_NULL_VOID(menuWrapper);
420 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
421
422 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(titleBarNode->GetParent());
423 CHECK_NULL_VOID(nodeBase);
424 bool isCustomMenu = nodeBase->GetPrevMenuIsCustomValue(false);
425 auto patternBase = nodeBase->GetPattern<NavDestinationPatternBase>();
426 CHECK_NULL_VOID(patternBase);
427 int32_t maxMenu = patternBase->GetMaxMenuNum();
428
429 if (isCustomMenu) {
430 // custom title can't be higher than 56vp
431 constraint.parentIdealSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
432 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI &&
433 !titleBarLayoutProperty->HasTitleHeight()) {
434 auto maxWidth = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * maxMenu +
435 defaultPaddingStart_.ConvertToPx();
436 constraint.parentIdealSize.SetWidth(maxWidth);
437 }
438 menuWrapper->Measure(constraint);
439 menuWidth_ = menuWrapper->GetGeometryNode()->GetFrameSize().Width();
440 menuHeight_ = menuWrapper->GetGeometryNode()->GetFrameSize().Height();
441 return;
442 }
443 auto menuItemNum = static_cast<int32_t>(menuNode->GetChildren().size());
444 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
445 if (menuItemNum >= maxMenu) {
446 menuWidth_ = static_cast<float>(iconBackgroundWidth_.ConvertToPx()) * maxMenu +
447 static_cast<float>(menuCompPadding_.ConvertToPx()) * (maxMenu - 1);
448 } else {
449 menuWidth_ = static_cast<float>(iconBackgroundWidth_.ConvertToPx()) * menuItemNum +
450 static_cast<float>(menuCompPadding_.ConvertToPx()) * (menuItemNum - 1);
451 }
452 } else {
453 if (menuItemNum >= maxMenu) {
454 menuWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * maxMenu;
455 } else {
456 menuWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * menuItemNum;
457 }
458 }
459 constraint.selfIdealSize = OptionalSizeF(menuWidth_, menuHeight_);
460 menuWrapper->Measure(constraint);
461 }
462
ShowBackButtonLayout(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,RefPtr<GeometryNode> & geometryNode,const RefPtr<LayoutWrapper> & backButtonWrapper)463 void TitleBarLayoutAlgorithm::ShowBackButtonLayout(LayoutWrapper* layoutWrapper,
464 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty,
465 RefPtr<GeometryNode>& geometryNode, const RefPtr<LayoutWrapper>& backButtonWrapper)
466 {
467 auto titleHeight = titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT);
468 Dimension backButtonHeight = BACK_BUTTON_SIZE;
469 float paddingLeft = (maxPaddingStart_ - BUTTON_PADDING).ConvertToPx();
470 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
471 backButtonHeight = backButtonHeight_;
472 paddingLeft = paddingLeft_;
473 BackButtonLayout(layoutWrapper);
474 }
475 float dividerOffset = 2.0f;
476 auto offsetY = (titleHeight - backButtonHeight) / dividerOffset;
477 auto offsetX = static_cast<float>(paddingLeft);
478 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
479 OffsetF backButtonOffset = OffsetF(offsetX, static_cast<float>(offsetY.ConvertToPx()));
480 geometryNode->SetMarginFrameOffset(backButtonOffset);
481 backButtonWrapper->Layout();
482 }
483
LayoutBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)484 void TitleBarLayoutAlgorithm::LayoutBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
485 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
486 {
487 auto backButtonNode = titleBarNode->GetBackButton();
488 CHECK_NULL_VOID(backButtonNode);
489 auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
490 auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
491 CHECK_NULL_VOID(backButtonWrapper);
492 auto geometryNode = backButtonWrapper->GetGeometryNode();
493
494 // navDestination title bar
495 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
496 TitleBarParentType::NAV_DESTINATION) {
497 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
498 if (!showBackButton_) {
499 SizeF size = SizeF(0.0f, 0.0f);
500 geometryNode->SetFrameSize(size);
501 backButtonWrapper->Layout();
502 return;
503 }
504 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
505 auto offsetY = (menuHeight_ - BACK_BUTTON_ICON_SIZE.ConvertToPx()) / 2;
506 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
507 static_cast<float>(maxPaddingStart_.ConvertToPx()));
508 backButtonOffset = OffsetF(offsetXResult, offsetY);
509 geometryNode->SetMarginFrameOffset(backButtonOffset);
510 backButtonWrapper->Layout();
511 return;
512 }
513
514 ShowBackButtonLayout(layoutWrapper, titleBarLayoutProperty, geometryNode, backButtonWrapper);
515 return;
516 }
517
518 // navBar title bar
519 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
520 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
521 geometryNode->SetMarginFrameOffset(backButtonOffset);
522 backButtonWrapper->Layout();
523 return;
524 }
525
526 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
527 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
528 geometryNode->SetMarginFrameOffset(backButtonOffset);
529 backButtonWrapper->Layout();
530 return;
531 }
532
533 ShowBackButtonLayout(layoutWrapper, titleBarLayoutProperty, geometryNode, backButtonWrapper);
534 }
535
GetFullModeTitleOffsetY(float titleHeight,float subtitleHeight,RefPtr<GeometryNode> titleBarGeometryNode)536 float TitleBarLayoutAlgorithm::GetFullModeTitleOffsetY(float titleHeight, float subtitleHeight,
537 RefPtr<GeometryNode> titleBarGeometryNode)
538 {
539 auto titleBarHeight = titleBarGeometryNode->GetFrameSize().Height();
540 // fixed white space menuHeight
541 OffsetF titleOffset = OffsetF(0.0f, 0.0f);
542 float offsetY = 0.0f;
543 auto titleSpace = titleBarHeight - menuHeight_ - static_cast<float>(paddingTopTwolines_.ConvertToPx());
544 auto titleRealHeight = titleHeight + subtitleHeight + navTitleSpaceVertical_;
545 float dividerOffset = 2.0f;
546 if (NearZero(subtitleHeight) && titleHeight < titleBarHeight - menuHeight_) {
547 offsetY = (titleBarHeight - menuHeight_ - titleRealHeight) / dividerOffset;
548 return offsetY;
549 }
550 if (titleRealHeight <= titleSpace) {
551 offsetY = (titleSpace - titleRealHeight +
552 static_cast<float>(paddingTopTwolines_.ConvertToPx())) / dividerOffset;
553 } else {
554 offsetY = titleSpace - titleRealHeight;
555 }
556
557 return offsetY;
558 }
559
LayoutTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)560 void TitleBarLayoutAlgorithm::LayoutTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
561 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
562 {
563 auto titleNode = titleBarNode->GetTitle();
564 CHECK_NULL_VOID(titleNode);
565 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
566 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
567 CHECK_NULL_VOID(titleWrapper);
568 auto geometryNode = titleWrapper->GetGeometryNode();
569 auto titleBarGeometryNode = titleBarNode->GetGeometryNode();
570 CHECK_NULL_VOID(titleBarGeometryNode);
571
572 auto titleHeight = geometryNode->GetFrameSize().Height();
573 float offsetY = 0.0f;
574 float dividerOffset = 2.0f;
575 if (!NearZero(subtitleHeight)) {
576 offsetY = (doubleLineTitleBarHeight_ - titleHeight - subtitleHeight - navTitleSpaceVertical_) / dividerOffset;
577 } else {
578 navTitleSpaceVertical_ = 0.0f;
579 offsetY = (singleLineTitleHeight_ - titleHeight) / dividerOffset;
580 }
581 // navDestination title bar
582 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
583 TitleBarParentType::NAV_DESTINATION) {
584 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
585 CHECK_NULL_VOID(navDestination);
586 auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
587 OffsetF titleOffset = OffsetF(0.0f, 0.0f);
588 // add sdk 9 compatible
589 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
590 if (showBackButton_) {
591 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
592 static_cast<float>(
593 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M).ConvertToPx()));
594 titleOffset = OffsetF(offsetXResult, offsetY);
595 geometryNode->SetMarginFrameOffset(titleOffset);
596 titleWrapper->Layout();
597 return;
598 }
599 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
600 static_cast<float>(maxPaddingStart_.ConvertToPx()));
601 titleOffset = OffsetF(offsetXResult, offsetY);
602 geometryNode->SetMarginFrameOffset(titleOffset);
603 titleWrapper->Layout();
604 return;
605 }
606 if (showBackButton_) {
607 auto offsetX = isCustom ? (paddingLeft_ + navBackIconWidth_ + navButtonPadding_) :
608 (paddingLeft_ + navBackIconWidth_ + navHorizontalMargin_);
609 offsetY = isCustom ? 0.0f : offsetY;
610 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
611 titleOffset = OffsetF(offsetXResult, offsetY);
612 geometryNode->SetMarginFrameOffset(titleOffset);
613 titleWrapper->Layout();
614 return;
615 }
616 auto offsetX = isCustom ? 0.0f : paddingLeft_;
617 offsetY = isCustom ? 0.0f : offsetY;
618 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
619 titleOffset = OffsetF(offsetXResult, offsetY);
620 geometryNode->SetMarginFrameOffset(titleOffset);
621 titleWrapper->Layout();
622 return;
623 }
624
625 // navBar title bar
626 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
627 CHECK_NULL_VOID(navBarNode);
628 auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
629 // full mode
630 if (!isCustom) {
631 float dividerOffset = 2.0f;
632 if (!NearZero(subtitleHeight)) {
633 offsetY = (doubleLineTitleBarHeight_ - titleHeight -
634 subtitleHeight - navTitleSpaceVertical_) / dividerOffset;
635 } else {
636 navTitleSpaceVertical_ = 0.0f;
637 offsetY = (singleLineTitleHeight_ - titleHeight) / dividerOffset;
638 }
639 }
640 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
641 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
642 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
643 auto offsetX = maxPaddingStart_.ConvertToPx();
644 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
645 geometryNode->SetMarginFrameOffset(OffsetF { offsetX, offsetY });
646 titleWrapper->Layout();
647 return;
648 }
649 auto offsetX = (defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
650 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
651 geometryNode->SetMarginFrameOffset(OffsetF {offsetX, offsetY});
652 titleWrapper->Layout();
653 return;
654 }
655 // NavigationCustomTitle and Custom builder layout margin is (0, 0);
656 offsetY = isCustom ? 0 : offsetY;
657 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
658 auto offsetX = isCustom ? 0.0f : paddingLeft_;
659 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
660 OffsetF titleOffset = OffsetF(offsetX, offsetY);
661 geometryNode->SetMarginFrameOffset(titleOffset);
662 titleWrapper->Layout();
663 return;
664 }
665
666 auto offsetX = isCustom ? (paddingLeft_ + navBackIconWidth_ + navButtonPadding_) :
667 (paddingLeft_ + navBackIconWidth_ + navHorizontalMargin_);
668 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
669 OffsetF offset = OffsetF(offsetX, offsetY);
670 geometryNode->SetMarginFrameOffset(offset);
671 titleWrapper->Layout();
672 return;
673 }
674
675 float offsetX = paddingLeft_;
676 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
677 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
678 offsetY = GetFullModeTitleOffsetY(titleHeight, subtitleHeight, titleBarGeometryNode);
679 }
680 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
681 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
682 offsetX = maxPaddingStart_.ConvertToPx();
683 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
684 geometryNode->SetMarginFrameOffset(OffsetF { offsetX, menuHeight_ + offsetY });
685 titleWrapper->Layout();
686 return;
687 }
688 // full mode
689 if (isCustom) {
690 // custom title margin is (0.0f, menuHeight_)
691 auto customOffsetY = NearZero(menuWidth_) ? 0.0f : menuHeight_;
692 float customOffsetX = 0.0f;
693 customOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, customOffsetX);
694 geometryNode->SetMarginFrameOffset(OffsetF { customOffsetX, customOffsetY});
695 titleWrapper->Layout();
696 return;
697 }
698 // fixed white space menuHeight
699 OffsetF titleOffset = OffsetF(0.0f, 0.0f);
700 titleOffset = OffsetF(offsetX, menuHeight_ + offsetY);
701 geometryNode->SetMarginFrameOffset(titleOffset);
702 titleWrapper->Layout();
703 return;
704 }
705
706 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
707 CHECK_NULL_VOID(titlePattern);
708 if (isCustom) {
709 // customBuilder and NavigationCustomTitle offset is (0.0f, menuHeight_)
710 auto customOffsetY = NearZero(menuWidth_) ? 0.0f : menuHeight_;
711 auto customOffsetX = 0.0f;
712 customOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, customOffsetX);
713 geometryNode->SetMarginFrameOffset(OffsetF { customOffsetX, customOffsetY});
714 titleWrapper->Layout();
715 return;
716 }
717 auto title = AceType::DynamicCast<FrameNode>(titleNode);
718 CHECK_NULL_VOID(title);
719 if (isInitialTitle_) {
720 auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
721 if (!textLayoutProperty) {
722 // current title mode is Navigation common title
723 OffsetF titleOffset = OffsetF(offsetX, menuHeight_+ offsetY);
724 geometryNode->SetMarginFrameOffset(titleOffset);
725 titleWrapper->Layout();
726 return;
727 }
728 MeasureContext context;
729 context.textContent = textLayoutProperty->GetContentValue();
730 context.fontSize = titleFontSize_;
731 #ifdef ENABLE_ROSEN_BACKEND
732 minTitleHeight_ = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(context).Height());
733 #else
734 minTitleHeight_ = 0.0;
735 #endif
736 initialTitleOffsetY_ = menuHeight_ + offsetY;
737 isInitialTitle_ = false;
738 auto titleOffset = OffsetF(offsetX, initialTitleOffsetY_);
739 titlePattern->SetCurrentTitleOffsetY(initialTitleOffsetY_);
740 geometryNode->SetMarginFrameOffset(titleOffset);
741 titleWrapper->Layout();
742 return;
743 }
744
745 if (NearZero(titlePattern->GetTempTitleOffsetY())) {
746 initialTitleOffsetY_ = menuHeight_ + offsetY;
747 titlePattern->SetCurrentTitleOffsetY(initialTitleOffsetY_);
748 auto titleOffset = OffsetF(offsetX, initialTitleOffsetY_);
749 geometryNode->SetMarginFrameOffset(titleOffset);
750 titleWrapper->Layout();
751 return;
752 }
753 auto overDragOffset = titlePattern->GetOverDragOffset();
754 auto titleOffset = OffsetF(offsetX, titlePattern->GetTempTitleOffsetY() + overDragOffset / 6.0f);
755 titlePattern->SetCurrentTitleOffsetY(titleOffset.GetY());
756 geometryNode->SetMarginFrameOffset(titleOffset);
757 titleWrapper->Layout();
758 }
759
LayoutSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float titleHeight)760 void TitleBarLayoutAlgorithm::LayoutSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
761 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float titleHeight)
762 {
763 auto subtitleNode = titleBarNode->GetSubtitle();
764 CHECK_NULL_VOID(subtitleNode);
765 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
766 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
767 CHECK_NULL_VOID(subtitleWrapper);
768 auto geometryNode = subtitleWrapper->GetGeometryNode();
769 auto titleBarGeometryNode = titleBarNode->GetGeometryNode();
770 CHECK_NULL_VOID(titleBarGeometryNode);
771
772 auto subtitleHeight = geometryNode->GetFrameSize().Height();
773 float offsetY = 0.0f;
774 float dividerOffset = 2.0f;
775 if (!NearZero(titleHeight)) {
776 offsetY = (doubleLineTitleBarHeight_ - titleHeight -
777 subtitleHeight - navTitleSpaceVertical_) / dividerOffset + titleHeight + navTitleSpaceVertical_;
778 } else {
779 navTitleSpaceVertical_ = 0.0f;
780 offsetY = (singleLineTitleHeight_ - subtitleHeight) / dividerOffset;
781 }
782 // navDestination title bar
783 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
784 TitleBarParentType::NAV_DESTINATION) {
785 OffsetF subTitleOffset = OffsetF(0.0f, 0.0f);
786 // subtitle doesn't support custom title
787 if (showBackButton_) {
788 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
789 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
790 static_cast<float>(
791 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M).ConvertToPx()));
792 subTitleOffset = OffsetF(offsetXResult, offsetY);
793 geometryNode->SetMarginFrameOffset(subTitleOffset);
794 } else {
795 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode,
796 paddingLeft_ + navBackIconWidth_ + navHorizontalMargin_);
797 subTitleOffset = OffsetF(offsetXResult, offsetY);
798 geometryNode->SetMarginFrameOffset(subTitleOffset);
799 }
800 subtitleWrapper->Layout();
801 return;
802 }
803
804 auto offsetXResult = ChangeOffsetByDirection(layoutWrapper, geometryNode, paddingLeft_);
805 subTitleOffset = OffsetF(offsetXResult, offsetY);
806 geometryNode->SetMarginFrameOffset(subTitleOffset);
807 subtitleWrapper->Layout();
808 return;
809 }
810
811 // navBar title bar
812 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
813 float offsetX = 0.0f;
814 offsetX = paddingLeft_;
815 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
816 auto titleOffsetY = GetFullModeTitleOffsetY(titleHeight, subtitleHeight, titleBarGeometryNode);
817 offsetY = titleOffsetY + titleHeight + navTitleSpaceVertical_;
818 }
819 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
820 initialSubtitleOffsetY_ = menuHeight_ + offsetY;
821 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
822 if (isInitialSubtitle_) {
823 isInitialSubtitle_ = false;
824 OffsetF titleOffset = OffsetF(offsetX, initialSubtitleOffsetY_);
825 geometryNode->SetMarginFrameOffset(titleOffset);
826 subtitleWrapper->Layout();
827 return;
828 }
829
830 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
831 CHECK_NULL_VOID(titlePattern);
832 if (NearZero(titlePattern->GetTempTitleOffsetY())) {
833 OffsetF titleOffset = OffsetF(offsetX, initialSubtitleOffsetY_);
834 geometryNode->SetMarginFrameOffset(titleOffset);
835 subtitleWrapper->Layout();
836 return;
837 }
838 auto overDragOffset = titlePattern->GetOverDragOffset();
839 OffsetF titleOffset = OffsetF(offsetX, titlePattern->GetTempSubTitleOffsetY() + overDragOffset / 6.0f);
840 geometryNode->SetMarginFrameOffset(titleOffset);
841 subtitleWrapper->Layout();
842 return;
843 }
844 // full mode
845 OffsetF titleOffset = OffsetF(offsetX, initialSubtitleOffsetY_);
846 geometryNode->SetMarginFrameOffset(titleOffset);
847 subtitleWrapper->Layout();
848 return;
849 }
850 // mini mode + hideBackButton true
851 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
852 auto offsetX = paddingLeft_;
853 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
854 OffsetF titleOffset = OffsetF(offsetX, offsetY);
855 geometryNode->SetMarginFrameOffset(titleOffset);
856 subtitleWrapper->Layout();
857 return;
858 }
859 float occupiedWidth = 0.0f;
860 // mini mode + back button
861 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
862 occupiedWidth = static_cast<float>((maxPaddingStart_ + BACK_BUTTON_ICON_SIZE +
863 NAV_HORIZONTAL_MARGIN_M).ConvertToPx());
864 } else {
865 occupiedWidth = paddingLeft_ + navBackIconWidth_ + navHorizontalMargin_;
866 }
867 auto miniOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, occupiedWidth);
868 OffsetF offset = OffsetF(miniOffsetX, offsetY);
869 geometryNode->SetMarginFrameOffset(offset);
870 subtitleWrapper->Layout();
871 }
872
LayoutMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)873 void TitleBarLayoutAlgorithm::LayoutMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
874 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
875 {
876 auto menuNode = titleBarNode->GetMenu();
877 CHECK_NULL_VOID(menuNode);
878 auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
879 auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
880 CHECK_NULL_VOID(menuWrapper);
881 auto geometryNode = menuWrapper->GetGeometryNode();
882 auto menuWidth = geometryNode->GetMarginFrameSize().Width();
883 auto maxWidth = geometryNode->GetParentLayoutConstraint()->maxSize.Width();
884 maxWidth = WidthAfterAvoidMenubar(titleBarNode, maxWidth);
885 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(titleBarNode->GetParent());
886 CHECK_NULL_VOID(nodeBase);
887 bool isCustomMenu = nodeBase->GetPrevMenuIsCustomValue(false);
888 auto currentOffsetX = maxWidth - menuWidth - defaultPaddingStart_.ConvertToPx();
889 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
890 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
891 auto overDragOffset = titlePattern->GetOverDragOffset();
892 auto menuOffsetY = isCustomMenu ? 0 : (SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() - menuHeight_) / 2;
893 // custom menu width has no right padding
894 float offsetX = 0.0f;
895 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
896 offsetX = isCustomMenu ? maxWidth - menuWidth
897 : (maxWidth - menuWidth - paddingRight_);
898 } else {
899 offsetX = isCustomMenu ? maxWidth - menuWidth
900 : (maxWidth - menuWidth - static_cast<float>(maxPaddingEnd_.ConvertToPx()) +
901 BUTTON_PADDING.ConvertToPx());
902 }
903 currentOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, currentOffsetX);
904 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
905 geometryNode->SetMarginFrameOffset(OffsetF { currentOffsetX,
906 menuOffsetY + overDragOffset / MENU_OFFSET_RATIO });
907 menuWrapper->Layout();
908 return;
909 }
910 offsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, offsetX);
911 OffsetF menuOffset(offsetX, menuOffsetY + overDragOffset / MENU_OFFSET_RATIO);
912 geometryNode->SetMarginFrameOffset(menuOffset);
913 menuWrapper->Layout();
914 return;
915 }
916 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
917 auto totalHeight = NearZero(subtitleHeight) ? SINGLE_LINE_TITLEBAR_HEIGHT : DOUBLE_LINE_TITLEBAR_HEIGHT;
918 geometryNode->SetMarginFrameOffset(OffsetF { currentOffsetX, (totalHeight.ConvertToPx() - menuHeight_) / 2 });
919 menuWrapper->Layout();
920 return;
921 }
922 // custom menu doesn't have top padding. if menu isn't custom, menu items has top padding
923 auto menuOffsetY = isCustomMenu ? 0.0f : (SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() - menuHeight_) / 2;
924 auto menuOffsetX = maxWidth - menuWidth;
925 // custom menu doesn't have right padding. if menu isn't custom, menu items has right padding
926 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
927 menuOffsetX =
928 isCustomMenu ? menuOffsetX : (menuOffsetX - paddingRight_);
929 } else {
930 menuOffsetX =
931 isCustomMenu ? menuOffsetX : (menuOffsetX - maxPaddingEnd_.ConvertToPx() + BUTTON_PADDING.ConvertToPx());
932 }
933 menuOffsetX = ChangeOffsetByDirection(layoutWrapper, geometryNode, menuOffsetX);
934 OffsetF menuOffset(menuOffsetX, menuOffsetY);
935 geometryNode->SetMarginFrameOffset(menuOffset);
936 menuWrapper->Layout();
937 }
938
939 // set variables from theme
InitializeTheme(const RefPtr<TitleBarNode> & titleBarNode,const SizeF & titleBarSize)940 void TitleBarLayoutAlgorithm::InitializeTheme(const RefPtr<TitleBarNode>& titleBarNode, const SizeF& titleBarSize)
941 {
942 auto theme = NavigationGetTheme();
943 CHECK_NULL_VOID(theme);
944 maxPaddingStart_ = theme->GetMaxPaddingStart();
945 maxPaddingEnd_ = theme->GetMaxPaddingEnd();
946 menuHeight_ = theme->GetHeight().ConvertToPx();
947 defaultPaddingStart_ = theme->GetDefaultPaddingStart();
948 iconSize_ = theme->GetMenuIconSize();
949 titleFontSize_ = theme->GetTitleFontSize();
950 menuCompPadding_ = theme->GetCompPadding();
951 iconBackgroundWidth_ = theme->GetIconBackgroundWidth();
952 backButtonWidth_ = theme->GetBackButtonWidth();
953 backButtonHeight_ = theme->GetBackButtonHeight();
954 paddingTopTwolines_ = theme->GetPaddingTopTwolines();
955 titleSpaceVertical_ = theme->GetTitleSpaceVertical();
956 backIconWidth_ = theme->GetIconWidth();
957 backIconHeight_ = theme->GetIconHeight();
958 singleLineTitleHeight_ = static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
959 doubleLineTitleBarHeight_ = static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
960 navTitleSpaceVertical_ = 0.0f;
961 paddingLeft_ = maxPaddingStart_.ConvertToPx();
962 navBackIconWidth_ = BACK_BUTTON_ICON_SIZE.ConvertToPx();
963 navButtonPadding_ = BUTTON_PADDING.ConvertToPx();
964 navHorizontalMargin_ = NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
965 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
966 doubleLineTitleBarHeight_ = static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
967 navTitleSpaceVertical_ = static_cast<float>(titleSpaceVertical_.ConvertToPx());
968 CHECK_NULL_VOID(titleBarNode);
969 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
970 CHECK_NULL_VOID(titlePattern);
971 auto options = titlePattern->GetTitleBarOptions();
972 auto paddingStart = options.brOptions.paddingStart;
973 if (paddingStart.has_value()) {
974 paddingLeft_ = ParseCalcDimensionToPx(paddingStart, titleBarSize);
975 } else {
976 paddingLeft_ = theme->GetMarginLeft().ConvertToPx();
977 }
978 auto paddingEnd = options.brOptions.paddingEnd;
979 if (paddingEnd.has_value()) {
980 paddingRight_ = ParseCalcDimensionToPx(paddingEnd, titleBarSize);
981 } else {
982 paddingRight_ = theme->GetMarginRight().ConvertToPx();
983 }
984 navBackIconWidth_ = backIconWidth_.ConvertToPx();
985 navButtonPadding_ = (MENU_BUTTON_PADDING + MENU_BUTTON_PADDING).ConvertToPx();
986 navHorizontalMargin_ = navButtonPadding_ + menuCompPadding_.ConvertToPx();
987 }
988 }
989
Measure(LayoutWrapper * layoutWrapper)990 void TitleBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
991 {
992 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
993 CHECK_NULL_VOID(titleBarNode);
994 auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
995 CHECK_NULL_VOID(layoutProperty);
996 const auto& constraint = layoutProperty->GetLayoutConstraint();
997 CHECK_NULL_VOID(constraint);
998 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
999 auto size = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT, true);
1000 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
1001 MinusPaddingToSize(padding, size);
1002 InitializeTheme(titleBarNode, size);
1003 do {
1004 if (layoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) !=
1005 TitleBarParentType::NAV_DESTINATION) {
1006 break;
1007 }
1008 auto navDestinationNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetParent());
1009 CHECK_NULL_BREAK(navDestinationNode);
1010 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestinationNode->GetPattern());
1011 CHECK_NULL_BREAK(navDestinationPattern);
1012 showBackButton_ = navDestinationPattern->GetBackButtonState();
1013 } while (false);
1014 MeasureBackButton(layoutWrapper, titleBarNode, layoutProperty);
1015 MeasureMenu(layoutWrapper, titleBarNode, layoutProperty);
1016 auto titleMaxWidth = GetTitleWidth(titleBarNode, layoutProperty, size);
1017 titleMaxWidth = WidthAfterAvoidMenubar(titleBarNode, titleMaxWidth);
1018 MeasureSubtitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
1019 MeasureTitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
1020 titlePattern->SetCurrentTitleBarHeight(size.Height());
1021 layoutWrapper->GetGeometryNode()->SetFrameSize(size);
1022 }
1023
Layout(LayoutWrapper * layoutWrapper)1024 void TitleBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1025 {
1026 auto pipeline = PipelineContext::GetCurrentContext();
1027 if (pipeline && pipeline->GetInstallationFree()) {
1028 //TitleBar run measure again during Layout in atomic service for avoiding menuBar
1029 Measure(layoutWrapper);
1030 }
1031 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
1032 CHECK_NULL_VOID(titleBarNode);
1033 auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
1034 CHECK_NULL_VOID(layoutProperty);
1035 LayoutBackButton(layoutWrapper, titleBarNode, layoutProperty);
1036
1037 float subtitleHeight = 0.0f;
1038 auto subtitleNode = titleBarNode->GetSubtitle();
1039 if (subtitleNode) {
1040 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
1041 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1042 CHECK_NULL_VOID(subtitleWrapper);
1043 auto geometryNode = subtitleWrapper->GetGeometryNode();
1044 subtitleHeight = geometryNode->GetFrameSize().Height();
1045 }
1046 LayoutTitle(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
1047
1048 float titleHeight = 0.0f;
1049 auto titleNode = titleBarNode->GetTitle();
1050 if (titleNode) {
1051 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
1052 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1053 CHECK_NULL_VOID(titleWrapper);
1054 auto geometryNode = titleWrapper->GetGeometryNode();
1055 titleHeight = geometryNode->GetFrameSize().Height();
1056 }
1057 LayoutSubtitle(layoutWrapper, titleBarNode, layoutProperty, titleHeight);
1058
1059 LayoutMenu(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
1060 }
1061
ChangeOffsetByDirection(LayoutWrapper * layoutWrapper,const RefPtr<NG::GeometryNode> & childGeometryNode,float offsetX) const1062 float TitleBarLayoutAlgorithm::ChangeOffsetByDirection(LayoutWrapper* layoutWrapper,
1063 const RefPtr<NG::GeometryNode>& childGeometryNode, float offsetX) const
1064 {
1065 CHECK_NULL_RETURN(layoutWrapper, offsetX);
1066 CHECK_NULL_RETURN(childGeometryNode, offsetX);
1067 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
1068 auto geometryNode = layoutWrapper->GetGeometryNode();
1069 CHECK_NULL_RETURN(geometryNode, offsetX);
1070 auto parentWidth = geometryNode->GetFrameSize().Width();
1071 offsetX = parentWidth - offsetX - childGeometryNode->GetFrameSize().Width();
1072 }
1073 return offsetX;
1074 }
1075
ParseCalcDimensionToPx(const std::optional<CalcDimension> & value,const SizeF & titleBarSize)1076 float TitleBarLayoutAlgorithm::ParseCalcDimensionToPx(const std::optional<CalcDimension>& value,
1077 const SizeF& titleBarSize)
1078 {
1079 float result = 0.0f;
1080 if (value.value().Unit() == DimensionUnit::PERCENT) {
1081 result = value.value().Value() * titleBarSize.Width();
1082 } else {
1083 result = value.value().ConvertToPx();
1084 }
1085 return result;
1086 }
1087 } // namespace OHOS::Ace::NG
1088