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