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 31 class SwiperUtils { 32 public: 33 SwiperUtils() = delete; 34 ~SwiperUtils() = delete; 35 IsStretch(const RefPtr<SwiperLayoutProperty> & property)36 static bool IsStretch(const RefPtr<SwiperLayoutProperty>& property) 37 { 38 // If display count is setted, use stretch mode. 39 CHECK_NULL_RETURN(property, true); 40 if (property->HasDisplayCount() && !property->HasMinSize()) { 41 return true; 42 } 43 44 return property->GetDisplayMode().value_or(SwiperDisplayMode::STRETCH) == SwiperDisplayMode::STRETCH; 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 auto scale = property->GetLayoutConstraint()->scaleProperty; 53 return ConvertToPx(property->GetItemSpace().value_or(0.0_px), scale).value_or(0); 54 } 55 CreateChildConstraint(const RefPtr<SwiperLayoutProperty> & property,const OptionalSizeF & idealSize,bool getAutoFill)56 static LayoutConstraintF CreateChildConstraint( 57 const RefPtr<SwiperLayoutProperty>& property, const OptionalSizeF& idealSize, bool getAutoFill) 58 { 59 auto layoutConstraint = property->CreateChildConstraint(); 60 layoutConstraint.parentIdealSize = idealSize; 61 auto displayCount = property->GetDisplayCount().value_or(1); 62 if ((!getAutoFill && !IsStretch(property)) || NonPositive(static_cast<double>(displayCount))) { 63 return layoutConstraint; 64 } 65 auto axis = property->GetDirection().value_or(Axis::HORIZONTAL); 66 // re-determine ignoreItemSpace_ based on child calc length 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 79 if ((axis == Axis::HORIZONTAL && idealSize.Width().has_value()) || 80 (axis == Axis::VERTICAL && idealSize.Height().has_value())) { 81 auto length = axis == Axis::HORIZONTAL ? idealSize.Width().value() : 82 idealSize.Height().value(); 83 childCalcIdealLength = (length - itemSpace * itemSpaceCount - 84 static_cast<float>(prevMargin + nextMargin)) / displayCount; 85 if (LessNotEqual(childCalcIdealLength, 0.0)) { 86 // prioritize margin and displayCount, ignore itemSpace to create a positive idealLength. 87 property->MarkIgnoreItemSpace(); 88 childCalcIdealLength = (length - static_cast<float>(prevMargin + nextMargin)) / displayCount; 89 } 90 if (CheckMarginPropertyExceed(property, childCalcIdealLength)) { 91 prevMargin = 0.0; 92 nextMargin = 0.0; 93 itemSpaceCount = CaculateDisplayItemSpaceCount(property, prevMargin, nextMargin); 94 childCalcIdealLength = (length - itemSpace * itemSpaceCount) / displayCount; 95 } 96 axis == Axis::HORIZONTAL ? childSelfIdealSize.SetWidth(childCalcIdealLength) 97 : childSelfIdealSize.SetHeight(childCalcIdealLength); 98 } 99 100 layoutConstraint.selfIdealSize = childSelfIdealSize; 101 return layoutConstraint; 102 } 103 CaculateDisplayItemSpaceCount(const RefPtr<SwiperLayoutProperty> & property,double prevMargin,double nextMargin)104 static int32_t CaculateDisplayItemSpaceCount( 105 const RefPtr<SwiperLayoutProperty>& property, double prevMargin, double nextMargin) 106 { 107 CHECK_NULL_RETURN(property, 0); 108 auto count = property->GetDisplayCountValue(1); 109 count = (Positive(static_cast<double>(count)) ? count : 1); 110 if (Positive(prevMargin) && Positive(nextMargin)) { 111 return count + 1; 112 } else if (NonPositive(prevMargin) && NonPositive(nextMargin)) { 113 return count - 1; 114 } else { 115 return count; 116 } 117 } 118 ComputePageIndex(int32_t index,int32_t displayCount)119 static int32_t ComputePageIndex(int32_t index, int32_t displayCount) 120 { 121 if (displayCount <= 0) { 122 return index; 123 } 124 125 return static_cast<int32_t>(std::floor(static_cast<float>(index) / static_cast<float>(displayCount))) * 126 displayCount; 127 } 128 ComputePageEndIndex(int32_t index,int32_t displayCount)129 static int32_t ComputePageEndIndex(int32_t index, int32_t displayCount) 130 { 131 if (displayCount <= 0) { 132 return index; 133 } 134 135 return static_cast<int32_t>(std::floor(static_cast<float>(index) / static_cast<float>(displayCount))) * 136 displayCount + displayCount - 1; 137 } 138 139 private: CheckMarginPropertyExceed(const RefPtr<SwiperLayoutProperty> & property,float childCalcIdealLength)140 static bool CheckMarginPropertyExceed( 141 const RefPtr<SwiperLayoutProperty>& property, float childCalcIdealLength) 142 { 143 CHECK_NULL_RETURN(property, false); 144 auto prevMargin = property->GetPrevMarginValue(0.0_px).ConvertToPx(); 145 auto nextMargin = property->GetNextMarginValue(0.0_px).ConvertToPx(); 146 if (GreatNotEqual(prevMargin, childCalcIdealLength) || 147 GreatNotEqual(nextMargin, childCalcIdealLength)) { 148 property->UpdatePrevMarginWithoutMeasure(0.0_px); 149 property->UpdateNextMarginWithoutMeasure(0.0_px); 150 return true; 151 } 152 return false; 153 } 154 }; 155 } // namespace OHOS::Ace::NG 156 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_UTILS_H 157