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/radio/radio_pattern.h"
17
18 #include "base/log/dump_log.h"
19 #include "base/utils/multi_thread.h"
20 #include "core/components/theme/icon_theme.h"
21 #include "core/components_ng/pattern/image/image_pattern.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23
24 namespace OHOS::Ace::NG {
25
26 namespace {
27 constexpr int FOR_HOTZONESIZE_CALCULATE_MULTIPLY_TWO = 2;
28 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
29
30 constexpr int32_t DEFAULT_RADIO_ANIMATION_DURATION = 200;
31 constexpr int32_t DEFAULT_RADIO_ANIMATION_DURATION_CIRCLE = 150;
32 constexpr float INDICATOR_MIN_SCALE = 0.8F;
33 constexpr float INDICATOR_MAX_SCALE = 1.0F;
34 constexpr float INDICATOR_MIN_OPACITY = 0.0F;
35 constexpr float INDICATOR_MAX_OPACITY = 1.0F;
36 constexpr int32_t RADIO_PADDING_COUNT = 2;
37
38 constexpr float DEFAULT_INTERPOLATINGSPRING_VELOCITY = 0.0f;
39 constexpr float DEFAULT_INTERPOLATINGSPRING_MASS = 1.0f;
40 constexpr float DEFAULT_INTERPOLATINGSPRING_STIFFNESS = 728.0f;
41 constexpr float DEFAULT_INTERPOLATINGSPRING_DAMPING = 46.0f;
42 constexpr Color DEFAULT_INDICATOR_DARK_LIGHT_COLOR = Color(0xffffffff);
43 } // namespace
44
OnAttachToFrameNode()45 void RadioPattern::OnAttachToFrameNode()
46 {
47 auto host = GetHost();
48 CHECK_NULL_VOID(host);
49 host->GetLayoutProperty()->UpdateAlignment(Alignment::CENTER);
50 }
51
UpdateGroupStatus(FrameNode * frameNode)52 void RadioPattern::UpdateGroupStatus(FrameNode* frameNode)
53 {
54 CHECK_NULL_VOID(frameNode);
55 auto groupManager = GetGroupManager();
56 CHECK_NULL_VOID(groupManager);
57 auto radioEventHub = frameNode->GetOrCreateEventHub<NG::RadioEventHub>();
58 CHECK_NULL_VOID(radioEventHub);
59 groupManager->RemoveRadioFromGroup(radioEventHub->GetGroup(), frameNode->GetId());
60 }
61
OnDetachFromFrameNode(FrameNode * frameNode)62 void RadioPattern::OnDetachFromFrameNode(FrameNode* frameNode)
63 {
64 THREAD_SAFE_NODE_CHECK(frameNode, OnDetachFromFrameNode);
65 UpdateGroupStatus(frameNode);
66 }
67
OnDetachFromMainTree()68 void RadioPattern::OnDetachFromMainTree()
69 {
70 auto host = GetHost();
71 THREAD_SAFE_NODE_CHECK(host, OnDetachFromMainTree, host);
72 }
73
SetBuilderState()74 void RadioPattern::SetBuilderState()
75 {
76 CHECK_NULL_VOID(builderChildNode_);
77 auto renderContext = builderChildNode_->GetRenderContext();
78 CHECK_NULL_VOID(renderContext);
79 renderContext->UpdateOpacity(0);
80 auto layoutProperty = builderChildNode_->GetLayoutProperty();
81 CHECK_NULL_VOID(layoutProperty);
82 layoutProperty->UpdateVisibility(VisibleType::GONE);
83 }
84
UpdateIndicatorType()85 void RadioPattern::UpdateIndicatorType()
86 {
87 auto host = GetHost();
88 CHECK_NULL_VOID(host);
89 auto radioPaintProperty = host->GetPaintProperty<RadioPaintProperty>();
90 CHECK_NULL_VOID(radioPaintProperty);
91 auto radioIndicatorType = radioPaintProperty->GetRadioIndicator().value_or(0);
92 if (radioIndicatorType == static_cast<int32_t>(RadioIndicatorType::CUSTOM)) {
93 LoadBuilder();
94 } else {
95 ImageNodeCreate();
96 }
97 CHECK_NULL_VOID(builderChildNode_);
98 auto renderContext = builderChildNode_->GetRenderContext();
99 CHECK_NULL_VOID(renderContext);
100 renderContext->UpdateTransformScale({ INDICATOR_MAX_SCALE, INDICATOR_MAX_SCALE });
101 renderContext->UpdateOpacity(1);
102 if (!radioPaintProperty->GetRadioCheckValue(false)) {
103 SetBuilderState();
104 }
105 }
106
OnModifyDone()107 void RadioPattern::OnModifyDone()
108 {
109 Pattern::OnModifyDone();
110 FireBuilder();
111 auto host = GetHost();
112 CHECK_NULL_VOID(host);
113 auto* pipeline = host->GetContext();
114 CHECK_NULL_VOID(pipeline);
115 auto radioTheme = pipeline->GetTheme<RadioTheme>();
116 CHECK_NULL_VOID(radioTheme);
117 if (!makeFunc_.has_value() && host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
118 auto radioPaintProperty = host->GetPaintProperty<RadioPaintProperty>();
119 if (!radioModifier_) {
120 radioModifier_ = AceType::MakeRefPtr<RadioModifier>();
121 }
122 if (radioPaintProperty && !radioPaintProperty->HasRadioCheck()) {
123 radioPaintProperty->UpdateRadioCheck(false);
124 }
125 if (radioPaintProperty && !radioPaintProperty->GetRadioCheckValue()) {
126 radioModifier_->InitOpacityScale(false);
127 }
128 auto callback = [weak = WeakClaim(this)]() {
129 auto radio = weak.Upgrade();
130 if (radio) {
131 radio->UpdateIndicatorType();
132 }
133 };
134 pipeline->AddBuildFinishCallBack(callback);
135 }
136 UpdateState();
137 hotZoneHorizontalPadding_ = radioTheme->GetHotZoneHorizontalPadding();
138 hotZoneVerticalPadding_ = radioTheme->GetHotZoneVerticalPadding();
139 InitDefaultMargin();
140 HandleEnabled();
141 InitClickEvent();
142 InitTouchEvent();
143 InitMouseEvent();
144 InitFocusEvent();
145 auto focusHub = host->GetFocusHub();
146 CHECK_NULL_VOID(focusHub);
147 InitOnKeyEvent(focusHub);
148 SetAccessibilityAction();
149 }
150
InitDefaultMargin()151 void RadioPattern::InitDefaultMargin()
152 {
153 if (makeFunc_.has_value()) {
154 ResetDefaultMargin();
155 return;
156 }
157 auto host = GetHost();
158 CHECK_NULL_VOID(host);
159 auto layoutProperty = host->GetLayoutProperty();
160 CHECK_NULL_VOID(layoutProperty);
161 MarginProperty margin;
162 margin.left = CalcLength(hotZoneHorizontalPadding_.Value());
163 margin.right = CalcLength(hotZoneHorizontalPadding_.Value());
164 margin.top = CalcLength(hotZoneVerticalPadding_.Value());
165 margin.bottom = CalcLength(hotZoneVerticalPadding_.Value());
166 auto& setMargin = layoutProperty->GetMarginProperty();
167 if (setMargin) {
168 if (setMargin->left.has_value()) {
169 margin.left = setMargin->left;
170 }
171 if (setMargin->right.has_value()) {
172 margin.right = setMargin->right;
173 }
174 if (setMargin->top.has_value()) {
175 margin.top = setMargin->top;
176 }
177 if (setMargin->bottom.has_value()) {
178 margin.bottom = setMargin->bottom;
179 }
180 }
181 layoutProperty->UpdateMargin(margin);
182 }
183
ResetDefaultMargin()184 void RadioPattern::ResetDefaultMargin()
185 {
186 if (isUserSetMargin_) {
187 return;
188 }
189 auto host = GetHost();
190 CHECK_NULL_VOID(host);
191 auto layoutProperty = host->GetLayoutProperty();
192 CHECK_NULL_VOID(layoutProperty);
193 MarginProperty margin;
194 layoutProperty->UpdateMargin(margin);
195 }
196
InitFocusEvent()197 void RadioPattern::InitFocusEvent()
198 {
199 if (focusEventInitialized_) {
200 return;
201 }
202 auto host = GetHost();
203 CHECK_NULL_VOID(host);
204 auto focusHub = host->GetOrCreateFocusHub();
205 CHECK_NULL_VOID(focusHub);
206 auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
207 auto pattern = weak.Upgrade();
208 CHECK_NULL_VOID(pattern);
209 pattern->HandleFocusEvent();
210 };
211 focusHub->SetOnFocusInternal(focusTask);
212 auto blurTask = [weak = WeakClaim(this)]() {
213 auto pattern = weak.Upgrade();
214 CHECK_NULL_VOID(pattern);
215 pattern->HandleBlurEvent();
216 };
217 focusHub->SetOnBlurInternal(blurTask);
218 focusEventInitialized_ = true;
219 }
220
HandleFocusEvent()221 void RadioPattern::HandleFocusEvent()
222 {
223 CHECK_NULL_VOID(radioModifier_);
224 AddIsFocusActiveUpdateEvent();
225 auto pipeline = PipelineContext::GetCurrentContext();
226 CHECK_NULL_VOID(pipeline);
227 if (pipeline->GetIsFocusActive()) {
228 OnIsFocusActiveUpdate(true);
229 }
230 }
231
HandleBlurEvent()232 void RadioPattern::HandleBlurEvent()
233 {
234 CHECK_NULL_VOID(radioModifier_);
235 RemoveIsFocusActiveUpdateEvent();
236 OnIsFocusActiveUpdate(false);
237 }
238
AddIsFocusActiveUpdateEvent()239 void RadioPattern::AddIsFocusActiveUpdateEvent()
240 {
241 if (!isFocusActiveUpdateEvent_) {
242 isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
243 auto pattern = weak.Upgrade();
244 CHECK_NULL_VOID(pattern);
245 pattern->OnIsFocusActiveUpdate(isFocusAcitve);
246 };
247 }
248
249 auto pipline = PipelineContext::GetCurrentContext();
250 CHECK_NULL_VOID(pipline);
251 pipline->AddIsFocusActiveUpdateEvent(GetHost(), isFocusActiveUpdateEvent_);
252 }
253
RemoveIsFocusActiveUpdateEvent()254 void RadioPattern::RemoveIsFocusActiveUpdateEvent()
255 {
256 auto pipline = PipelineContext::GetCurrentContext();
257 CHECK_NULL_VOID(pipline);
258 pipline->RemoveIsFocusActiveUpdateEvent(GetHost());
259 }
260
OnIsFocusActiveUpdate(bool isFocusAcitve)261 void RadioPattern::OnIsFocusActiveUpdate(bool isFocusAcitve)
262 {
263 CHECK_NULL_VOID(radioModifier_);
264 radioModifier_->SetIsFocused(isFocusAcitve);
265 }
266
ImageNodeCreate()267 void RadioPattern::ImageNodeCreate()
268 {
269 auto host = GetHost();
270 CHECK_NULL_VOID(host);
271 auto childNode = DynamicCast<FrameNode>(host->GetFirstChild());
272 if (preTypeIsBuilder_) {
273 host->RemoveChild(childNode);
274 }
275 if (!childNode || preTypeIsBuilder_) {
276 auto node = FrameNode::GetOrCreateFrameNode(V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
277 []() { return AceType::MakeRefPtr<ImagePattern>(); });
278 CHECK_NULL_VOID(node);
279 builderChildNode_ = AceType::DynamicCast<FrameNode>(node);
280 CHECK_NULL_VOID(builderChildNode_);
281 auto gesturehub = builderChildNode_->GetOrCreateGestureEventHub();
282 CHECK_NULL_VOID(gesturehub);
283 gesturehub->SetHitTestMode(HitTestMode::HTMNONE);
284 }
285 CHECK_NULL_VOID(builderChildNode_);
286 auto radioPaintProperty = host->GetPaintProperty<RadioPaintProperty>();
287 CHECK_NULL_VOID(radioPaintProperty);
288 auto imageProperty = builderChildNode_->GetLayoutProperty<ImageLayoutProperty>();
289 CHECK_NULL_VOID(imageProperty);
290 auto* pipeline = host->GetContext();
291 CHECK_NULL_VOID(pipeline);
292 auto radioTheme = pipeline->GetTheme<RadioTheme>();
293 CHECK_NULL_VOID(radioTheme);
294 imageProperty->UpdateUserDefinedIdealSize(GetChildContentSize(radioTheme));
295 auto imageSourceInfo = GetImageSourceInfoFromTheme(radioPaintProperty->GetRadioIndicator().value_or(0), radioTheme);
296 UpdateInternalResource(imageSourceInfo);
297 auto indicatorColor = radioPaintProperty->GetRadioIndicatorColor().value_or(Color(radioTheme->GetPointColor()));
298 auto imageRenderProperty = builderChildNode_->GetPaintProperty<ImageRenderProperty>();
299 CHECK_NULL_VOID(imageRenderProperty);
300 imageRenderProperty->UpdateSvgFillColor(indicatorColor);
301 imageProperty->UpdateImageSourceInfo(imageSourceInfo);
302 preTypeIsBuilder_ = false;
303 builderChildNode_->MountToParent(host);
304 builderChildNode_->MarkModifyDone();
305 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
306 }
307
SetAccessibilityAction()308 void RadioPattern::SetAccessibilityAction()
309 {
310 auto host = GetHost();
311 CHECK_NULL_VOID(host);
312 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
313 CHECK_NULL_VOID(accessibilityProperty);
314 accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
315 const auto& pattern = weakPtr.Upgrade();
316 CHECK_NULL_VOID(pattern);
317 pattern->UpdateSelectStatus(true);
318 });
319
320 accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
321 const auto& pattern = weakPtr.Upgrade();
322 CHECK_NULL_VOID(pattern);
323 pattern->UpdateSelectStatus(false);
324 });
325 }
326
UpdateSelectStatus(bool isSelected)327 void RadioPattern::UpdateSelectStatus(bool isSelected)
328 {
329 auto host = GetHost();
330 CHECK_NULL_VOID(host);
331 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d update status %d", host->GetId(), isSelected);
332 auto context = host->GetRenderContext();
333 CHECK_NULL_VOID(context);
334 MarkIsSelected(isSelected);
335 context->OnMouseSelectUpdate(isSelected, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
336 }
337
MarkIsSelected(bool isSelected)338 void RadioPattern::MarkIsSelected(bool isSelected)
339 {
340 if (preCheck_ == isSelected) {
341 return;
342 }
343 preCheck_ = isSelected;
344 auto eventHub = GetOrCreateEventHub<RadioEventHub>();
345 CHECK_NULL_VOID(eventHub);
346 eventHub->UpdateChangeEvent(isSelected);
347 auto host = GetHost();
348 CHECK_NULL_VOID(host);
349 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d fire change event %{public}d", host->GetId(),
350 isSelected);
351 if (isSelected) {
352 eventHub->UpdateCurrentUIState(UI_STATE_SELECTED);
353 host->OnAccessibilityEvent(AccessibilityEventType::SELECTED);
354 } else {
355 eventHub->ResetCurrentUIState(UI_STATE_SELECTED);
356 host->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
357 }
358 }
359
OnAfterModifyDone()360 void RadioPattern::OnAfterModifyDone()
361 {
362 auto host = GetHost();
363 CHECK_NULL_VOID(host);
364 auto inspectorId = host->GetInspectorId().value_or("");
365 if (inspectorId.empty()) {
366 return;
367 }
368 auto eventHub = host->GetOrCreateEventHub<RadioEventHub>();
369 CHECK_NULL_VOID(eventHub);
370 Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, eventHub->GetValue(), preCheck_);
371 }
372
InitClickEvent()373 void RadioPattern::InitClickEvent()
374 {
375 if (clickListener_) {
376 return;
377 }
378 auto host = GetHost();
379 CHECK_NULL_VOID(host);
380 auto gesture = host->GetOrCreateGestureEventHub();
381 CHECK_NULL_VOID(gesture);
382 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
383 auto radioPattern = weak.Upgrade();
384 CHECK_NULL_VOID(radioPattern);
385 radioPattern->OnClick();
386 };
387 clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
388 gesture->AddClickEvent(clickListener_);
389 }
390
InitTouchEvent()391 void RadioPattern::InitTouchEvent()
392 {
393 if (UseContentModifier()) {
394 return;
395 }
396 if (touchListener_) {
397 return;
398 }
399 auto host = GetHost();
400 CHECK_NULL_VOID(host);
401 auto gesture = host->GetOrCreateGestureEventHub();
402 CHECK_NULL_VOID(gesture);
403 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
404 auto radioPattern = weak.Upgrade();
405 CHECK_NULL_VOID(radioPattern);
406 if (info.GetTouches().empty()) {
407 return;
408 }
409 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
410 radioPattern->OnTouchDown();
411 }
412 if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
413 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
414 radioPattern->OnTouchUp();
415 }
416 };
417 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
418 gesture->AddTouchEvent(touchListener_);
419 }
420
InitMouseEvent()421 void RadioPattern::InitMouseEvent()
422 {
423 if (UseContentModifier()) {
424 return;
425 }
426 if (mouseEvent_) {
427 return;
428 }
429 auto host = GetHost();
430 CHECK_NULL_VOID(host);
431 auto gesture = host->GetOrCreateGestureEventHub();
432 CHECK_NULL_VOID(gesture);
433 auto eventHub = host->GetOrCreateEventHub<RadioEventHub>();
434 auto inputHub = eventHub->GetOrCreateInputEventHub();
435
436 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
437 auto pattern = weak.Upgrade();
438 if (pattern) {
439 pattern->HandleMouseEvent(isHover);
440 }
441 };
442 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
443 inputHub->AddOnHoverEvent(mouseEvent_);
444 }
445
HandleMouseEvent(bool isHover)446 void RadioPattern::HandleMouseEvent(bool isHover)
447 {
448 if (UseContentModifier()) {
449 return;
450 }
451 isHover_ = isHover;
452 if (isHover) {
453 touchHoverType_ = TouchHoverAnimationType::HOVER;
454 } else {
455 touchHoverType_ = TouchHoverAnimationType::NONE;
456 }
457 auto host = GetHost();
458 CHECK_NULL_VOID(host);
459 TAG_LOGD(
460 AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d handle mouse hover %{public}d", host->GetId(), isHover);
461 host->MarkNeedRenderOnly();
462 }
463
OnClick()464 void RadioPattern::OnClick()
465 {
466 if (UseContentModifier()) {
467 return;
468 }
469 auto host = GetHost();
470 CHECK_NULL_VOID(host);
471 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d handle click event", host->GetId());
472 auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
473 CHECK_NULL_VOID(paintProperty);
474 bool check = false;
475 if (paintProperty->HasRadioCheck()) {
476 check = paintProperty->GetRadioCheckValue();
477 } else {
478 paintProperty->UpdateRadioCheck(false);
479 }
480 if (!preCheck_ && !check) {
481 paintProperty->UpdateRadioCheck(true);
482 UpdateState();
483 }
484 }
485
OnTouchDown()486 void RadioPattern::OnTouchDown()
487 {
488 if (UseContentModifier()) {
489 return;
490 }
491 if (isHover_) {
492 touchHoverType_ = TouchHoverAnimationType::HOVER_TO_PRESS;
493 } else {
494 touchHoverType_ = TouchHoverAnimationType::PRESS;
495 }
496 auto host = GetHost();
497 CHECK_NULL_VOID(host);
498 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d onTouch Down", host->GetId());
499 isTouch_ = true;
500 host->MarkNeedRenderOnly();
501 }
502
OnTouchUp()503 void RadioPattern::OnTouchUp()
504 {
505 if (UseContentModifier()) {
506 return;
507 }
508 if (isHover_) {
509 touchHoverType_ = TouchHoverAnimationType::PRESS_TO_HOVER;
510 } else {
511 touchHoverType_ = TouchHoverAnimationType::NONE;
512 }
513 auto host = GetHost();
514 CHECK_NULL_VOID(host);
515 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d onTouch Up", host->GetId());
516 isTouch_ = false;
517 host->MarkNeedRenderOnly();
518 }
519
CheckPageNode()520 void RadioPattern::CheckPageNode()
521 {
522 if (Container::IsInSubContainer()) {
523 return;
524 }
525 auto host = GetHost();
526 CHECK_NULL_VOID(host);
527 auto prePageId = GetPrePageId();
528 auto pipelineContext = PipelineContext::GetCurrentContext();
529 CHECK_NULL_VOID(pipelineContext);
530 auto stageManager = pipelineContext->GetStageManager();
531 CHECK_NULL_VOID(stageManager);
532 auto pageNode = stageManager->GetPageById(host->GetPageId());
533 CHECK_NULL_VOID(pageNode);
534 if (pageNode->GetId() != prePageId) {
535 auto eventHub = host->GetOrCreateEventHub<RadioEventHub>();
536 CHECK_NULL_VOID(eventHub);
537 auto groupManager = GetGroupManager();
538 CHECK_NULL_VOID(groupManager);
539 auto group = eventHub->GetGroup();
540 groupManager->AddRadioToGroup(group, host->GetId());
541 auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
542 CHECK_NULL_VOID(paintProperty);
543 bool check = false;
544 if (paintProperty->HasRadioCheck()) {
545 check = paintProperty->GetRadioCheckValue();
546 }
547 UpdateGroupCheckStatus(host, groupManager, check);
548 }
549 }
550
UpdateState()551 void RadioPattern::UpdateState()
552 {
553 auto host = GetHost();
554 CHECK_NULL_VOID(host);
555 auto eventHub = host->GetOrCreateEventHub<RadioEventHub>();
556 CHECK_NULL_VOID(eventHub);
557
558 auto pipelineContext = PipelineContext::GetCurrentContext();
559 CHECK_NULL_VOID(pipelineContext);
560 auto groupManager = GetGroupManager();
561 CHECK_NULL_VOID(groupManager);
562 auto preGroup = GetPreGroup();
563 auto group = eventHub->GetGroup();
564 if (!preGroup.has_value()) {
565 groupManager->AddRadioToGroup(group, host->GetId());
566 SetPrePageIdToLastPageId();
567 auto callback = [weak = WeakClaim(this)]() {
568 auto radio = weak.Upgrade();
569 if (radio) {
570 radio->CheckPageNode();
571 }
572 };
573 pipelineContext->AddBuildFinishCallBack(callback);
574 }
575 if (preGroup.has_value() && preGroup.value() != group) {
576 groupManager->RemoveRadioFromGroup(preGroup.value(), host->GetId());
577 groupManager->AddRadioToGroup(group, host->GetId());
578 SetPrePageIdToLastPageId();
579 isGroupChanged_ = true;
580 }
581 SetPreGroup(group);
582
583 auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
584 CHECK_NULL_VOID(paintProperty);
585
586 bool check = false;
587 if (paintProperty->HasRadioCheck()) {
588 check = paintProperty->GetRadioCheckValue();
589 /*
590 * Do not set isFirstCreated_ to false if the radio is set to true at creation time. The isFirstCreated_ is set
591 * to false in UpdateGroupCheckStatus because isFirstCreated_ is also required to determine if an onChange event
592 * needs to be triggered.
593 */
594 if (check) {
595 UpdateUIStatus(true);
596 isOnAnimationFlag_ = true;
597 } else {
598 // If the radio is set to false, set isFirstCreated_ to false.
599 isFirstCreated_ = false;
600 }
601 } else {
602 paintProperty->UpdateRadioCheck(false);
603 // If the radio check is not set, set isFirstCreated_ to false.
604 isFirstCreated_ = false;
605 }
606 if (preCheck_ != check || isGroupChanged_) {
607 UpdateGroupCheckStatus(host, groupManager, check);
608 }
609 preCheck_ = check;
610 isGroupChanged_ = false;
611 }
612
UpdateUncheckStatus(const RefPtr<FrameNode> & frameNode)613 void RadioPattern::UpdateUncheckStatus(const RefPtr<FrameNode>& frameNode)
614 {
615 auto radioPaintProperty = frameNode->GetPaintProperty<RadioPaintProperty>();
616 CHECK_NULL_VOID(radioPaintProperty);
617 if (radioPaintProperty->GetRadioCheckValue(false)) {
618 radioPaintProperty->UpdateRadioCheck(false);
619 FireBuilder();
620 }
621 frameNode->MarkNeedRenderOnly();
622 if (frameNode->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
623 startExitAnimation();
624 }
625 if (preCheck_) {
626 auto radioEventHub = GetOrCreateEventHub<RadioEventHub>();
627 CHECK_NULL_VOID(radioEventHub);
628 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d fire unselect event", frameNode->GetId());
629 radioEventHub->UpdateChangeEvent(false);
630 isOnAnimationFlag_ = false;
631 }
632 preCheck_ = false;
633 }
634
startEnterAnimation()635 void RadioPattern::startEnterAnimation()
636 {
637 auto host = GetHost();
638 CHECK_NULL_VOID(host);
639 auto springCurve = AceType::MakeRefPtr<InterpolatingSpring>(DEFAULT_INTERPOLATINGSPRING_VELOCITY,
640 DEFAULT_INTERPOLATINGSPRING_MASS, DEFAULT_INTERPOLATINGSPRING_STIFFNESS, DEFAULT_INTERPOLATINGSPRING_DAMPING);
641 AnimationOption delayOption;
642
643 auto pipeline = host->GetContextRefPtr();
644 CHECK_NULL_VOID(pipeline);
645 auto radioTheme = pipeline->GetTheme<RadioTheme>();
646 CHECK_NULL_VOID(radioTheme);
647 if (radioTheme->IsCircleDial()) {
648 delayOption.SetCurve(Curves::FAST_OUT_SLOW_IN);
649 delayOption.SetDelay(DEFAULT_RADIO_ANIMATION_DURATION_CIRCLE);
650 } else {
651 delayOption.SetCurve(springCurve);
652 delayOption.SetDelay(DEFAULT_RADIO_ANIMATION_DURATION);
653 }
654
655 CHECK_NULL_VOID(builderChildNode_);
656 auto renderContext = builderChildNode_->GetRenderContext();
657 CHECK_NULL_VOID(renderContext);
658 renderContext->UpdateOpacity(INDICATOR_MIN_OPACITY);
659 renderContext->UpdateTransformScale({ INDICATOR_MIN_SCALE, INDICATOR_MIN_SCALE });
660 auto layoutProperty = builderChildNode_->GetLayoutProperty();
661 CHECK_NULL_VOID(layoutProperty);
662 layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
663 auto eventHub = builderChildNode_->GetOrCreateEventHub<EventHub>();
664 if (eventHub) {
665 eventHub->SetEnabled(true);
666 }
667 AnimationUtils::Animate(
668 delayOption,
669 [&]() {
670 renderContext->UpdateTransformScale({ INDICATOR_MAX_SCALE, INDICATOR_MAX_SCALE });
671 renderContext->UpdateOpacity(INDICATOR_MAX_OPACITY);
672 },
673 nullptr, nullptr, pipeline);
674 }
675
startExitAnimation()676 void RadioPattern::startExitAnimation()
677 {
678 auto springCurve = AceType::MakeRefPtr<InterpolatingSpring>(DEFAULT_INTERPOLATINGSPRING_VELOCITY,
679 DEFAULT_INTERPOLATINGSPRING_MASS, DEFAULT_INTERPOLATINGSPRING_STIFFNESS, DEFAULT_INTERPOLATINGSPRING_DAMPING);
680 AnimationOption delayOption;
681
682 auto host = GetHost();
683 CHECK_NULL_VOID(host);
684 auto pipeline = host->GetContextRefPtr();
685 CHECK_NULL_VOID(pipeline);
686 auto radioTheme = pipeline->GetTheme<RadioTheme>();
687 CHECK_NULL_VOID(radioTheme);
688 if (radioTheme->IsCircleDial()) {
689 delayOption.SetCurve(Curves::FAST_OUT_SLOW_IN);
690 delayOption.SetDelay(DEFAULT_RADIO_ANIMATION_DURATION_CIRCLE);
691 } else {
692 delayOption.SetCurve(springCurve);
693 }
694
695 CHECK_NULL_VOID(builderChildNode_);
696 auto renderContext = builderChildNode_->GetRenderContext();
697 CHECK_NULL_VOID(renderContext);
698 AnimationUtils::Animate(
699 delayOption,
700 [&]() {
701 renderContext->UpdateTransformScale({ INDICATOR_MIN_SCALE, INDICATOR_MIN_SCALE });
702 renderContext->UpdateOpacity(INDICATOR_MIN_OPACITY);
703 },
704 nullptr, nullptr, pipeline);
705 auto eventHub = builderChildNode_->GetOrCreateEventHub<EventHub>();
706 if (eventHub) {
707 eventHub->SetEnabled(false);
708 }
709 }
710
GetImageSourceInfoFromTheme(int32_t RadioIndicator,const RefPtr<RadioTheme> & radioTheme)711 ImageSourceInfo RadioPattern::GetImageSourceInfoFromTheme(int32_t RadioIndicator, const RefPtr<RadioTheme>& radioTheme)
712 {
713 ImageSourceInfo imageSourceInfo;
714 CHECK_NULL_RETURN(radioTheme, imageSourceInfo);
715 switch (RadioIndicator) {
716 case static_cast<int32_t>(RadioIndicatorType::TICK):
717 imageSourceInfo.SetResourceId(radioTheme->GetTickResourceId());
718 break;
719 case static_cast<int32_t>(RadioIndicatorType::DOT):
720 imageSourceInfo.SetResourceId(radioTheme->GetDotResourceId());
721 break;
722 default:
723 imageSourceInfo.SetResourceId(radioTheme->GetTickResourceId());
724 break;
725 }
726 return imageSourceInfo;
727 }
728
UpdateInternalResource(ImageSourceInfo & sourceInfo)729 void RadioPattern::UpdateInternalResource(ImageSourceInfo& sourceInfo)
730 {
731 CHECK_NULL_VOID(sourceInfo.IsInternalResource());
732 auto host = GetHost();
733 CHECK_NULL_VOID(host);
734 auto* pipeline = host->GetContext();
735 CHECK_NULL_VOID(pipeline);
736 auto iconTheme = pipeline->GetTheme<IconTheme>();
737 CHECK_NULL_VOID(iconTheme);
738 auto iconPath = iconTheme->GetIconPath(sourceInfo.GetResourceId());
739 if (iconPath.empty()) {
740 return;
741 }
742 sourceInfo.SetSrc(iconPath);
743 }
744
LoadBuilder()745 void RadioPattern::LoadBuilder()
746 {
747 RefPtr<UINode> customNode;
748 if (builder_) {
749 auto host = GetHost();
750 CHECK_NULL_VOID(host);
751 auto childNode = DynamicCast<FrameNode>(host->GetFirstChild());
752 if (preTypeIsBuilder_) {
753 return;
754 } else {
755 if (childNode) {
756 host->RemoveChild(childNode);
757 }
758 }
759 NG::ScopedViewStackProcessor builderViewStackProcessor;
760 builder_();
761 customNode = NG::ViewStackProcessor::GetInstance()->Finish();
762 CHECK_NULL_VOID(customNode);
763 builderChildNode_ = AceType::DynamicCast<FrameNode>(customNode);
764 CHECK_NULL_VOID(builderChildNode_);
765 preTypeIsBuilder_ = true;
766 builderChildNode_->MountToParent(host);
767 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
768 }
769 }
770
GetChildContentSize(const RefPtr<RadioTheme> & radioTheme)771 CalcSize RadioPattern::GetChildContentSize(const RefPtr<RadioTheme>& radioTheme)
772 {
773 CHECK_NULL_RETURN(radioTheme, CalcSize());
774 auto host = GetHost();
775 CHECK_NULL_RETURN(host, CalcSize());
776 auto layoutProperty = host->GetLayoutProperty<LayoutProperty>();
777 CHECK_NULL_RETURN(layoutProperty, CalcSize());
778 auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
779 if (layoutConstraint && layoutConstraint->selfIdealSize) {
780 auto selfIdealSize = layoutConstraint->selfIdealSize;
781 if (selfIdealSize->IsValid()) {
782 auto height = selfIdealSize->Height()->GetDimension() * DEFAULT_RADIO_IMAGE_SCALE;
783 auto width = selfIdealSize->Width()->GetDimension() * DEFAULT_RADIO_IMAGE_SCALE;
784 auto length = std::min(width, height);
785 return CalcSize(NG::CalcLength(length), NG::CalcLength(length));
786 }
787 if (selfIdealSize->Width().has_value()) {
788 auto width = selfIdealSize->Width()->GetDimension() * DEFAULT_RADIO_IMAGE_SCALE;
789 return CalcSize(NG::CalcLength(width), NG::CalcLength(width));
790 }
791 if (selfIdealSize->Height().has_value()) {
792 auto height = selfIdealSize->Height()->GetDimension() * DEFAULT_RADIO_IMAGE_SCALE;
793 return CalcSize(NG::CalcLength(height), NG::CalcLength(height));
794 }
795 }
796 Dimension defaultWidth = radioTheme->GetWidth();
797 Dimension defaultHeight = radioTheme->GetHeight();
798 Dimension horizontalPadding = radioTheme->GetDefaultPaddingSize();
799 Dimension verticalPadding = radioTheme->GetDefaultPaddingSize();
800 auto width = (defaultWidth - horizontalPadding * RADIO_PADDING_COUNT) * DEFAULT_RADIO_IMAGE_SCALE;
801 auto height = (defaultHeight - verticalPadding * RADIO_PADDING_COUNT) * DEFAULT_RADIO_IMAGE_SCALE;
802 return CalcSize(NG::CalcLength(width), NG::CalcLength(height));
803 }
804
UpdateGroupCheckStatus(const RefPtr<FrameNode> & frameNode,const RefPtr<GroupManager> & groupManager,bool check)805 void RadioPattern::UpdateGroupCheckStatus(
806 const RefPtr<FrameNode>& frameNode, const RefPtr<GroupManager>& groupManager, bool check)
807 {
808 frameNode->MarkNeedRenderOnly();
809 if (frameNode->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
810 if (!isFirstCreated_ && check) {
811 startEnterAnimation();
812 }
813 }
814
815 auto radioEventHub = GetOrCreateEventHub<RadioEventHub>();
816 CHECK_NULL_VOID(radioEventHub);
817 if (check) {
818 groupManager->UpdateRadioGroupValue(radioEventHub->GetGroup(), frameNode->GetId());
819 } else {
820 auto radioPaintProperty = frameNode->GetPaintProperty<RadioPaintProperty>();
821 CHECK_NULL_VOID(radioPaintProperty);
822 radioPaintProperty->UpdateRadioCheck(check);
823 if (!isGroupChanged_) {
824 isOnAnimationFlag_ = false;
825 }
826 }
827
828 if (!isFirstCreated_) {
829 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "radio node %{public}d fire group change event %{public}d",
830 frameNode->GetId(), check);
831 radioEventHub->UpdateChangeEvent(check);
832 }
833 }
834
UpdateUIStatus(bool check)835 void RadioPattern::UpdateUIStatus(bool check)
836 {
837 uiStatus_ = check ? UIStatus::SELECTED : UIStatus::UNSELECTED;
838 auto host = GetHost();
839 CHECK_NULL_VOID(host);
840 host->MarkNeedRenderOnly();
841 }
842
OnKeyEvent(const KeyEvent & event)843 bool RadioPattern::OnKeyEvent(const KeyEvent& event)
844 {
845 if (event.action == KeyAction::DOWN && event.code == KeyCode::KEY_FUNCTION) {
846 OnClick();
847 return true;
848 }
849 return false;
850 }
851
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)852 void RadioPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
853 {
854 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
855 auto pattern = wp.Upgrade();
856 if (pattern) {
857 pattern->GetInnerFocusPaintRect(paintRect);
858 }
859 };
860 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
861
862 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
863 auto pattern = wp.Upgrade();
864 if (pattern) {
865 return pattern->OnKeyEvent(event);
866 } else {
867 return false;
868 }
869 };
870 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
871 }
872
GetInnerFocusPaintRect(RoundRect & paintRect)873 void RadioPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
874 {
875 auto host = GetHost();
876 CHECK_NULL_VOID(host);
877 auto* pipeline = host->GetContext();
878 CHECK_NULL_VOID(pipeline);
879 auto radioTheme = pipeline->GetTheme<RadioTheme>();
880 CHECK_NULL_VOID(radioTheme);
881 auto focusPaintPadding = radioTheme->GetFocusPaintPadding().ConvertToPx();
882 float outCircleRadius = size_.Width() / 2 + focusPaintPadding;
883 float originX = offset_.GetX() - focusPaintPadding;
884 float originY = offset_.GetY() - focusPaintPadding;
885 float width = size_.Width() + 2 * focusPaintPadding;
886 float height = size_.Height() + 2 * focusPaintPadding;
887 paintRect.SetRect({ originX, originY, width, height });
888 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, outCircleRadius, outCircleRadius);
889 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, outCircleRadius, outCircleRadius);
890 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, outCircleRadius, outCircleRadius);
891 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, outCircleRadius, outCircleRadius);
892 }
893
GetFocusPattern() const894 FocusPattern RadioPattern::GetFocusPattern() const
895 {
896 auto host = GetHost();
897 CHECK_NULL_RETURN(host, FocusPattern());
898 auto pipeline = host->GetContext();
899 CHECK_NULL_RETURN(pipeline, FocusPattern());
900 auto radioTheme = pipeline->GetTheme<RadioTheme>();
901 CHECK_NULL_RETURN(radioTheme, FocusPattern());
902 FocusPaintParam focusPaintParam;
903 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
904 auto focusColor = radioTheme->GetFocusColor();
905 focusPaintParam.SetPaintColor(focusColor);
906 } else {
907 auto activeColor = radioTheme->GetActiveColor();
908 focusPaintParam.SetPaintColor(activeColor);
909 }
910 return { FocusType::NODE, true, FocusStyleType::CUSTOM_REGION, focusPaintParam };
911 }
912
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig &)913 bool RadioPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& /*config*/)
914 {
915 auto geometryNode = dirty->GetGeometryNode();
916 offset_ = geometryNode->GetContentOffset();
917 size_ = geometryNode->GetContentSize();
918 if (!isUserSetResponseRegion_) {
919 AddHotZoneRect();
920 }
921 return true;
922 }
923
924 // Set the default hot zone for the component.
AddHotZoneRect()925 void RadioPattern::AddHotZoneRect()
926 {
927 hotZoneOffset_.SetX(offset_.GetX() - hotZoneHorizontalPadding_.ConvertToPx());
928 hotZoneOffset_.SetY(offset_.GetY() - hotZoneVerticalPadding_.ConvertToPx());
929 hotZoneSize_.SetWidth(
930 size_.Width() + FOR_HOTZONESIZE_CALCULATE_MULTIPLY_TWO * hotZoneHorizontalPadding_.ConvertToPx());
931 hotZoneSize_.SetHeight(
932 size_.Height() + FOR_HOTZONESIZE_CALCULATE_MULTIPLY_TWO * hotZoneVerticalPadding_.ConvertToPx());
933 DimensionRect hotZoneRegion;
934 hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize_.Width()), Dimension(hotZoneSize_.Height())));
935 hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset_.GetX()), Dimension(hotZoneOffset_.GetY())));
936 auto host = GetHost();
937 CHECK_NULL_VOID(host);
938 auto gestureHub = host->GetOrCreateGestureEventHub();
939 CHECK_NULL_VOID(gestureHub);
940 gestureHub->SetResponseRegion(std::vector<DimensionRect>({ hotZoneRegion }));
941 }
942
RemoveLastHotZoneRect() const943 void RadioPattern::RemoveLastHotZoneRect() const
944 {
945 auto host = GetHost();
946 CHECK_NULL_VOID(host);
947 host->RemoveLastHotZoneRect();
948 }
949
ProvideRestoreInfo()950 std::string RadioPattern::ProvideRestoreInfo()
951 {
952 auto jsonObj = JsonUtil::Create(true);
953 auto radioPaintProperty = GetPaintProperty<RadioPaintProperty>();
954 CHECK_NULL_RETURN(radioPaintProperty, "");
955 jsonObj->Put("checked", radioPaintProperty->GetRadioCheck().value_or(false));
956 return jsonObj->ToString();
957 }
958
OnRestoreInfo(const std::string & restoreInfo)959 void RadioPattern::OnRestoreInfo(const std::string& restoreInfo)
960 {
961 auto radioPaintProperty = GetPaintProperty<RadioPaintProperty>();
962 CHECK_NULL_VOID(radioPaintProperty);
963 auto info = JsonUtil::ParseJsonString(restoreInfo);
964 if (!info->IsValid() || !info->IsObject()) {
965 return;
966 }
967 auto jsonChecked = info->GetValue("checked");
968 radioPaintProperty->UpdateRadioCheck(jsonChecked->GetBool());
969 OnModifyDone();
970 }
971
HandleEnabled()972 void RadioPattern::HandleEnabled()
973 {
974 auto host = GetHost();
975 CHECK_NULL_VOID(host);
976 auto eventHub = host->GetOrCreateEventHub<EventHub>();
977 CHECK_NULL_VOID(eventHub);
978 auto enabled = eventHub->IsEnabled();
979 auto radioPaintProperty = GetHost()->GetPaintProperty<RadioPaintProperty>();
980 if (enabled_ != enabled) {
981 enabled_ = enabled;
982 if (!enabled_ && host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
983 if (!radioModifier_) {
984 radioModifier_ = AceType::MakeRefPtr<RadioModifier>();
985 }
986 if (!radioPaintProperty->HasRadioCheck() || !radioPaintProperty->GetRadioCheckValue()) {
987 radioModifier_->SetUIStatus(UIStatus::UNSELECTED);
988 }
989 }
990 auto paintProperty = GetPaintProperty<RadioPaintProperty>();
991 CHECK_NULL_VOID(paintProperty);
992 paintProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_RENDER);
993 }
994 }
995
SetRadioChecked(bool check)996 void RadioPattern::SetRadioChecked(bool check)
997 {
998 auto host = GetHost();
999 CHECK_NULL_VOID(host);
1000 auto eventHub = host->GetOrCreateEventHub<EventHub>();
1001 CHECK_NULL_VOID(eventHub);
1002 auto enabled = eventHub->IsEnabled();
1003 if (!enabled) {
1004 return;
1005 }
1006 auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
1007 CHECK_NULL_VOID(paintProperty);
1008 paintProperty->UpdateRadioCheck(check);
1009 UpdateState();
1010 OnModifyDone();
1011 }
1012
DumpInfo()1013 void RadioPattern::DumpInfo ()
1014 {
1015 auto eventHub = GetOrCreateEventHub<RadioEventHub>();
1016 CHECK_NULL_VOID(eventHub);
1017 DumpLog::GetInstance().AddDesc("Value: " + eventHub->GetValue());
1018 DumpLog::GetInstance().AddDesc("Group: " + eventHub->GetGroup());
1019
1020 auto paintProperty = GetPaintProperty<RadioPaintProperty>();
1021 CHECK_NULL_VOID(paintProperty);
1022 if (paintProperty->HasRadioIndicator()) {
1023 DumpLog::GetInstance().AddDesc("IndicatorType: " + std::to_string(paintProperty->GetRadioIndicatorValue()));
1024 }
1025 if (paintProperty->HasRadioCheck()) {
1026 DumpLog::GetInstance().AddDesc(
1027 "IsChecked: " + std::string(paintProperty->GetRadioCheckValue() ? "true" : "false"));
1028 }
1029 if (paintProperty->HasRadioCheckedBackgroundColor()) {
1030 DumpLog::GetInstance().AddDesc(
1031 "CheckedBackgroundColor: " + paintProperty->GetRadioCheckedBackgroundColorValue().ToString());
1032 }
1033 if (paintProperty->HasRadioUncheckedBorderColor()) {
1034 DumpLog::GetInstance().AddDesc(
1035 "UncheckedBorderColor: " + paintProperty->GetRadioUncheckedBorderColorValue().ToString());
1036 }
1037 if (paintProperty->HasRadioIndicatorColor()) {
1038 DumpLog::GetInstance().AddDesc("IndicatorColor: " + paintProperty->GetRadioIndicatorColorValue().ToString());
1039 }
1040 }
1041
UpdateRadioComponentColor(const Color & color,const RadioColorType radioColorType)1042 void RadioPattern::UpdateRadioComponentColor(const Color& color, const RadioColorType radioColorType)
1043 {
1044 auto host = GetHost();
1045 CHECK_NULL_VOID(host);
1046 auto pipelineContext = host->GetContext();
1047 CHECK_NULL_VOID(pipelineContext);
1048 auto paintProperty = GetPaintProperty<RadioPaintProperty>();
1049 CHECK_NULL_VOID(paintProperty);
1050 switch (radioColorType) {
1051 case RadioColorType::CHECKED_BACKGROUND_COLOR:
1052 paintProperty->UpdateRadioCheckedBackgroundColor(color);
1053 break;
1054 case RadioColorType::UNCHECKED_BORDER_COLOR:
1055 paintProperty->UpdateRadioUncheckedBorderColor(color);
1056 break;
1057 case RadioColorType::INDICATOR_COLOR:
1058 paintProperty->UpdateRadioIndicatorColor(color);
1059 ImageNodeCreate();
1060 break;
1061 default:
1062 break;
1063 }
1064 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1065 }
1066
FireBuilder()1067 void RadioPattern::FireBuilder()
1068 {
1069 auto host = GetHost();
1070 CHECK_NULL_VOID(host);
1071 if (!makeFunc_.has_value()) {
1072 host->RemoveChildAndReturnIndex(customNode_);
1073 customNode_ = nullptr;
1074 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
1075 return;
1076 }
1077 auto node = BuildContentModifierNode();
1078 if (customNode_ == node) {
1079 return;
1080 }
1081 host->RemoveChildAndReturnIndex(customNode_);
1082 customNode_ = node;
1083 CHECK_NULL_VOID(customNode_);
1084 host->AddChild(customNode_, 0);
1085 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
1086 }
1087
BuildContentModifierNode()1088 RefPtr<FrameNode> RadioPattern::BuildContentModifierNode()
1089 {
1090 CHECK_NULL_RETURN(makeFunc_, nullptr);
1091 auto host = GetHost();
1092 CHECK_NULL_RETURN(host, nullptr);
1093 auto eventHub = host->GetOrCreateEventHub<RadioEventHub>();
1094 CHECK_NULL_RETURN(eventHub, nullptr);
1095 auto value = eventHub->GetValue();
1096 auto enabled = eventHub->IsEnabled();
1097 auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
1098 CHECK_NULL_RETURN(paintProperty, nullptr);
1099 bool isChecked = false;
1100 if (paintProperty->HasRadioCheck()) {
1101 isChecked = paintProperty->GetRadioCheckValue();
1102 } else {
1103 isChecked = false;
1104 }
1105 RadioConfiguration radioConfiguration(value, isChecked, enabled);
1106 return (makeFunc_.value())(radioConfiguration);
1107 }
1108
GetGroupManager()1109 RefPtr<GroupManager> RadioPattern::GetGroupManager()
1110 {
1111 auto manager = groupManager_.Upgrade();
1112 if (manager) {
1113 return manager;
1114 }
1115 groupManager_ = GroupManager::GetGroupManager();
1116 return groupManager_.Upgrade();
1117 }
1118
SetPrePageIdToLastPageId()1119 void RadioPattern::SetPrePageIdToLastPageId()
1120 {
1121 if (!Container::IsInSubContainer()) {
1122 auto pipelineContext = PipelineContext::GetCurrentContext();
1123 CHECK_NULL_VOID(pipelineContext);
1124 auto stageManager = pipelineContext->GetStageManager();
1125 CHECK_NULL_VOID(stageManager);
1126 auto pageNode = stageManager->GetLastPage();
1127 CHECK_NULL_VOID(pageNode);
1128 SetPrePageId(pageNode->GetId());
1129 }
1130 }
1131
OnColorConfigurationUpdate()1132 void RadioPattern::OnColorConfigurationUpdate()
1133 {
1134 if (!SystemProperties::ConfigChangePerform()) {
1135 return;
1136 }
1137 auto host = GetHost();
1138 CHECK_NULL_VOID(host);
1139 auto paintProperty = host->GetPaintProperty<RadioPaintProperty>();
1140 CHECK_NULL_VOID(paintProperty);
1141 auto pipeline = host->GetContext();
1142 CHECK_NULL_VOID(pipeline);
1143 auto radioTheme = pipeline->GetTheme<RadioTheme>();
1144 CHECK_NULL_VOID(radioTheme);
1145 auto pattern = host->GetPattern<RadioPattern>();
1146 CHECK_NULL_VOID(pattern);
1147
1148 if (!paintProperty->GetRadioCheckedBackgroundColorSetByUser().value_or(false)) {
1149 auto activeColor = radioTheme->GetActiveColor();
1150 paintProperty->UpdateRadioCheckedBackgroundColor(activeColor);
1151 }
1152 if (!paintProperty->GetRadioUncheckedBorderColorSetByUser().value_or(false)) {
1153 Color inActiveColor;
1154 if (pattern->GetUncheckedBorderColorByJSRadioTheme()) {
1155 inActiveColor = radioTheme->GetInactiveColor();
1156 } else {
1157 inActiveColor = radioTheme->GetUnCheckBorderColor();
1158 }
1159 paintProperty->UpdateRadioUncheckedBorderColor(inActiveColor);
1160 }
1161 if (!paintProperty->GetRadioIndicatorColorSetByUser().value_or(false)) {
1162 Color pointColor;
1163 if (pattern->GetIndicatorColorByJSRadioTheme()) {
1164 pointColor = radioTheme->GetPointColor();
1165 paintProperty->UpdateRadioIndicatorColor(pointColor);
1166 } else {
1167 paintProperty->UpdateRadioIndicatorColor(DEFAULT_INDICATOR_DARK_LIGHT_COLOR);
1168 }
1169 ImageNodeCreate();
1170 }
1171 host->MarkModifyDone();
1172 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1173 }
1174 } // namespace OHOS::Ace::NG
1175