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