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