• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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