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/checkbox/checkbox_pattern.h"
17 
18 #include "core/common/recorder/node_data_cache.h"
19 #include "core/components/checkable/checkable_component.h"
20 #include "core/components/checkable/checkable_theme.h"
21 #include "core/components_ng/pattern/checkbox/checkbox_layout_algorithm.h"
22 #include "core/components_ng/pattern/checkbox/checkbox_paint_property.h"
23 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_paint_property.h"
24 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_pattern.h"
25 #include "core/components_ng/pattern/stage/page_event_hub.h"
26 #include "core/components_ng/property/calc_length.h"
27 #include "core/components_ng/property/property.h"
28 #include "core/components_v2/inspector/inspector_constants.h"
29 #include "core/event/touch_event.h"
30 #include "core/pipeline/base/constants.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
36 constexpr int32_t DEFAULT_CHECKBOX_ANIMATION_DURATION = 100;
37 } // namespace
38 
OnAttachToFrameNode()39 void CheckBoxPattern::OnAttachToFrameNode()
40 {
41     auto host = GetHost();
42     CHECK_NULL_VOID(host);
43     host->GetLayoutProperty()->UpdateAlignment(Alignment::CENTER);
44 }
45 
SetBuilderNodeHidden()46 void CheckBoxPattern::SetBuilderNodeHidden()
47 {
48     CHECK_NULL_VOID(builderNode_);
49     auto layoutProperty = builderNode_->GetLayoutProperty();
50     CHECK_NULL_VOID(layoutProperty);
51     layoutProperty->UpdateVisibility(VisibleType::GONE);
52 }
53 
UpdateIndicator()54 void CheckBoxPattern::UpdateIndicator()
55 {
56     auto host = GetHost();
57     CHECK_NULL_VOID(host);
58     if (builder_.has_value() && !UseContentModifier()) {
59         LoadBuilder();
60         auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
61         CHECK_NULL_VOID(paintProperty);
62         bool isSelected = false;
63         if (paintProperty->HasCheckBoxSelect()) {
64             isSelected = paintProperty->GetCheckBoxSelectValue();
65             if (!isSelected) {
66                 SetBuilderNodeHidden();
67             }
68         } else {
69             paintProperty->UpdateCheckBoxSelect(false);
70             SetBuilderNodeHidden();
71         }
72     } else if (builderNode_) {
73         host->RemoveChildAndReturnIndex(builderNode_);
74         builderNode_ = nullptr;
75     }
76 }
77 
OnModifyDone()78 void CheckBoxPattern::OnModifyDone()
79 {
80     Pattern::OnModifyDone();
81     FireBuilder();
82     UpdateIndicator();
83     UpdateState();
84     auto host = GetHost();
85     CHECK_NULL_VOID(host);
86     auto pipeline = GetContext();
87     CHECK_NULL_VOID(pipeline);
88     auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
89     CHECK_NULL_VOID(checkBoxTheme);
90     auto layoutProperty = host->GetLayoutProperty();
91     CHECK_NULL_VOID(layoutProperty);
92     MarginProperty margin;
93     margin.left = CalcLength(checkBoxTheme->GetHotZoneHorizontalPadding().Value());
94     margin.right = CalcLength(checkBoxTheme->GetHotZoneHorizontalPadding().Value());
95     margin.top = CalcLength(checkBoxTheme->GetHotZoneVerticalPadding().Value());
96     margin.bottom = CalcLength(checkBoxTheme->GetHotZoneVerticalPadding().Value());
97     auto& setMargin = layoutProperty->GetMarginProperty();
98     if (setMargin) {
99         if (setMargin->left.has_value()) {
100             margin.left = setMargin->left;
101         }
102         if (setMargin->right.has_value()) {
103             margin.right = setMargin->right;
104         }
105         if (setMargin->top.has_value()) {
106             margin.top = setMargin->top;
107         }
108         if (setMargin->bottom.has_value()) {
109             margin.bottom = setMargin->bottom;
110         }
111     }
112     layoutProperty->UpdateMargin(margin);
113     hotZoneHorizontalPadding_ = checkBoxTheme->GetHotZoneHorizontalPadding();
114     hotZoneVerticalPadding_ = checkBoxTheme->GetHotZoneVerticalPadding();
115     InitClickEvent();
116     InitTouchEvent();
117     InitMouseEvent();
118     auto focusHub = host->GetFocusHub();
119     CHECK_NULL_VOID(focusHub);
120     InitOnKeyEvent(focusHub);
121     SetAccessibilityAction();
122 }
123 
SetAccessibilityAction()124 void CheckBoxPattern::SetAccessibilityAction()
125 {
126     auto host = GetHost();
127     CHECK_NULL_VOID(host);
128     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
129     CHECK_NULL_VOID(accessibilityProperty);
130     accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
131         const auto& pattern = weakPtr.Upgrade();
132         CHECK_NULL_VOID(pattern);
133         pattern->UpdateSelectStatus(true);
134     });
135 
136     accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
137         const auto& pattern = weakPtr.Upgrade();
138         CHECK_NULL_VOID(pattern);
139         pattern->UpdateSelectStatus(false);
140     });
141 }
142 
UpdateSelectStatus(bool isSelected)143 void CheckBoxPattern::UpdateSelectStatus(bool isSelected)
144 {
145     auto host = GetHost();
146     CHECK_NULL_VOID(host);
147     auto context = host->GetRenderContext();
148     CHECK_NULL_VOID(context);
149     MarkIsSelected(isSelected);
150     context->OnMouseSelectUpdate(isSelected, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
151 }
152 
MarkIsSelected(bool isSelected)153 void CheckBoxPattern::MarkIsSelected(bool isSelected)
154 {
155     if (lastSelect_ == isSelected) {
156         return;
157     }
158     lastSelect_ = isSelected;
159     auto eventHub = GetEventHub<CheckBoxEventHub>();
160     CHECK_NULL_VOID(eventHub);
161     eventHub->UpdateChangeEvent(isSelected);
162     auto host = GetHost();
163     CHECK_NULL_VOID(host);
164     if (isSelected) {
165         eventHub->UpdateCurrentUIState(UI_STATE_SELECTED);
166         host->OnAccessibilityEvent(AccessibilityEventType::SELECTED);
167     } else {
168         eventHub->ResetCurrentUIState(UI_STATE_SELECTED);
169         host->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
170     }
171 }
172 
OnAfterModifyDone()173 void CheckBoxPattern::OnAfterModifyDone()
174 {
175     auto host = GetHost();
176     CHECK_NULL_VOID(host);
177     auto inspectorId = host->GetInspectorId().value_or("");
178     if (inspectorId.empty()) {
179         return;
180     }
181     auto eventHub = host->GetEventHub<CheckBoxEventHub>();
182     CHECK_NULL_VOID(eventHub);
183     Recorder::NodeDataCache::Get().PutMultiple(host, inspectorId, eventHub->GetName(), lastSelect_);
184 }
185 
InitClickEvent()186 void CheckBoxPattern::InitClickEvent()
187 {
188     if (clickListener_) {
189         return;
190     }
191     auto host = GetHost();
192     CHECK_NULL_VOID(host);
193     auto gesture = host->GetOrCreateGestureEventHub();
194     CHECK_NULL_VOID(gesture);
195     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
196         auto checkboxPattern = weak.Upgrade();
197         CHECK_NULL_VOID(checkboxPattern);
198         checkboxPattern->OnClick();
199     };
200     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
201     gesture->AddClickEvent(clickListener_);
202 }
203 
InitTouchEvent()204 void CheckBoxPattern::InitTouchEvent()
205 {
206     if (touchListener_) {
207         return;
208     }
209     auto host = GetHost();
210     CHECK_NULL_VOID(host);
211     auto gesture = host->GetOrCreateGestureEventHub();
212     CHECK_NULL_VOID(gesture);
213     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
214         auto checkboxPattern = weak.Upgrade();
215         CHECK_NULL_VOID(checkboxPattern);
216         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
217             checkboxPattern->OnTouchDown();
218         }
219         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
220             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
221             checkboxPattern->OnTouchUp();
222         }
223     };
224     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
225     gesture->AddTouchEvent(touchListener_);
226 }
227 
InitMouseEvent()228 void CheckBoxPattern::InitMouseEvent()
229 {
230     if (mouseEvent_) {
231         return;
232     }
233     auto host = GetHost();
234     CHECK_NULL_VOID(host);
235     auto gesture = host->GetOrCreateGestureEventHub();
236     CHECK_NULL_VOID(gesture);
237     auto eventHub = host->GetEventHub<CheckBoxEventHub>();
238     auto inputHub = eventHub->GetOrCreateInputEventHub();
239 
240     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
241         auto pattern = weak.Upgrade();
242         if (pattern) {
243             pattern->HandleMouseEvent(isHover);
244         }
245     };
246     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
247     inputHub->AddOnHoverEvent(mouseEvent_);
248 }
249 
HandleMouseEvent(bool isHover)250 void CheckBoxPattern::HandleMouseEvent(bool isHover)
251 {
252     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox on hover %{public}d", isHover);
253     isHover_ = isHover;
254     if (isHover) {
255         touchHoverType_ = TouchHoverAnimationType::HOVER;
256     } else {
257         touchHoverType_ = TouchHoverAnimationType::NONE;
258     }
259     auto host = GetHost();
260     CHECK_NULL_VOID(host);
261     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
262 }
263 
OnClick()264 void CheckBoxPattern::OnClick()
265 {
266     if (UseContentModifier()) {
267         return;
268     }
269     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox onclick");
270     auto host = GetHost();
271     CHECK_NULL_VOID(host);
272     auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
273     CHECK_NULL_VOID(paintProperty);
274     bool isSelected = false;
275     if (paintProperty->HasCheckBoxSelect()) {
276         isSelected = paintProperty->GetCheckBoxSelectValue();
277     } else {
278         isSelected = false;
279     }
280     paintProperty->UpdateCheckBoxSelect(!isSelected);
281     UpdateState();
282 }
283 
OnTouchDown()284 void CheckBoxPattern::OnTouchDown()
285 {
286     if (UseContentModifier()) {
287         return;
288     }
289     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox touch down %{public}d", isHover_);
290     if (isHover_) {
291         touchHoverType_ = TouchHoverAnimationType::HOVER_TO_PRESS;
292     } else {
293         touchHoverType_ = TouchHoverAnimationType::PRESS;
294     }
295     auto host = GetHost();
296     CHECK_NULL_VOID(host);
297     isTouch_ = true;
298     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
299 }
300 
OnTouchUp()301 void CheckBoxPattern::OnTouchUp()
302 {
303     if (UseContentModifier()) {
304         return;
305     }
306     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox touch up %{public}d", isHover_);
307     if (isHover_) {
308         touchHoverType_ = TouchHoverAnimationType::PRESS_TO_HOVER;
309     } else {
310         touchHoverType_ = TouchHoverAnimationType::NONE;
311     }
312     auto host = GetHost();
313     CHECK_NULL_VOID(host);
314     isTouch_ = false;
315     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
316 }
317 
UpdateUnSelect()318 void CheckBoxPattern::UpdateUnSelect()
319 {
320     auto host = GetHost();
321     CHECK_NULL_VOID(host);
322     auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
323     CHECK_NULL_VOID(paintProperty);
324     if (paintProperty->HasCheckBoxSelect() && !paintProperty->GetCheckBoxSelectValue()) {
325         uiStatus_ = UIStatus::UNSELECTED;
326         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
327     }
328 }
329 
UpdateUIStatus(bool check)330 void CheckBoxPattern::UpdateUIStatus(bool check)
331 {
332     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox update status %{public}d", check);
333     uiStatus_ = check ? UIStatus::OFF_TO_ON : UIStatus::ON_TO_OFF;
334     auto host = GetHost();
335     CHECK_NULL_VOID(host);
336     if (UseContentModifier()) {
337         auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
338         CHECK_NULL_VOID(paintProperty);
339         paintProperty->UpdateCheckBoxSelect(check);
340         FireBuilder();
341     }
342     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
343 }
344 
OnDetachFromFrameNode(FrameNode * frameNode)345 void CheckBoxPattern::OnDetachFromFrameNode(FrameNode* frameNode)
346 {
347     CHECK_NULL_VOID(frameNode);
348     auto groupManager = GetGroupManager();
349     CHECK_NULL_VOID(groupManager);
350     auto group = GetGroupNameWithNavId();
351     groupManager->RemoveCheckBoxFromGroup(group, frameNode->GetId());
352     auto groupNode = groupManager->GetCheckboxGroup(group);
353     CHECK_NULL_VOID(groupNode);
354     auto checkboxList = groupManager->GetCheckboxList(group);
355     UpdateCheckBoxGroupStatus(groupNode, checkboxList);
356 }
357 
CheckPageNode()358 void CheckBoxPattern::CheckPageNode()
359 {
360     if (Container::IsInSubContainer()) {
361         return;
362     }
363     auto host = GetHost();
364     CHECK_NULL_VOID(host);
365     auto prePageId = GetPrePageId();
366     auto pipelineContext = GetContext();
367     CHECK_NULL_VOID(pipelineContext);
368     auto stageManager = pipelineContext->GetStageManager();
369     CHECK_NULL_VOID(stageManager);
370     auto pageNode = stageManager->GetPageById(host->GetPageId());
371     CHECK_NULL_VOID(pageNode);
372     if (pageNode->GetId() != prePageId) {
373         auto pageEventHub = pageNode->GetEventHub<NG::PageEventHub>();
374         CHECK_NULL_VOID(pageEventHub);
375         auto groupManager = pageEventHub->GetGroupManager();
376         CHECK_NULL_VOID(groupManager);
377         groupManager_ = groupManager;
378         auto group = GetGroupNameWithNavId();
379         groupManager->AddCheckBoxToGroup(group, host);
380         SetPrePageId(pageNode->GetId());
381     }
382 }
383 
UpdateState()384 void CheckBoxPattern::UpdateState()
385 {
386     auto host = GetHost();
387     CHECK_NULL_VOID(host);
388     auto pipelineContext = GetContext();
389     CHECK_NULL_VOID(pipelineContext);
390     auto groupManager = GetGroupManager();
391     CHECK_NULL_VOID(groupManager);
392     auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
393     CHECK_NULL_VOID(paintProperty);
394     auto preGroup = GetPreGroup();
395     auto group = GetGroupNameWithNavId();
396     if (!preGroup.has_value()) {
397         groupManager->AddCheckBoxToGroup(group, host);
398         SetPrePageIdToLastPageId();
399         auto callback = [weak = WeakClaim(this)]() {
400             auto checkbox = weak.Upgrade();
401             if (checkbox) {
402                 checkbox->CheckPageNode();
403                 checkbox->CheckBoxGroupIsTrue();
404             }
405         };
406         pipelineContext->AddBuildFinishCallBack(callback);
407         if (paintProperty->HasCheckBoxSelect()) {
408             auto isSelected = paintProperty->GetCheckBoxSelectValue();
409             SetLastSelect(isSelected);
410         }
411         isFirstCreated_ = false;
412         SetPreGroup(group);
413         return;
414     }
415     if (preGroup.has_value() && preGroup.value() != group) {
416         groupManager->RemoveCheckBoxFromGroup(preGroup.value(), host->GetId());
417         groupManager->AddCheckBoxToGroup(group, host);
418         SetPrePageIdToLastPageId();
419     }
420     SetPreGroup(group);
421     ChangeSelfStatusAndNotify(paintProperty);
422     auto groupNode = groupManager->GetCheckboxGroup(group);
423     CHECK_NULL_VOID(groupNode);
424     auto checkboxList = groupManager->GetCheckboxList(group);
425     UpdateCheckBoxGroupStatus(groupNode, checkboxList);
426 }
427 
ChangeSelfStatusAndNotify(const RefPtr<CheckBoxPaintProperty> & paintProperty)428 void CheckBoxPattern::ChangeSelfStatusAndNotify(const RefPtr<CheckBoxPaintProperty>& paintProperty)
429 {
430     auto host = GetHost();
431     CHECK_NULL_VOID(host);
432     bool isSelected = false;
433     if (paintProperty->HasCheckBoxSelect()) {
434         isSelected = paintProperty->GetCheckBoxSelectValue();
435         if (lastSelect_ != isSelected) {
436             UpdateUIStatus(isSelected);
437             SetLastSelect(isSelected);
438             auto checkboxEventHub = GetEventHub<CheckBoxEventHub>();
439             CHECK_NULL_VOID(checkboxEventHub);
440             TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox node %{public}d update change event %{public}d",
441                 host->GetId(), isSelected);
442             checkboxEventHub->UpdateChangeEvent(isSelected);
443         }
444     }
445     StartCustomNodeAnimation(isSelected);
446     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
447     FireBuilder();
448 }
449 
StartEnterAnimation()450 void CheckBoxPattern::StartEnterAnimation()
451 {
452     AnimationOption option;
453     option.SetCurve(Curves::FAST_OUT_SLOW_IN);
454     option.SetDuration(DEFAULT_CHECKBOX_ANIMATION_DURATION);
455     CHECK_NULL_VOID(builderNode_);
456     const auto& renderContext = builderNode_->GetRenderContext();
457     CHECK_NULL_VOID(renderContext);
458     renderContext->UpdateOpacity(0);
459     const auto& layoutProperty = builderNode_->GetLayoutProperty();
460     CHECK_NULL_VOID(layoutProperty);
461     layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
462     const auto& eventHub = builderNode_->GetEventHub<EventHub>();
463     if (eventHub) {
464         eventHub->SetEnabled(true);
465     }
466     AnimationUtils::Animate(
467         option,
468         [&]() {
469             TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "check enter animation");
470             renderContext->UpdateOpacity(1);
471         },
472         nullptr);
473 }
474 
StartExitAnimation()475 void CheckBoxPattern::StartExitAnimation()
476 {
477     AnimationOption option;
478     option.SetCurve(Curves::FAST_OUT_SLOW_IN);
479     option.SetDuration(DEFAULT_CHECKBOX_ANIMATION_DURATION);
480     CHECK_NULL_VOID(builderNode_);
481     const auto& renderContext = builderNode_->GetRenderContext();
482     CHECK_NULL_VOID(renderContext);
483     AnimationUtils::Animate(
484         option,
485         [&]() {
486             TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "check exit animation");
487             renderContext->UpdateOpacity(0);
488         },
489         nullptr);
490     const auto& eventHub = builderNode_->GetEventHub<EventHub>();
491     if (eventHub) {
492         eventHub->SetEnabled(false);
493     }
494 }
495 
LoadBuilder()496 void CheckBoxPattern::LoadBuilder()
497 {
498     RefPtr<UINode> customNode;
499     if (builder_.has_value()) {
500         auto host = GetHost();
501         CHECK_NULL_VOID(host);
502         if (builderNode_) {
503             host->RemoveChildAndReturnIndex(builderNode_);
504         }
505         NG::ScopedViewStackProcessor builderViewStackProcessor;
506         builder_.value()();
507         customNode = NG::ViewStackProcessor::GetInstance()->Finish();
508         CHECK_NULL_VOID(customNode);
509         builderNode_ = AceType::DynamicCast<FrameNode>(customNode);
510         CHECK_NULL_VOID(builderNode_);
511         builderNode_->MountToParent(host);
512         host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
513     }
514 }
515 
StartCustomNodeAnimation(bool select)516 void CheckBoxPattern::StartCustomNodeAnimation(bool select)
517 {
518     if (!isFirstCreated_ && builder_.has_value()) {
519         if (select) {
520             StartEnterAnimation();
521         } else {
522             StartExitAnimation();
523         }
524     }
525 }
526 
UpdateCheckBoxGroupStatus(RefPtr<FrameNode> checkBoxGroupNode,const std::list<RefPtr<FrameNode>> & list)527 void CheckBoxPattern::UpdateCheckBoxGroupStatus(
528     RefPtr<FrameNode> checkBoxGroupNode, const std::list<RefPtr<FrameNode>>& list)
529 {
530     std::vector<std::string> vec;
531     bool haveCheckBoxSelected = false;
532     bool isAllCheckBoxSelected = true;
533     for (auto node : list) {
534         if (!node) {
535             continue;
536         }
537         auto paintProperty = node->GetPaintProperty<CheckBoxPaintProperty>();
538         CHECK_NULL_VOID(paintProperty);
539         if (paintProperty->GetCheckBoxSelectValue(false)) {
540             auto eventHub = node->GetEventHub<CheckBoxEventHub>();
541             CHECK_NULL_VOID(eventHub);
542             vec.push_back(eventHub->GetName());
543             haveCheckBoxSelected = true;
544         } else {
545             isAllCheckBoxSelected = false;
546         }
547     }
548     ChangeGroupStatusAndNotify(checkBoxGroupNode, vec, haveCheckBoxSelected, isAllCheckBoxSelected);
549 }
550 
ChangeGroupStatusAndNotify(const RefPtr<FrameNode> & checkBoxGroupNode,const std::vector<std::string> & vec,bool haveCheckBoxSelected,bool isAllCheckBoxSelected)551 void CheckBoxPattern::ChangeGroupStatusAndNotify(const RefPtr<FrameNode>& checkBoxGroupNode,
552     const std::vector<std::string>& vec, bool haveCheckBoxSelected, bool isAllCheckBoxSelected)
553 {
554     CHECK_NULL_VOID(checkBoxGroupNode);
555     auto groupPaintProperty = checkBoxGroupNode->GetPaintProperty<CheckBoxGroupPaintProperty>();
556     CHECK_NULL_VOID(groupPaintProperty);
557     auto pattern = checkBoxGroupNode->GetPattern<CheckBoxGroupPattern>();
558     CHECK_NULL_VOID(pattern);
559     auto preStatus = groupPaintProperty->GetSelectStatus();
560     if (haveCheckBoxSelected) {
561         if (isAllCheckBoxSelected) {
562             groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::ALL);
563             pattern->UpdateUIStatus(true);
564         } else {
565             groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::PART);
566             pattern->ResetUIStatus();
567         }
568     } else {
569         groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::NONE);
570         pattern->UpdateUIStatus(false);
571     }
572     checkBoxGroupNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
573     auto status = groupPaintProperty->GetSelectStatus();
574     if (preStatus != status && (preStatus == CheckBoxGroupPaintProperty::SelectStatus::ALL ||
575                                    status == CheckBoxGroupPaintProperty::SelectStatus::ALL)) {
576         pattern->SetSkipFlag(true);
577     }
578     CheckboxGroupResult groupResult(vec, int(status));
579     auto eventHub = checkBoxGroupNode->GetEventHub<CheckBoxGroupEventHub>();
580     CHECK_NULL_VOID(eventHub);
581     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "update checkboxgroup result %d", groupResult.GetStatus());
582     eventHub->UpdateChangeEvent(&groupResult);
583 }
584 
CheckBoxGroupIsTrue()585 void CheckBoxPattern::CheckBoxGroupIsTrue()
586 {
587     auto host = GetHost();
588     CHECK_NULL_VOID(host);
589     auto groupManager = GetGroupManager();
590     CHECK_NULL_VOID(groupManager);
591     auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
592     CHECK_NULL_VOID(paintProperty);
593     auto group = GetGroupNameWithNavId();
594     RefPtr<FrameNode> checkBoxGroupNode = groupManager->GetCheckboxGroup(group);
595     CHECK_NULL_VOID(checkBoxGroupNode);
596     std::vector<std::string> vec;
597     bool allSelectIsNull = true;
598     const auto& list = groupManager->GetCheckboxList(group);
599     for (auto node : list) {
600         if (!node) {
601             continue;
602         }
603         auto paintProperty = node->GetPaintProperty<CheckBoxPaintProperty>();
604         CHECK_NULL_VOID(paintProperty);
605         if (paintProperty->HasCheckBoxSelect()) {
606             allSelectIsNull = false;
607         } else {
608             paintProperty->UpdateCheckBoxSelect(false);
609         }
610     }
611     const auto& groupPaintProperty = checkBoxGroupNode->GetPaintProperty<CheckBoxGroupPaintProperty>();
612     CHECK_NULL_VOID(groupPaintProperty);
613     if (!groupManager->GetCheckboxGroupIsChange(group) && groupPaintProperty->GetIsCheckBoxCallbackDealed()) {
614         return;
615     }
616     // All checkboxes do not set select status.
617     if (allSelectIsNull && groupPaintProperty->GetCheckBoxGroupSelectValue(false)) {
618         InitCheckBoxStatusByGroup(checkBoxGroupNode, groupPaintProperty, list);
619     }
620     // Some checkboxes set select status.
621     if (!allSelectIsNull) {
622         UpdateCheckBoxGroupStatus(checkBoxGroupNode, list);
623     }
624     groupPaintProperty->SetIsCheckBoxCallbackDealed(true);
625     groupManager->SetCheckboxGroupIsChange(group, false);
626 }
627 
InitCheckBoxStatusByGroup(RefPtr<FrameNode> checkBoxGroupNode,const RefPtr<CheckBoxGroupPaintProperty> & groupPaintProperty,const std::list<RefPtr<FrameNode>> & list)628 void CheckBoxPattern::InitCheckBoxStatusByGroup(RefPtr<FrameNode> checkBoxGroupNode,
629     const RefPtr<CheckBoxGroupPaintProperty>& groupPaintProperty, const std::list<RefPtr<FrameNode>>& list)
630 {
631     if (groupPaintProperty->GetCheckBoxGroupSelectValue(false)) {
632         groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::ALL);
633         groupPaintProperty->UpdateCheckBoxGroupSelect(true);
634         checkBoxGroupNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
635         for (auto node : list) {
636             if (!node) {
637                 continue;
638             }
639             auto paintProperty = node->GetPaintProperty<CheckBoxPaintProperty>();
640             CHECK_NULL_VOID(paintProperty);
641             paintProperty->UpdateCheckBoxSelect(true);
642             auto checkBoxPattern = node->GetPattern<CheckBoxPattern>();
643             CHECK_NULL_VOID(checkBoxPattern);
644             checkBoxPattern->StartCustomNodeAnimation(true);
645             checkBoxPattern->UpdateUIStatus(true);
646             checkBoxPattern->SetLastSelect(true);
647         }
648     }
649 }
650 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)651 void CheckBoxPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
652 {
653     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
654         auto pattern = wp.Upgrade();
655         if (pattern) {
656             pattern->GetInnerFocusPaintRect(paintRect);
657         }
658     };
659     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
660 }
661 
GetInnerFocusPaintRect(RoundRect & paintRect)662 void CheckBoxPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
663 {
664     auto host = GetHost();
665     CHECK_NULL_VOID(host);
666     auto* pipelineContext = host->GetContextWithCheck();
667     CHECK_NULL_VOID(pipelineContext);
668     auto checkBoxTheme = pipelineContext->GetTheme<CheckboxTheme>();
669     CHECK_NULL_VOID(checkBoxTheme);
670     auto borderRadius = checkBoxTheme->GetFocusRadius().ConvertToPx();
671     auto focusPaintPadding = checkBoxTheme->GetFocusPaintPadding().ConvertToPx();
672     float originX = offset_.GetX() - focusPaintPadding;
673     float originY = offset_.GetY() - focusPaintPadding;
674     float width = size_.Width() + 2 * focusPaintPadding;
675     float height = size_.Height() + 2 * focusPaintPadding;
676     paintRect.SetRect({ originX, originY, width, height });
677     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, borderRadius, borderRadius);
678     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, borderRadius, borderRadius);
679     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, borderRadius, borderRadius);
680     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, borderRadius, borderRadius);
681 }
682 
GetFocusPattern() const683 FocusPattern CheckBoxPattern::GetFocusPattern() const
684 {
685     auto host = GetHost();
686     CHECK_NULL_RETURN(host, FocusPattern());
687     auto* pipeline = host->GetContextWithCheck();
688     CHECK_NULL_RETURN(pipeline, FocusPattern());
689     auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
690     CHECK_NULL_RETURN(checkBoxTheme, FocusPattern());
691     auto activeColor = checkBoxTheme->GetActiveColor();
692     FocusPaintParam focusPaintParam;
693     focusPaintParam.SetPaintColor(activeColor);
694     return { FocusType::NODE, true, FocusStyleType::CUSTOM_REGION, focusPaintParam };
695 }
696 
697 // Set the default hot zone for the component.
AddHotZoneRect()698 void CheckBoxPattern::AddHotZoneRect()
699 {
700     hotZoneOffset_.SetX(offset_.GetX() - hotZoneHorizontalPadding_.ConvertToPx());
701     hotZoneOffset_.SetY(offset_.GetY() - hotZoneVerticalPadding_.ConvertToPx());
702     hotZoneSize_.SetWidth(size_.Width() + 2 * hotZoneHorizontalPadding_.ConvertToPx());
703     hotZoneSize_.SetHeight(size_.Height() + 2 * hotZoneVerticalPadding_.ConvertToPx());
704     DimensionRect hotZoneRegion;
705     hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize_.Width()), Dimension(hotZoneSize_.Height())));
706     hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset_.GetX()), Dimension(hotZoneOffset_.GetY())));
707     auto host = GetHost();
708     CHECK_NULL_VOID(host);
709     auto gestureHub = host->GetOrCreateGestureEventHub();
710     CHECK_NULL_VOID(gestureHub);
711     std::vector<DimensionRect> hotZoneRegions;
712     hotZoneRegions.emplace_back(hotZoneRegion);
713     gestureHub->SetResponseRegion(hotZoneRegions);
714 }
715 
RemoveLastHotZoneRect() const716 void CheckBoxPattern::RemoveLastHotZoneRect() const
717 {
718     auto host = GetHost();
719     CHECK_NULL_VOID(host);
720     host->RemoveLastHotZoneRect();
721 }
722 
ProvideRestoreInfo()723 std::string CheckBoxPattern::ProvideRestoreInfo()
724 {
725     auto jsonObj = JsonUtil::Create(true);
726     auto checkBoxPaintProperty = GetPaintProperty<CheckBoxPaintProperty>();
727     CHECK_NULL_RETURN(checkBoxPaintProperty, "");
728     jsonObj->Put("isOn", checkBoxPaintProperty->GetCheckBoxSelect().value_or(false));
729     return jsonObj->ToString();
730 }
731 
OnRestoreInfo(const std::string & restoreInfo)732 void CheckBoxPattern::OnRestoreInfo(const std::string& restoreInfo)
733 {
734     auto checkBoxPaintProperty = GetPaintProperty<CheckBoxPaintProperty>();
735     CHECK_NULL_VOID(checkBoxPaintProperty);
736     auto info = JsonUtil::ParseJsonString(restoreInfo);
737     if (!info->IsValid() || !info->IsObject()) {
738         return;
739     }
740     auto jsonCheckBoxSelect = info->GetValue("isOn");
741     checkBoxPaintProperty->UpdateCheckBoxSelect(jsonCheckBoxSelect->GetBool());
742 }
743 
SetCheckBoxSelect(bool select)744 void CheckBoxPattern::SetCheckBoxSelect(bool select)
745 {
746     auto host = GetHost();
747     CHECK_NULL_VOID(host);
748     auto eventHub = host->GetEventHub<EventHub>();
749     CHECK_NULL_VOID(eventHub);
750     auto enabled = eventHub->IsEnabled();
751     if (!enabled) {
752         return;
753     }
754     auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
755     CHECK_NULL_VOID(paintProperty);
756     paintProperty->UpdateCheckBoxSelect(select);
757     UpdateState();
758     OnModifyDone();
759 }
760 
FireBuilder()761 void CheckBoxPattern::FireBuilder()
762 {
763     auto host = GetHost();
764     CHECK_NULL_VOID(host);
765     if (!makeFunc_.has_value() && !toggleMakeFunc_.has_value()) {
766         host->RemoveChildAndReturnIndex(contentModifierNode_);
767         contentModifierNode_ = nullptr;
768         host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
769         return;
770     }
771     auto node = BuildContentModifierNode();
772     if (contentModifierNode_ == node) {
773         return;
774     }
775     auto renderContext = host->GetRenderContext();
776     CHECK_NULL_VOID(renderContext);
777     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
778     host->RemoveChildAndReturnIndex(contentModifierNode_);
779     contentModifierNode_ = node;
780     CHECK_NULL_VOID(contentModifierNode_);
781     host->AddChild(contentModifierNode_, 0);
782     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
783 }
784 
BuildContentModifierNode()785 RefPtr<FrameNode> CheckBoxPattern::BuildContentModifierNode()
786 {
787     if (!makeFunc_.has_value() && !toggleMakeFunc_.has_value()) {
788         return nullptr;
789     }
790     auto host = GetHost();
791     CHECK_NULL_RETURN(host, nullptr);
792     auto eventHub = host->GetEventHub<CheckBoxEventHub>();
793     CHECK_NULL_RETURN(eventHub, nullptr);
794     auto name = eventHub->GetName();
795     auto enabled = eventHub->IsEnabled();
796     auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
797     CHECK_NULL_RETURN(paintProperty, nullptr);
798     bool isSelected = false;
799     if (paintProperty->HasCheckBoxSelect()) {
800         isSelected = paintProperty->GetCheckBoxSelectValue();
801     } else {
802         isSelected = false;
803     }
804     if (host->GetHostTag() == V2::CHECKBOX_ETS_TAG && toggleMakeFunc_.has_value()) {
805         return (toggleMakeFunc_.value())(ToggleConfiguration(enabled, isSelected));
806     }
807     CheckBoxConfiguration checkBoxConfiguration(name, isSelected, enabled);
808     return (makeFunc_.value())(checkBoxConfiguration);
809 }
810 
UpdatePaintPropertyBySettingData(RefPtr<CheckBoxPaintProperty> paintProp)811 void CheckBoxPattern::UpdatePaintPropertyBySettingData(RefPtr<CheckBoxPaintProperty> paintProp)
812 {
813     if (checkboxSettingData_.selectedColor.has_value()) {
814         paintProp->UpdateCheckBoxSelectedColor(checkboxSettingData_.selectedColor.value());
815     }
816     if (checkboxSettingData_.unselectedColor.has_value()) {
817         paintProp->UpdateCheckBoxUnSelectedColor(checkboxSettingData_.unselectedColor.value());
818     }
819     if (checkboxSettingData_.strokeColor.has_value()) {
820         paintProp->UpdateCheckBoxCheckMarkColor(checkboxSettingData_.strokeColor.value());
821     }
822 }
823 
OnColorConfigurationUpdate()824 void CheckBoxPattern::OnColorConfigurationUpdate()
825 {
826     auto host = GetHost();
827     CHECK_NULL_VOID(host);
828     auto* pipeline = host->GetContextWithCheck();
829     CHECK_NULL_VOID(pipeline);
830     auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
831     CHECK_NULL_VOID(checkBoxTheme);
832     auto checkBoxPaintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
833     CHECK_NULL_VOID(checkBoxPaintProperty);
834     checkBoxPaintProperty->UpdateCheckBoxSelectedColor(checkBoxTheme->GetActiveColor());
835     checkBoxPaintProperty->UpdateCheckBoxUnSelectedColor(checkBoxTheme->GetInactiveColor());
836     checkBoxPaintProperty->UpdateCheckBoxCheckMarkColor(checkBoxTheme->GetPointColor());
837     UpdatePaintPropertyBySettingData(checkBoxPaintProperty);
838     host->MarkModifyDone();
839     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
840 }
841 
SetPrePageIdToLastPageId()842 void CheckBoxPattern::SetPrePageIdToLastPageId()
843 {
844     if (!Container::IsInSubContainer()) {
845         auto pipelineContext = PipelineContext::GetCurrentContext();
846         CHECK_NULL_VOID(pipelineContext);
847         auto stageManager = pipelineContext->GetStageManager();
848         CHECK_NULL_VOID(stageManager);
849         auto pageNode = stageManager->GetLastPage();
850         CHECK_NULL_VOID(pageNode);
851         SetPrePageId(pageNode->GetId());
852     }
853 }
854 
OnAttachToMainTree()855 void CheckBoxPattern::OnAttachToMainTree()
856 {
857     auto host = GetHost();
858     CHECK_NULL_VOID(host);
859     auto groupManager = GetGroupManager();
860     CHECK_NULL_VOID(groupManager);
861     auto parent = host->GetParent();
862     while (parent) {
863         if (parent->GetTag() == V2::NAVDESTINATION_CONTENT_ETS_TAG) {
864             currentNavId_ = std::to_string(parent->GetId());
865             groupManager->SetLastNavId(currentNavId_);
866             UpdateState();
867             return;
868         }
869         parent = parent->GetParent();
870     }
871     if (!currentNavId_.value_or("").empty()) {
872         currentNavId_ = "";
873         groupManager->SetLastNavId(std::nullopt);
874         UpdateState();
875     }
876 }
877 
GetGroupNameWithNavId()878 std::string CheckBoxPattern::GetGroupNameWithNavId()
879 {
880     auto host = GetHost();
881     CHECK_NULL_RETURN(host, "");
882     auto eventHub = host->GetEventHub<CheckBoxEventHub>();
883     CHECK_NULL_RETURN(eventHub, "");
884     if (currentNavId_.has_value()) {
885         return eventHub->GetGroupName() + currentNavId_.value();
886     }
887     auto groupManager = GetGroupManager();
888     CHECK_NULL_RETURN(groupManager, eventHub->GetGroupName());
889     return eventHub->GetGroupName() + groupManager->GetLastNavId();
890 }
891 
GetGroupManager()892 RefPtr<GroupManager> CheckBoxPattern::GetGroupManager()
893 {
894     auto manager = groupManager_.Upgrade();
895     if (manager) {
896         return manager;
897     }
898     groupManager_ = GroupManager::GetGroupManager();
899     return groupManager_.Upgrade();
900 }
901 } // namespace OHOS::Ace::NG
902