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