• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_UTILS_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_UTILS_H
18 
19 #include <optional>
20 
21 #include "base/geometry/axis.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
26 #include "core/components_ng/pattern/swiper/swiper_paint_property.h"
27 #include "core/components_ng/property/measure_utils.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr Dimension SWIPER_MARGIN = 16.0_vp;
32 constexpr Dimension SWIPER_GUTTER = 16.0_vp;
33 } // namespace
34 
35 class SwiperUtils {
36 public:
37     SwiperUtils() = delete;
38     ~SwiperUtils() = delete;
39 
IsStretch(const RefPtr<SwiperLayoutProperty> & property)40     static bool IsStretch(const RefPtr<SwiperLayoutProperty>& property)
41     {
42         // If display count is setted, use stretch mode.
43         CHECK_NULL_RETURN(property, true);
44         return property->IsStretch();
45     }
46 
GetItemSpace(const RefPtr<SwiperLayoutProperty> & property)47     static float GetItemSpace(const RefPtr<SwiperLayoutProperty>& property)
48     {
49         if (!property || property->IgnoreItemSpace()) {
50             return 0.0f;
51         }
52         return property->GetItemSpace().value_or(0.0_px).ConvertToPx();
53     }
54 
CheckLayoutPolicyConstraint(const RefPtr<SwiperLayoutProperty> & property,OptionalSizeF childSelfIdealSize,LayoutConstraintF layoutConstraint)55     static LayoutConstraintF CheckLayoutPolicyConstraint(const RefPtr<SwiperLayoutProperty>& property,
56         OptionalSizeF childSelfIdealSize, LayoutConstraintF layoutConstraint)
57     {
58         auto layoutPolicy = property->GetLayoutPolicyProperty();
59         auto axis = property->GetDirection().value_or(Axis::HORIZONTAL);
60         if (layoutPolicy.has_value()) {
61             auto widthLayoutPolicy = layoutPolicy.value().widthLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
62             auto heightLayoutPolicy = layoutPolicy.value().heightLayoutPolicy_.value_or(LayoutCalPolicy::NO_MATCH);
63             // crosss axis set maxSize and reset IdealSize'cross width/heigth, when layoutPolicy is matchParent
64             if (axis == Axis::HORIZONTAL && heightLayoutPolicy == LayoutCalPolicy::MATCH_PARENT) {
65                 auto heightOpt = childSelfIdealSize.Height();
66                 if (heightOpt) {
67                     layoutConstraint.maxSize.SetHeight(heightOpt.value());
68                 }
69                 auto width = childSelfIdealSize.Width();
70                 childSelfIdealSize.Reset();
71                 childSelfIdealSize.SetWidth(width);
72             } else if (axis == Axis::VERTICAL && widthLayoutPolicy == LayoutCalPolicy::MATCH_PARENT) {
73                 auto widthOpt = childSelfIdealSize.Width();
74                 if (widthOpt) {
75                     layoutConstraint.maxSize.SetWidth(widthOpt.value());
76                 }
77                 auto height = childSelfIdealSize.Height();
78                 childSelfIdealSize.Reset();
79                 childSelfIdealSize.SetHeight(height);
80             }
81         }
82         layoutConstraint.selfIdealSize = childSelfIdealSize;
83         return layoutConstraint;
84     }
85 
CreateChildConstraint(const RefPtr<SwiperLayoutProperty> & property,const OptionalSizeF & idealSize,bool getAutoFill)86     static LayoutConstraintF CreateChildConstraint(
87         const RefPtr<SwiperLayoutProperty>& property, const OptionalSizeF& idealSize, bool getAutoFill)
88     {
89         CHECK_NULL_RETURN(property, {});
90         auto layoutConstraint = property->CreateChildConstraint();
91         layoutConstraint.parentIdealSize = idealSize;
92         auto displayCount = property->GetDisplayCount().value_or(1);
93         if ((!getAutoFill && !IsStretch(property)) || NonPositive(static_cast<double>(displayCount))) {
94             return layoutConstraint;
95         }
96         auto axis = property->GetDirection().value_or(Axis::HORIZONTAL);
97         // re-determine ignoreItemSpace_ based on child calc length
98         property->ResetIgnorePrevMarginAndNextMargin();
99         property->ResetIgnoreItemSpace();
100         auto itemSpace = GetItemSpace(property);
101         auto parentMainSize = idealSize.MainSize(axis);
102         if (parentMainSize.has_value() && itemSpace > parentMainSize.value()) {
103             itemSpace = 0.0f;
104         }
105         auto prevMargin = property->GetPrevMarginValue(0.0_px).ConvertToPx();
106         auto nextMargin = property->GetNextMarginValue(0.0_px).ConvertToPx();
107         auto itemSpaceCount = CaculateDisplayItemSpaceCount(property, prevMargin, nextMargin);
108         auto childSelfIdealSize = idealSize;
109         float childCalcIdealLength = 0.0f;
110         // Invalid size need not to calculate margin
111         if (!idealSize.IsNonPositive() && ((axis == Axis::HORIZONTAL && idealSize.Width().has_value()) ||
112                                               (axis == Axis::VERTICAL && idealSize.Height().has_value()))) {
113             auto length = axis == Axis::HORIZONTAL ? idealSize.Width().value() : idealSize.Height().value();
114             childCalcIdealLength =
115                 (length - itemSpace * itemSpaceCount - static_cast<float>(prevMargin + nextMargin)) / displayCount;
116             if (LessNotEqual(childCalcIdealLength, 0.0)) {
117                 // prioritize margin and displayCount, ignore itemSpace to create a positive idealLength.
118                 property->MarkIgnoreItemSpace();
119                 childCalcIdealLength = (length - static_cast<float>(prevMargin + nextMargin)) / displayCount;
120             }
121             if (CheckMarginPropertyExceed(property, childCalcIdealLength)) {
122                 prevMargin = 0.0;
123                 nextMargin = 0.0;
124                 itemSpaceCount = CaculateDisplayItemSpaceCount(property, prevMargin, nextMargin);
125                 childCalcIdealLength = (length - itemSpace * itemSpaceCount) / displayCount;
126                 if (LessNotEqual(childCalcIdealLength, 0.0)) {
127                     childCalcIdealLength = length / displayCount;
128                 } else {
129                     property->ResetIgnoreItemSpace();
130                 }
131             }
132             axis == Axis::HORIZONTAL ? childSelfIdealSize.SetWidth(childCalcIdealLength)
133                                      : childSelfIdealSize.SetHeight(childCalcIdealLength);
134         }
135 
136         return CheckLayoutPolicyConstraint(property, childSelfIdealSize, layoutConstraint);
137     }
138 
CaculateDisplayItemSpaceCount(const RefPtr<SwiperLayoutProperty> & property,double prevMargin,double nextMargin)139     static int32_t CaculateDisplayItemSpaceCount(
140         const RefPtr<SwiperLayoutProperty>& property, double prevMargin, double nextMargin)
141     {
142         CHECK_NULL_RETURN(property, 0);
143         auto count = property->GetDisplayCountValue(1);
144         count = (Positive(static_cast<double>(count)) ? count : 1);
145         if (Positive(prevMargin) && Positive(nextMargin)) {
146             return count + 1;
147         } else if (NonPositive(prevMargin) && NonPositive(nextMargin)) {
148             return count - 1;
149         } else {
150             return count;
151         }
152     }
153 
ComputePageIndex(int32_t index,int32_t displayCount)154     static int32_t ComputePageIndex(int32_t index, int32_t displayCount)
155     {
156         if (displayCount <= 0) {
157             return index;
158         }
159 
160         return static_cast<int32_t>(std::floor(static_cast<float>(index) / static_cast<float>(displayCount))) *
161                displayCount;
162     }
163 
ComputePageEndIndex(int32_t index,int32_t displayCount)164     static int32_t ComputePageEndIndex(int32_t index, int32_t displayCount)
165     {
166         if (displayCount <= 0) {
167             return index;
168         }
169 
170         return static_cast<int32_t>(std::floor(static_cast<float>(index) / static_cast<float>(displayCount))) *
171                    displayCount +
172                displayCount - 1;
173     }
174 
CheckAutoFillDisplayCount(RefPtr<SwiperLayoutProperty> & swiperLayoutProperty,float contentWidth,int32_t totalCount)175     static void CheckAutoFillDisplayCount(
176         RefPtr<SwiperLayoutProperty>& swiperLayoutProperty, float contentWidth, int32_t totalCount)
177     {
178         CHECK_NULL_VOID(swiperLayoutProperty);
179         bool isAutoFill = swiperLayoutProperty->GetMinSize().has_value();
180         if (!isAutoFill) {
181             return;
182         }
183         auto minSize = swiperLayoutProperty->GetMinSize()->ConvertToPx();
184         auto displayCount =
185             static_cast<int32_t>(floor((contentWidth - 2 * SWIPER_MARGIN.ConvertToPx() + SWIPER_GUTTER.ConvertToPx()) /
186                                        (minSize + SWIPER_GUTTER.ConvertToPx())));
187         if (LessOrEqual(minSize, 0)) {
188             displayCount = 1;
189         }
190         displayCount = displayCount > 0 ? displayCount : 1;
191         displayCount = displayCount > totalCount ? totalCount : displayCount;
192 
193         auto displayCountProperty = swiperLayoutProperty->GetDisplayCount().value_or(1);
194         if (displayCountProperty != displayCount) {
195             swiperLayoutProperty->UpdateDisplayCount(displayCount);
196         }
197     }
198 
CheckIsSingleCase(const RefPtr<SwiperLayoutProperty> & property)199     static bool CheckIsSingleCase(const RefPtr<SwiperLayoutProperty>& property)
200     {
201         bool hasMinSize = property->GetMinSize().has_value() && !LessOrEqual(property->GetMinSizeValue().Value(), 0);
202         bool hasPrevMargin = Positive(property->GetCalculatedPrevMargin());
203         bool hasNextMargin = Positive(property->GetCalculatedNextMargin());
204 
205         return !hasMinSize && (!hasPrevMargin && !hasNextMargin) &&
206                ((property->GetDisplayCount().has_value() && property->GetDisplayCountValue() == 1) ||
207                    (!property->GetDisplayCount().has_value() && SwiperUtils::IsStretch(property)));
208     }
209 
210 private:
CheckMarginPropertyExceed(const RefPtr<SwiperLayoutProperty> & property,float childCalcIdealLength)211     static bool CheckMarginPropertyExceed(const RefPtr<SwiperLayoutProperty>& property, float childCalcIdealLength)
212     {
213         CHECK_NULL_RETURN(property, false);
214         auto prevMargin = property->GetPrevMarginValue(0.0_px).ConvertToPx();
215         auto nextMargin = property->GetNextMarginValue(0.0_px).ConvertToPx();
216         if (GreatNotEqual(prevMargin, childCalcIdealLength) || GreatNotEqual(nextMargin, childCalcIdealLength)) {
217             property->MarkIgnorePrevMarginAndNextMargin();
218             return true;
219         }
220         return false;
221     }
222 };
223 
224 /**
225  * @brief Helper RAII object. set @c var to @c value when this object goes out of scope.
226  * REQUIRES: the life span of @c var surpasses this object.
227  */
228 template<typename T>
229 class DestructSetter {
230 public:
231     DestructSetter() = delete;
DestructSetter(T & var,T value)232     DestructSetter(T& var, T value) : ref_(var), value_(value) {}
~DestructSetter()233     ~DestructSetter()
234     {
235         ref_ = value_;
236     }
237 
238 private:
239     T& ref_;
240     T value_ {};
241 
242     ACE_DISALLOW_COPY_AND_MOVE(DestructSetter);
243 };
244 } // namespace OHOS::Ace::NG
245 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_UTILS_H
246