• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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