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/ng/offset_t.h"
19 #include "base/geometry/ng/size_t.h"
20 #include "base/memory/ace_type.h"
21 #include "base/utils/measure_util.h"
22 #include "base/utils/utils.h"
23 #include "core/components/custom_paint/rosen_render_custom_paint.h"
24 #include "core/components_ng/base/frame_node.h"
25 #include "core/components_ng/pattern/navigation/nav_bar_node.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/title_bar_layout_property.h"
29 #include "core/components_ng/pattern/navigation/title_bar_node.h"
30 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
31 #include "core/components_ng/pattern/text/text_layout_property.h"
32 #include "core/components_ng/property/layout_constraint.h"
33 #include "core/components_ng/property/measure_property.h"
34 #include "core/components_ng/property/measure_utils.h"
35
36 namespace OHOS::Ace::NG {
37
38 namespace {
39 constexpr int32_t MAX_MENU_ITEMS_NUM = 3;
40 }
41
MeasureBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)42 void TitleBarLayoutAlgorithm::MeasureBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
43 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
44 {
45 auto backButtonNode = titleBarNode->GetBackButton();
46 CHECK_NULL_VOID(backButtonNode);
47 auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
48 auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
49 CHECK_NULL_VOID(backButtonWrapper);
50 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
51
52 // navDestination title bar
53 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
54 TitleBarParentType::NAV_DESTINATION) {
55 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()),
56 static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()));
57 backButtonWrapper->Measure(constraint);
58 return;
59 }
60
61 // navBar title bar
62 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
63 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
64 backButtonWrapper->Measure(constraint);
65 return;
66 }
67
68 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
69 constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
70 backButtonWrapper->Measure(constraint);
71 return;
72 }
73
74 constraint.selfIdealSize = OptionalSizeF(static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()),
75 static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()));
76 backButtonWrapper->Measure(constraint);
77 }
78
MeasureSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float menuWidth)79 void TitleBarLayoutAlgorithm::MeasureSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
80 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float menuWidth)
81 {
82 auto subtitleNode = titleBarNode->GetSubtitle();
83 CHECK_NULL_VOID(subtitleNode);
84 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
85 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
86 CHECK_NULL_VOID(subtitleWrapper);
87 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
88 constraint.maxSize.SetHeight(titleBarSize.Height());
89
90 // navDestination title bar
91 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
92 TitleBarParentType::NAV_DESTINATION) {
93 if (titleBarNode->GetBackButton()) {
94 auto occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + HORIZONTAL_MARGIN_M + maxPaddingEnd_;
95 constraint.maxSize.SetWidth(titleBarSize.Width() - static_cast<float>(occupiedWidth.ConvertToPx()));
96 subtitleWrapper->Measure(constraint);
97 return;
98 }
99
100 auto occupiedWidth = maxPaddingStart_ + maxPaddingEnd_;
101 constraint.maxSize.SetWidth(titleBarSize.Width() - static_cast<float>(occupiedWidth.ConvertToPx()));
102 subtitleWrapper->Measure(constraint);
103 return;
104 }
105
106 // navBar title bar
107 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
108 auto occupiedWidth = maxPaddingStart_ + maxPaddingEnd_ + HORIZONTAL_MARGIN;
109 constraint.maxSize.SetWidth(titleBarSize.Width() -
110 static_cast<float>(occupiedWidth.ConvertToPx()) - menuWidth);
111 subtitleWrapper->Measure(constraint);
112 return;
113 }
114
115 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
116 auto occupiedWidth = maxPaddingStart_ + maxPaddingEnd_ + HORIZONTAL_MARGIN;
117 constraint.maxSize.SetWidth(titleBarSize.Width() -
118 static_cast<float>(occupiedWidth.ConvertToPx()) - menuWidth);
119 subtitleWrapper->Measure(constraint);
120 return;
121 }
122
123 auto occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE +
124 HORIZONTAL_MARGIN_M + HORIZONTAL_MARGIN + maxPaddingEnd_;
125 constraint.maxSize.SetWidth(titleBarSize.Width() -
126 static_cast<float>(occupiedWidth.ConvertToPx()) - menuWidth);
127 subtitleWrapper->Measure(constraint);
128 }
129
MeasureTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,const SizeF & titleBarSize,float menuWidth)130 void TitleBarLayoutAlgorithm::MeasureTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
131 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, const SizeF& titleBarSize, float menuWidth)
132 {
133 auto titleNode = titleBarNode->GetTitle();
134 CHECK_NULL_VOID(titleNode);
135 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
136 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
137 CHECK_NULL_VOID(titleWrapper);
138 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
139 constraint.maxSize.SetHeight(titleBarSize.Height());
140
141 // navDestination title bar
142 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
143 TitleBarParentType::NAV_DESTINATION) {
144 if (titleBarNode->GetBackButton()) {
145 auto occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + maxPaddingEnd_;
146 constraint.maxSize.SetWidth(titleBarSize.Width() - static_cast<float>(occupiedWidth.ConvertToPx()));
147 titleWrapper->Measure(constraint);
148 return;
149 }
150
151 auto occupiedWidth = maxPaddingStart_ + maxPaddingEnd_;
152 constraint.maxSize.SetWidth(titleBarSize.Width() - static_cast<float>(occupiedWidth.ConvertToPx()));
153 titleWrapper->Measure(constraint);
154 return;
155 }
156
157 // navBar title bar
158 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
159 CHECK_NULL_VOID(navBarNode);
160 if (navBarNode->GetPrevTitleIsCustomValue(false)) {
161 auto occupiedWidth = Dimension(0.0, DimensionUnit::VP);
162 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI ||
163 titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
164 occupiedWidth = maxPaddingStart_ + defaultPaddingStart_ + HORIZONTAL_MARGIN;
165 } else {
166 occupiedWidth = defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE + HORIZONTAL_MARGIN * 2 + defaultPaddingStart_;
167 }
168 constraint.parentIdealSize.SetWidth(titleBarSize.Width() - static_cast<float>(occupiedWidth.ConvertToPx()));
169 titleWrapper->Measure(constraint);
170 return;
171 }
172 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
173 auto occupiedWidth = maxPaddingStart_ + defaultPaddingStart_ + HORIZONTAL_MARGIN;
174 constraint.maxSize.SetWidth(titleBarSize.Width() -
175 static_cast<float>(occupiedWidth.ConvertToPx()) - menuWidth);
176 titleWrapper->Measure(constraint);
177 return;
178 }
179
180 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
181 auto occupiedWidth = maxPaddingStart_ + defaultPaddingStart_ + HORIZONTAL_MARGIN;
182 constraint.maxSize.SetWidth(titleBarSize.Width() -
183 static_cast<float>(occupiedWidth.ConvertToPx()) - menuWidth);
184 titleWrapper->Measure(constraint);
185 return;
186 }
187
188 auto occupiedWidth = defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE + HORIZONTAL_MARGIN * 2 + defaultPaddingStart_;
189 constraint.maxSize.SetWidth(titleBarSize.Width() -
190 static_cast<float>(occupiedWidth.ConvertToPx()) - menuWidth);
191 titleWrapper->Measure(constraint);
192 }
193
MeasureMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)194 float TitleBarLayoutAlgorithm::MeasureMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
195 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
196 {
197 auto menuNode = titleBarNode->GetMenu();
198 CHECK_NULL_RETURN(menuNode, 0.0f);
199 auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
200 auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
201 CHECK_NULL_RETURN(menuWrapper, 0.0f);
202 auto constraint = titleBarLayoutProperty->CreateChildConstraint();
203 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
204 CHECK_NULL_RETURN(navBarNode, 0.0f);
205 auto isCustomMenu = navBarNode->GetPrevMenuIsCustomValue(false);
206 if (isCustomMenu) {
207 menuWrapper->Measure(constraint);
208 return menuWrapper->GetGeometryNode()->GetFrameSize().Width();
209 }
210 auto menuItemNum = static_cast<int32_t>(menuNode->GetChildren().size());
211 float menuWidth = 0.0f;
212 if (menuItemNum >= MAX_MENU_ITEMS_NUM) {
213 menuWidth = static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()) * MAX_MENU_ITEMS_NUM;
214 } else {
215 menuWidth = static_cast<float>(BACK_BUTTON_SIZE.ConvertToPx()) * menuItemNum;
216 }
217 constraint.selfIdealSize = OptionalSizeF(menuWidth, static_cast<float>(menuHeight_.ConvertToPx()));
218 menuWrapper->Measure(constraint);
219 return menuWidth;
220 }
221
LayoutBackButton(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty)222 void TitleBarLayoutAlgorithm::LayoutBackButton(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
223 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty)
224 {
225 auto backButtonNode = titleBarNode->GetBackButton();
226 CHECK_NULL_VOID(backButtonNode);
227 auto index = titleBarNode->GetChildIndexById(backButtonNode->GetId());
228 auto backButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
229 CHECK_NULL_VOID(backButtonWrapper);
230 auto geometryNode = backButtonWrapper->GetGeometryNode();
231
232 // navDestination title bar
233 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
234 TitleBarParentType::NAV_DESTINATION) {
235 if (!titleBarNode->GetBackButton()) {
236 return;
237 }
238
239 auto offsetY = (menuHeight_ - BACK_BUTTON_ICON_SIZE) / 2;
240 OffsetF backButtonOffset =
241 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), static_cast<float>(offsetY.ConvertToPx()));
242 geometryNode->SetMarginFrameOffset(backButtonOffset);
243 backButtonWrapper->Layout();
244 return;
245 }
246
247 // navBar title bar
248 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
249 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
250 geometryNode->SetMarginFrameOffset(backButtonOffset);
251 backButtonWrapper->Layout();
252 return;
253 }
254
255 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
256 OffsetF backButtonOffset = OffsetF(0.0f, 0.0f);
257 geometryNode->SetMarginFrameOffset(backButtonOffset);
258 backButtonWrapper->Layout();
259 return;
260 }
261
262 auto offsetY = (menuHeight_ - BACK_BUTTON_SIZE) / 2;
263 OffsetF backButtonOffset = OffsetF(static_cast<float>((defaultPaddingStart_ - BUTTON_PADDING).ConvertToPx()),
264 static_cast<float>(offsetY.ConvertToPx()));
265 geometryNode->SetMarginFrameOffset(backButtonOffset);
266 backButtonWrapper->Layout();
267 }
268
LayoutTitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)269 void TitleBarLayoutAlgorithm::LayoutTitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
270 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
271 {
272 auto titleNode = titleBarNode->GetTitle();
273 CHECK_NULL_VOID(titleNode);
274 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
275 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
276 CHECK_NULL_VOID(titleWrapper);
277 auto geometryNode = titleWrapper->GetGeometryNode();
278
279 auto titleHeight = geometryNode->GetFrameSize().Height();
280 float offsetY = 0.0f;
281 if (!NearZero(subtitleHeight)) {
282 offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight - subtitleHeight) / 2;
283 } else {
284 offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight) / 2;
285 }
286
287 // navDestination title bar
288 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
289 TitleBarParentType::NAV_DESTINATION) {
290 if (titleBarNode->GetBackButton()) {
291 OffsetF offset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()) +
292 static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()) +
293 static_cast<float>(HORIZONTAL_MARGIN_M.ConvertToPx()),
294 offsetY);
295 geometryNode->SetMarginFrameOffset(offset);
296 titleWrapper->Layout();
297 return;
298 }
299
300 OffsetF offset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
301 geometryNode->SetMarginFrameOffset(offset);
302 titleWrapper->Layout();
303 return;
304 }
305
306 // navBar title bar
307 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::MINI) {
308 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
309 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
310 geometryNode->SetMarginFrameOffset(titleOffset);
311 titleWrapper->Layout();
312 return;
313 }
314
315 auto occupiedWidth = defaultPaddingStart_ + BACK_BUTTON_ICON_SIZE + HORIZONTAL_MARGIN;
316 OffsetF offset = OffsetF(static_cast<float>(occupiedWidth.ConvertToPx()), offsetY);
317 geometryNode->SetMarginFrameOffset(offset);
318 titleWrapper->Layout();
319 return;
320 }
321 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::FREE) {
322 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
323 static_cast<float>(menuHeight_.ConvertToPx()) + offsetY);
324 geometryNode->SetMarginFrameOffset(titleOffset);
325 titleWrapper->Layout();
326 return;
327 }
328 if (isInitialTitle_) {
329 auto title = AceType::DynamicCast<FrameNode>(titleNode);
330 CHECK_NULL_VOID(title);
331
332 auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
333 if (!textLayoutProperty) {
334 titleWrapper->Layout();
335 return;
336 }
337 MeasureContext context;
338 context.textContent = textLayoutProperty->GetContentValue();
339 context.fontSize = titleFontSize_;
340 #ifdef ENABLE_ROSEN_BACKEND
341 minTitleHeight_ = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(context).Height());
342 #else
343 minTitleHeight_ = 0.0;
344 #endif
345 initialTitleOffsetY_ = static_cast<float>(menuHeight_.ConvertToPx()) + offsetY;
346 isInitialTitle_ = false;
347 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialTitleOffsetY_);
348 geometryNode->SetMarginFrameOffset(titleOffset);
349 titleWrapper->Layout();
350 return;
351 }
352
353 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
354 CHECK_NULL_VOID(titlePattern);
355 if (NearZero(titlePattern->GetTempTitleOffsetY())) {
356 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialTitleOffsetY_);
357 geometryNode->SetMarginFrameOffset(titleOffset);
358 titleWrapper->Layout();
359 return;
360 }
361
362 OffsetF titleOffset =
363 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), titlePattern->GetTempTitleOffsetY());
364 geometryNode->SetMarginFrameOffset(titleOffset);
365 titleWrapper->Layout();
366 }
367
LayoutSubtitle(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float titleHeight)368 void TitleBarLayoutAlgorithm::LayoutSubtitle(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
369 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float titleHeight)
370 {
371 auto subtitleNode = titleBarNode->GetSubtitle();
372 CHECK_NULL_VOID(subtitleNode);
373 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
374 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
375 CHECK_NULL_VOID(subtitleWrapper);
376 auto geometryNode = subtitleWrapper->GetGeometryNode();
377
378 auto subtitleHeight = geometryNode->GetFrameSize().Height();
379 float offsetY = 0.0f;
380 if (!NearZero(titleHeight)) {
381 offsetY = (static_cast<float>(DOUBLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - titleHeight - subtitleHeight) / 2 +
382 titleHeight;
383 } else {
384 offsetY = (static_cast<float>(SINGLE_LINE_TITLEBAR_HEIGHT.ConvertToPx()) - subtitleHeight) / 2;
385 }
386 // navDestination title bar
387 if (titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR) ==
388 TitleBarParentType::NAV_DESTINATION) {
389 if (titleBarNode->GetBackButton()) {
390 OffsetF offset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()) +
391 static_cast<float>(BACK_BUTTON_ICON_SIZE.ConvertToPx()) +
392 static_cast<float>(HORIZONTAL_MARGIN_M.ConvertToPx()),
393 offsetY);
394 geometryNode->SetMarginFrameOffset(offset);
395 subtitleWrapper->Layout();
396 return;
397 }
398
399 OffsetF offset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
400 geometryNode->SetMarginFrameOffset(offset);
401 subtitleWrapper->Layout();
402 return;
403 }
404
405 // navBar title bar
406 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) != NavigationTitleMode::MINI) {
407 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
408 if (isInitialSubtitle_) {
409 initialSubtitleOffsetY_ = static_cast<float>(menuHeight_.ConvertToPx()) + offsetY;
410 isInitialSubtitle_ = false;
411 OffsetF titleOffset =
412 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialSubtitleOffsetY_);
413 geometryNode->SetMarginFrameOffset(titleOffset);
414 subtitleWrapper->Layout();
415 return;
416 }
417
418 auto titlePattern = titleBarNode->GetPattern<TitleBarPattern>();
419 CHECK_NULL_VOID(titlePattern);
420 if (NearZero(titlePattern->GetTempTitleOffsetY())) {
421 OffsetF titleOffset =
422 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), initialSubtitleOffsetY_);
423 geometryNode->SetMarginFrameOffset(titleOffset);
424 subtitleWrapper->Layout();
425 return;
426 }
427
428 OffsetF titleOffset =
429 OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), titlePattern->GetTempSubTitleOffsetY());
430 geometryNode->SetMarginFrameOffset(titleOffset);
431 subtitleWrapper->Layout();
432 return;
433 }
434
435 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()),
436 static_cast<float>(menuHeight_.ConvertToPx()) + offsetY);
437 geometryNode->SetMarginFrameOffset(titleOffset);
438 subtitleWrapper->Layout();
439 return;
440 }
441
442 if (titleBarLayoutProperty->GetHideBackButton().value_or(false)) {
443 OffsetF titleOffset = OffsetF(static_cast<float>(maxPaddingStart_.ConvertToPx()), offsetY);
444 geometryNode->SetMarginFrameOffset(titleOffset);
445 subtitleWrapper->Layout();
446 return;
447 }
448
449 auto occupiedWidth = maxPaddingStart_ + BACK_BUTTON_ICON_SIZE + HORIZONTAL_MARGIN_M;
450 OffsetF offset = OffsetF(static_cast<float>(occupiedWidth.ConvertToPx()), offsetY);
451 geometryNode->SetMarginFrameOffset(offset);
452 subtitleWrapper->Layout();
453 }
454
LayoutMenu(LayoutWrapper * layoutWrapper,const RefPtr<TitleBarNode> & titleBarNode,const RefPtr<TitleBarLayoutProperty> & titleBarLayoutProperty,float subtitleHeight)455 void TitleBarLayoutAlgorithm::LayoutMenu(LayoutWrapper* layoutWrapper, const RefPtr<TitleBarNode>& titleBarNode,
456 const RefPtr<TitleBarLayoutProperty>& titleBarLayoutProperty, float subtitleHeight)
457 {
458 auto menuNode = titleBarNode->GetMenu();
459 CHECK_NULL_VOID(menuNode);
460 auto index = titleBarNode->GetChildIndexById(menuNode->GetId());
461 auto menuWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
462 CHECK_NULL_VOID(menuWrapper);
463 auto geometryNode = menuWrapper->GetGeometryNode();
464 auto menuWidth = geometryNode->GetMarginFrameSize().Width();
465 auto maxWidth = geometryNode->GetParentLayoutConstraint()->maxSize.Width();
466
467 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
468 auto menuOffsetY = (SINGLE_LINE_TITLEBAR_HEIGHT - menuHeight_) / 2;
469 OffsetF menuOffset(maxWidth - menuWidth - static_cast<float>(defaultPaddingStart_.ConvertToPx()),
470 static_cast<float>(menuOffsetY.ConvertToPx()));
471 geometryNode->SetMarginFrameOffset(menuOffset);
472 menuWrapper->Layout();
473 return;
474 }
475
476 Dimension menuOffsetY;
477 if (!NearZero(subtitleHeight)) {
478 menuOffsetY = (DOUBLE_LINE_TITLEBAR_HEIGHT - menuHeight_) / 2;
479 } else {
480 menuOffsetY = (SINGLE_LINE_TITLEBAR_HEIGHT - menuHeight_) / 2;
481 }
482 OffsetF menuOffset(maxWidth - menuWidth - static_cast<float>(defaultPaddingStart_.ConvertToPx()),
483 static_cast<float>(menuOffsetY.ConvertToPx()));
484 geometryNode->SetMarginFrameOffset(menuOffset);
485 menuWrapper->Layout();
486 }
487
488 // set variables from theme
InitializeTheme()489 void TitleBarLayoutAlgorithm::InitializeTheme()
490 {
491 auto theme = NavigationGetTheme();
492 CHECK_NULL_VOID(theme);
493 maxPaddingStart_ = theme->GetMaxPaddingStart();
494 maxPaddingEnd_ = theme->GetMaxPaddingEnd();
495 menuHeight_ = theme->GetHeight();
496 defaultPaddingStart_ = theme->GetDefaultPaddingStart();
497 iconSize_ = theme->GetMenuIconSize();
498 titleFontSize_ = theme->GetTitleFontSize();
499 }
500
Measure(LayoutWrapper * layoutWrapper)501 void TitleBarLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
502 {
503 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
504 CHECK_NULL_VOID(titleBarNode);
505 auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
506 CHECK_NULL_VOID(layoutProperty);
507 const auto& constraint = layoutProperty->GetLayoutConstraint();
508 CHECK_NULL_VOID(constraint);
509 auto size = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT, true);
510 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
511 MinusPaddingToSize(padding, size);
512 InitializeTheme();
513
514 MeasureBackButton(layoutWrapper, titleBarNode, layoutProperty);
515 auto menuWidth = MeasureMenu(layoutWrapper, titleBarNode, layoutProperty);
516 MeasureTitle(layoutWrapper, titleBarNode, layoutProperty, size, menuWidth);
517 MeasureSubtitle(layoutWrapper, titleBarNode, layoutProperty, size, menuWidth);
518 layoutWrapper->GetGeometryNode()->SetFrameSize(size);
519 }
520
Layout(LayoutWrapper * layoutWrapper)521 void TitleBarLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
522 {
523 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(layoutWrapper->GetHostNode());
524 CHECK_NULL_VOID(titleBarNode);
525 auto layoutProperty = AceType::DynamicCast<TitleBarLayoutProperty>(layoutWrapper->GetLayoutProperty());
526 CHECK_NULL_VOID(layoutProperty);
527 LayoutBackButton(layoutWrapper, titleBarNode, layoutProperty);
528
529 float subtitleHeight = 0.0f;
530 auto subtitleNode = titleBarNode->GetSubtitle();
531 if (subtitleNode) {
532 auto index = titleBarNode->GetChildIndexById(subtitleNode->GetId());
533 auto subtitleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
534 CHECK_NULL_VOID(subtitleWrapper);
535 auto geometryNode = subtitleWrapper->GetGeometryNode();
536 subtitleHeight = geometryNode->GetFrameSize().Height();
537 }
538 LayoutTitle(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
539
540 float titleHeight = 0.0f;
541 auto titleNode = titleBarNode->GetTitle();
542 if (titleNode) {
543 auto index = titleBarNode->GetChildIndexById(titleNode->GetId());
544 auto titleWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
545 CHECK_NULL_VOID(titleWrapper);
546 auto geometryNode = titleWrapper->GetGeometryNode();
547 titleHeight = geometryNode->GetFrameSize().Height();
548 }
549 LayoutSubtitle(layoutWrapper, titleBarNode, layoutProperty, titleHeight);
550
551 LayoutMenu(layoutWrapper, titleBarNode, layoutProperty, subtitleHeight);
552 }
553
554 } // namespace OHOS::Ace::NG
555