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