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 eventHub = frameNode->GetEventHub<CheckBoxEventHub>();
351 CHECK_NULL_VOID(eventHub);
352 auto group = eventHub->GetGroupName() + currentNavId_.value_or(groupManager->GetLastNavId());
353 groupManager->RemoveCheckBoxFromGroup(group, frameNode->GetId());
354 auto groupNode = groupManager->GetCheckboxGroup(group);
355 CHECK_NULL_VOID(groupNode);
356 auto checkboxList = groupManager->GetCheckboxList(group);
357 UpdateCheckBoxGroupStatus(groupNode, checkboxList);
358 }
359
CheckPageNode()360 void CheckBoxPattern::CheckPageNode()
361 {
362 if (Container::IsInSubContainer()) {
363 return;
364 }
365 auto host = GetHost();
366 CHECK_NULL_VOID(host);
367 auto prePageId = GetPrePageId();
368 auto pipelineContext = GetContext();
369 CHECK_NULL_VOID(pipelineContext);
370 auto stageManager = pipelineContext->GetStageManager();
371 CHECK_NULL_VOID(stageManager);
372 auto pageNode = stageManager->GetPageById(host->GetPageId());
373 CHECK_NULL_VOID(pageNode);
374 if (pageNode->GetId() != prePageId) {
375 auto pageEventHub = pageNode->GetEventHub<NG::PageEventHub>();
376 CHECK_NULL_VOID(pageEventHub);
377 auto groupManager = pageEventHub->GetGroupManager();
378 CHECK_NULL_VOID(groupManager);
379 groupManager_ = groupManager;
380 auto group = GetGroupNameWithNavId();
381 groupManager->AddCheckBoxToGroup(group, host);
382 SetPrePageId(pageNode->GetId());
383 }
384 }
385
UpdateState()386 void CheckBoxPattern::UpdateState()
387 {
388 auto host = GetHost();
389 CHECK_NULL_VOID(host);
390 auto pipelineContext = GetContext();
391 CHECK_NULL_VOID(pipelineContext);
392 auto groupManager = GetGroupManager();
393 CHECK_NULL_VOID(groupManager);
394 auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
395 CHECK_NULL_VOID(paintProperty);
396 auto preGroup = GetPreGroup();
397 auto group = GetGroupNameWithNavId();
398 if (!preGroup.has_value()) {
399 groupManager->AddCheckBoxToGroup(group, host);
400 SetPrePageIdToLastPageId();
401 auto callback = [weak = WeakClaim(this)]() {
402 auto checkbox = weak.Upgrade();
403 if (checkbox) {
404 checkbox->CheckPageNode();
405 checkbox->CheckBoxGroupIsTrue();
406 }
407 };
408 pipelineContext->AddBuildFinishCallBack(callback);
409 if (paintProperty->HasCheckBoxSelect()) {
410 auto isSelected = paintProperty->GetCheckBoxSelectValue();
411 SetLastSelect(isSelected);
412 }
413 isFirstCreated_ = false;
414 SetPreGroup(group);
415 return;
416 }
417 if (preGroup.has_value() && preGroup.value() != group) {
418 groupManager->RemoveCheckBoxFromGroup(preGroup.value(), host->GetId());
419 groupManager->AddCheckBoxToGroup(group, host);
420 SetPrePageIdToLastPageId();
421 }
422 SetPreGroup(group);
423 ChangeSelfStatusAndNotify(paintProperty);
424 auto groupNode = groupManager->GetCheckboxGroup(group);
425 CHECK_NULL_VOID(groupNode);
426 auto checkboxList = groupManager->GetCheckboxList(group);
427 UpdateCheckBoxGroupStatus(groupNode, checkboxList);
428 }
429
ChangeSelfStatusAndNotify(const RefPtr<CheckBoxPaintProperty> & paintProperty)430 void CheckBoxPattern::ChangeSelfStatusAndNotify(const RefPtr<CheckBoxPaintProperty>& paintProperty)
431 {
432 auto host = GetHost();
433 CHECK_NULL_VOID(host);
434 bool isSelected = false;
435 if (paintProperty->HasCheckBoxSelect()) {
436 isSelected = paintProperty->GetCheckBoxSelectValue();
437 if (lastSelect_ != isSelected) {
438 UpdateUIStatus(isSelected);
439 SetLastSelect(isSelected);
440 auto checkboxEventHub = GetEventHub<CheckBoxEventHub>();
441 CHECK_NULL_VOID(checkboxEventHub);
442 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "checkbox node %{public}d update change event %{public}d",
443 host->GetId(), isSelected);
444 checkboxEventHub->UpdateChangeEvent(isSelected);
445 }
446 }
447 StartCustomNodeAnimation(isSelected);
448 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
449 FireBuilder();
450 }
451
StartEnterAnimation()452 void CheckBoxPattern::StartEnterAnimation()
453 {
454 AnimationOption option;
455 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
456 option.SetDuration(DEFAULT_CHECKBOX_ANIMATION_DURATION);
457 CHECK_NULL_VOID(builderNode_);
458 const auto& renderContext = builderNode_->GetRenderContext();
459 CHECK_NULL_VOID(renderContext);
460 renderContext->UpdateOpacity(0);
461 const auto& layoutProperty = builderNode_->GetLayoutProperty();
462 CHECK_NULL_VOID(layoutProperty);
463 layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
464 const auto& eventHub = builderNode_->GetEventHub<EventHub>();
465 if (eventHub) {
466 eventHub->SetEnabled(true);
467 }
468 AnimationUtils::Animate(
469 option,
470 [&]() {
471 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "check enter animation");
472 renderContext->UpdateOpacity(1);
473 },
474 nullptr);
475 }
476
StartExitAnimation()477 void CheckBoxPattern::StartExitAnimation()
478 {
479 AnimationOption option;
480 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
481 option.SetDuration(DEFAULT_CHECKBOX_ANIMATION_DURATION);
482 CHECK_NULL_VOID(builderNode_);
483 const auto& renderContext = builderNode_->GetRenderContext();
484 CHECK_NULL_VOID(renderContext);
485 AnimationUtils::Animate(
486 option,
487 [&]() {
488 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "check exit animation");
489 renderContext->UpdateOpacity(0);
490 },
491 nullptr);
492 const auto& eventHub = builderNode_->GetEventHub<EventHub>();
493 if (eventHub) {
494 eventHub->SetEnabled(false);
495 }
496 }
497
LoadBuilder()498 void CheckBoxPattern::LoadBuilder()
499 {
500 RefPtr<UINode> customNode;
501 if (builder_.has_value()) {
502 auto host = GetHost();
503 CHECK_NULL_VOID(host);
504 if (builderNode_) {
505 host->RemoveChildAndReturnIndex(builderNode_);
506 }
507 NG::ScopedViewStackProcessor builderViewStackProcessor;
508 builder_.value()();
509 customNode = NG::ViewStackProcessor::GetInstance()->Finish();
510 CHECK_NULL_VOID(customNode);
511 builderNode_ = AceType::DynamicCast<FrameNode>(customNode);
512 CHECK_NULL_VOID(builderNode_);
513 builderNode_->MountToParent(host);
514 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
515 }
516 }
517
StartCustomNodeAnimation(bool select)518 void CheckBoxPattern::StartCustomNodeAnimation(bool select)
519 {
520 if (!isFirstCreated_ && builder_.has_value()) {
521 if (select) {
522 StartEnterAnimation();
523 } else {
524 StartExitAnimation();
525 }
526 }
527 }
528
UpdateCheckBoxGroupStatus(RefPtr<FrameNode> checkBoxGroupNode,const std::list<RefPtr<FrameNode>> & list)529 void CheckBoxPattern::UpdateCheckBoxGroupStatus(
530 RefPtr<FrameNode> checkBoxGroupNode, const std::list<RefPtr<FrameNode>>& list)
531 {
532 std::vector<std::string> vec;
533 bool haveCheckBoxSelected = false;
534 bool isAllCheckBoxSelected = true;
535 for (auto node : list) {
536 if (!node) {
537 continue;
538 }
539 auto paintProperty = node->GetPaintProperty<CheckBoxPaintProperty>();
540 CHECK_NULL_VOID(paintProperty);
541 if (paintProperty->GetCheckBoxSelectValue(false)) {
542 auto eventHub = node->GetEventHub<CheckBoxEventHub>();
543 CHECK_NULL_VOID(eventHub);
544 vec.push_back(eventHub->GetName());
545 haveCheckBoxSelected = true;
546 } else {
547 isAllCheckBoxSelected = false;
548 }
549 }
550 ChangeGroupStatusAndNotify(checkBoxGroupNode, vec, haveCheckBoxSelected, isAllCheckBoxSelected);
551 }
552
ChangeGroupStatusAndNotify(const RefPtr<FrameNode> & checkBoxGroupNode,const std::vector<std::string> & vec,bool haveCheckBoxSelected,bool isAllCheckBoxSelected)553 void CheckBoxPattern::ChangeGroupStatusAndNotify(const RefPtr<FrameNode>& checkBoxGroupNode,
554 const std::vector<std::string>& vec, bool haveCheckBoxSelected, bool isAllCheckBoxSelected)
555 {
556 CHECK_NULL_VOID(checkBoxGroupNode);
557 auto groupPaintProperty = checkBoxGroupNode->GetPaintProperty<CheckBoxGroupPaintProperty>();
558 CHECK_NULL_VOID(groupPaintProperty);
559 auto pattern = checkBoxGroupNode->GetPattern<CheckBoxGroupPattern>();
560 CHECK_NULL_VOID(pattern);
561 auto preStatus = groupPaintProperty->GetSelectStatus();
562 if (haveCheckBoxSelected) {
563 if (isAllCheckBoxSelected) {
564 groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::ALL);
565 pattern->UpdateUIStatus(true);
566 } else {
567 groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::PART);
568 pattern->ResetUIStatus();
569 }
570 } else {
571 groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::NONE);
572 pattern->UpdateUIStatus(false);
573 }
574 checkBoxGroupNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
575 auto status = groupPaintProperty->GetSelectStatus();
576 if (preStatus != status && (preStatus == CheckBoxGroupPaintProperty::SelectStatus::ALL ||
577 status == CheckBoxGroupPaintProperty::SelectStatus::ALL)) {
578 pattern->SetSkipFlag(true);
579 }
580 CheckboxGroupResult groupResult(vec, int(status));
581 auto eventHub = checkBoxGroupNode->GetEventHub<CheckBoxGroupEventHub>();
582 CHECK_NULL_VOID(eventHub);
583 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "update checkboxgroup result %d", groupResult.GetStatus());
584 eventHub->UpdateChangeEvent(&groupResult);
585 }
586
CheckBoxGroupIsTrue()587 void CheckBoxPattern::CheckBoxGroupIsTrue()
588 {
589 auto host = GetHost();
590 CHECK_NULL_VOID(host);
591 auto groupManager = GetGroupManager();
592 CHECK_NULL_VOID(groupManager);
593 auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
594 CHECK_NULL_VOID(paintProperty);
595 auto group = GetGroupNameWithNavId();
596 RefPtr<FrameNode> checkBoxGroupNode = groupManager->GetCheckboxGroup(group);
597 CHECK_NULL_VOID(checkBoxGroupNode);
598 std::vector<std::string> vec;
599 bool allSelectIsNull = true;
600 const auto& list = groupManager->GetCheckboxList(group);
601 for (auto node : list) {
602 if (!node) {
603 continue;
604 }
605 auto paintProperty = node->GetPaintProperty<CheckBoxPaintProperty>();
606 CHECK_NULL_VOID(paintProperty);
607 if (paintProperty->HasCheckBoxSelect()) {
608 allSelectIsNull = false;
609 } else {
610 paintProperty->UpdateCheckBoxSelect(false);
611 }
612 }
613 const auto& groupPaintProperty = checkBoxGroupNode->GetPaintProperty<CheckBoxGroupPaintProperty>();
614 CHECK_NULL_VOID(groupPaintProperty);
615 if (!groupManager->GetCheckboxGroupIsChange(group) && groupPaintProperty->GetIsCheckBoxCallbackDealed()) {
616 return;
617 }
618 // All checkboxes do not set select status.
619 if (allSelectIsNull && groupPaintProperty->GetCheckBoxGroupSelectValue(false)) {
620 InitCheckBoxStatusByGroup(checkBoxGroupNode, groupPaintProperty, list);
621 }
622 // Some checkboxes set select status.
623 if (!allSelectIsNull) {
624 UpdateCheckBoxGroupStatus(checkBoxGroupNode, list);
625 }
626 groupPaintProperty->SetIsCheckBoxCallbackDealed(true);
627 groupManager->SetCheckboxGroupIsChange(group, false);
628 }
629
InitCheckBoxStatusByGroup(RefPtr<FrameNode> checkBoxGroupNode,const RefPtr<CheckBoxGroupPaintProperty> & groupPaintProperty,const std::list<RefPtr<FrameNode>> & list)630 void CheckBoxPattern::InitCheckBoxStatusByGroup(RefPtr<FrameNode> checkBoxGroupNode,
631 const RefPtr<CheckBoxGroupPaintProperty>& groupPaintProperty, const std::list<RefPtr<FrameNode>>& list)
632 {
633 if (groupPaintProperty->GetCheckBoxGroupSelectValue(false)) {
634 groupPaintProperty->SetSelectStatus(CheckBoxGroupPaintProperty::SelectStatus::ALL);
635 groupPaintProperty->UpdateCheckBoxGroupSelect(true);
636 checkBoxGroupNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
637 for (auto node : list) {
638 if (!node) {
639 continue;
640 }
641 auto paintProperty = node->GetPaintProperty<CheckBoxPaintProperty>();
642 CHECK_NULL_VOID(paintProperty);
643 paintProperty->UpdateCheckBoxSelect(true);
644 auto checkBoxPattern = node->GetPattern<CheckBoxPattern>();
645 CHECK_NULL_VOID(checkBoxPattern);
646 checkBoxPattern->StartCustomNodeAnimation(true);
647 checkBoxPattern->UpdateUIStatus(true);
648 checkBoxPattern->SetLastSelect(true);
649 }
650 }
651 }
652
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)653 void CheckBoxPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
654 {
655 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
656 auto pattern = wp.Upgrade();
657 if (pattern) {
658 pattern->GetInnerFocusPaintRect(paintRect);
659 }
660 };
661 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
662 }
663
GetInnerFocusPaintRect(RoundRect & paintRect)664 void CheckBoxPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
665 {
666 auto host = GetHost();
667 CHECK_NULL_VOID(host);
668 auto* pipelineContext = host->GetContextWithCheck();
669 CHECK_NULL_VOID(pipelineContext);
670 auto checkBoxTheme = pipelineContext->GetTheme<CheckboxTheme>();
671 CHECK_NULL_VOID(checkBoxTheme);
672 auto borderRadius = checkBoxTheme->GetFocusRadius().ConvertToPx();
673 auto focusPaintPadding = checkBoxTheme->GetFocusPaintPadding().ConvertToPx();
674 float originX = offset_.GetX() - focusPaintPadding;
675 float originY = offset_.GetY() - focusPaintPadding;
676 float width = size_.Width() + 2 * focusPaintPadding;
677 float height = size_.Height() + 2 * focusPaintPadding;
678 paintRect.SetRect({ originX, originY, width, height });
679 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, borderRadius, borderRadius);
680 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, borderRadius, borderRadius);
681 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, borderRadius, borderRadius);
682 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, borderRadius, borderRadius);
683 }
684
GetFocusPattern() const685 FocusPattern CheckBoxPattern::GetFocusPattern() const
686 {
687 auto host = GetHost();
688 CHECK_NULL_RETURN(host, FocusPattern());
689 auto* pipeline = host->GetContextWithCheck();
690 CHECK_NULL_RETURN(pipeline, FocusPattern());
691 auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
692 CHECK_NULL_RETURN(checkBoxTheme, FocusPattern());
693 auto activeColor = checkBoxTheme->GetActiveColor();
694 FocusPaintParam focusPaintParam;
695 focusPaintParam.SetPaintColor(activeColor);
696 return { FocusType::NODE, true, FocusStyleType::CUSTOM_REGION, focusPaintParam };
697 }
698
699 // Set the default hot zone for the component.
AddHotZoneRect()700 void CheckBoxPattern::AddHotZoneRect()
701 {
702 hotZoneOffset_.SetX(offset_.GetX() - hotZoneHorizontalPadding_.ConvertToPx());
703 hotZoneOffset_.SetY(offset_.GetY() - hotZoneVerticalPadding_.ConvertToPx());
704 hotZoneSize_.SetWidth(size_.Width() + 2 * hotZoneHorizontalPadding_.ConvertToPx());
705 hotZoneSize_.SetHeight(size_.Height() + 2 * hotZoneVerticalPadding_.ConvertToPx());
706 DimensionRect hotZoneRegion;
707 hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize_.Width()), Dimension(hotZoneSize_.Height())));
708 hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset_.GetX()), Dimension(hotZoneOffset_.GetY())));
709 auto host = GetHost();
710 CHECK_NULL_VOID(host);
711 auto gestureHub = host->GetOrCreateGestureEventHub();
712 CHECK_NULL_VOID(gestureHub);
713 std::vector<DimensionRect> hotZoneRegions;
714 hotZoneRegions.emplace_back(hotZoneRegion);
715 gestureHub->SetResponseRegion(hotZoneRegions);
716 }
717
RemoveLastHotZoneRect() const718 void CheckBoxPattern::RemoveLastHotZoneRect() const
719 {
720 auto host = GetHost();
721 CHECK_NULL_VOID(host);
722 host->RemoveLastHotZoneRect();
723 }
724
ProvideRestoreInfo()725 std::string CheckBoxPattern::ProvideRestoreInfo()
726 {
727 auto jsonObj = JsonUtil::Create(true);
728 auto checkBoxPaintProperty = GetPaintProperty<CheckBoxPaintProperty>();
729 CHECK_NULL_RETURN(checkBoxPaintProperty, "");
730 jsonObj->Put("isOn", checkBoxPaintProperty->GetCheckBoxSelect().value_or(false));
731 return jsonObj->ToString();
732 }
733
OnRestoreInfo(const std::string & restoreInfo)734 void CheckBoxPattern::OnRestoreInfo(const std::string& restoreInfo)
735 {
736 auto checkBoxPaintProperty = GetPaintProperty<CheckBoxPaintProperty>();
737 CHECK_NULL_VOID(checkBoxPaintProperty);
738 auto info = JsonUtil::ParseJsonString(restoreInfo);
739 if (!info->IsValid() || !info->IsObject()) {
740 return;
741 }
742 auto jsonCheckBoxSelect = info->GetValue("isOn");
743 checkBoxPaintProperty->UpdateCheckBoxSelect(jsonCheckBoxSelect->GetBool());
744 }
745
SetCheckBoxSelect(bool select)746 void CheckBoxPattern::SetCheckBoxSelect(bool select)
747 {
748 auto host = GetHost();
749 CHECK_NULL_VOID(host);
750 auto eventHub = host->GetEventHub<EventHub>();
751 CHECK_NULL_VOID(eventHub);
752 auto enabled = eventHub->IsEnabled();
753 if (!enabled) {
754 return;
755 }
756 auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
757 CHECK_NULL_VOID(paintProperty);
758 paintProperty->UpdateCheckBoxSelect(select);
759 UpdateState();
760 OnModifyDone();
761 }
762
FireBuilder()763 void CheckBoxPattern::FireBuilder()
764 {
765 auto host = GetHost();
766 CHECK_NULL_VOID(host);
767 if (!makeFunc_.has_value() && !toggleMakeFunc_.has_value()) {
768 host->RemoveChildAndReturnIndex(contentModifierNode_);
769 contentModifierNode_ = nullptr;
770 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
771 return;
772 }
773 auto node = BuildContentModifierNode();
774 if (contentModifierNode_ == node) {
775 return;
776 }
777 auto renderContext = host->GetRenderContext();
778 CHECK_NULL_VOID(renderContext);
779 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
780 host->RemoveChildAndReturnIndex(contentModifierNode_);
781 contentModifierNode_ = node;
782 CHECK_NULL_VOID(contentModifierNode_);
783 host->AddChild(contentModifierNode_, 0);
784 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
785 }
786
BuildContentModifierNode()787 RefPtr<FrameNode> CheckBoxPattern::BuildContentModifierNode()
788 {
789 if (!makeFunc_.has_value() && !toggleMakeFunc_.has_value()) {
790 return nullptr;
791 }
792 auto host = GetHost();
793 CHECK_NULL_RETURN(host, nullptr);
794 auto eventHub = host->GetEventHub<CheckBoxEventHub>();
795 CHECK_NULL_RETURN(eventHub, nullptr);
796 auto name = eventHub->GetName();
797 auto enabled = eventHub->IsEnabled();
798 auto paintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
799 CHECK_NULL_RETURN(paintProperty, nullptr);
800 bool isSelected = false;
801 if (paintProperty->HasCheckBoxSelect()) {
802 isSelected = paintProperty->GetCheckBoxSelectValue();
803 } else {
804 isSelected = false;
805 }
806 if (host->GetHostTag() == V2::CHECKBOX_ETS_TAG && toggleMakeFunc_.has_value()) {
807 return (toggleMakeFunc_.value())(ToggleConfiguration(enabled, isSelected));
808 }
809 CheckBoxConfiguration checkBoxConfiguration(name, isSelected, enabled);
810 return (makeFunc_.value())(checkBoxConfiguration);
811 }
812
UpdatePaintPropertyBySettingData(RefPtr<CheckBoxPaintProperty> paintProp)813 void CheckBoxPattern::UpdatePaintPropertyBySettingData(RefPtr<CheckBoxPaintProperty> paintProp)
814 {
815 if (checkboxSettingData_.selectedColor.has_value()) {
816 paintProp->UpdateCheckBoxSelectedColor(checkboxSettingData_.selectedColor.value());
817 }
818 if (checkboxSettingData_.unselectedColor.has_value()) {
819 paintProp->UpdateCheckBoxUnSelectedColor(checkboxSettingData_.unselectedColor.value());
820 }
821 if (checkboxSettingData_.strokeColor.has_value()) {
822 paintProp->UpdateCheckBoxCheckMarkColor(checkboxSettingData_.strokeColor.value());
823 }
824 }
825
OnColorConfigurationUpdate()826 void CheckBoxPattern::OnColorConfigurationUpdate()
827 {
828 auto host = GetHost();
829 CHECK_NULL_VOID(host);
830 auto* pipeline = host->GetContextWithCheck();
831 CHECK_NULL_VOID(pipeline);
832 auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
833 CHECK_NULL_VOID(checkBoxTheme);
834 auto checkBoxPaintProperty = host->GetPaintProperty<CheckBoxPaintProperty>();
835 CHECK_NULL_VOID(checkBoxPaintProperty);
836 checkBoxPaintProperty->UpdateCheckBoxSelectedColor(checkBoxTheme->GetActiveColor());
837 checkBoxPaintProperty->UpdateCheckBoxUnSelectedColor(checkBoxTheme->GetInactiveColor());
838 checkBoxPaintProperty->UpdateCheckBoxCheckMarkColor(checkBoxTheme->GetPointColor());
839 UpdatePaintPropertyBySettingData(checkBoxPaintProperty);
840 host->MarkModifyDone();
841 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
842 }
843
SetPrePageIdToLastPageId()844 void CheckBoxPattern::SetPrePageIdToLastPageId()
845 {
846 if (!Container::IsInSubContainer()) {
847 auto pipelineContext = PipelineContext::GetCurrentContext();
848 CHECK_NULL_VOID(pipelineContext);
849 auto stageManager = pipelineContext->GetStageManager();
850 CHECK_NULL_VOID(stageManager);
851 auto pageNode = stageManager->GetLastPage();
852 CHECK_NULL_VOID(pageNode);
853 SetPrePageId(pageNode->GetId());
854 }
855 }
856
OnAttachToMainTree()857 void CheckBoxPattern::OnAttachToMainTree()
858 {
859 auto host = GetHost();
860 CHECK_NULL_VOID(host);
861 auto groupManager = GetGroupManager();
862 CHECK_NULL_VOID(groupManager);
863 auto parent = host->GetParent();
864 while (parent) {
865 if (parent->GetTag() == V2::NAVDESTINATION_CONTENT_ETS_TAG) {
866 currentNavId_ = std::to_string(parent->GetId());
867 groupManager->SetLastNavId(currentNavId_);
868 UpdateState();
869 return;
870 }
871 parent = parent->GetParent();
872 }
873 if (!currentNavId_.value_or("").empty()) {
874 currentNavId_ = "";
875 groupManager->SetLastNavId(std::nullopt);
876 UpdateState();
877 }
878 }
879
GetGroupNameWithNavId()880 std::string CheckBoxPattern::GetGroupNameWithNavId()
881 {
882 auto host = GetHost();
883 CHECK_NULL_RETURN(host, "");
884 auto eventHub = host->GetEventHub<CheckBoxEventHub>();
885 CHECK_NULL_RETURN(eventHub, "");
886 if (currentNavId_.has_value()) {
887 return eventHub->GetGroupName() + currentNavId_.value();
888 }
889 auto groupManager = GetGroupManager();
890 CHECK_NULL_RETURN(groupManager, eventHub->GetGroupName());
891 return eventHub->GetGroupName() + groupManager->GetLastNavId();
892 }
893
GetGroupManager()894 RefPtr<GroupManager> CheckBoxPattern::GetGroupManager()
895 {
896 auto manager = groupManager_.Upgrade();
897 if (manager) {
898 return manager;
899 }
900 groupManager_ = GroupManager::GetGroupManager();
901 return groupManager_.Upgrade();
902 }
903 } // namespace OHOS::Ace::NG
904