• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 #include "frameworks/bridge/common/dom/input/dom_button_util.h"
17 
18 #include "frameworks/bridge/common/utils/utils.h"
19 
20 namespace OHOS::Ace::Framework {
21 namespace {
22 
23 constexpr uint32_t WATCH_BACKGROUND_COLOR = 0xff007dff;
24 constexpr uint32_t WATCH_TEXT_COLOR = 0xffffffff;
25 constexpr Dimension BOX_HOVER_RADIUS = 8.0_vp;
26 
27 } // namespace
28 
InitDefaultValue(const RefPtr<ButtonComponent> & component,const RefPtr<TextComponent> & textChild,const RefPtr<ButtonTheme> & theme)29 void DOMButtonUtil::InitDefaultValue(
30     const RefPtr<ButtonComponent>& component, const RefPtr<TextComponent>& textChild, const RefPtr<ButtonTheme>& theme)
31 {
32     // set default properties
33     component->SetLayoutFlag(LAYOUT_FLAG_EXTEND_TO_PARENT);
34     component->SetBackgroundColor(theme->GetBgColor());
35     component->SetFocusColor(theme->GetBgFocusColor());
36     component->SetFocusAnimationColor(theme->GetBgFocusColor());
37     component->SetHoverColor(theme->GetHoverColor());
38     component->SetCatchMode(false);
39     textChild->SetFocusColor(theme->GetTextFocusColor());
40     // set text styles
41     auto textStyle = theme->GetTextStyle();
42     textStyle.SetAdaptTextSize(textStyle.GetFontSize(), theme->GetMinFontSize());
43     textStyle.SetTextAlign(TextAlign::CENTER);
44     textStyle.SetMaxLines(theme->GetTextMaxLines());
45     textStyle.SetTextOverflow(TextOverflow::ELLIPSIS);
46     // set default background color and text color in watch
47     if (SystemProperties::GetDeviceType() == DeviceType::WATCH) {
48         component->SetBackgroundColor(Color(WATCH_BACKGROUND_COLOR));
49         textStyle.SetTextColor(Color(WATCH_TEXT_COLOR));
50         textChild->SetFocusColor(Color(WATCH_TEXT_COLOR));
51     }
52     textChild->SetTextStyle(textStyle);
53 }
54 
CreateComponentAndSetChildAttr(const std::map<std::string,std::string> & attrs,DOMInput & node)55 RefPtr<ButtonComponent> DOMButtonUtil::CreateComponentAndSetChildAttr(
56     const std::map<std::string, std::string>& attrs, DOMInput& node)
57 {
58     std::list<RefPtr<Component>> buttonChildren;
59     RefPtr<ButtonComponent> component = AceType::MakeRefPtr<ButtonComponent>(buttonChildren);
60     RefPtr<ButtonTheme> theme = node.GetTheme<ButtonTheme>();
61     if (!theme) {
62         return component;
63     }
64     RefPtr<TextComponent> textChild = AceType::MakeRefPtr<TextComponent>("");
65     RefPtr<PaddingComponent> padding = AceType::MakeRefPtr<PaddingComponent>();
66     padding->SetPadding(theme->GetPadding());
67     padding->SetChild(textChild);
68     component->AppendChild(padding);
69     InitDefaultValue(component, textChild, theme);
70 
71     auto boxComponent = node.GetBoxComponent();
72     if (boxComponent) {
73         if (!boxComponent->GetBackDecoration()) {
74             RefPtr<Decoration> backDecoration = AceType::MakeRefPtr<Decoration>();
75             backDecoration->SetBorderRadius(Radius(BOX_HOVER_RADIUS));
76             boxComponent->SetBackDecoration(backDecoration);
77         }
78     } else {
79         LOGE("boxComponent is null");
80         return component;
81     }
82     if (LessOrEqual(node.GetHeight().Value(), 0.0)) {
83         node.SetHeight(theme->GetHeight());
84         component->SetHeight(theme->GetHeight());
85         boxComponent->SetHeight(theme->GetHeight());
86     } else {
87         component->SetHeight(boxComponent->GetHeightDimension());
88     }
89     if (GreatNotEqual(boxComponent->GetWidthDimension().Value(), 0.0)) {
90         padding->SetPadding(Edge());
91         component->SetWidth(boxComponent->GetWidthDimension());
92     }
93     if (component->GetHeight().Unit() == DimensionUnit::PERCENT) {
94         component->SetInputButton(true);
95     } else {
96         component->SetRectRadius(component->GetHeight() / 2);
97     }
98     component->SetMouseAnimationType(HoverAnimationType::SCALE);
99     SetChildAttr(component, attrs, theme);
100     return component;
101 }
102 
SetChildAttr(const RefPtr<ButtonComponent> & component,const std::map<std::string,std::string> & attrs,const RefPtr<ButtonTheme> & theme)103 void DOMButtonUtil::SetChildAttr(const RefPtr<ButtonComponent>& component,
104     const std::map<std::string, std::string>& attrs, const RefPtr<ButtonTheme>& theme)
105 {
106     if (!component) {
107         LOGE("fail to set child attr due to button component is null");
108         return;
109     }
110     component->SetType(ButtonType::NORMAL);
111     for (const auto& attr : attrs) {
112         if (attr.first == DOM_DISABLED) {
113             component->SetDisabledState(StringToBool(attr.second));
114         } else if (attr.first == DOM_INPUT_AUTO_FOCUS) {
115             component->SetAutoFocusState(StringToBool(attr.second));
116         }
117     }
118     // set text data to Text child
119     std::list<RefPtr<Component>> children = component->GetChildren();
120     RefPtr<PaddingComponent> padding = AceType::DynamicCast<PaddingComponent>(children.front());
121     if (!padding) {
122         return;
123     }
124     RefPtr<TextComponent> textChild = AceType::DynamicCast<TextComponent>(padding->GetChild());
125     auto inputValue = attrs.find(DOM_INPUT_VALUE);
126     if (inputValue != attrs.end()) {
127         textChild->SetData(inputValue->second);
128     }
129     if (component->GetDisabledState()) {
130         auto textStyle = textChild->GetTextStyle();
131         textStyle.SetTextColor(theme->GetTextDisabledColor());
132         textChild->SetTextStyle(textStyle);
133     }
134 }
135 
SetChildStyle(const RefPtr<BoxComponent> & boxComponent,const RefPtr<ButtonComponent> & component,const std::map<std::string,std::string> & styles,DOMInput & node)136 void DOMButtonUtil::SetChildStyle(const RefPtr<BoxComponent>& boxComponent, const RefPtr<ButtonComponent>& component,
137     const std::map<std::string, std::string>& styles, DOMInput& node)
138 {
139     if (!boxComponent || !component) {
140         LOGE("fail to set child style due to box and button component is null");
141         return;
142     }
143     // get style which is set by theme
144     std::list<RefPtr<Component>> children = component->GetChildren();
145     RefPtr<PaddingComponent> padding = AceType::DynamicCast<PaddingComponent>(children.front());
146     if (!padding) {
147         return;
148     }
149     RefPtr<TextComponent> textChild = AceType::DynamicCast<TextComponent>(padding->GetChild());
150     TextStyle parentStyle = textChild->GetTextStyle();
151     static const LinearMapNode<void (*)(
152         const std::string&, const DOMInput&, const RefPtr<ButtonComponent>&, TextStyle&)>
153         styleOperators[] = {
154             { DOM_INPUT_BACKGROUND_COLOR,
155                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
156                     TextStyle& style) { component->SetBackgroundColor(node.ParseColor(value)); } },
157             { DOM_INPUT_CLICKED_COLOR,
158                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
159                     TextStyle& style) { component->SetClickedColor(node.ParseColor(value)); } },
160             { DOM_INPUT_COLOR,
161                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
162                     TextStyle& style) { style.SetTextColor(node.ParseColor(value)); } },
163             { DOM_INPUT_DISABLE_COLOR,
164                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
165                     TextStyle& style) { component->SetDisabledColor(node.ParseColor(value)); } },
166             { DOM_INPUT_FOCUS_COLOR,
167                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
168                     TextStyle& style) { component->SetFocusColor(node.ParseColor(value)); } },
169             { DOM_INPUT_FONT_FAMILY,
170                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
171                     TextStyle& style) {
172                     std::vector<std::string> fontFamilies;
173                     std::stringstream sstr(value);
174                     std::string fontFamily;
175                     while (getline(sstr, fontFamily, ',')) {
176                         fontFamilies.emplace_back(fontFamily);
177                     }
178                     style.SetFontFamilies(fontFamilies);
179                 } },
180             { DOM_INPUT_FONT_SIZE,
181                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
182                     TextStyle& style) { style.SetFontSize(node.ParseDimension(value)); } },
183             { DOM_INPUT_FONT_WEIGHT,
184                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
185                     TextStyle& style) { style.SetFontWeight(ConvertStrToFontWeight(value)); } },
186             { DOM_INPUT_RECT_RADIUS,
187                 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
188                     TextStyle& style) { component->SetRectRadius(node.ParseDimension(value)); } },
189         };
190     static const LinearMapNode<void (*)(const std::string&, const DOMInput&, const RefPtr<PaddingComponent>&)>
191         paddingStyleOperators[] = {
192             { DOM_PADDING_BOTTOM,
193                 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
194                     component->SetPaddingBottom(node.ParseDimension(value));
195                 } },
196             { DOM_PADDING_LEFT,
197                 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
198                     component->SetPaddingLeft(node.ParseDimension(value));
199                 } },
200             { DOM_PADDING_RIGHT,
201                 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
202                     component->SetPaddingRight(node.ParseDimension(value));
203                 } },
204             { DOM_PADDING_TOP,
205                 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
206                     component->SetPaddingTop(node.ParseDimension(value));
207                 } },
208         };
209     // set text style properties
210     for (const auto& [key, value] : styles) {
211         auto operatorIter = BinarySearchFindIndex(styleOperators, ArraySize(styleOperators), key.c_str());
212         if (operatorIter != -1) {
213             styleOperators[operatorIter].value(value, node, component, parentStyle);
214             continue;
215         }
216         auto paddingOperator =
217             BinarySearchFindIndex(paddingStyleOperators, ArraySize(paddingStyleOperators), key.c_str());
218         if (paddingOperator != -1) {
219             paddingStyleOperators[paddingOperator].value(value, node, padding);
220         }
221     }
222     auto theme = node.GetTheme<ButtonTheme>();
223     if (theme) {
224         component->SetDisabledColor(component->GetBackgroundColor().BlendOpacity(theme->GetBgDisabledAlpha()));
225         component->SetClickedColor(component->GetBackgroundColor().BlendColor(theme->GetClickedColor()));
226         if (parentStyle.GetFontSize() != theme->GetTextStyle().GetFontSize()) {
227             parentStyle.SetAdaptTextSize(parentStyle.GetFontSize(), parentStyle.GetFontSize());
228         }
229     }
230     // set text style to Text child
231     if (SystemProperties::GetDeviceType() != DeviceType::TV) {
232         textChild->SetFocusColor(parentStyle.GetTextColor());
233     }
234     textChild->SetTextStyle(parentStyle);
235 
236     auto backDecoration = boxComponent->GetBackDecoration();
237     if (backDecoration) {
238         const auto& border = backDecoration->GetBorder();
239         if (node.HasBorderRadiusStyle()) {
240             component->SetRectRadius(border.TopLeftRadius().GetX() - border.Top().GetWidth());
241             component->SetRadiusState(true);
242         } else {
243             backDecoration->SetBorderRadius(Radius(component->GetRectRadius()));
244         }
245         if (node.CheckPseduo(backDecoration)) {
246             component->SetType(ButtonType::ICON);
247         }
248     }
249     boxComponent->SetPadding(Edge());
250 }
251 
AddChildEvent(const RefPtr<ButtonComponent> & component,int32_t pageId,const std::string & nodeId,const std::vector<std::string> & events)252 void DOMButtonUtil::AddChildEvent(const RefPtr<ButtonComponent>& component, int32_t pageId, const std::string& nodeId,
253     const std::vector<std::string>& events)
254 {
255     if (!component) {
256         LOGE("fail to add child event due to button component is null");
257         return;
258     }
259     static const LinearMapNode<void (*)(const RefPtr<ButtonComponent>&, EventMarker&)> eventOperators[] = {
260         { DOM_CATCH_BUBBLE_CLICK,
261             [](const RefPtr<ButtonComponent>& component, EventMarker& event) {
262                 event.SetCatchMode(true);
263                 component->SetClickedEventId(event);
264             } },
265         { DOM_CLICK,
266             [](const RefPtr<ButtonComponent>& component, EventMarker& event) {
267                 event.SetCatchMode(false);
268                 component->SetClickedEventId(event);
269             } },
270     };
271     for (const auto& event : events) {
272         auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
273         if (operatorIter != -1) {
274             EventMarker eventMarker(nodeId, event, pageId);
275             eventOperators[operatorIter].value(component, eventMarker);
276         }
277     }
278 }
279 
280 } // namespace OHOS::Ace::Framework
281