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