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