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 16namespace OHOS::Ace::NG { 17template<typename T> 18void LayoutConstraintT<T>::ApplyAspectRatio( 19 float ratio, const std::optional<CalcSize>& calcSize, bool greaterThanApiTen) 20{ 21 if (!Positive(ratio)) { 22 // just in case ratio is illegal value 23 return; 24 } 25 std::optional<bool> useDefinedWidth; 26 if (calcSize) { 27 if (calcSize.value().Width()) { 28 useDefinedWidth = true; 29 } else if (calcSize.value().Height()) { 30 useDefinedWidth = false; 31 } 32 } 33 if (useDefinedWidth) { 34 if (useDefinedWidth.value_or(false)) { 35 if (selfIdealSize.Width()) { 36 selfIdealSize.SetHeight(selfIdealSize.Width().value() / ratio); 37 } 38 minSize.SetHeight(minSize.Width() / ratio); 39 maxSize.SetHeight(maxSize.Width() / ratio); 40 ApplyAspectRatioToParentIdealSize(true, ratio); 41 return; 42 } 43 if (selfIdealSize.Height()) { 44 selfIdealSize.SetWidth(selfIdealSize.Height().value() * ratio); 45 } 46 minSize.SetWidth(minSize.Height() * ratio); 47 maxSize.SetWidth(maxSize.Height() * ratio); 48 ApplyAspectRatioToParentIdealSize(false, ratio); 49 return; 50 } else { 51 if (selfIdealSize.Width()) { 52 selfIdealSize.SetHeight(selfIdealSize.Width().value() / ratio); 53 minSize.SetHeight(minSize.Width() / ratio); 54 maxSize.SetHeight(maxSize.Width() / ratio); 55 ApplyAspectRatioToParentIdealSize(true, ratio); 56 return; 57 } 58 if (selfIdealSize.Height()) { 59 selfIdealSize.SetWidth(selfIdealSize.Height().value() * ratio); 60 minSize.SetWidth(minSize.Height() * ratio); 61 maxSize.SetWidth(maxSize.Height() * ratio); 62 ApplyAspectRatioToParentIdealSize(false, ratio); 63 return; 64 } 65 } 66 // after previous conditions, ideal size does not exist, we use max size to rule aspect ratio 67 // but nothing can be done if both width and height are inf 68 if (NearEqual(maxSize.Width(), Infinity<T>()) && NearEqual(maxSize.Height(), Infinity<T>())) { 69 return; 70 } 71 ApplyAspectRatioByMaxSize(ratio, useDefinedWidth, greaterThanApiTen); 72} 73 74template<typename T> 75void LayoutConstraintT<T>::ApplyAspectRatioToParentIdealSize(bool useWidth, float ratio) 76{ 77 if (!Positive(ratio)) { 78 return; 79 } 80 if (useWidth && parentIdealSize.Width()) { 81 parentIdealSize.SetHeight(parentIdealSize.Width().value() / ratio); 82 return; 83 } 84 if (!parentIdealSize.Height()) { 85 return; 86 } 87 parentIdealSize.SetWidth(parentIdealSize.Height().value() * ratio); 88} 89 90template<typename T> 91void LayoutConstraintT<T>::ApplyAspectRatioByMaxSize( 92 float ratio, std::optional<bool> useDefinedWidth, bool greaterThanApiTen) 93{ 94 if (!Positive(ratio)) { 95 return; 96 } 97 if (useDefinedWidth) { 98 ApplyAspectRatioWithCalcSize(ratio, useDefinedWidth.value()); 99 return; 100 } 101 ApplyAspectRatioWithoutCalcSize(ratio, greaterThanApiTen); 102} 103 104template<typename T> 105void LayoutConstraintT<T>::ApplyAspectRatioWithCalcSize(float ratio, bool useDefinedWidth) 106{ 107 if (!Positive(ratio)) { 108 return; 109 } 110 if (useDefinedWidth) { 111 minSize.SetHeight(minSize.Width() / ratio); 112 maxSize.SetHeight(maxSize.Width() / ratio); 113 percentReference.SetHeight(percentReference.Width() / ratio); 114 ApplyAspectRatioToParentIdealSize(true, ratio); 115 return; 116 } 117 minSize.SetWidth(minSize.Height() * ratio); 118 maxSize.SetWidth(maxSize.Height() * ratio); 119 percentReference.SetWidth(percentReference.Height() / ratio); 120 ApplyAspectRatioToParentIdealSize(false, ratio); 121} 122 123template<typename T> 124void LayoutConstraintT<T>::ApplyAspectRatioWithoutCalcSize(float ratio, bool greaterThanApiTen) 125{ 126 if (!Positive(ratio)) { 127 return; 128 } 129 if (greaterThanApiTen) { 130 if (percentReference.Height() * ratio > maxSize.Width()) { 131 minSize.SetHeight(minSize.Width() / ratio); 132 maxSize.SetHeight(maxSize.Width() / ratio); 133 percentReference.SetHeight(percentReference.Width() / ratio); 134 ApplyAspectRatioToParentIdealSize(true, ratio); 135 return; 136 } 137 if (percentReference.Width() / ratio > maxSize.Height()) { 138 minSize.SetWidth(minSize.Height() * ratio); 139 maxSize.SetWidth(maxSize.Height() * ratio); 140 percentReference.SetWidth(percentReference.Height() * ratio); 141 ApplyAspectRatioToParentIdealSize(false, ratio); 142 } 143 return; 144 } else { 145 if (maxSize.Width() < maxSize.Height()) { 146 minSize.SetHeight(minSize.Width() / ratio); 147 maxSize.SetHeight(maxSize.Width() / ratio); 148 percentReference.SetHeight(percentReference.Width() / ratio); 149 ApplyAspectRatioToParentIdealSize(true, ratio); 150 return; 151 } 152 } 153 minSize.SetWidth(minSize.Height() * ratio); 154 maxSize.SetWidth(maxSize.Height() * ratio); 155 percentReference.SetWidth(percentReference.Height() / ratio); 156 ApplyAspectRatioToParentIdealSize(false, ratio); 157} 158 159template<typename T> 160void LayoutConstraintT<T>::Reset() 161{ 162 scaleProperty.Reset(); 163 minSize = { 0, 0 }; 164 maxSize = { Infinity<T>(), Infinity<T>() }; 165 percentReference = { 0, 0 }; 166 parentIdealSize.Reset(); 167 selfIdealSize.Reset(); 168} 169 170template<typename T> 171void LayoutConstraintT<T>::MinusPadding(const std::optional<T>& left, const std::optional<T>& right, 172 const std::optional<T>& top, const std::optional<T>& bottom) 173{ 174 minSize.MinusPadding(left, right, top, bottom); 175 maxSize.MinusPadding(left, right, top, bottom); 176 parentIdealSize.MinusPadding(left, right, top, bottom); 177 selfIdealSize.MinusPadding(left, right, top, bottom); 178 percentReference.MinusPadding(left, right, top, bottom); 179} 180 181template<typename T> 182void LayoutConstraintT<T>::MinusPaddingToNonNegativeSize(const std::optional<T>& left, const std::optional<T>& right, 183 const std::optional<T>& top, const std::optional<T>& bottom) 184{ 185 minSize.MinusPaddingToNonNegative(left, right, top, bottom); 186 maxSize.MinusPaddingToNonNegative(left, right, top, bottom); 187 parentIdealSize.MinusPadding(left, right, top, bottom); 188 selfIdealSize.MinusPadding(left, right, top, bottom); 189 percentReference.MinusPaddingToNonNegative(left, right, top, bottom); 190} 191 192template<typename T> 193std::string LayoutConstraintT<T>::ToString() const 194{ 195 std::string str; 196 str.append("minSize: [").append(minSize.ToString()).append("]"); 197 str.append("maxSize: [").append(maxSize.ToString()).append("]"); 198 str.append("percentReference: [").append(percentReference.ToString()).append("]"); 199 str.append("parentIdealSize: [").append(parentIdealSize.ToString()).append("]"); 200 str.append("selfIdealSize: [").append(selfIdealSize.ToString()).append("]"); 201 return str; 202} 203 204template<typename T> 205SizeF LayoutConstraintT<T>::Constrain(const SizeF& size) const 206{ 207 SizeF constrainSize; 208 constrainSize.SetWidth(std::clamp(size.Width(), minSize.Width(), maxSize.Width())); 209 constrainSize.SetHeight(std::clamp(size.Height(), minSize.Height(), maxSize.Height())); 210 return constrainSize; 211} 212} // namespace OHOS::Ace::NG