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 menuPattern->HideMenu();
161 }
162
PlayBgColorAnimation(bool isHoverChange)163 void OptionPattern::PlayBgColorAnimation(bool isHoverChange)
164 {
165 AnimationOption option = AnimationOption();
166 if (isHoverChange) {
167 option.SetDuration(selectTheme_->GetHoverAnimationDuration());
168 option.SetCurve(Curves::FRICTION);
169 } else {
170 option.SetDuration(selectTheme_->GetPressAnimationDuration());
171 option.SetCurve(Curves::SHARP);
172 }
173
174 AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
175 auto pattern = weak.Upgrade();
176 CHECK_NULL_VOID(pattern);
177 auto host = pattern->GetHost();
178 CHECK_NULL_VOID(host);
179 auto renderContext = host->GetRenderContext();
180 CHECK_NULL_VOID(renderContext);
181 renderContext->BlendBgColor(pattern->GetBgBlendColor());
182 });
183 }
184
RegisterOnClick()185 void OptionPattern::RegisterOnClick()
186 {
187 auto host = GetHost();
188 CHECK_NULL_VOID(host);
189 auto hub = host->GetEventHub<OptionEventHub>();
190
191 auto event = [weak = WeakClaim(this)](GestureEvent& /* info */) {
192 auto pattern = weak.Upgrade();
193 CHECK_NULL_VOID(pattern);
194 pattern->OnSelectProcess();
195 };
196 auto clickEvent = MakeRefPtr<ClickEvent>(std::move(event));
197
198 auto gestureHub = host->GetOrCreateGestureEventHub();
199 CHECK_NULL_VOID(gestureHub);
200 gestureHub->AddClickEvent(clickEvent);
201 }
202
RegisterOnTouch()203 void OptionPattern::RegisterOnTouch()
204 {
205 auto host = GetHost();
206 CHECK_NULL_VOID(host);
207 auto gestureHub = host->GetOrCreateGestureEventHub();
208 CHECK_NULL_VOID(gestureHub);
209
210 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
211 auto pattern = weak.Upgrade();
212 CHECK_NULL_VOID(pattern);
213 pattern->OnPress(info);
214 };
215 auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
216 gestureHub->AddTouchEvent(touchEvent);
217 }
218
RegisterOnHover()219 void OptionPattern::RegisterOnHover()
220 {
221 auto host = GetHost();
222 CHECK_NULL_VOID(host);
223 auto inputHub = host->GetOrCreateInputEventHub();
224 CHECK_NULL_VOID(inputHub);
225 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
226 auto pattern = weak.Upgrade();
227 CHECK_NULL_VOID(pattern);
228 pattern->OnHover(isHover);
229 };
230 auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
231 inputHub->AddOnHoverEvent(mouseEvent);
232 }
233
RegisterOnKeyEvent()234 void OptionPattern::RegisterOnKeyEvent()
235 {
236 auto host = GetHost();
237 CHECK_NULL_VOID(host);
238 auto focusHub = host->GetOrCreateFocusHub();
239 CHECK_NULL_VOID(focusHub);
240 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
241 auto pattern = wp.Upgrade();
242 CHECK_NULL_RETURN(pattern, false);
243 return pattern->OnKeyEvent(event);
244 };
245 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
246 }
247
OnKeyEvent(const KeyEvent & event)248 bool OptionPattern::OnKeyEvent(const KeyEvent& event)
249 {
250 if (event.action != KeyAction::DOWN) {
251 return false;
252 }
253 if (event.code == KeyCode::KEY_ENTER) {
254 OnSelectProcess();
255 return true;
256 }
257 if ((event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) && IsSelectOption()) {
258 return UpdateOptionFocus(event.code);
259 }
260 return false;
261 }
262
UpdateOptionFocus(KeyCode code)263 bool OptionPattern::UpdateOptionFocus(KeyCode code)
264 {
265 auto meunNode = GetMenu().Upgrade();
266 CHECK_NULL_RETURN(meunNode, false);
267 auto menuPattern = meunNode->GetPattern<MenuPattern>();
268 CHECK_NULL_RETURN(menuPattern, false);
269 auto options = menuPattern->GetOptions();
270 if (!options.empty()) {
271 auto optionNode = (code == KeyCode::KEY_MOVE_HOME) ? options.front() : options.back();
272 auto eventHub = optionNode->GetOrCreateFocusHub();
273 eventHub->RequestFocusImmediately();
274 return true;
275 }
276 return false;
277 }
278
OnPress(const TouchEventInfo & info)279 void OptionPattern::OnPress(const TouchEventInfo& info)
280 {
281 auto host = GetHost();
282 CHECK_NULL_VOID(host);
283 const auto& renderContext = host->GetRenderContext();
284 CHECK_NULL_VOID(renderContext);
285 auto props = GetPaintProperty<OptionPaintProperty>();
286 CHECK_NULL_VOID(props);
287 auto touchType = info.GetTouches().front().GetTouchType();
288
289 auto pipeline = PipelineBase::GetCurrentContext();
290 CHECK_NULL_VOID(pipeline);
291 auto theme = pipeline->GetTheme<SelectTheme>();
292 // enter press status
293 if (touchType == TouchType::DOWN) {
294 // change background color, update press status
295 SetBgBlendColor(theme->GetClickedColor());
296 PlayBgColorAnimation(false);
297
298 props->UpdatePress(true);
299 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
300 // disable next option node's divider
301 UpdateNextNodeDivider(false);
302 } else if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
303 // leave press status
304 if (IsHover()) {
305 SetBgBlendColor(theme->GetHoverColor());
306 } else {
307 SetBgBlendColor(Color::TRANSPARENT);
308 }
309 PlayBgColorAnimation(false);
310
311 props->UpdatePress(false);
312 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
313 UpdateNextNodeDivider(true);
314 }
315 }
316
OnHover(bool isHover)317 void OptionPattern::OnHover(bool isHover)
318 {
319 SetIsHover(isHover);
320
321 auto host = GetHost();
322 CHECK_NULL_VOID(host);
323 auto renderContext = host->GetRenderContext();
324 CHECK_NULL_VOID(renderContext);
325 auto props = GetPaintProperty<OptionPaintProperty>();
326 CHECK_NULL_VOID(props);
327 if (isHover) {
328 auto pipeline = PipelineContext::GetCurrentContext();
329 CHECK_NULL_VOID(pipeline);
330 auto theme = pipeline->GetTheme<SelectTheme>();
331 auto hoverColor = theme->GetHoverColor();
332 SetBgBlendColor(hoverColor);
333
334 props->UpdateHover(true);
335 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
336 UpdateNextNodeDivider(false);
337 } else {
338 SetBgBlendColor(Color::TRANSPARENT);
339
340 props->UpdateHover(false);
341 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
342 UpdateNextNodeDivider(true);
343 }
344 PlayBgColorAnimation();
345 }
346
UpdateNextNodeDivider(bool needDivider)347 void OptionPattern::UpdateNextNodeDivider(bool needDivider)
348 {
349 auto host = GetHost();
350 // find next option node from parent menuNode
351 CHECK_NULL_VOID(host);
352 auto parent = host->GetParent();
353 CHECK_NULL_VOID(parent);
354 auto nextNode = parent->GetChildAtIndex(index_ + 1);
355 if (nextNode) {
356 if (!InstanceOf<FrameNode>(nextNode)) {
357 LOGW("next optionNode is not a frameNode! type = %{public}s", nextNode->GetTag().c_str());
358 return;
359 }
360 auto props = DynamicCast<FrameNode>(nextNode)->GetPaintProperty<OptionPaintProperty>();
361 CHECK_NULL_VOID(props);
362 props->UpdateNeedDivider(needDivider);
363 nextNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
364 }
365 }
366
SetBgColor(const Color & color)367 void OptionPattern::SetBgColor(const Color& color)
368 {
369 auto renderContext = GetHost()->GetRenderContext();
370 CHECK_NULL_VOID(renderContext);
371 renderContext->UpdateBackgroundColor(color);
372 bgColor_ = color;
373 }
374
SetFontSize(const Dimension & value)375 void OptionPattern::SetFontSize(const Dimension& value)
376 {
377 CHECK_NULL_VOID(text_);
378 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
379 CHECK_NULL_VOID(props);
380 text_->MarkModifyDone();
381 CHECK_NULL_VOID(selectTheme_);
382 props->UpdateFontSize(value.IsNegative() ? selectTheme_->GetMenuFontSize() : value);
383 }
384
SetItalicFontStyle(const Ace::FontStyle & value)385 void OptionPattern::SetItalicFontStyle(const Ace::FontStyle& value)
386 {
387 CHECK_NULL_VOID(text_);
388 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
389 CHECK_NULL_VOID(props);
390 text_->MarkModifyDone();
391 props->UpdateItalicFontStyle(value);
392 }
393
SetFontWeight(const FontWeight & value)394 void OptionPattern::SetFontWeight(const FontWeight& value)
395 {
396 CHECK_NULL_VOID(text_);
397 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
398 CHECK_NULL_VOID(props);
399 text_->MarkModifyDone();
400 props->UpdateFontWeight(value);
401 }
402
SetFontFamily(const std::vector<std::string> & value)403 void OptionPattern::SetFontFamily(const std::vector<std::string>& value)
404 {
405 CHECK_NULL_VOID(text_);
406 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
407 CHECK_NULL_VOID(props);
408 text_->MarkModifyDone();
409 props->UpdateFontFamily(value);
410 }
411
SetFontColor(const Color & color)412 void OptionPattern::SetFontColor(const Color& color)
413 {
414 CHECK_NULL_VOID(text_);
415 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
416 CHECK_NULL_VOID(props);
417 text_->MarkModifyDone();
418 props->UpdateTextColor(color);
419 auto context = text_->GetRenderContext();
420 CHECK_NULL_VOID(context);
421 context->UpdateForegroundColor(color);
422 context->UpdateForegroundColorFlag(false);
423 context->ResetForegroundColorStrategy();
424 }
425
InspectorGetFont()426 std::string OptionPattern::InspectorGetFont()
427 {
428 CHECK_NULL_RETURN(text_, "");
429 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
430 CHECK_NULL_RETURN(props, "");
431 return props->InspectorGetTextFont();
432 }
433
GetBgColor()434 Color OptionPattern::GetBgColor()
435 {
436 auto pipeline = PipelineContext::GetCurrentContext();
437 CHECK_NULL_RETURN(pipeline, Color());
438 auto theme = pipeline->GetTheme<SelectTheme>();
439 CHECK_NULL_RETURN(theme, Color());
440 auto bgColor = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) ? Color::TRANSPARENT
441 : theme->GetBackgroundColor();
442 return bgColor_.value_or(bgColor);
443 }
444
GetFontSize()445 Dimension OptionPattern::GetFontSize()
446 {
447 CHECK_NULL_RETURN(text_, Dimension());
448 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
449 CHECK_NULL_RETURN(props, Dimension());
450 CHECK_NULL_RETURN(selectTheme_, Dimension());
451 auto defaultSize = selectTheme_->GetMenuFontSize();
452 return props->GetFontSizeValue(defaultSize);
453 }
454
GetItalicFontStyle()455 Ace::FontStyle OptionPattern::GetItalicFontStyle()
456 {
457 CHECK_NULL_RETURN(text_, Ace::FontStyle());
458 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
459 CHECK_NULL_RETURN(props, Ace::FontStyle());
460 auto defaultStyle = textTheme_->GetTextStyle().GetFontStyle();
461 return props->GetItalicFontStyleValue(defaultStyle);
462 }
463
GetFontWeight()464 FontWeight OptionPattern::GetFontWeight()
465 {
466 CHECK_NULL_RETURN(text_, FontWeight());
467 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
468 CHECK_NULL_RETURN(props, FontWeight());
469 auto defaultWeight = textTheme_->GetTextStyle().GetFontWeight();
470 return props->GetFontWeightValue(defaultWeight);
471 }
472
GetFontFamily()473 std::vector<std::string> OptionPattern::GetFontFamily()
474 {
475 CHECK_NULL_RETURN(text_, std::vector<std::string>());
476 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
477 CHECK_NULL_RETURN(props, std::vector<std::string>());
478 auto defaultFamily = textTheme_->GetTextStyle().GetFontFamilies();
479 return props->GetFontFamilyValue(defaultFamily);
480 }
481
GetFontColor()482 Color OptionPattern::GetFontColor()
483 {
484 CHECK_NULL_RETURN(text_, Color::TRANSPARENT);
485 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
486 CHECK_NULL_RETURN(props, Color::TRANSPARENT);
487 auto defaultColor = selectTheme_->GetMenuFontColor();
488 return props->GetTextColorValue(defaultColor);
489 }
490
GetText()491 std::string OptionPattern::GetText()
492 {
493 CHECK_NULL_RETURN(text_, std::string());
494 auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
495 CHECK_NULL_RETURN(textProps, std::string());
496 return textProps->GetContentValue();
497 }
498
UpdateText(const std::string & content)499 void OptionPattern::UpdateText(const std::string& content)
500 {
501 CHECK_NULL_VOID(text_);
502 auto props = text_->GetLayoutProperty<TextLayoutProperty>();
503 CHECK_NULL_VOID(props);
504 props->UpdateContent(content);
505 text_->MarkModifyDone();
506 text_->MarkDirtyNode();
507 }
508
UpdateIcon(const std::string & src,const std::function<void (WeakPtr<NG::FrameNode>)> symbolIcon)509 void OptionPattern::UpdateIcon(const std::string& src, const std::function<void(WeakPtr<NG::FrameNode>)> symbolIcon)
510 {
511 iconSrc_ = src;
512 auto host = GetHost();
513 CHECK_NULL_VOID(host);
514 RefPtr<FrameNode> row =
515 host->GetChildAtIndex(0) ? AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(0)) : nullptr;
516 CHECK_NULL_VOID(row);
517 if (symbolIcon && (!icon_ || icon_->GetTag() != V2::SYMBOL_ETS_TAG)) {
518 icon_ = OptionView::CreateSymbol(symbolIcon, row, icon_);
519 row->MarkModifyDone();
520 row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
521 return;
522 } else if (symbolIcon == nullptr && !src.empty() && (!icon_ || icon_->GetTag() != V2::IMAGE_ETS_TAG)) {
523 icon_ = OptionView::CreateIcon(src, row, icon_);
524 row->MarkModifyDone();
525 row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
526 return;
527 } else if (icon_) {
528 if (symbolIcon != nullptr) {
529 symbolIcon(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(icon_)));
530 icon_->MarkModifyDone();
531 icon_->MarkDirtyNode();
532 return;
533 } else if (!src.empty()) {
534 auto props = icon_->GetLayoutProperty<ImageLayoutProperty>();
535 CHECK_NULL_VOID(props);
536 auto imageSrcInfo = props->GetImageSourceInfo();
537 CHECK_NULL_VOID(imageSrcInfo);
538 imageSrcInfo->SetSrc(src);
539 props->UpdateImageSourceInfo(imageSrcInfo.value());
540 icon_->MarkModifyDone();
541 icon_->MarkDirtyNode();
542 return;
543 }
544 }
545
546 row->RemoveChild(icon_); // it's safe even if icon_ is nullptr
547 row->MarkModifyDone();
548 row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
549 icon_ = nullptr;
550 }
551
SetAccessibilityAction()552 void OptionPattern::SetAccessibilityAction()
553 {
554 auto host = GetHost();
555 CHECK_NULL_VOID(host);
556 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
557 CHECK_NULL_VOID(accessibilityProperty);
558 accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
559 const auto& pattern = weakPtr.Upgrade();
560 CHECK_NULL_VOID(pattern);
561 pattern->OnSelectProcess();
562 });
563 }
564
GetSelectOptionWidth()565 float OptionPattern::GetSelectOptionWidth()
566 {
567 RefPtr<GridColumnInfo> columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::MENU);
568 auto parent = columnInfo->GetParent();
569 CHECK_NULL_RETURN(parent, MIN_OPTION_WIDTH.ConvertToPx());
570 parent->BuildColumnWidth();
571 auto defaultWidth = static_cast<float>(columnInfo->GetWidth(COLUMN_NUM)) - OPTION_MARGIN.ConvertToPx();
572 auto optionNode = GetHost();
573 CHECK_NULL_RETURN(optionNode, MIN_OPTION_WIDTH.ConvertToPx());
574 float finalWidth = MIN_OPTION_WIDTH.ConvertToPx();
575
576 if (IsWidthModifiedBySelect()) {
577 auto optionPatintProperty = optionNode->GetPaintProperty<OptionPaintProperty>();
578 CHECK_NULL_RETURN(optionPatintProperty, MIN_OPTION_WIDTH.ConvertToPx());
579 auto selectmodifiedwidth = optionPatintProperty->GetSelectModifiedWidth();
580 finalWidth = selectmodifiedwidth.value();
581 } else {
582 finalWidth = defaultWidth;
583 }
584
585 if (finalWidth < MIN_OPTION_WIDTH.ConvertToPx()) {
586 finalWidth = defaultWidth;
587 }
588
589 return finalWidth;
590 }
591 } // namespace OHOS::Ace::NG
592