• 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_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