1 /*
2 * Copyright (c) 2022 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/navigation/nav_bar_node.h"
27 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
28 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
29 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
30 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
31 #include "core/components_ng/pattern/navigation/title_bar_node.h"
32 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
33 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
34 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
35 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
36 #include "core/components_ng/pattern/text/text_layout_property.h"
37 #include "core/components_ng/property/layout_constraint.h"
38 #include "core/components_ng/property/measure_property.h"
39 #include "core/components_ng/property/measure_utils.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 } // namespace
49
MeasureBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)50 void TitleBarLayoutAlgorithm::MeasureBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
51 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
52 {
53 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
54 CHECK_NULL_VOID(backButtonNode);
55 auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
56 auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
57 CHECK_NULL_VOID(backButtonWrapper);
58 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
59 // navDestination title bar
60 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
61 TitleBarParentType::NAV_DESTINATION) {
62 if (!showBackButton_) {
63 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
64 auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty();
65 PaddingProperty padding;
66 padding.SetEdges(CalcLength(Dimension(0.0f, DimensionUnit::VP)));
67 backButtonLayoutProperty->UpdatePadding(padding);
68 backButtonWrapper->Measure(constraint);
69 return;
70 }
71 auto buttonLayoutProperty = backButtonNode->GetLayoutProperty();
72 PaddingProperty padding;
73 padding.SetEdges(CalcLength(BUTTON_PADDING));
74 buttonLayoutProperty->UpdatePadding(padding);
75 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
76 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()),
77 static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()));
78 backButtonWrapper->Measure(constraint);
79 return;
80 }
81 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()),
82 static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
83 backButtonWrapper->Measure(constraint);
84 return;
85 }
86
87 // navBar title bar
88 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
89 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
90 backButtonWrapper->Measure(constraint);
91 return;
92 }
93
94 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
95 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
96 backButtonWrapper->Measure(constraint);
97 return;
98 }
99
100 constraint.selfIdealSize = OptionalSizeF(
101 static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()), static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
102 backButtonWrapper->Measure(constraint);
103 }
104
GetTitleWidth(const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize)105 float TitleBarLayoutAlgorithm::GetTitleWidth(const RefPtr<TitleBarNode>& titleBarNode,
106 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize)
107 {
108 // navDestination title bar
109 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
110 TitleBarParentType::NAV_DESTINATION) {
111
112 // nav destination custom title
113 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
114 CHECK_NULL_RETURN(navDestination, 0.0f);
115 auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
116 float occupiedWidth = 0.0f;
117 // left padding
118 if (showBackButton_) {
119 occupiedWidth += isCustom ? (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() :
120 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
121 } else {
122 occupiedWidth += isCustom ? 0.0f : maxPaddingStart_.ConvertToPx();
123 }
124 // right padding
125 occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
126 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
127 }
128 // navBar title bar
129 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
130 CHECK_NULL_RETURN(navBarNode, 0.0f);
131 float occupiedWidth = 0.0f;
132 auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
133 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
134 // mini mode
135 if (titleBarLayoutProperty->GetHideBackButtonValue(false)) {
136 occupiedWidth += isCustom ? 0 : maxPaddingStart_.ConvertToPx();
137 } else {
138 occupiedWidth += (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE).ConvertToPx();
139 // custom right padding is the back button hot zone
140 occupiedWidth += isCustom ? BUTTON_PADDING.ConvertToPx() : NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
141 }
142 // compute right padding
143 if (NearZero(menuWidth_)) {
144 occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
145 } else {
146 occupiedWidth += menuWidth_;
147 if (!navBarNode->GetPrevMenuIsCustomValue(false)) {
148 occupiedWidth += defaultPaddingStart_.ConvertToPx();
149 occupiedWidth += isCustom ? 0.0f : NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
150 }
151 }
152 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
153 }
154 // left padding of full and free mode
155 occupiedWidth = isCustom ? 0.0f : maxPaddingStart_.ConvertToPx();
156 // right padding of full mode
157 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FULL
158 || isCustom) {
159 occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
160 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
161 }
162 // right padding of free mode
163 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
164 if (titleBarPattern && titleBarPattern->IsFreeTitleUpdated() &&
165 titleBarPattern->GetTempTitleOffsetY() < menuHeight_) {
166 if (NearZero(menuWidth_)) {
167 occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
168 } else {
169 occupiedWidth += menuWidth_;
170 if (!navBarNode->GetPrevMenuIsCustomValue(false)) {
171 occupiedWidth += defaultPaddingStart_.ConvertToPx();
172 occupiedWidth += isCustom ? 0.0f : NAV_HORIZONTAL_MARGIN_L.ConvertToPx();
173 }
174 }
175 } else {
176 occupiedWidth += isCustom ? 0.0f : maxPaddingEnd_.ConvertToPx();
177 }
178 return titleBarSize.Width() < occupiedWidth ? 0.0f : titleBarSize.Width() - occupiedWidth;
179 }
180
MeasureSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)181 void TitleBarLayoutAlgorithm::MeasureSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
182 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
183 {
184 auto subtitleNode = titleBarNode->GetSubtitle();
185 CHECK_NULL_VOID(subtitleNode);
186 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
187 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
188 CHECK_NULL_VOID(subtitleWrapper);
189 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
190 constraint.maxSize.SetHeight(titleBarSize.Height());
191 constraint.maxSize.SetWidth(maxWidth);
192 subtitleWrapper->Measure(constraint);
193 }
194
MeasureTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float maxWidth)195 void TitleBarLayoutAlgorithm::MeasureTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
196 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float maxWidth)
197 {
198 auto titleNode = titleBarNode->GetTitle();
199 CHECK_NULL_VOID(titleNode);
200 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
201 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
202 CHECK_NULL_VOID(titleWrapper);
203 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
204 constraint.maxSize.SetHeight(titleBarSize.Height());
205
206 // navDestination title bar
207 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
208 TitleBarParentType::NAV_DESTINATION) {
209 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
210 CHECK_NULL_VOID(navDestination);
211 auto isCustomTitle = navDestination->GetPrevTitleIsCustomValue(false);
212 if (isCustomTitle) {
213 constraint.parentIdealSize.SetWidth(maxWidth);
214 constraint.maxSize.SetWidth(maxWidth);
215 // custom title must be single line title
216
217 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
218 constraint.maxSize.SetHeight(titleBarSize.Height());
219 titleWrapper->Measure(constraint);
220 return;
221 }
222 constraint.maxSize.SetWidth(maxWidth);
223 if (!titleBarNode->GetSubtitle()) {
224 constraint.maxSize.SetHeight(titleBarSize.Height());
225 titleWrapper->Measure(constraint);
226 return;
227 }
228 auto subtitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
229 auto subtitleHeight = subtitle->GetGeometryNode()->GetFrameSize().Height();
230 constraint.maxSize.SetHeight(titleBarSize.Height() - subtitleHeight);
231 titleWrapper->Measure(constraint);
232 return;
233 }
234 // NavigationCustomTitle: Custom title + height
235 if (titleBarLayoutProperty->HasTitleHeight()) {
236 constraint.parentIdealSize.SetWidth(maxWidth);
237 constraint.maxSize.SetWidth(maxWidth);
238 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
239 constraint.maxSize.SetHeight(titleBarSize.Height());
240 titleWrapper->Measure(constraint);
241 return;
242 }
243 // subTitle
244 auto titleMode = titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE);
245 auto subTitle = titleBarNode->GetSubtitle();
246 if (subTitle) {
247 // common title
248 auto index = titleBarNode->GetChildIndexById(subTitle->GetId());
249 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
250 CHECK_NULL_VOID(subtitleWrapper);
251 auto geometryNode = subtitleWrapper->GetGeometryNode();
252 // mini mode double title height is 56vp, free/full mode is 82vp
253 auto maxTitleHeight = titleMode == NavigationTitleMode::MINI ? SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() :
254 DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
255 constraint.maxSize.SetWidth(maxWidth);
256 constraint.maxSize.SetHeight(maxTitleHeight - geometryNode->GetFrameSize().Height());
257 titleWrapper->Measure(constraint);
258 return;
259 }
260 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
261 CHECK_NULL_VOID(navBarNode);
262 auto isCustomTitle = navBarNode->GetPrevTitleIsCustomValue(false);
263 // single line title and mini mode
264 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
265 if (isCustomTitle) {
266 constraint.parentIdealSize.SetWidth(maxWidth);
267 constraint.maxSize.SetWidth(maxWidth);
268 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
269 constraint.maxSize.SetHeight(titleBarSize.Height());
270 } else {
271 constraint.maxSize.SetWidth(maxWidth);
272 constraint.maxSize.SetHeight(titleBarSize.Height());
273 }
274 titleWrapper->Measure(constraint);
275 return;
276 }
277 // custom builder
278 if (isCustomTitle) {
279 constraint.parentIdealSize.SetWidth(maxWidth);
280 constraint.maxSize.SetWidth(maxWidth);
281 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
282 constraint.parentIdealSize.SetHeight(titleBarSize.Height());
283 } else {
284 auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
285 // if has menu and menu is not custom, max height is single line height
286 auto maxHeight = NearZero(menuWidth_) ? titleBarSize.Height()
287 : isCustomMenu ? titleBarSize.Height() - menuHeight_
288 : SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx();
289 constraint.parentIdealSize.SetHeight(maxHeight);
290 constraint.maxSize.SetHeight(maxHeight);
291 }
292 titleWrapper->Measure(constraint);
293 return;
294 }
295 // resourceStr title
296 constraint.maxSize.SetWidth(maxWidth);
297 constraint.maxSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
298 titleWrapper->Measure(constraint);
299 }
300
MeasureMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)301 void TitleBarLayoutAlgorithm::MeasureMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
302 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
303 {
304 auto menuNode = titleBarNode->GetMenu();
305 CHECK_NULL_VOID(menuNode);
306 auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
307 auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
308 CHECK_NULL_VOID(menuWrapper);
309 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
310 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
311 CHECK_NULL_VOID(navBarNode);
312 auto navBarPattern = AceType::DynamicCast<NavBarPattern>(navBarNode->GetPattern());
313 CHECK_NULL_VOID(navBarPattern);
314 auto maxMenu = navBarPattern->GetMaxMenuNum();
315 auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
316 if (isCustomMenu) {
317 // custom title can't be higher than 56vp
318 constraint.parentIdealSize.SetHeight(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx());
319 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI &&
320 !titleBarLayoutProperty->HasTitleHeight()) {
321 auto maxWidth = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * maxMenu +
322 defaultPaddingStart_.ConvertToPx();
323 constraint.parentIdealSize.SetWidth(maxWidth);
324 }
325 menuWrapper->Measure(constraint);
326 menuWidth_ = menuWrapper->GetGeometryNode()->GetFrameSize().Width();
327 menuHeight_ = menuWrapper->GetGeometryNode()->GetFrameSize().Height();
328 return;
329 }
330 auto menuItemNum = static_cast<int32_t>(menuNode->GetChildren().size());
331 if (menuItemNum >= maxMenu) {
332 menuWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * maxMenu;
333 } else {
334 menuWidth_ = static_cast<float>(MENU_ITEM_SIZE.ConvertToPx()) * menuItemNum;
335 }
336 constraint.selfIdealSize = OptionalSizeF(menuWidth_, menuHeight_);
337 menuWrapper->Measure(constraint);
338 }
339
LayoutBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)340 void TitleBarLayoutAlgorithm::LayoutBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
341 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
342 {
343 auto backButtonNode = titleBarNode->GetBackButton();
344 CHECK_NULL_VOID(backButtonNode);
345 auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
346 auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
347 CHECK_NULL_VOID(backButtonWrapper);
348 auto geometryNode = backButtonWrapper->GetGeometryNode();
349
350 // navDestination title bar
351 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
352 TitleBarParentType::NAV_DESTINATION) {
353 if (!showBackButton_) {
354 SizeF size = SizeF(0.0f, 0.0f);
355 geometryNode->SetFrameSize(size);
356 backButtonWrapper->Layout();
357 return;
358 }
359 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
360 auto offsetY = (menuHeight_ - BACK_BUTTON_ICON_SIZE.ConvertToPx()) / 2;
361 geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(), offsetY });
362 backButtonWrapper->Layout();
363 return;
364 }
365 auto titleHeight = titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT);
366 auto offsetY = (titleHeight - BACK_BUTTON_SIZE) / 2;
367
368 OffsetF backButtonOffset = OffsetF(static_cast<float>((maxPaddingStart_ - BUTTON_PADDING).ConvertToPx()),
369 static_cast<float>(offsetY.ConvertToPx()));
370 geometryNode->SetMarginFrameOffset(backButtonOffset);
371 backButtonWrapper->Layout();
372 return;
373 }
374
375 // navBar title bar
376 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
377 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
378 geometryNode->SetMarginFrameOffset(backButtonOffset);
379 backButtonWrapper->Layout();
380 return;
381 }
382
383 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
384 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
385 geometryNode->SetMarginFrameOffset(backButtonOffset);
386 backButtonWrapper->Layout();
387 return;
388 }
389 auto titleHeight = titleBarLayoutProperty->GetTitleHeightValue(SINGLE_LINE_TITLEBAR_HEIGHT);
390 auto offsetY = (titleHeight - BACK_BUTTON_SIZE) / 2;
391 auto offsetX = (maxPaddingStart_ - (BACK_BUTTON_SIZE - BACK_BUTTON_ICON_SIZE) / 2).ConvertToPx();
392 OffsetF backButtonOffset = OffsetF(offsetX, static_cast<float>(offsetY.ConvertToPx()));
393 geometryNode->SetMarginFrameOffset(backButtonOffset);
394 backButtonWrapper->Layout();
395 }
396
LayoutTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)397 void TitleBarLayoutAlgorithm::LayoutTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
398 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
399 {
400 auto titleNode = titleBarNode->GetTitle();
401 CHECK_NULL_VOID(titleNode);
402 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
403 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
404 CHECK_NULL_VOID(titleWrapper);
405 auto geometryNode = titleWrapper->GetGeometryNode();
406
407 auto titleHeight = geometryNode->GetFrameSize().Height();
408 float offsetY = 0.0f;
409 if (!NearZero(subtitleHeight)) {
410 offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight - subtitleHeight) / 2;
411 } else {
412 offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight) / 2;
413 }
414 // navDestination title bar
415 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
416 TitleBarParentType::NAV_DESTINATION) {
417 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
418 CHECK_NULL_VOID(navDestination);
419 auto isCustom = navDestination->GetPrevTitleIsCustomValue(false);
420 // add sdk 9 compatible
421 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
422 if (showBackButton_) {
423 geometryNode->SetMarginFrameOffset(OffsetF {
424 static_cast<float>((maxPaddingStart_ + BACK_BUTTON_ICON_SIZE +
425 NAV_HORIZONTAL_MARGIN_M).ConvertToPx()), offsetY });
426 titleWrapper->Layout();
427 return;
428 }
429 geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(), offsetY});
430 titleWrapper->Layout();
431 return;
432 }
433 if (showBackButton_) {
434 auto offsetX = isCustom ? (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() :
435 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
436 offsetY = isCustom ? 0.0f : offsetY;
437 geometryNode->SetMarginFrameOffset(OffsetF { offsetX, offsetY });
438 titleWrapper->Layout();
439 return;
440 }
441 auto offsetX = isCustom ? 0.0f : maxPaddingStart_.ConvertToPx();
442 offsetY = isCustom ? 0.0f : offsetY;
443 OffsetF offset = OffsetF(offsetX, offsetY);
444 geometryNode->SetMarginFrameOffset(offset);
445 titleWrapper->Layout();
446 return;
447 }
448
449 // navBar title bar
450 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
451 CHECK_NULL_VOID(navBarNode);
452 auto isCustom = navBarNode->GetPrevTitleIsCustomValue(false);
453 // full mode
454 if (!isCustom) {
455 auto dividerOffset = 2;
456 if (!NearZero(subtitleHeight)) {
457 offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight -
458 subtitleHeight) / dividerOffset;
459 } else {
460 offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight) / dividerOffset;
461 }
462 }
463 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
464 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
465 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
466 geometryNode->SetMarginFrameOffset(OffsetF { maxPaddingStart_.ConvertToPx(), offsetY });
467 titleWrapper->Layout();
468 return;
469 }
470 geometryNode->SetMarginFrameOffset(OffsetF { (defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE +
471 NAV_HORIZONTAL_MARGIN_L).ConvertToPx(), offsetY});
472 titleWrapper->Layout();
473 return;
474 }
475 // NavigationCustomTitle and Custom builder layout margin is (0, 0);
476 offsetY = isCustom ? 0 : offsetY;
477 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
478 auto offsetX = isCustom ? 0.0f : (maxPaddingStart_).ConvertToPx();
479 OffsetF titleOffset = OffsetF(offsetX, offsetY);
480 geometryNode->SetMarginFrameOffset(titleOffset);
481 titleWrapper->Layout();
482 return;
483 }
484
485 auto offsetX = isCustom ? (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + BUTTON_PADDING).ConvertToPx() :
486 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L).ConvertToPx();
487 OffsetF offset = OffsetF(offsetX, offsetY);
488 geometryNode->SetMarginFrameOffset(offset);
489 titleWrapper->Layout();
490 return;
491 }
492
493 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
494 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
495 geometryNode->SetMarginFrameOffset(
496 OffsetF { maxPaddingStart_.ConvertToPx(), menuHeight_ + offsetY });
497 titleWrapper->Layout();
498 return;
499 }
500 // full mode
501 if (isCustom) {
502 // custom title margin is (0.0f, menuHeight_)
503 auto customOffsetY = NearZero(menuWidth_) ? 0.0f : menuHeight_;
504 geometryNode->SetMarginFrameOffset(OffsetF { 0.0f, customOffsetY});
505 titleWrapper->Layout();
506 } else {
507 // fixed white space menuHeight
508 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
509 menuHeight_ + offsetY);
510 geometryNode->SetMarginFrameOffset(titleOffset);
511 titleWrapper->Layout();
512 }
513 return;
514 }
515 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
516 if (isInitialTitle_) {
517 // free mode
518 if (isCustom) {
519 // customBuilder and NavigationCustomTitle offset is (0.0f, menuHeight_)
520 auto customOffsetY = NearZero(menuWidth_) ? 0.0f : menuHeight_;
521 geometryNode->SetMarginFrameOffset(OffsetF { 0.0f, customOffsetY});
522 titleWrapper->Layout();
523 return;
524 }
525 auto title = AceType::DynamicCast<FrameNode>(titleNode);
526 CHECK_NULL_VOID(title);
527
528 auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
529 if (!textLayoutProperty) {
530 // current title mode is Navigation common title
531 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
532 menuHeight_+ offsetY);
533 geometryNode->SetMarginFrameOffset(titleOffset);
534 titleWrapper->Layout();
535 return;
536 }
537 MeasureContext context;
538 context.textContent = textLayoutProperty->GetContentValue();
539 context.fontSize = titleFontSize_;
540 #ifdef ENABLE_ROSEN_BACKEND
541 minTitleHeight_ = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(context).Height());
542 #else
543 minTitleHeight_ = 0.0;
544 #endif
545 initialTitleOffsetY_ = menuHeight_ + offsetY;
546 isInitialTitle_ = false;
547 auto titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialTitleOffsetY_);
548 titlePattern->SetCurrentTitleOffsetY(initialTitleOffsetY_);
549 geometryNode->SetMarginFrameOffset(titleOffset);
550 titleWrapper->Layout();
551 return;
552 }
553
554 if (NearZero(titlePattern->GetTempTitleOffsetY())) {
555 initialTitleOffsetY_ = menuHeight_ + offsetY;
556 auto titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialTitleOffsetY_);
557 geometryNode->SetMarginFrameOffset(titleOffset);
558 titleWrapper->Layout();
559 return;
560 }
561 auto overDragOffset = titlePattern->GetOverDragOffset();
562 auto titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
563 titlePattern->GetTempTitleOffsetY() + overDragOffset / 6.0f);
564 titlePattern->SetCurrentTitleOffsetY(titleOffset.GetY());
565 geometryNode->SetMarginFrameOffset(titleOffset);
566 titleWrapper->Layout();
567 }
568
LayoutSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float titleHeight)569 void TitleBarLayoutAlgorithm::LayoutSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
570 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float titleHeight)
571 {
572 auto subtitleNode = titleBarNode->GetSubtitle();
573 CHECK_NULL_VOID(subtitleNode);
574 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
575 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
576 CHECK_NULL_VOID(subtitleWrapper);
577 auto geometryNode = subtitleWrapper->GetGeometryNode();
578
579 auto subtitleHeight = geometryNode->GetFrameSize().Height();
580 float offsetY = 0.0f;
581 if (!NearZero(titleHeight)) {
582 offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight - subtitleHeight) / 2 +
583 titleHeight;
584 } else {
585 offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - subtitleHeight) / 2;
586 }
587 // navDestination title bar
588 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
589 TitleBarParentType::NAV_DESTINATION) {
590 // subtitle doesn't support custom title
591 if (showBackButton_) {
592 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
593 geometryNode->SetMarginFrameOffset(OffsetF {
594 (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M).ConvertToPx(), offsetY });
595 } else {
596 geometryNode->SetMarginFrameOffset(OffsetF { (maxPaddingStart_ + BACK_BUTTON_ICON_SIZE
597 + NAV_HORIZONTAL_MARGIN_L).ConvertToPx(), offsetY });
598 }
599 subtitleWrapper->Layout();
600 return;
601 }
602
603 OffsetF offset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
604 geometryNode->SetMarginFrameOffset(offset);
605 subtitleWrapper->Layout();
606 return;
607 }
608
609 // navBar title bar
610 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
611 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
612 initialSubtitleOffsetY_ = menuHeight_ + offsetY;
613 if (isInitialSubtitle_) {
614 isInitialSubtitle_ = false;
615 OffsetF titleOffset =
616 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialSubtitleOffsetY_);
617 geometryNode->SetMarginFrameOffset(titleOffset);
618 subtitleWrapper->Layout();
619 return;
620 }
621
622 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
623 CHECK_NULL_VOID(titlePattern);
624 if (NearZero(titlePattern->GetTempTitleOffsetY())) {
625 OffsetF titleOffset =
626 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialSubtitleOffsetY_);
627 geometryNode->SetMarginFrameOffset(titleOffset);
628 subtitleWrapper->Layout();
629 return;
630 }
631 auto overDragOffset = titlePattern->GetOverDragOffset();
632 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
633 titlePattern->GetTempSubTitleOffsetY() + overDragOffset / 6.0f);
634 geometryNode->SetMarginFrameOffset(titleOffset);
635 subtitleWrapper->Layout();
636 return;
637 }
638 // full mode
639 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
640 menuHeight_ + offsetY);
641 geometryNode->SetMarginFrameOffset(titleOffset);
642 subtitleWrapper->Layout();
643 return;
644 }
645 // mini mode + hideBackButton true
646 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
647 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
648 geometryNode->SetMarginFrameOffset(titleOffset);
649 subtitleWrapper->Layout();
650 return;
651 }
652 Dimension occupiedWidth = Dimension(0.0f, DimensionUnit::PX);
653 // mini mode + back button
654 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
655 occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_M;
656 } else {
657 occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + NAV_HORIZONTAL_MARGIN_L;
658 }
659 OffsetF offset = OffsetF(static_cast<float>(occupiedWidth.ConvertToPx()), offsetY);
660 geometryNode->SetMarginFrameOffset(offset);
661 subtitleWrapper->Layout();
662 }
663
LayoutMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)664 void TitleBarLayoutAlgorithm::LayoutMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
665 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
666 {
667 auto menuNode = titleBarNode->GetMenu();
668 CHECK_NULL_VOID(menuNode);
669 auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
670 auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
671 CHECK_NULL_VOID(menuWrapper);
672 auto geometryNode = menuWrapper->GetGeometryNode();
673 auto menuWidth = geometryNode->GetMarginFrameSize().Width();
674 auto maxWidth = geometryNode->GetParentLayoutConstraint()->maxSize.Width();
675 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
676 auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
677 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
678 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
679 auto overDragOffset = titlePattern->GetOverDragOffset();
680 auto menuOffsetY = isCustomMenu ? 0 : (SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() - menuHeight_) / 2;
681 // custom menu width has no right padding
682 auto offsetX = isCustomMenu ? maxWidth - menuWidth
683 : (maxWidth - menuWidth - static_cast<float>(maxPaddingEnd_.ConvertToPx()) +
684 BUTTON_PADDING.ConvertToPx());
685 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
686 geometryNode->SetMarginFrameOffset(OffsetF { maxWidth - menuWidth - defaultPaddingStart_.ConvertToPx(),
687 menuOffsetY + overDragOffset / MENU_OFFSET_RATIO });
688 menuWrapper->Layout();
689 return;
690 }
691 OffsetF menuOffset(offsetX, menuOffsetY + overDragOffset / MENU_OFFSET_RATIO);
692 geometryNode->SetMarginFrameOffset(menuOffset);
693 menuWrapper->Layout();
694 return;
695 }
696 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
697 auto totalHeight = NearZero(subtitleHeight) ? SINGLE_LINE_TITLEBAR_HEIGHT : DOUBLE_LINE_TITLEBAR_HEIGHT;
698 geometryNode->SetMarginFrameOffset(OffsetF { maxWidth - menuWidth - defaultPaddingStart_.ConvertToPx(),
699 (totalHeight.ConvertToPx() - menuHeight_) / 2 });
700 menuWrapper->Layout();
701 return;
702 }
703 // custom menu doesn't have top padding. if menu isn't custom, menu items has top padding
704 auto menuOffsetY = isCustomMenu ? 0.0f : (SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx() - menuHeight_) / 2;
705 auto menuOffsetX = maxWidth - menuWidth;
706 // custom menu doesn't have right padding. if menu isn't custom, menu items has right padding
707 menuOffsetX =
708 isCustomMenu ? menuOffsetX : (menuOffsetX - maxPaddingEnd_.ConvertToPx() + BUTTON_PADDING.ConvertToPx());
709 OffsetF menuOffset(menuOffsetX, menuOffsetY);
710 geometryNode->SetMarginFrameOffset(menuOffset);
711 menuWrapper->Layout();
712 }
713
714 // set variables from theme
InitializeTheme()715 void TitleBarLayoutAlgorithm::InitializeTheme()
716 {
717 auto theme = NavigationGetTheme();
718 CHECK_NULL_VOID(theme);
719 maxPaddingStart_ = theme->GetMaxPaddingStart();
720 maxPaddingEnd_ = theme->GetMaxPaddingEnd();
721 menuHeight_ = theme->GetHeight().ConvertToPx();
722 defaultPaddingStart_ = theme->GetDefaultPaddingStart();
723 iconSize_ = theme->GetMenuIconSize();
724 titleFontSize_ = theme->GetTitleFontSize();
725 }
726
Measure(LayoutWrapper * layoutWrapper)727 void TitleBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
728 {
729 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
730 CHECK_NULL_VOID(titleBarNode);
731 auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
732 CHECK_NULL_VOID(layoutProperty);
733 const auto& constraint = layoutProperty->GetLayoutConstraint();
734 CHECK_NULL_VOID(constraint);
735 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
736 auto size = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT, true);
737 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
738 MinusPaddingToSize(padding, size);
739 InitializeTheme();
740 do {
741 if (layoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) !=
742 TitleBarParentType::NAV_DESTINATION) {
743 break;
744 }
745 auto navDestinationNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetParent());
746 CHECK_NULL_BREAK(navDestinationNode);
747 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(navDestinationNode->GetPattern());
748 CHECK_NULL_BREAK(navDestinationPattern);
749 showBackButton_ = navDestinationPattern->GetBackButtonState();
750 } while (false);
751 MeasureBackButton(layoutWrapper, titleBarNode, layoutProperty);
752 MeasureMenu(layoutWrapper, titleBarNode, layoutProperty);
753 auto titleMaxWidth = GetTitleWidth(titleBarNode, layoutProperty, size);
754 MeasureSubtitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
755 MeasureTitle(layoutWrapper, titleBarNode, layoutProperty, size, titleMaxWidth);
756 titlePattern->SetCurrentTitleBarHeight(size.Height());
757 layoutWrapper->GetGeometryNode()->SetFrameSize(size);
758 }
759
Layout(LayoutWrapper * layoutWrapper)760 void TitleBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
761 {
762 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
763 CHECK_NULL_VOID(titleBarNode);
764 auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
765 CHECK_NULL_VOID(layoutProperty);
766 LayoutBackButton(layoutWrapper, titleBarNode, layoutProperty);
767
768 float subtitleHeight = 0.0f;
769 auto subtitleNode = titleBarNode->GetSubtitle();
770 if (subtitleNode) {
771 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
772 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
773 CHECK_NULL_VOID(subtitleWrapper);
774 auto geometryNode = subtitleWrapper->GetGeometryNode();
775 subtitleHeight = geometryNode->GetFrameSize().Height();
776 }
777 LayoutTitle(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
778
779 float titleHeight = 0.0f;
780 auto titleNode = titleBarNode->GetTitle();
781 if (titleNode) {
782 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
783 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
784 CHECK_NULL_VOID(titleWrapper);
785 auto geometryNode = titleWrapper->GetGeometryNode();
786 titleHeight = geometryNode->GetFrameSize().Height();
787 }
788 LayoutSubtitle(layoutWrapper, titleBarNode, layoutProperty, titleHeight);
789
790 LayoutMenu(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
791 }
792
793 } // namespace OHOS::Ace::NG
794