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_PROPERTIES_FLEX_PROPERTIES_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PROPERTIES_FLEX_PROPERTIES_H 18 19 #include <map> 20 21 #include "base/geometry/dimension.h" 22 #include "base/json/json_util.h" 23 #include "base/log/dump_log.h" 24 #include "core/components/common/layout/constants.h" 25 #include "core/components/common/layout/position_param.h" 26 #include "core/components_ng/base/inspector_filter.h" 27 #include "core/components_ng/property/property.h" 28 29 namespace OHOS::Ace::NG { 30 using AlignRulesItem = std::map<AlignDirection, AlignRule>; 31 using BiasPair = std::pair<float, float>; 32 using ChainWeightPair = std::pair<std::optional<float>, std::optional<float>>; // <horizontal,vertical> 33 using GuidelineItem = std::vector<GuidelineInfo>; 34 using BarrierItem = std::vector<BarrierInfo>; 35 36 class FlexItemProperty { 37 public: 38 FlexItemProperty() = default; 39 ~FlexItemProperty() = default; 40 HorizontalAlignToString(HorizontalAlign align)41 std::string HorizontalAlignToString(HorizontalAlign align) 42 { 43 switch (align) { 44 case HorizontalAlign::CENTER: 45 return "HorizontalAlign::Center"; 46 case HorizontalAlign::START: 47 return "HorizontalAlign::Left"; 48 case HorizontalAlign::END: 49 return "HorizontalAlign::End"; 50 default: 51 return "Unknown"; 52 } 53 } 54 VerticalAlignToString(VerticalAlign align)55 std::string VerticalAlignToString(VerticalAlign align) 56 { 57 switch (align) { 58 case VerticalAlign::TOP: 59 return "VerticalAlign::Top"; 60 case VerticalAlign::CENTER: 61 return "VerticalAlign::Center"; 62 case VerticalAlign::BOTTOM: 63 return "VerticalAlign::Bottom"; 64 case VerticalAlign::BASELINE: 65 return "VerticalAlign::BaseLine"; 66 default: 67 return "Unknown"; 68 } 69 } 70 AlignDirectionToString(AlignDirection direction)71 std::string AlignDirectionToString(AlignDirection direction) 72 { 73 switch (direction) { 74 case AlignDirection::MIDDLE: 75 return "AlignDirection::Middle"; 76 case AlignDirection::LEFT: 77 return "AlignDirection::Left"; 78 case AlignDirection::RIGHT: 79 return "AlignDirection::RIGHT"; 80 case AlignDirection::TOP: 81 return "AlignDirection::Top"; 82 case AlignDirection::CENTER: 83 return "AlignDirection::Center"; 84 case AlignDirection::BOTTOM: 85 return "AlignDirection::Bottom"; 86 default: 87 return "Unknown"; 88 } 89 } 90 SingleAlignRuleToString(AlignDirection direction,AlignRule rule)91 std::string SingleAlignRuleToString(AlignDirection direction, AlignRule rule) 92 { 93 std::string result = AlignDirectionToString(direction) + ": {'" + rule.anchor + "', "; 94 if (static_cast<int32_t>(direction) < HORIZONTAL_DIRECTION_RANGE) { 95 result += HorizontalAlignToString(rule.horizontal); 96 } else if (static_cast<int32_t>(direction) < VERTICAL_DIRECTION_RANGE) { 97 result += VerticalAlignToString(rule.vertical); 98 } else { 99 result += "Unknown"; 100 } 101 result += "}"; 102 return result; 103 } 104 ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter)105 void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const 106 { 107 static const char* ITEM_ALIGN[] = { "ItemAlign.Auto", "ItemAlign.Start", "ItemAlign.Center", "ItemAlign.End", 108 "ItemAlign.Stretch", "ItemAlign.Baseline" }; 109 /* no fixed attr below, just return */ 110 if (filter.IsFastFilter()) { 111 return; 112 } 113 json->PutExtAttr( 114 "flexBasis", propFlexBasis.has_value() ? propFlexBasis.value().ToString().c_str() : "auto", filter); 115 json->PutExtAttr("flexGrow", round(static_cast<double>(propFlexGrow.value_or(0.0)) * 100) / 100, filter); 116 json->PutExtAttr("flexShrink", round(static_cast<double>(propFlexShrink.value_or(1)) * 100) / 100, filter); 117 json->PutExtAttr( 118 "alignSelf", ITEM_ALIGN[static_cast<int32_t>(propAlignSelf.value_or(FlexAlign::AUTO))], filter); 119 json->PutExtAttr("displayPriority", propDisplayIndex.value_or(1), filter); 120 auto res = JsonUtil::Create(true); 121 res->Put("horizontal", propChainWeight->first.value_or(0.0f)); 122 res->Put("vertical", propChainWeight->second.value_or(0.0f)); 123 json->PutExtAttr("chainWeight", res, filter); 124 } 125 AlignRulesToString()126 std::string AlignRulesToString() 127 { 128 if (!HasAlignRules()) { 129 return ""; 130 } 131 return AlignRulesToString(GetAlignRules().value()); 132 } 133 AlignRulesToString(const AlignRulesItem & alignRules)134 std::string AlignRulesToString(const AlignRulesItem& alignRules) 135 { 136 std::string result; 137 auto iter = alignRules.begin(); 138 for (; iter != alignRules.end(); iter++) { 139 result.append(SingleAlignRuleToString(iter->first, iter->second)); 140 result.append(", "); 141 } 142 return result; 143 } 144 ClearAlignValue()145 void ClearAlignValue() 146 { 147 ResetAlignLeft(); 148 ResetAlignRight(); 149 ResetAlignMiddle(); 150 ResetAlignTop(); 151 ResetAlignBottom(); 152 ResetAlignCenter(); 153 } 154 GetTwoHorizontalDirectionAligned()155 bool GetTwoHorizontalDirectionAligned() const 156 { 157 return (HasAlignLeft() && HasAlignRight()) || (HasAlignRight() && HasAlignMiddle()) || 158 (HasAlignLeft() && HasAlignMiddle()); 159 } 160 GetTwoVerticalDirectionAligned()161 bool GetTwoVerticalDirectionAligned() const 162 { 163 return (HasAlignTop() && HasAlignCenter()) || (HasAlignBottom() && HasAlignCenter()) || 164 (HasAlignTop() && HasAlignBottom()); 165 } 166 SetAlignValue(const AlignDirection & alignDirection,float value)167 void SetAlignValue(const AlignDirection& alignDirection, float value) 168 { 169 static const std::unordered_map<AlignDirection, void (*)(float, FlexItemProperty&)> operators = { 170 { AlignDirection::LEFT, 171 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignLeft(inMapValue); } }, 172 { AlignDirection::RIGHT, 173 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignRight(inMapValue); } }, 174 { AlignDirection::MIDDLE, 175 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignMiddle(inMapValue); } }, 176 { AlignDirection::TOP, [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignTop(inMapValue); } }, 177 { AlignDirection::BOTTOM, 178 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignBottom(inMapValue); } }, 179 { AlignDirection::CENTER, 180 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignCenter(inMapValue); } }, 181 }; 182 auto operatorIter = operators.find(alignDirection); 183 if (operatorIter != operators.end()) { 184 operatorIter->second(value, *this); 185 return; 186 } 187 LOGW("Unknown Align Direction"); 188 } 189 GetAligned(const AlignDirection & alignDirection)190 bool GetAligned(const AlignDirection& alignDirection) 191 { 192 static const std::unordered_map<AlignDirection, bool (*)(FlexItemProperty&)> operators = { 193 { AlignDirection::LEFT, [](FlexItemProperty& item) { return item.HasAlignLeft(); } }, 194 { AlignDirection::RIGHT, [](FlexItemProperty& item) { return item.HasAlignRight(); } }, 195 { AlignDirection::MIDDLE, [](FlexItemProperty& item) { return item.HasAlignMiddle(); } }, 196 { AlignDirection::TOP, [](FlexItemProperty& item) { return item.HasAlignTop(); } }, 197 { AlignDirection::BOTTOM, [](FlexItemProperty& item) { return item.HasAlignBottom(); } }, 198 { AlignDirection::CENTER, [](FlexItemProperty& item) { return item.HasAlignCenter(); } }, 199 }; 200 auto operatorIter = operators.find(alignDirection); 201 if (operatorIter != operators.end()) { 202 return operatorIter->second(*this); 203 } 204 LOGW("Unknown Align Direction"); 205 return false; 206 } 207 GetAlignValue(const AlignDirection & alignDirection)208 float GetAlignValue(const AlignDirection& alignDirection) 209 { 210 static const std::unordered_map<AlignDirection, float (*)(FlexItemProperty&)> operators = { 211 { AlignDirection::LEFT, [](FlexItemProperty& item) { return item.GetAlignLeft().value_or(0.0f); } }, 212 { AlignDirection::RIGHT, [](FlexItemProperty& item) { return item.GetAlignRight().value_or(0.0f); } }, 213 { AlignDirection::MIDDLE, [](FlexItemProperty& item) { return item.GetAlignMiddle().value_or(0.0f); } }, 214 { AlignDirection::TOP, [](FlexItemProperty& item) { return item.GetAlignTop().value_or(0.0f); } }, 215 { AlignDirection::BOTTOM, [](FlexItemProperty& item) { return item.GetAlignBottom().value_or(0.0f); } }, 216 { AlignDirection::CENTER, [](FlexItemProperty& item) { return item.GetAlignCenter().value_or(0.0f); } }, 217 }; 218 auto operatorIter = operators.find(alignDirection); 219 if (operatorIter != operators.end()) { 220 return operatorIter->second(*this); 221 } 222 LOGW("Unknown Align Direction"); 223 return 0.0f; 224 } 225 NeedMarkParentMeasure()226 bool NeedMarkParentMeasure() 227 { 228 return needMarkParentMeasure_; 229 } SetMarkParentMeasure(bool mark)230 void SetMarkParentMeasure(bool mark) 231 { 232 needMarkParentMeasure_ = mark; 233 } 234 FlexLayoutInfoToString()235 std::string FlexLayoutInfoToString() 236 { 237 std::stringstream ss; 238 if (GetFlexBasis().has_value()) { 239 ss << "flexBasis:" << GetFlexBasis().value().ToString() << ", "; 240 } 241 if (GetFlexGrow().has_value()) { 242 ss << "flexGrow:" << GetFlexGrow().value() << ", "; 243 } 244 if (GetFlexShrink().has_value()) { 245 ss << "flexshrink:" << GetFlexShrink().value() << ", "; 246 } 247 if (GetAlignSelf().has_value()) { 248 ss << "alignSelf:" << static_cast<int32_t>(GetAlignSelf().value()) << ", "; 249 } 250 if (GetDisplayIndex().has_value()) { 251 ss << "displayPriority:" << GetDisplayIndex().value(); 252 } 253 return ss.str(); 254 } 255 256 ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexGrow, float); 257 ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexShrink, float); 258 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignSelf, FlexAlign); 259 ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexBasis, Dimension); 260 ACE_DEFINE_PROPERTY_GROUP_ITEM(DisplayIndex, int32_t); 261 ACE_DEFINE_PROPERTY_GROUP_ITEM(HorizontalChainStyle, ChainInfo); 262 ACE_DEFINE_PROPERTY_GROUP_ITEM(VerticalChainStyle, ChainInfo); 263 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignLeft, float); 264 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignMiddle, float); 265 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignRight, float); 266 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignTop, float); 267 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignCenter, float); 268 ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignBottom, float); 269 ACE_DEFINE_PROPERTY_GROUP_ITEM(Bias, BiasPair); 270 ACE_DEFINE_PROPERTY_GROUP_ITEM(Barrier, BarrierItem); 271 ACE_DEFINE_PROPERTY_GROUP_ITEM(Guideline, GuidelineItem); 272 ACE_DEFINE_PROPERTY_GROUP_ITEM_WITH_CALLBACK(AlignRules, AlignRulesItem); 273 ACE_DEFINE_PROPERTY_GROUP_ITEM(ChainWeight, ChainWeightPair); // <horizontal,vertical> 274 275 private: OnAlignRulesUpdate(const AlignRulesItem & item)276 void OnAlignRulesUpdate(const AlignRulesItem& item) 277 { 278 auto prevValue = propAlignRules_; 279 if (TopologicalOrderMightChanged(item)) { 280 needMarkParentMeasure_ = true; 281 } 282 } TopologicalOrderMightChanged(const AlignRulesItem & newValue)283 bool TopologicalOrderMightChanged(const AlignRulesItem& newValue) 284 { 285 // return if has no prev value, then relativeContainer must measure 286 if (!propAlignRules_.has_value()) { 287 return true; 288 } 289 auto& prevValue = propAlignRules_.value(); 290 // target: container can skip redo topological ordering even children might have some changes related to 291 // alignRules Rule Ver.1: a. all key of new map must exist in prev map b. values related to the same key should 292 // have the same value c. when we have less alignRules than the last time, keeping topo order would be fine Next 293 // possible update: allowing new map has more align rules but extra anchor has lower topo order 294 // meaning a new dependency that will be measured earlier is added 295 for (auto iter = newValue.begin(); iter != newValue.end(); iter++) { 296 if (prevValue.find(iter->first) != prevValue.end()) { 297 if (prevValue[iter->first] != iter->second) { 298 return true; 299 } 300 } else { 301 return true; 302 } 303 } 304 return false; 305 } 306 307 bool needMarkParentMeasure_ = false; 308 }; 309 } // namespace OHOS::Ace::NG 310 311 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PROPERTIES_FLEX_PROPERTIES_H 312