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