1 /*
2  * Copyright (c) 2022-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/panel/sliding_panel_layout_algorithm.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/geometry/ng/size_t.h"
21 #include "base/log/ace_trace.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/layout/grid_system_manager.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/layout/layout_algorithm.h"
27 #include "core/components_ng/pattern/panel/close_icon_layout_property.h"
28 #include "core/components_ng/pattern/panel/sliding_panel_layout_property.h"
29 #include "core/components_ng/property/layout_constraint.h"
30 #include "core/components_ng/property/measure_property.h"
31 #include "core/components_ng/property/measure_utils.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34 
35 namespace OHOS::Ace::NG {
36 
37 namespace {
38 
39 constexpr Dimension BLANK_MIN_HEIGHT = 8.0_vp;
40 constexpr Dimension DRAG_UP_THRESHOLD = 48.0_vp;
41 constexpr double HALF_VALUS = 2.0;
42 constexpr int32_t DOUBLENESS = 2;
43 
44 } // namespace
45 
Measure(LayoutWrapper * layoutWrapper)46 void SlidingPanelLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
47 {
48     CHECK_NULL_VOID(layoutWrapper);
49     auto layoutProperty = AceType::DynamicCast<SlidingPanelLayoutProperty>(layoutWrapper->GetLayoutProperty());
50     CHECK_NULL_VOID(layoutProperty);
51     auto layoutConstraint = layoutProperty->GetLayoutConstraint();
52     if (!layoutConstraint) {
53         return;
54     }
55     auto childLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
56     childLayoutConstraint.UpdateMaxSizeWithCheck(layoutConstraint->maxSize);
57     auto maxSize = childLayoutConstraint.maxSize;
58     auto idealSize =
59         !invisibleFlag_
60             ? ((PipelineBase::GetCurrentContext() && PipelineBase::GetCurrentContext()->GetMinPlatformVersion() > 9)
61                 ? CreateIdealSizeByPercentRef(layoutConstraint.value(), Axis::HORIZONTAL,
62                     layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT)).ConvertToSizeT()
63                 : CreateIdealSize(layoutConstraint.value(), Axis::HORIZONTAL,
64                     layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT), true))
65             : SizeF();
66     auto width = GetMaxWidthByScreenSizeType(maxSize, idealSize);
67     maxWidth_ = width;
68     idealSize_ = idealSize;
69     layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
70     layoutWrapper->GetGeometryNode()->SetContentSize(idealSize);
71     MinusPaddingToSize(layoutProperty->CreatePaddingAndBorder(), idealSize);
72     auto type = layoutProperty->GetPanelType();
73     if (type != PanelType::CUSTOM) {
74         childLayoutConstraint.minSize = SizeF(width, static_cast<float>(idealSize.Height() - currentOffset_));
75     }
76     childLayoutConstraint.maxSize = SizeF(width, static_cast<float>(idealSize.Height() - currentOffset_));
77     childLayoutConstraint.parentIdealSize =
78         OptionalSizeF(width, static_cast<float>(idealSize.Height() - currentOffset_));
79     if (type == PanelType::CUSTOM) {
80         auto calc = layoutProperty->GetCustomHeight().value_or(Dimension(0.0));
81         if (!calc.CalcValue().empty() && calc.CalcValue().find("wrapContent") != std::string::npos) {
82             childLayoutConstraint.maxSize = SizeF(width, static_cast<float>(idealSize.Height()));
83             childLayoutConstraint.parentIdealSize = OptionalSizeF(width, static_cast<float>(idealSize.Height()));
84         }
85     }
86     childLayoutConstraint.percentReference = childLayoutConstraint.maxSize;
87     layoutConstraint->percentReference = childLayoutConstraint.maxSize;
88     auto colunmNodeWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::COLUMN_ETS_TAG);
89     if (colunmNodeWrapper) {
90         colunmNodeWrapper->Measure(childLayoutConstraint);
91     }
92     auto closeIconWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::PANEL_CLOSE_ICON_ETS_TAG);
93     if (closeIconWrapper) {
94         MeasureCloseIcon(closeIconWrapper, layoutProperty);
95     }
96 }
97 
Layout(LayoutWrapper * layoutWrapper)98 void SlidingPanelLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
99 {
100     CHECK_NULL_VOID(layoutWrapper);
101     auto layoutProperty = AceType::DynamicCast<SlidingPanelLayoutProperty>(layoutWrapper->GetLayoutProperty());
102     CHECK_NULL_VOID(layoutProperty);
103     auto padding = layoutProperty->CreatePaddingAndBorder();
104     auto geometryNode = layoutWrapper->GetGeometryNode();
105     CHECK_NULL_VOID(geometryNode);
106 
107     auto frameSize = geometryNode->GetFrameSize();
108     auto columnWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::COLUMN_ETS_TAG);
109     CHECK_NULL_VOID(columnWrapper);
110     auto columnGeometryNode = columnWrapper->GetGeometryNode();
111     CHECK_NULL_VOID(columnGeometryNode);
112     auto leftPadding = 0.0f;
113     auto rightPadding = 0.0f;
114     if (geometryNode->GetPadding()) {
115         leftPadding = geometryNode->GetPadding()->left.value_or(0.0f);
116         rightPadding = geometryNode->GetPadding()->right.value_or(0.0f);
117     }
118     auto childOffsetX = static_cast<float>((idealSize_.Width() - leftPadding - rightPadding - maxWidth_) / HALF_VALUS);
119     fullHeight_ =
120         layoutProperty->GetFullHeight().value_or(Dimension(frameSize.Height() - BLANK_MIN_HEIGHT.ConvertToPx()));
121     halfHeight_ = layoutProperty->GetHalfHeight().value_or(
122         Dimension((frameSize.Height() - BLANK_MIN_HEIGHT.ConvertToPx()) / HALF_VALUS));
123     miniHeight_ = layoutProperty->GetMiniHeight().value_or(Dimension(DRAG_UP_THRESHOLD.ConvertToPx()));
124     customHeight_ = layoutProperty->GetCustomHeight().value_or(Dimension(0.0));
125     auto type = layoutProperty->GetPanelType();
126     if (type == PanelType::CUSTOM) {
127         auto calc = layoutProperty->GetCustomHeight().value_or(Dimension(0.0));
128         if (!calc.CalcValue().empty() && calc.CalcValue().find("wrapContent") != std::string::npos) {
129             customHeight_ = Dimension(columnGeometryNode->GetFrameSize().Height());
130         }
131     }
132 
133     auto childOffset = OffsetF();
134     if (isFirstLayout_) {
135         if (invisibleFlag_) {
136             auto rootHeight = PipelineContext::GetCurrentRootHeight();
137             childOffset = OffsetF(childOffsetX, rootHeight);
138         } else {
139             childOffset = OffsetF(childOffsetX, frameSize.Height());
140         }
141         columnWrapper->GetGeometryNode()->SetMarginFrameOffset(childOffset + padding.Offset());
142         isFirstLayout_ = false;
143     } else {
144         childOffset = OffsetF(childOffsetX, currentOffset_);
145         columnGeometryNode->SetMarginFrameOffset(childOffset + padding.Offset());
146     }
147     columnWrapper->Layout();
148 
149     auto closeIconWrapper = GetNodeLayoutWrapperByTag(layoutWrapper, V2::PANEL_CLOSE_ICON_ETS_TAG);
150     CHECK_NULL_VOID(closeIconWrapper);
151     auto closeIconLayoutProperty = AceType::DynamicCast<CloseIconLayoutProperty>(closeIconWrapper->GetLayoutProperty());
152     CHECK_NULL_VOID(closeIconLayoutProperty);
153     auto closeIconWidth = closeIconLayoutProperty->GetCloseIconWidthValue();
154     auto closeIconMarginTop = closeIconLayoutProperty->GetCloseIconMarginTopValue();
155     auto closeIconMargionRight = closeIconLayoutProperty->GetCloseIconMarginRightValue();
156     auto closeIconX = maxWidth_ + childOffsetX - static_cast<float>(closeIconWidth.ConvertToPx()) -
157                       static_cast<float>(closeIconMargionRight.ConvertToPx());
158     auto closeIconY = childOffset.GetY() + static_cast<float>(closeIconMarginTop.ConvertToPx());
159     auto closeIconOffset = OffsetF(closeIconX, closeIconY);
160     closeIconWrapper->GetGeometryNode()->SetMarginFrameOffset(closeIconOffset + padding.Offset());
161     closeIconWrapper->Layout();
162 }
163 
GetNodeLayoutWrapperByTag(LayoutWrapper * layoutWrapper,const std::string & tagName) const164 RefPtr<LayoutWrapper> SlidingPanelLayoutAlgorithm::GetNodeLayoutWrapperByTag(
165     LayoutWrapper* layoutWrapper, const std::string& tagName) const
166 {
167     CHECK_NULL_RETURN(layoutWrapper, nullptr);
168     auto totalChildCount = layoutWrapper->GetTotalChildCount();
169     if (totalChildCount == 0) {
170         return nullptr;
171     }
172     RefPtr<LayoutWrapper> nodeWrapper = nullptr;
173     for (int32_t i = 0; i < totalChildCount; i++) {
174         nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(i);
175         if (nodeWrapper && (nodeWrapper->GetHostTag() == tagName)) {
176             return nodeWrapper;
177         }
178     }
179     return nullptr;
180 }
181 
MeasureCloseIcon(const RefPtr<LayoutWrapper> & closeIconWrapper,const RefPtr<LayoutProperty> & layoutProperty) const182 void SlidingPanelLayoutAlgorithm::MeasureCloseIcon(
183     const RefPtr<LayoutWrapper>& closeIconWrapper, const RefPtr<LayoutProperty>& layoutProperty) const
184 {
185     CHECK_NULL_VOID(closeIconWrapper);
186     CHECK_NULL_VOID(layoutProperty);
187     auto slidingPanelLayoutProperty = AceType::DynamicCast<SlidingPanelLayoutProperty>(layoutProperty);
188     CHECK_NULL_VOID(slidingPanelLayoutProperty);
189     auto closeIconGeometryNode = closeIconWrapper->GetGeometryNode();
190     CHECK_NULL_VOID(closeIconGeometryNode);
191     auto closeIconLayoutProperty = AceType::DynamicCast<CloseIconLayoutProperty>(closeIconWrapper->GetLayoutProperty());
192     CHECK_NULL_VOID(closeIconLayoutProperty);
193     auto closeIconWidth = closeIconLayoutProperty->GetCloseIconWidthValue();
194     auto closeIconHeigth = closeIconLayoutProperty->GetCloseIconHeightValue();
195     SizeF frameSize =
196         SizeF(static_cast<float>(closeIconWidth.ConvertToPx()), static_cast<float>(closeIconHeigth.ConvertToPx()));
197     closeIconGeometryNode->SetFrameSize(frameSize);
198     auto childConstraint = slidingPanelLayoutProperty->CreateChildConstraint();
199     closeIconWrapper->Measure(childConstraint);
200 }
201 
GetMaxWidthByScreenSizeType(const SizeF & maxSize,const SizeF & idealSize) const202 float SlidingPanelLayoutAlgorithm::GetMaxWidthByScreenSizeType(const SizeF& maxSize, const SizeF& idealSize) const
203 {
204     RefPtr<GridColumnInfo> columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::PANEL);
205     columnInfo->GetParent()->BuildColumnWidth(maxSize.Width());
206     auto gridSizeType = ScreenSystemManager::GetInstance().GetSize(maxSize.Width());
207     auto width = 0.0f;
208     uint32_t columns = 0;
209     switch (gridSizeType) {
210         case ScreenSizeType::UNDEFINED:
211         case ScreenSizeType::XS:
212         case ScreenSizeType::SM:
213             width = idealSize.Width();
214             break;
215         case ScreenSizeType::MD:
216             columns = columnInfo->GetColumns(gridSizeType);
217             width =
218                 columnInfo->GetWidth(columns) + columnInfo->GetParent()->GetGutterWidth().ConvertToPx() * DOUBLENESS;
219             break;
220         case ScreenSizeType::LG:
221         case ScreenSizeType::XL:
222             columns = columnInfo->GetColumns(ScreenSizeType::LG);
223             width =
224                 columnInfo->GetWidth(columns) + columnInfo->GetParent()->GetGutterWidth().ConvertToPx() * DOUBLENESS;
225             break;
226         default:
227             break;
228     }
229     if (width > maxSize.Width()) {
230         return maxSize.Width();
231     }
232     return width;
233 }
234 } // namespace OHOS::Ace::NG
235