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 "core/components/common/layout/constants.h"
24 #include "core/components/common/layout/position_param.h"
25 #include "core/components_ng/base/inspector_filter.h"
26 #include "core/components_ng/property/property.h"
27 
28 namespace OHOS::Ace::NG {
29 using AlignRulesItem = std::map<AlignDirection, AlignRule>;
30 using BiasPair = std::pair<float, float>;
31 using LayoutWeightPair = std::pair<std::optional<float>, std::optional<float>>; // <horizontal,vertical>
32 using GuidelineItem = std::vector<GuidelineInfo>;
33 using BarrierItem = std::vector<BarrierInfo>;
34 namespace {
35 constexpr int32_t HORIZONTAL_DIRECTION_RANGE = 3;
36 constexpr int32_t VERTICAL_DIRECTION_RANGE = 6;
HorizontalAlignToString(HorizontalAlign align)37 std::string HorizontalAlignToString(HorizontalAlign align)
38 {
39     switch (align) {
40         case HorizontalAlign::CENTER:
41             return "HorizontalAlign::Center";
42         case HorizontalAlign::START:
43             return "HorizontalAlign::Start";
44         case HorizontalAlign::END:
45             return "HorizontalAlign::End";
46         default:
47             return "Unknown";
48     }
49 }
50 
VerticalAlignToString(VerticalAlign align)51 std::string VerticalAlignToString(VerticalAlign align)
52 {
53     switch (align) {
54         case VerticalAlign::TOP:
55             return "VerticalAlign::Top";
56         case VerticalAlign::CENTER:
57             return "VerticalAlign::Center";
58         case VerticalAlign::BOTTOM:
59             return "VerticalAlign::Bottom";
60         case VerticalAlign::BASELINE:
61             return "VerticalAlign::BaseLine";
62         default:
63             return "Unknown";
64     }
65 }
66 
AlignDirectionToString(AlignDirection direction)67 std::string AlignDirectionToString(AlignDirection direction)
68 {
69     switch (direction) {
70         case AlignDirection::MIDDLE:
71             return "AlignDirection::Middle";
72         case AlignDirection::LEFT:
73             return "AlignDirection::Left";
74         case AlignDirection::RIGHT:
75             return "AlignDirection::Middle";
76         case AlignDirection::TOP:
77             return "AlignDirection::Top";
78         case AlignDirection::CENTER:
79             return "AlignDirection::Center";
80         case AlignDirection::BOTTOM:
81             return "AlignDirection::Bottom";
82         default:
83             return "Unknown";
84     }
85 }
86 
SingleAlignRuleToString(AlignDirection direction,AlignRule rule)87 std::string SingleAlignRuleToString(AlignDirection direction, AlignRule rule)
88 {
89     std::string result = AlignDirectionToString(direction) + ": {'" + rule.anchor + "', ";
90     if (static_cast<int32_t>(direction) < HORIZONTAL_DIRECTION_RANGE) {
91         result += HorizontalAlignToString(rule.horizontal);
92     } else if (static_cast<int32_t>(direction) < VERTICAL_DIRECTION_RANGE) {
93         result += VerticalAlignToString(rule.vertical);
94     } else {
95         result += "Unknown";
96     }
97     result += "}";
98     return result;
99 }
100 } // namespace
101 
102 struct FlexItemProperty {
103     ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexGrow, float);
104     ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexShrink, float);
105     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignSelf, FlexAlign);
106     ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexBasis, Dimension);
107     ACE_DEFINE_PROPERTY_GROUP_ITEM(DisplayIndex, int32_t);
108     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignRules, AlignRulesItem);
109     ACE_DEFINE_PROPERTY_GROUP_ITEM(HorizontalChainStyle, ChainInfo);
110     ACE_DEFINE_PROPERTY_GROUP_ITEM(VerticalChainStyle, ChainInfo);
111     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignLeft, float);
112     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignMiddle, float);
113     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignRight, float);
114     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignTop, float);
115     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignCenter, float);
116     ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignBottom, float);
117     ACE_DEFINE_PROPERTY_GROUP_ITEM(Bias, BiasPair);
118     ACE_DEFINE_PROPERTY_GROUP_ITEM(Barrier, BarrierItem);
119     ACE_DEFINE_PROPERTY_GROUP_ITEM(Guideline, GuidelineItem);
120     ACE_DEFINE_PROPERTY_GROUP_ITEM(ChainWeight, LayoutWeightPair); // <horizontal,vertical>
121 
ToJsonValueFlexItemProperty122     void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
123     {
124         static const char* ITEM_ALIGN[] = { "ItemAlign.Auto", "ItemAlign.Start", "ItemAlign.Center", "ItemAlign.End",
125             "ItemAlign.Stretch", "ItemAlign.Baseline" };
126         /* no fixed attr below, just return */
127         if (filter.IsFastFilter()) {
128             return;
129         }
130         json->PutExtAttr("flexBasis",
131             propFlexBasis.has_value() ? propFlexBasis.value().ToString().c_str() : "auto", filter);
132         json->PutExtAttr("flexGrow", round(static_cast<double>(propFlexGrow.value_or(0.0)) * 100) / 100, filter);
133         json->PutExtAttr("flexShrink", round(static_cast<double>(propFlexShrink.value_or(1)) * 100) / 100, filter);
134         json->PutExtAttr("alignSelf",
135             ITEM_ALIGN[static_cast<int32_t>(propAlignSelf.value_or(FlexAlign::AUTO))], filter);
136         json->PutExtAttr("displayPriority", propDisplayIndex.value_or(1), filter);
137     }
138 
AlignRulesToStringFlexItemProperty139     std::string AlignRulesToString()
140     {
141         std::string result;
142         if (!HasAlignRules()) {
143             return result;
144         }
145         auto rules = GetAlignRules().value();
146         auto iter = rules.begin();
147         for (; iter != rules.end(); iter++) {
148             result.append(SingleAlignRuleToString(iter->first, iter->second));
149             result.append(", ");
150         }
151         return result;
152     }
153 
ClearAlignValueFlexItemProperty154     void ClearAlignValue()
155     {
156         ResetAlignLeft();
157         ResetAlignRight();
158         ResetAlignMiddle();
159         ResetAlignTop();
160         ResetAlignBottom();
161         ResetAlignCenter();
162     }
163 
GetTwoHorizontalDirectionAlignedFlexItemProperty164     bool GetTwoHorizontalDirectionAligned() const
165     {
166         return (HasAlignLeft() && HasAlignRight()) || (HasAlignRight() && HasAlignMiddle()) ||
167                (HasAlignLeft() && HasAlignMiddle());
168     }
169 
GetTwoVerticalDirectionAlignedFlexItemProperty170     bool GetTwoVerticalDirectionAligned() const
171     {
172         return (HasAlignTop() && HasAlignCenter()) || (HasAlignBottom() && HasAlignCenter()) ||
173                (HasAlignTop() && HasAlignBottom());
174     }
175 
SetAlignValueFlexItemProperty176     void SetAlignValue(const AlignDirection& alignDirection, float value)
177     {
178         static const std::unordered_map<AlignDirection, void (*)(float, FlexItemProperty&)> operators = {
179             { AlignDirection::LEFT,
180                 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignLeft(inMapValue); } },
181             { AlignDirection::RIGHT,
182                 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignRight(inMapValue); } },
183             { AlignDirection::MIDDLE,
184                 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignMiddle(inMapValue); } },
185             { AlignDirection::TOP, [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignTop(inMapValue); } },
186             { AlignDirection::BOTTOM,
187                 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignBottom(inMapValue); } },
188             { AlignDirection::CENTER,
189                 [](float inMapValue, FlexItemProperty& item) { item.UpdateAlignCenter(inMapValue); } },
190         };
191         auto operatorIter = operators.find(alignDirection);
192         if (operatorIter != operators.end()) {
193             operatorIter->second(value, *this);
194             return;
195         }
196         LOGE("Unknown Align Direction");
197     }
198 
GetAlignedFlexItemProperty199     bool GetAligned(const AlignDirection& alignDirection)
200     {
201         static const std::unordered_map<AlignDirection, bool (*)(FlexItemProperty&)> operators = {
202             { AlignDirection::LEFT, [](FlexItemProperty& item) { return item.HasAlignLeft(); } },
203             { AlignDirection::RIGHT, [](FlexItemProperty& item) { return item.HasAlignRight(); } },
204             { AlignDirection::MIDDLE, [](FlexItemProperty& item) { return item.HasAlignMiddle(); } },
205             { AlignDirection::TOP, [](FlexItemProperty& item) { return item.HasAlignTop(); } },
206             { AlignDirection::BOTTOM, [](FlexItemProperty& item) { return item.HasAlignBottom(); } },
207             { AlignDirection::CENTER, [](FlexItemProperty& item) { return item.HasAlignCenter(); } },
208         };
209         auto operatorIter = operators.find(alignDirection);
210         if (operatorIter != operators.end()) {
211             return operatorIter->second(*this);
212         }
213         LOGE("Unknown Align Direction");
214         return false;
215     }
216 
GetAlignValueFlexItemProperty217     float GetAlignValue(const AlignDirection& alignDirection)
218     {
219         static const std::unordered_map<AlignDirection, float (*)(FlexItemProperty&)> operators = {
220             { AlignDirection::LEFT, [](FlexItemProperty& item) { return item.GetAlignLeft().value_or(0.0f); } },
221             { AlignDirection::RIGHT, [](FlexItemProperty& item) { return item.GetAlignRight().value_or(0.0f); } },
222             { AlignDirection::MIDDLE, [](FlexItemProperty& item) { return item.GetAlignMiddle().value_or(0.0f); } },
223             { AlignDirection::TOP, [](FlexItemProperty& item) { return item.GetAlignTop().value_or(0.0f); } },
224             { AlignDirection::BOTTOM, [](FlexItemProperty& item) { return item.GetAlignBottom().value_or(0.0f); } },
225             { AlignDirection::CENTER, [](FlexItemProperty& item) { return item.GetAlignCenter().value_or(0.0f); } },
226         };
227         auto operatorIter = operators.find(alignDirection);
228         if (operatorIter != operators.end()) {
229             return operatorIter->second(*this);
230         }
231         LOGE("Unknown Align Direction");
232         return 0.0f;
233     }
234 };
235 } // namespace OHOS::Ace::NG
236 
237 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PROPERTIES_FLEX_PROPERTIES_H
238