1 /*
2 * Copyright (c) 2022-2023 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 #include "core/components_ng/pattern/option/option_view.h"
16
17 #include "base/geometry/dimension.h"
18 #include "base/i18n/localization.h"
19 #include "base/memory/ace_type.h"
20 #include "base/memory/referenced.h"
21 #include "base/utils/utils.h"
22 #include "core/components/select/select_theme.h"
23 #include "core/components_ng/base/frame_node.h"
24 #include "core/components_ng/base/view_stack_processor.h"
25 #include "core/components_ng/pattern/image/image_model_ng.h"
26 #include "core/components_ng/pattern/image/image_pattern.h"
27 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
28 #include "core/components_ng/pattern/option/option_event_hub.h"
29 #include "core/components_ng/pattern/option/option_pattern.h"
30 #include "core/components_ng/pattern/security_component/paste_button/paste_button_common.h"
31 #include "core/components_ng/pattern/security_component/paste_button/paste_button_model_ng.h"
32 #include "core/components_ng/pattern/security_component/security_component_pattern.h"
33 #include "core/components_ng/pattern/text/text_pattern.h"
34 #include "core/components_v2/inspector/inspector_constants.h"
35 #include "core/image/image_source_info.h"
36
37 namespace OHOS::Ace::NG {
38
39 namespace {
40
Create(int32_t index)41 RefPtr<FrameNode> Create(int32_t index)
42 {
43 auto Id = ElementRegister::GetInstance()->MakeUniqueId();
44 ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::OPTION_ETS_TAG, Id);
45 auto node = FrameNode::CreateFrameNode(V2::OPTION_ETS_TAG, Id, AceType::MakeRefPtr<OptionPattern>(index));
46
47 // set border radius
48 auto renderContext = node->GetRenderContext();
49 CHECK_NULL_RETURN(renderContext, nullptr);
50 auto pipeline = PipelineBase::GetCurrentContext();
51 CHECK_NULL_RETURN(pipeline, nullptr);
52 auto theme = pipeline->GetTheme<SelectTheme>();
53 CHECK_NULL_RETURN(theme, nullptr);
54 BorderRadiusProperty border;
55 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
56 border.SetRadius(theme->GetMenuDefaultInnerRadius());
57 } else {
58 border.SetRadius(theme->GetInnerBorderRadius());
59 }
60 renderContext->UpdateBorderRadius(border);
61
62 auto props = node->GetPaintProperty<OptionPaintProperty>();
63 CHECK_NULL_RETURN(props, nullptr);
64 props->UpdateHover(false);
65 props->UpdatePress(false);
66 return node;
67 }
68 } // namespace
69
CreateText(const std::string & value,const RefPtr<FrameNode> & parent)70 RefPtr<FrameNode> OptionView::CreateText(const std::string& value, const RefPtr<FrameNode>& parent)
71 {
72 // create child text node
73 auto textId = ElementRegister::GetInstance()->MakeUniqueId();
74 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, textId, AceType::MakeRefPtr<TextPattern>());
75 CHECK_NULL_RETURN(textNode, nullptr);
76
77 auto textProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
78 CHECK_NULL_RETURN(textProperty, nullptr);
79
80 auto pipeline = PipelineBase::GetCurrentContext();
81 CHECK_NULL_RETURN(pipeline, nullptr);
82 auto theme = pipeline->GetTheme<SelectTheme>();
83 CHECK_NULL_RETURN(theme, nullptr);
84
85 textProperty->UpdateMaxLines(1);
86 textProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
87 textProperty->UpdateFontSize(theme->GetMenuFontSize());
88 textProperty->UpdateFontWeight(FontWeight::REGULAR);
89 textProperty->UpdateTextColor(theme->GetMenuFontColor());
90 // set default foregroundColor
91 auto textRenderContext = textNode->GetRenderContext();
92 textRenderContext->UpdateForegroundColor(theme->GetMenuFontColor());
93 textProperty->UpdateContent(value);
94 textNode->MountToParent(parent);
95 textNode->MarkModifyDone();
96
97 return textNode;
98 }
99
CreateIcon(const std::string & icon,const RefPtr<FrameNode> & parent,const RefPtr<FrameNode> & child)100 RefPtr<FrameNode> OptionView::CreateIcon(const std::string& icon, const RefPtr<FrameNode>& parent,
101 const RefPtr<FrameNode>& child)
102 {
103 auto iconNode = FrameNode::CreateFrameNode(
104 V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
105 CHECK_NULL_RETURN(iconNode, nullptr);
106 auto props = iconNode->GetLayoutProperty<ImageLayoutProperty>();
107 auto pipeline = PipelineBase::GetCurrentContext();
108 CHECK_NULL_RETURN(pipeline, nullptr);
109 auto theme = pipeline->GetTheme<SelectTheme>();
110 CHECK_NULL_RETURN(theme, nullptr);
111 if (!icon.empty()) {
112 ImageSourceInfo info(icon);
113 props->UpdateImageSourceInfo(info);
114 }
115 props->UpdateUserDefinedIdealSize(
116 CalcSize(CalcLength(theme->GetIconSideLength()), CalcLength(theme->GetIconSideLength())));
117 props->UpdateAlignment(Alignment::CENTER_LEFT);
118
119 if (child) {
120 parent->ReplaceChild(child, iconNode);
121 } else {
122 iconNode->MountToParent(parent, 0);
123 }
124 iconNode->MarkModifyDone();
125 return iconNode;
126 }
127
CreateSymbol(const std::function<void (WeakPtr<NG::FrameNode>)> & symbolApply,const RefPtr<FrameNode> & parent,const RefPtr<FrameNode> & child,const std::optional<Dimension> & symbolUserDefinedIdealFontSize)128 RefPtr<FrameNode> OptionView::CreateSymbol(const std::function<void(WeakPtr<NG::FrameNode>)>& symbolApply,
129 const RefPtr<FrameNode>& parent, const RefPtr<FrameNode>& child,
130 const std::optional<Dimension>& symbolUserDefinedIdealFontSize)
131 {
132 auto iconNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
133 []() { return AceType::MakeRefPtr<TextPattern>(); });
134 CHECK_NULL_RETURN(iconNode, nullptr);
135 auto props = iconNode->GetLayoutProperty<TextLayoutProperty>();
136 CHECK_NULL_RETURN(props, nullptr);
137 auto pipeline = PipelineBase::GetCurrentContext();
138 CHECK_NULL_RETURN(pipeline, nullptr);
139 auto theme = pipeline->GetTheme<SelectTheme>();
140 CHECK_NULL_RETURN(theme, nullptr);
141 props->UpdateFontSize(theme->GetEndIconWidth());
142 props->UpdateSymbolColorList({theme->GetMenuIconColor()});
143 props->UpdateAlignment(Alignment::CENTER_LEFT);
144 MarginProperty margin;
145 margin.right = CalcLength(theme->GetIconContentPadding());
146 props->UpdateMargin(margin);
147 if (symbolApply != nullptr) {
148 symbolApply(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(iconNode)));
149 }
150 if (symbolUserDefinedIdealFontSize.has_value()) {
151 props->UpdateFontSize(symbolUserDefinedIdealFontSize.value());
152 }
153 if (child) {
154 parent->ReplaceChild(child, iconNode);
155 } else {
156 iconNode->MountToParent(parent, 0);
157 }
158 iconNode->MarkModifyDone();
159 return iconNode;
160 }
161
CreatePasteButton(bool optionsHasIcon,const RefPtr<FrameNode> & option,const RefPtr<FrameNode> & row,const std::function<void ()> & onClickFunc,const std::string & icon)162 void OptionView::CreatePasteButton(bool optionsHasIcon, const RefPtr<FrameNode>& option, const RefPtr<FrameNode>& row,
163 const std::function<void()>& onClickFunc, const std::string& icon)
164 {
165 RefPtr<FrameNode> pasteNode;
166 if (optionsHasIcon) {
167 pasteNode =
168 PasteButtonModelNG::GetInstance()->CreateNode(static_cast<int32_t>(PasteButtonPasteDescription::PASTE),
169 static_cast<int32_t>(PasteButtonIconStyle::ICON_LINE), static_cast<int32_t>(ButtonType::NORMAL), true);
170 } else {
171 pasteNode =
172 PasteButtonModelNG::GetInstance()->CreateNode(static_cast<int32_t>(PasteButtonPasteDescription::PASTE),
173 static_cast<int32_t>(PasteButtonIconStyle::ICON_NULL), static_cast<int32_t>(ButtonType::NORMAL), true);
174 }
175 CHECK_NULL_VOID(pasteNode);
176 auto pattern = option->GetPattern<OptionPattern>();
177 CHECK_NULL_VOID(pattern);
178
179 auto pasteLayoutProperty = pasteNode->GetLayoutProperty<SecurityComponentLayoutProperty>();
180 CHECK_NULL_VOID(pasteLayoutProperty);
181 auto pastePaintProperty = pasteNode->GetPaintProperty<SecurityComponentPaintProperty>();
182 CHECK_NULL_VOID(pastePaintProperty);
183 auto pipeline = PipelineBase::GetCurrentContext();
184 CHECK_NULL_VOID(pipeline);
185 auto theme = pipeline->GetTheme<SelectTheme>();
186 CHECK_NULL_VOID(theme);
187
188 pasteLayoutProperty->UpdateFontSize(theme->GetMenuFontSize());
189 pasteLayoutProperty->UpdateFontWeight(FontWeight::REGULAR);
190 pastePaintProperty->UpdateFontColor(theme->GetMenuFontColor());
191 pastePaintProperty->UpdateBackgroundColor(Color::TRANSPARENT);
192 pasteLayoutProperty->UpdateBackgroundBorderRadius(theme->GetInnerBorderRadius());
193 pasteLayoutProperty->UpdateIconSize(theme->GetIconSideLength());
194 pastePaintProperty->UpdateIconColor(theme->GetMenuIconColor());
195 if (optionsHasIcon) {
196 pasteLayoutProperty->UpdateTextIconSpace(theme->GetIconContentPadding());
197 }
198 pasteNode->MountToParent(row);
199 pasteNode->MarkModifyDone();
200
201 row->MountToParent(option);
202 row->MarkModifyDone();
203 auto eventHub = option->GetEventHub<OptionEventHub>();
204 CHECK_NULL_VOID(eventHub);
205 pasteNode->GetOrCreateGestureEventHub()->SetUserOnClick([onClickFunc](GestureEvent& info) {
206 if (!PasteButtonModelNG::GetInstance()->IsClickResultSuccess(info)) {
207 return;
208 }
209 if (onClickFunc) {
210 onClickFunc();
211 }
212 });
213 pattern->SetPasteButton(pasteNode);
214 }
215
CreateOption(bool optionsHasIcon,std::vector<OptionParam> & params,int32_t index,const RefPtr<FrameNode> & row,const RefPtr<FrameNode> & option)216 void OptionView::CreateOption(bool optionsHasIcon, std::vector<OptionParam>& params, int32_t index,
217 const RefPtr<FrameNode>& row, const RefPtr<FrameNode>& option)
218 {
219 auto pattern = option->GetPattern<OptionPattern>();
220 CHECK_NULL_VOID(pattern);
221 if (optionsHasIcon) {
222 auto iconNode = CreateSymbol(params[index].symbol, row, nullptr, params[index].symbolUserDefinedIdealFontSize);
223 pattern->SetIconNode(iconNode);
224 }
225 auto textNode = CreateText(params[index].value, row);
226 row->MountToParent(option);
227 row->MarkModifyDone();
228 pattern->SetTextNode(textNode);
229
230 auto eventHub = option->GetEventHub<OptionEventHub>();
231 CHECK_NULL_VOID(eventHub);
232 eventHub->SetMenuOnClick(params[index].action);
233 }
234
CreateOption(bool optionsHasIcon,const std::string & value,const std::string & icon,const RefPtr<FrameNode> & row,const RefPtr<FrameNode> & option,const std::function<void ()> & onClickFunc)235 void OptionView::CreateOption(bool optionsHasIcon, const std::string& value, const std::string& icon,
236 const RefPtr<FrameNode>& row, const RefPtr<FrameNode>& option, const std::function<void()>& onClickFunc)
237 {
238 auto pattern = option->GetPattern<OptionPattern>();
239 CHECK_NULL_VOID(pattern);
240 if (optionsHasIcon) {
241 auto iconNode = CreateIcon(icon, row);
242 pattern->SetIconNode(iconNode);
243 pattern->SetIcon(icon);
244 }
245 auto textNode = CreateText(value, row);
246 row->MountToParent(option);
247 row->MarkModifyDone();
248 pattern->SetTextNode(textNode);
249
250 auto eventHub = option->GetEventHub<OptionEventHub>();
251 CHECK_NULL_VOID(eventHub);
252 eventHub->SetMenuOnClick(onClickFunc);
253 }
254
CreateMenuOption(bool optionsHasIcon,std::vector<OptionParam> & params,int32_t index)255 RefPtr<FrameNode> OptionView::CreateMenuOption(bool optionsHasIcon, std::vector<OptionParam>& params, int32_t index)
256 {
257 auto option = Create(index);
258 CHECK_NULL_RETURN(option, nullptr);
259 auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
260 AceType::MakeRefPtr<LinearLayoutPattern>(false));
261
262 #ifdef OHOS_PLATFORM
263 constexpr char BUTTON_PASTE[] = "textoverlay.paste";
264 if (params[index].value == Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE)) {
265 CreatePasteButton(optionsHasIcon, option, row, params[index].action);
266 } else {
267 CreateOption(optionsHasIcon, params, index, row, option);
268 }
269 #else
270 CreateOption(optionsHasIcon, params, index, row, option);
271 #endif
272 return option;
273 }
274
CreateMenuOption(bool optionsHasIcon,const OptionValueInfo & value,const std::function<void ()> & onClickFunc,int32_t index,const std::string & icon)275 RefPtr<FrameNode> OptionView::CreateMenuOption(bool optionsHasIcon, const OptionValueInfo& value,
276 const std::function<void()>& onClickFunc, int32_t index, const std::string& icon)
277 {
278 auto option = Create(index);
279 CHECK_NULL_RETURN(option, nullptr);
280 auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
281 AceType::MakeRefPtr<LinearLayoutPattern>(false));
282
283 #ifdef OHOS_PLATFORM
284 constexpr char BUTTON_PASTE[] = "textoverlay.paste";
285 if (value.value == Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE) || value.isPasteOption) {
286 CreatePasteButton(optionsHasIcon, option, row, onClickFunc, icon);
287 } else {
288 CreateOption(optionsHasIcon, value.value, icon, row, option, onClickFunc);
289 }
290 #else
291 CreateOption(optionsHasIcon, value.value, icon, row, option, onClickFunc);
292 #endif
293 return option;
294 }
295
CreateSelectOption(const SelectParam & param,int32_t index)296 RefPtr<FrameNode> OptionView::CreateSelectOption(const SelectParam& param, int32_t index)
297 {
298 LOGI("create option value = %s", param.text.c_str());
299 auto option = Create(index);
300 auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
301 AceType::MakeRefPtr<LinearLayoutPattern>(false));
302 row->MountToParent(option);
303
304 auto pattern = option->GetPattern<OptionPattern>();
305 CHECK_NULL_RETURN(pattern, option);
306 // create icon node
307 RefPtr<FrameNode> iconNode;
308 if (param.symbolIcon != nullptr) {
309 iconNode = CreateSymbol(param.symbolIcon, row);
310 } else if (!param.icon.empty()) {
311 iconNode = CreateIcon(param.icon, row);
312 pattern->SetIcon(param.icon);
313 }
314 pattern->SetIconNode(iconNode);
315
316 auto text = CreateText(param.text, row);
317 pattern->SetTextNode(text);
318 return option;
319 }
320
321 } // namespace OHOS::Ace::NG
322