• 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/select/select_pattern.h"
17 
18 #include <cstdint>
19 #include <optional>
20 
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/json/json_util.h"
24 #include "base/utils/system_properties.h"
25 #include "base/utils/utils.h"
26 #include "base/utils/utf_helper.h"
27 #include "core/animation/curves.h"
28 #include "core/common/recorder/event_recorder.h"
29 #include "core/common/recorder/node_data_cache.h"
30 #include "core/components/common/properties/color.h"
31 #include "core/components/common/properties/text_style.h"
32 #include "core/components/select/select_theme.h"
33 #include "core/components/theme/shadow_theme.h"
34 #include "core/components/theme/icon_theme.h"
35 #include "core/components_ng/base/frame_node.h"
36 #include "core/components_ng/base/inspector_filter.h"
37 #include "core/components_ng/base/view_abstract.h"
38 #include "core/components_ng/base/view_stack_processor.h"
39 #include "core/components_ng/pattern/image/image_pattern.h"
40 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
41 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
42 #include "core/components_ng/pattern/menu/menu_divider/menu_divider_pattern.h"
43 #include "core/components_ng/pattern/menu/menu_item/menu_item_pattern.h"
44 #include "core/components_ng/pattern/menu/menu_pattern.h"
45 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h"
46 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
47 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
48 #include "core/components_ng/pattern/select/select_event_hub.h"
49 #include "core/components_ng/pattern/select/select_paint_property.h"
50 #include "core/components_ng/pattern/select/select_properties.h"
51 #include "core/components_ng/pattern/text/text_layout_property.h"
52 #include "core/components_ng/pattern/text/text_pattern.h"
53 #include "core/components_ng/property/border_property.h"
54 #include "core/components_ng/property/measure_property.h"
55 #include "core/components_ng/property/measure_utils.h"
56 #include "core/components_ng/property/property.h"
57 #include "core/components_v2/inspector/inspector_constants.h"
58 #include "core/components_v2/inspector/utils.h"
59 
60 namespace OHOS::Ace::NG {
61 
62 namespace {
63 
64 constexpr uint32_t SELECT_ITSELF_TEXT_LINES = 1;
65 
66 constexpr Dimension OPTION_MARGIN = 8.0_vp;
67 
68 constexpr Dimension CALIBERATE_X = 4.0_vp;
69 
70 constexpr Dimension CALIBERATE_Y = 4.0_vp;
71 
72 constexpr Dimension SELECT_SMALL_PADDING_VP = 4.0_vp;
73 
74 constexpr Dimension SELECT_MARGIN_VP = 8.0_vp;
75 
ConvertControlSizeToString(ControlSize controlSize)76 static std::string ConvertControlSizeToString(ControlSize controlSize)
77 {
78     std::string result;
79     switch (controlSize) {
80         case ControlSize::SMALL:
81             result = "ControlSize.SMALL";
82             break;
83         case ControlSize::NORMAL:
84             result = "ControlSize.NORMAL";
85             break;
86         default:
87             break;
88     }
89     return result;
90 }
91 
RecordChange(RefPtr<FrameNode> host,int32_t index,const std::string & value)92 void RecordChange(RefPtr<FrameNode> host, int32_t index, const std::string& value)
93 {
94     if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
95         auto inspectorId = host->GetInspectorId().value_or("");
96         Recorder::EventParamsBuilder builder;
97         builder.SetId(inspectorId)
98             .SetType(host->GetTag())
99             .SetIndex(index)
100             .SetText(value)
101             .SetHost(host)
102             .SetDescription(host->GetAutoEventParamValue(""));
103         Recorder::EventRecorder::Get().OnChange(std::move(builder));
104         if (!inspectorId.empty()) {
105             Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, value, index);
106         }
107     }
108 }
109 } // namespace
110 
OnAttachToFrameNode()111 void SelectPattern::OnAttachToFrameNode()
112 {
113     RegisterOnKeyEvent();
114     RegisterOnClick();
115     RegisterOnPress();
116     RegisterOnHover();
117 }
118 
OnModifyDone()119 void SelectPattern::OnModifyDone()
120 {
121     Pattern::OnModifyDone();
122     CreateSelectedCallback();
123 
124     auto host = GetHost();
125     CHECK_NULL_VOID(host);
126     auto eventHub = host->GetEventHub<SelectEventHub>();
127     CHECK_NULL_VOID(eventHub);
128     if (!eventHub->IsEnabled()) {
129         SetDisabledStyle();
130     }
131     auto menu = GetMenuNode();
132     CHECK_NULL_VOID(menu);
133     auto menuPattern = menu->GetPattern<MenuPattern>();
134     CHECK_NULL_VOID(menuPattern);
135     menuPattern->UpdateSelectIndex(selected_);
136     InitFocusEvent();
137     auto renderContext = host->GetRenderContext();
138     CHECK_NULL_VOID(renderContext);
139     auto selectPaintProperty = host->GetPaintProperty<SelectPaintProperty>();
140     CHECK_NULL_VOID(selectPaintProperty);
141     if (selectPaintProperty->HasBackgroundColor()) {
142         return;
143     }
144     auto context = host->GetContextRefPtr();
145     CHECK_NULL_VOID(context);
146     auto theme = context->GetTheme<SelectTheme>(host->GetThemeScopeId());
147     CHECK_NULL_VOID(theme);
148     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
149         renderContext->UpdateBackgroundColor(theme->GetBackgroundColor());
150     } else {
151         renderContext->UpdateBackgroundColor(theme->GetButtonBackgroundColor());
152     }
153 }
154 
OnAfterModifyDone()155 void SelectPattern::OnAfterModifyDone()
156 {
157     auto host = GetHost();
158     CHECK_NULL_VOID(host);
159     auto inspectorId = host->GetInspectorId().value_or("");
160     if (inspectorId.empty()) {
161         return;
162     }
163     Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, selectValue_, selected_);
164 }
165 
SetItemSelected(int32_t index,const std::string & value)166 void SelectPattern::SetItemSelected(int32_t index, const std::string& value)
167 {
168     auto host = GetHost();
169     CHECK_NULL_VOID(host);
170     auto menu = GetMenuNode();
171     CHECK_NULL_VOID(menu);
172     auto menuPattern = menu->GetPattern<MenuPattern>();
173     CHECK_NULL_VOID(menuPattern);
174     isSelected_ = true;
175     menuPattern->UpdateSelectIndex(index);
176     CHECK_NULL_VOID(text_);
177     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
178     CHECK_NULL_VOID(textProps);
179     SetSelected(index);
180     textProps->UpdateContent(value);
181     text_->MarkModifyDone();
182     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
183     menuPattern->HideMenu();
184     auto hub = host->GetEventHub<SelectEventHub>();
185     CHECK_NULL_VOID(hub);
186 
187     auto onSelect = hub->GetSelectEvent();
188     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select choice index %{public}d", index);
189     if (onSelect) {
190         onSelect(index, value);
191     }
192     RecordChange(host, index, value);
193 }
194 
ShowSelectMenu()195 void SelectPattern::ShowSelectMenu()
196 {
197     CHECK_NULL_VOID(!options_.empty());
198     auto host = GetHost();
199     CHECK_NULL_VOID(host);
200     auto context = host->GetContext();
201     CHECK_NULL_VOID(context);
202     auto overlayManager = context->GetOverlayManager();
203     CHECK_NULL_VOID(overlayManager);
204     UpdateTargetSize();
205     auto offset = host->GetPaintRectOffset(false, true);
206     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
207         offset.AddY(selectSize_.Height() + CALIBERATE_Y.ConvertToPx());
208         offset.AddX(-CALIBERATE_X.ConvertToPx());
209     } else {
210         offset.AddY(selectSize_.Height());
211     }
212 
213     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "select click to show menu.");
214     overlayManager->ShowMenu(host->GetId(), offset, menuWrapper_);
215 }
216 
UpdateOptionsWidth(float selectWidth)217 void SelectPattern::UpdateOptionsWidth(float selectWidth)
218 {
219     for (size_t i = 0; i < options_.size(); ++i) {
220         auto optionNode = options_[i];
221         CHECK_NULL_VOID(optionNode);
222         auto optionGeoNode = optionNode->GetGeometryNode();
223         CHECK_NULL_VOID(optionGeoNode);
224         auto optionWidth = selectWidth - OPTION_MARGIN.ConvertToPx();
225         auto optionPattern = optionNode->GetPattern<MenuItemPattern>();
226         CHECK_NULL_VOID(optionPattern);
227         optionPattern->SetIsWidthModifiedBySelect(true);
228         auto optionPaintProperty = optionNode->GetPaintProperty<MenuItemPaintProperty>();
229         CHECK_NULL_VOID(optionPaintProperty);
230         optionPaintProperty->UpdateSelectModifiedWidth(optionWidth);
231         optionNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
232     }
233 }
234 
235 // add click event to show menu
RegisterOnClick()236 void SelectPattern::RegisterOnClick()
237 {
238     auto host = GetHost();
239     CHECK_NULL_VOID(host);
240 
241     GestureEventFunc callback = [weak = WeakClaim(this)](GestureEvent& /* info */) mutable {
242         auto pattern = weak.Upgrade();
243         CHECK_NULL_VOID(pattern);
244 
245         auto selected = pattern->GetSelected();
246         if (selected > -1 && selected < static_cast<int32_t>(pattern->GetOptions().size())) {
247             pattern->UpdateSelectedProps(selected);
248         }
249         pattern->ShowSelectMenu();
250     };
251     auto gestureHub = host->GetOrCreateGestureEventHub();
252     if (!gestureHub->GetTouchable()) {
253         return;
254     }
255     gestureHub->BindMenu(std::move(callback));
256 }
257 
PlayBgColorAnimation(bool isHoverChange)258 void SelectPattern::PlayBgColorAnimation(bool isHoverChange)
259 {
260     auto host = GetHost();
261     CHECK_NULL_VOID(host);
262     auto* pipeline = host->GetContextWithCheck();
263     CHECK_NULL_VOID(pipeline);
264     auto selectTheme = pipeline->GetTheme<SelectTheme>();
265     CHECK_NULL_VOID(selectTheme);
266 
267     AnimationOption option = AnimationOption();
268     if (isHoverChange) {
269         option.SetDuration(selectTheme->GetHoverAnimationDuration());
270         option.SetCurve(Curves::FRICTION);
271     } else {
272         option.SetDuration(selectTheme->GetPressAnimationDuration());
273         option.SetCurve(Curves::SHARP);
274     }
275 
276     AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
277         auto pattern = weak.Upgrade();
278         CHECK_NULL_VOID(pattern);
279         auto host = pattern->GetHost();
280         CHECK_NULL_VOID(host);
281         auto renderContext = host->GetRenderContext();
282         CHECK_NULL_VOID(renderContext);
283         renderContext->BlendBgColor(pattern->GetBgBlendColor());
284     });
285 }
286 
287 // change background color when hovered
RegisterOnHover()288 void SelectPattern::RegisterOnHover()
289 {
290     auto host = GetHost();
291     CHECK_NULL_VOID(host);
292     auto inputHub = host->GetOrCreateInputEventHub();
293     CHECK_NULL_VOID(inputHub);
294     auto mouseCallback = [weak = WeakClaim(this)](bool isHover) {
295         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select mouse hover %{public}d", isHover);
296         auto pattern = weak.Upgrade();
297         CHECK_NULL_VOID(pattern);
298         pattern->SetIsHover(isHover);
299         auto host = pattern->GetHost();
300         CHECK_NULL_VOID(host);
301         auto* pipeline = host->GetContextWithCheck();
302         CHECK_NULL_VOID(pipeline);
303         auto theme = pipeline->GetTheme<SelectTheme>();
304         CHECK_NULL_VOID(theme);
305         auto selectRenderContext = host->GetRenderContext();
306         CHECK_NULL_VOID(selectRenderContext);
307         // update hover status, repaint background color
308         if (isHover) {
309             float scaleHover = theme->GetSelectHoverOrFocusedScale();
310             VectorF scale(scaleHover, scaleHover);
311             auto&& transform = selectRenderContext->GetOrCreateTransform();
312             CHECK_NULL_VOID(transform);
313             if (!transform->HasTransformScale() || transform->GetTransformScale() == scale) {
314                 selectRenderContext->SetScale(scaleHover, scaleHover);
315             }
316             pattern->SetBgBlendColor(theme->GetHoverColor());
317         } else {
318             selectRenderContext->SetScale(1.0f, 1.0f);
319             pattern->SetBgBlendColor(Color::TRANSPARENT);
320         }
321         pattern->PlayBgColorAnimation();
322     };
323     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseCallback));
324     inputHub->AddOnHoverEvent(mouseEvent);
325 }
326 
327 // change background color when pressed
RegisterOnPress()328 void SelectPattern::RegisterOnPress()
329 {
330     auto host = GetHost();
331     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
332         if (info.GetTouches().empty()) {
333             return;
334         }
335         auto pattern = weak.Upgrade();
336         CHECK_NULL_VOID(pattern);
337         auto host = pattern->GetHost();
338         CHECK_NULL_VOID(host);
339         auto context = host->GetContextRefPtr();
340         CHECK_NULL_VOID(context);
341         auto theme = context->GetTheme<SelectTheme>();
342         CHECK_NULL_VOID(theme);
343         auto touchType = info.GetTouches().front().GetTouchType();
344         const auto& renderContext = host->GetRenderContext();
345         CHECK_NULL_VOID(renderContext);
346         // update press status, repaint background color
347         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select touch type %{public}zu", touchType);
348         if (touchType == TouchType::DOWN) {
349             pattern->SetBgBlendColor(theme->GetClickedColor());
350             pattern->PlayBgColorAnimation(false);
351         }
352         if (touchType == TouchType::UP) {
353             if (pattern->IsHover()) {
354                 pattern->SetBgBlendColor(theme->GetHoverColor());
355             } else {
356                 pattern->SetBgBlendColor(Color::TRANSPARENT);
357             }
358             pattern->PlayBgColorAnimation(false);
359         }
360     };
361     auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
362     auto gestureHub = host->GetOrCreateGestureEventHub();
363     gestureHub->AddTouchEvent(touchEvent);
364 }
365 
CreateSelectedCallback()366 void SelectPattern::CreateSelectedCallback()
367 {
368     auto host = GetHost();
369     CHECK_NULL_VOID(host);
370     auto callback = [weak = WeakClaim(RawPtr(host))](int32_t index) {
371         auto host = weak.Upgrade();
372         CHECK_NULL_VOID(host);
373         auto pattern = host->GetPattern<SelectPattern>();
374         CHECK_NULL_VOID(pattern);
375         pattern->SetSelected(index);
376         pattern->UpdateText(index);
377         pattern->isSelected_ = true;
378         auto hub = host->GetEventHub<SelectEventHub>();
379         CHECK_NULL_VOID(hub);
380         // execute change event callback
381         auto selectChangeEvent = hub->GetSelectChangeEvent();
382         if (selectChangeEvent) {
383             selectChangeEvent(index);
384         }
385         auto valueChangeEvent = hub->GetValueChangeEvent();
386         if (valueChangeEvent) {
387             auto newSelected = pattern->options_[index]->GetPattern<MenuItemPattern>();
388             CHECK_NULL_VOID(newSelected);
389             valueChangeEvent(newSelected->GetText());
390         }
391         // execute onSelect callback
392         auto newSelected = pattern->options_[index]->GetPattern<MenuItemPattern>();
393         CHECK_NULL_VOID(newSelected);
394         auto value = newSelected->GetText();
395         auto onSelect = hub->GetSelectEvent();
396         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select choice index %{public}d", index);
397         if (onSelect) {
398             onSelect(index, value);
399         }
400         RecordChange(host, index, value);
401     };
402     for (auto&& option : options_) {
403         auto hub = option->GetEventHub<MenuItemEventHub>();
404         // no std::move, need to set multiple options
405         hub->SetOnSelect(callback);
406         option->MarkModifyDone();
407     }
408 }
409 
InitFocusEvent()410 void SelectPattern::InitFocusEvent()
411 {
412     auto host = GetHost();
413     CHECK_NULL_VOID(host);
414     auto selectRenderContext = host->GetRenderContext();
415     CHECK_NULL_VOID(selectRenderContext);
416     auto pipeline = host->GetContext();
417     CHECK_NULL_VOID(pipeline);
418     auto selectTheme = pipeline->GetTheme<SelectTheme>();
419     CHECK_NULL_VOID(selectTheme);
420     auto isApplyFocusedStyle = selectTheme->GetoptionApplyFocusedStyle();
421     if (!isApplyFocusedStyle) {
422         return;
423     }
424     CHECK_NULL_VOID(!focusEventInitialized_);
425     auto focusHub = host->GetOrCreateFocusHub();
426     CHECK_NULL_VOID(focusHub);
427 
428     auto focusTask = [weak = WeakClaim(this)]() {
429         auto pattern = weak.Upgrade();
430         CHECK_NULL_VOID(pattern);
431         pattern->HandleFocusStyleTask();
432     };
433     focusHub->SetOnFocusInternal(focusTask);
434     auto blurTask = [weak = WeakClaim(this)]() {
435         auto pattern = weak.Upgrade();
436         CHECK_NULL_VOID(pattern);
437         pattern->HandleBlurStyleTask();
438     };
439     focusHub->SetOnBlurInternal(blurTask);
440     focusEventInitialized_ = true;
441 }
442 
HandleFocusStyleTask()443 void SelectPattern::HandleFocusStyleTask()
444 {
445     auto host = GetHost();
446     CHECK_NULL_VOID(host);
447     auto pipeline = host->GetContext();
448     CHECK_NULL_VOID(pipeline);
449     AddIsFocusActiveUpdateEvent();
450 
451     if (pipeline->GetIsFocusActive()) {
452         SetFocusStyle();
453     }
454 }
455 
HandleBlurStyleTask()456 void SelectPattern::HandleBlurStyleTask()
457 {
458     RemoveIsFocusActiveUpdateEvent();
459     ClearFocusStyle();
460 }
461 
SetFocusStyle()462 void SelectPattern::SetFocusStyle()
463 {
464     auto host = GetHost();
465     CHECK_NULL_VOID(host);
466     auto selectRenderContext = host->GetRenderContext();
467     CHECK_NULL_VOID(selectRenderContext);
468     auto pipeline = host->GetContext();
469     CHECK_NULL_VOID(pipeline);
470     auto selectTheme = pipeline->GetTheme<SelectTheme>(host->GetThemeScopeId());
471     CHECK_NULL_VOID(selectTheme);
472     auto&& graphics = selectRenderContext->GetOrCreateGraphics();
473     CHECK_NULL_VOID(graphics);
474     auto&& transform = selectRenderContext->GetOrCreateTransform();
475     CHECK_NULL_VOID(transform);
476 
477     ShadowStyle shadowStyle = selectTheme->GetSelectNormalShadow();
478     Shadow shadow;
479     GetShadowFromTheme(shadowStyle, shadow);
480     if (!graphics->HasBackShadow() || graphics->GetBackShadowValue() == shadow) {
481         shadowModify_ = true;
482         shadowStyle = selectTheme->GetSelectFocusedShadow();
483         GetShadowFromTheme(shadowStyle, shadow);
484         selectRenderContext->UpdateBackShadow(shadow);
485     }
486     float scaleFocus = selectTheme->GetSelectHoverOrFocusedScale();
487     VectorF scale(scaleFocus, scaleFocus);
488     if (!transform->HasTransformScale() || transform->GetTransformScale() == scale) {
489         scaleModify_ = true;
490         selectRenderContext->SetScale(scaleFocus, scaleFocus);
491     }
492     Color color = selectTheme->GetButtonBackgroundColor();
493     bgColorModify_ = selectRenderContext->GetBackgroundColor() == color;
494     if (bgColorModify_) {
495         selectRenderContext->UpdateBackgroundColor(selectTheme->GetSelectFocusedBackground());
496     }
497     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
498     CHECK_NULL_VOID(props);
499     focusTextColorModify_ = props->GetTextColor() == selectTheme->GetFontColor();
500     if (focusTextColorModify_) {
501         props->UpdateTextColor(selectTheme->GetSelectFocusTextColor());
502         auto textRenderContext = text_->GetRenderContext();
503         CHECK_NULL_VOID(textRenderContext);
504         textRenderContext->UpdateForegroundColor(selectTheme->GetSelectFocusTextColor());
505         text_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
506     }
507     ModFocusIconStyle(selectTheme, true);
508 }
509 
ClearFocusStyle()510 void SelectPattern::ClearFocusStyle()
511 {
512     auto host = GetHost();
513     CHECK_NULL_VOID(host);
514     auto selectRenderContext = host->GetRenderContext();
515     CHECK_NULL_VOID(selectRenderContext);
516     auto pipeline = host->GetContext();
517     CHECK_NULL_VOID(pipeline);
518     auto selectTheme = pipeline->GetTheme<SelectTheme>(host->GetThemeScopeId());
519     CHECK_NULL_VOID(selectTheme);
520 
521     if (shadowModify_) {
522         ShadowStyle shadowStyle = selectTheme->GetSelectNormalShadow();
523         Shadow shadow;
524         GetShadowFromTheme(shadowStyle, shadow);
525         selectRenderContext->UpdateBackShadow(shadow);
526         shadowModify_ = false;
527     }
528 
529     if (scaleModify_) {
530         scaleModify_ = false;
531         selectRenderContext->SetScale(1.0f, 1.0f);
532     }
533     if (bgColorModify_) {
534         bgColorModify_ = false;
535         Color color = selectTheme->GetButtonBackgroundColor();
536         selectRenderContext->UpdateBackgroundColor(color);
537     }
538     if (focusTextColorModify_) {
539         focusTextColorModify_ = false;
540         auto props = text_->GetLayoutProperty<TextLayoutProperty>();
541         CHECK_NULL_VOID(props);
542         props->UpdateTextColor(selectTheme->GetFontColor());
543         auto textRenderContext = text_->GetRenderContext();
544         CHECK_NULL_VOID(textRenderContext);
545         textRenderContext->UpdateForegroundColor(selectTheme->GetFontColor());
546         text_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
547     }
548     ModFocusIconStyle(selectTheme, false);
549 }
550 
ModFocusIconStyle(RefPtr<SelectTheme> selectTheme,bool focusedFlag)551 void SelectPattern::ModFocusIconStyle(RefPtr<SelectTheme> selectTheme, bool focusedFlag)
552 {
553     auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
554     CHECK_NULL_VOID(spinnerLayoutProperty);
555     focusedFlag ? spinnerLayoutProperty->UpdateSymbolColorList({selectTheme->GetSpinnerFocusedSymbolColor()}) :
556         spinnerLayoutProperty->UpdateSymbolColorList({selectTheme->GetSpinnerSymbolColor()});
557     spinner_->MarkDirtyNode();
558 }
559 
AddIsFocusActiveUpdateEvent()560 void SelectPattern::AddIsFocusActiveUpdateEvent()
561 {
562     if (!isFocusActiveUpdateEvent_) {
563         isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
564             auto selectPattern = weak.Upgrade();
565             CHECK_NULL_VOID(selectPattern);
566             isFocusAcitve ? selectPattern->SetFocusStyle() : selectPattern->ClearFocusStyle();
567         };
568     }
569 
570     auto pipline = PipelineContext::GetCurrentContext();
571     CHECK_NULL_VOID(pipline);
572     pipline->AddIsFocusActiveUpdateEvent(GetHost(), isFocusActiveUpdateEvent_);
573 }
574 
RemoveIsFocusActiveUpdateEvent()575 void SelectPattern::RemoveIsFocusActiveUpdateEvent()
576 {
577     auto pipline = PipelineContext::GetCurrentContext();
578     CHECK_NULL_VOID(pipline);
579     pipline->RemoveIsFocusActiveUpdateEvent(GetHost());
580 }
581 
RegisterOnKeyEvent()582 void SelectPattern::RegisterOnKeyEvent()
583 {
584     auto host = GetHost();
585     CHECK_NULL_VOID(host);
586     auto focusHub = host->GetOrCreateFocusHub();
587     CHECK_NULL_VOID(focusHub);
588     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
589         auto pattern = wp.Upgrade();
590         CHECK_NULL_RETURN(pattern, false);
591         return pattern->OnKeyEvent(event);
592     };
593     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
594 }
595 
OnKeyEvent(const KeyEvent & event)596 bool SelectPattern::OnKeyEvent(const KeyEvent& event)
597 {
598     if (event.action != KeyAction::DOWN) {
599         return false;
600     }
601     if (event.code == KeyCode::KEY_ENTER) {
602         auto host = GetHost();
603         CHECK_NULL_RETURN(host, false);
604         auto focusHub = host->GetOrCreateFocusHub();
605         CHECK_NULL_RETURN(focusHub, false);
606         focusHub->OnClick(event);
607         return true;
608     }
609     return false;
610 }
611 
SetDisabledStyle()612 void SelectPattern::SetDisabledStyle()
613 {
614     auto host = GetHost();
615     CHECK_NULL_VOID(host);
616     auto pipeline = host->GetContextWithCheck();
617     CHECK_NULL_VOID(pipeline);
618     auto theme = pipeline->GetTheme<SelectTheme>(host->GetThemeScopeId());
619     CHECK_NULL_VOID(theme);
620 
621     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
622     CHECK_NULL_VOID(textProps);
623     textProps->UpdateTextColor(theme->GetDisabledFontColor());
624     text_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
625 
626     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE) &&
627         SystemProperties::IsNeedSymbol()) {
628         auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
629         CHECK_NULL_VOID(spinnerLayoutProperty);
630         spinnerLayoutProperty->UpdateSymbolColorList({theme->GetDisabledSpinnerSymbolColor()});
631     } else {
632         auto spinnerLayoutProperty = spinner_->GetLayoutProperty<ImageLayoutProperty>();
633         CHECK_NULL_VOID(spinnerLayoutProperty);
634 
635         ImageSourceInfo imageSourceInfo = spinnerLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo());
636         auto iconTheme = pipeline->GetTheme<IconTheme>();
637         CHECK_NULL_VOID(iconTheme);
638         auto iconPath = iconTheme->GetIconPath(InternalResource::ResourceId::SPINNER_DISABLE);
639         imageSourceInfo.SetSrc(iconPath);
640         if (imageSourceInfo.IsSvg()) {
641             imageSourceInfo.SetFillColor(theme->GetDisabledSpinnerColor());
642         }
643         spinnerLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
644         auto spinnerRenderProperty = spinner_->GetPaintProperty<ImageRenderProperty>();
645         CHECK_NULL_VOID(spinnerRenderProperty);
646         spinnerRenderProperty->UpdateSvgFillColor(theme->GetDisabledSpinnerColor());
647     }
648     spinner_->MarkModifyDone();
649 
650     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
651         auto renderContext = host->GetRenderContext();
652         CHECK_NULL_VOID(renderContext);
653         renderContext->UpdateBackgroundColor(renderContext->GetBackgroundColor()
654                                                  .value_or(theme->GetButtonBackgroundColor())
655                                                  .BlendOpacity(theme->GetDisabledFontColorAlpha()));
656     }
657 }
658 
SetSelected(int32_t index)659 void SelectPattern::SetSelected(int32_t index)
660 {
661     // if option is already selected, do nothing
662     if (index == selected_) {
663         return;
664     }
665     if (index >= static_cast<int32_t>(options_.size()) || index < 0) {
666         selected_ = -1;
667         ResetOptionProps();
668         return;
669     }
670     UpdateLastSelectedProps(index);
671     selected_ = index;
672     for (size_t i = 0; i < options_.size(); ++i) {
673         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
674         if (pattern) {
675             pattern->SetSelected(selected_);
676         }
677     }
678 }
679 
AddOptionNode(const RefPtr<FrameNode> & option)680 void SelectPattern::AddOptionNode(const RefPtr<FrameNode>& option)
681 {
682     CHECK_NULL_VOID(option);
683     options_.push_back(option);
684 }
685 
BuildChild()686 void SelectPattern::BuildChild()
687 {
688     auto select = GetHost();
689     CHECK_NULL_VOID(select);
690     // get theme from SelectThemeManager
691     auto* pipeline = select->GetContextWithCheck();
692     CHECK_NULL_VOID(pipeline);
693     auto theme = pipeline->GetTheme<SelectTheme>();
694     CHECK_NULL_VOID(theme);
695 
696     bool hasRowNode = HasRowNode();
697     bool hasTextNode = HasTextNode();
698     bool hasSpinnerNode = HasSpinnerNode();
699     auto rowId = GetRowId();
700     auto textId = GetTextId();
701     auto spinnerId = GetSpinnerId();
702 
703     auto row = FrameNode::GetOrCreateFrameNode(
704         V2::ROW_ETS_TAG, rowId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
705     CHECK_NULL_VOID(row);
706     row->SetInternal();
707     auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
708     CHECK_NULL_VOID(rowProps);
709     rowProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
710     rowProps->UpdateCrossAxisAlign(FlexAlign::CENTER);
711     rowProps->UpdateFlexDirection(FlexDirection::ROW);
712     rowProps->UpdateSpace(theme->GetContentSpinnerPadding());
713     text_ =
714         FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG, textId, []() { return AceType::MakeRefPtr<TextPattern>(); });
715     CHECK_NULL_VOID(text_);
716     text_->SetInternal();
717     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
718     CHECK_NULL_VOID(textProps);
719     InitTextProps(textProps);
720     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE) &&
721         SystemProperties::IsNeedSymbol()) {
722         spinner_ = FrameNode::GetOrCreateFrameNode(
723             V2::SYMBOL_ETS_TAG, spinnerId, []() { return AceType::MakeRefPtr<TextPattern>(); });
724         CHECK_NULL_VOID(spinner_);
725         spinner_->SetInternal();
726         InitSpinner(spinner_, theme);
727     } else {
728         spinner_ = FrameNode::GetOrCreateFrameNode(
729             V2::IMAGE_ETS_TAG, spinnerId, []() { return AceType::MakeRefPtr<ImagePattern>(); });
730         CHECK_NULL_VOID(spinner_);
731         spinner_->SetInternal();
732         auto iconTheme = pipeline->GetTheme<IconTheme>();
733         CHECK_NULL_VOID(iconTheme);
734         InitSpinner(spinner_, iconTheme, theme);
735     }
736     // mount triangle and text
737     text_->MarkModifyDone();
738     if (!hasTextNode) {
739         text_->MountToParent(row);
740     }
741     spinner_->MarkModifyDone();
742     if (!hasSpinnerNode) {
743         spinner_->MountToParent(row);
744     }
745     if (!hasRowNode) {
746         row->MountToParent(select);
747     }
748     row->MarkModifyDone();
749     row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
750 
751     // set bgColor and border
752     auto renderContext = select->GetRenderContext();
753     CHECK_NULL_VOID(renderContext);
754     if (!renderContext->HasBorderColor()) {
755         BorderColorProperty borderColor;
756         borderColor.SetColor(theme->GetSelectNormalBorderColor());
757         renderContext->UpdateBorderColor(borderColor);
758     }
759     if (!renderContext->HasBorderWidth()) {
760         auto layoutProperty = select->GetLayoutProperty();
761         BorderWidthProperty borderWidth;
762         borderWidth.SetBorderWidth(theme->GetSelectNormalBorderWidth());
763         layoutProperty->UpdateBorderWidth(borderWidth);
764         renderContext->UpdateBorderWidth(borderWidth);
765     }
766     if (!renderContext->HasBackShadow()) {
767         ShadowStyle shadowStyle = theme->GetSelectNormalShadow();
768         Shadow shadow;
769         GetShadowFromTheme(shadowStyle, shadow);
770         renderContext->UpdateBackShadow(shadow);
771     }
772     renderContext->SetClipToFrame(true);
773     BorderRadiusProperty border;
774     border.SetRadius(theme->GetSelectBorderRadius());
775     renderContext->UpdateBorderRadius(border);
776 }
777 
SetValue(const std::string & value)778 void SelectPattern::SetValue(const std::string& value)
779 {
780     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
781     CHECK_NULL_VOID(props);
782     props->UpdateContent(value);
783     auto pattern = text_->GetPattern<TextPattern>();
784     CHECK_NULL_VOID(pattern);
785     auto modifier = pattern->GetContentModifier();
786     CHECK_NULL_VOID(modifier);
787     modifier->ContentChange();
788     selectValue_ = value;
789 }
790 
SetFontSize(const Dimension & value)791 void SelectPattern::SetFontSize(const Dimension& value)
792 {
793     if (value.IsNegative()) {
794         return;
795     }
796     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
797     CHECK_NULL_VOID(props);
798     props->UpdateFontSize(value);
799 }
800 
SetItalicFontStyle(const Ace::FontStyle & value)801 void SelectPattern::SetItalicFontStyle(const Ace::FontStyle& value)
802 {
803     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
804     CHECK_NULL_VOID(props);
805     props->UpdateItalicFontStyle(value);
806 }
807 
SetFontWeight(const FontWeight & value)808 void SelectPattern::SetFontWeight(const FontWeight& value)
809 {
810     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
811     CHECK_NULL_VOID(props);
812     props->UpdateFontWeight(value);
813 }
814 
SetFontFamily(const std::vector<std::string> & value)815 void SelectPattern::SetFontFamily(const std::vector<std::string>& value)
816 {
817     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
818     CHECK_NULL_VOID(props);
819     props->UpdateFontFamily(value);
820 }
821 
SetFontColor(const Color & color)822 void SelectPattern::SetFontColor(const Color& color)
823 {
824     fontColor_ = color;
825     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
826     CHECK_NULL_VOID(props);
827     props->UpdateTextColor(color);
828     auto context = text_->GetRenderContext();
829     context->UpdateForegroundColor(color);
830     context->UpdateForegroundColorFlag(false);
831     context->ResetForegroundColorStrategy();
832 }
833 
SetOptionBgColor(const Color & color)834 void SelectPattern::SetOptionBgColor(const Color& color)
835 {
836     optionBgColor_ = color;
837     for (size_t i = 0; i < options_.size(); ++i) {
838         if (static_cast<int32_t>(i) == selected_ && selectedBgColor_.has_value()) {
839             continue;
840         }
841         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
842         CHECK_NULL_VOID(pattern);
843         pattern->SetBgColor(color);
844         pattern->SetIsBGColorSetByUser(true);
845         pattern->SetOptionBgColor(color);
846         pattern->SetIsOptionBgColorSetByUser(true);
847     }
848 }
849 
SetOptionFontSize(const Dimension & value)850 void SelectPattern::SetOptionFontSize(const Dimension& value)
851 {
852     optionFont_.FontSize = value;
853     for (size_t i = 0; i < options_.size(); ++i) {
854         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontSize.has_value()) {
855             continue;
856         }
857         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
858         CHECK_NULL_VOID(pattern);
859         pattern->SetFontSize(value);
860     }
861 }
862 
SetOptionItalicFontStyle(const Ace::FontStyle & value)863 void SelectPattern::SetOptionItalicFontStyle(const Ace::FontStyle& value)
864 {
865     optionFont_.FontStyle = value;
866     for (size_t i = 0; i < options_.size(); ++i) {
867         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontStyle.has_value()) {
868             continue;
869         }
870         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
871         CHECK_NULL_VOID(pattern);
872         pattern->SetItalicFontStyle(value);
873     }
874 }
875 
SetOptionFontWeight(const FontWeight & value)876 void SelectPattern::SetOptionFontWeight(const FontWeight& value)
877 {
878     optionFont_.FontWeight = value;
879     for (size_t i = 0; i < options_.size(); ++i) {
880         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontWeight.has_value()) {
881             continue;
882         }
883         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
884         CHECK_NULL_VOID(pattern);
885         pattern->SetFontWeight(value);
886     }
887 }
888 
SetOptionFontFamily(const std::vector<std::string> & value)889 void SelectPattern::SetOptionFontFamily(const std::vector<std::string>& value)
890 {
891     optionFont_.FontFamily = value;
892     for (size_t i = 0; i < options_.size(); ++i) {
893         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontFamily.has_value()) {
894             continue;
895         }
896         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
897         CHECK_NULL_VOID(pattern);
898         pattern->SetFontFamily(value);
899     }
900 }
901 
SetOptionFontColor(const Color & color)902 void SelectPattern::SetOptionFontColor(const Color& color)
903 {
904     optionFont_.FontColor = color;
905     for (size_t i = 0; i < options_.size(); ++i) {
906         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontColor.has_value()) {
907             continue;
908         }
909         auto pattern = options_[i]->GetPattern<MenuItemPattern>();
910         CHECK_NULL_VOID(pattern);
911         pattern->SetFontColor(color);
912         pattern->SetOptionFontColor(color);
913         pattern->SetIsOptionFontColorSetByUser(true);
914     }
915 }
916 
917 // set props of option node when selected
SetSelectedOptionBgColor(const Color & color)918 void SelectPattern::SetSelectedOptionBgColor(const Color& color)
919 {
920     selectedBgColor_ = color;
921     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
922         auto pattern = options_[selected_]->GetPattern<MenuItemPattern>();
923         CHECK_NULL_VOID(pattern);
924         pattern->SetBgColor(color);
925         pattern->SetIsBGColorSetByUser(true);
926     }
927 }
928 
SetSelectedOptionFontSize(const Dimension & value)929 void SelectPattern::SetSelectedOptionFontSize(const Dimension& value)
930 {
931     selectedFont_.FontSize = value;
932     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
933         auto pattern = options_[selected_]->GetPattern<MenuItemPattern>();
934         CHECK_NULL_VOID(pattern);
935         pattern->SetFontSize(value);
936     }
937 }
938 
SetSelectedOptionItalicFontStyle(const Ace::FontStyle & value)939 void SelectPattern::SetSelectedOptionItalicFontStyle(const Ace::FontStyle& value)
940 {
941     selectedFont_.FontStyle = value;
942     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
943         auto pattern = options_[selected_]->GetPattern<MenuItemPattern>();
944         CHECK_NULL_VOID(pattern);
945         pattern->SetItalicFontStyle(value);
946     }
947 }
948 
SetSelectedOptionFontWeight(const FontWeight & value)949 void SelectPattern::SetSelectedOptionFontWeight(const FontWeight& value)
950 {
951     selectedFont_.FontWeight = value;
952     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
953         auto pattern = options_[selected_]->GetPattern<MenuItemPattern>();
954         CHECK_NULL_VOID(pattern);
955         pattern->SetFontWeight(value);
956     }
957 }
958 
SetSelectedOptionFontFamily(const std::vector<std::string> & value)959 void SelectPattern::SetSelectedOptionFontFamily(const std::vector<std::string>& value)
960 {
961     selectedFont_.FontFamily = value;
962     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
963         auto pattern = options_[selected_]->GetPattern<MenuItemPattern>();
964         CHECK_NULL_VOID(pattern);
965         pattern->SetFontFamily(value);
966     }
967 }
968 
SetSelectedOptionFontColor(const Color & color)969 void SelectPattern::SetSelectedOptionFontColor(const Color& color)
970 {
971     selectedFont_.FontColor = color;
972     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
973         auto pattern = options_[selected_]->GetPattern<MenuItemPattern>();
974         CHECK_NULL_VOID(pattern);
975         pattern->SetFontColor(color);
976         pattern->SetSelectFontColor(color);
977         pattern->SetIsTextColorSetByUser(true);
978     }
979 }
980 
GetOptions()981 const std::vector<RefPtr<FrameNode>>& SelectPattern::GetOptions()
982 {
983     return options_;
984 }
985 
ResetOptionProps()986 void SelectPattern::ResetOptionProps()
987 {
988     auto host = GetHost();
989     CHECK_NULL_VOID(host);
990     auto pipeline = host->GetContextWithCheck();
991     CHECK_NULL_VOID(pipeline);
992     auto selectTheme = pipeline->GetTheme<SelectTheme>(host->GetThemeScopeId());
993     auto textTheme = pipeline->GetTheme<TextTheme>();
994     CHECK_NULL_VOID(selectTheme && textTheme);
995 
996     for (const auto& option : options_) {
997         auto pattern = option->GetPattern<MenuItemPattern>();
998         CHECK_NULL_VOID(pattern);
999         pattern->SetSelected(false);
1000         pattern->SetBgColor(optionBgColor_.value_or(selectTheme->GetBackgroundColor()));
1001         pattern->SetFontSize(optionFont_.FontSize.value_or(selectTheme->GetMenuFontSize()));
1002         pattern->SetItalicFontStyle(optionFont_.FontStyle.value_or(textTheme->GetTextStyle().GetFontStyle()));
1003         pattern->SetFontWeight(optionFont_.FontWeight.value_or(textTheme->GetTextStyle().GetFontWeight()));
1004         pattern->SetFontFamily(optionFont_.FontFamily.value_or(textTheme->GetTextStyle().GetFontFamilies()));
1005         pattern->SetFontColor(optionFont_.FontColor.value_or(selectTheme->GetMenuFontColor()));
1006         pattern->SetIsBGColorSetByUser(false);
1007         pattern->SetIsTextColorSetByUser(false);
1008         pattern->SetIsOptionFontColorSetByUser(false);
1009         pattern->SetIsOptionBgColorSetByUser(false);
1010     }
1011 }
1012 
UpdateLastSelectedProps(int32_t index)1013 void SelectPattern::UpdateLastSelectedProps(int32_t index)
1014 {
1015     CHECK_NULL_VOID(options_[index]);
1016     auto newSelected = options_[index]->GetPattern<MenuItemPattern>();
1017     CHECK_NULL_VOID(newSelected);
1018     // set lastSelected option props back to default (unselected) values
1019     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
1020         CHECK_NULL_VOID(options_[selected_]);
1021         auto lastSelected = options_[selected_]->GetPattern<MenuItemPattern>();
1022         CHECK_NULL_VOID(lastSelected);
1023 
1024         lastSelected->SetFontColor(newSelected->GetFontColor());
1025         lastSelected->SetFontFamily(newSelected->GetFontFamily());
1026         lastSelected->SetFontSize(newSelected->GetFontSize());
1027         lastSelected->SetItalicFontStyle(newSelected->GetItalicFontStyle());
1028         lastSelected->SetFontWeight(newSelected->GetFontWeight());
1029         lastSelected->SetBorderColor(newSelected->GetBorderColor());
1030         lastSelected->SetBorderWidth(newSelected->GetBorderWidth());
1031         lastSelected->SetBgColor(newSelected->GetBgColor());
1032         lastSelected->SetSelected(false);
1033         lastSelected->UpdateNextNodeDivider(true);
1034         lastSelected->SetIsBGColorSetByUser(false);
1035         lastSelected->SetIsTextColorSetByUser(false);
1036         lastSelected->SetIsOptionFontColorSetByUser(false);
1037         lastSelected->SetIsOptionBgColorSetByUser(false);
1038         if (selectedBgColor_.has_value()) {
1039             newSelected->SetIsBGColorSetByUser(true);
1040             newSelected->SetBgColor(selectedBgColor_.value());
1041         }
1042         if (selectedFont_.FontColor.has_value()) {
1043             newSelected->SetIsTextColorSetByUser(true);
1044             newSelected->SetSelectFontColor(selectedFont_.FontColor.value());
1045         }
1046         if (optionFont_.FontColor.has_value()) {
1047             lastSelected->SetIsOptionFontColorSetByUser(true);
1048             lastSelected->SetOptionFontColor(optionFont_.FontColor.value());
1049             newSelected->SetIsOptionFontColorSetByUser(false);
1050         }
1051         if (optionBgColor_.has_value()) {
1052             lastSelected->SetIsOptionBgColorSetByUser(true);
1053             lastSelected->SetOptionBgColor(optionBgColor_.value());
1054             newSelected->SetIsOptionBgColorSetByUser(false);
1055         }
1056         if (selected_ != 0) {
1057             auto lastSelectedNode = lastSelected->GetHost();
1058             CHECK_NULL_VOID(lastSelectedNode);
1059             auto lastSelectedPros = lastSelectedNode->GetPaintProperty<MenuItemPaintProperty>();
1060             CHECK_NULL_VOID(lastSelectedPros);
1061             lastSelectedPros->UpdateNeedDivider(true);
1062         }
1063         options_[selected_]->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
1064     }
1065 }
1066 
1067 // update selected option props
UpdateSelectedProps(int32_t index)1068 void SelectPattern::UpdateSelectedProps(int32_t index)
1069 {
1070     CHECK_NULL_VOID(options_[index]);
1071     auto newSelected = options_[index]->GetPattern<MenuItemPattern>();
1072     CHECK_NULL_VOID(newSelected);
1073 
1074     // set newSelected props
1075     auto host = GetHost();
1076     CHECK_NULL_VOID(host);
1077     auto pipeline = host->GetContextRefPtr();
1078     CHECK_NULL_VOID(pipeline);
1079     auto theme = pipeline->GetTheme<SelectTheme>();
1080     CHECK_NULL_VOID(theme);
1081     if (selectedFont_.FontColor.has_value()) {
1082         newSelected->SetFontColor(selectedFont_.FontColor.value());
1083     } else {
1084         auto selectedColorText = theme->GetSelectedColorText();
1085         newSelected->SetFontColor(selectedColorText);
1086     }
1087     if (selectedFont_.FontFamily.has_value()) {
1088         newSelected->SetFontFamily(selectedFont_.FontFamily.value());
1089     }
1090     if (selectedFont_.FontSize.has_value()) {
1091         newSelected->SetFontSize(selectedFont_.FontSize.value());
1092     } else if (!optionFont_.FontSize.has_value()) {
1093         auto selectedFontSizeText = theme->GetSelectFontSizeText();
1094         newSelected->SetFontSize(selectedFontSizeText);
1095     }
1096     if (selectedFont_.FontStyle.has_value()) {
1097         newSelected->SetItalicFontStyle(selectedFont_.FontStyle.value());
1098     }
1099     if (selectedFont_.FontWeight.has_value()) {
1100         newSelected->SetFontWeight(selectedFont_.FontWeight.value());
1101     }
1102     if (selectedBgColor_.has_value()) {
1103         newSelected->SetBgColor(selectedBgColor_.value());
1104     } else {
1105         auto selectedColor = theme->GetSelectedColor();
1106         newSelected->SetBgColor(selectedColor);
1107     }
1108     newSelected->SetBorderColor(theme->GetOptionSelectedBorderColor());
1109     newSelected->SetBorderWidth(theme->GetOptionSelectedBorderWidth());
1110     newSelected->SetSelected(true);
1111     newSelected->UpdateNextNodeDivider(false);
1112     auto newSelectedNode = newSelected->GetHost();
1113     CHECK_NULL_VOID(newSelectedNode);
1114     auto newSelectedPros = newSelectedNode->GetPaintProperty<MenuItemPaintProperty>();
1115     CHECK_NULL_VOID(newSelectedPros);
1116     newSelectedPros->UpdateNeedDivider(false);
1117 }
1118 
UpdateText(int32_t index)1119 void SelectPattern::UpdateText(int32_t index)
1120 {
1121     // update text to selected option's text
1122     CHECK_NULL_VOID(text_);
1123     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
1124     CHECK_NULL_VOID(textProps);
1125     if (index >= static_cast<int32_t>(options_.size()) || index < 0) {
1126         return;
1127     }
1128     auto newSelected = options_[index]->GetPattern<MenuItemPattern>();
1129     CHECK_NULL_VOID(newSelected);
1130     textProps->UpdateContent(newSelected->GetText());
1131     text_->MarkModifyDone();
1132     auto host = GetHost();
1133     CHECK_NULL_VOID(host);
1134     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1135     selectValue_ = newSelected->GetText();
1136 }
1137 
InitTextProps(const RefPtr<TextLayoutProperty> & textProps)1138 void SelectPattern::InitTextProps(const RefPtr<TextLayoutProperty>& textProps)
1139 {
1140     auto select = GetHost();
1141     CHECK_NULL_VOID(select);
1142     auto* pipeline = select->GetContextWithCheck();
1143     CHECK_NULL_VOID(pipeline);
1144     auto theme = pipeline->GetTheme<SelectTheme>(select->GetThemeScopeId());
1145     CHECK_NULL_VOID(theme);
1146     textProps->UpdateFontSize(theme->GetFontSize());
1147     textProps->UpdateFontWeight(FontWeight::MEDIUM);
1148     textProps->UpdateTextColor(theme->GetFontColor());
1149     textProps->UpdateTextDecoration(theme->GetTextDecoration());
1150     textProps->UpdateTextOverflow(TextOverflow::ELLIPSIS);
1151     textProps->UpdateMaxLines(SELECT_ITSELF_TEXT_LINES);
1152 }
1153 
InitSpinner(const RefPtr<FrameNode> & spinner,const RefPtr<IconTheme> & iconTheme,const RefPtr<SelectTheme> & selectTheme)1154 void SelectPattern::InitSpinner(
1155     const RefPtr<FrameNode>& spinner, const RefPtr<IconTheme>& iconTheme, const RefPtr<SelectTheme>& selectTheme)
1156 {
1157     ImageSourceInfo imageSourceInfo;
1158     auto iconPath = iconTheme->GetIconPath(InternalResource::ResourceId::SPINNER);
1159     imageSourceInfo.SetSrc(iconPath);
1160     imageSourceInfo.SetFillColor(selectTheme->GetSpinnerColor());
1161 
1162     auto spinnerLayoutProperty = spinner->GetLayoutProperty<ImageLayoutProperty>();
1163     CHECK_NULL_VOID(spinnerLayoutProperty);
1164     spinnerLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
1165     CalcSize idealSize = { CalcLength(selectTheme->GetSpinnerWidth()), CalcLength(selectTheme->GetSpinnerHeight()) };
1166     MeasureProperty layoutConstraint;
1167     layoutConstraint.selfIdealSize = idealSize;
1168     spinnerLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
1169     auto spinnerRenderProperty = spinner->GetPaintProperty<ImageRenderProperty>();
1170     CHECK_NULL_VOID(spinnerRenderProperty);
1171     spinnerRenderProperty->UpdateSvgFillColor(selectTheme->GetSpinnerColor());
1172 }
1173 
InitSpinner(const RefPtr<FrameNode> & spinner,const RefPtr<SelectTheme> & selectTheme)1174 void SelectPattern::InitSpinner(
1175     const RefPtr<FrameNode>& spinner, const RefPtr<SelectTheme>& selectTheme)
1176 {
1177     auto spinnerLayoutProperty = spinner->GetLayoutProperty<TextLayoutProperty>();
1178     CHECK_NULL_VOID(spinnerLayoutProperty);
1179     uint32_t symbolId = selectTheme->GetSpinnerSource();
1180     spinnerLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo{symbolId});
1181     spinnerLayoutProperty->UpdateSymbolColorList({selectTheme->GetSpinnerSymbolColor()});
1182     spinnerLayoutProperty->UpdateFontSize(selectTheme->GetFontSize());
1183 }
1184 
1185 // XTS inspector code
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1186 void SelectPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1187 {
1188     /* no fixed attr below, just return */
1189     if (filter.IsFastFilter()) {
1190         ToJsonArrowAndText(json, filter);
1191         ToJsonOptionAlign(json, filter);
1192         ToJsonMenuBackgroundStyle(json, filter);
1193         return;
1194     }
1195     json->PutExtAttr("options", InspectorGetOptions().c_str(), filter);
1196     json->PutExtAttr("selected", std::to_string(selected_).c_str(), filter);
1197     ToJsonArrowAndText(json, filter);
1198     json->PutExtAttr("selectedOptionBgColor", selectedBgColor_->ColorToString().c_str(), filter);
1199     json->PutExtAttr("selectedOptionFont", InspectorGetSelectedFont().c_str(), filter);
1200     json->PutExtAttr("selectedOptionFontColor",
1201         selectedFont_.FontColor.value_or(Color::BLACK).ColorToString().c_str(), filter);
1202 
1203     if (options_.empty()) {
1204         json->PutExtAttr("optionBgColor", "", filter);
1205         json->PutExtAttr("optionFont", "", filter);
1206         json->PutExtAttr("optionFontColor", "", filter);
1207     } else {
1208         auto optionPattern = options_[0]->GetPattern<MenuItemPattern>();
1209         CHECK_NULL_VOID(optionPattern);
1210         json->PutExtAttr("optionBgColor", optionPattern->GetBgColor().ColorToString().c_str(), filter);
1211         json->PutExtAttr("optionFont", optionPattern->InspectorGetFont().c_str(), filter);
1212         json->PutExtAttr("optionFontColor", optionPattern->GetFontColor().ColorToString().c_str(), filter);
1213     }
1214     ToJsonOptionAlign(json, filter);
1215     for (size_t i = 0; i < options_.size(); ++i) {
1216         auto optionPaintProperty = options_[i]->GetPaintProperty<MenuItemPaintProperty>();
1217         CHECK_NULL_VOID(optionPaintProperty);
1218         std::string optionWidth = std::to_string(optionPaintProperty->GetSelectModifiedWidthValue(0.0f));
1219         json->PutExtAttr("optionWidth", optionWidth.c_str(), filter);
1220     }
1221 
1222     auto menu = GetMenuNode();
1223     CHECK_NULL_VOID(menu);
1224     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1225     CHECK_NULL_VOID(menuLayoutProps);
1226     std::string optionHeight =  std::to_string(menuLayoutProps->GetSelectModifiedHeightValue(0.0f));
1227     json->PutExtAttr("optionHeight", optionHeight.c_str(), filter);
1228     ToJsonMenuBackgroundStyle(json, filter);
1229     ToJsonDivider(json, filter);
1230 }
1231 
ToJsonArrowAndText(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1232 void SelectPattern::ToJsonArrowAndText(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1233 {
1234     /* no fixed attr below, just return */
1235     if (filter.IsFastFilter()) {
1236         return;
1237     }
1238     auto host = GetHost();
1239     CHECK_NULL_VOID(host);
1240     if (!host->GetChildren().empty()) {
1241         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1242         CHECK_NULL_VOID(row);
1243         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1244         CHECK_NULL_VOID(rowProps);
1245         json->PutExtAttr("space", rowProps->GetSpaceValue(Dimension()).ToString().c_str(), filter);
1246 
1247         if (rowProps->GetFlexDirection().value_or(FlexDirection::ROW) == FlexDirection::ROW) {
1248             json->PutExtAttr("arrowPosition", "ArrowPosition.END", filter);
1249         } else {
1250             json->PutExtAttr("arrowPosition", "ArrowPosition.START", filter);
1251         }
1252     }
1253 
1254     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
1255     CHECK_NULL_VOID(props);
1256     json->PutExtAttr("value", UtfUtils::Str16ToStr8(props->GetContent().value_or(u"")).c_str(), filter);
1257     Color fontColor = props->GetTextColor().value_or(Color::BLACK);
1258     json->PutExtAttr("fontColor", fontColor.ColorToString().c_str(), filter);
1259     json->PutExtAttr("font", props->InspectorGetTextFont().c_str(), filter);
1260     json->PutExtAttr("controlSize", ConvertControlSizeToString(controlSize_).c_str(), filter);
1261 }
1262 
ToJsonMenuBackgroundStyle(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1263 void SelectPattern::ToJsonMenuBackgroundStyle(
1264     std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1265 {
1266     /* no fixed attr below, just return */
1267     if (filter.IsFastFilter()) {
1268         return;
1269     }
1270     auto menu = GetMenuNode();
1271     CHECK_NULL_VOID(menu);
1272     auto menuRenderContext = menu->GetRenderContext();
1273     CHECK_NULL_VOID(menuRenderContext);
1274     json->PutExtAttr("menuBackgroundColor",
1275         menuRenderContext->GetBackgroundColor()->ColorToString().c_str(), filter);
1276     if (menuRenderContext->GetBackBlurStyle().has_value()) {
1277         BlurStyleOption blurStyleOption = menuRenderContext->GetBackBlurStyle().value();
1278         auto jsonValue = JsonUtil::Create(true);
1279         blurStyleOption.ToJsonValue(jsonValue, filter);
1280         json->PutExtAttr("menuBackgroundBlurStyle",
1281             jsonValue->GetValue("backgroundBlurStyle")->GetValue("value"), filter);
1282     } else {
1283         json->PutExtAttr("menuBackgroundBlurStyle", "", filter);
1284     }
1285 }
1286 
ToJsonDivider(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1287 void SelectPattern::ToJsonDivider(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1288 {
1289     /* no fixed attr below, just return */
1290     if (filter.IsFastFilter()) {
1291         return;
1292     }
1293     if (options_.empty()) {
1294         json->PutExtAttr("divider", "", filter);
1295     } else {
1296         auto props = options_[0]->GetPaintProperty<MenuItemPaintProperty>();
1297         CHECK_NULL_VOID(props);
1298         auto divider = JsonUtil::Create(true);
1299         if (props->HasDivider()) {
1300             divider->Put("strokeWidth", props->GetDividerValue().strokeWidth.ToString().c_str());
1301             divider->Put("startMargin", props->GetDividerValue().startMargin.ToString().c_str());
1302             divider->Put("endMargin", props->GetDividerValue().endMargin.ToString().c_str());
1303             divider->Put("color", props->GetDividerValue().color.ColorToString().c_str());
1304             json->PutExtAttr("divider", divider->ToString().c_str(), filter);
1305         } else {
1306             json->PutExtAttr("divider", "", filter);
1307         }
1308     }
1309 }
1310 
ToJsonOptionAlign(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1311 void SelectPattern::ToJsonOptionAlign(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1312 {
1313     /* no fixed attr below, just return */
1314     if (filter.IsFastFilter()) {
1315         return;
1316     }
1317     auto optionAlignJson = JsonUtil::Create(true);
1318     std::string alignTypeString = "MenuAlignType.Start";
1319     if (menuAlign_.alignType == MenuAlignType::START) {
1320         alignTypeString = "MenuAlignType.Start";
1321     } else if (menuAlign_.alignType == MenuAlignType::CENTER) {
1322         alignTypeString = "MenuAlignType.Center";
1323     } else if (menuAlign_.alignType == MenuAlignType::END) {
1324         alignTypeString = "MenuAlignType.End";
1325     }
1326     optionAlignJson->Put("alignType", alignTypeString.c_str());
1327 
1328     auto offsetValueJson = JsonUtil::Create(true);
1329     offsetValueJson->Put("dX", menuAlign_.offset.GetX().Value());
1330     offsetValueJson->Put("dY", menuAlign_.offset.GetY().Value());
1331     optionAlignJson->Put("offset", offsetValueJson);
1332 
1333     json->PutExtAttr("menuAlign", optionAlignJson, filter);
1334 }
1335 
InspectorGetOptions() const1336 std::string SelectPattern::InspectorGetOptions() const
1337 {
1338     auto jsonValue = JsonUtil::Create(true);
1339     auto jsonOptions = JsonUtil::CreateArray(true);
1340     for (size_t i = 0; i < options_.size(); ++i) {
1341         auto temp = JsonUtil::Create(true);
1342         auto optionPattern = options_[i]->GetPattern<MenuItemPattern>();
1343         temp->Put("value", optionPattern->GetText().c_str());
1344         temp->Put("icon", optionPattern->GetIcon().c_str());
1345         auto index = std::to_string(i);
1346         jsonOptions->Put(index.c_str(), temp);
1347     }
1348     jsonValue->Put("options", jsonOptions);
1349     return jsonValue->ToString();
1350 }
1351 
InspectorGetSelectedFont() const1352 std::string SelectPattern::InspectorGetSelectedFont() const
1353 {
1354     TextStyle font;
1355     if (selectedFont_.FontFamily.has_value()) {
1356         font.SetFontFamilies(selectedFont_.FontFamily.value());
1357     }
1358     if (selectedFont_.FontSize.has_value()) {
1359         font.SetFontSize(selectedFont_.FontSize.value());
1360     }
1361     if (selectedFont_.FontStyle.has_value()) {
1362         font.SetFontStyle(selectedFont_.FontStyle.value());
1363     }
1364     if (selectedFont_.FontWeight.has_value()) {
1365         font.SetFontWeight(selectedFont_.FontWeight.value());
1366     }
1367     return V2::GetTextStyleInJson(font);
1368 }
1369 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1370 bool SelectPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1371 {
1372     auto geometryNode = dirty->GetGeometryNode();
1373     CHECK_NULL_RETURN(geometryNode, false);
1374     SetSelectSize(geometryNode->GetFrameSize());
1375     CHECK_NULL_RETURN(menuWrapper_, false);
1376     auto wrapperPattern = menuWrapper_->GetPattern<MenuWrapperPattern>();
1377     if (wrapperPattern && wrapperPattern->IsShow()) {
1378         UpdateTargetSize();
1379     }
1380     return false;
1381 }
1382 
UpdateTargetSize()1383 void SelectPattern::UpdateTargetSize()
1384 {
1385     auto menu = GetMenuNode();
1386     CHECK_NULL_VOID(menu);
1387     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1388     CHECK_NULL_VOID(menuLayoutProps);
1389     menuLayoutProps->UpdateTargetSize(selectSize_);
1390     if (isFitTrigger_) {
1391         auto selectWidth = selectSize_.Width();
1392         auto menuPattern = menu->GetPattern<MenuPattern>();
1393         CHECK_NULL_VOID(menuPattern);
1394         menuPattern->SetIsWidthModifiedBySelect(true);
1395         menuLayoutProps->UpdateSelectMenuModifiedWidth(selectWidth);
1396         auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1397         CHECK_NULL_VOID(scroll);
1398         auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1399         CHECK_NULL_VOID(scrollPattern);
1400         scrollPattern->SetIsWidthModifiedBySelect(true);
1401         auto scrollLayoutProps = scroll->GetLayoutProperty<ScrollLayoutProperty>();
1402         CHECK_NULL_VOID(scrollLayoutProps);
1403         scrollLayoutProps->UpdateScrollWidth(selectWidth);
1404         UpdateOptionsWidth(selectWidth);
1405     }
1406     menu->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1407 }
1408 
SetSpace(const Dimension & value)1409 void SelectPattern::SetSpace(const Dimension& value)
1410 {
1411     auto host = GetHost();
1412     CHECK_NULL_VOID(host);
1413     if (!host->GetChildren().empty()) {
1414         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1415         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1416         rowProps->UpdateSpace(value);
1417         row->MarkModifyDone();
1418         row->MarkDirtyNode();
1419     }
1420 }
1421 
SetArrowPosition(const ArrowPosition value)1422 void SelectPattern::SetArrowPosition(const ArrowPosition value)
1423 {
1424     auto host = GetHost();
1425     CHECK_NULL_VOID(host);
1426     if (!host->GetChildren().empty()) {
1427         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1428         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1429 
1430         if (value == ArrowPosition::END) {
1431             rowProps->UpdateFlexDirection(FlexDirection::ROW);
1432         } else {
1433             rowProps->UpdateFlexDirection(FlexDirection::ROW_REVERSE);
1434         }
1435         row->MarkModifyDone();
1436         row->MarkDirtyNode();
1437     }
1438 }
1439 
GetValue()1440 std::string SelectPattern::GetValue()
1441 {
1442     CHECK_NULL_RETURN(text_, "");
1443     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
1444     CHECK_NULL_RETURN(textProps, "");
1445     return UtfUtils::Str16ToStr8(textProps->GetContentValue(u""));
1446 }
1447 
SetMenuAlign(const MenuAlign & menuAlign)1448 void SelectPattern::SetMenuAlign(const MenuAlign& menuAlign)
1449 {
1450     menuAlign_ = menuAlign;
1451     auto menu = GetMenuNode();
1452     CHECK_NULL_VOID(menu);
1453     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1454     CHECK_NULL_VOID(menuLayoutProps);
1455     menuLayoutProps->UpdateAlignType(menuAlign.alignType);
1456     menuLayoutProps->UpdateOffset(menuAlign.offset);
1457 }
1458 
SetAvoidance(const Avoidance & avoidance)1459 void SelectPattern::SetAvoidance(const Avoidance& avoidance)
1460 {
1461     avoidance_ = avoidance;
1462     auto menu = GetMenuNode();
1463     CHECK_NULL_VOID(menu);
1464     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1465     CHECK_NULL_VOID(menuLayoutProps);
1466     menuLayoutProps->UpdateSelectAvoidanceMode(avoidance.mode);
1467 }
1468 
ProvideRestoreInfo()1469 std::string SelectPattern::ProvideRestoreInfo()
1470 {
1471     auto jsonObj = JsonUtil::Create(true);
1472     jsonObj->Put("selected", selected_);
1473     jsonObj->Put("isSelected", isSelected_);
1474     return jsonObj->ToString();
1475 }
1476 
OnRestoreInfo(const std::string & restoreInfo)1477 void SelectPattern::OnRestoreInfo(const std::string& restoreInfo)
1478 {
1479     auto info = JsonUtil::ParseJsonString(restoreInfo);
1480     if (!info->IsValid() || !info->IsObject()) {
1481         return;
1482     }
1483     auto jsonIsOn = info->GetValue("selected");
1484     auto jsonIsSelect = info->GetValue("isSelected");
1485     if (jsonIsSelect->GetBool()) {
1486         SetSelected(jsonIsOn->GetInt());
1487         UpdateText(jsonIsOn->GetInt());
1488     }
1489 }
1490 
OnColorConfigurationUpdate()1491 void SelectPattern::OnColorConfigurationUpdate()
1492 {
1493     auto host = GetHost();
1494     CHECK_NULL_VOID(host);
1495     auto pipeline = host->GetContextWithCheck();
1496     CHECK_NULL_VOID(pipeline);
1497     auto selectTheme = pipeline->GetTheme<SelectTheme>(host->GetThemeScopeId());
1498     CHECK_NULL_VOID(selectTheme);
1499 
1500     auto pattern = host->GetPattern<SelectPattern>();
1501     auto menuNode = pattern->GetMenuNode();
1502     CHECK_NULL_VOID(menuNode);
1503     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1504     CHECK_NULL_VOID(menuPattern);
1505 
1506     auto renderContext = menuNode->GetRenderContext();
1507     renderContext->UpdateBackgroundColor(selectTheme->GetBackgroundColor());
1508     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && renderContext->IsUniRenderEnabled()) {
1509         renderContext->UpdateBackBlurStyle(renderContext->GetBackBlurStyle());
1510     }
1511 
1512     auto optionNode = menuPattern->GetOptions();
1513     for (auto child : optionNode) {
1514         auto optionsPattern = child->GetPattern<MenuItemPattern>();
1515         optionsPattern->SetFontColor(selectTheme->GetFontColor());
1516 
1517         child->MarkModifyDone();
1518         child->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1519     }
1520     SetOptionBgColor(selectTheme->GetBackgroundColor());
1521     host->SetNeedCallChildrenUpdate(false);
1522 }
1523 
OnThemeScopeUpdate(int32_t themeScopeId)1524 bool SelectPattern::OnThemeScopeUpdate(int32_t themeScopeId)
1525 {
1526     bool result = false;
1527     auto host = GetHost();
1528     CHECK_NULL_RETURN(host, false);
1529     auto pipeline = host->GetContextWithCheck();
1530     CHECK_NULL_RETURN(pipeline, false);
1531     auto selectTheme = pipeline->GetTheme<SelectTheme>(themeScopeId);
1532     CHECK_NULL_RETURN(selectTheme, false);
1533 
1534     if (!fontColor_.has_value()) {
1535         ResetFontColor();
1536         text_->MarkDirtyNode();
1537         result = true;
1538     }
1539 
1540     auto selectRenderContext = host->GetRenderContext();
1541     CHECK_NULL_RETURN(selectRenderContext, false);
1542     auto selectPaintProperty = host->GetPaintProperty<SelectPaintProperty>();
1543     CHECK_NULL_RETURN(selectPaintProperty, false);
1544     if (!selectPaintProperty->HasBackgroundColor()) {
1545         selectRenderContext->UpdateBackgroundColor(selectTheme->GetButtonBackgroundColor());
1546         result = true;
1547     }
1548     return result;
1549 }
1550 
OnLanguageConfigurationUpdate()1551 void SelectPattern::OnLanguageConfigurationUpdate()
1552 {
1553     auto host = GetHost();
1554     CHECK_NULL_VOID(host);
1555     auto context = host->GetContextRefPtr();
1556     CHECK_NULL_VOID(context);
1557     auto taskExecutor = context->GetTaskExecutor();
1558     CHECK_NULL_VOID(taskExecutor);
1559     taskExecutor->PostTask(
1560         [weak = WeakClaim(this)]() {
1561             auto pattern = weak.Upgrade();
1562             CHECK_NULL_VOID(pattern);
1563             auto index = pattern->selected_;
1564             pattern->UpdateText(index);
1565             auto host = pattern->GetHost();
1566             CHECK_NULL_VOID(host);
1567             auto hub = host->GetEventHub<SelectEventHub>();
1568             CHECK_NULL_VOID(hub);
1569             if (index >= static_cast<int32_t>(pattern->options_.size()) || index < 0) {
1570                 return;
1571             }
1572             auto newSelected = pattern->options_[index]->GetPattern<MenuItemPattern>();
1573             CHECK_NULL_VOID(newSelected);
1574             auto value = newSelected->GetText();
1575             auto valueChangeEvent = hub->GetValueChangeEvent();
1576             if (valueChangeEvent) {
1577                 valueChangeEvent(value);
1578             }
1579             auto onSelect = hub->GetSelectEvent();
1580             if (onSelect) {
1581                 onSelect(index, value);
1582             }
1583 
1584         },
1585         TaskExecutor::TaskType::UI, "ArkUISelectLanguageConfigUpdate");
1586 }
1587 
GetFontSize()1588 Dimension SelectPattern::GetFontSize()
1589 {
1590     Dimension defaultRet = Dimension();
1591     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
1592     CHECK_NULL_RETURN(props, defaultRet);
1593     auto host = props->GetHost();
1594     CHECK_NULL_RETURN(host, defaultRet);
1595     auto pipeline = host->GetContextWithCheck();
1596     CHECK_NULL_RETURN(pipeline, defaultRet);
1597     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1598     CHECK_NULL_RETURN(selectTheme, defaultRet);
1599     return props->GetFontSize().value_or(selectTheme->GetFontSize());
1600 }
1601 
SetOptionWidth(const Dimension & value)1602 void SelectPattern::SetOptionWidth(const Dimension& value)
1603 {
1604     isFitTrigger_ = false;
1605     auto menu = GetMenuNode();
1606     CHECK_NULL_VOID(menu);
1607     auto menuPattern = menu->GetPattern<MenuPattern>();
1608     CHECK_NULL_VOID(menuPattern);
1609     menuPattern->SetIsWidthModifiedBySelect(true);
1610     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1611     CHECK_NULL_VOID(menuLayoutProps);
1612     menuLayoutProps->UpdateSelectMenuModifiedWidth(value.ConvertToPx() + OPTION_MARGIN.ConvertToPx());
1613 
1614     auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1615     CHECK_NULL_VOID(scroll);
1616     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1617     CHECK_NULL_VOID(scrollPattern);
1618     scrollPattern->SetIsWidthModifiedBySelect(true);
1619     auto scrollLayoutProps = scroll->GetLayoutProperty<ScrollLayoutProperty>();
1620     CHECK_NULL_VOID(scrollLayoutProps);
1621     scrollLayoutProps->UpdateScrollWidth(value.ConvertToPx() + OPTION_MARGIN.ConvertToPx());
1622 
1623     for (size_t i = 0; i < options_.size(); ++i) {
1624         auto optionWidth = value.ConvertToPx();
1625         auto optionPattern = options_[i]->GetPattern<MenuItemPattern>();
1626         CHECK_NULL_VOID(optionPattern);
1627         optionPattern->SetIsWidthModifiedBySelect(true);
1628         auto optionPaintProperty = options_[i]->GetPaintProperty<MenuItemPaintProperty>();
1629         CHECK_NULL_VOID(optionPaintProperty);
1630         optionPaintProperty->UpdateSelectModifiedWidth(optionWidth);
1631     }
1632 }
1633 
SetOptionWidthFitTrigger(bool isFitTrigger)1634 void SelectPattern::SetOptionWidthFitTrigger(bool isFitTrigger)
1635 {
1636     isFitTrigger_ = isFitTrigger;
1637 }
1638 
SetHasOptionWidth(bool hasOptionWidth)1639 void SelectPattern::SetHasOptionWidth(bool hasOptionWidth)
1640 {
1641     auto menu = GetMenuNode();
1642     CHECK_NULL_VOID(menu);
1643     auto menuPattern = menu->GetPattern<MenuPattern>();
1644     CHECK_NULL_VOID(menuPattern);
1645     menuPattern->SetHasOptionWidth(true);
1646     auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1647     CHECK_NULL_VOID(scroll);
1648     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1649     CHECK_NULL_VOID(scrollPattern);
1650     scrollPattern->SetHasOptionWidth(true);
1651     for (size_t i = 0; i < options_.size(); ++i) {
1652         auto optionPattern = options_[i]->GetPattern<MenuItemPattern>();
1653         CHECK_NULL_VOID(optionPattern);
1654         optionPattern->SetHasOptionWidth(true);
1655     }
1656 }
1657 
SetOptionHeight(const Dimension & value)1658 void SelectPattern::SetOptionHeight(const Dimension& value)
1659 {
1660     auto menuMaxHeight = value.ConvertToPx();
1661     auto menu = GetMenuNode();
1662     CHECK_NULL_VOID(menu);
1663     auto menuPattern = menu->GetPattern<MenuPattern>();
1664     CHECK_NULL_VOID(menuPattern);
1665     menuPattern->SetIsHeightModifiedBySelect(true);
1666     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1667     CHECK_NULL_VOID(menuLayoutProps);
1668     menuLayoutProps->UpdateSelectModifiedHeight(menuMaxHeight);
1669 }
1670 
SetMenuBackgroundColor(const Color & color)1671 void SelectPattern::SetMenuBackgroundColor(const Color& color)
1672 {
1673     auto menu = GetMenuNode();
1674     CHECK_NULL_VOID(menu);
1675     auto renderContext = menu->GetRenderContext();
1676     CHECK_NULL_VOID(renderContext);
1677     renderContext->UpdateBackgroundColor(color);
1678 }
1679 
SetMenuBackgroundBlurStyle(const BlurStyleOption & blurStyle)1680 void SelectPattern::SetMenuBackgroundBlurStyle(const BlurStyleOption& blurStyle)
1681 {
1682     auto menu = GetMenuNode();
1683     CHECK_NULL_VOID(menu);
1684     auto renderContext = menu->GetRenderContext();
1685     CHECK_NULL_VOID(renderContext);
1686     renderContext->UpdateBackBlurStyle(blurStyle);
1687 }
1688 
ResetParams()1689 void SelectPattern::ResetParams()
1690 {
1691     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1692         return;
1693     }
1694     auto select = GetHost();
1695     CHECK_NULL_VOID(select);
1696     auto* pipeline = select->GetContextWithCheck();
1697     CHECK_NULL_VOID(pipeline);
1698     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1699     CHECK_NULL_VOID(selectTheme);
1700     auto layoutProperty = select->GetLayoutProperty();
1701     CHECK_NULL_VOID(layoutProperty);
1702     layoutProperty->UpdateCalcMinSize(CalcSize(CalcLength(selectTheme->GetSelectMinWidth(controlSize_)),
1703         CalcLength(selectTheme->GetSelectDefaultHeight(controlSize_))));
1704     SetFontSize(selectTheme->GetFontSize(controlSize_));
1705     auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
1706     CHECK_NULL_VOID(spinnerLayoutProperty);
1707     spinnerLayoutProperty->UpdateFontSize(selectTheme->GetFontSize(controlSize_));
1708     auto renderContext = select->GetRenderContext();
1709     BorderRadiusProperty border;
1710     border.SetRadius(selectTheme->GetSelectDefaultBorderRadius(controlSize_));
1711     renderContext->UpdateBorderRadius(border);
1712 
1713     NG::PaddingProperty paddings;
1714     paddings.top = std::nullopt;
1715     paddings.bottom = std::nullopt;
1716     if (controlSize_ == ControlSize::SMALL) {
1717         paddings.left = NG::CalcLength(SELECT_SMALL_PADDING_VP);
1718         paddings.right = NG::CalcLength(SELECT_SMALL_PADDING_VP);
1719     } else {
1720         paddings.left = NG::CalcLength(selectTheme->GetSelectNormalLeftRightMargin());
1721         paddings.right = NG::CalcLength(selectTheme->GetSelectNormalLeftRightMargin());
1722     }
1723     ViewAbstract::SetPadding(paddings);
1724 }
1725 
SetControlSize(const ControlSize & controlSize)1726 void SelectPattern::SetControlSize(const ControlSize& controlSize)
1727 {
1728     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1729         return;
1730     }
1731     controlSize_ = controlSize;
1732     ResetParams();
1733 }
1734 
SetLayoutDirection(TextDirection value)1735 void SelectPattern::SetLayoutDirection(TextDirection value)
1736 {
1737     auto select = GetHost();
1738     auto menu = GetMenuNode();
1739     std::function<void (decltype(select))> updateDirectionFunc = [&](decltype(select) node) {
1740         if (!node) return;
1741         auto updateProperty = node->GetLayoutProperty();
1742         updateProperty->UpdateLayoutDirection(value);
1743         if (node->GetHostTag() == V2::SCROLL_ETS_TAG) {
1744             auto scrollPattern = AceType::DynamicCast<ScrollPattern>(node->GetPattern());
1745             if (scrollPattern) scrollPattern->TriggerModifyDone();
1746         }
1747         for (auto child : node->GetAllChildrenWithBuild()) {
1748             auto frameNode = AceType::DynamicCast<FrameNode>(child);
1749             if (!frameNode) continue;
1750             updateDirectionFunc(frameNode);
1751         }
1752     };
1753     updateDirectionFunc(select);
1754     updateDirectionFunc(menu);
1755 }
1756 
GetControlSize()1757 ControlSize SelectPattern::GetControlSize()
1758 {
1759     return controlSize_;
1760 }
1761 
GetSelectLeftRightMargin() const1762 Dimension SelectPattern::GetSelectLeftRightMargin() const
1763 {
1764     auto host = GetHost();
1765     CHECK_NULL_RETURN(host, SELECT_MARGIN_VP);
1766     auto pipeline = host->GetContext();
1767     CHECK_NULL_RETURN(pipeline, SELECT_MARGIN_VP);
1768     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1769     CHECK_NULL_RETURN(selectTheme, SELECT_MARGIN_VP);
1770     return selectTheme->GetSelectNormalLeftRightMargin();
1771 }
1772 
GetShadowFromTheme(ShadowStyle shadowStyle,Shadow & shadow)1773 bool SelectPattern::GetShadowFromTheme(ShadowStyle shadowStyle, Shadow& shadow)
1774 {
1775     auto host = GetHost();
1776     CHECK_NULL_RETURN(host, false);
1777     auto context = host->GetContextRefPtr();
1778     CHECK_NULL_RETURN(context, false);
1779     auto shadowTheme = context->GetTheme<ShadowTheme>();
1780     CHECK_NULL_RETURN(shadowTheme, false);
1781     auto colorMode = context->GetColorMode();
1782     shadow = shadowTheme->GetShadow(shadowStyle, colorMode);
1783     return true;
1784 }
1785 
SetDivider(const SelectDivider & divider)1786 void SelectPattern::SetDivider(const SelectDivider& divider)
1787 {
1788     for (auto&& option : options_) {
1789         auto props = option->GetPaintProperty<MenuItemPaintProperty>();
1790         CHECK_NULL_VOID(props);
1791         props->UpdateDivider(divider);
1792         auto optionPattern = option->GetPattern<MenuItemPattern>();
1793         CHECK_NULL_VOID(optionPattern);
1794         auto frameNode = optionPattern->GetBottomDivider();
1795         if (!frameNode) {
1796             continue;
1797         }
1798         auto dividerProperty = frameNode->GetPaintProperty<MenuDividerPaintProperty>();
1799         CHECK_NULL_VOID(dividerProperty);
1800         dividerProperty->UpdateStrokeWidth(divider.strokeWidth);
1801         dividerProperty->UpdateDividerColor(divider.color);
1802         dividerProperty->UpdateStartMargin(divider.startMargin);
1803         dividerProperty->UpdateEndMargin(divider.endMargin);
1804     }
1805 }
1806 
ResetFontColor()1807 void SelectPattern::ResetFontColor()
1808 {
1809     if (fontColor_.has_value()) {
1810         fontColor_.reset();
1811     }
1812     auto host = GetHost();
1813     CHECK_NULL_VOID(host);
1814     auto pipeline = host->GetContextWithCheck();
1815     CHECK_NULL_VOID(pipeline);
1816     auto selectTheme = pipeline->GetTheme<SelectTheme>(host->GetThemeScopeId());
1817     CHECK_NULL_VOID(selectTheme);
1818     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
1819     CHECK_NULL_VOID(props);
1820     props->UpdateTextColor(selectTheme->GetFontColor());
1821     auto context = text_->GetRenderContext();
1822     CHECK_NULL_VOID(context);
1823     context->UpdateForegroundColor(selectTheme->GetFontColor());
1824     context->UpdateForegroundColorFlag(false);
1825     context->ResetForegroundColorStrategy();
1826 }
1827 
SetDividerMode(const std::optional<DividerMode> & mode)1828 void SelectPattern::SetDividerMode(const std::optional<DividerMode>& mode)
1829 {
1830     auto menu = GetMenuNode();
1831     CHECK_NULL_VOID(menu);
1832     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1833     CHECK_NULL_VOID(menuLayoutProps);
1834     if (mode.has_value()) {
1835         menuLayoutProps->UpdateItemDividerMode(mode.value());
1836     } else {
1837         menuLayoutProps->ResetItemDividerMode();
1838     }
1839     auto menuPattern = menu->GetPattern<MenuPattern>();
1840     CHECK_NULL_VOID(menuPattern);
1841     menuPattern->UpdateMenuItemDivider();
1842 }
1843 } // namespace OHOS::Ace::NG
1844