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 return component;
80 }
81 if (LessOrEqual(node.GetHeight().Value(), 0.0)) {
82 node.SetHeight(theme->GetHeight());
83 component->SetHeight(theme->GetHeight());
84 boxComponent->SetHeight(theme->GetHeight());
85 } else {
86 component->SetHeight(boxComponent->GetHeightDimension());
87 }
88 if (GreatNotEqual(boxComponent->GetWidthDimension().Value(), 0.0)) {
89 padding->SetPadding(Edge());
90 component->SetWidth(boxComponent->GetWidthDimension());
91 }
92 if (component->GetHeight().Unit() == DimensionUnit::PERCENT) {
93 component->SetInputButton(true);
94 } else {
95 component->SetRectRadius(component->GetHeight() / 2);
96 }
97 component->SetMouseAnimationType(HoverAnimationType::SCALE);
98 SetChildAttr(component, attrs, theme);
99 return component;
100 }
101
SetChildAttr(const RefPtr<ButtonComponent> & component,const std::map<std::string,std::string> & attrs,const RefPtr<ButtonTheme> & theme)102 void DOMButtonUtil::SetChildAttr(const RefPtr<ButtonComponent>& component,
103 const std::map<std::string, std::string>& attrs, const RefPtr<ButtonTheme>& theme)
104 {
105 if (!component) {
106 return;
107 }
108 component->SetType(ButtonType::NORMAL);
109 for (const auto& attr : attrs) {
110 if (attr.first == DOM_DISABLED) {
111 component->SetDisabledState(StringToBool(attr.second));
112 } else if (attr.first == DOM_INPUT_AUTO_FOCUS) {
113 component->SetAutoFocusState(StringToBool(attr.second));
114 }
115 }
116 // set text data to Text child
117 std::list<RefPtr<Component>> children = component->GetChildren();
118 RefPtr<PaddingComponent> padding = AceType::DynamicCast<PaddingComponent>(children.front());
119 if (!padding) {
120 return;
121 }
122 RefPtr<TextComponent> textChild = AceType::DynamicCast<TextComponent>(padding->GetChild());
123 auto inputValue = attrs.find(DOM_INPUT_VALUE);
124 if (inputValue != attrs.end()) {
125 textChild->SetData(inputValue->second);
126 }
127 if (component->GetDisabledState()) {
128 auto textStyle = textChild->GetTextStyle();
129 textStyle.SetTextColor(theme->GetTextDisabledColor());
130 textChild->SetTextStyle(textStyle);
131 }
132 }
133
SetChildStyle(const RefPtr<BoxComponent> & boxComponent,const RefPtr<ButtonComponent> & component,const std::map<std::string,std::string> & styles,DOMInput & node)134 void DOMButtonUtil::SetChildStyle(const RefPtr<BoxComponent>& boxComponent, const RefPtr<ButtonComponent>& component,
135 const std::map<std::string, std::string>& styles, DOMInput& node)
136 {
137 if (!boxComponent || !component) {
138 return;
139 }
140 // get style which is set by theme
141 std::list<RefPtr<Component>> children = component->GetChildren();
142 RefPtr<PaddingComponent> padding = AceType::DynamicCast<PaddingComponent>(children.front());
143 if (!padding) {
144 return;
145 }
146 RefPtr<TextComponent> textChild = AceType::DynamicCast<TextComponent>(padding->GetChild());
147 TextStyle parentStyle = textChild->GetTextStyle();
148 static const LinearMapNode<void (*)(
149 const std::string&, const DOMInput&, const RefPtr<ButtonComponent>&, TextStyle&)>
150 styleOperators[] = {
151 { DOM_INPUT_BACKGROUND_COLOR,
152 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
153 TextStyle& style) { component->SetBackgroundColor(node.ParseColor(value)); } },
154 { DOM_INPUT_CLICKED_COLOR,
155 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
156 TextStyle& style) { component->SetClickedColor(node.ParseColor(value)); } },
157 { DOM_INPUT_COLOR,
158 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
159 TextStyle& style) { style.SetTextColor(node.ParseColor(value)); } },
160 { DOM_INPUT_DISABLE_COLOR,
161 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
162 TextStyle& style) { component->SetDisabledColor(node.ParseColor(value)); } },
163 { DOM_INPUT_FOCUS_COLOR,
164 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
165 TextStyle& style) { component->SetFocusColor(node.ParseColor(value)); } },
166 { DOM_INPUT_FONT_FAMILY,
167 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
168 TextStyle& style) {
169 std::vector<std::string> fontFamilies;
170 std::stringstream sstr(value);
171 std::string fontFamily;
172 while (getline(sstr, fontFamily, ',')) {
173 fontFamilies.emplace_back(fontFamily);
174 }
175 style.SetFontFamilies(fontFamilies);
176 } },
177 { DOM_INPUT_FONT_SIZE,
178 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
179 TextStyle& style) { style.SetFontSize(node.ParseDimension(value)); } },
180 { DOM_INPUT_FONT_WEIGHT,
181 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
182 TextStyle& style) { style.SetFontWeight(ConvertStrToFontWeight(value)); } },
183 { DOM_INPUT_RECT_RADIUS,
184 [](const std::string& value, const DOMInput& node, const RefPtr<ButtonComponent>& component,
185 TextStyle& style) { component->SetRectRadius(node.ParseDimension(value)); } },
186 };
187 static const LinearMapNode<void (*)(const std::string&, const DOMInput&, const RefPtr<PaddingComponent>&)>
188 paddingStyleOperators[] = {
189 { DOM_PADDING_BOTTOM,
190 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
191 component->SetPaddingBottom(node.ParseDimension(value));
192 } },
193 { DOM_PADDING_LEFT,
194 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
195 component->SetPaddingLeft(node.ParseDimension(value));
196 } },
197 { DOM_PADDING_RIGHT,
198 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
199 component->SetPaddingRight(node.ParseDimension(value));
200 } },
201 { DOM_PADDING_TOP,
202 [](const std::string& value, const DOMInput& node, const RefPtr<PaddingComponent>& component) {
203 component->SetPaddingTop(node.ParseDimension(value));
204 } },
205 };
206 // set text style properties
207 for (const auto& [key, value] : styles) {
208 auto operatorIter = BinarySearchFindIndex(styleOperators, ArraySize(styleOperators), key.c_str());
209 if (operatorIter != -1) {
210 styleOperators[operatorIter].value(value, node, component, parentStyle);
211 continue;
212 }
213 auto paddingOperator =
214 BinarySearchFindIndex(paddingStyleOperators, ArraySize(paddingStyleOperators), key.c_str());
215 if (paddingOperator != -1) {
216 paddingStyleOperators[paddingOperator].value(value, node, padding);
217 }
218 }
219 auto theme = node.GetTheme<ButtonTheme>();
220 if (theme) {
221 component->SetDisabledColor(component->GetBackgroundColor().BlendOpacity(theme->GetBgDisabledAlpha()));
222 component->SetClickedColor(component->GetBackgroundColor().BlendColor(theme->GetClickedColor()));
223 if (parentStyle.GetFontSize() != theme->GetTextStyle().GetFontSize()) {
224 parentStyle.SetAdaptTextSize(parentStyle.GetFontSize(), parentStyle.GetFontSize());
225 }
226 }
227 // set text style to Text child
228 if (SystemProperties::GetDeviceType() != DeviceType::TV) {
229 textChild->SetFocusColor(parentStyle.GetTextColor());
230 }
231 textChild->SetTextStyle(parentStyle);
232
233 auto backDecoration = boxComponent->GetBackDecoration();
234 if (backDecoration) {
235 const auto& border = backDecoration->GetBorder();
236 if (node.HasBorderRadiusStyle()) {
237 component->SetRectRadius(border.TopLeftRadius().GetX() - border.Top().GetWidth());
238 component->SetRadiusState(true);
239 } else {
240 backDecoration->SetBorderRadius(Radius(component->GetRectRadius()));
241 }
242 if (node.CheckPseduo(backDecoration)) {
243 component->SetType(ButtonType::ICON);
244 }
245 }
246 boxComponent->SetPadding(Edge());
247 }
248
AddChildEvent(const RefPtr<ButtonComponent> & component,int32_t pageId,const std::string & nodeId,const std::vector<std::string> & events)249 void DOMButtonUtil::AddChildEvent(const RefPtr<ButtonComponent>& component, int32_t pageId, const std::string& nodeId,
250 const std::vector<std::string>& events)
251 {
252 if (!component) {
253 return;
254 }
255 static const LinearMapNode<void (*)(const RefPtr<ButtonComponent>&, EventMarker&)> eventOperators[] = {
256 { DOM_CATCH_BUBBLE_CLICK,
257 [](const RefPtr<ButtonComponent>& component, EventMarker& event) {
258 event.SetCatchMode(true);
259 component->SetClickedEventId(event);
260 } },
261 { DOM_CLICK,
262 [](const RefPtr<ButtonComponent>& component, EventMarker& event) {
263 event.SetCatchMode(false);
264 component->SetClickedEventId(event);
265 } },
266 };
267 for (const auto& event : events) {
268 auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
269 if (operatorIter != -1) {
270 EventMarker eventMarker(nodeId, event, pageId);
271 eventOperators[operatorIter].value(component, eventMarker);
272 }
273 }
274 }
275
276 } // namespace OHOS::Ace::Framework
277