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