• 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(false, true);
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         SystemProperties::IsNeedSymbol()) {
443         auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
444         CHECK_NULL_VOID(spinnerLayoutProperty);
445         spinnerLayoutProperty->UpdateSymbolColorList({theme->GetDisabledSpinnerSymbolColor()});
446     } else {
447         auto spinnerLayoutProperty = spinner_->GetLayoutProperty<ImageLayoutProperty>();
448         CHECK_NULL_VOID(spinnerLayoutProperty);
449 
450         ImageSourceInfo imageSourceInfo = spinnerLayoutProperty->GetImageSourceInfo().value_or(ImageSourceInfo());
451         auto iconTheme = pipeline->GetTheme<IconTheme>();
452         CHECK_NULL_VOID(iconTheme);
453         auto iconPath = iconTheme->GetIconPath(InternalResource::ResourceId::SPINNER_DISABLE);
454         imageSourceInfo.SetSrc(iconPath);
455         if (imageSourceInfo.IsSvg()) {
456             imageSourceInfo.SetFillColor(theme->GetDisabledSpinnerColor());
457         }
458         spinnerLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
459         auto spinnerRenderProperty = spinner_->GetPaintProperty<ImageRenderProperty>();
460         CHECK_NULL_VOID(spinnerRenderProperty);
461         spinnerRenderProperty->UpdateSvgFillColor(theme->GetDisabledSpinnerColor());
462     }
463     spinner_->MarkModifyDone();
464 
465     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
466         auto renderContext = host->GetRenderContext();
467         CHECK_NULL_VOID(renderContext);
468         renderContext->UpdateBackgroundColor(renderContext->GetBackgroundColor()
469                                                  .value_or(theme->GetButtonBackgroundColor())
470                                                  .BlendOpacity(theme->GetDisabledFontColorAlpha()));
471     }
472 }
473 
SetSelected(int32_t index)474 void SelectPattern::SetSelected(int32_t index)
475 {
476     // if option is already selected, do nothing
477     if (index == selected_) {
478         return;
479     }
480     if (index >= static_cast<int32_t>(options_.size()) || index < 0) {
481         selected_ = -1;
482         ResetOptionProps();
483         return;
484     }
485     UpdateLastSelectedProps(index);
486     selected_ = index;
487 }
488 
AddOptionNode(const RefPtr<FrameNode> & option)489 void SelectPattern::AddOptionNode(const RefPtr<FrameNode>& option)
490 {
491     CHECK_NULL_VOID(option);
492     options_.push_back(option);
493 }
494 
BuildChild()495 void SelectPattern::BuildChild()
496 {
497     auto select = GetHost();
498     CHECK_NULL_VOID(select);
499     // get theme from SelectThemeManager
500     auto* pipeline = select->GetContextWithCheck();
501     CHECK_NULL_VOID(pipeline);
502     auto theme = pipeline->GetTheme<SelectTheme>();
503     CHECK_NULL_VOID(theme);
504 
505     bool hasRowNode = HasRowNode();
506     bool hasTextNode = HasTextNode();
507     bool hasSpinnerNode = HasSpinnerNode();
508     auto rowId = GetRowId();
509     auto textId = GetTextId();
510     auto spinnerId = GetSpinnerId();
511 
512     auto row = FrameNode::GetOrCreateFrameNode(
513         V2::ROW_ETS_TAG, rowId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
514     CHECK_NULL_VOID(row);
515     row->SetInternal();
516     auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
517     CHECK_NULL_VOID(rowProps);
518     rowProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
519     rowProps->UpdateCrossAxisAlign(FlexAlign::CENTER);
520     rowProps->UpdateFlexDirection(FlexDirection::ROW);
521     rowProps->UpdateSpace(theme->GetContentSpinnerPadding());
522     text_ =
523         FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG, textId, []() { return AceType::MakeRefPtr<TextPattern>(); });
524     CHECK_NULL_VOID(text_);
525     text_->SetInternal();
526     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
527     CHECK_NULL_VOID(textProps);
528     InitTextProps(textProps, theme);
529     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE) &&
530         SystemProperties::IsNeedSymbol()) {
531         spinner_ = FrameNode::GetOrCreateFrameNode(
532             V2::SYMBOL_ETS_TAG, spinnerId, []() { return AceType::MakeRefPtr<TextPattern>(); });
533         CHECK_NULL_VOID(spinner_);
534         spinner_->SetInternal();
535         InitSpinner(spinner_, theme);
536     } else {
537         spinner_ = FrameNode::GetOrCreateFrameNode(
538             V2::IMAGE_ETS_TAG, spinnerId, []() { return AceType::MakeRefPtr<ImagePattern>(); });
539         CHECK_NULL_VOID(spinner_);
540         spinner_->SetInternal();
541         auto iconTheme = pipeline->GetTheme<IconTheme>();
542         CHECK_NULL_VOID(iconTheme);
543         InitSpinner(spinner_, iconTheme, theme);
544     }
545     // mount triangle and text
546     text_->MarkModifyDone();
547     if (!hasTextNode) {
548         text_->MountToParent(row);
549     }
550     spinner_->MarkModifyDone();
551     if (!hasSpinnerNode) {
552         spinner_->MountToParent(row);
553     }
554     if (!hasRowNode) {
555         row->MountToParent(select);
556     }
557     row->MarkModifyDone();
558     row->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
559 
560     // set bgColor and border
561     auto renderContext = select->GetRenderContext();
562     CHECK_NULL_VOID(renderContext);
563     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
564         renderContext->UpdateBackgroundColor(theme->GetBackgroundColor());
565     } else {
566         renderContext->UpdateBackgroundColor(theme->GetButtonBackgroundColor());
567     }
568     renderContext->SetClipToFrame(true);
569     BorderRadiusProperty border;
570     border.SetRadius(theme->GetSelectBorderRadius());
571     renderContext->UpdateBorderRadius(border);
572 }
573 
SetValue(const std::string & value)574 void SelectPattern::SetValue(const std::string& value)
575 {
576     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
577     CHECK_NULL_VOID(props);
578     props->UpdateContent(value);
579     auto pattern = text_->GetPattern<TextPattern>();
580     CHECK_NULL_VOID(pattern);
581     auto modifier = pattern->GetContentModifier();
582     CHECK_NULL_VOID(modifier);
583     modifier->ContentChange();
584     selectValue_ = value;
585 }
586 
SetFontSize(const Dimension & value)587 void SelectPattern::SetFontSize(const Dimension& value)
588 {
589     if (value.IsNegative()) {
590         return;
591     }
592     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
593     CHECK_NULL_VOID(props);
594     props->UpdateFontSize(value);
595 }
596 
SetItalicFontStyle(const Ace::FontStyle & value)597 void SelectPattern::SetItalicFontStyle(const Ace::FontStyle& value)
598 {
599     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
600     CHECK_NULL_VOID(props);
601     props->UpdateItalicFontStyle(value);
602 }
603 
SetFontWeight(const FontWeight & value)604 void SelectPattern::SetFontWeight(const FontWeight& value)
605 {
606     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
607     CHECK_NULL_VOID(props);
608     props->UpdateFontWeight(value);
609 }
610 
SetFontFamily(const std::vector<std::string> & value)611 void SelectPattern::SetFontFamily(const std::vector<std::string>& value)
612 {
613     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
614     CHECK_NULL_VOID(props);
615     props->UpdateFontFamily(value);
616 }
617 
SetFontColor(const Color & color)618 void SelectPattern::SetFontColor(const Color& color)
619 {
620     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
621     CHECK_NULL_VOID(props);
622     props->UpdateTextColor(color);
623     auto context = text_->GetRenderContext();
624     context->UpdateForegroundColor(color);
625     context->UpdateForegroundColorFlag(false);
626     context->ResetForegroundColorStrategy();
627 }
628 
SetOptionBgColor(const Color & color)629 void SelectPattern::SetOptionBgColor(const Color& color)
630 {
631     optionBgColor_ = color;
632     for (size_t i = 0; i < options_.size(); ++i) {
633         if (static_cast<int32_t>(i) == selected_ && selectedBgColor_.has_value()) {
634             continue;
635         }
636         auto pattern = options_[i]->GetPattern<OptionPattern>();
637         CHECK_NULL_VOID(pattern);
638         pattern->SetBgColor(color);
639     }
640 }
641 
SetOptionFontSize(const Dimension & value)642 void SelectPattern::SetOptionFontSize(const Dimension& value)
643 {
644     optionFont_.FontSize = value;
645     for (size_t i = 0; i < options_.size(); ++i) {
646         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontSize.has_value()) {
647             continue;
648         }
649         auto pattern = options_[i]->GetPattern<OptionPattern>();
650         CHECK_NULL_VOID(pattern);
651         pattern->SetFontSize(value);
652     }
653 }
654 
SetOptionItalicFontStyle(const Ace::FontStyle & value)655 void SelectPattern::SetOptionItalicFontStyle(const Ace::FontStyle& value)
656 {
657     optionFont_.FontStyle = value;
658     for (size_t i = 0; i < options_.size(); ++i) {
659         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontStyle.has_value()) {
660             continue;
661         }
662         auto pattern = options_[i]->GetPattern<OptionPattern>();
663         CHECK_NULL_VOID(pattern);
664         pattern->SetItalicFontStyle(value);
665     }
666 }
667 
SetOptionFontWeight(const FontWeight & value)668 void SelectPattern::SetOptionFontWeight(const FontWeight& value)
669 {
670     optionFont_.FontWeight = value;
671     for (size_t i = 0; i < options_.size(); ++i) {
672         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontWeight.has_value()) {
673             continue;
674         }
675         auto pattern = options_[i]->GetPattern<OptionPattern>();
676         CHECK_NULL_VOID(pattern);
677         pattern->SetFontWeight(value);
678     }
679 }
680 
SetOptionFontFamily(const std::vector<std::string> & value)681 void SelectPattern::SetOptionFontFamily(const std::vector<std::string>& value)
682 {
683     optionFont_.FontFamily = value;
684     for (size_t i = 0; i < options_.size(); ++i) {
685         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontFamily.has_value()) {
686             continue;
687         }
688         auto pattern = options_[i]->GetPattern<OptionPattern>();
689         CHECK_NULL_VOID(pattern);
690         pattern->SetFontFamily(value);
691     }
692 }
693 
SetOptionFontColor(const Color & color)694 void SelectPattern::SetOptionFontColor(const Color& color)
695 {
696     optionFont_.FontColor = color;
697     for (size_t i = 0; i < options_.size(); ++i) {
698         if (static_cast<int32_t>(i) == selected_ && selectedFont_.FontColor.has_value()) {
699             continue;
700         }
701         auto pattern = options_[i]->GetPattern<OptionPattern>();
702         CHECK_NULL_VOID(pattern);
703         pattern->SetFontColor(color);
704     }
705 }
706 
707 // set props of option node when selected
SetSelectedOptionBgColor(const Color & color)708 void SelectPattern::SetSelectedOptionBgColor(const Color& color)
709 {
710     selectedBgColor_ = color;
711     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
712         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
713         CHECK_NULL_VOID(pattern);
714         pattern->SetBgColor(color);
715     }
716 }
717 
SetSelectedOptionFontSize(const Dimension & value)718 void SelectPattern::SetSelectedOptionFontSize(const Dimension& value)
719 {
720     selectedFont_.FontSize = value;
721     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
722         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
723         CHECK_NULL_VOID(pattern);
724         pattern->SetFontSize(value);
725     }
726 }
727 
SetSelectedOptionItalicFontStyle(const Ace::FontStyle & value)728 void SelectPattern::SetSelectedOptionItalicFontStyle(const Ace::FontStyle& value)
729 {
730     selectedFont_.FontStyle = value;
731     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
732         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
733         CHECK_NULL_VOID(pattern);
734         pattern->SetItalicFontStyle(value);
735     }
736 }
737 
SetSelectedOptionFontWeight(const FontWeight & value)738 void SelectPattern::SetSelectedOptionFontWeight(const FontWeight& value)
739 {
740     selectedFont_.FontWeight = value;
741     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
742         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
743         CHECK_NULL_VOID(pattern);
744         pattern->SetFontWeight(value);
745     }
746 }
747 
SetSelectedOptionFontFamily(const std::vector<std::string> & value)748 void SelectPattern::SetSelectedOptionFontFamily(const std::vector<std::string>& value)
749 {
750     selectedFont_.FontFamily = value;
751     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
752         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
753         CHECK_NULL_VOID(pattern);
754         pattern->SetFontFamily(value);
755     }
756 }
757 
SetSelectedOptionFontColor(const Color & color)758 void SelectPattern::SetSelectedOptionFontColor(const Color& color)
759 {
760     selectedFont_.FontColor = color;
761     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
762         auto pattern = options_[selected_]->GetPattern<OptionPattern>();
763         CHECK_NULL_VOID(pattern);
764         pattern->SetFontColor(color);
765     }
766 }
767 
GetOptions()768 const std::vector<RefPtr<FrameNode>>& SelectPattern::GetOptions()
769 {
770     return options_;
771 }
772 
ResetOptionProps()773 void SelectPattern::ResetOptionProps()
774 {
775     auto host = GetHost();
776     CHECK_NULL_VOID(host);
777     auto pipeline = host->GetContextWithCheck();
778     CHECK_NULL_VOID(pipeline);
779     auto selectTheme = pipeline->GetTheme<SelectTheme>();
780     auto textTheme = pipeline->GetTheme<TextTheme>();
781     CHECK_NULL_VOID(selectTheme && textTheme);
782 
783     for (const auto& option : options_) {
784         auto pattern = option->GetPattern<OptionPattern>();
785         CHECK_NULL_VOID(pattern);
786         pattern->SetSelected(false);
787         pattern->SetBgColor(optionBgColor_.value_or(selectTheme->GetBackgroundColor()));
788         pattern->SetFontSize(optionFont_.FontSize.value_or(selectTheme->GetMenuFontSize()));
789         pattern->SetItalicFontStyle(optionFont_.FontStyle.value_or(textTheme->GetTextStyle().GetFontStyle()));
790         pattern->SetFontWeight(optionFont_.FontWeight.value_or(textTheme->GetTextStyle().GetFontWeight()));
791         pattern->SetFontFamily(optionFont_.FontFamily.value_or(textTheme->GetTextStyle().GetFontFamilies()));
792         pattern->SetFontColor(optionFont_.FontColor.value_or(selectTheme->GetMenuFontColor()));
793     }
794 }
795 
UpdateLastSelectedProps(int32_t index)796 void SelectPattern::UpdateLastSelectedProps(int32_t index)
797 {
798     CHECK_NULL_VOID(options_[index]);
799     auto newSelected = options_[index]->GetPattern<OptionPattern>();
800     CHECK_NULL_VOID(newSelected);
801     // set lastSelected option props back to default (unselected) values
802     if (selected_ >= 0 && selected_ < static_cast<int32_t>(options_.size())) {
803         CHECK_NULL_VOID(options_[selected_]);
804         auto lastSelected = options_[selected_]->GetPattern<OptionPattern>();
805         CHECK_NULL_VOID(lastSelected);
806 
807         lastSelected->SetFontColor(newSelected->GetFontColor());
808         lastSelected->SetFontFamily(newSelected->GetFontFamily());
809         lastSelected->SetFontSize(newSelected->GetFontSize());
810         lastSelected->SetItalicFontStyle(newSelected->GetItalicFontStyle());
811         lastSelected->SetFontWeight(newSelected->GetFontWeight());
812 
813         lastSelected->SetBgColor(newSelected->GetBgColor());
814         lastSelected->SetSelected(false);
815         lastSelected->UpdateNextNodeDivider(true);
816         if (selected_ != 0) {
817             auto lastSelectedNode = lastSelected->GetHost();
818             CHECK_NULL_VOID(lastSelectedNode);
819             auto lastSelectedPros = lastSelectedNode->GetPaintProperty<OptionPaintProperty>();
820             CHECK_NULL_VOID(lastSelectedPros);
821             lastSelectedPros->UpdateNeedDivider(true);
822         }
823         options_[selected_]->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
824     }
825 }
826 
827 // update selected option props
UpdateSelectedProps(int32_t index)828 void SelectPattern::UpdateSelectedProps(int32_t index)
829 {
830     CHECK_NULL_VOID(options_[index]);
831     auto newSelected = options_[index]->GetPattern<OptionPattern>();
832     CHECK_NULL_VOID(newSelected);
833 
834     // set newSelected props
835     auto host = GetHost();
836     CHECK_NULL_VOID(host);
837     auto pipeline = host->GetContextRefPtr();
838     CHECK_NULL_VOID(pipeline);
839     auto theme = pipeline->GetTheme<SelectTheme>();
840     CHECK_NULL_VOID(theme);
841     if (selectedFont_.FontColor.has_value()) {
842         newSelected->SetFontColor(selectedFont_.FontColor.value());
843     } else {
844         auto selectedColorText = theme->GetSelectedColorText();
845         newSelected->SetFontColor(selectedColorText);
846     }
847     if (selectedFont_.FontFamily.has_value()) {
848         newSelected->SetFontFamily(selectedFont_.FontFamily.value());
849     }
850     if (selectedFont_.FontSize.has_value()) {
851         newSelected->SetFontSize(selectedFont_.FontSize.value());
852     }
853     if (selectedFont_.FontStyle.has_value()) {
854         newSelected->SetItalicFontStyle(selectedFont_.FontStyle.value());
855     }
856     if (selectedFont_.FontWeight.has_value()) {
857         newSelected->SetFontWeight(selectedFont_.FontWeight.value());
858     }
859     if (selectedBgColor_.has_value()) {
860         newSelected->SetBgColor(selectedBgColor_.value());
861     } else {
862         auto selectedColor = theme->GetSelectedColor();
863         newSelected->SetBgColor(selectedColor);
864     }
865     newSelected->SetSelected(true);
866     newSelected->UpdateNextNodeDivider(false);
867     auto newSelectedNode = newSelected->GetHost();
868     CHECK_NULL_VOID(newSelectedNode);
869     auto newSelectedPros = newSelectedNode->GetPaintProperty<OptionPaintProperty>();
870     CHECK_NULL_VOID(newSelectedPros);
871     newSelectedPros->UpdateNeedDivider(false);
872 }
873 
UpdateText(int32_t index)874 void SelectPattern::UpdateText(int32_t index)
875 {
876     // update text to selected option's text
877     CHECK_NULL_VOID(text_);
878     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
879     CHECK_NULL_VOID(textProps);
880     if (index >= static_cast<int32_t>(options_.size()) || index < 0) {
881         return;
882     }
883     auto newSelected = options_[index]->GetPattern<OptionPattern>();
884     CHECK_NULL_VOID(newSelected);
885     textProps->UpdateContent(newSelected->GetText());
886     text_->MarkModifyDone();
887     auto host = GetHost();
888     CHECK_NULL_VOID(host);
889     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
890     selectValue_ = newSelected->GetText();
891 }
892 
InitTextProps(const RefPtr<TextLayoutProperty> & textProps,const RefPtr<SelectTheme> & theme)893 void SelectPattern::InitTextProps(const RefPtr<TextLayoutProperty>& textProps, const RefPtr<SelectTheme>& theme)
894 {
895     textProps->UpdateFontSize(theme->GetFontSize());
896     textProps->UpdateFontWeight(FontWeight::MEDIUM);
897     textProps->UpdateTextColor(theme->GetFontColor());
898     textProps->UpdateTextDecoration(theme->GetTextDecoration());
899     textProps->UpdateTextOverflow(TextOverflow::ELLIPSIS);
900     textProps->UpdateMaxLines(SELECT_ITSELF_TEXT_LINES);
901 }
902 
InitSpinner(const RefPtr<FrameNode> & spinner,const RefPtr<IconTheme> & iconTheme,const RefPtr<SelectTheme> & selectTheme)903 void SelectPattern::InitSpinner(
904     const RefPtr<FrameNode>& spinner, const RefPtr<IconTheme>& iconTheme, const RefPtr<SelectTheme>& selectTheme)
905 {
906     ImageSourceInfo imageSourceInfo;
907     auto iconPath = iconTheme->GetIconPath(InternalResource::ResourceId::SPINNER);
908     imageSourceInfo.SetSrc(iconPath);
909     imageSourceInfo.SetFillColor(selectTheme->GetSpinnerColor());
910 
911     auto spinnerLayoutProperty = spinner->GetLayoutProperty<ImageLayoutProperty>();
912     CHECK_NULL_VOID(spinnerLayoutProperty);
913     spinnerLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
914     CalcSize idealSize = { CalcLength(selectTheme->GetSpinnerWidth()), CalcLength(selectTheme->GetSpinnerHeight()) };
915     MeasureProperty layoutConstraint;
916     layoutConstraint.selfIdealSize = idealSize;
917     spinnerLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
918     auto spinnerRenderProperty = spinner->GetPaintProperty<ImageRenderProperty>();
919     CHECK_NULL_VOID(spinnerRenderProperty);
920     spinnerRenderProperty->UpdateSvgFillColor(selectTheme->GetSpinnerColor());
921 }
922 
InitSpinner(const RefPtr<FrameNode> & spinner,const RefPtr<SelectTheme> & selectTheme)923 void SelectPattern::InitSpinner(
924     const RefPtr<FrameNode>& spinner, const RefPtr<SelectTheme>& selectTheme)
925 {
926     auto spinnerLayoutProperty = spinner->GetLayoutProperty<TextLayoutProperty>();
927     CHECK_NULL_VOID(spinnerLayoutProperty);
928     uint32_t symbolId = selectTheme->GetSpinnerSource();
929     spinnerLayoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo{symbolId});
930     spinnerLayoutProperty->UpdateSymbolColorList({selectTheme->GetSpinnerSymbolColor()});
931     spinnerLayoutProperty->UpdateFontSize(selectTheme->GetFontSize());
932 }
933 
934 // XTS inspector code
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const935 void SelectPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
936 {
937     /* no fixed attr below, just return */
938     if (filter.IsFastFilter()) {
939         ToJsonArrowAndText(json, filter);
940         ToJsonOptionAlign(json, filter);
941         ToJsonMenuBackgroundStyle(json, filter);
942         return;
943     }
944     json->PutExtAttr("options", InspectorGetOptions().c_str(), filter);
945     json->PutExtAttr("selected", std::to_string(selected_).c_str(), filter);
946     ToJsonArrowAndText(json, filter);
947     json->PutExtAttr("selectedOptionBgColor", selectedBgColor_->ColorToString().c_str(), filter);
948     json->PutExtAttr("selectedOptionFont", InspectorGetSelectedFont().c_str(), filter);
949     json->PutExtAttr("selectedOptionFontColor",
950         selectedFont_.FontColor.value_or(Color::BLACK).ColorToString().c_str(), filter);
951 
952     if (options_.empty()) {
953         json->PutExtAttr("optionBgColor", "", filter);
954         json->PutExtAttr("optionFont", "", filter);
955         json->PutExtAttr("optionFontColor", "", filter);
956     } else {
957         auto optionPattern = options_[0]->GetPattern<OptionPattern>();
958         CHECK_NULL_VOID(optionPattern);
959         json->PutExtAttr("optionBgColor", optionPattern->GetBgColor().ColorToString().c_str(), filter);
960         json->PutExtAttr("optionFont", optionPattern->InspectorGetFont().c_str(), filter);
961         json->PutExtAttr("optionFontColor", optionPattern->GetFontColor().ColorToString().c_str(), filter);
962     }
963     ToJsonOptionAlign(json, filter);
964     for (size_t i = 0; i < options_.size(); ++i) {
965         auto optionPaintProperty = options_[i]->GetPaintProperty<OptionPaintProperty>();
966         CHECK_NULL_VOID(optionPaintProperty);
967         std::string optionWidth = std::to_string(optionPaintProperty->GetSelectModifiedWidthValue(0.0f));
968         json->PutExtAttr("optionWidth", optionWidth.c_str(), filter);
969     }
970 
971     auto menu = GetMenuNode();
972     CHECK_NULL_VOID(menu);
973     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
974     CHECK_NULL_VOID(menuLayoutProps);
975     std::string optionHeight =  std::to_string(menuLayoutProps->GetSelectModifiedHeightValue(0.0f));
976     json->PutExtAttr("optionHeight", optionHeight.c_str(), filter);
977     ToJsonMenuBackgroundStyle(json, filter);
978     ToJsonDivider(json, filter);
979 }
980 
ToJsonArrowAndText(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const981 void SelectPattern::ToJsonArrowAndText(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
982 {
983     /* no fixed attr below, just return */
984     if (filter.IsFastFilter()) {
985         return;
986     }
987     auto host = GetHost();
988     CHECK_NULL_VOID(host);
989     if (!host->GetChildren().empty()) {
990         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
991         CHECK_NULL_VOID(row);
992         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
993         CHECK_NULL_VOID(rowProps);
994         json->PutExtAttr("space", rowProps->GetSpace()->ToString().c_str(), filter);
995 
996         if (rowProps->GetFlexDirection().value() == FlexDirection::ROW) {
997             json->PutExtAttr("arrowPosition", "ArrowPosition.END", filter);
998         } else {
999             json->PutExtAttr("arrowPosition", "ArrowPosition.START", filter);
1000         }
1001     }
1002 
1003     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
1004     CHECK_NULL_VOID(props);
1005     json->PutExtAttr("value", props->GetContent().value_or("").c_str(), filter);
1006     Color fontColor = props->GetTextColor().value_or(Color::BLACK);
1007     json->PutExtAttr("fontColor", fontColor.ColorToString().c_str(), filter);
1008     json->PutExtAttr("font", props->InspectorGetTextFont().c_str(), filter);
1009     json->PutExtAttr("controlSize", ConvertControlSizeToString(controlSize_).c_str(), filter);
1010 }
1011 
ToJsonMenuBackgroundStyle(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1012 void SelectPattern::ToJsonMenuBackgroundStyle(
1013     std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1014 {
1015     /* no fixed attr below, just return */
1016     if (filter.IsFastFilter()) {
1017         return;
1018     }
1019     auto menu = GetMenuNode();
1020     CHECK_NULL_VOID(menu);
1021     auto menuRenderContext = menu->GetRenderContext();
1022     CHECK_NULL_VOID(menuRenderContext);
1023     json->PutExtAttr("menuBackgroundColor",
1024         menuRenderContext->GetBackgroundColor()->ColorToString().c_str(), filter);
1025     if (menuRenderContext->GetBackBlurStyle().has_value()) {
1026         BlurStyleOption blurStyleOption = menuRenderContext->GetBackBlurStyle().value();
1027         auto jsonValue = JsonUtil::Create(true);
1028         blurStyleOption.ToJsonValue(jsonValue, filter);
1029         json->PutExtAttr("menuBackgroundBlurStyle",
1030             jsonValue->GetValue("backgroundBlurStyle")->GetValue("value"), filter);
1031     } else {
1032         json->PutExtAttr("menuBackgroundBlurStyle", "", filter);
1033     }
1034 }
1035 
ToJsonDivider(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1036 void SelectPattern::ToJsonDivider(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1037 {
1038     /* no fixed attr below, just return */
1039     if (filter.IsFastFilter()) {
1040         return;
1041     }
1042     if (options_.empty()) {
1043         json->PutExtAttr("divider", "", filter);
1044     } else {
1045         auto props = options_[0]->GetPaintProperty<OptionPaintProperty>();
1046         CHECK_NULL_VOID(props);
1047         auto divider = JsonUtil::Create(true);
1048         if (props->HasDivider()) {
1049             divider->Put("strokeWidth", props->GetDividerValue().strokeWidth.ToString().c_str());
1050             divider->Put("startMargin", props->GetDividerValue().startMargin.ToString().c_str());
1051             divider->Put("endMargin", props->GetDividerValue().endMargin.ToString().c_str());
1052             divider->Put("color", props->GetDividerValue().color.ColorToString().c_str());
1053             json->PutExtAttr("divider", divider->ToString().c_str(), filter);
1054         } else {
1055             json->PutExtAttr("divider", "", filter);
1056         }
1057     }
1058 }
1059 
ToJsonOptionAlign(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1060 void SelectPattern::ToJsonOptionAlign(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1061 {
1062     /* no fixed attr below, just return */
1063     if (filter.IsFastFilter()) {
1064         return;
1065     }
1066     auto optionAlignJson = JsonUtil::Create(true);
1067     std::string alignTypeString = "MenuAlignType.Start";
1068     if (menuAlign_.alignType == MenuAlignType::START) {
1069         alignTypeString = "MenuAlignType.Start";
1070     } else if (menuAlign_.alignType == MenuAlignType::CENTER) {
1071         alignTypeString = "MenuAlignType.Center";
1072     } else if (menuAlign_.alignType == MenuAlignType::END) {
1073         alignTypeString = "MenuAlignType.End";
1074     }
1075     optionAlignJson->Put("alignType", alignTypeString.c_str());
1076 
1077     auto offsetValueJson = JsonUtil::Create(true);
1078     offsetValueJson->Put("dX", menuAlign_.offset.GetX().Value());
1079     offsetValueJson->Put("dY", menuAlign_.offset.GetY().Value());
1080     optionAlignJson->Put("offset", offsetValueJson);
1081 
1082     json->PutExtAttr("menuAlign", optionAlignJson, filter);
1083 }
1084 
InspectorGetOptions() const1085 std::string SelectPattern::InspectorGetOptions() const
1086 {
1087     auto jsonValue = JsonUtil::Create(true);
1088     auto jsonOptions = JsonUtil::CreateArray(true);
1089     for (size_t i = 0; i < options_.size(); ++i) {
1090         auto temp = JsonUtil::Create(true);
1091         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
1092         temp->Put("value", optionPattern->GetText().c_str());
1093         temp->Put("icon", optionPattern->GetIcon().c_str());
1094         auto index = std::to_string(i);
1095         jsonOptions->Put(index.c_str(), temp);
1096     }
1097     jsonValue->Put("options", jsonOptions);
1098     return jsonValue->ToString();
1099 }
1100 
InspectorGetSelectedFont() const1101 std::string SelectPattern::InspectorGetSelectedFont() const
1102 {
1103     TextStyle font;
1104     if (selectedFont_.FontFamily.has_value()) {
1105         font.SetFontFamilies(selectedFont_.FontFamily.value());
1106     }
1107     if (selectedFont_.FontSize.has_value()) {
1108         font.SetFontSize(selectedFont_.FontSize.value());
1109     }
1110     if (selectedFont_.FontStyle.has_value()) {
1111         font.SetFontStyle(selectedFont_.FontStyle.value());
1112     }
1113     if (selectedFont_.FontWeight.has_value()) {
1114         font.SetFontWeight(selectedFont_.FontWeight.value());
1115     }
1116     return V2::GetTextStyleInJson(font);
1117 }
1118 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)1119 bool SelectPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
1120 {
1121     auto geometryNode = dirty->GetGeometryNode();
1122     CHECK_NULL_RETURN(geometryNode, false);
1123     SetSelectSize(geometryNode->GetFrameSize());
1124     return false;
1125 }
1126 
SetSpace(const Dimension & value)1127 void SelectPattern::SetSpace(const Dimension& value)
1128 {
1129     auto host = GetHost();
1130     CHECK_NULL_VOID(host);
1131     if (!host->GetChildren().empty()) {
1132         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1133         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1134         rowProps->UpdateSpace(value);
1135         row->MarkModifyDone();
1136         row->MarkDirtyNode();
1137     }
1138 }
1139 
SetArrowPosition(const ArrowPosition value)1140 void SelectPattern::SetArrowPosition(const ArrowPosition value)
1141 {
1142     auto host = GetHost();
1143     CHECK_NULL_VOID(host);
1144     if (!host->GetChildren().empty()) {
1145         auto row = FrameNode::GetFrameNode(host->GetFirstChild()->GetTag(), host->GetFirstChild()->GetId());
1146         auto rowProps = row->GetLayoutProperty<FlexLayoutProperty>();
1147 
1148         if (value == ArrowPosition::END) {
1149             rowProps->UpdateFlexDirection(FlexDirection::ROW);
1150         } else {
1151             rowProps->UpdateFlexDirection(FlexDirection::ROW_REVERSE);
1152         }
1153         row->MarkModifyDone();
1154         row->MarkDirtyNode();
1155     }
1156 }
1157 
GetValue()1158 std::string SelectPattern::GetValue()
1159 {
1160     CHECK_NULL_RETURN(text_, "");
1161     auto textProps = text_->GetLayoutProperty<TextLayoutProperty>();
1162     CHECK_NULL_RETURN(textProps, "");
1163     return textProps->GetContentValue("");
1164 }
1165 
SetMenuAlign(const MenuAlign & menuAlign)1166 void SelectPattern::SetMenuAlign(const MenuAlign& menuAlign)
1167 {
1168     menuAlign_ = menuAlign;
1169     auto menu = GetMenuNode();
1170     CHECK_NULL_VOID(menu);
1171     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1172     CHECK_NULL_VOID(menuLayoutProps);
1173     menuLayoutProps->UpdateAlignType(menuAlign.alignType);
1174     menuLayoutProps->UpdateOffset(menuAlign.offset);
1175 }
1176 
ProvideRestoreInfo()1177 std::string SelectPattern::ProvideRestoreInfo()
1178 {
1179     auto jsonObj = JsonUtil::Create(true);
1180     jsonObj->Put("selected", selected_);
1181     jsonObj->Put("isSelected", isSelected_);
1182     return jsonObj->ToString();
1183 }
1184 
OnRestoreInfo(const std::string & restoreInfo)1185 void SelectPattern::OnRestoreInfo(const std::string& restoreInfo)
1186 {
1187     auto info = JsonUtil::ParseJsonString(restoreInfo);
1188     if (!info->IsValid() || !info->IsObject()) {
1189         return;
1190     }
1191     auto jsonIsOn = info->GetValue("selected");
1192     auto jsonIsSelect = info->GetValue("isSelected");
1193     if (jsonIsSelect->GetBool()) {
1194         SetSelected(jsonIsOn->GetInt());
1195         UpdateText(jsonIsOn->GetInt());
1196     }
1197 }
1198 
OnColorConfigurationUpdate()1199 void SelectPattern::OnColorConfigurationUpdate()
1200 {
1201     auto host = GetHost();
1202     CHECK_NULL_VOID(host);
1203     auto pipeline = host->GetContextWithCheck();
1204     CHECK_NULL_VOID(pipeline);
1205     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1206     CHECK_NULL_VOID(selectTheme);
1207 
1208     auto pattern = host->GetPattern<SelectPattern>();
1209     auto menuNode = pattern->GetMenuNode();
1210     CHECK_NULL_VOID(menuNode);
1211     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1212     CHECK_NULL_VOID(menuPattern);
1213 
1214     auto renderContext = menuNode->GetRenderContext();
1215     renderContext->UpdateBackgroundColor(selectTheme->GetBackgroundColor());
1216     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && renderContext->IsUniRenderEnabled()) {
1217         renderContext->UpdateBackBlurStyle(renderContext->GetBackBlurStyle());
1218     }
1219 
1220     auto optionNode = menuPattern->GetOptions();
1221     for (auto child : optionNode) {
1222         auto optionsPattern = child->GetPattern<OptionPattern>();
1223         optionsPattern->SetFontColor(selectTheme->GetFontColor());
1224 
1225         child->MarkModifyDone();
1226         child->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1227     }
1228     SetOptionBgColor(selectTheme->GetBackgroundColor());
1229     host->SetNeedCallChildrenUpdate(false);
1230 }
1231 
OnLanguageConfigurationUpdate()1232 void SelectPattern::OnLanguageConfigurationUpdate()
1233 {
1234     auto host = GetHost();
1235     CHECK_NULL_VOID(host);
1236     auto context = host->GetContextRefPtr();
1237     CHECK_NULL_VOID(context);
1238     auto taskExecutor = context->GetTaskExecutor();
1239     CHECK_NULL_VOID(taskExecutor);
1240     taskExecutor->PostTask(
1241         [weak = WeakClaim(this)]() {
1242             auto pattern = weak.Upgrade();
1243             CHECK_NULL_VOID(pattern);
1244             auto index = pattern->selected_;
1245             pattern->UpdateText(index);
1246             auto host = pattern->GetHost();
1247             CHECK_NULL_VOID(host);
1248             auto hub = host->GetEventHub<SelectEventHub>();
1249             CHECK_NULL_VOID(hub);
1250             if (index >= static_cast<int32_t>(pattern->options_.size()) || index < 0) {
1251                 return;
1252             }
1253             auto newSelected = pattern->options_[index]->GetPattern<OptionPattern>();
1254             CHECK_NULL_VOID(newSelected);
1255             auto value = newSelected->GetText();
1256             auto valueChangeEvent = hub->GetValueChangeEvent();
1257             if (valueChangeEvent) {
1258                 valueChangeEvent(value);
1259             }
1260             auto onSelect = hub->GetSelectEvent();
1261             if (onSelect) {
1262                 onSelect(index, value);
1263             }
1264         },
1265         TaskExecutor::TaskType::UI, "ArkUISelectLanguageConfigUpdate");
1266 }
1267 
GetFontSize()1268 Dimension SelectPattern::GetFontSize()
1269 {
1270     Dimension defaultRet = Dimension();
1271     auto props = text_->GetLayoutProperty<TextLayoutProperty>();
1272     CHECK_NULL_RETURN(props, defaultRet);
1273     auto host = props->GetHost();
1274     CHECK_NULL_RETURN(host, defaultRet);
1275     auto pipeline = host->GetContextWithCheck();
1276     CHECK_NULL_RETURN(pipeline, defaultRet);
1277     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1278     CHECK_NULL_RETURN(selectTheme, defaultRet);
1279     return props->GetFontSize().value_or(selectTheme->GetFontSize());
1280 }
1281 
SetSelectDefaultTheme()1282 void SelectPattern::SetSelectDefaultTheme()
1283 {
1284     auto select = GetHost();
1285     CHECK_NULL_VOID(select);
1286     auto pipeline = select->GetContextWithCheck();
1287     CHECK_NULL_VOID(pipeline);
1288     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1289     CHECK_NULL_VOID(selectTheme);
1290 
1291     auto renderContext = select->GetRenderContext();
1292     CHECK_NULL_VOID(renderContext);
1293 
1294     if (selectDefaultBgColor_ == Color::TRANSPARENT) {
1295         renderContext->UpdateBackgroundColor(selectTheme->GetSelectDefaultBgColor());
1296     } else {
1297         renderContext->UpdateBackgroundColor(selectDefaultBgColor_);
1298     }
1299     BorderRadiusProperty border;
1300     border.SetRadius(selectTheme->GetSelectDefaultBorderRadius());
1301     renderContext->UpdateBorderRadius(border);
1302 }
1303 
SetOptionWidth(const Dimension & value)1304 void SelectPattern::SetOptionWidth(const Dimension& value)
1305 {
1306     isFitTrigger_ = false;
1307     auto menu = GetMenuNode();
1308     CHECK_NULL_VOID(menu);
1309     auto menuPattern = menu->GetPattern<MenuPattern>();
1310     CHECK_NULL_VOID(menuPattern);
1311     menuPattern->SetIsWidthModifiedBySelect(true);
1312     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1313     CHECK_NULL_VOID(menuLayoutProps);
1314     menuLayoutProps->UpdateSelectMenuModifiedWidth(value.ConvertToPx() + OPTION_MARGIN.ConvertToPx());
1315 
1316     auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1317     CHECK_NULL_VOID(scroll);
1318     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1319     CHECK_NULL_VOID(scrollPattern);
1320     scrollPattern->SetIsWidthModifiedBySelect(true);
1321     auto scrollLayoutProps = scroll->GetLayoutProperty<ScrollLayoutProperty>();
1322     CHECK_NULL_VOID(scrollLayoutProps);
1323     scrollLayoutProps->UpdateScrollWidth(value.ConvertToPx() + OPTION_MARGIN.ConvertToPx());
1324 
1325     for (size_t i = 0; i < options_.size(); ++i) {
1326         auto optionWidth = value.ConvertToPx();
1327         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
1328         CHECK_NULL_VOID(optionPattern);
1329         optionPattern->SetIsWidthModifiedBySelect(true);
1330         auto optionPaintProperty = options_[i]->GetPaintProperty<OptionPaintProperty>();
1331         CHECK_NULL_VOID(optionPaintProperty);
1332         optionPaintProperty->UpdateSelectModifiedWidth(optionWidth);
1333     }
1334 }
1335 
SetOptionWidthFitTrigger(bool isFitTrigger)1336 void SelectPattern::SetOptionWidthFitTrigger(bool isFitTrigger)
1337 {
1338     isFitTrigger_ = isFitTrigger;
1339 }
1340 
SetHasOptionWidth(bool hasOptionWidth)1341 void SelectPattern::SetHasOptionWidth(bool hasOptionWidth)
1342 {
1343     auto menu = GetMenuNode();
1344     CHECK_NULL_VOID(menu);
1345     auto menuPattern = menu->GetPattern<MenuPattern>();
1346     CHECK_NULL_VOID(menuPattern);
1347     menuPattern->SetHasOptionWidth(true);
1348     auto scroll = DynamicCast<FrameNode>(menu->GetFirstChild());
1349     CHECK_NULL_VOID(scroll);
1350     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1351     CHECK_NULL_VOID(scrollPattern);
1352     scrollPattern->SetHasOptionWidth(true);
1353     for (size_t i = 0; i < options_.size(); ++i) {
1354         auto optionPattern = options_[i]->GetPattern<OptionPattern>();
1355         CHECK_NULL_VOID(optionPattern);
1356         optionPattern->SetHasOptionWidth(true);
1357     }
1358 }
1359 
SetOptionHeight(const Dimension & value)1360 void SelectPattern::SetOptionHeight(const Dimension& value)
1361 {
1362     auto menuMaxHeight = value.ConvertToPx();
1363     auto menu = GetMenuNode();
1364     CHECK_NULL_VOID(menu);
1365     auto menuPattern = menu->GetPattern<MenuPattern>();
1366     CHECK_NULL_VOID(menuPattern);
1367     menuPattern->SetIsHeightModifiedBySelect(true);
1368     auto menuLayoutProps = menu->GetLayoutProperty<MenuLayoutProperty>();
1369     CHECK_NULL_VOID(menuLayoutProps);
1370     menuLayoutProps->UpdateSelectModifiedHeight(menuMaxHeight);
1371 }
1372 
SetMenuBackgroundColor(const Color & color)1373 void SelectPattern::SetMenuBackgroundColor(const Color& color)
1374 {
1375     auto menu = GetMenuNode();
1376     CHECK_NULL_VOID(menu);
1377     auto renderContext = menu->GetRenderContext();
1378     CHECK_NULL_VOID(renderContext);
1379     renderContext->UpdateBackgroundColor(color);
1380 }
1381 
SetMenuBackgroundBlurStyle(const BlurStyleOption & blurStyle)1382 void SelectPattern::SetMenuBackgroundBlurStyle(const BlurStyleOption& blurStyle)
1383 {
1384     auto menu = GetMenuNode();
1385     CHECK_NULL_VOID(menu);
1386     auto renderContext = menu->GetRenderContext();
1387     CHECK_NULL_VOID(renderContext);
1388     renderContext->UpdateBackBlurStyle(blurStyle);
1389 }
1390 
ResetParams()1391 void SelectPattern::ResetParams()
1392 {
1393     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1394         return;
1395     }
1396     auto select = GetHost();
1397     CHECK_NULL_VOID(select);
1398     auto* pipeline = select->GetContextWithCheck();
1399     CHECK_NULL_VOID(pipeline);
1400     auto selectTheme = pipeline->GetTheme<SelectTheme>();
1401     CHECK_NULL_VOID(selectTheme);
1402     auto layoutProperty = select->GetLayoutProperty();
1403     CHECK_NULL_VOID(layoutProperty);
1404     layoutProperty->UpdateCalcMinSize(CalcSize(CalcLength(selectTheme->GetSelectMinWidth(controlSize_)),
1405         CalcLength(selectTheme->GetSelectDefaultHeight(controlSize_))));
1406     SetFontSize(selectTheme->GetFontSize(controlSize_));
1407     auto spinnerLayoutProperty = spinner_->GetLayoutProperty<TextLayoutProperty>();
1408     CHECK_NULL_VOID(spinnerLayoutProperty);
1409     spinnerLayoutProperty->UpdateFontSize(selectTheme->GetFontSize(controlSize_));
1410     auto renderContext = select->GetRenderContext();
1411     BorderRadiusProperty border;
1412     border.SetRadius(selectTheme->GetSelectDefaultBorderRadius(controlSize_));
1413     renderContext->UpdateBorderRadius(border);
1414 
1415     NG::PaddingProperty paddings;
1416     paddings.top = std::nullopt;
1417     paddings.bottom = std::nullopt;
1418     if (controlSize_ == ControlSize::SMALL) {
1419         paddings.left = NG::CalcLength(SELECT_SMALL_PADDING_VP);
1420         paddings.right = NG::CalcLength(SELECT_SMALL_PADDING_VP);
1421     } else {
1422         paddings.left = NG::CalcLength(SELECT_MARGIN_VP);
1423         paddings.right = NG::CalcLength(SELECT_MARGIN_VP);
1424     }
1425     ViewAbstract::SetPadding(paddings);
1426 }
1427 
SetControlSize(const ControlSize & controlSize)1428 void SelectPattern::SetControlSize(const ControlSize& controlSize)
1429 {
1430     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1431         return;
1432     }
1433     controlSize_ = controlSize;
1434     ResetParams();
1435 }
1436 
SetLayoutDirection(TextDirection value)1437 void SelectPattern::SetLayoutDirection(TextDirection value)
1438 {
1439     auto select = GetHost();
1440     auto menu = GetMenuNode();
1441     std::function<void (decltype(select))> updateDirectionFunc = [&](decltype(select) node) {
1442         if (!node) return;
1443         auto updateProperty = node->GetLayoutProperty();
1444         updateProperty->UpdateLayoutDirection(value);
1445         if (node->GetHostTag() == V2::SCROLL_ETS_TAG) {
1446             auto scrollPattern = AceType::DynamicCast<ScrollPattern>(node->GetPattern());
1447             if (scrollPattern) scrollPattern->TriggerModifyDone();
1448         }
1449         for (auto child : node->GetAllChildrenWithBuild()) {
1450             auto frameNode = AceType::DynamicCast<FrameNode>(child);
1451             if (!frameNode) continue;
1452             updateDirectionFunc(frameNode);
1453         }
1454     };
1455     updateDirectionFunc(select);
1456     updateDirectionFunc(menu);
1457 }
1458 
GetControlSize()1459 ControlSize SelectPattern::GetControlSize()
1460 {
1461     return controlSize_;
1462 }
1463 
SetDivider(const SelectDivider & divider)1464 void SelectPattern::SetDivider(const SelectDivider& divider)
1465 {
1466     for (auto&& option : options_) {
1467         auto props = option->GetPaintProperty<OptionPaintProperty>();
1468         CHECK_NULL_VOID(props);
1469         props->UpdateDivider(divider);
1470     }
1471 }
1472 } // namespace OHOS::Ace::NG
1473