• 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 "core/animation/curves.h"
27 #include "core/common/recorder/event_recorder.h"
28 #include "core/common/recorder/node_data_cache.h"
29 #include "core/components/common/properties/color.h"
30 #include "core/components/common/properties/text_style.h"
31 #include "core/components/select/select_theme.h"
32 #include "core/components/theme/icon_theme.h"
33 #include "core/components_ng/base/frame_node.h"
34 #include "core/components_ng/base/inspector_filter.h"
35 #include "core/components_ng/base/view_abstract.h"
36 #include "core/components_ng/base/view_stack_processor.h"
37 #include "core/components_ng/pattern/image/image_pattern.h"
38 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
39 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
40 #include "core/components_ng/pattern/menu/menu_pattern.h"
41 #include "core/components_ng/pattern/option/option_pattern.h"
42 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
43 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
44 #include "core/components_ng/pattern/select/select_event_hub.h"
45 #include "core/components_ng/pattern/select/select_properties.h"
46 #include "core/components_ng/pattern/text/text_layout_property.h"
47 #include "core/components_ng/pattern/text/text_pattern.h"
48 #include "core/components_ng/property/border_property.h"
49 #include "core/components_ng/property/measure_property.h"
50 #include "core/components_ng/property/measure_utils.h"
51 #include "core/components_ng/property/property.h"
52 #include "core/components_v2/inspector/inspector_constants.h"
53 #include "core/components_v2/inspector/utils.h"
54 #include "core/pipeline/pipeline_base.h"
55 
56 namespace OHOS::Ace::NG {
57 
58 namespace {
59 
60 constexpr uint32_t SELECT_ITSELF_TEXT_LINES = 1;
61 
62 constexpr Dimension OPTION_MARGIN = 8.0_vp;
63 
64 constexpr Dimension CALIBERATE_X = 4.0_vp;
65 
66 constexpr Dimension CALIBERATE_Y = 4.0_vp;
67 
68 constexpr Dimension SELECT_SMALL_PADDING_VP = 4.0_vp;
69 
70 constexpr Dimension SELECT_MARGIN_VP = 8.0_vp;
71 
RecordChange(RefPtr<FrameNode> host,int32_t index,const std::string & value)72 void RecordChange(RefPtr<FrameNode> host, int32_t index, const std::string& value)
73 {
74     if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
75         auto inspectorId = host->GetInspectorId().value_or("");
76         Recorder::EventParamsBuilder builder;
77         builder.SetId(inspectorId)
78             .SetType(host->GetTag())
79             .SetIndex(index)
80             .SetText(value)
81             .SetDescription(host->GetAutoEventParamValue(""));
82         Recorder::EventRecorder::Get().OnChange(std::move(builder));
83         if (!inspectorId.empty()) {
84             Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, value, index);
85         }
86     }
87 }
88 
ConvertControlSizeToString(ControlSize controlSize)89 static std::string ConvertControlSizeToString(ControlSize controlSize)
90 {
91     std::string result;
92     switch (controlSize) {
93         case ControlSize::SMALL:
94             result = "ControlSize.SMALL";
95             break;
96         case ControlSize::NORMAL:
97             result = "ControlSize.NORMAL";
98             break;
99         default:
100             break;
101     }
102     return result;
103 }
104 } // namespace
105 
OnAttachToFrameNode()106 void SelectPattern::OnAttachToFrameNode()
107 {
108     RegisterOnKeyEvent();
109     RegisterOnClick();
110     RegisterOnPress();
111     RegisterOnHover();
112 }
113 
OnModifyDone()114 void SelectPattern::OnModifyDone()
115 {
116     Pattern::OnModifyDone();
117     CreateSelectedCallback();
118 
119     auto host = GetHost();
120     CHECK_NULL_VOID(host);
121     auto eventHub = host->GetEventHub<SelectEventHub>();
122     CHECK_NULL_VOID(eventHub);
123     if (!eventHub->IsEnabled()) {
124         SetDisabledStyle();
125     }
126     auto menu = GetMenuNode();
127     CHECK_NULL_VOID(menu);
128     auto menuPattern = menu->GetPattern<MenuPattern>();
129     CHECK_NULL_VOID(menuPattern);
130     menuPattern->UpdateSelectIndex(selected_);
131 }
132 
OnAfterModifyDone()133 void SelectPattern::OnAfterModifyDone()
134 {
135     auto host = GetHost();
136     CHECK_NULL_VOID(host);
137     auto inspectorId = host->GetInspectorId().value_or("");
138     if (inspectorId.empty()) {
139         return;
140     }
141     Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, selectValue_, selected_);
142 }
143 
SetItemSelected(int32_t index,const std::string & value)144 void SelectPattern::SetItemSelected(int32_t index, const std::string& value)
145 {
146     auto host = GetHost();
147     CHECK_NULL_VOID(host);
148     auto menu = GetMenuNode();
149     CHECK_NULL_VOID(menu);
150     auto menuPattern = menu->GetPattern<MenuPattern>();
151     CHECK_NULL_VOID(menuPattern);
152     isSelected_ = true;
153     menuPattern->UpdateSelectIndex(index);
154     CHECK_NULL_VOID(text_);
155     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
156     CHECK_NULL_VOID(textProps);
157     SetSelected(index);
158     textProps->UpdateContent(value);
159     text_->MarkModifyDone();
160     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
161     menuPattern->HideMenu();
162     auto hub = host->GetEventHub<SelectEventHub>();
163     CHECK_NULL_VOID(hub);
164 
165     auto onSelect = hub->GetSelectEvent();
166     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select choice index %{public}d", index);
167     if (onSelect) {
168         onSelect(index, value);
169     }
170     RecordChange(host, index, value);
171 }
172 
ShowSelectMenu()173 void SelectPattern::ShowSelectMenu()
174 {
175     CHECK_NULL_VOID(!options_.empty());
176     auto context = PipelineContext::GetCurrentContext();
177     CHECK_NULL_VOID(context);
178     auto overlayManager = context->GetOverlayManager();
179     CHECK_NULL_VOID(overlayManager);
180 
181     auto menu = GetMenuNode();
182     CHECK_NULL_VOID(menu);
183     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
184     CHECK_NULL_VOID(menuLayoutProps);
185     menuLayoutProps->UpdateTargetSize(selectSize_);
186 
187     auto select = GetHost();
188     CHECK_NULL_VOID(select);
189     auto selectGeometry = select->GetGeometryNode();
190     CHECK_NULL_VOID(selectGeometry);
191     auto selectProps = select->GetLayoutProperty();
192     CHECK_NULL_VOID(selectProps);
193 
194     if (isFitTrigger_) {
195         auto selectWidth = selectSize_.Width();
196         auto menuPattern = menu->GetPattern<MenuPattern>();
197         CHECK_NULL_VOID(menuPattern);
198         menuPattern->SetIsWidthModifiedBySelect(true);
199         menuLayoutProps->UpdateSelectMenuModifiedWidth(selectWidth);
200         auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
201         CHECK_NULL_VOID(scroll);
202         auto scrollPattern = scroll->GetPattern<ScrollPattern>();
203         CHECK_NULL_VOID(scrollPattern);
204         scrollPattern->SetIsWidthModifiedBySelect(true);
205         auto scrollLayoutProps = scroll->GetLayoutProperty<ScrollLayoutProperty>();
206         CHECK_NULL_VOID(scrollLayoutProps);
207         scrollLayoutProps->UpdateScrollWidth(selectWidth);
208         UpdateOptionsWidth(selectWidth);
209     }
210 
211     auto offset = GetHost()->GetPaintRectOffset();
212     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
213         offset.AddY(selectSize_.Height() + CALIBERATE_Y.ConvertToPx());
214         offset.AddX(-CALIBERATE_X.ConvertToPx());
215     } else {
216         offset.AddY(selectSize_.Height());
217     }
218 
219     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select click to show menu.");
220     overlayManager->ShowMenu(GetHost()->GetId(), offset, menuWrapper_);
221 }
222 
UpdateOptionsWidth(float selectWidth)223 void SelectPattern::UpdateOptionsWidth(float selectWidth)
224 {
225     for (size_t i = 0; i < options_.size(); ++i) {
226         auto optionGeoNode = options_[i]->GetGeometryNode();
227         CHECK_NULL_VOID(optionGeoNode);
228         auto optionWidth = selectWidth - OPTION_MARGIN.ConvertToPx();
229         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
230         CHECK_NULL_VOID(optionPattern);
231         optionPattern->SetIsWidthModifiedBySelect(true);
232         auto optionPaintProperty = options_[i]->GetPaintProperty<OptionPaintProperty>();
233         CHECK_NULL_VOID(optionPaintProperty);
234         optionPaintProperty->UpdateSelectModifiedWidth(optionWidth);
235     }
236 }
237 
238 // add click event to show menu
RegisterOnClick()239 void SelectPattern::RegisterOnClick()
240 {
241     auto host = GetHost();
242     CHECK_NULL_VOID(host);
243 
244     GestureEventFunc callback = [weak = WeakClaim(this)](GestureEvent& /* info */) mutable {
245         auto pattern = weak.Upgrade();
246         CHECK_NULL_VOID(pattern);
247 
248         auto selected = pattern->GetSelected();
249         if (selected > -1 && selected < static_cast<int32_t>(pattern->GetOptions().size())) {
250             pattern->UpdateSelectedProps(selected);
251         }
252         pattern->ShowSelectMenu();
253     };
254     auto gestureHub = host->GetOrCreateGestureEventHub();
255     if (!gestureHub->GetTouchable()) {
256         return;
257     }
258     gestureHub->BindMenu(std::move(callback));
259 }
260 
PlayBgColorAnimation(bool isHoverChange)261 void SelectPattern::PlayBgColorAnimation(bool isHoverChange)
262 {
263     auto host = GetHost();
264     CHECK_NULL_VOID(host);
265     auto* pipeline = host->GetContextWithCheck();
266     CHECK_NULL_VOID(pipeline);
267     auto selectTheme = pipeline->GetTheme<SelectTheme>();
268     CHECK_NULL_VOID(selectTheme);
269 
270     AnimationOption option = AnimationOption();
271     if (isHoverChange) {
272         option.SetDuration(selectTheme->GetHoverAnimationDuration());
273         option.SetCurve(Curves::FRICTION);
274     } else {
275         option.SetDuration(selectTheme->GetPressAnimationDuration());
276         option.SetCurve(Curves::SHARP);
277     }
278 
279     AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
280         auto pattern = weak.Upgrade();
281         CHECK_NULL_VOID(pattern);
282         auto host = pattern->GetHost();
283         CHECK_NULL_VOID(host);
284         auto renderContext = host->GetRenderContext();
285         CHECK_NULL_VOID(renderContext);
286         renderContext->BlendBgColor(pattern->GetBgBlendColor());
287     });
288 }
289 
290 // change background color when hovered
RegisterOnHover()291 void SelectPattern::RegisterOnHover()
292 {
293     auto host = GetHost();
294     CHECK_NULL_VOID(host);
295     auto inputHub = host->GetOrCreateInputEventHub();
296     CHECK_NULL_VOID(inputHub);
297     auto mouseCallback = [weak = WeakClaim(this), host](bool isHover) {
298         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select mouse hover %{public}d", isHover);
299         auto pattern = weak.Upgrade();
300         CHECK_NULL_VOID(pattern);
301         pattern->SetIsHover(isHover);
302         auto* pipeline = host->GetContextWithCheck();
303         CHECK_NULL_VOID(pipeline);
304         auto theme = pipeline->GetTheme<SelectTheme>();
305         CHECK_NULL_VOID(theme);
306         // update hover status, repaint background color
307         if (isHover) {
308             pattern->SetBgBlendColor(theme->GetHoverColor());
309         } else {
310             pattern->SetBgBlendColor(Color::TRANSPARENT);
311         }
312         pattern->PlayBgColorAnimation();
313     };
314     auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseCallback));
315     inputHub->AddOnHoverEvent(mouseEvent);
316 }
317 
318 // change background color when pressed
RegisterOnPress()319 void SelectPattern::RegisterOnPress()
320 {
321     auto host = GetHost();
322     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
323         auto pattern = weak.Upgrade();
324         CHECK_NULL_VOID(pattern);
325         auto host = pattern->GetHost();
326         CHECK_NULL_VOID(host);
327         auto context = host->GetContextRefPtr();
328         CHECK_NULL_VOID(context);
329         auto theme = context->GetTheme<SelectTheme>();
330         auto touchType = info.GetTouches().front().GetTouchType();
331         const auto& renderContext = host->GetRenderContext();
332         CHECK_NULL_VOID(renderContext);
333         // update press status, repaint background color
334         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select touch type %{public}zu", touchType);
335         if (touchType == TouchType::DOWN) {
336             pattern->SetBgBlendColor(theme->GetClickedColor());
337             pattern->PlayBgColorAnimation(false);
338         }
339         if (touchType == TouchType::UP) {
340             if (pattern->IsHover()) {
341                 pattern->SetBgBlendColor(theme->GetHoverColor());
342             } else {
343                 pattern->SetBgBlendColor(Color::TRANSPARENT);
344             }
345             pattern->PlayBgColorAnimation(false);
346         }
347     };
348     auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
349     auto gestureHub = host->GetOrCreateGestureEventHub();
350     gestureHub->AddTouchEvent(touchEvent);
351 }
352 
CreateSelectedCallback()353 void SelectPattern::CreateSelectedCallback()
354 {
355     auto host = GetHost();
356     CHECK_NULL_VOID(host);
357     auto callback = [weak = WeakClaim(RawPtr(host))](int32_t index) {
358         auto host = weak.Upgrade();
359         CHECK_NULL_VOID(host);
360         auto pattern = host->GetPattern<SelectPattern>();
361         CHECK_NULL_VOID(pattern);
362         pattern->SetSelected(index);
363         pattern->UpdateText(index);
364         pattern->isSelected_ = true;
365         auto hub = host->GetEventHub<SelectEventHub>();
366         CHECK_NULL_VOID(hub);
367         // execute change event callback
368         auto selectChangeEvent = hub->GetSelectChangeEvent();
369         if (selectChangeEvent) {
370             selectChangeEvent(index);
371         }
372         auto valueChangeEvent = hub->GetValueChangeEvent();
373         if (valueChangeEvent) {
374             auto newSelected = pattern->options_[index]->GetPattern<OptionPattern>();
375             CHECK_NULL_VOID(newSelected);
376             valueChangeEvent(newSelected->GetText());
377         }
378         // execute onSelect callback
379         auto newSelected = pattern->options_[index]->GetPattern<OptionPattern>();
380         CHECK_NULL_VOID(newSelected);
381         auto value = newSelected->GetText();
382         auto onSelect = hub->GetSelectEvent();
383         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "select choice index %{public}d", index);
384         if (onSelect) {
385             onSelect(index, value);
386         }
387         RecordChange(host, index, value);
388     };
389     for (auto&& option : options_) {
390         auto hub = option->GetEventHub<OptionEventHub>();
391         // no std::move, need to set multiple options
392         hub->SetOnSelect(callback);
393         option->MarkModifyDone();
394     }
395 }
396 
RegisterOnKeyEvent()397 void SelectPattern::RegisterOnKeyEvent()
398 {
399     auto host = GetHost();
400     CHECK_NULL_VOID(host);
401     auto focusHub = host->GetOrCreateFocusHub();
402     CHECK_NULL_VOID(focusHub);
403     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
404         auto pattern = wp.Upgrade();
405         CHECK_NULL_RETURN(pattern, false);
406         return pattern->OnKeyEvent(event);
407     };
408     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
409 }
410 
OnKeyEvent(const KeyEvent & event)411 bool SelectPattern::OnKeyEvent(const KeyEvent& event)
412 {
413     if (event.action != KeyAction::DOWN) {
414         return false;
415     }
416     if (event.code == KeyCode::KEY_ENTER) {
417         auto host = GetHost();
418         CHECK_NULL_RETURN(host, false);
419         auto focusHub = host->GetOrCreateFocusHub();
420         CHECK_NULL_RETURN(focusHub, false);
421         focusHub->OnClick(event);
422         return true;
423     }
424     return false;
425 }
426 
SetDisabledStyle()427 void SelectPattern::SetDisabledStyle()
428 {
429     auto host = GetHost();
430     CHECK_NULL_VOID(host);
431     auto pipeline = host->GetContextWithCheck();
432     CHECK_NULL_VOID(pipeline);
433     auto theme = pipeline->GetTheme<SelectTheme>();
434     CHECK_NULL_VOID(theme);
435 
436     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
437     CHECK_NULL_VOID(textProps);
438     textProps->UpdateTextColor(theme->GetDisabledFontColor());
439     text_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
440 
441     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
442         auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
443         CHECK_NULL_VOID(spinnerLayoutProperty);
444         spinnerLayoutProperty->UpdateSymbolColorList({theme->GetDisabledSpinnerSymbolColor()});
445     } else {
446         auto spinnerLayoutProperty = spinner_->GetLayoutProperty<ImageLayoutProperty>();
447         CHECK_NULL_VOID(spinnerLayoutProperty);
448 
449         ImageSourceInfo imageSourceInfo = spinnerLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo());
450         auto iconTheme = pipeline->GetTheme<IconTheme>();
451         CHECK_NULL_VOID(iconTheme);
452         auto iconPath = iconTheme->GetIconPath(InternalResource::ResourceId::SPINNER_DISABLE);
453         imageSourceInfo.SetSrc(iconPath);
454         if (imageSourceInfo.IsSvg()) {
455             imageSourceInfo.SetFillColor(theme->GetDisabledSpinnerColor());
456         }
457         spinnerLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
458         auto spinnerRenderProperty = spinner_->GetPaintProperty<ImageRenderProperty>();
459         CHECK_NULL_VOID(spinnerRenderProperty);
460         spinnerRenderProperty->UpdateSvgFillColor(theme->GetDisabledSpinnerColor());
461     }
462     spinner_->MarkModifyDone();
463 
464     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
465         auto renderContext = host->GetRenderContext();
466         CHECK_NULL_VOID(renderContext);
467         renderContext->UpdateBackgroundColor(renderContext->GetBackgroundColor()
468                                                  .value_or(theme->GetButtonBackgroundColor())
469                                                  .BlendOpacity(theme->GetDisabledFontColorAlpha()));
470     }
471 }
472 
SetSelected(int32_t index)473 void SelectPattern::SetSelected(int32_t index)
474 {
475     // if option is already selected, do nothing
476     if (index == selected_) {
477         return;
478     }
479     if (index >= static_cast<int32_t>(options_.size()) || index < 0) {
480         selected_ = -1;
481         ResetOptionProps();
482         return;
483     }
484     UpdateLastSelectedProps(index);
485     selected_ = index;
486 }
487 
AddOptionNode(const RefPtr<FrameNode> & option)488 void SelectPattern::AddOptionNode(const RefPtr<FrameNode>& option)
489 {
490     CHECK_NULL_VOID(option);
491     options_.push_back(option);
492 }
493 
BuildChild()494 void SelectPattern::BuildChild()
495 {
496     auto select = GetHost();
497     CHECK_NULL_VOID(select);
498     // get theme from SelectThemeManager
499     auto* pipeline = select->GetContextWithCheck();
500     CHECK_NULL_VOID(pipeline);
501     auto theme = pipeline->GetTheme<SelectTheme>();
502     CHECK_NULL_VOID(theme);
503 
504     bool hasRowNode = HasRowNode();
505     bool hasTextNode = HasTextNode();
506     bool hasSpinnerNode = HasSpinnerNode();
507     auto rowId = GetRowId();
508     auto textId = GetTextId();
509     auto spinnerId = GetSpinnerId();
510 
511     auto row = FrameNode::GetOrCreateFrameNode(
512         V2::ROW_ETS_TAG, rowId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
513     CHECK_NULL_VOID(row);
514     row->SetInternal();
515     auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
516     CHECK_NULL_VOID(rowProps);
517     rowProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
518     rowProps->UpdateCrossAxisAlign(FlexAlign::CENTER);
519     rowProps->UpdateFlexDirection(FlexDirection::ROW);
520     rowProps->UpdateSpace(theme->GetContentSpinnerPadding());
521     text_ =
522         FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG, textId, []() { return AceType::MakeRefPtr<TextPattern>(); });
523     CHECK_NULL_VOID(text_);
524     text_->SetInternal();
525     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
526     CHECK_NULL_VOID(textProps);
527     InitTextProps(textProps, theme);
528     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
529         spinner_ = FrameNode::GetOrCreateFrameNode(
530             V2::SYMBOL_ETS_TAG, spinnerId, []() { return AceType::MakeRefPtr<TextPattern>(); });
531         CHECK_NULL_VOID(spinner_);
532         spinner_->SetInternal();
533         InitSpinner(spinner_, theme);
534     } else {
535         spinner_ = FrameNode::GetOrCreateFrameNode(
536             V2::IMAGE_ETS_TAG, spinnerId, []() { return AceType::MakeRefPtr<ImagePattern>(); });
537         CHECK_NULL_VOID(spinner_);
538         spinner_->SetInternal();
539         auto iconTheme = pipeline->GetTheme<IconTheme>();
540         CHECK_NULL_VOID(iconTheme);
541         InitSpinner(spinner_, iconTheme, theme);
542     }
543     // mount triangle and text
544     text_->MarkModifyDone();
545     if (!hasTextNode) {
546         text_->MountToParent(row);
547     }
548     spinner_->MarkModifyDone();
549     if (!hasSpinnerNode) {
550         spinner_->MountToParent(row);
551     }
552     if (!hasRowNode) {
553         row->MountToParent(select);
554     }
555     row->MarkModifyDone();
556     row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
557 
558     // set bgColor and border
559     auto renderContext = select->GetRenderContext();
560     CHECK_NULL_VOID(renderContext);
561     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
562         renderContext->UpdateBackgroundColor(theme->GetBackgroundColor());
563     } else {
564         renderContext->UpdateBackgroundColor(theme->GetButtonBackgroundColor());
565     }
566     renderContext->SetClipToFrame(true);
567     BorderRadiusProperty border;
568     border.SetRadius(theme->GetSelectBorderRadius());
569     renderContext->UpdateBorderRadius(border);
570 }
571 
SetValue(const std::string & value)572 void SelectPattern::SetValue(const std::string& value)
573 {
574     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
575     CHECK_NULL_VOID(props);
576     props->UpdateContent(value);
577     auto pattern = text_->GetPattern<TextPattern>();
578     CHECK_NULL_VOID(pattern);
579     auto modifier = pattern->GetContentModifier();
580     CHECK_NULL_VOID(modifier);
581     modifier->ContentChange();
582     selectValue_ = value;
583 }
584 
SetFontSize(const Dimension & value)585 void SelectPattern::SetFontSize(const Dimension& value)
586 {
587     if (value.IsNegative()) {
588         return;
589     }
590     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
591     CHECK_NULL_VOID(props);
592     props->UpdateFontSize(value);
593 }
594 
SetItalicFontStyle(const Ace::FontStyle & value)595 void SelectPattern::SetItalicFontStyle(const Ace::FontStyle& value)
596 {
597     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
598     CHECK_NULL_VOID(props);
599     props->UpdateItalicFontStyle(value);
600 }
601 
SetFontWeight(const FontWeight & value)602 void SelectPattern::SetFontWeight(const FontWeight& value)
603 {
604     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
605     CHECK_NULL_VOID(props);
606     props->UpdateFontWeight(value);
607 }
608 
SetFontFamily(const std::vector<std::string> & value)609 void SelectPattern::SetFontFamily(const std::vector<std::string>& value)
610 {
611     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
612     CHECK_NULL_VOID(props);
613     props->UpdateFontFamily(value);
614 }
615 
SetFontColor(const Color & color)616 void SelectPattern::SetFontColor(const Color& color)
617 {
618     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
619     CHECK_NULL_VOID(props);
620     props->UpdateTextColor(color);
621     auto context = text_->GetRenderContext();
622     context->UpdateForegroundColor(color);
623     context->UpdateForegroundColorFlag(false);
624     context->ResetForegroundColorStrategy();
625 }
626 
SetOptionBgColor(const Color & color)627 void SelectPattern::SetOptionBgColor(const Color& color)
628 {
629     optionBgColor_ = color;
630     for (size_t i = 0; i < options_.size(); ++i) {
631         if (static_cast<int32_t>(i) == selected_ && selectedBgColor_.has_value()) {
632             continue;
633         }
634         auto pattern = options_[i]->GetPattern<OptionPattern>();
635         CHECK_NULL_VOID(pattern);
636         pattern->SetBgColor(color);
637     }
638 }
639 
SetOptionFontSize(const Dimension & value)640 void SelectPattern::SetOptionFontSize(const Dimension& value)
641 {
642     optionFont_.FontSize = value;
643     for (size_t i = 0; i < options_.size(); ++i) {
644         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontSize.has_value()) {
645             continue;
646         }
647         auto pattern = options_[i]->GetPattern<OptionPattern>();
648         CHECK_NULL_VOID(pattern);
649         pattern->SetFontSize(value);
650     }
651 }
652 
SetOptionItalicFontStyle(const Ace::FontStyle & value)653 void SelectPattern::SetOptionItalicFontStyle(const Ace::FontStyle& value)
654 {
655     optionFont_.FontStyle = value;
656     for (size_t i = 0; i < options_.size(); ++i) {
657         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontStyle.has_value()) {
658             continue;
659         }
660         auto pattern = options_[i]->GetPattern<OptionPattern>();
661         CHECK_NULL_VOID(pattern);
662         pattern->SetItalicFontStyle(value);
663     }
664 }
665 
SetOptionFontWeight(const FontWeight & value)666 void SelectPattern::SetOptionFontWeight(const FontWeight& value)
667 {
668     optionFont_.FontWeight = value;
669     for (size_t i = 0; i < options_.size(); ++i) {
670         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontWeight.has_value()) {
671             continue;
672         }
673         auto pattern = options_[i]->GetPattern<OptionPattern>();
674         CHECK_NULL_VOID(pattern);
675         pattern->SetFontWeight(value);
676     }
677 }
678 
SetOptionFontFamily(const std::vector<std::string> & value)679 void SelectPattern::SetOptionFontFamily(const std::vector<std::string>& value)
680 {
681     optionFont_.FontFamily = value;
682     for (size_t i = 0; i < options_.size(); ++i) {
683         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontFamily.has_value()) {
684             continue;
685         }
686         auto pattern = options_[i]->GetPattern<OptionPattern>();
687         CHECK_NULL_VOID(pattern);
688         pattern->SetFontFamily(value);
689     }
690 }
691 
SetOptionFontColor(const Color & color)692 void SelectPattern::SetOptionFontColor(const Color& color)
693 {
694     optionFont_.FontColor = color;
695     for (size_t i = 0; i < options_.size(); ++i) {
696         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontColor.has_value()) {
697             continue;
698         }
699         auto pattern = options_[i]->GetPattern<OptionPattern>();
700         CHECK_NULL_VOID(pattern);
701         pattern->SetFontColor(color);
702     }
703 }
704 
705 // set props of option node when selected
SetSelectedOptionBgColor(const Color & color)706 void SelectPattern::SetSelectedOptionBgColor(const Color& color)
707 {
708     selectedBgColor_ = color;
709     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
710         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
711         CHECK_NULL_VOID(pattern);
712         pattern->SetBgColor(color);
713     }
714 }
715 
SetSelectedOptionFontSize(const Dimension & value)716 void SelectPattern::SetSelectedOptionFontSize(const Dimension& value)
717 {
718     selectedFont_.FontSize = value;
719     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
720         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
721         CHECK_NULL_VOID(pattern);
722         pattern->SetFontSize(value);
723     }
724 }
725 
SetSelectedOptionItalicFontStyle(const Ace::FontStyle & value)726 void SelectPattern::SetSelectedOptionItalicFontStyle(const Ace::FontStyle& value)
727 {
728     selectedFont_.FontStyle = value;
729     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
730         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
731         CHECK_NULL_VOID(pattern);
732         pattern->SetItalicFontStyle(value);
733     }
734 }
735 
SetSelectedOptionFontWeight(const FontWeight & value)736 void SelectPattern::SetSelectedOptionFontWeight(const FontWeight& value)
737 {
738     selectedFont_.FontWeight = value;
739     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
740         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
741         CHECK_NULL_VOID(pattern);
742         pattern->SetFontWeight(value);
743     }
744 }
745 
SetSelectedOptionFontFamily(const std::vector<std::string> & value)746 void SelectPattern::SetSelectedOptionFontFamily(const std::vector<std::string>& value)
747 {
748     selectedFont_.FontFamily = value;
749     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
750         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
751         CHECK_NULL_VOID(pattern);
752         pattern->SetFontFamily(value);
753     }
754 }
755 
SetSelectedOptionFontColor(const Color & color)756 void SelectPattern::SetSelectedOptionFontColor(const Color& color)
757 {
758     selectedFont_.FontColor = color;
759     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
760         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
761         CHECK_NULL_VOID(pattern);
762         pattern->SetFontColor(color);
763     }
764 }
765 
GetOptions()766 const std::vector<RefPtr<FrameNode>>& SelectPattern::GetOptions()
767 {
768     return options_;
769 }
770 
ResetOptionProps()771 void SelectPattern::ResetOptionProps()
772 {
773     auto host = GetHost();
774     CHECK_NULL_VOID(host);
775     auto pipeline = host->GetContextWithCheck();
776     CHECK_NULL_VOID(pipeline);
777     auto selectTheme = pipeline->GetTheme<SelectTheme>();
778     auto textTheme = pipeline->GetTheme<TextTheme>();
779     CHECK_NULL_VOID(selectTheme && textTheme);
780 
781     for (const auto& option : options_) {
782         auto pattern = option->GetPattern<OptionPattern>();
783         CHECK_NULL_VOID(pattern);
784         pattern->SetBgColor(optionBgColor_.value_or(selectTheme->GetBackgroundColor()));
785         pattern->SetFontSize(optionFont_.FontSize.value_or(selectTheme->GetMenuFontSize()));
786         pattern->SetItalicFontStyle(optionFont_.FontStyle.value_or(textTheme->GetTextStyle().GetFontStyle()));
787         pattern->SetFontWeight(optionFont_.FontWeight.value_or(textTheme->GetTextStyle().GetFontWeight()));
788         pattern->SetFontFamily(optionFont_.FontFamily.value_or(textTheme->GetTextStyle().GetFontFamilies()));
789         pattern->SetFontColor(optionFont_.FontColor.value_or(selectTheme->GetMenuFontColor()));
790     }
791 }
792 
UpdateLastSelectedProps(int32_t index)793 void SelectPattern::UpdateLastSelectedProps(int32_t index)
794 {
795     CHECK_NULL_VOID(options_[index]);
796     auto newSelected = options_[index]->GetPattern<OptionPattern>();
797     CHECK_NULL_VOID(newSelected);
798     // set lastSelected option props back to default (unselected) values
799     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
800         CHECK_NULL_VOID(options_[selected_]);
801         auto lastSelected = options_[selected_]->GetPattern<OptionPattern>();
802         CHECK_NULL_VOID(lastSelected);
803 
804         lastSelected->SetFontColor(newSelected->GetFontColor());
805         lastSelected->SetFontFamily(newSelected->GetFontFamily());
806         lastSelected->SetFontSize(newSelected->GetFontSize());
807         lastSelected->SetItalicFontStyle(newSelected->GetItalicFontStyle());
808         lastSelected->SetFontWeight(newSelected->GetFontWeight());
809 
810         lastSelected->SetBgColor(newSelected->GetBgColor());
811         lastSelected->UpdateNextNodeDivider(true);
812         if (selected_ != 0) {
813             auto lastSelectedNode = lastSelected->GetHost();
814             CHECK_NULL_VOID(lastSelectedNode);
815             auto lastSelectedPros = lastSelectedNode->GetPaintProperty<OptionPaintProperty>();
816             CHECK_NULL_VOID(lastSelectedPros);
817             lastSelectedPros->UpdateNeedDivider(true);
818         }
819         options_[selected_]->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
820     }
821 }
822 
823 // update selected option props
UpdateSelectedProps(int32_t index)824 void SelectPattern::UpdateSelectedProps(int32_t index)
825 {
826     CHECK_NULL_VOID(options_[index]);
827     auto newSelected = options_[index]->GetPattern<OptionPattern>();
828     CHECK_NULL_VOID(newSelected);
829 
830     // set newSelected props
831     auto host = GetHost();
832     CHECK_NULL_VOID(host);
833     auto pipeline = host->GetContextRefPtr();
834     CHECK_NULL_VOID(pipeline);
835     auto theme = pipeline->GetTheme<SelectTheme>();
836     CHECK_NULL_VOID(theme);
837     if (selectedFont_.FontColor.has_value()) {
838         newSelected->SetFontColor(selectedFont_.FontColor.value());
839     } else {
840         auto selectedColorText = theme->GetSelectedColorText();
841         newSelected->SetFontColor(selectedColorText);
842     }
843     if (selectedFont_.FontFamily.has_value()) {
844         newSelected->SetFontFamily(selectedFont_.FontFamily.value());
845     }
846     if (selectedFont_.FontSize.has_value()) {
847         newSelected->SetFontSize(selectedFont_.FontSize.value());
848     }
849     if (selectedFont_.FontStyle.has_value()) {
850         newSelected->SetItalicFontStyle(selectedFont_.FontStyle.value());
851     }
852     if (selectedFont_.FontWeight.has_value()) {
853         newSelected->SetFontWeight(selectedFont_.FontWeight.value());
854     }
855     if (selectedBgColor_.has_value()) {
856         newSelected->SetBgColor(selectedBgColor_.value());
857     } else {
858         auto selectedColor = theme->GetSelectedColor();
859         newSelected->SetBgColor(selectedColor);
860     }
861     newSelected->UpdateNextNodeDivider(false);
862     auto newSelectedNode = newSelected->GetHost();
863     CHECK_NULL_VOID(newSelectedNode);
864     auto newSelectedPros = newSelectedNode->GetPaintProperty<OptionPaintProperty>();
865     CHECK_NULL_VOID(newSelectedPros);
866     newSelectedPros->UpdateNeedDivider(false);
867 }
868 
UpdateText(int32_t index)869 void SelectPattern::UpdateText(int32_t index)
870 {
871     // update text to selected option's text
872     CHECK_NULL_VOID(text_);
873     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
874     CHECK_NULL_VOID(textProps);
875     if (index >= static_cast<int32_t>(options_.size()) || index < 0) {
876         return;
877     }
878     auto newSelected = options_[index]->GetPattern<OptionPattern>();
879     CHECK_NULL_VOID(newSelected);
880     textProps->UpdateContent(newSelected->GetText());
881     text_->MarkModifyDone();
882     auto host = GetHost();
883     CHECK_NULL_VOID(host);
884     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
885     selectValue_ = newSelected->GetText();
886 }
887 
InitTextProps(const RefPtr<TextLayoutProperty> & textProps,const RefPtr<SelectTheme> & theme)888 void SelectPattern::InitTextProps(const RefPtr<TextLayoutProperty>& textProps, const RefPtr<SelectTheme>& theme)
889 {
890     textProps->UpdateFontSize(theme->GetFontSize());
891     textProps->UpdateFontWeight(FontWeight::MEDIUM);
892     textProps->UpdateTextColor(theme->GetFontColor());
893     textProps->UpdateTextDecoration(theme->GetTextDecoration());
894     textProps->UpdateTextOverflow(TextOverflow::ELLIPSIS);
895     textProps->UpdateMaxLines(SELECT_ITSELF_TEXT_LINES);
896 }
897 
InitSpinner(const RefPtr<FrameNode> & spinner,const RefPtr<IconTheme> & iconTheme,const RefPtr<SelectTheme> & selectTheme)898 void SelectPattern::InitSpinner(
899     const RefPtr<FrameNode>& spinner, const RefPtr<IconTheme>& iconTheme, const RefPtr<SelectTheme>& selectTheme)
900 {
901     ImageSourceInfo imageSourceInfo;
902     auto iconPath = iconTheme->GetIconPath(InternalResource::ResourceId::SPINNER);
903     imageSourceInfo.SetSrc(iconPath);
904     imageSourceInfo.SetFillColor(selectTheme->GetSpinnerColor());
905 
906     auto spinnerLayoutProperty = spinner->GetLayoutProperty<ImageLayoutProperty>();
907     CHECK_NULL_VOID(spinnerLayoutProperty);
908     spinnerLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
909     CalcSize idealSize = { CalcLength(selectTheme->GetSpinnerWidth()), CalcLength(selectTheme->GetSpinnerHeight()) };
910     MeasureProperty layoutConstraint;
911     layoutConstraint.selfIdealSize = idealSize;
912     spinnerLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
913     auto spinnerRenderProperty = spinner->GetPaintProperty<ImageRenderProperty>();
914     CHECK_NULL_VOID(spinnerRenderProperty);
915     spinnerRenderProperty->UpdateSvgFillColor(selectTheme->GetSpinnerColor());
916 }
917 
InitSpinner(const RefPtr<FrameNode> & spinner,const RefPtr<SelectTheme> & selectTheme)918 void SelectPattern::InitSpinner(
919     const RefPtr<FrameNode>& spinner, const RefPtr<SelectTheme>& selectTheme)
920 {
921     auto spinnerLayoutProperty = spinner->GetLayoutProperty<TextLayoutProperty>();
922     CHECK_NULL_VOID(spinnerLayoutProperty);
923     uint32_t symbolId = selectTheme->GetSpinnerSource();
924     spinnerLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo{symbolId});
925     spinnerLayoutProperty->UpdateSymbolColorList({selectTheme->GetSpinnerSymbolColor()});
926     spinnerLayoutProperty->UpdateFontSize(selectTheme->GetFontSize());
927 }
928 
929 // XTS inspector code
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const930 void SelectPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
931 {
932     /* no fixed attr below, just return */
933     if (filter.IsFastFilter()) {
934         ToJsonArrowAndText(json, filter);
935         ToJsonOptionAlign(json, filter);
936         ToJsonMenuBackgroundStyle(json, filter);
937         return;
938     }
939     json->PutExtAttr("options", InspectorGetOptions().c_str(), filter);
940     json->PutExtAttr("selected", std::to_string(selected_).c_str(), filter);
941     ToJsonArrowAndText(json, filter);
942     json->PutExtAttr("selectedOptionBgColor", selectedBgColor_->ColorToString().c_str(), filter);
943     json->PutExtAttr("selectedOptionFont", InspectorGetSelectedFont().c_str(), filter);
944     json->PutExtAttr("selectedOptionFontColor",
945         selectedFont_.FontColor.value_or(Color::BLACK).ColorToString().c_str(), filter);
946 
947     if (options_.empty()) {
948         json->PutExtAttr("optionBgColor", "", filter);
949         json->PutExtAttr("optionFont", "", filter);
950         json->PutExtAttr("optionFontColor", "", filter);
951     } else {
952         auto optionPattern = options_[0]->GetPattern<OptionPattern>();
953         CHECK_NULL_VOID(optionPattern);
954         json->PutExtAttr("optionBgColor", optionPattern->GetBgColor().ColorToString().c_str(), filter);
955         json->PutExtAttr("optionFont", optionPattern->InspectorGetFont().c_str(), filter);
956         json->PutExtAttr("optionFontColor", optionPattern->GetFontColor().ColorToString().c_str(), filter);
957     }
958     ToJsonOptionAlign(json, filter);
959     for (size_t i = 0; i < options_.size(); ++i) {
960         auto optionPaintProperty = options_[i]->GetPaintProperty<OptionPaintProperty>();
961         CHECK_NULL_VOID(optionPaintProperty);
962         std::string optionWidth = std::to_string(optionPaintProperty->GetSelectModifiedWidthValue(0.0f));
963         json->PutExtAttr("optionWidth", optionWidth.c_str(), filter);
964     }
965 
966     auto menu = GetMenuNode();
967     CHECK_NULL_VOID(menu);
968     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
969     CHECK_NULL_VOID(menuLayoutProps);
970     std::string optionHeight =  std::to_string(menuLayoutProps->GetSelectModifiedHeightValue(0.0f));
971     json->PutExtAttr("optionHeight", optionHeight.c_str(), filter);
972     ToJsonMenuBackgroundStyle(json, filter);
973     ToJsonDivider(json, filter);
974 }
975 
ToJsonArrowAndText(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const976 void SelectPattern::ToJsonArrowAndText(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
977 {
978     /* no fixed attr below, just return */
979     if (filter.IsFastFilter()) {
980         return;
981     }
982     auto host = GetHost();
983     CHECK_NULL_VOID(host);
984     if (!host->GetChildren().empty()) {
985         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
986         CHECK_NULL_VOID(row);
987         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
988         CHECK_NULL_VOID(rowProps);
989         json->PutExtAttr("space", rowProps->GetSpace()->ToString().c_str(), filter);
990 
991         if (rowProps->GetFlexDirection().value() == FlexDirection::ROW) {
992             json->PutExtAttr("arrowPosition", "ArrowPosition.END", filter);
993         } else {
994             json->PutExtAttr("arrowPosition", "ArrowPosition.START", filter);
995         }
996     }
997 
998     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
999     CHECK_NULL_VOID(props);
1000     json->PutExtAttr("value", props->GetContent().value_or("").c_str(), filter);
1001     Color fontColor = props->GetTextColor().value_or(Color::BLACK);
1002     json->PutExtAttr("fontColor", fontColor.ColorToString().c_str(), filter);
1003     json->PutExtAttr("font", props->InspectorGetTextFont().c_str(), filter);
1004     json->PutExtAttr("controlSize", ConvertControlSizeToString(controlSize_).c_str(), filter);
1005 }
1006 
ToJsonMenuBackgroundStyle(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1007 void SelectPattern::ToJsonMenuBackgroundStyle(
1008     std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1009 {
1010     /* no fixed attr below, just return */
1011     if (filter.IsFastFilter()) {
1012         return;
1013     }
1014     auto menu = GetMenuNode();
1015     CHECK_NULL_VOID(menu);
1016     auto menuRenderContext = menu->GetRenderContext();
1017     CHECK_NULL_VOID(menuRenderContext);
1018     json->PutExtAttr("menuBackgroundColor",
1019         menuRenderContext->GetBackgroundColor()->ColorToString().c_str(), filter);
1020     if (menuRenderContext->GetBackBlurStyle().has_value()) {
1021         BlurStyleOption blurStyleOption = menuRenderContext->GetBackBlurStyle().value();
1022         auto jsonValue = JsonUtil::Create(true);
1023         blurStyleOption.ToJsonValue(jsonValue, filter);
1024         json->PutExtAttr("menuBackgroundBlurStyle",
1025             jsonValue->GetValue("backgroundBlurStyle")->GetValue("value"), filter);
1026     } else {
1027         json->PutExtAttr("menuBackgroundBlurStyle", "", filter);
1028     }
1029 }
1030 
ToJsonDivider(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1031 void SelectPattern::ToJsonDivider(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1032 {
1033     /* no fixed attr below, just return */
1034     if (filter.IsFastFilter()) {
1035         return;
1036     }
1037     if (options_.empty()) {
1038         json->PutExtAttr("divider", "", filter);
1039     } else {
1040         auto props = options_[0]->GetPaintProperty<OptionPaintProperty>();
1041         CHECK_NULL_VOID(props);
1042         auto divider = JsonUtil::Create(true);
1043         if (props->HasDivider()) {
1044             divider->Put("strokeWidth", props->GetDividerValue().strokeWidth.ToString().c_str());
1045             divider->Put("startMargin", props->GetDividerValue().startMargin.ToString().c_str());
1046             divider->Put("endMargin", props->GetDividerValue().endMargin.ToString().c_str());
1047             divider->Put("color", props->GetDividerValue().color.ColorToString().c_str());
1048             json->PutExtAttr("divider", divider->ToString().c_str(), filter);
1049         } else {
1050             json->PutExtAttr("divider", "", filter);
1051         }
1052     }
1053 }
1054 
ToJsonOptionAlign(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1055 void SelectPattern::ToJsonOptionAlign(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1056 {
1057     /* no fixed attr below, just return */
1058     if (filter.IsFastFilter()) {
1059         return;
1060     }
1061     auto optionAlignJson = JsonUtil::Create(true);
1062     std::string alignTypeString = "MenuAlignType.Start";
1063     if (menuAlign_.alignType == MenuAlignType::START) {
1064         alignTypeString = "MenuAlignType.Start";
1065     } else if (menuAlign_.alignType == MenuAlignType::CENTER) {
1066         alignTypeString = "MenuAlignType.Center";
1067     } else if (menuAlign_.alignType == MenuAlignType::END) {
1068         alignTypeString = "MenuAlignType.End";
1069     }
1070     optionAlignJson->Put("alignType", alignTypeString.c_str());
1071 
1072     auto offsetValueJson = JsonUtil::Create(true);
1073     offsetValueJson->Put("dX", menuAlign_.offset.GetX().Value());
1074     offsetValueJson->Put("dY", menuAlign_.offset.GetY().Value());
1075     optionAlignJson->Put("offset", offsetValueJson);
1076 
1077     json->PutExtAttr("menuAlign", optionAlignJson, filter);
1078 }
1079 
InspectorGetOptions() const1080 std::string SelectPattern::InspectorGetOptions() const
1081 {
1082     auto jsonValue = JsonUtil::Create(true);
1083     auto jsonOptions = JsonUtil::CreateArray(true);
1084     for (size_t i = 0; i < options_.size(); ++i) {
1085         auto temp = JsonUtil::Create(true);
1086         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
1087         temp->Put("value", optionPattern->GetText().c_str());
1088         temp->Put("icon", optionPattern->GetIcon().c_str());
1089         auto index = std::to_string(i);
1090         jsonOptions->Put(index.c_str(), temp);
1091     }
1092     jsonValue->Put("options", jsonOptions);
1093     return jsonValue->ToString();
1094 }
1095 
InspectorGetSelectedFont() const1096 std::string SelectPattern::InspectorGetSelectedFont() const
1097 {
1098     TextStyle font;
1099     if (selectedFont_.FontFamily.has_value()) {
1100         font.SetFontFamilies(selectedFont_.FontFamily.value());
1101     }
1102     if (selectedFont_.FontSize.has_value()) {
1103         font.SetFontSize(selectedFont_.FontSize.value());
1104     }
1105     if (selectedFont_.FontStyle.has_value()) {
1106         font.SetFontStyle(selectedFont_.FontStyle.value());
1107     }
1108     if (selectedFont_.FontWeight.has_value()) {
1109         font.SetFontWeight(selectedFont_.FontWeight.value());
1110     }
1111     return V2::GetTextStyleInJson(font);
1112 }
1113 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1114 bool SelectPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1115 {
1116     auto geometryNode = dirty->GetGeometryNode();
1117     CHECK_NULL_RETURN(geometryNode, false);
1118     SetSelectSize(geometryNode->GetFrameSize());
1119     return false;
1120 }
1121 
SetSpace(const Dimension & value)1122 void SelectPattern::SetSpace(const Dimension& value)
1123 {
1124     auto host = GetHost();
1125     CHECK_NULL_VOID(host);
1126     if (!host->GetChildren().empty()) {
1127         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1128         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1129         rowProps->UpdateSpace(value);
1130         row->MarkModifyDone();
1131         row->MarkDirtyNode();
1132     }
1133 }
1134 
SetArrowPosition(const ArrowPosition value)1135 void SelectPattern::SetArrowPosition(const ArrowPosition value)
1136 {
1137     auto host = GetHost();
1138     CHECK_NULL_VOID(host);
1139     if (!host->GetChildren().empty()) {
1140         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1141         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1142 
1143         if (value == ArrowPosition::END) {
1144             rowProps->UpdateFlexDirection(FlexDirection::ROW);
1145         } else {
1146             rowProps->UpdateFlexDirection(FlexDirection::ROW_REVERSE);
1147         }
1148         row->MarkModifyDone();
1149         row->MarkDirtyNode();
1150     }
1151 }
1152 
GetValue()1153 std::string SelectPattern::GetValue()
1154 {
1155     CHECK_NULL_RETURN(text_, "");
1156     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
1157     CHECK_NULL_RETURN(textProps, "");
1158     return textProps->GetContentValue("");
1159 }
1160 
SetMenuAlign(const MenuAlign & menuAlign)1161 void SelectPattern::SetMenuAlign(const MenuAlign& menuAlign)
1162 {
1163     menuAlign_ = menuAlign;
1164     auto menu = GetMenuNode();
1165     CHECK_NULL_VOID(menu);
1166     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1167     CHECK_NULL_VOID(menuLayoutProps);
1168     menuLayoutProps->UpdateAlignType(menuAlign.alignType);
1169     menuLayoutProps->UpdateOffset(menuAlign.offset);
1170 }
1171 
ProvideRestoreInfo()1172 std::string SelectPattern::ProvideRestoreInfo()
1173 {
1174     auto jsonObj = JsonUtil::Create(true);
1175     jsonObj->Put("selected", selected_);
1176     jsonObj->Put("isSelected", isSelected_);
1177     return jsonObj->ToString();
1178 }
1179 
OnRestoreInfo(const std::string & restoreInfo)1180 void SelectPattern::OnRestoreInfo(const std::string& restoreInfo)
1181 {
1182     auto info = JsonUtil::ParseJsonString(restoreInfo);
1183     if (!info->IsValid() || !info->IsObject()) {
1184         return;
1185     }
1186     auto jsonIsOn = info->GetValue("selected");
1187     auto jsonIsSelect = info->GetValue("isSelected");
1188     if (jsonIsSelect->GetBool()) {
1189         SetSelected(jsonIsOn->GetInt());
1190         UpdateText(jsonIsOn->GetInt());
1191     }
1192 }
1193 
OnColorConfigurationUpdate()1194 void SelectPattern::OnColorConfigurationUpdate()
1195 {
1196     auto host = GetHost();
1197     CHECK_NULL_VOID(host);
1198     auto pipeline = host->GetContextWithCheck();
1199     CHECK_NULL_VOID(pipeline);
1200     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1201     CHECK_NULL_VOID(selectTheme);
1202 
1203     auto pattern = host->GetPattern<SelectPattern>();
1204     auto menuNode = pattern->GetMenuNode();
1205     CHECK_NULL_VOID(menuNode);
1206     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1207     CHECK_NULL_VOID(menuPattern);
1208 
1209     auto renderContext = menuNode->GetRenderContext();
1210     renderContext->UpdateBackgroundColor(selectTheme->GetBackgroundColor());
1211     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && renderContext->IsUniRenderEnabled()) {
1212         renderContext->UpdateBackBlurStyle(renderContext->GetBackBlurStyle());
1213     }
1214 
1215     auto optionNode = menuPattern->GetOptions();
1216     for (auto child : optionNode) {
1217         auto optionsPattern = child->GetPattern<OptionPattern>();
1218         optionsPattern->SetFontColor(selectTheme->GetFontColor());
1219 
1220         child->MarkModifyDone();
1221         child->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1222     }
1223     SetOptionBgColor(selectTheme->GetBackgroundColor());
1224     host->SetNeedCallChildrenUpdate(false);
1225 }
1226 
OnLanguageConfigurationUpdate()1227 void SelectPattern::OnLanguageConfigurationUpdate()
1228 {
1229     auto host = GetHost();
1230     CHECK_NULL_VOID(host);
1231     auto context = host->GetContextRefPtr();
1232     CHECK_NULL_VOID(context);
1233     auto taskExecutor = context->GetTaskExecutor();
1234     CHECK_NULL_VOID(taskExecutor);
1235     taskExecutor->PostTask(
1236         [weak = WeakClaim(this)]() {
1237             auto pattern = weak.Upgrade();
1238             CHECK_NULL_VOID(pattern);
1239             auto index = pattern->selected_;
1240             pattern->UpdateText(index);
1241             auto host = pattern->GetHost();
1242             CHECK_NULL_VOID(host);
1243             auto hub = host->GetEventHub<SelectEventHub>();
1244             CHECK_NULL_VOID(hub);
1245             if (index >= static_cast<int32_t>(pattern->options_.size()) || index < 0) {
1246                 return;
1247             }
1248             auto newSelected = pattern->options_[index]->GetPattern<OptionPattern>();
1249             CHECK_NULL_VOID(newSelected);
1250             auto value = newSelected->GetText();
1251             auto valueChangeEvent = hub->GetValueChangeEvent();
1252             if (valueChangeEvent) {
1253                 valueChangeEvent(value);
1254             }
1255             auto onSelect = hub->GetSelectEvent();
1256             if (onSelect) {
1257                 onSelect(index, value);
1258             }
1259         },
1260         TaskExecutor::TaskType::UI, "ArkUISelectLanguageConfigUpdate");
1261 }
1262 
GetFontSize()1263 Dimension SelectPattern::GetFontSize()
1264 {
1265     Dimension defaultRet = Dimension();
1266     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
1267     CHECK_NULL_RETURN(props, defaultRet);
1268     auto host = props->GetHost();
1269     CHECK_NULL_RETURN(host, defaultRet);
1270     auto pipeline = host->GetContextWithCheck();
1271     CHECK_NULL_RETURN(pipeline, defaultRet);
1272     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1273     CHECK_NULL_RETURN(selectTheme, defaultRet);
1274     return props->GetFontSize().value_or(selectTheme->GetFontSize());
1275 }
1276 
SetSelectDefaultTheme()1277 void SelectPattern::SetSelectDefaultTheme()
1278 {
1279     auto select = GetHost();
1280     CHECK_NULL_VOID(select);
1281     auto pipeline = select->GetContextWithCheck();
1282     CHECK_NULL_VOID(pipeline);
1283     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1284     CHECK_NULL_VOID(selectTheme);
1285 
1286     auto renderContext = select->GetRenderContext();
1287     CHECK_NULL_VOID(renderContext);
1288 
1289     if (selectDefaultBgColor_ == Color::TRANSPARENT) {
1290         renderContext->UpdateBackgroundColor(selectTheme->GetSelectDefaultBgColor());
1291     } else {
1292         renderContext->UpdateBackgroundColor(selectDefaultBgColor_);
1293     }
1294     BorderRadiusProperty border;
1295     border.SetRadius(selectTheme->GetSelectDefaultBorderRadius());
1296     renderContext->UpdateBorderRadius(border);
1297 }
1298 
SetOptionWidth(const Dimension & value)1299 void SelectPattern::SetOptionWidth(const Dimension& value)
1300 {
1301     isFitTrigger_ = false;
1302     auto menu = GetMenuNode();
1303     CHECK_NULL_VOID(menu);
1304     auto menuPattern = menu->GetPattern<MenuPattern>();
1305     CHECK_NULL_VOID(menuPattern);
1306     menuPattern->SetIsWidthModifiedBySelect(true);
1307     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1308     CHECK_NULL_VOID(menuLayoutProps);
1309     menuLayoutProps->UpdateSelectMenuModifiedWidth(value.ConvertToPx() + OPTION_MARGIN.ConvertToPx());
1310 
1311     auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1312     CHECK_NULL_VOID(scroll);
1313     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1314     CHECK_NULL_VOID(scrollPattern);
1315     scrollPattern->SetIsWidthModifiedBySelect(true);
1316     auto scrollLayoutProps = scroll->GetLayoutProperty<ScrollLayoutProperty>();
1317     CHECK_NULL_VOID(scrollLayoutProps);
1318     scrollLayoutProps->UpdateScrollWidth(value.ConvertToPx() + OPTION_MARGIN.ConvertToPx());
1319 
1320     for (size_t i = 0; i < options_.size(); ++i) {
1321         auto optionWidth = value.ConvertToPx();
1322         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
1323         CHECK_NULL_VOID(optionPattern);
1324         optionPattern->SetIsWidthModifiedBySelect(true);
1325         auto optionPaintProperty = options_[i]->GetPaintProperty<OptionPaintProperty>();
1326         CHECK_NULL_VOID(optionPaintProperty);
1327         optionPaintProperty->UpdateSelectModifiedWidth(optionWidth);
1328     }
1329 }
1330 
SetOptionWidthFitTrigger(bool isFitTrigger)1331 void SelectPattern::SetOptionWidthFitTrigger(bool isFitTrigger)
1332 {
1333     isFitTrigger_ = isFitTrigger;
1334 }
1335 
SetHasOptionWidth(bool hasOptionWidth)1336 void SelectPattern::SetHasOptionWidth(bool hasOptionWidth)
1337 {
1338     auto menu = GetMenuNode();
1339     CHECK_NULL_VOID(menu);
1340     auto menuPattern = menu->GetPattern<MenuPattern>();
1341     CHECK_NULL_VOID(menuPattern);
1342     menuPattern->SetHasOptionWidth(true);
1343     auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1344     CHECK_NULL_VOID(scroll);
1345     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1346     CHECK_NULL_VOID(scrollPattern);
1347     scrollPattern->SetHasOptionWidth(true);
1348     for (size_t i = 0; i < options_.size(); ++i) {
1349         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
1350         CHECK_NULL_VOID(optionPattern);
1351         optionPattern->SetHasOptionWidth(true);
1352     }
1353 }
1354 
SetOptionHeight(const Dimension & value)1355 void SelectPattern::SetOptionHeight(const Dimension& value)
1356 {
1357     auto menuMaxHeight = value.ConvertToPx();
1358     auto menu = GetMenuNode();
1359     CHECK_NULL_VOID(menu);
1360     auto menuPattern = menu->GetPattern<MenuPattern>();
1361     CHECK_NULL_VOID(menuPattern);
1362     menuPattern->SetIsHeightModifiedBySelect(true);
1363     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1364     CHECK_NULL_VOID(menuLayoutProps);
1365     menuLayoutProps->UpdateSelectModifiedHeight(menuMaxHeight);
1366 }
1367 
SetMenuBackgroundColor(const Color & color)1368 void SelectPattern::SetMenuBackgroundColor(const Color& color)
1369 {
1370     auto menu = GetMenuNode();
1371     CHECK_NULL_VOID(menu);
1372     auto renderContext = menu->GetRenderContext();
1373     CHECK_NULL_VOID(renderContext);
1374     renderContext->UpdateBackgroundColor(color);
1375 }
1376 
SetMenuBackgroundBlurStyle(const BlurStyleOption & blurStyle)1377 void SelectPattern::SetMenuBackgroundBlurStyle(const BlurStyleOption& blurStyle)
1378 {
1379     auto menu = GetMenuNode();
1380     CHECK_NULL_VOID(menu);
1381     auto renderContext = menu->GetRenderContext();
1382     CHECK_NULL_VOID(renderContext);
1383     renderContext->UpdateBackBlurStyle(blurStyle);
1384 }
1385 
ResetParams()1386 void SelectPattern::ResetParams()
1387 {
1388     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1389         return;
1390     }
1391     auto select = GetHost();
1392     CHECK_NULL_VOID(select);
1393     auto* pipeline = select->GetContextWithCheck();
1394     CHECK_NULL_VOID(pipeline);
1395     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1396     CHECK_NULL_VOID(selectTheme);
1397     auto layoutProperty = select->GetLayoutProperty();
1398     CHECK_NULL_VOID(layoutProperty);
1399     layoutProperty->UpdateCalcMinSize(CalcSize(CalcLength(selectTheme->GetSelectMinWidth(controlSize_)),
1400         CalcLength(selectTheme->GetSelectDefaultHeight(controlSize_))));
1401     SetFontSize(selectTheme->GetFontSize(controlSize_));
1402     auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
1403     CHECK_NULL_VOID(spinnerLayoutProperty);
1404     spinnerLayoutProperty->UpdateFontSize(selectTheme->GetFontSize(controlSize_));
1405     auto renderContext = select->GetRenderContext();
1406     BorderRadiusProperty border;
1407     border.SetRadius(selectTheme->GetSelectDefaultBorderRadius(controlSize_));
1408     renderContext->UpdateBorderRadius(border);
1409 
1410     NG::PaddingProperty paddings;
1411     paddings.top = std::nullopt;
1412     paddings.bottom = std::nullopt;
1413     if (controlSize_ == ControlSize::SMALL) {
1414         paddings.left = NG::CalcLength(SELECT_SMALL_PADDING_VP);
1415         paddings.right = NG::CalcLength(SELECT_SMALL_PADDING_VP);
1416     } else {
1417         paddings.left = NG::CalcLength(SELECT_MARGIN_VP);
1418         paddings.right = NG::CalcLength(SELECT_MARGIN_VP);
1419     }
1420     ViewAbstract::SetPadding(paddings);
1421 }
1422 
SetControlSize(const ControlSize & controlSize)1423 void SelectPattern::SetControlSize(const ControlSize& controlSize)
1424 {
1425     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1426         return;
1427     }
1428     controlSize_ = controlSize;
1429     ResetParams();
1430 }
1431 
SetLayoutDirection(TextDirection value)1432 void SelectPattern::SetLayoutDirection(TextDirection value)
1433 {
1434     auto select = GetHost();
1435     auto menu = GetMenuNode();
1436     std::function<void (decltype(select))> updateDirectionFunc = [&](decltype(select) node) {
1437         if (!node) return;
1438         auto updateProperty = node->GetLayoutProperty();
1439         updateProperty->UpdateLayoutDirection(value);
1440         if (node->GetHostTag() == V2::SCROLL_ETS_TAG) {
1441             auto scrollPattern = AceType::DynamicCast<ScrollPattern>(node->GetPattern());
1442             if (scrollPattern) scrollPattern->TriggerModifyDone();
1443         }
1444         for (auto child : node->GetAllChildrenWithBuild()) {
1445             auto frameNode = AceType::DynamicCast<FrameNode>(child);
1446             if (!frameNode) continue;
1447             updateDirectionFunc(frameNode);
1448         }
1449     };
1450     updateDirectionFunc(select);
1451     updateDirectionFunc(menu);
1452 }
1453 
GetControlSize()1454 ControlSize SelectPattern::GetControlSize()
1455 {
1456     return controlSize_;
1457 }
1458 
SetDivider(const SelectDivider & divider)1459 void SelectPattern::SetDivider(const SelectDivider& divider)
1460 {
1461     for (auto&& option : options_) {
1462         auto props = option->GetPaintProperty<OptionPaintProperty>();
1463         CHECK_NULL_VOID(props);
1464         props->UpdateDivider(divider);
1465     }
1466 }
1467 } // namespace OHOS::Ace::NG
1468