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->IgnoreItemSpace()) { 50 return 0.0f; 51 } 52 return property->GetItemSpace().value_or(0.0_px).ConvertToPx(); 53 } 54 CreateChildConstraint(const RefPtr<SwiperLayoutProperty> & property,const OptionalSizeF & idealSize,bool getAutoFill)55 static LayoutConstraintF CreateChildConstraint( 56 const RefPtr<SwiperLayoutProperty>& property, const OptionalSizeF& idealSize, bool getAutoFill) 57 { 58 auto layoutConstraint = property->CreateChildConstraint(); 59 layoutConstraint.parentIdealSize = idealSize; 60 auto displayCount = property->GetDisplayCount().value_or(1); 61 if ((!getAutoFill && !IsStretch(property)) || NonPositive(static_cast<double>(displayCount))) { 62 return layoutConstraint; 63 } 64 auto axis = property->GetDirection().value_or(Axis::HORIZONTAL); 65 // re-determine ignoreItemSpace_ based on child calc length 66 property->ResetIgnorePrevMarginAndNextMargin(); 67 property->ResetIgnoreItemSpace(); 68 auto itemSpace = GetItemSpace(property); 69 auto parentMainSize = idealSize.MainSize(axis); 70 if (parentMainSize.has_value() && itemSpace > parentMainSize.value()) { 71 itemSpace = 0.0f; 72 } 73 auto prevMargin = property->GetPrevMarginValue(0.0_px).ConvertToPx(); 74 auto nextMargin = property->GetNextMarginValue(0.0_px).ConvertToPx(); 75 auto itemSpaceCount = CaculateDisplayItemSpaceCount(property, prevMargin, nextMargin); 76 auto childSelfIdealSize = idealSize; 77 float childCalcIdealLength = 0.0f; 78 // Invalid size need not to calculate margin 79 if (!idealSize.IsNonPositive() && ((axis == Axis::HORIZONTAL && idealSize.Width().has_value()) || 80 (axis == Axis::VERTICAL && idealSize.Height().has_value()))) { 81 auto length = axis == Axis::HORIZONTAL ? idealSize.Width().value() : idealSize.Height().value(); 82 childCalcIdealLength = 83 (length - itemSpace * itemSpaceCount - static_cast<float>(prevMargin + nextMargin)) / displayCount; 84 if (LessNotEqual(childCalcIdealLength, 0.0)) { 85 // prioritize margin and displayCount, ignore itemSpace to create a positive idealLength. 86 property->MarkIgnoreItemSpace(); 87 childCalcIdealLength = (length - static_cast<float>(prevMargin + nextMargin)) / displayCount; 88 } 89 if (CheckMarginPropertyExceed(property, childCalcIdealLength)) { 90 prevMargin = 0.0; 91 nextMargin = 0.0; 92 itemSpaceCount = CaculateDisplayItemSpaceCount(property, prevMargin, nextMargin); 93 childCalcIdealLength = (length - itemSpace * itemSpaceCount) / displayCount; 94 if (LessNotEqual(childCalcIdealLength, 0.0)) { 95 childCalcIdealLength = length / displayCount; 96 } else { 97 property->ResetIgnoreItemSpace(); 98 } 99 } 100 axis == Axis::HORIZONTAL ? childSelfIdealSize.SetWidth(childCalcIdealLength) 101 : childSelfIdealSize.SetHeight(childCalcIdealLength); 102 } 103 104 layoutConstraint.selfIdealSize = childSelfIdealSize; 105 return layoutConstraint; 106 } 107 CaculateDisplayItemSpaceCount(const RefPtr<SwiperLayoutProperty> & property,double prevMargin,double nextMargin)108 static int32_t CaculateDisplayItemSpaceCount( 109 const RefPtr<SwiperLayoutProperty>& property, double prevMargin, double nextMargin) 110 { 111 CHECK_NULL_RETURN(property, 0); 112 auto count = property->GetDisplayCountValue(1); 113 count = (Positive(static_cast<double>(count)) ? count : 1); 114 if (Positive(prevMargin) && Positive(nextMargin)) { 115 return count + 1; 116 } else if (NonPositive(prevMargin) && NonPositive(nextMargin)) { 117 return count - 1; 118 } else { 119 return count; 120 } 121 } 122 ComputePageIndex(int32_t index,int32_t displayCount)123 static int32_t ComputePageIndex(int32_t index, int32_t displayCount) 124 { 125 if (displayCount <= 0) { 126 return index; 127 } 128 129 return static_cast<int32_t>(std::floor(static_cast<float>(index) / static_cast<float>(displayCount))) * 130 displayCount; 131 } 132 ComputePageEndIndex(int32_t index,int32_t displayCount)133 static int32_t ComputePageEndIndex(int32_t index, int32_t displayCount) 134 { 135 if (displayCount <= 0) { 136 return index; 137 } 138 139 return static_cast<int32_t>(std::floor(static_cast<float>(index) / static_cast<float>(displayCount))) * 140 displayCount + 141 displayCount - 1; 142 } 143 CheckAutoFillDisplayCount(RefPtr<SwiperLayoutProperty> & swiperLayoutProperty,float contentWidth,int32_t totalCount)144 static void CheckAutoFillDisplayCount( 145 RefPtr<SwiperLayoutProperty>& swiperLayoutProperty, float contentWidth, int32_t totalCount) 146 { 147 bool isAutoFill = swiperLayoutProperty->GetMinSize().has_value(); 148 if (!isAutoFill) { 149 return; 150 } 151 auto minSize = swiperLayoutProperty->GetMinSize()->ConvertToPx(); 152 auto displayCount = 153 static_cast<int32_t>(floor((contentWidth - 2 * SWIPER_MARGIN.ConvertToPx() + SWIPER_GUTTER.ConvertToPx()) / 154 (minSize + SWIPER_GUTTER.ConvertToPx()))); 155 if (LessOrEqual(minSize, 0)) { 156 displayCount = 1; 157 } 158 displayCount = displayCount > 0 ? displayCount : 1; 159 displayCount = displayCount > totalCount ? totalCount : displayCount; 160 161 auto displayCountProperty = swiperLayoutProperty->GetDisplayCount().value_or(1); 162 if (displayCountProperty != displayCount) { 163 swiperLayoutProperty->UpdateDisplayCount(displayCount); 164 } 165 } 166 167 private: CheckMarginPropertyExceed(const RefPtr<SwiperLayoutProperty> & property,float childCalcIdealLength)168 static bool CheckMarginPropertyExceed(const RefPtr<SwiperLayoutProperty>& property, float childCalcIdealLength) 169 { 170 CHECK_NULL_RETURN(property, false); 171 auto prevMargin = property->GetPrevMarginValue(0.0_px).ConvertToPx(); 172 auto nextMargin = property->GetNextMarginValue(0.0_px).ConvertToPx(); 173 if (GreatNotEqual(prevMargin, childCalcIdealLength) || GreatNotEqual(nextMargin, childCalcIdealLength)) { 174 property->MarkIgnorePrevMarginAndNextMargin(); 175 return true; 176 } 177 return false; 178 } 179 }; 180 181 /** 182 * @brief Helper RAII object. set @c var to @c value when this object goes out of scope. 183 * REQUIRES: the life span of @c var surpasses this object. 184 */ 185 template<typename T> 186 class DestructSetter { 187 public: 188 DestructSetter() = delete; DestructSetter(T & var,T value)189 DestructSetter(T& var, T value) : ref_(var), value_(value) {} ~DestructSetter()190 ~DestructSetter() 191 { 192 ref_ = value_; 193 } 194 195 private: 196 T& ref_; 197 T value_ {}; 198 199 ACE_DISALLOW_COPY_AND_MOVE(DestructSetter); 200 }; 201 } // namespace OHOS::Ace::NG 202 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_UTILS_H 203