• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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/folder_stack/folder_stack_layout_algorithm.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/subwindow/subwindow_manager.h"
20 #include "base/utils/utils.h"
21 #include "core/common/container.h"
22 #include "core/common/display_info.h"
23 #include "core/components/common/layout/constants.h"
24 #include "core/components_ng/layout/layout_wrapper.h"
25 #include "core/components_ng/pattern/folder_stack/control_parts_stack_node.h"
26 #include "core/components_ng/pattern/folder_stack/folder_stack_group_node.h"
27 #include "core/components_ng/pattern/folder_stack/folder_stack_layout_property.h"
28 #include "core/components_ng/pattern/folder_stack/folder_stack_pattern.h"
29 #include "core/components_ng/pattern/folder_stack/hover_stack_node.h"
30 #include "core/components_ng/pattern/stack/stack_layout_algorithm.h"
31 #include "core/components_ng/pattern/stack/stack_layout_property.h"
32 #include "core/components_ng/syntax/if_else_model.h"
33 #include "core/pipeline/pipeline_base.h"
34 #include "core/pipeline_ng/pipeline_context.h"
35 
36 namespace OHOS::Ace::NG {
37 namespace {
38 constexpr float OFFSET_VALUE = 1.0f;
39 constexpr float OFFSET_DIVISOR = 2.0f;
40 } // namespace
41 
42 FolderStackLayoutAlgorithm::FolderStackLayoutAlgorithm() = default;
43 
Layout(LayoutWrapper * layoutWrapper)44 void FolderStackLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
45 {
46     auto folderStackLayoutProperty =
47         AceType::DynamicCast<FolderStackLayoutProperty>(layoutWrapper->GetLayoutProperty());
48     CHECK_NULL_VOID(folderStackLayoutProperty);
49     auto hostNode = AceType::DynamicCast<FolderStackGroupNode>(layoutWrapper->GetHostNode());
50     CHECK_NULL_VOID(hostNode);
51     auto align = Alignment::CENTER;
52     if (folderStackLayoutProperty->GetPositionProperty()) {
53         align = folderStackLayoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER);
54     }
55     if (!isIntoFolderStack_) {
56         auto childLayoutProperty = AceType::DynamicCast<StackLayoutProperty>(layoutWrapper->GetLayoutProperty());
57         if (childLayoutProperty->GetPositionProperty()) {
58             childLayoutProperty->GetPositionProperty()->UpdateAlignment(align);
59         }
60         StackLayoutAlgorithm::Layout(layoutWrapper);
61         return;
62     }
63     LayoutHoverStack(layoutWrapper, hostNode, folderStackLayoutProperty);
64     LayoutControlPartsStack(layoutWrapper, hostNode, folderStackLayoutProperty);
65 }
66 
LayoutHoverStack(LayoutWrapper * layoutWrapper,const RefPtr<FolderStackGroupNode> & hostNode,const RefPtr<FolderStackLayoutProperty> & folderStackLayoutProperty)67 void FolderStackLayoutAlgorithm::LayoutHoverStack(LayoutWrapper* layoutWrapper,
68     const RefPtr<FolderStackGroupNode>& hostNode, const RefPtr<FolderStackLayoutProperty>& folderStackLayoutProperty)
69 {
70     auto folderStackGeometryNode = layoutWrapper->GetGeometryNode();
71     auto size = folderStackGeometryNode->GetFrameSize();
72     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
73     auto layoutDirection = layoutWrapper->GetLayoutProperty()->GetLayoutDirection();
74     if (layoutDirection == TextDirection::AUTO) {
75         layoutDirection = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
76     }
77     MinusPaddingToSize(padding, size);
78     auto left = padding.left.value_or(0);
79     auto top = padding.top.value_or(0);
80     auto paddingOffset = OffsetF(left, top);
81     auto align = Alignment::CENTER;
82     if (folderStackLayoutProperty->GetPositionProperty()) {
83         align = folderStackLayoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER);
84     }
85     auto hoverNode = hostNode->GetHoverNode();
86     auto index = hostNode->GetChildIndexById(hoverNode->GetId());
87     auto hoverStackWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
88     auto geometryNode = hoverStackWrapper->GetGeometryNode();
89     auto hoverStackOffset = OffsetT<float>(0.0f, 0.0f);
90     geometryNode->SetMarginFrameOffset(hoverStackOffset);
91     auto hoverSize = geometryNode->GetFrameSize();
92     for (auto&& child : hoverStackWrapper->GetAllChildrenWithBuild()) {
93         auto translate =
94             CalculateStackAlignment(hoverSize, child->GetGeometryNode()->GetMarginFrameSize(), align) + paddingOffset;
95         if (layoutDirection == TextDirection::RTL) {
96             translate.SetX(
97                 hoverSize.Width() - translate.GetX() - child->GetGeometryNode()->GetMarginFrameSize().Width());
98         }
99         child->GetGeometryNode()->SetMarginFrameOffset(translate);
100     }
101     hoverStackWrapper->Layout();
102 }
103 
LayoutControlPartsStack(LayoutWrapper * layoutWrapper,const RefPtr<FolderStackGroupNode> & hostNode,const RefPtr<FolderStackLayoutProperty> & folderStackLayoutProperty)104 void FolderStackLayoutAlgorithm::LayoutControlPartsStack(LayoutWrapper* layoutWrapper,
105     const RefPtr<FolderStackGroupNode>& hostNode, const RefPtr<FolderStackLayoutProperty>& folderStackLayoutProperty)
106 {
107     auto folderStackGeometryNode = layoutWrapper->GetGeometryNode();
108     auto layoutDirection = layoutWrapper->GetLayoutProperty()->GetLayoutDirection();
109     if (layoutDirection == TextDirection::AUTO) {
110         layoutDirection = AceApplicationInfo::GetInstance().IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR;
111     }
112 
113     auto align = Alignment::CENTER;
114     if (folderStackLayoutProperty->GetPositionProperty()) {
115         align = folderStackLayoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER);
116     }
117     auto controlPartsStackNode = hostNode->GetControlPartsStackNode();
118     auto index = hostNode->GetChildIndexById(controlPartsStackNode->GetId());
119     auto controlPartsStackWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
120     auto geometryNode = controlPartsStackWrapper->GetGeometryNode();
121     auto controlPartsStackRect = GetControlPartsStackRect();
122     geometryNode->SetMarginFrameOffset(controlPartsStackRect);
123     controlPartsStackWrapper->Layout();
124 }
125 
Measure(LayoutWrapper * layoutWrapper)126 void FolderStackLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
127 {
128     CHECK_NULL_VOID(layoutWrapper);
129     auto hostNode = AceType::DynamicCast<FolderStackGroupNode>(layoutWrapper->GetHostNode());
130     CHECK_NULL_VOID(hostNode);
131     auto pattern = layoutWrapper->GetHostNode()->GetPattern<FolderStackPattern>();
132     CHECK_NULL_VOID(pattern);
133     const auto& layoutProperty = DynamicCast<FolderStackLayoutProperty>(layoutWrapper->GetLayoutProperty());
134     CHECK_NULL_VOID(layoutProperty);
135     const auto& layoutConstraint = layoutProperty->GetLayoutConstraint();
136     CHECK_NULL_VOID(layoutConstraint);
137     auto geometryNode = layoutWrapper->GetGeometryNode();
138     auto size = CreateIdealSizeByPercentRef(layoutConstraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT)
139                     .ConvertToSizeT();
140     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
141     isIntoFolderStack_ = IsIntoFolderStack(size, layoutProperty, layoutWrapper);
142     AdjustNodeTree(hostNode);
143     OnHoverStatusChange(layoutWrapper);
144     if (!isIntoFolderStack_) {
145         MeasureByStack(hostNode, layoutWrapper);
146         pattern->SetNeedCallBack(false);
147         return;
148     }
149     if (!pattern->GetNeedCallBack()) {
150         pattern->SetNeedCallBack(true);
151         auto displayInfo = pattern->GetDisplayInfo();
152         if (displayInfo) {
153             FolderEventInfo event(displayInfo->GetFoldStatus());
154             auto eventHub = layoutWrapper->GetHostNode()->GetEventHub<FolderStackEventHub>();
155             if (eventHub) {
156                 eventHub->OnFolderStateChange(event);
157             }
158         }
159     }
160     RangeCalculation(hostNode, layoutProperty, size);
161     MeasureHoverStack(layoutWrapper, hostNode, layoutProperty, size);
162     MeasureControlPartsStack(layoutWrapper, hostNode, layoutProperty, size);
163 }
164 
MeasureHoverStack(LayoutWrapper * layoutWrapper,const RefPtr<FolderStackGroupNode> & hostNode,const RefPtr<FolderStackLayoutProperty> & foldStackLayoutProperty,const SizeF & size)165 void FolderStackLayoutAlgorithm::MeasureHoverStack(LayoutWrapper* layoutWrapper,
166     const RefPtr<FolderStackGroupNode>& hostNode, const RefPtr<FolderStackLayoutProperty>& foldStackLayoutProperty,
167     const SizeF& size)
168 {
169     auto hoverNode = hostNode->GetHoverNode();
170     CHECK_NULL_VOID(hoverNode);
171     auto index = hostNode->GetChildIndexById(hoverNode->GetId());
172     auto hoverWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
173     CHECK_NULL_VOID(hoverWrapper);
174     auto constraint = foldStackLayoutProperty->CreateChildConstraint();
175     constraint.selfIdealSize = OptionalSizeF(size.Width(), preHoverStackHeight_);
176     hoverWrapper->Measure(constraint);
177 }
178 
MeasureControlPartsStack(LayoutWrapper * layoutWrapper,const RefPtr<FolderStackGroupNode> & hostNode,const RefPtr<FolderStackLayoutProperty> & foldStackLayoutProperty,const SizeF & size)179 void FolderStackLayoutAlgorithm::MeasureControlPartsStack(LayoutWrapper* layoutWrapper,
180     const RefPtr<FolderStackGroupNode>& hostNode, const RefPtr<FolderStackLayoutProperty>& foldStackLayoutProperty,
181     const SizeF& size)
182 {
183     auto controlPartsStackNode = hostNode->GetControlPartsStackNode();
184     CHECK_NULL_VOID(controlPartsStackNode);
185     auto index = hostNode->GetChildIndexById(controlPartsStackNode->GetId());
186     auto controlPartsWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
187     CHECK_NULL_VOID(controlPartsWrapper);
188     auto constraint = foldStackLayoutProperty->CreateChildConstraint();
189     constraint.selfIdealSize = OptionalSizeF(size.Width(), preControlPartsStackHeight_);
190     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
191     PaddingProperty controlPartsPadding;
192     controlPartsPadding.left = CalcLength(padding.left.value_or(0));
193     controlPartsPadding.right = CalcLength(padding.right.value_or(0));
194     controlPartsPadding.top = CalcLength(padding.top.value_or(0));
195     controlPartsPadding.bottom = CalcLength(padding.bottom.value_or(0));
196     controlPartsWrapper->GetLayoutProperty()->UpdatePadding(controlPartsPadding);
197     controlPartsWrapper->Measure(constraint);
198 }
199 
RangeCalculation(const RefPtr<FolderStackGroupNode> & hostNode,const RefPtr<FolderStackLayoutProperty> & folderStackLayoutProperty,const SizeF & size)200 void FolderStackLayoutAlgorithm::RangeCalculation(const RefPtr<FolderStackGroupNode>& hostNode,
201     const RefPtr<FolderStackLayoutProperty>& folderStackLayoutProperty, const SizeF& size)
202 {
203     int32_t creaseY = 0;
204     int32_t creaseHeight = 0;
205     const auto& constraint = folderStackLayoutProperty->GetLayoutConstraint();
206     CHECK_NULL_VOID(constraint);
207     auto pipeline = PipelineContext::GetCurrentContext();
208     CHECK_NULL_VOID(pipeline);
209     auto safeArea = pipeline->GetSafeArea();
210     int32_t length = static_cast<int32_t>(safeArea.top_.Length());
211     auto container = Container::Current();
212     CHECK_NULL_VOID(container);
213     auto displayInfo = container->GetDisplayInfo();
214     CHECK_NULL_VOID(displayInfo);
215     auto foldCreaseRects = displayInfo->GetCurrentFoldCreaseRegion();
216     if (!foldCreaseRects.empty()) {
217         auto foldCrease = foldCreaseRects.front();
218         creaseY = static_cast<int32_t>(foldCrease.Bottom() - foldCrease.Height());
219         creaseHeight = static_cast<int32_t>(foldCrease.Height());
220     }
221     preHoverStackHeight_ = static_cast<float>(creaseY - length);
222     preControlPartsStackHeight_ = static_cast<float>(size.Height() - creaseHeight - preHoverStackHeight_);
223     controlPartsStackRect_ = OffsetF(0.0f, creaseY - length + creaseHeight);
224 }
225 
IsFullWindow(SizeF & frameSize,const RefPtr<FolderStackLayoutProperty> & foldStackLayoutProperty,LayoutWrapper * layoutWrapper)226 bool FolderStackLayoutAlgorithm::IsFullWindow(
227     SizeF& frameSize, const RefPtr<FolderStackLayoutProperty>& foldStackLayoutProperty, LayoutWrapper* layoutWrapper)
228 {
229     auto host = layoutWrapper->GetHostNode();
230     CHECK_NULL_RETURN(host, false);
231     auto parent = AceType::DynamicCast<FrameNode>(host->GetParent());
232     CHECK_NULL_RETURN(parent, false);
233     auto padding = parent->GetLayoutProperty()->CreatePaddingAndBorder();
234     auto pipeline = PipelineContext::GetCurrentContext();
235     CHECK_NULL_RETURN(pipeline, false);
236     auto windowManager = pipeline->GetWindowManager();
237     auto safeArea = pipeline->GetSafeArea();
238     CHECK_NULL_RETURN(windowManager, false);
239     auto windowMode = windowManager->GetWindowMode();
240     auto realWidth = frameSize.Width() + padding.Width();
241     auto realHeight = frameSize.Height() + padding.Height();
242     if (!NearEqual(realWidth, pipeline->GetRootWidth() - safeArea.left_.Length() - safeArea.right_.Length()) ||
243         !NearEqual(realHeight, pipeline->GetRootHeight() - safeArea.top_.Length() - safeArea.bottom_.Length()) ||
244         windowMode != WindowMode::WINDOW_MODE_FULLSCREEN) {
245         return false;
246     }
247     return true;
248 }
249 
AdjustNodeTree(const RefPtr<FolderStackGroupNode> & hostNode)250 void FolderStackLayoutAlgorithm::AdjustNodeTree(const RefPtr<FolderStackGroupNode>& hostNode)
251 {
252     auto hoverNode = hostNode->GetHoverNode();
253     auto controlPartsStackNode = hostNode->GetControlPartsStackNode();
254     auto isChangeItemId = hostNode->GetIsChangeItemId();
255     if (isChangeItemId) {
256         hostNode->SetIsChangeItemId(false);
257     } else if ((!isIntoFolderStack_ && hoverNode->GetChildren().size() == 0) ||
258         (isIntoFolderStack_ && hoverNode->GetChildren().size() > 0)) {
259         return;
260     }
261 
262     for (auto& hover : hoverNode->GetChildren()) {
263         hoverNode->RemoveChild(hover);
264     }
265     for (auto& controlPart : controlPartsStackNode->GetChildren()) {
266         controlPartsStackNode->RemoveChild(controlPart);
267     }
268     if (!isIntoFolderStack_) {
269         for (auto& childNode : hostNode->GetChildNode()) {
270             controlPartsStackNode->AddChild(childNode);
271         }
272     } else {
273         auto itemId = hostNode->GetItemId();
274         for (auto& childNode : hostNode->GetChildNode()) {
275             if (std::count(itemId.begin(), itemId.end(), childNode->GetInspectorId())) {
276                 hoverNode->AddChild(childNode);
277             } else {
278                 controlPartsStackNode->AddChild(childNode);
279             }
280         }
281     }
282 }
283 
CalculateStackAlignment(const NG::SizeF & parentSize,const NG::SizeF & childSize,const Alignment & alignment)284 NG::OffsetF FolderStackLayoutAlgorithm::CalculateStackAlignment(
285     const NG::SizeF& parentSize, const NG::SizeF& childSize, const Alignment& alignment)
286 {
287     NG::OffsetF offset;
288     offset.SetX((OFFSET_VALUE + alignment.GetHorizontal()) * (parentSize.Width() - childSize.Width()) / OFFSET_DIVISOR);
289     offset.SetY((OFFSET_VALUE + alignment.GetVertical()) * (parentSize.Height() - childSize.Height()) / OFFSET_DIVISOR);
290     return offset;
291 }
292 
IsIntoFolderStack(SizeF & frameSize,const RefPtr<FolderStackLayoutProperty> & foldStackLayoutProperty,LayoutWrapper * layoutWrapper)293 bool FolderStackLayoutAlgorithm::IsIntoFolderStack(
294     SizeF& frameSize, const RefPtr<FolderStackLayoutProperty>& foldStackLayoutProperty, LayoutWrapper* layoutWrapper)
295 {
296     auto pattern = layoutWrapper->GetHostNode()->GetPattern<FolderStackPattern>();
297     CHECK_NULL_RETURN(pattern, false);
298     auto displayInfo = pattern->GetDisplayInfo();
299     if (!displayInfo) {
300         auto container = Container::Current();
301         CHECK_NULL_RETURN(container, false);
302         displayInfo = container->GetDisplayInfo();
303     }
304     CHECK_NULL_RETURN(displayInfo, false);
305     bool isFullWindow = IsFullWindow(frameSize, foldStackLayoutProperty, layoutWrapper);
306     bool isFoldable = displayInfo->GetIsFoldable();
307     auto foldStatus = displayInfo->GetFoldStatus();
308     auto rotation = displayInfo->GetRotation();
309     auto isLandscape = rotation == Rotation::ROTATION_90 || rotation == Rotation::ROTATION_270;
310     TAG_LOGI(AceLogTag::ACE_FOLDER_STACK,
311         "folderStack state isFullWindow:%{public}d, isFoldable:%{public}d, "
312         "foldStatus:%{public}d, isLandscape:%{public}d",
313         isFullWindow, isFoldable, foldStatus, isLandscape);
314     return isFullWindow && isFoldable && foldStatus == FoldStatus::HALF_FOLD && isLandscape;
315 }
316 
OnHoverStatusChange(LayoutWrapper * layoutWrapper)317 void FolderStackLayoutAlgorithm::OnHoverStatusChange(LayoutWrapper* layoutWrapper)
318 {
319     auto pattern = layoutWrapper->GetHostNode()->GetPattern<FolderStackPattern>();
320     CHECK_NULL_VOID(pattern);
321     if (isIntoFolderStack_ == pattern->IsInHoverMode()) {
322         return;
323     }
324     auto eventHub = layoutWrapper->GetHostNode()->GetEventHub<FolderStackEventHub>();
325     auto pipeline = PipelineContext::GetCurrentContext();
326     CHECK_NULL_VOID(pipeline);
327     auto windowManager = pipeline->GetWindowManager();
328     CHECK_NULL_VOID(windowManager);
329     auto windowMode = windowManager->GetWindowMode();
330     auto displayInfo = pattern->GetDisplayInfo();
331     FolderEventInfo hoverChangeEvent(
332         displayInfo->GetFoldStatus(), isIntoFolderStack_, displayInfo->GetRotation(), windowMode);
333     if (eventHub) {
334         eventHub->OnHoverStatusChange(std::move(hoverChangeEvent));
335         TAG_LOGI(AceLogTag::ACE_FOLDER_STACK,
336             "hoverStatus change callback FoldStatus:%{public}d, isHoverMode:%{public}d, "
337             "appRotation:%{public}d, windowMode:%{public}d",
338             displayInfo->GetFoldStatus(), isIntoFolderStack_, displayInfo->GetRotation(), windowMode);
339     }
340 }
341 
MeasureByStack(const RefPtr<FolderStackGroupNode> & hostNode,LayoutWrapper * layoutWrapper)342 void FolderStackLayoutAlgorithm::MeasureByStack(
343     const RefPtr<FolderStackGroupNode>& hostNode, LayoutWrapper* layoutWrapper)
344 {
345     PaddingProperty padding { CalcLength(0.0f), CalcLength(0.0f), CalcLength(0.0f), CalcLength(0.0f) };
346     auto controlPartsStackNode = hostNode->GetControlPartsStackNode();
347     CHECK_NULL_VOID(controlPartsStackNode);
348     auto index = hostNode->GetChildIndexById(controlPartsStackNode->GetId());
349     auto controlPartsWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
350     CHECK_NULL_VOID(controlPartsWrapper);
351     controlPartsWrapper->GetLayoutProperty()->UpdatePadding(padding);
352     StackLayoutAlgorithm::Measure(layoutWrapper);
353     auto hoverNode = hostNode->GetHoverNode();
354     CHECK_NULL_VOID(hoverNode);
355     auto hoverIndex = hostNode->GetChildIndexById(hoverNode->GetId());
356     auto hoverStackWrapper = layoutWrapper->GetOrCreateChildByIndex(hoverIndex);
357     CHECK_NULL_VOID(hoverStackWrapper);
358     auto geometryNode = hoverStackWrapper->GetGeometryNode();
359     geometryNode->SetFrameSize(controlPartsWrapper->GetGeometryNode()->GetFrameSize());
360 }
361 } // namespace OHOS::Ace::NG
362