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/dom_menu.h"
17
18 #include "frameworks/bridge/common/utils/utils.h"
19
20 namespace OHOS::Ace::Framework {
21
DOMMenu(NodeId nodeId,const std::string & nodeName)22 DOMMenu::DOMMenu(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
23 {
24 menuChild_ = AceType::MakeRefPtr<MenuComponent>(std::to_string(nodeId), nodeName);
25 }
26
~DOMMenu()27 DOMMenu::~DOMMenu()
28 {
29 if (!clickMarkerId_.IsEmpty()) {
30 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(clickMarkerId_);
31 }
32 if (!focusMarkerId_.IsEmpty()) {
33 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(focusMarkerId_);
34 }
35 if (!longPressMarkerId_.IsEmpty()) {
36 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(longPressMarkerId_);
37 }
38 }
39
InitializeStyle()40 void DOMMenu::InitializeStyle()
41 {
42 ResetInitializedStyle();
43 }
44
ResetInitializedStyle()45 void DOMMenu::ResetInitializedStyle()
46 {
47 menuChild_->InitTheme(GetThemeManager());
48 titleStyle_ = menuChild_->GetTitleStyle();
49 }
50
OnChildNodeRemoved(const RefPtr<DOMNode> & child)51 void DOMMenu::OnChildNodeRemoved(const RefPtr<DOMNode>& child)
52 {
53 if (!child) {
54 return;
55 }
56
57 auto option = AceType::DynamicCast<OptionComponent>(child->GetSpecializedComponent());
58 if (!option) {
59 return;
60 }
61
62 menuChild_->RemoveOption(option);
63 }
64
PrepareSpecializedComponent()65 void DOMMenu::PrepareSpecializedComponent()
66 {
67 menuChild_->SetTextDirection((IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR));
68 menuChild_->SetTitleStyle(titleStyle_);
69 }
70
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)71 bool DOMMenu::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
72 {
73 if (attr.first == DOM_TYPE) {
74 isClickType_ = (attr.second == DOM_CLICK);
75 return true;
76 }
77
78 if (attr.first == DOM_TITLE && !attr.second.empty()) {
79 menuChild_->SetTitle(attr.second);
80 }
81
82 return true;
83 }
84
SetSpecializedStyle(const std::pair<std::string,std::string> & style)85 bool DOMMenu::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
86 {
87 static const LinearMapNode<void (*)(TextStyle&, const std::string&, const DOMMenu&)> menuStyleOperators[] = {
88 { DOM_TEXT_ALLOW_SCALE, [](TextStyle& textStyle, const std::string& val,
89 const DOMMenu&) { textStyle.SetAllowScale(StringToBool(val)); } },
90 { DOM_TEXT_FONT_FAMILY, [](TextStyle& textStyle, const std::string& val,
91 const DOMMenu& node) { textStyle.SetFontFamilies(node.ParseFontFamilies(val)); } },
92 { DOM_TEXT_FONT_SIZE, [](TextStyle& textStyle, const std::string& val,
93 const DOMMenu& node) { textStyle.SetFontSize(node.ParseDimension(val)); } },
94 { DOM_TEXT_FONT_STYLE, [](TextStyle& textStyle, const std::string& val,
95 const DOMMenu&) { textStyle.SetFontStyle(ConvertStrToFontStyle(val)); } },
96 { DOM_TEXT_FONT_WEIGHT, [](TextStyle& textStyle, const std::string& val,
97 const DOMMenu&) { textStyle.SetFontWeight(ConvertStrToFontWeight(val)); } },
98 { DOM_TEXT_LETTER_SPACING, [](TextStyle& textStyle, const std::string& val,
99 const DOMMenu& node) { textStyle.SetLetterSpacing(node.ParseDimension(val)); } },
100 { DOM_PICKER_TEXT_COLOR, // use define of picker which is the same "text-color"
101 [](TextStyle& textStyle, const std::string& val, const DOMMenu& node) {
102 textStyle.SetTextColor(node.ParseColor(val));
103 } },
104 { DOM_TEXT_DECORATION, [](TextStyle& textStyle, const std::string& val,
105 const DOMMenu&) { textStyle.SetTextDecoration(ConvertStrToTextDecoration(val)); } },
106 };
107 auto operatorIter = BinarySearchFindIndex(menuStyleOperators, ArraySize(menuStyleOperators), style.first.c_str());
108 if (operatorIter != -1) {
109 menuStyleOperators[operatorIter].value(titleStyle_, style.second, *this);
110 return true;
111 }
112 return false;
113 }
114
AddSpecializedEvent(int32_t pageId,const std::string & event)115 bool DOMMenu::AddSpecializedEvent(int32_t pageId, const std::string& event)
116 {
117 if (event == DOM_SELECTED) {
118 menuChild_->SetOnSuccess(EventMarker(GetNodeIdForEvent(), event, pageId));
119 } else if (event == DOM_CANCEL) {
120 menuChild_->SetOnCancel(EventMarker(GetNodeIdForEvent(), event, pageId));
121 } else {
122 return false;
123 }
124 return true;
125 }
126
GetSpecializedComponent()127 RefPtr<Component> DOMMenu::GetSpecializedComponent()
128 {
129 return menuChild_;
130 }
131
BindIdNode(const RefPtr<DOMNode> & idNode)132 void DOMMenu::BindIdNode(const RefPtr<DOMNode>& idNode)
133 {
134 if (SystemProperties::GetDeviceType() == DeviceType::TV) {
135 focusMarkerId_ = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
136 BackEndEventManager<void()>::GetInstance().BindBackendEvent(focusMarkerId_, [weak = WeakClaim(this), idNode]() {
137 if (!idNode || idNode->IsNodeDisabled()) {
138 return;
139 }
140 auto domMenu = weak.Upgrade();
141 if (!domMenu) {
142 return;
143 }
144 const auto& targetCallback = domMenu->menuChild_->GetTargetCallback();
145 const auto& targetId = idNode->GetRootComponent()->GetId();
146 if (targetCallback) {
147 targetCallback(targetId, Offset(0, 0));
148 }
149 });
150 idNode->SetOnFocusClick(focusMarkerId_);
151 }
152 if (isClickType_) {
153 clickMarkerId_ = BackEndEventManager<void(const ClickInfo&)>::GetInstance().GetAvailableMarker();
154 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
155 clickMarkerId_, [weak = WeakClaim(this), idNode](const ClickInfo& clickInfo) {
156 auto domMenu = weak.Upgrade();
157 if (!domMenu || !idNode) {
158 return;
159 }
160 const auto& targetCallback = domMenu->menuChild_->GetTargetCallback();
161 const auto& targetId = idNode->GetRootComponent()->GetId();
162 if (targetCallback) {
163 targetCallback(targetId, clickInfo.GetGlobalLocation());
164 }
165 });
166 idNode->SetOnClick(clickMarkerId_);
167 } else {
168 longPressMarkerId_ =
169 BackEndEventManager<void(const LongPressInfo&)>::GetInstance().GetAvailableMarker();
170 BackEndEventManager<void(const LongPressInfo&)>::GetInstance().BindBackendEvent(
171 longPressMarkerId_, [weak = WeakClaim(this), idNode](const LongPressInfo& longPressInfo) {
172 auto domMenu = weak.Upgrade();
173 if (!domMenu || !idNode) {
174 return;
175 }
176 const auto& targetCallback = domMenu->menuChild_->GetTargetCallback();
177 const auto& targetId = idNode->GetRootComponent()->GetId();
178 if (targetCallback) {
179 targetCallback(targetId, longPressInfo.GetGlobalLocation());
180 }
181 });
182 idNode->SetOnLongPress(longPressMarkerId_);
183 }
184 }
185
GetJsonDouble(const std::unique_ptr<JsonValue> & json,const std::string & name,double defaultValue) const186 double DOMMenu::GetJsonDouble(
187 const std::unique_ptr<JsonValue>& json, const std::string& name, double defaultValue) const
188 {
189 if (json && json->IsArray() && json->GetArraySize() > 0) {
190 std::unique_ptr<JsonValue> itemValue = json->GetArrayItem(0)->GetValue(name);
191 if (itemValue && itemValue->IsNumber()) {
192 return itemValue->GetDouble();
193 }
194 }
195
196 return defaultValue;
197 }
198
CallSpecializedMethod(const std::string & method,const std::string & args)199 void DOMMenu::CallSpecializedMethod(const std::string& method, const std::string& args)
200 {
201 if (method == "show") {
202 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
203 double x = GetJsonDouble(argsValue, "x", 0);
204 double y = GetJsonDouble(argsValue, "y", 0);
205 const auto& targetCallback = menuChild_->GetTargetCallback();
206 if (targetCallback) {
207 targetCallback("", Offset(x, y));
208 }
209 }
210 }
211
OnChildNodeAdded(const RefPtr<DOMNode> & child,int32_t slot)212 void DOMMenu::OnChildNodeAdded(const RefPtr<DOMNode>& child, int32_t slot)
213 {
214 if (!child) {
215 return;
216 }
217
218 auto option = AceType::DynamicCast<OptionComponent>(child->GetSpecializedComponent());
219 if (!option) {
220 return;
221 }
222
223 if (slot < 0) {
224 menuChild_->AppendOption(option);
225 } else {
226 menuChild_->InsertOption(option, static_cast<uint32_t>(slot));
227 }
228 }
229
230 } // namespace OHOS::Ace::Framework
231