1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/navigation/navigation_toolbar_util.h"
17 
18 #include "base/i18n/localization.h"
19 #include "core/common/agingadapation/aging_adapation_dialog_theme.h"
20 #include "core/common/agingadapation/aging_adapation_dialog_util.h"
21 #include "core/common/container.h"
22 #include "core/components_ng/base/view_abstract.h"
23 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
24 #include "core/components_ng/pattern/button/button_layout_property.h"
25 #include "core/components_ng/pattern/button/button_pattern.h"
26 #include "core/components_ng/pattern/divider/divider_pattern.h"
27 #include "core/components_ng/pattern/grid/grid_pattern.h"
28 #include "core/components_ng/pattern/image/image_layout_property.h"
29 #include "core/components_ng/pattern/image/image_pattern.h"
30 #include "core/components_ng/pattern/menu/menu_view.h"
31 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h"
32 #include "core/components_ng/pattern/navigation/bar_item_event_hub.h"
33 #include "core/components_ng/pattern/navigation/bar_item_pattern.h"
34 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
35 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
36 #include "core/components_ng/pattern/navigation/navdestination_pattern_base.h"
37 #include "core/components_ng/pattern/navigation/title_bar_node.h"
38 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
39 #include "core/components_ng/pattern/navigation/tool_bar_node.h"
40 #include "core/components_ng/pattern/navigation/tool_bar_pattern.h"
41 #include "core/components_ng/pattern/text/text_pattern.h"
42 
43 namespace OHOS::Ace::NG {
44 
45 namespace {
AddSafeIntervalBetweenToolbarItem(MarginProperty & margin,uint32_t count,size_t toolbarItemSize,bool needMoreButton)46 void AddSafeIntervalBetweenToolbarItem(
47     MarginProperty& margin, uint32_t count, size_t toolbarItemSize, bool needMoreButton)
48 {
49     auto theme = NavigationGetTheme();
50     CHECK_NULL_VOID(theme);
51     if (count == ONE_TOOLBAR_ITEM && toolbarItemSize != ONE_TOOLBAR_ITEM) {
52         margin.right = CalcLength(theme->GetToolbarItemMargin());
53     } else if (!needMoreButton && (count == toolbarItemSize) && (toolbarItemSize != ONE_TOOLBAR_ITEM)) {
54         margin.left = CalcLength(theme->GetToolbarItemMargin());
55     } else if (toolbarItemSize == ONE_TOOLBAR_ITEM) {
56         margin.left = CalcLength(theme->GetToolbarItemSpecialMargin());
57         margin.right = CalcLength(theme->GetToolbarItemSpecialMargin());
58     } else {
59         margin.left = CalcLength(theme->GetToolbarItemMargin());
60         margin.right = CalcLength(theme->GetToolbarItemMargin());
61     }
62 }
63 
CreateToolbarItemTextNode(const std::string & text)64 RefPtr<FrameNode> CreateToolbarItemTextNode(const std::string& text)
65 {
66     int32_t nodeId = ElementRegister::GetInstance()->MakeUniqueId();
67     auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, nodeId, AceType::MakeRefPtr<TextPattern>());
68     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
69     CHECK_NULL_RETURN(textLayoutProperty, nullptr);
70     auto theme = NavigationGetTheme();
71     CHECK_NULL_RETURN(theme, nullptr);
72     textLayoutProperty->UpdateContent(text);
73     textLayoutProperty->UpdateFontSize(theme->GetToolBarItemFontSize());
74     textLayoutProperty->UpdateTextColor(theme->GetToolBarItemFontColor());
75     textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
76     textLayoutProperty->UpdateFontWeight(FontWeight::MEDIUM);
77     textLayoutProperty->UpdateAdaptMinFontSize(theme->GetToolBarItemMinFontSize());
78     textLayoutProperty->UpdateAdaptMaxFontSize(theme->GetToolBarItemFontSize());
79     textLayoutProperty->UpdateMaxLines(theme->GetToolbarItemTextMaxLines());
80     textLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
81     textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
82 
83     textLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), std::nullopt));
84     return textNode;
85 }
86 
UpdateSymbolEffect(RefPtr<TextLayoutProperty> symbolProperty,bool isActive)87 void UpdateSymbolEffect(RefPtr<TextLayoutProperty> symbolProperty, bool isActive)
88 {
89     CHECK_NULL_VOID(symbolProperty);
90     auto symbolEffectOptions = SymbolEffectOptions(SymbolEffectType::BOUNCE);
91     symbolEffectOptions.SetIsTxtActive(isActive);
92     symbolEffectOptions.SetIsTxtActiveSource(0);
93     symbolProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
94 }
95 
CreateToolbarItemIconNode(const BarItem & barItem)96 RefPtr<FrameNode> CreateToolbarItemIconNode(const BarItem& barItem)
97 {
98     auto theme = NavigationGetTheme();
99     CHECK_NULL_RETURN(theme, nullptr);
100     if (barItem.iconSymbol.has_value() && barItem.iconSymbol.value() != nullptr) {
101         auto iconNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG,
102             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
103         CHECK_NULL_RETURN(iconNode, nullptr);
104         auto symbolProperty = iconNode->GetLayoutProperty<TextLayoutProperty>();
105         CHECK_NULL_RETURN(symbolProperty, nullptr);
106         symbolProperty->UpdateSymbolColorList({ theme->GetToolbarIconColor() });
107         barItem.iconSymbol.value()(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(iconNode)));
108         symbolProperty->UpdateFontSize(theme->GetToolbarIconSize());
109         UpdateSymbolEffect(symbolProperty, false);
110         iconNode->MarkModifyDone();
111         return iconNode;
112     }
113     int32_t nodeId = ElementRegister::GetInstance()->MakeUniqueId();
114     ImageSourceInfo info(barItem.icon.value());
115     auto iconNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, nodeId, AceType::MakeRefPtr<ImagePattern>());
116     auto imageLayoutProperty = iconNode->GetLayoutProperty<ImageLayoutProperty>();
117     CHECK_NULL_RETURN(imageLayoutProperty, nullptr);
118 
119     info.SetFillColor(theme->GetToolbarIconColor());
120     imageLayoutProperty->UpdateImageSourceInfo(info);
121 
122     auto iconSize = theme->GetToolbarIconSize();
123     imageLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(iconSize), CalcLength(iconSize)));
124 
125     iconNode->MarkModifyDone();
126     return iconNode;
127 }
128 
RegisterToolbarHotZoneEvent(const RefPtr<FrameNode> & buttonNode,const RefPtr<BarItemNode> & barItemNode)129 void RegisterToolbarHotZoneEvent(const RefPtr<FrameNode>& buttonNode, const RefPtr<BarItemNode>& barItemNode)
130 {
131     auto gestureEventHub = buttonNode->GetOrCreateGestureEventHub();
132     CHECK_NULL_VOID(gestureEventHub);
133     auto clickCallback = [weakNode = WeakPtr<BarItemNode>(barItemNode)](GestureEvent& info) {
134         if (info.GetSourceDevice() == SourceType::KEYBOARD) {
135             return;
136         }
137         auto barItemNode = weakNode.Upgrade();
138         auto eventHub = barItemNode->GetEventHub<BarItemEventHub>();
139         CHECK_NULL_VOID(eventHub);
140         auto pattern = barItemNode->GetPattern<BarItemPattern>();
141         CHECK_NULL_VOID(pattern);
142         eventHub->FireItemAction();
143         pattern->UpdateBarItemActiveStatusResource();
144     };
145     gestureEventHub->AddClickEvent(AceType::MakeRefPtr<ClickEvent>(clickCallback));
146 }
147 
UpdateBarItemPattern(const RefPtr<BarItemNode> & barItemNode,const BarItem & barItem)148 void UpdateBarItemPattern(const RefPtr<BarItemNode>& barItemNode, const BarItem& barItem)
149 {
150     auto theme = NavigationGetTheme();
151     CHECK_NULL_VOID(theme);
152     auto barItemPattern = barItemNode->GetPattern<BarItemPattern>();
153     CHECK_NULL_VOID(barItemPattern);
154     if (barItem.status == NG::NavToolbarItemStatus::ACTIVE &&
155         ((barItem.activeIcon.has_value() && !barItem.activeIcon.value().empty()) ||
156             (barItem.activeIconSymbol.has_value() && barItem.activeIconSymbol.value() != nullptr)) &&
157         ((barItem.icon.has_value() && !barItem.icon.value().empty()) ||
158             (barItem.iconSymbol.has_value() && barItem.iconSymbol.value() != nullptr))) {
159         if (barItem.iconSymbol.has_value() && barItem.iconSymbol.value() != nullptr) {
160             barItemPattern->SetInitialIconSymbol(barItem.iconSymbol.value());
161         } else if (barItem.icon.has_value()) {
162             ImageSourceInfo initialIconInfo(barItem.icon.value());
163             initialIconInfo.SetFillColor(theme->GetToolbarIconColor());
164             barItemPattern->SetInitialIconImageSourceInfo(initialIconInfo);
165         }
166 
167         if (barItem.activeIconSymbol.has_value() && barItem.activeIconSymbol.value() != nullptr) {
168             barItemPattern->SetActiveIconSymbol(barItem.activeIconSymbol.value());
169         } else if (barItem.activeIcon.has_value()) {
170             ImageSourceInfo activeIconInfo(barItem.activeIcon.value());
171             activeIconInfo.SetFillColor(theme->GetToolbarActiveIconColor());
172             barItemPattern->SetActiveIconImageSourceInfo(activeIconInfo);
173         }
174         barItemPattern->SetToolbarItemStatus(barItem.status);
175         barItemPattern->SetCurrentIconStatus(NG::ToolbarIconStatus::INITIAL);
176         barItemPattern->UpdateBarItemActiveStatusResource();
177     }
178 }
179 
UpdateToolbarItemNodeWithConfiguration(const RefPtr<BarItemNode> & barItemNode,const BarItem & barItem,const RefPtr<FrameNode> & buttonNode,bool enableStatus)180 void UpdateToolbarItemNodeWithConfiguration(
181     const RefPtr<BarItemNode>& barItemNode, const BarItem& barItem,
182     const RefPtr<FrameNode>& buttonNode, bool enableStatus)
183 {
184     barItemNode->SetBarItemUsedInToolbarConfiguration(true);
185     if (barItem.text.has_value() && !barItem.text.value().empty()) {
186         auto textNode = CreateToolbarItemTextNode(barItem.text.value());
187         barItemNode->SetTextNode(textNode);
188         barItemNode->AddChild(textNode);
189     }
190     if ((barItem.icon.has_value() && !barItem.icon.value().empty())
191         || (barItem.iconSymbol.has_value() && barItem.iconSymbol.value() != nullptr)) {
192         auto iconNode = CreateToolbarItemIconNode(barItem);
193         barItemNode->SetIconNode(iconNode);
194         barItemNode->AddChild(iconNode);
195     }
196     if (barItem.action) {
197         auto eventHub = barItemNode->GetEventHub<BarItemEventHub>();
198         CHECK_NULL_VOID(eventHub);
199         eventHub->SetItemAction(barItem.action);
200         RegisterToolbarHotZoneEvent(buttonNode, barItemNode);
201     }
202 
203     auto theme = NavigationGetTheme();
204     CHECK_NULL_VOID(theme);
205     if (barItem.status == NG::NavToolbarItemStatus::DISABLED || !enableStatus) {
206         auto renderContext = barItemNode->GetRenderContext();
207         CHECK_NULL_VOID(renderContext);
208         renderContext->UpdateOpacity(theme->GetToolbarItemDisabledAlpha());
209 
210         auto itemEventHub = barItemNode->GetEventHub<BarItemEventHub>();
211         CHECK_NULL_VOID(itemEventHub);
212         itemEventHub->SetEnabled(false);
213         auto itemFocusHub = barItemNode->GetFocusHub();
214         CHECK_NULL_VOID(itemFocusHub);
215         itemFocusHub->SetEnabled(false);
216 
217         auto buttonEventHub = buttonNode->GetEventHub<ButtonEventHub>();
218         CHECK_NULL_VOID(buttonEventHub);
219         buttonEventHub->SetEnabled(false);
220         auto buttonFocusHub = buttonNode->GetFocusHub();
221         CHECK_NULL_VOID(buttonFocusHub);
222         buttonFocusHub->SetEnabled(false);
223     }
224 
225     UpdateBarItemPattern(barItemNode, barItem);
226     barItemNode->MarkModifyDone();
227 }
228 
BuildSymbolToolbarMoreItemNode(const RefPtr<BarItemNode> & barItemNode,bool enabled)229 void BuildSymbolToolbarMoreItemNode(const RefPtr<BarItemNode>& barItemNode, bool enabled)
230 {
231     auto theme = NavigationGetTheme();
232     CHECK_NULL_VOID(theme);
233     auto renderContext = barItemNode->GetRenderContext();
234     CHECK_NULL_VOID(renderContext);
235     if (!enabled) {
236         renderContext->UpdateOpacity(theme->GetToolbarItemDisabledAlpha());
237     }
238 
239     auto symbolNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG,
240         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
241     CHECK_NULL_VOID(symbolNode);
242     auto symbolProperty = symbolNode->GetLayoutProperty<TextLayoutProperty>();
243     CHECK_NULL_VOID(symbolProperty);
244     symbolProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(theme->GetMoreSymbolId()));
245     symbolProperty->UpdateFontSize(theme->GetToolbarIconSize());
246     symbolProperty->UpdateSymbolColorList({ theme->GetToolbarIconColor() });
247     symbolNode->MarkModifyDone();
248     barItemNode->SetIconNode(symbolNode);
249     barItemNode->SetIsMoreItemNode(true);
250     barItemNode->AddChild(symbolNode);
251 }
252 
BuildImageToolbarMoreItemNode(const RefPtr<BarItemNode> & barItemNode,bool enabled)253 void BuildImageToolbarMoreItemNode(const RefPtr<BarItemNode>& barItemNode, bool enabled)
254 {
255     auto theme = NavigationGetTheme();
256     CHECK_NULL_VOID(theme);
257 
258     int32_t imageNodeId = ElementRegister::GetInstance()->MakeUniqueId();
259     auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, imageNodeId, AceType::MakeRefPtr<ImagePattern>());
260     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
261     CHECK_NULL_VOID(imageLayoutProperty);
262     auto info = ImageSourceInfo("");
263     info.SetResourceId(theme->GetMoreResourceId());
264     if (!enabled) {
265         auto renderContext = barItemNode->GetRenderContext();
266         CHECK_NULL_VOID(renderContext);
267         renderContext->UpdateOpacity(theme->GetToolbarItemDisabledAlpha());
268     } else {
269         info.SetFillColor(theme->GetToolbarIconColor());
270     }
271     imageLayoutProperty->UpdateImageSourceInfo(info);
272     auto iconSize = theme->GetToolbarIconSize();
273     imageLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(iconSize), CalcLength(iconSize)));
274     imageNode->MarkModifyDone();
275     barItemNode->SetIconNode(imageNode);
276     barItemNode->AddChild(imageNode);
277 }
278 
CreateToolbarItemsContainerNode(const RefPtr<FrameNode> & toolBarNode)279 RefPtr<FrameNode> CreateToolbarItemsContainerNode(const RefPtr<FrameNode>& toolBarNode)
280 {
281     int32_t containerNodeId = ElementRegister::GetInstance()->MakeUniqueId();
282     auto containerNode = FrameNode::GetOrCreateFrameNode(
283         V2::TOOL_BAR_ETS_TAG, containerNodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
284     CHECK_NULL_RETURN(containerNode, nullptr);
285     auto containerRowProperty = containerNode->GetLayoutProperty<LinearLayoutProperty>();
286     CHECK_NULL_RETURN(containerRowProperty, nullptr);
287     containerRowProperty->UpdateMainAxisAlign(FlexAlign::SPACE_EVENLY);
288     toolBarNode->AddChild(containerNode);
289     return containerNode;
290 }
291 
CreateToolbarItemInContainer(const BarItem & toolBarItem,size_t toolbarItemSize,uint32_t count,bool needMoreButton,bool enableStatus)292 RefPtr<FrameNode> CreateToolbarItemInContainer(
293     const BarItem& toolBarItem, size_t toolbarItemSize, uint32_t count, bool needMoreButton, bool enableStatus)
294 {
295     auto theme = NavigationGetTheme();
296     CHECK_NULL_RETURN(theme, nullptr);
297     auto buttonPattern = AceType::MakeRefPtr<ButtonPattern>();
298     CHECK_NULL_RETURN(buttonPattern, nullptr);
299     buttonPattern->setComponentButtonType(ComponentButtonType::NAVIGATION);
300     buttonPattern->SetFocusBorderColor(theme->GetToolBarItemFocusColor());
301     buttonPattern->SetFocusBorderWidth(theme->GetToolBarItemFocusBorderWidth());
302     auto toolBarItemNode = FrameNode::CreateFrameNode(
303         V2::MENU_ITEM_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), buttonPattern);
304     CHECK_NULL_RETURN(toolBarItemNode, nullptr);
305     auto toolBarItemLayoutProperty = toolBarItemNode->GetLayoutProperty<ButtonLayoutProperty>();
306     CHECK_NULL_RETURN(toolBarItemLayoutProperty, nullptr);
307     toolBarItemLayoutProperty->UpdateUserDefinedIdealSize(
308         CalcSize(std::nullopt, CalcLength(theme->GetToolbarItemHeigth())));
309     toolBarItemLayoutProperty->UpdateType(ButtonType::NORMAL);
310     toolBarItemLayoutProperty->UpdateBorderRadius(theme->GetToolBarItemBorderRadius());
311     auto renderContext = toolBarItemNode->GetRenderContext();
312     CHECK_NULL_RETURN(renderContext, nullptr);
313     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
314     MarginProperty margin;
315     AddSafeIntervalBetweenToolbarItem(margin, count, toolbarItemSize, needMoreButton);
316     toolBarItemLayoutProperty->UpdateMargin(margin);
317 
318     PaddingProperty padding;
319     padding.left = CalcLength(theme->GetToolbarItemLeftOrRightPadding());
320     padding.right = CalcLength(theme->GetToolbarItemLeftOrRightPadding());
321     padding.top = CalcLength(theme->GetToolbarItemTopPadding());
322     padding.bottom = CalcLength(theme->GetToolbarItemBottomPadding());
323     toolBarItemLayoutProperty->UpdatePadding(padding);
324 
325     int32_t barItemNodeId = ElementRegister::GetInstance()->MakeUniqueId();
326     auto barItemNode = BarItemNode::GetOrCreateBarItemNode(
327         V2::BAR_ITEM_ETS_TAG, barItemNodeId, []() { return AceType::MakeRefPtr<BarItemPattern>(); });
328     UpdateToolbarItemNodeWithConfiguration(barItemNode, toolBarItem, toolBarItemNode, enableStatus);
329     auto barItemLayoutProperty = barItemNode->GetLayoutProperty();
330     CHECK_NULL_RETURN(barItemLayoutProperty, nullptr);
331     barItemLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
332 
333     barItemNode->MountToParent(toolBarItemNode);
334     toolBarItemNode->MarkModifyDone();
335     return toolBarItemNode;
336 }
337 
BuildToolbarMoreItemNode(const RefPtr<BarItemNode> & barItemNode,bool enabled)338 void BuildToolbarMoreItemNode(const RefPtr<BarItemNode>& barItemNode, bool enabled)
339 {
340     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
341         BuildSymbolToolbarMoreItemNode(barItemNode, enabled);
342     } else {
343         BuildImageToolbarMoreItemNode(barItemNode, enabled);
344     }
345     auto textNode = CreateToolbarItemTextNode(Localization::GetInstance()->GetEntryLetters("common.more"));
346     CHECK_NULL_VOID(textNode);
347     barItemNode->SetTextNode(textNode);
348     barItemNode->SetBarItemUsedInToolbarConfiguration(true);
349     barItemNode->AddChild(textNode);
350     barItemNode->MarkModifyDone();
351 }
352 
CreateToolbarMoreMenuNode(const RefPtr<BarItemNode> & barItemNode)353 RefPtr<FrameNode> CreateToolbarMoreMenuNode(const RefPtr<BarItemNode>& barItemNode)
354 {
355     auto theme = NavigationGetTheme();
356     CHECK_NULL_RETURN(theme, nullptr);
357     auto buttonPattern = AceType::MakeRefPtr<ButtonPattern>();
358     CHECK_NULL_RETURN(buttonPattern, nullptr);
359     buttonPattern->setComponentButtonType(ComponentButtonType::NAVIGATION);
360     buttonPattern->SetFocusBorderColor(theme->GetToolBarItemFocusColor());
361     buttonPattern->SetFocusBorderWidth(theme->GetToolBarItemFocusBorderWidth());
362     auto toolBarItemNode = FrameNode::CreateFrameNode(
363         V2::MENU_ITEM_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), buttonPattern);
364     CHECK_NULL_RETURN(toolBarItemNode, nullptr);
365     auto menuItemLayoutProperty = toolBarItemNode->GetLayoutProperty<ButtonLayoutProperty>();
366     CHECK_NULL_RETURN(menuItemLayoutProperty, nullptr);
367     menuItemLayoutProperty->UpdateUserDefinedIdealSize(
368         CalcSize(std::nullopt, CalcLength(theme->GetToolbarItemHeigth())));
369     menuItemLayoutProperty->UpdateType(ButtonType::NORMAL);
370     menuItemLayoutProperty->UpdateBorderRadius(theme->GetToolBarItemBorderRadius());
371 
372     auto renderContext = toolBarItemNode->GetRenderContext();
373     CHECK_NULL_RETURN(renderContext, nullptr);
374     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
375 
376     MarginProperty menuButtonMargin;
377     menuButtonMargin.left = CalcLength(theme->GetToolbarItemMargin());
378     menuItemLayoutProperty->UpdateMargin(menuButtonMargin);
379 
380     PaddingProperty padding;
381     padding.left = CalcLength(theme->GetToolbarItemLeftOrRightPadding());
382     padding.right = CalcLength(theme->GetToolbarItemLeftOrRightPadding());
383     padding.top = CalcLength(theme->GetToolbarItemTopPadding());
384     padding.bottom = CalcLength(theme->GetToolbarItemBottomPadding());
385     menuItemLayoutProperty->UpdatePadding(padding);
386 
387     barItemNode->MountToParent(toolBarItemNode);
388     barItemNode->MarkModifyDone();
389     toolBarItemNode->MarkModifyDone();
390     return toolBarItemNode;
391 }
392 
BuildToolbarMoreMenuNodeAction(const RefPtr<BarItemNode> & barItemNode,const RefPtr<FrameNode> & barMenuNode,const RefPtr<FrameNode> & buttonNode)393 void BuildToolbarMoreMenuNodeAction(
394     const RefPtr<BarItemNode>& barItemNode, const RefPtr<FrameNode>& barMenuNode, const RefPtr<FrameNode>& buttonNode)
395 {
396     auto eventHub = barItemNode->GetEventHub<BarItemEventHub>();
397     CHECK_NULL_VOID(eventHub);
398 
399     auto context = PipelineContext::GetCurrentContext();
400     auto clickCallback = [weakContext = WeakPtr<PipelineContext>(context), id = barItemNode->GetId(),
401                              weakMenu = WeakPtr<FrameNode>(barMenuNode),
402                              weakBarItemNode = WeakPtr<BarItemNode>(barItemNode)]() {
403         auto context = weakContext.Upgrade();
404         CHECK_NULL_VOID(context);
405 
406         auto overlayManager = context->GetOverlayManager();
407         CHECK_NULL_VOID(overlayManager);
408 
409         auto menu = weakMenu.Upgrade();
410         CHECK_NULL_VOID(menu);
411 
412         auto barItemNode = weakBarItemNode.Upgrade();
413         CHECK_NULL_VOID(barItemNode);
414 
415         auto imageNode = barItemNode->GetChildAtIndex(0);
416         CHECK_NULL_VOID(imageNode);
417 
418         auto imageFrameNode = AceType::DynamicCast<FrameNode>(imageNode);
419         CHECK_NULL_VOID(imageFrameNode);
420         auto imgOffset = imageFrameNode->GetOffsetRelativeToWindow();
421         auto imageSize = imageFrameNode->GetGeometryNode()->GetFrameSize();
422 
423         auto menuNode = AceType::DynamicCast<FrameNode>(menu->GetChildAtIndex(0));
424         CHECK_NULL_VOID(menuNode);
425         auto menuLayoutProperty = menuNode->GetLayoutProperty<MenuLayoutProperty>();
426         CHECK_NULL_VOID(menuLayoutProperty);
427         menuLayoutProperty->UpdateTargetSize(imageSize);
428         auto menuPattern = menuNode->GetPattern<MenuPattern>();
429         CHECK_NULL_VOID(menuPattern);
430         menuPattern->SetIsSelectMenu(true);
431 
432         bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
433         if (isRightToLeft) {
434             imgOffset.SetX(imgOffset.GetX() + imageSize.Width());
435         } else {
436             imgOffset.SetX(imgOffset.GetX());
437         }
438         imgOffset.SetY(imgOffset.GetY() - imageSize.Height());
439         overlayManager->ShowMenu(id, imgOffset, menu);
440     };
441     eventHub->SetItemAction(clickCallback);
442     RegisterToolbarHotZoneEvent(buttonNode, barItemNode);
443 }
444 
CreateToolbarItemNodeAndMenuNode(bool enabled,std::vector<OptionParam> && params,const FieldProperty & fieldProperty,RefPtr<FrameNode> & barMenuNodeOut,const RefPtr<FrameNode> & containerNode)445 bool CreateToolbarItemNodeAndMenuNode(bool enabled, std::vector<OptionParam>&& params,
446     const FieldProperty& fieldProperty, RefPtr<FrameNode>& barMenuNodeOut, const RefPtr<FrameNode>& containerNode)
447 {
448     int32_t barItemNodeId = ElementRegister::GetInstance()->MakeUniqueId();
449     auto barItemNode = BarItemNode::GetOrCreateBarItemNode(
450         V2::BAR_ITEM_ETS_TAG, barItemNodeId, []() { return AceType::MakeRefPtr<BarItemPattern>(); });
451     auto barItemLayoutProperty = barItemNode->GetLayoutProperty();
452     CHECK_NULL_RETURN(barItemLayoutProperty, false);
453     barItemLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
454     BuildToolbarMoreItemNode(barItemNode, enabled);
455     MenuParam menuParam;
456     menuParam.isShowInSubWindow = false;
457     auto barMenuNode = MenuView::Create(
458         std::move(params), barItemNodeId, V2::BAR_ITEM_ETS_TAG, MenuType::NAVIGATION_MENU, menuParam);
459     auto toolBarItemNode = CreateToolbarMoreMenuNode(barItemNode);
460     CHECK_NULL_RETURN(toolBarItemNode, false);
461     BuildToolbarMoreMenuNodeAction(barItemNode, barMenuNode, toolBarItemNode);
462 
463     // set Navigation/NavDestination toolBar "more" button InspectorId
464     NavigationTitleUtil::SetInnerChildId(toolBarItemNode, fieldProperty.field,
465         containerNode->GetTag(), "More", fieldProperty.parentId);
466     containerNode->AddChild(toolBarItemNode);
467     barMenuNodeOut = barMenuNode;
468     return true;
469 }
470 
BuildToolBarItems(const RefPtr<NavToolbarNode> & toolBarNode,const std::vector<NG::BarItem> & toolBarItems,const FieldProperty & fieldProperty,bool enabled,RefPtr<FrameNode> & barMenuNodeOut)471 bool BuildToolBarItems(const RefPtr<NavToolbarNode>& toolBarNode, const std::vector<NG::BarItem>& toolBarItems,
472     const FieldProperty& fieldProperty, bool enabled, RefPtr<FrameNode>& barMenuNodeOut)
473 {
474     CHECK_NULL_RETURN(toolBarNode, false);
475     auto rowProperty = toolBarNode->GetLayoutProperty();
476     CHECK_NULL_RETURN(rowProperty, false);
477     auto containerNode = CreateToolbarItemsContainerNode(toolBarNode);
478     CHECK_NULL_RETURN(containerNode, false);
479     toolBarNode->SetToolbarContainerNode(containerNode);
480     bool needMoreButton = toolBarItems.size() > MAXIMUM_TOOLBAR_ITEMS_IN_BAR;
481     uint32_t count = 0;
482     std::vector<OptionParam> params;
483     auto theme = NavigationGetTheme();
484     CHECK_NULL_RETURN(theme, false);
485     OptionParam param;
486     for (const auto& toolBarItem : toolBarItems) {
487         ++count;
488         if (needMoreButton && (count > MAXIMUM_TOOLBAR_ITEMS_IN_BAR - 1)) {
489             param = { toolBarItem.text.value_or(""), toolBarItem.icon.value_or(""), toolBarItem.action,
490                 toolBarItem.iconSymbol.value_or(nullptr) };
491             param.SetSymbolUserDefinedIdealFontSize(theme->GetToolbarIconSize());
492             params.push_back(param);
493         } else {
494             auto toolBarItemNode = CreateToolbarItemInContainer(
495                 toolBarItem, toolBarItems.size(), count, needMoreButton, enabled);
496             CHECK_NULL_RETURN(toolBarItemNode, false);
497 
498             // set Navigation/NavDestination toolBar menuItem InspectorId
499             std::string toolBarItemId = toolBarItemNode->GetTag() + std::to_string(count);
500             NavigationTitleUtil::SetInnerChildId(toolBarItemNode, fieldProperty.field,
501                 containerNode->GetTag(), toolBarItemId, fieldProperty.parentId);
502 
503             containerNode->AddChild(toolBarItemNode);
504         }
505     }
506     bool hasValidContent = !containerNode->GetChildren().empty();
507     toolBarNode->SetHasValidContent(hasValidContent);
508     rowProperty->UpdateVisibility(hasValidContent ? VisibleType::VISIBLE : VisibleType::GONE);
509     if (!needMoreButton) {
510         return true;
511     }
512     return CreateToolbarItemNodeAndMenuNode(enabled, std::move(params), fieldProperty,
513         barMenuNodeOut, containerNode);;
514 }
515 } //namespace
516 
CreateToolBarDividerNodeIfNeeded(const RefPtr<NavDestinationNodeBase> & nodeBase)517 void NavigationToolbarUtil::CreateToolBarDividerNodeIfNeeded(const RefPtr<NavDestinationNodeBase>& nodeBase)
518 {
519     auto dividerNode = AceType::DynamicCast<FrameNode>(nodeBase->GetToolBarDividerNode());
520     if (!dividerNode) {
521         int32_t dividerNodeId = ElementRegister::GetInstance()->MakeUniqueId();
522         dividerNode = FrameNode::GetOrCreateFrameNode(
523             V2::DIVIDER_ETS_TAG, dividerNodeId, []() { return AceType::MakeRefPtr<DividerPattern>(); });
524         nodeBase->AddChild(dividerNode);
525         auto dividerLayoutProperty = dividerNode->GetLayoutProperty<DividerLayoutProperty>();
526         CHECK_NULL_VOID(dividerLayoutProperty);
527         auto theme = NavigationGetTheme();
528         CHECK_NULL_VOID(theme);
529         dividerLayoutProperty->UpdateStrokeWidth(theme->GetToolBarDividerWidth());
530         dividerLayoutProperty->UpdateVertical(false);
531         auto dividerRenderProperty = dividerNode->GetPaintProperty<DividerRenderProperty>();
532         CHECK_NULL_VOID(dividerRenderProperty);
533         dividerRenderProperty->UpdateDividerColor(theme->GetToolBarDividerColor());
534         nodeBase->SetToolBarDividerNode(dividerNode);
535     }
536     nodeBase->AddChild(dividerNode);
537 }
538 
SetToolbarConfiguration(const RefPtr<NavDestinationNodeBase> & nodeBase,std::vector<NG::BarItem> && toolBarItems,bool enabled,const FieldProperty & fieldProperty)539 void NavigationToolbarUtil::SetToolbarConfiguration(const RefPtr<NavDestinationNodeBase>& nodeBase,
540     std::vector<NG::BarItem>&& toolBarItems, bool enabled, const FieldProperty& fieldProperty)
541 {
542     CHECK_NULL_VOID(nodeBase);
543     if (nodeBase->GetPrevToolBarIsCustom().value_or(false)) {
544         nodeBase->UpdateToolBarNodeOperation(ChildNodeOperation::REPLACE);
545     } else {
546         auto toolbarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetPreToolBarNode());
547         auto containerNode = toolbarNode->GetToolbarContainerNode();
548         if (toolbarNode && containerNode) {
549             nodeBase->UpdateToolBarNodeOperation(ChildNodeOperation::REPLACE);
550             auto preToolbarNode = nodeBase->GetPreToolBarNode();
551             preToolbarNode->RemoveChild(containerNode);
552             nodeBase->RemoveChild(nodeBase->GetToolBarDividerNode());
553         } else {
554             nodeBase->UpdateToolBarNodeOperation(ChildNodeOperation::ADD);
555         }
556     }
557     auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetPreToolBarNode());
558     CHECK_NULL_VOID(toolBarNode);
559     toolBarNode->SetIsUseNewToolbar(true);
560     auto rowProperty = toolBarNode->GetLayoutProperty<LinearLayoutProperty>();
561     CHECK_NULL_VOID(rowProperty);
562     rowProperty->UpdateMainAxisAlign(FlexAlign::CENTER);
563     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ||
564         !SystemProperties::GetNavigationBlurEnabled()) {
565         NavigationToolbarUtil::CreateToolBarDividerNodeIfNeeded(nodeBase);
566     }
567     bool needMoreButton = toolBarItems.size() > MAXIMUM_TOOLBAR_ITEMS_IN_BAR;
568     RefPtr<FrameNode> barMenuNode = nullptr;
569     if (!BuildToolBarItems(toolBarNode, toolBarItems, fieldProperty, enabled, barMenuNode)) {
570         return;
571     }
572     if (needMoreButton) {
573         nodeBase->SetToolbarMenuNode(barMenuNode);
574     }
575     nodeBase->SetToolBarNode(toolBarNode);
576     nodeBase->SetPreToolBarNode(toolBarNode);
577     nodeBase->UpdatePrevToolBarIsCustom(false);
578     nodeBase->SetIsUseToolbarConfiguration(true);
579     auto navDestinationPatternBase = nodeBase->GetPattern<NavDestinationPatternBase>();
580     CHECK_NULL_VOID(navDestinationPatternBase);
581     navDestinationPatternBase->SetToolBarMenuItems(toolBarItems);
582 }
583 
SetCustomToolBar(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<AceType> & customNode)584 void NavigationToolbarUtil::SetCustomToolBar(
585     const RefPtr<NavDestinationNodeBase>& nodeBase, const RefPtr<AceType>& customNode)
586 {
587     CHECK_NULL_VOID(nodeBase);
588     auto customToolBar = AceType::DynamicCast<NG::UINode>(customNode);
589     CHECK_NULL_VOID(customToolBar);
590     if (nodeBase->GetPrevToolBarIsCustom().value_or(false)) {
591         if (customToolBar->GetId() == nodeBase->GetToolBarNode()->GetId()) {
592             nodeBase->UpdateToolBarNodeOperation(ChildNodeOperation::NONE);
593             nodeBase->UpdatePrevToolBarIsCustom(true);
594             return;
595         }
596     }
597     nodeBase->UpdateToolBarNodeOperation(ChildNodeOperation::REPLACE);
598     auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
599     CHECK_NULL_VOID(toolBarNode);
600     toolBarNode->Clean();
601     customToolBar->MountToParent(toolBarNode);
602     nodeBase->UpdatePrevToolBarIsCustom(true);
603     toolBarNode->SetHasValidContent(true);
604     auto property = toolBarNode->GetLayoutProperty();
605     CHECK_NULL_VOID(property);
606     property->UpdateVisibility(VisibleType::VISIBLE);
607 }
608 
SetToolbarOptions(const RefPtr<NavDestinationNodeBase> & nodeBase,NavigationToolbarOptions && opt)609 void NavigationToolbarUtil::SetToolbarOptions(
610     const RefPtr<NavDestinationNodeBase>& nodeBase, NavigationToolbarOptions&& opt)
611 {
612     CHECK_NULL_VOID(nodeBase);
613     auto navDestinationPatternBase = nodeBase->GetPattern<NavDestinationPatternBase>();
614     CHECK_NULL_VOID(navDestinationPatternBase);
615     navDestinationPatternBase->SetToolBarStyle(opt.brOptions.barStyle);
616     auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
617     CHECK_NULL_VOID(toolBarNode);
618     auto toolBarPattern = toolBarNode->GetPattern<NavToolbarPattern>();
619     CHECK_NULL_VOID(toolBarPattern);
620     toolBarPattern->SetToolbarOptions(std::move(opt));
621 }
622 
MountToolBar(const RefPtr<NavDestinationNodeBase> & nodeBase,bool & needRunToolBarAnimation)623 void NavigationToolbarUtil::MountToolBar(
624     const RefPtr<NavDestinationNodeBase>& nodeBase, bool& needRunToolBarAnimation)
625 {
626     needRunToolBarAnimation = false;
627     CHECK_NULL_VOID(nodeBase);
628     auto toolbarNode = nodeBase->GetToolBarNode();
629     CHECK_NULL_VOID(toolbarNode);
630     auto navDestinationPatternBase = nodeBase->GetPattern<NavDestinationPatternBase>();
631     CHECK_NULL_VOID(navDestinationPatternBase);
632     auto propertyBase = nodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
633     CHECK_NULL_VOID(propertyBase);
634     auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(toolbarNode);
635     CHECK_NULL_VOID(toolBarNode);
636     auto toolBarLayoutProperty = toolBarNode->GetLayoutProperty<LayoutProperty>();
637     CHECK_NULL_VOID(toolBarLayoutProperty);
638     auto divider = AceType::DynamicCast<FrameNode>(nodeBase->GetToolBarDividerNode());
639 
640     if (nodeBase->GetToolBarNodeOperationValue(ChildNodeOperation::NONE) == ChildNodeOperation::REPLACE) {
641         nodeBase->RemoveChild(nodeBase->GetPreToolBarNode());
642         nodeBase->AddChild(toolbarNode);
643     }
644 
645     bool hideToolBar = propertyBase->GetHideToolBarValue(false);
646     auto currhideToolBar = navDestinationPatternBase->GetCurrHideToolBar();
647     if (currhideToolBar.has_value() && currhideToolBar.value() != hideToolBar && hideToolBar) {
648         /**
649          * we need reset translate&opacity of toolBar when state change from show to hide.
650          * @sa NavDestinationPattern::EnableTitleBarSwipe
651          */
652         NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, toolBarNode, 0.0f, false);
653     }
654     /**
655      * 1. At the initial state, animation is not required;
656      * 2. When toolbar is displayed at Title's menu position, no animation is needed for the toolbar.
657      */
658     if (!currhideToolBar.has_value() || !propertyBase->GetIsAnimatedToolBarValue(false) ||
659         navDestinationPatternBase->IsNeedHideToolBarForNavWidth()) {
660         navDestinationPatternBase->SetCurrHideToolBar(hideToolBar);
661         navDestinationPatternBase->HideOrShowToolBarImmediately(nodeBase, hideToolBar);
662         return;
663     }
664     toolBarNode->MarkModifyDone();
665     toolBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
666 
667     // Animation is needed only when the status changed.
668     needRunToolBarAnimation = currhideToolBar.value() != hideToolBar;
669     navDestinationPatternBase->SetCurrHideToolBar(hideToolBar);
670 }
671 } // namespace OHOS::Ace::NG