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
16 #include "core/components_ng/pattern/option/option_pattern.h"
17
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "core/common/container.h"
21 #include "core/components/common/layout/grid_system_manager.h"
22 #include "core/components/select/select_theme.h"
23 #include "core/components_ng/base/ui_node.h"
24 #include "core/components_ng/pattern/image/image_pattern.h"
25 #include "core/components_ng/pattern/image/image_layout_property.h"
26 #include "core/components_ng/pattern/menu/menu_pattern.h"
27 #include "core/components_ng/pattern/option/option_paint_property.h"
28 #include "core/components_ng/pattern/option/option_view.h"
29 #include "core/components_ng/pattern/security_component/paste_button/paste_button_common.h"
30 #include "core/components_ng/pattern/security_component/paste_button/paste_button_model_ng.h"
31 #include "core/components_ng/pattern/security_component/security_component_pattern.h"
32 #include "core/components_ng/pattern/security_component/security_component_layout_property.h"
33 #include "core/components_ng/pattern/text/text_layout_property.h"
34 #include "core/components_ng/property/property.h"
35 #include "core/event/touch_event.h"
36 #include "core/pipeline/pipeline_base.h"
37 #include "core/pipeline_ng/pipeline_context.h"
38
39 namespace OHOS::Ace::NG {
40 namespace {
41 constexpr Dimension MIN_OPTION_WIDTH = 56.0_vp;
42 constexpr Dimension OPTION_MARGIN = 8.0_vp;
43 constexpr int32_t COLUMN_NUM = 2;
44 const std::string SYSTEM_RESOURCE_PREFIX = std::string("resource:///");
45 // id of system resource start from 0x07000000
46 constexpr uint64_t MIN_SYSTEM_RESOURCE_ID = 0x07000000;
47 // id of system resource end to 0x07FFFFFF
48 constexpr uint64_t MAX_SYSTEM_RESOURCE_ID = 0x07FFFFFF;
49 } // namespace
50
OnAttachToFrameNode()51 void OptionPattern::OnAttachToFrameNode()
52 {
53 RegisterOnKeyEvent();
54 RegisterOnClick();
55 RegisterOnTouch();
56 RegisterOnHover();
57 }
58
OnModifyDone()59 void OptionPattern::OnModifyDone()
60 {
61 Pattern::OnModifyDone();
62 auto context = PipelineBase::GetCurrentContext();
63 CHECK_NULL_VOID(context);
64 textTheme_ = context->GetTheme<TextTheme>();
65 CHECK_NULL_VOID(textTheme_);
66 selectTheme_ = context->GetTheme<SelectTheme>();
67 CHECK_NULL_VOID(selectTheme_);
68
69 auto host = GetHost();
70 CHECK_NULL_VOID(host);
71 auto eventHub = host->GetEventHub<OptionEventHub>();
72 CHECK_NULL_VOID(eventHub);
73 UpdateIconSrc();
74 if (!eventHub->IsEnabled()) {
75 UpdatePasteFontColor(selectTheme_->GetDisabledMenuFontColor());
76 CHECK_NULL_VOID(text_);
77 text_->GetRenderContext()->UpdateForegroundColor(selectTheme_->GetDisabledMenuFontColor());
78 auto textLayoutProperty = text_->GetLayoutProperty<TextLayoutProperty>();
79 CHECK_NULL_VOID(textLayoutProperty);
80 textLayoutProperty->UpdateTextColor(selectTheme_->GetDisabledMenuFontColor());
81 text_->MarkModifyDone();
82 if (icon_) {
83 icon_->GetRenderContext()->UpdateOpacity(selectTheme_->GetDisabledFontColorAlpha());
84 icon_->MarkModifyDone();
85 }
86 } else {
87 UpdatePasteFontColor(selectTheme_->GetMenuFontColor());
88 }
89 SetAccessibilityAction();
90 }
91
UseDefaultThemeIcon(const ImageSourceInfo & imageSourceInfo)92 bool OptionPattern::UseDefaultThemeIcon(const ImageSourceInfo& imageSourceInfo)
93 {
94 if (imageSourceInfo.IsSvg()) {
95 auto src = imageSourceInfo.GetSrc();
96 auto srcId = src.substr(SYSTEM_RESOURCE_PREFIX.size(),
97 src.substr(0, src.rfind(".svg")).size() - SYSTEM_RESOURCE_PREFIX.size());
98 if (srcId.find("public_") != std::string::npos) {
99 return true;
100 }
101 uint64_t parsedSrcId = StringUtils::StringToLongUint(srcId);
102 return (parsedSrcId != 0
103 && (parsedSrcId >= MIN_SYSTEM_RESOURCE_ID)
104 && (parsedSrcId <= MAX_SYSTEM_RESOURCE_ID));
105 }
106 return false;
107 }
108
UpdateIconSrc()109 void OptionPattern::UpdateIconSrc()
110 {
111 if (icon_ == nullptr || iconSrc_.empty()) {
112 return;
113 }
114 auto pipeline = PipelineBase::GetCurrentContext();
115 CHECK_NULL_VOID(pipeline);
116 auto selectTheme = pipeline->GetTheme<SelectTheme>();
117 CHECK_NULL_VOID(selectTheme);
118 ImageSourceInfo imageSourceInfo(iconSrc_);
119 bool useDefaultIcon = UseDefaultThemeIcon(imageSourceInfo);
120 if (useDefaultIcon) {
121 auto iconRenderProperty = icon_->GetPaintProperty<ImageRenderProperty>();
122 CHECK_NULL_VOID(iconRenderProperty);
123 iconRenderProperty->UpdateSvgFillColor(selectTheme->GetMenuIconColor());
124 }
125 }
126
UpdatePasteFontColor(const Color & fontColor)127 void OptionPattern::UpdatePasteFontColor(const Color& fontColor)
128 {
129 CHECK_NULL_VOID(pasteButton_);
130 auto property = pasteButton_->GetPaintProperty<SecurityComponentPaintProperty>();
131 CHECK_NULL_VOID(property);
132 property->UpdateFontColor(fontColor);
133 pasteButton_->MarkModifyDone();
134 }
135
OnSelectProcess()136 void OptionPattern::OnSelectProcess()
137 {
138 auto host = GetHost();
139 CHECK_NULL_VOID(host);
140 auto hub = host->GetEventHub<OptionEventHub>();
141 CHECK_NULL_VOID(hub);
142 auto JsAction = hub->GetJsCallback();
143 if (JsAction) {
144 JsAction();
145 }
146 auto onSelect = hub->GetOnSelect();
147 if (onSelect) {
148 onSelect(index_);
149 }
150 host->OnAccessibilityEvent(AccessibilityEventType::SELECTED);
151 // hide menu when option is clicked
152 auto pipeline = PipelineContext::GetCurrentContext();
153 CHECK_NULL_VOID(pipeline);
154 auto overlayManager = pipeline->GetOverlayManager();
155 CHECK_NULL_VOID(overlayManager);
156 auto menu = GetMenu().Upgrade();
157 CHECK_NULL_VOID(menu);
158 auto menuPattern = menu->GetPattern<MenuPattern>();
159 CHECK_NULL_VOID(menuPattern);
160 if (!blockClick_) {
161 menuPattern->HideMenu();
162 }
163 }
164
PlayBgColorAnimation(bool isHoverChange)165 void OptionPattern::PlayBgColorAnimation(bool isHoverChange)
166 {
167 AnimationOption option = AnimationOption();
168 if (isHoverChange) {
169 option.SetDuration(selectTheme_->GetHoverAnimationDuration());
170 option.SetCurve(Curves::FRICTION);
171 } else {
172 option.SetDuration(selectTheme_->GetPressAnimationDuration());
173 option.SetCurve(Curves::SHARP);
174 }
175
176 AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
177 auto pattern = weak.Upgrade();
178 CHECK_NULL_VOID(pattern);
179 auto host = pattern->GetHost();
180 CHECK_NULL_VOID(host);
181 auto renderContext = host->GetRenderContext();
182 CHECK_NULL_VOID(renderContext);
183 renderContext->BlendBgColor(pattern->GetBgBlendColor());
184 });
185 }
186
RegisterOnClick()187 void OptionPattern::RegisterOnClick()
188 {
189 auto host = GetHost();
190 CHECK_NULL_VOID(host);
191 auto hub = host->GetEventHub<OptionEventHub>();
192
193 auto event = [weak = WeakClaim(this)](GestureEvent& /* info */) {
194 auto pattern = weak.Upgrade();
195 CHECK_NULL_VOID(pattern);
196 pattern->OnSelectProcess();
197 };
198 auto clickEvent = MakeRefPtr<ClickEvent>(std::move(event));
199
200 auto gestureHub = host->GetOrCreateGestureEventHub();
201 CHECK_NULL_VOID(gestureHub);
202 gestureHub->AddClickEvent(clickEvent);
203 }
204
RegisterOnTouch()205 void OptionPattern::RegisterOnTouch()
206 {
207 auto host = GetHost();
208 CHECK_NULL_VOID(host);
209 auto gestureHub = host->GetOrCreateGestureEventHub();
210 CHECK_NULL_VOID(gestureHub);
211
212 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
213 auto pattern = weak.Upgrade();
214 CHECK_NULL_VOID(pattern);
215 pattern->OnPress(info);
216 };
217 auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
218 gestureHub->AddTouchEvent(touchEvent);
219 }
220
RegisterOnHover()221 void OptionPattern::RegisterOnHover()
222 {
223 auto host = GetHost();
224 CHECK_NULL_VOID(host);
225 auto inputHub = host->GetOrCreateInputEventHub();
226 CHECK_NULL_VOID(inputHub);
227 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
228 auto pattern = weak.Upgrade();
229 CHECK_NULL_VOID(pattern);
230 pattern->OnHover(isHover);
231 };
232 auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
233 inputHub->AddOnHoverEvent(mouseEvent);
234 }
235
RegisterOnKeyEvent()236 void OptionPattern::RegisterOnKeyEvent()
237 {
238 auto host = GetHost();
239 CHECK_NULL_VOID(host);
240 auto focusHub = host->GetOrCreateFocusHub();
241 CHECK_NULL_VOID(focusHub);
242 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
243 auto pattern = wp.Upgrade();
244 CHECK_NULL_RETURN(pattern, false);
245 return pattern->OnKeyEvent(event);
246 };
247 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
248 }
249
OnKeyEvent(const KeyEvent & event)250 bool OptionPattern::OnKeyEvent(const KeyEvent& event)
251 {
252 if (event.action != KeyAction::DOWN) {
253 return false;
254 }
255 if (event.code == KeyCode::KEY_ENTER) {
256 OnSelectProcess();
257 return true;
258 }
259 if ((event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) && IsSelectOption()) {
260 return UpdateOptionFocus(event.code);
261 }
262 return false;
263 }
264
UpdateOptionFocus(KeyCode code)265 bool OptionPattern::UpdateOptionFocus(KeyCode code)
266 {
267 auto meunNode = GetMenu().Upgrade();
268 CHECK_NULL_RETURN(meunNode, false);
269 auto menuPattern = meunNode->GetPattern<MenuPattern>();
270 CHECK_NULL_RETURN(menuPattern, false);
271 auto options = menuPattern->GetOptions();
272 if (!options.empty()) {
273 auto optionNode = (code == KeyCode::KEY_MOVE_HOME) ? options.front() : options.back();
274 auto eventHub = optionNode->GetOrCreateFocusHub();
275 eventHub->RequestFocusImmediately();
276 return true;
277 }
278 return false;
279 }
280
OnPress(const TouchEventInfo & info)281 void OptionPattern::OnPress(const TouchEventInfo& info)
282 {
283 auto host = GetHost();
284 CHECK_NULL_VOID(host);
285 const auto& renderContext = host->GetRenderContext();
286 CHECK_NULL_VOID(renderContext);
287 auto props = GetPaintProperty<OptionPaintProperty>();
288 CHECK_NULL_VOID(props);
289 auto touchType = info.GetTouches().front().GetTouchType();
290
291 auto pipeline = PipelineBase::GetCurrentContext();
292 CHECK_NULL_VOID(pipeline);
293 auto theme = pipeline->GetTheme<SelectTheme>();
294 // enter press status
295 if (touchType == TouchType::DOWN) {
296 // change background color, update press status
297 SetBgBlendColor(theme->GetClickedColor());
298 PlayBgColorAnimation(false);
299
300 props->UpdatePress(true);
301 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
302 // disable next option node's divider
303 UpdateNextNodeDivider(false);
304 } else if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
305 // leave press status
306 if (IsHover()) {
307 SetBgBlendColor(theme->GetHoverColor());
308 } else {
309 SetBgBlendColor(Color::TRANSPARENT);
310 }
311 PlayBgColorAnimation(false);
312
313 props->UpdatePress(false);
314 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
315 UpdateNextNodeDivider(true);
316 }
317 }
318
OnHover(bool isHover)319 void OptionPattern::OnHover(bool isHover)
320 {
321 SetIsHover(isHover);
322
323 auto host = GetHost();
324 CHECK_NULL_VOID(host);
325 auto renderContext = host->GetRenderContext();
326 CHECK_NULL_VOID(renderContext);
327 auto props = GetPaintProperty<OptionPaintProperty>();
328 CHECK_NULL_VOID(props);
329 if (isHover) {
330 auto pipeline = PipelineContext::GetCurrentContext();
331 CHECK_NULL_VOID(pipeline);
332 auto theme = pipeline->GetTheme<SelectTheme>();
333 auto hoverColor = theme->GetHoverColor();
334 SetBgBlendColor(hoverColor);
335
336 props->UpdateHover(true);
337 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
338 UpdateNextNodeDivider(false);
339 } else {
340 SetBgBlendColor(Color::TRANSPARENT);
341
342 props->UpdateHover(false);
343 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
344 UpdateNextNodeDivider(true);
345 }
346 PlayBgColorAnimation();
347 }
348
UpdateNextNodeDivider(bool needDivider)349 void OptionPattern::UpdateNextNodeDivider(bool needDivider)
350 {
351 auto host = GetHost();
352 // find next option node from parent menuNode
353 CHECK_NULL_VOID(host);
354 auto parent = host->GetParent();
355 CHECK_NULL_VOID(parent);
356 auto nextNode = parent->GetChildAtIndex(index_ + 1);
357 if (nextNode) {
358 if (!InstanceOf<FrameNode>(nextNode)) {
359 LOGW("next optionNode is not a frameNode! type = %{public}s", nextNode->GetTag().c_str());
360 return;
361 }
362 auto props = DynamicCast<FrameNode>(nextNode)->GetPaintProperty<OptionPaintProperty>();
363 CHECK_NULL_VOID(props);
364 props->UpdateNeedDivider(needDivider);
365 nextNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
366 }
367 }
368
SetBgColor(const Color & color)369 void OptionPattern::SetBgColor(const Color& color)
370 {
371 auto renderContext = GetHost()->GetRenderContext();
372 CHECK_NULL_VOID(renderContext);
373 renderContext->UpdateBackgroundColor(color);
374 bgColor_ = color;
375 }
376
SetFontSize(const Dimension & value)377 void OptionPattern::SetFontSize(const Dimension& value)
378 {
379 CHECK_NULL_VOID(text_);
380 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
381 CHECK_NULL_VOID(props);
382 text_->MarkModifyDone();
383 CHECK_NULL_VOID(selectTheme_);
384 props->UpdateFontSize(value.IsNegative() ? selectTheme_->GetMenuFontSize() : value);
385 }
386
SetItalicFontStyle(const Ace::FontStyle & value)387 void OptionPattern::SetItalicFontStyle(const Ace::FontStyle& value)
388 {
389 CHECK_NULL_VOID(text_);
390 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
391 CHECK_NULL_VOID(props);
392 text_->MarkModifyDone();
393 props->UpdateItalicFontStyle(value);
394 }
395
SetFontWeight(const FontWeight & value)396 void OptionPattern::SetFontWeight(const FontWeight& value)
397 {
398 CHECK_NULL_VOID(text_);
399 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
400 CHECK_NULL_VOID(props);
401 text_->MarkModifyDone();
402 props->UpdateFontWeight(value);
403 }
404
SetFontFamily(const std::vector<std::string> & value)405 void OptionPattern::SetFontFamily(const std::vector<std::string>& value)
406 {
407 CHECK_NULL_VOID(text_);
408 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
409 CHECK_NULL_VOID(props);
410 text_->MarkModifyDone();
411 props->UpdateFontFamily(value);
412 }
413
SetFontColor(const Color & color)414 void OptionPattern::SetFontColor(const Color& color)
415 {
416 CHECK_NULL_VOID(text_);
417 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
418 CHECK_NULL_VOID(props);
419 text_->MarkModifyDone();
420 props->UpdateTextColor(color);
421 auto context = text_->GetRenderContext();
422 CHECK_NULL_VOID(context);
423 context->UpdateForegroundColor(color);
424 context->UpdateForegroundColorFlag(false);
425 context->ResetForegroundColorStrategy();
426 }
427
InspectorGetFont()428 std::string OptionPattern::InspectorGetFont()
429 {
430 CHECK_NULL_RETURN(text_, "");
431 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
432 CHECK_NULL_RETURN(props, "");
433 return props->InspectorGetTextFont();
434 }
435
GetBgColor()436 Color OptionPattern::GetBgColor()
437 {
438 auto pipeline = PipelineContext::GetCurrentContext();
439 CHECK_NULL_RETURN(pipeline, Color());
440 auto theme = pipeline->GetTheme<SelectTheme>();
441 CHECK_NULL_RETURN(theme, Color());
442 auto bgColor = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? Color::TRANSPARENT
443 : theme->GetBackgroundColor();
444 return bgColor_.value_or(bgColor);
445 }
446
GetFontSize()447 Dimension OptionPattern::GetFontSize()
448 {
449 CHECK_NULL_RETURN(text_, Dimension());
450 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
451 CHECK_NULL_RETURN(props, Dimension());
452 CHECK_NULL_RETURN(selectTheme_, Dimension());
453 auto defaultSize = selectTheme_->GetMenuFontSize();
454 return props->GetFontSizeValue(defaultSize);
455 }
456
GetItalicFontStyle()457 Ace::FontStyle OptionPattern::GetItalicFontStyle()
458 {
459 CHECK_NULL_RETURN(text_, Ace::FontStyle());
460 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
461 CHECK_NULL_RETURN(props, Ace::FontStyle());
462 auto defaultStyle = textTheme_->GetTextStyle().GetFontStyle();
463 return props->GetItalicFontStyleValue(defaultStyle);
464 }
465
GetFontWeight()466 FontWeight OptionPattern::GetFontWeight()
467 {
468 CHECK_NULL_RETURN(text_, FontWeight());
469 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
470 CHECK_NULL_RETURN(props, FontWeight());
471 auto defaultWeight = textTheme_->GetTextStyle().GetFontWeight();
472 return props->GetFontWeightValue(defaultWeight);
473 }
474
GetFontFamily()475 std::vector<std::string> OptionPattern::GetFontFamily()
476 {
477 CHECK_NULL_RETURN(text_, std::vector<std::string>());
478 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
479 CHECK_NULL_RETURN(props, std::vector<std::string>());
480 auto defaultFamily = textTheme_->GetTextStyle().GetFontFamilies();
481 return props->GetFontFamilyValue(defaultFamily);
482 }
483
GetFontColor()484 Color OptionPattern::GetFontColor()
485 {
486 CHECK_NULL_RETURN(text_, Color::TRANSPARENT);
487 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
488 CHECK_NULL_RETURN(props, Color::TRANSPARENT);
489 auto defaultColor = selectTheme_->GetMenuFontColor();
490 return props->GetTextColorValue(defaultColor);
491 }
492
GetText()493 std::string OptionPattern::GetText()
494 {
495 CHECK_NULL_RETURN(text_, std::string());
496 auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
497 CHECK_NULL_RETURN(textProps, std::string());
498 return textProps->GetContentValue();
499 }
500
UpdateText(const std::string & content)501 void OptionPattern::UpdateText(const std::string& content)
502 {
503 CHECK_NULL_VOID(text_);
504 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
505 CHECK_NULL_VOID(props);
506 props->UpdateContent(content);
507 text_->MarkModifyDone();
508 text_->MarkDirtyNode();
509 }
510
UpdateIcon(const std::string & src,const std::function<void (WeakPtr<NG::FrameNode>)> symbolIcon)511 void OptionPattern::UpdateIcon(const std::string& src, const std::function<void(WeakPtr<NG::FrameNode>)> symbolIcon)
512 {
513 iconSrc_ = src;
514 auto host = GetHost();
515 CHECK_NULL_VOID(host);
516 RefPtr<FrameNode> row =
517 host->GetChildAtIndex(0) ? AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(0)) : nullptr;
518 CHECK_NULL_VOID(row);
519 if (symbolIcon && (!icon_ || icon_->GetTag() != V2::SYMBOL_ETS_TAG)) {
520 icon_ = OptionView::CreateSymbol(symbolIcon, row, icon_);
521 row->MarkModifyDone();
522 row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
523 return;
524 } else if (symbolIcon == nullptr && !src.empty() && (!icon_ || icon_->GetTag() != V2::IMAGE_ETS_TAG)) {
525 icon_ = OptionView::CreateIcon(src, row, icon_);
526 row->MarkModifyDone();
527 row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
528 return;
529 } else if (icon_) {
530 if (symbolIcon != nullptr) {
531 symbolIcon(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(icon_)));
532 icon_->MarkModifyDone();
533 icon_->MarkDirtyNode();
534 return;
535 } else if (!src.empty()) {
536 auto props = icon_->GetLayoutProperty<ImageLayoutProperty>();
537 CHECK_NULL_VOID(props);
538 auto imageSrcInfo = props->GetImageSourceInfo();
539 CHECK_NULL_VOID(imageSrcInfo);
540 imageSrcInfo->SetSrc(src);
541 props->UpdateImageSourceInfo(imageSrcInfo.value());
542 icon_->MarkModifyDone();
543 icon_->MarkDirtyNode();
544 return;
545 }
546 }
547
548 row->RemoveChild(icon_); // it's safe even if icon_ is nullptr
549 row->MarkModifyDone();
550 row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
551 icon_ = nullptr;
552 }
553
SetAccessibilityAction()554 void OptionPattern::SetAccessibilityAction()
555 {
556 auto host = GetHost();
557 CHECK_NULL_VOID(host);
558 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
559 CHECK_NULL_VOID(accessibilityProperty);
560 accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
561 const auto& pattern = weakPtr.Upgrade();
562 CHECK_NULL_VOID(pattern);
563 pattern->OnSelectProcess();
564 });
565 }
566
GetSelectOptionWidth()567 float OptionPattern::GetSelectOptionWidth()
568 {
569 RefPtr<GridColumnInfo> columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::MENU);
570 auto parent = columnInfo->GetParent();
571 CHECK_NULL_RETURN(parent, MIN_OPTION_WIDTH.ConvertToPx());
572 parent->BuildColumnWidth();
573 auto defaultWidth = static_cast<float>(columnInfo->GetWidth(COLUMN_NUM)) - OPTION_MARGIN.ConvertToPx();
574 auto optionNode = GetHost();
575 CHECK_NULL_RETURN(optionNode, MIN_OPTION_WIDTH.ConvertToPx());
576 float finalWidth = MIN_OPTION_WIDTH.ConvertToPx();
577
578 if (IsWidthModifiedBySelect()) {
579 auto optionPatintProperty = optionNode->GetPaintProperty<OptionPaintProperty>();
580 CHECK_NULL_RETURN(optionPatintProperty, MIN_OPTION_WIDTH.ConvertToPx());
581 auto selectmodifiedwidth = optionPatintProperty->GetSelectModifiedWidth();
582 finalWidth = selectmodifiedwidth.value();
583 } else {
584 finalWidth = defaultWidth;
585 }
586
587 if (finalWidth < MIN_OPTION_WIDTH.ConvertToPx()) {
588 finalWidth = defaultWidth;
589 }
590
591 return finalWidth;
592 }
593 } // namespace OHOS::Ace::NG
594