• 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/navigation_pattern.h"
17 
18 #include "base/memory/referenced.h"
19 #include "base/mousestyle/mouse_style.h"
20 #include "base/utils/utils.h"
21 #include "core/components/common/layout/constants.h"
22 #include "core/components_ng/pattern/button/button_pattern.h"
23 #include "core/components_ng/pattern/image/image_layout_property.h"
24 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
25 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
26 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
27 #include "core/components_ng/pattern/navigation/navigation_event_hub.h"
28 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
29 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
30 #include "core/components_ng/pattern/navigation/navigation_model_data.h"
31 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
32 #include "core/components_ng/pattern/navrouter/navdestination_event_hub.h"
33 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
34 #include "core/components_ng/pattern/navrouter/navdestination_layout_property.h"
35 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
36 #include "core/components_ng/pattern/navrouter/navrouter_group_node.h"
37 #include "core/components_ng/property/property.h"
38 #include "core/gestures/gesture_info.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 #include "core/pipeline_ng/ui_task_scheduler.h"
41 
42 namespace OHOS::Ace::NG {
43 
44 constexpr int32_t NAVIMODE_CHANGE_ANIMATION_DURATION = 250;
45 constexpr int32_t OPACITY_ANIMATION_DURATION_APPEAR = 150;
46 constexpr int32_t OPACITY_ANIMATION_DURATION_DISAPPEAR = 250;
47 constexpr Dimension DEFAULT_DRAG_REGION = 20.0_vp;
48 constexpr float DEFAULT_HALF = 2.0f;
49 
50 namespace {
51 
52 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
53 
54 } // namespace
55 
GetTitleBarRenderContext()56 RefPtr<RenderContext> NavigationPattern::GetTitleBarRenderContext()
57 {
58     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
59     CHECK_NULL_RETURN(hostNode, nullptr);
60     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
61     CHECK_NULL_RETURN(layoutProperty, nullptr);
62     auto contentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
63     CHECK_NULL_RETURN(contentNode, nullptr);
64     if (contentNode->FindChildNodeOfClass<NavDestinationGroupNode>()) {
65         auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
66         CHECK_NULL_RETURN(navBarNode, nullptr);
67         auto renderContext = navBarNode->GetRenderContext();
68         return renderContext;
69     } else {
70         auto renderContext = contentNode->GetRenderContext();
71         return renderContext;
72     }
73 }
74 
DoAnimation(NavigationMode usrNavigationMode)75 void NavigationPattern::DoAnimation(NavigationMode usrNavigationMode)
76 {
77     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
78     CHECK_NULL_VOID(hostNode);
79     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
80     CHECK_NULL_VOID(layoutProperty);
81 
82     auto context = PipelineContext::GetCurrentContext();
83     CHECK_NULL_VOID(context);
84     layoutProperty->UpdateNavigationMode(navigationMode_);
85     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
86     AnimationOption option = AnimationOption();
87     option.SetDuration(NAVIMODE_CHANGE_ANIMATION_DURATION);
88     option.SetCurve(Curves::FRICTION);
89     option.SetFillMode(FillMode::FORWARDS);
90     AnimationOption optionAlpha = AnimationOption();
91     optionAlpha.SetCurve(Curves::SHARP);
92     optionAlpha.SetFillMode(FillMode::FORWARDS);
93     auto renderContext = GetTitleBarRenderContext();
94     CHECK_NULL_VOID(renderContext);
95 
96     std::function<void()> finishCallback = [optionAlpha, renderContext, hostNode]() {
97         renderContext->OpacityAnimation(optionAlpha, 0, 1);
98         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
99     };
100 
101     context->OpenImplicitAnimation(option, option.GetCurve(), finishCallback);
102     layoutProperty->UpdateNavigationMode(usrNavigationMode);
103     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
104     context->FlushUITasks();
105     if (usrNavigationMode == NavigationMode::STACK || navigationMode_ == NavigationMode::SPLIT) {
106         optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_DISAPPEAR);
107         renderContext->OpacityAnimation(optionAlpha, 1, 0);
108     } else if (usrNavigationMode == NavigationMode::SPLIT || navigationMode_ == NavigationMode::STACK) {
109         optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_APPEAR);
110         renderContext->OpacityAnimation(optionAlpha, 0, 1);
111     }
112     context->CloseImplicitAnimation();
113     navigationMode_ = usrNavigationMode;
114 }
115 
OnAttachToFrameNode()116 void NavigationPattern::OnAttachToFrameNode()
117 {
118     auto host = GetHost();
119     CHECK_NULL_VOID(host);
120     auto pipelineContext = PipelineContext::GetCurrentContext();
121     CHECK_NULL_VOID(pipelineContext);
122     pipelineContext->AddWindowStateChangedCallback(host->GetId());
123 }
124 
OnDetachFromFrameNode(FrameNode * frameNode)125 void NavigationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
126 {
127     auto id = frameNode->GetId();
128     auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
129     CHECK_NULL_VOID_NOLOG(pipeline);
130     pipeline->RemoveWindowStateChangedCallback(id);
131 }
132 
OnModifyDone()133 void NavigationPattern::OnModifyDone()
134 {
135     Pattern::OnModifyDone();
136     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
137     CHECK_NULL_VOID(hostNode);
138     auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
139     CHECK_NULL_VOID(navBarNode);
140     navBarNode->MarkModifyDone();
141     auto preTopNavPath = navigationStack_->GetPreTopNavPath();
142     auto pathNames = navigationStack_->GetAllPathName();
143     auto preSize = navigationStack_->PreSize();
144 
145     NavPathList navPathList;
146     for (size_t i = 0; i < pathNames.size(); ++i) {
147         auto pathName = pathNames[i];
148         RefPtr<UINode> uiNode = navigationStack_->Get(pathName);
149         if (uiNode) {
150             navPathList.emplace_back(std::make_pair(pathName, uiNode));
151             navigationStack_->RemoveInNavPathList(pathName, uiNode);
152             navigationStack_->RemoveInPreNavPathList(pathName, uiNode);
153             continue;
154         }
155         uiNode = navigationStack_->GetFromPreBackup(pathName);
156         if (uiNode) {
157             navPathList.emplace_back(std::make_pair(pathName, uiNode));
158             navigationStack_->RemoveInPreNavPathList(pathName, uiNode);
159             continue;
160         }
161         uiNode = GenerateUINodeByIndex(static_cast<int32_t>(i));
162         navPathList.emplace_back(std::make_pair(pathName, uiNode));
163     }
164 
165     navigationStack_->SetNavPathList(navPathList);
166     hostNode->UpdateNavDestinationNodeWithoutMarkDirty(preTopNavPath.has_value() ? preTopNavPath->second : nullptr);
167     auto newTopNavPath = navigationStack_->GetTopNavPath();
168     auto size = navigationStack_->Size();
169     CheckTopNavPathChange(preTopNavPath, newTopNavPath, preSize > size);
170 
171     auto pipeline = PipelineContext::GetCurrentContext();
172     CHECK_NULL_VOID(pipeline);
173     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
174 
175     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
176         auto dividerNode = GetDividerNode();
177         CHECK_NULL_VOID(dividerNode);
178         auto gestureHub = dividerNode->GetOrCreateGestureEventHub();
179         CHECK_NULL_VOID(gestureHub);
180         InitDragEvent(gestureHub);
181         auto inputHub = dividerNode->GetOrCreateInputEventHub();
182         CHECK_NULL_VOID(inputHub);
183         InitDividerMouseEvent(inputHub);
184     }
185 }
186 
CheckTopNavPathChange(const std::optional<std::pair<std::string,RefPtr<UINode>>> & preTopNavPath,const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath,bool isPopPage)187 void NavigationPattern::CheckTopNavPathChange(
188     const std::optional<std::pair<std::string, RefPtr<UINode>>>& preTopNavPath,
189     const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath, bool isPopPage)
190 {
191     if (preTopNavPath == newTopNavPath) {
192         return;
193     }
194     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
195     CHECK_NULL_VOID(hostNode);
196     auto contentNode = hostNode->GetContentNode();
197     CHECK_NULL_VOID(contentNode);
198     auto context = PipelineContext::GetCurrentContext();
199     CHECK_NULL_VOID(context);
200     // fire onHidden and lostFocus event
201     RefPtr<NavDestinationGroupNode> preTopNavDestination;
202     if (preTopNavPath.has_value()) {
203         // pre page is not in the current stack
204         isPopPage |= navigationStack_->FindIndex(preTopNavPath->first, preTopNavPath->second, true) == -1;
205         preTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
206             NavigationGroupNode::GetNavDestinationNode(preTopNavPath->second));
207         if (preTopNavDestination) {
208             auto navDestinationPattern =
209                 AceType::DynamicCast<NavDestinationPattern>(preTopNavDestination->GetPattern());
210             CHECK_NULL_VOID(navDestinationPattern);
211             if (navDestinationPattern->GetIsOnShow()) {
212                 auto eventHub = preTopNavDestination->GetEventHub<NavDestinationEventHub>();
213                 CHECK_NULL_VOID(eventHub);
214                 eventHub->FireOnHiddenEvent();
215                 navDestinationPattern->SetIsOnShow(false);
216             }
217             auto focusHub = preTopNavDestination->GetOrCreateFocusHub();
218             focusHub->SetParentFocusable(false);
219             focusHub->LostFocus();
220 
221             // in STACK mode with pop page, need to remain page until animation is finished
222             if (navigationMode_ != NavigationMode::STACK && isPopPage) {
223                 // without animation, clean content directly
224                 auto navDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
225                 auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
226                 if (shallowBuilder) {
227                     shallowBuilder->MarkIsExecuteDeepRenderDone(false);
228                 }
229                 if (preTopNavDestination->GetContentNode()) {
230                     preTopNavDestination->GetContentNode()->Clean();
231                 }
232                 auto parent = preTopNavDestination->GetParent();
233                 if (parent) {
234                     parent->RemoveChild(preTopNavDestination);
235                 }
236             }
237         } else {
238             LOGW("prev page is illegal");
239         }
240     } else {
241         // navBar to new top page case
242         auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
243         CHECK_NULL_VOID(navBarNode);
244         auto focusHub = navBarNode->GetOrCreateFocusHub();
245         focusHub->SetParentFocusable(false);
246         focusHub->LostFocus();
247     }
248 
249     RefPtr<NavDestinationGroupNode> newTopNavDestination;
250     // fire onShown and requestFocus Event
251     if (newTopNavPath.has_value()) {
252         newTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
253             NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second));
254         if (newTopNavDestination) {
255             auto navDestinationPattern =
256                 AceType::DynamicCast<NavDestinationPattern>(newTopNavDestination->GetPattern());
257             CHECK_NULL_VOID(navDestinationPattern);
258             if (!navDestinationPattern->GetIsOnShow()) {
259                 auto eventHub = newTopNavDestination->GetEventHub<NavDestinationEventHub>();
260                 CHECK_NULL_VOID(eventHub);
261                 eventHub->FireOnShownEvent();
262                 navDestinationPattern->SetIsOnShow(true);
263             }
264             auto focusHub = newTopNavDestination->GetOrCreateFocusHub();
265             context->AddAfterLayoutTask([focusHub]() {
266                 focusHub->SetParentFocusable(true);
267                 focusHub->RequestFocus();
268             });
269         } else {
270             LOGW("new page is illegal");
271         }
272     } else {
273         // back to navBar case
274         auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
275         CHECK_NULL_VOID(navBarNode);
276         navBarNode->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
277         navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
278         auto focusHub = navBarNode->GetOrCreateFocusHub();
279         focusHub->SetParentFocusable(true);
280         focusHub->RequestFocus();
281     }
282     if (navigationMode_ == NavigationMode::STACK) {
283         // animation need to run after layout task
284         context->AddAfterLayoutTask([preTopNavDestination, newTopNavDestination, isPopPage,
285                                         weakNavigationPattern = WeakClaim(this)]() {
286             auto navigationPattern = weakNavigationPattern.Upgrade();
287             CHECK_NULL_VOID(navigationPattern);
288             navigationPattern->DoNavigationTransitionAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
289         });
290     }
291     hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
292 }
293 
DoNavigationTransitionAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)294 void NavigationPattern::DoNavigationTransitionAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
295     const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
296 {
297     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
298     CHECK_NULL_VOID(navigationNode);
299     auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
300     CHECK_NULL_VOID(navBarNode);
301     if (newTopNavDestination && preTopNavDestination) {
302         if (isPopPage) {
303             navigationNode->ExitTransitionWithPop(preTopNavDestination);
304             navigationNode->EnterTransitionWithPop(newTopNavDestination);
305         } else {
306             navigationNode->ExitTransitionWithPush(preTopNavDestination);
307             navigationNode->EnterTransitionWithPush(newTopNavDestination);
308         }
309         return;
310     }
311 
312     // navBar push new destination page
313     if (newTopNavDestination) {
314         navigationNode->ExitTransitionWithPush(navBarNode, true);
315         navigationNode->EnterTransitionWithPush(newTopNavDestination);
316         return;
317     }
318 
319     // pop to navBar
320     if (preTopNavDestination) {
321         navigationNode->ExitTransitionWithPop(preTopNavDestination);
322         navigationNode->EnterTransitionWithPop(navBarNode, true);
323     }
324 }
325 
OnVisibleChange(bool isVisible)326 void NavigationPattern::OnVisibleChange(bool isVisible)
327 {
328     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
329     CHECK_NULL_VOID(hostNode);
330     auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
331     CHECK_NULL_VOID(eventHub);
332     eventHub->FireNavBarStateChangeEvent(isVisible);
333 }
334 
OnNavBarStateChange(bool modeChange)335 void NavigationPattern::OnNavBarStateChange(bool modeChange)
336 {
337     auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
338     CHECK_NULL_VOID(layoutProperty);
339     auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
340     if (visibilityValue != VisibleType::VISIBLE) {
341         return;
342     }
343 
344     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
345     CHECK_NULL_VOID(hostNode);
346     auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
347     CHECK_NULL_VOID(eventHub);
348     auto currentNavigationMode = GetNavigationMode();
349 
350     if (modeChange) {
351         if (currentNavigationMode == NavigationMode::SPLIT) {
352             if (layoutProperty->GetHideNavBarValue(false)) {
353                 eventHub->FireNavBarStateChangeEvent(false);
354             } else {
355                 eventHub->FireNavBarStateChangeEvent(true);
356             }
357         } else {
358             if (navigationStack_->Empty() && !layoutProperty->GetHideNavBarValue(false)) {
359                 eventHub->FireNavBarStateChangeEvent(true);
360             } else {
361                 eventHub->FireNavBarStateChangeEvent(false);
362             }
363         }
364         SetNavBarVisibilityChange(false);
365         return;
366     }
367 
368     if (GetNavBarVisibilityChange()) {
369         if (!layoutProperty->GetHideNavBarValue(false)) {
370             eventHub->FireNavBarStateChangeEvent(true);
371         } else {
372             eventHub->FireNavBarStateChangeEvent(false);
373         }
374         SetNavBarVisibilityChange(false);
375         return;
376     }
377 
378     // STACK mode, check navigationStack
379     if (navigationStack_->Empty()) {
380         eventHub->FireNavBarStateChangeEvent(true);
381     } else {
382         eventHub->FireNavBarStateChangeEvent(false);
383     }
384 }
385 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)386 bool NavigationPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
387 {
388     if (config.skipMeasure && config.skipLayout) {
389         return false;
390     }
391     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
392     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
393     auto navigationLayoutAlgorithm =
394         DynamicCast<NavigationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
395     CHECK_NULL_RETURN(navigationLayoutAlgorithm, false);
396     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
397     CHECK_NULL_RETURN(hostNode, false);
398     auto oldMode = navigationMode_;
399     navigationMode_ = navigationLayoutAlgorithm->GetNavigationMode();
400     OnNavBarStateChange(oldMode != navigationMode_);
401     auto context = PipelineContext::GetCurrentContext();
402     if (context) {
403         context->GetTaskExecutor()->PostTask(
404             [weak = WeakClaim(this), navigationStackWeak = WeakPtr<NavigationStack>(navigationStack_),
405                 navigationWeak = WeakPtr<NavigationGroupNode>(hostNode)] {
406                 auto pattern = weak.Upgrade();
407                 CHECK_NULL_VOID(pattern);
408                 auto navigationGroupNode = navigationWeak.Upgrade();
409                 CHECK_NULL_VOID(navigationGroupNode);
410                 auto navigationLayoutProperty =
411                     AceType::DynamicCast<NavigationLayoutProperty>(navigationGroupNode->GetLayoutProperty());
412                 CHECK_NULL_VOID(navigationLayoutProperty);
413                 auto navigationStack = navigationStackWeak.Upgrade();
414                 CHECK_NULL_VOID(navigationStack);
415                 auto curTopNavPath = navigationStack->GetTopNavPath();
416                 if (curTopNavPath.has_value()) {
417                     // considering backButton visibility
418                     auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
419                         NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
420                     if (navigationStack->Size() == 1 &&
421                         (pattern->GetNavigationMode() == NavigationMode::SPLIT ||
422                             navigationLayoutProperty->GetHideNavBar().value_or(false))) {
423                         // cases that backButton of navDestination is gone when there's only one child and
424                         // 1. In SPLIT mode, it's the first level page
425                         // 2. In STACK mode, the navBar is hidden
426                         navigationGroupNode->SetBackButtonVisible(curTopNavDestination, false);
427                     } else {
428                         navigationGroupNode->SetBackButtonVisible(curTopNavDestination, true);
429                     }
430                     pattern->UpdateContextRect(curTopNavDestination, navigationGroupNode);
431                 }
432                 // considering navBar visibility
433                 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationGroupNode->GetNavBarNode());
434                 CHECK_NULL_VOID(navBarNode);
435                 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
436                 CHECK_NULL_VOID(navBarLayoutProperty);
437                 if (navigationLayoutProperty->GetHideNavBar().value_or(false) ||
438                     (pattern->GetNavigationMode() == NavigationMode::STACK &&
439                         navigationGroupNode->GetNeedSetInvisible())) {
440                     navBarLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
441                 } else {
442                     navBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
443                 }
444             },
445             TaskExecutor::TaskType::UI);
446     }
447     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
448     CHECK_NULL_RETURN(navigationLayoutProperty, false);
449 
450     UpdateTitleModeChangeEventHub(hostNode);
451     AddDividerHotZoneRect(navigationLayoutAlgorithm);
452     ifNeedInit_ = false;
453     return false;
454 }
455 
UpdateContextRect(const RefPtr<NavDestinationGroupNode> & curDestination,const RefPtr<NavigationGroupNode> & hostNode)456 void NavigationPattern::UpdateContextRect(
457     const RefPtr<NavDestinationGroupNode>& curDestination, const RefPtr<NavigationGroupNode>& hostNode)
458 {
459     CHECK_NULL_VOID_NOLOG(curDestination);
460     CHECK_NULL_VOID_NOLOG(hostNode);
461     auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
462     CHECK_NULL_VOID_NOLOG(hostNode);
463     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
464     CHECK_NULL_VOID(navigationPattern);
465     auto size = curDestination->GetGeometryNode()->GetFrameSize();
466     curDestination->GetRenderContext()->ClipWithRRect(
467         RectF(0.0f, 0.0f, size.Width(), size.Height()), RadiusF(EdgeF(0.0f, 0.0f)));
468     curDestination->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
469 
470     if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
471         curDestination->GetRenderContext()->SetActualForegroundColor(DEFAULT_MASK_COLOR);
472         navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(false);
473         return;
474     }
475     auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
476     CHECK_NULL_VOID(navigationLayoutProperty);
477     auto navBarProperty = navBarNode->GetLayoutProperty();
478     navBarProperty->UpdateVisibility(navigationLayoutProperty->GetVisibilityValue(VisibleType::VISIBLE));
479     curDestination->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
480     curDestination->GetRenderContext()->SetActualForegroundColor(DEFAULT_MASK_COLOR);
481     navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
482     auto titleNode = AceType::DynamicCast<FrameNode>(navBarNode->GetTitle());
483     CHECK_NULL_VOID_NOLOG(titleNode);
484     titleNode->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
485 }
486 
UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode> & hostNode)487 bool NavigationPattern::UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode>& hostNode)
488 {
489     auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
490     CHECK_NULL_RETURN(navBarNode, false);
491     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
492     CHECK_NULL_RETURN(titleBarNode, false);
493     auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
494     CHECK_NULL_RETURN(titleBarLayoutProperty, false);
495     auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
496     CHECK_NULL_RETURN(eventHub, false);
497     if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
498         auto titleBarPattern = AceType::DynamicCast<TitleBarPattern>(titleBarNode->GetPattern());
499         CHECK_NULL_RETURN(titleBarPattern, false);
500         NavigationTitleMode titleMode = titleBarPattern->GetNavigationTitleMode();
501         if (titleMode != NavigationTitleMode::FREE && titleMode_ != titleMode) {
502             NavigationTitleModeChangeEvent navigationTitleModeChange(titleMode == NavigationTitleMode::MINI);
503             eventHub->FireChangeEvent(&navigationTitleModeChange);
504             titleMode_ = titleMode;
505         }
506     }
507     return true;
508 }
509 
GenerateUINodeByIndex(int32_t index)510 RefPtr<UINode> NavigationPattern::GenerateUINodeByIndex(int32_t index)
511 {
512     return navigationStack_->CreateNodeByIndex(index);
513 }
514 
InitDividerMouseEvent(const RefPtr<InputEventHub> & inputHub)515 void NavigationPattern::InitDividerMouseEvent(const RefPtr<InputEventHub>& inputHub)
516 {
517     CHECK_NULL_VOID(inputHub);
518     CHECK_NULL_VOID_NOLOG(!hoverEvent_);
519 
520     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
521         auto pattern = weak.Upgrade();
522         if (pattern) {
523             pattern->OnHover(isHover);
524         }
525     };
526     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
527     inputHub->AddOnHoverEvent(hoverEvent_);
528 }
529 
HandleDragStart()530 void NavigationPattern::HandleDragStart()
531 {
532     preNavBarWidth_ = realNavBarWidth_;
533 }
534 
HandleDragUpdate(float xOffset)535 void NavigationPattern::HandleDragUpdate(float xOffset)
536 {
537     auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
538     CHECK_NULL_VOID(navigationLayoutProperty);
539     auto host = GetHost();
540     CHECK_NULL_VOID(host);
541     auto geometryNode = host->GetGeometryNode();
542     CHECK_NULL_VOID(geometryNode);
543     auto frameSize = geometryNode->GetFrameSize();
544     auto frameWidth = frameSize.Width();
545     auto constraint = navigationLayoutProperty->GetLayoutConstraint();
546     auto parentSize = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
547 
548     float minNavBarWidthPx = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
549     float maxNavBarWidthPx = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
550     float minContentWidthPx = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
551     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
552 
553     auto navigationPosition = navigationLayoutProperty->GetNavBarPosition().value_or(NavBarPosition::START);
554     bool isNavBarStart = navigationPosition == NavBarPosition::START;
555     auto navBarLine = preNavBarWidth_ + (isNavBarStart ? xOffset : -xOffset);
556     float currentNavBarWidth = realNavBarWidth_;
557 
558     if (maxNavBarWidthPx + dividerWidth + minContentWidthPx > frameWidth) {
559         maxNavBarWidthPx = frameWidth - minContentWidthPx - dividerWidth;
560     }
561     navBarLine = std::min(navBarLine, maxNavBarWidthPx);
562 
563     if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
564         if (minContentWidthPx >= frameWidth) {
565             realNavBarWidth_ = 0.0f;
566         } else if (navBarLine + dividerWidth + minContentWidthPx <= frameWidth) {
567             realNavBarWidth_ = navBarLine;
568         } else {
569             realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
570         }
571     } else {
572         realDividerWidth_ = dividerWidth;
573         float remainingSpace = frameWidth - navBarLine - dividerWidth;
574         if (remainingSpace >= minContentWidthPx) {
575             realNavBarWidth_ = navBarLine;
576         } else if (remainingSpace < minContentWidthPx && navBarLine > minNavBarWidthPx) {
577             realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
578         } else {
579             realNavBarWidth_ = minNavBarWidthPx;
580         }
581     }
582     realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
583     realNavBarWidth_ = std::min(realNavBarWidth_, maxNavBarWidthPx);
584     realNavBarWidth_ = std::max(realNavBarWidth_, minNavBarWidthPx);
585 
586     // MEASURE
587     if (realNavBarWidth_ != currentNavBarWidth) {
588         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
589     }
590 }
591 
HandleDragEnd()592 void NavigationPattern::HandleDragEnd()
593 {
594     preNavBarWidth_ = realNavBarWidth_;
595 }
596 
InitDragEvent(const RefPtr<GestureEventHub> & gestureHub)597 void NavigationPattern::InitDragEvent(const RefPtr<GestureEventHub>& gestureHub)
598 {
599     CHECK_NULL_VOID_NOLOG(!dragEvent_);
600     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
601         auto pattern = weak.Upgrade();
602         CHECK_NULL_VOID_NOLOG(pattern);
603         pattern->HandleDragStart();
604     };
605     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
606         auto pattern = weak.Upgrade();
607         CHECK_NULL_VOID_NOLOG(pattern);
608         pattern->HandleDragUpdate(static_cast<float>(info.GetOffsetX()));
609     };
610     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
611         auto pattern = weak.Upgrade();
612         CHECK_NULL_VOID_NOLOG(pattern);
613         pattern->HandleDragEnd();
614     };
615     auto actionCancelTask = [weak = WeakClaim(this)]() {
616         auto pattern = weak.Upgrade();
617         CHECK_NULL_VOID_NOLOG(pattern);
618         pattern->HandleDragEnd();
619     };
620     dragEvent_ = MakeRefPtr<DragEvent>(
621         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
622     PanDirection panDirection = { .type = PanDirection::HORIZONTAL };
623     gestureHub->SetDragEvent(dragEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
624 }
625 
OnHover(bool isHover)626 void NavigationPattern::OnHover(bool isHover)
627 {
628     MouseFormat format = isHover ? MouseFormat::RESIZE_LEFT_RIGHT : MouseFormat::DEFAULT;
629     auto pipeline = PipelineContext::GetCurrentContext();
630     CHECK_NULL_VOID(pipeline);
631     auto windowId = pipeline->GetWindowId();
632     auto mouseStyle = MouseStyle::CreateMouseStyle();
633     int32_t currentPointerStyle = 0;
634     mouseStyle->GetPointerStyle(windowId, currentPointerStyle);
635     if (currentPointerStyle != static_cast<int32_t>(format)) {
636         mouseStyle->SetPointerStyle(windowId, format);
637     }
638 }
639 
GetDividerNode() const640 RefPtr<FrameNode> NavigationPattern::GetDividerNode() const
641 {
642     RefPtr<FrameNode> dividerFrameNode;
643     auto host = GetHost();
644     CHECK_NULL_RETURN(host, nullptr);
645     auto children = host->GetChildren();
646     for (auto begin = children.begin(); begin != children.end(); begin++) {
647         auto dividerNode = *begin;
648         if (dividerNode->GetTag() == V2::DIVIDER_ETS_TAG) {
649             dividerFrameNode = AceType::DynamicCast<FrameNode>(dividerNode);
650             CHECK_NULL_RETURN(dividerFrameNode, nullptr);
651             break;
652         }
653     }
654     return dividerFrameNode;
655 }
656 
AddDividerHotZoneRect(const RefPtr<NavigationLayoutAlgorithm> & layoutAlgorithm)657 void NavigationPattern::AddDividerHotZoneRect(const RefPtr<NavigationLayoutAlgorithm>& layoutAlgorithm)
658 {
659     CHECK_NULL_VOID(layoutAlgorithm);
660     if (realDividerWidth_ <= 0.0f) {
661         return;
662     }
663     OffsetF hotZoneOffset;
664     hotZoneOffset.SetX(-DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
665     hotZoneOffset.SetY(DEFAULT_DIVIDER_START_MARGIN.ConvertToPx());
666     SizeF hotZoneSize;
667     hotZoneSize.SetWidth(realDividerWidth_ + DIVIDER_HOT_ZONE_HORIZONTAL_PADDING_NUM *
668                                                  DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
669     hotZoneSize.SetHeight(layoutAlgorithm->GetRealNavBarHeight());
670     DimensionRect hotZoneRegion;
671     hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize.Width()), Dimension(hotZoneSize.Height())));
672     hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset.GetX()), Dimension(hotZoneOffset.GetY())));
673 
674     std::vector<DimensionRect> mouseRegion;
675     mouseRegion.emplace_back(hotZoneRegion);
676 
677     auto dividerFrameNode = GetDividerNode();
678     CHECK_NULL_VOID(dividerFrameNode);
679     auto dividerGestureHub = dividerFrameNode->GetOrCreateGestureEventHub();
680     CHECK_NULL_VOID(dividerGestureHub);
681     dividerGestureHub->SetMouseResponseRegion(mouseRegion);
682 
683     auto dragRectOffset = layoutAlgorithm->GetNavBarOffset();
684     dragRectOffset.SetX(-DEFAULT_DRAG_REGION.ConvertToPx());
685     dragRect_.SetOffset(dragRectOffset);
686     dragRect_.SetSize(SizeF(
687         DEFAULT_DRAG_REGION.ConvertToPx() * DEFAULT_HALF + realDividerWidth_, layoutAlgorithm->GetRealNavBarHeight()));
688 
689     std::vector<DimensionRect> responseRegion;
690     DimensionOffset responseOffset(dragRectOffset);
691     DimensionRect responseRect(Dimension(dragRect_.Width(), DimensionUnit::PX),
692         Dimension(dragRect_.Height(), DimensionUnit::PX), responseOffset);
693     responseRegion.emplace_back(responseRect);
694     dividerGestureHub->MarkResponseRegion(true);
695     dividerGestureHub->SetResponseRegion(responseRegion);
696 }
697 
OnWindowHide()698 void NavigationPattern::OnWindowHide()
699 {
700     auto curTopNavPath = navigationStack_->GetTopNavPath();
701     CHECK_NULL_VOID_NOLOG(curTopNavPath.has_value());
702     CHECK_NULL_VOID(curTopNavPath->second);
703     auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
704         NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
705     CHECK_NULL_VOID(curTopNavDestination);
706     auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(curTopNavDestination->GetPattern());
707     CHECK_NULL_VOID(navDestinationPattern);
708     CHECK_NULL_VOID_NOLOG(navDestinationPattern->GetIsOnShow());
709     auto eventHub = curTopNavDestination->GetEventHub<NavDestinationEventHub>();
710     CHECK_NULL_VOID(eventHub);
711     eventHub->FireOnHiddenEvent();
712     navDestinationPattern->SetIsOnShow(false);
713 }
714 
OnWindowShow()715 void NavigationPattern::OnWindowShow()
716 {
717     auto curTopNavPath = navigationStack_->GetTopNavPath();
718     CHECK_NULL_VOID_NOLOG(curTopNavPath.has_value());
719     CHECK_NULL_VOID(curTopNavPath->second);
720     auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
721         NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
722     CHECK_NULL_VOID(curTopNavDestination);
723     auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(curTopNavDestination->GetPattern());
724     CHECK_NULL_VOID(navDestinationPattern);
725     CHECK_NULL_VOID_NOLOG(!(navDestinationPattern->GetIsOnShow()));
726     auto eventHub = curTopNavDestination->GetEventHub<NavDestinationEventHub>();
727     eventHub->FireOnShownEvent();
728     navDestinationPattern->SetIsOnShow(true);
729 }
730 
OnColorConfigurationUpdate()731 void NavigationPattern::OnColorConfigurationUpdate()
732 {
733     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
734     auto pattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
735     CHECK_NULL_VOID(pattern);
736     const auto& navDestinationNodes = pattern->GetAllNavDestinationNodes();
737 
738     size_t size = navDestinationNodes.size();
739     for (size_t i = 0; i < size; i++) {
740         const auto& childNode = navDestinationNodes[i];
741         auto newNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
742             NavigationGroupNode::GetNavDestinationNode(childNode.second));
743         CHECK_NULL_VOID(newNavDestination);
744         auto destinationTitleBarNode = DynamicCast<TitleBarNode>(newNavDestination->GetTitleBarNode());
745         CHECK_NULL_VOID(destinationTitleBarNode);
746         auto backButtonNode = DynamicCast<FrameNode>(destinationTitleBarNode->GetBackButton());
747         CHECK_NULL_VOID(backButtonNode);
748         auto buttonPattern = backButtonNode->GetPattern<ButtonPattern>();
749         CHECK_NULL_VOID(buttonPattern);
750         buttonPattern->SetSkipColorConfigurationUpdate();
751         auto renderContext = backButtonNode->GetRenderContext();
752         CHECK_NULL_VOID(renderContext);
753         renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
754         backButtonNode->MarkModifyDone();
755         backButtonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
756     }
757 }
758 
759 } // namespace OHOS::Ace::NG
760