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/toggle/switch_pattern.h"
17
18 #include <cmath>
19 #include <cstdint>
20
21 #include "base/memory/referenced.h"
22 #include "base/utils/utils.h"
23 #include "core/animation/curve.h"
24 #include "core/animation/curves.h"
25 #include "core/common/container.h"
26 #include "core/common/recorder/node_data_cache.h"
27 #include "core/components/checkable/checkable_theme.h"
28 #include "core/components_ng/pattern/toggle/switch_layout_algorithm.h"
29 #include "core/components_ng/pattern/toggle/switch_paint_property.h"
30 #include "core/components_ng/property/property.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr int32_t DEFAULT_DURATION = 200;
36 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
37 constexpr double NUMBER_TWO = 2.0;
38 } // namespace
39
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)40 bool SwitchPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
41 {
42 if (skipMeasure || dirty->SkipMeasureContent()) {
43 return false;
44 }
45 if (isOn_.value_or(false)) {
46 currentOffset_ = GetSwitchWidth();
47 }
48
49 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
50 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
51 auto switchLayoutAlgorithm = DynamicCast<SwitchLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
52 CHECK_NULL_RETURN(switchLayoutAlgorithm, false);
53
54 auto height = switchLayoutAlgorithm->GetHeight();
55 auto width = switchLayoutAlgorithm->GetWidth();
56
57 width_ = width;
58 height_ = height;
59 auto geometryNode = dirty->GetGeometryNode();
60 offset_ = geometryNode->GetContentOffset();
61 size_ = geometryNode->GetContentSize();
62 if (!isUserSetResponseRegion_) {
63 AddHotZoneRect();
64 }
65 return true;
66 }
67
OnModifyDone()68 void SwitchPattern::OnModifyDone()
69 {
70 Pattern::OnModifyDone();
71 UpdateSwitchLayoutProperty();
72 UpdateSwitchPaintProperty();
73 InitClickEvent();
74 auto host = GetHost();
75 CHECK_NULL_VOID(host);
76 auto hub = host->GetEventHub<EventHub>();
77 CHECK_NULL_VOID(hub);
78 auto enabled = hub->IsEnabled();
79 if (enabled_ != enabled) {
80 enabled_ = enabled;
81 auto paintProperty = GetPaintProperty<SwitchPaintProperty>();
82 CHECK_NULL_VOID(paintProperty);
83 paintProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_RENDER);
84 }
85 auto gestureHub = hub->GetOrCreateGestureEventHub();
86 CHECK_NULL_VOID(gestureHub);
87 InitPanEvent(gestureHub);
88 InitTouchEvent();
89 InitMouseEvent();
90 auto focusHub = host->GetFocusHub();
91 CHECK_NULL_VOID(focusHub);
92 InitOnKeyEvent(focusHub);
93 SetAccessibilityAction();
94 FireBuilder();
95 }
96
UpdateSwitchPaintProperty()97 void SwitchPattern::UpdateSwitchPaintProperty()
98 {
99 auto host = GetHost();
100 CHECK_NULL_VOID(host);
101 auto switchPaintProperty = host->GetPaintProperty<SwitchPaintProperty>();
102 CHECK_NULL_VOID(switchPaintProperty);
103 auto geometryNode = host->GetGeometryNode();
104 CHECK_NULL_VOID(geometryNode);
105 if (!isOn_.has_value()) {
106 isOn_ = switchPaintProperty->GetIsOnValue(false);
107 }
108 auto isOn = switchPaintProperty->GetIsOnValue(false);
109 if (isOn != isOn_.value_or(false)) {
110 isOn_ = isOn;
111 OnChange();
112 }
113 }
114
UpdateSwitchLayoutProperty()115 void SwitchPattern::UpdateSwitchLayoutProperty()
116 {
117 auto pipeline = GetContext();
118 CHECK_NULL_VOID(pipeline);
119 auto switchTheme = pipeline->GetTheme<SwitchTheme>();
120 CHECK_NULL_VOID(switchTheme);
121 MarginProperty margin;
122 margin.left = CalcLength(switchTheme->GetHotZoneHorizontalPadding().Value());
123 margin.right = CalcLength(switchTheme->GetHotZoneHorizontalPadding().Value());
124 margin.top = CalcLength(switchTheme->GetHotZoneVerticalPadding().Value());
125 margin.bottom = CalcLength(switchTheme->GetHotZoneVerticalPadding().Value());
126 auto host = GetHost();
127 CHECK_NULL_VOID(host);
128 auto layoutProperty = host->GetLayoutProperty();
129 CHECK_NULL_VOID(layoutProperty);
130 direction_ = layoutProperty->GetNonAutoLayoutDirection();
131 auto& setMargin = layoutProperty->GetMarginProperty();
132 if (setMargin) {
133 if (setMargin->left.has_value()) {
134 margin.left = setMargin->left;
135 }
136 if (setMargin->right.has_value()) {
137 margin.right = setMargin->right;
138 }
139 if (setMargin->top.has_value()) {
140 margin.top = setMargin->top;
141 }
142 if (setMargin->bottom.has_value()) {
143 margin.bottom = setMargin->bottom;
144 }
145 }
146 layoutProperty->UpdateMargin(margin);
147 hotZoneHorizontalPadding_ = switchTheme->GetHotZoneHorizontalPadding();
148 hotZoneVerticalPadding_ = switchTheme->GetHotZoneVerticalPadding();
149 if (layoutProperty->GetPositionProperty()) {
150 layoutProperty->UpdateAlignment(
151 layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER));
152 } else {
153 layoutProperty->UpdateAlignment(Alignment::CENTER);
154 }
155 }
156
SetAccessibilityAction()157 void SwitchPattern::SetAccessibilityAction()
158 {
159 auto host = GetHost();
160 CHECK_NULL_VOID(host);
161 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
162 CHECK_NULL_VOID(accessibilityProperty);
163 accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
164 const auto& pattern = weakPtr.Upgrade();
165 CHECK_NULL_VOID(pattern);
166 pattern->UpdateSelectStatus(true);
167 });
168
169 accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
170 const auto& pattern = weakPtr.Upgrade();
171 CHECK_NULL_VOID(pattern);
172 pattern->UpdateSelectStatus(false);
173 });
174 FireBuilder();
175 }
176
UpdateSelectStatus(bool isSelected)177 void SwitchPattern::UpdateSelectStatus(bool isSelected)
178 {
179 auto host = GetHost();
180 CHECK_NULL_VOID(host);
181 auto context = host->GetRenderContext();
182 CHECK_NULL_VOID(context);
183 MarkIsSelected(isSelected);
184 context->OnMouseSelectUpdate(isSelected, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
185 }
186
MarkIsSelected(bool isSelected)187 void SwitchPattern::MarkIsSelected(bool isSelected)
188 {
189 if (isOn_ == isSelected) {
190 return;
191 }
192 isOn_ = isSelected;
193 auto eventHub = GetEventHub<SwitchEventHub>();
194 CHECK_NULL_VOID(eventHub);
195 eventHub->UpdateChangeEvent(isSelected);
196 auto host = GetHost();
197 CHECK_NULL_VOID(host);
198 eventHub->SetCurrentUIState(UI_STATE_SELECTED, isSelected);
199 host->OnAccessibilityEvent(AccessibilityEventType::COMPONENT_CHANGE);
200 }
201
OnAfterModifyDone()202 void SwitchPattern::OnAfterModifyDone()
203 {
204 auto host = GetHost();
205 CHECK_NULL_VOID(host);
206 auto inspectorId = host->GetInspectorId().value_or("");
207 if (!inspectorId.empty()) {
208 Recorder::NodeDataCache::Get().PutBool(host, inspectorId, isOn_.value_or(false));
209 }
210 }
211
GetCurve() const212 RefPtr<Curve> SwitchPattern::GetCurve() const
213 {
214 auto switchPaintProperty = GetPaintProperty<SwitchPaintProperty>();
215 CHECK_NULL_RETURN(switchPaintProperty, nullptr);
216 return switchPaintProperty->GetCurve().value_or(nullptr);
217 }
218
GetDuration() const219 int32_t SwitchPattern::GetDuration() const
220 {
221 auto switchPaintProperty = GetPaintProperty<SwitchPaintProperty>();
222 CHECK_NULL_RETURN(switchPaintProperty, DEFAULT_DURATION);
223 return switchPaintProperty->GetDuration().value_or(DEFAULT_DURATION);
224 }
225
OnChange()226 void SwitchPattern::OnChange()
227 {
228 auto host = GetHost();
229 CHECK_NULL_VOID(host);
230 auto switchPaintProperty = host->GetPaintProperty<SwitchPaintProperty>();
231 CHECK_NULL_VOID(switchPaintProperty);
232 switchPaintProperty->UpdateIsOn(isOn_.value_or(false));
233 UpdateChangeEvent();
234 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
235 }
236
GetSwitchWidth() const237 float SwitchPattern::GetSwitchWidth() const
238 {
239 auto host = GetHost();
240 CHECK_NULL_RETURN(host, false);
241 auto geometryNode = host->GetGeometryNode();
242 CHECK_NULL_RETURN(geometryNode, false);
243 auto switchWidth = geometryNode->GetContentSize().Width() - geometryNode->GetContentSize().Height();
244 return switchWidth;
245 }
246
GetSwitchContentOffsetX() const247 float SwitchPattern::GetSwitchContentOffsetX() const
248 {
249 auto host = GetHost();
250 CHECK_NULL_RETURN(host, 0.0f);
251 auto geometryNode = host->GetGeometryNode();
252 CHECK_NULL_RETURN(geometryNode, 0.0f);
253 return geometryNode->GetContentOffset().GetX();
254 }
255
UpdateChangeEvent() const256 void SwitchPattern::UpdateChangeEvent() const
257 {
258 auto switchEventHub = GetEventHub<SwitchEventHub>();
259 CHECK_NULL_VOID(switchEventHub);
260 switchEventHub->UpdateChangeEvent(isOn_.value());
261 }
262
OnClick()263 void SwitchPattern::OnClick()
264 {
265 if (UseContentModifier()) {
266 return;
267 }
268 isOn_ = !isOn_.value_or(false);
269 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch click result %{public}d", isOn_.value_or(false));
270 OnChange();
271 auto host = GetHost();
272 CHECK_NULL_VOID(host);
273 host->OnAccessibilityEvent(AccessibilityEventType::COMPONENT_CHANGE);
274 }
275
OnTouchDown()276 void SwitchPattern::OnTouchDown()
277 {
278 if (UseContentModifier()) {
279 return;
280 }
281 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch touch down hover status %{public}d", isHover_);
282 if (isHover_) {
283 touchHoverType_ = TouchHoverAnimationType::HOVER_TO_PRESS;
284 } else {
285 touchHoverType_ = TouchHoverAnimationType::PRESS;
286 }
287 auto host = GetHost();
288 CHECK_NULL_VOID(host);
289 isTouch_ = true;
290 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
291 }
292
OnTouchUp()293 void SwitchPattern::OnTouchUp()
294 {
295 if (UseContentModifier()) {
296 return;
297 }
298 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch touch up hover status %{public}d", isHover_);
299 if (isHover_) {
300 touchHoverType_ = TouchHoverAnimationType::PRESS_TO_HOVER;
301 } else {
302 touchHoverType_ = TouchHoverAnimationType::NONE;
303 }
304 auto host = GetHost();
305 CHECK_NULL_VOID(host);
306 isTouch_ = false;
307 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
308 FireBuilder();
309 }
310
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)311 void SwitchPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
312 {
313 if (panEvent_) {
314 return;
315 }
316
317 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
318 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag start");
319 auto pattern = weak.Upgrade();
320 CHECK_NULL_VOID(pattern);
321 if (info.GetInputEventType() == InputEventType::AXIS) {
322 return;
323 }
324 pattern->HandleDragStart();
325 };
326
327 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
328 auto pattern = weak.Upgrade();
329 CHECK_NULL_VOID(pattern);
330 pattern->HandleDragUpdate(info);
331 };
332
333 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
334 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag end");
335 auto pattern = weak.Upgrade();
336 CHECK_NULL_VOID(pattern);
337 if (info.GetInputEventType() == InputEventType::AXIS) {
338 return;
339 }
340 pattern->HandleDragEnd();
341 };
342
343 auto actionCancelTask = [weak = WeakClaim(this)]() {
344 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag cancel");
345 auto pattern = weak.Upgrade();
346 CHECK_NULL_VOID(pattern);
347 pattern->HandleDragEnd();
348 };
349
350 PanDirection panDirection;
351 panDirection.type = PanDirection::HORIZONTAL;
352
353 panEvent_ = MakeRefPtr<PanEvent>(
354 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
355 gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
356 }
357
InitClickEvent()358 void SwitchPattern::InitClickEvent()
359 {
360 if (clickListener_) {
361 return;
362 }
363 auto host = GetHost();
364 CHECK_NULL_VOID(host);
365 auto gesture = host->GetOrCreateGestureEventHub();
366 CHECK_NULL_VOID(gesture);
367 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
368 auto switchPattern = weak.Upgrade();
369 CHECK_NULL_VOID(switchPattern);
370 switchPattern->OnClick();
371 };
372
373 clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
374 gesture->AddClickEvent(clickListener_);
375 }
376
InitTouchEvent()377 void SwitchPattern::InitTouchEvent()
378 {
379 if (touchListener_) {
380 return;
381 }
382 auto host = GetHost();
383 CHECK_NULL_VOID(host);
384 auto gesture = host->GetOrCreateGestureEventHub();
385 CHECK_NULL_VOID(gesture);
386 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
387 auto switchPattern = weak.Upgrade();
388 CHECK_NULL_VOID(switchPattern);
389 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
390 switchPattern->OnTouchDown();
391 }
392 if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
393 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
394 switchPattern->OnTouchUp();
395 }
396 };
397 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
398 gesture->AddTouchEvent(touchListener_);
399 }
400
InitMouseEvent()401 void SwitchPattern::InitMouseEvent()
402 {
403 if (mouseEvent_) {
404 return;
405 }
406 auto host = GetHost();
407 CHECK_NULL_VOID(host);
408 auto gesture = host->GetOrCreateGestureEventHub();
409 CHECK_NULL_VOID(gesture);
410 auto eventHub = GetHost()->GetEventHub<SwitchEventHub>();
411 auto inputHub = eventHub->GetOrCreateInputEventHub();
412
413 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
414 auto pattern = weak.Upgrade();
415 CHECK_NULL_VOID(pattern);
416 pattern->HandleMouseEvent(isHover);
417 };
418 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
419 inputHub->AddOnHoverEvent(mouseEvent_);
420 }
421
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)422 void SwitchPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
423 {
424 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
425 auto pattern = wp.Upgrade();
426 if (pattern) {
427 pattern->GetInnerFocusPaintRect(paintRect);
428 }
429 };
430 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
431 }
432
GetInnerFocusPaintRect(RoundRect & paintRect)433 void SwitchPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
434 {
435 auto pipelineContext = PipelineBase::GetCurrentContext();
436 CHECK_NULL_VOID(pipelineContext);
437 auto switchTheme = pipelineContext->GetTheme<SwitchTheme>();
438 CHECK_NULL_VOID(switchTheme);
439 auto focusPaintPadding = switchTheme->GetFocusPaintPadding().ConvertToPx();
440
441 auto height = height_ + focusPaintPadding * 2;
442 auto width = width_ + focusPaintPadding * 2;
443 auto radio = height / 2.0;
444 auto offsetX = offset_.GetX() - focusPaintPadding;
445 auto offsetY = offset_.GetY() - focusPaintPadding;
446 CHECK_NULL_VOID(paintMethod_);
447 auto switchModifier = paintMethod_->GetSwitchModifier();
448 CHECK_NULL_VOID(switchModifier);
449 auto trackRadius = switchModifier->GetTrackRadius();
450 auto pointRadius = switchModifier->GetPointRadius();
451 if (pointRadius * NUMBER_TWO > height_) {
452 width = width_ - height_ + pointRadius * NUMBER_TWO + focusPaintPadding * NUMBER_TWO;
453 height = pointRadius * NUMBER_TWO + focusPaintPadding * NUMBER_TWO;
454 radio = pointRadius + focusPaintPadding;
455 offsetX = offset_.GetX() - focusPaintPadding - (pointRadius - height_ / NUMBER_TWO);
456 offsetY = offset_.GetY() - focusPaintPadding - (pointRadius - height_ / NUMBER_TWO);
457 if (width_ < height_) {
458 width = width_ + (pointRadius - trackRadius + focusPaintPadding) * NUMBER_TWO;
459 offsetX = offset_.GetX() - (pointRadius - trackRadius + focusPaintPadding);
460 }
461 } else {
462 if (SWITCH_ERROR_RADIUS != trackRadius) {
463 radio = trackRadius + focusPaintPadding;
464 }
465 if (width_ < height_ && pointRadius > trackRadius) {
466 width = width_ + (pointRadius - trackRadius + focusPaintPadding) * NUMBER_TWO;
467 offsetX = offset_.GetX() - (pointRadius - trackRadius + focusPaintPadding);
468 }
469 }
470 auto Rect = RectF(offsetX, offsetY, width, height);
471
472 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, radio, radio);
473 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, radio, radio);
474 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, radio, radio);
475 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, radio, radio);
476 paintRect.SetRect(Rect);
477 }
478
HandleMouseEvent(bool isHover)479 void SwitchPattern::HandleMouseEvent(bool isHover)
480 {
481 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch mouse event %{public}d", isHover);
482 isHover_ = isHover;
483 if (isHover) {
484 touchHoverType_ = TouchHoverAnimationType::HOVER;
485 } else {
486 touchHoverType_ = TouchHoverAnimationType::NONE;
487 }
488 auto host = GetHost();
489 CHECK_NULL_VOID(host);
490 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
491 }
492
HandleDragStart()493 void SwitchPattern::HandleDragStart()
494 {
495 isDragEvent_ = true;
496 }
497
HandleDragUpdate(const GestureEvent & info)498 void SwitchPattern::HandleDragUpdate(const GestureEvent& info)
499 {
500 dragOffsetX_ = static_cast<float>(info.GetLocalLocation().GetX());
501 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag update %{public}f", dragOffsetX_);
502 auto host = GetHost();
503 CHECK_NULL_VOID(host);
504 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
505 }
506
HandleDragEnd()507 void SwitchPattern::HandleDragEnd()
508 {
509 auto mainSize = GetSwitchWidth();
510 auto contentOffset = GetSwitchContentOffsetX();
511 if ((direction_ == TextDirection::RTL &&
512 ((isOn_.value() && dragOffsetX_ - contentOffset > mainSize / 2) ||
513 (!isOn_.value() && dragOffsetX_ - contentOffset <= mainSize / 2))) ||
514 (direction_ != TextDirection::RTL &&
515 ((isOn_.value() && dragOffsetX_ - contentOffset < mainSize / 2) ||
516 (!isOn_.value() && dragOffsetX_ - contentOffset >= mainSize / 2)))) {
517 OnClick();
518 }
519 isDragEvent_ = false;
520 dragOffsetX_ = 0.0f;
521 auto host = GetHost();
522 CHECK_NULL_VOID(host);
523 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
524 }
525
IsOutOfBoundary(double mainOffset) const526 bool SwitchPattern::IsOutOfBoundary(double mainOffset) const
527 {
528 return mainOffset < 0 || mainOffset > GetSwitchWidth();
529 }
530
531 // Set the default hot zone for the component.
AddHotZoneRect()532 void SwitchPattern::AddHotZoneRect()
533 {
534 hotZoneOffset_.SetX(offset_.GetX() - hotZoneHorizontalPadding_.ConvertToPx());
535 hotZoneOffset_.SetY(offset_.GetY() - hotZoneVerticalPadding_.ConvertToPx());
536 hotZoneSize_.SetWidth(size_.Width() + 2 * hotZoneHorizontalPadding_.ConvertToPx());
537 hotZoneSize_.SetHeight(size_.Height() + 2 * hotZoneVerticalPadding_.ConvertToPx());
538 DimensionRect hotZoneRegion;
539 hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize_.Width()), Dimension(hotZoneSize_.Height())));
540 hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset_.GetX()), Dimension(hotZoneOffset_.GetY())));
541 auto host = GetHost();
542 CHECK_NULL_VOID(host);
543 auto gestureHub = host->GetOrCreateGestureEventHub();
544 CHECK_NULL_VOID(gestureHub);
545 std::vector<DimensionRect> hotZoneRegions;
546 hotZoneRegions.emplace_back(hotZoneRegion);
547 gestureHub->SetResponseRegion(hotZoneRegions);
548 }
549
RemoveLastHotZoneRect() const550 void SwitchPattern::RemoveLastHotZoneRect() const
551 {
552 auto host = GetHost();
553 CHECK_NULL_VOID(host);
554 host->RemoveLastHotZoneRect();
555 }
556
ProvideRestoreInfo()557 std::string SwitchPattern::ProvideRestoreInfo()
558 {
559 auto jsonObj = JsonUtil::Create(true);
560 jsonObj->Put("IsOn", isOn_.value_or(false));
561 return jsonObj->ToString();
562 }
563
OnRestoreInfo(const std::string & restoreInfo)564 void SwitchPattern::OnRestoreInfo(const std::string& restoreInfo)
565 {
566 auto switchPaintProperty = GetPaintProperty<SwitchPaintProperty>();
567 CHECK_NULL_VOID(switchPaintProperty);
568 auto info = JsonUtil::ParseJsonString(restoreInfo);
569 if (!info->IsValid() || !info->IsObject()) {
570 return;
571 }
572 auto jsonIsOn = info->GetValue("IsOn");
573 switchPaintProperty->UpdateIsOn(jsonIsOn->GetBool());
574 OnModifyDone();
575 }
576
OnColorConfigurationUpdate()577 void SwitchPattern::OnColorConfigurationUpdate()
578 {
579 auto host = GetHost();
580 CHECK_NULL_VOID(host);
581 auto pipeline = PipelineBase::GetCurrentContext();
582 CHECK_NULL_VOID(pipeline);
583 auto switchTheme = pipeline->GetTheme<SwitchTheme>();
584 CHECK_NULL_VOID(switchTheme);
585 auto switchPaintProperty = host->GetPaintProperty<SwitchPaintProperty>();
586 CHECK_NULL_VOID(switchPaintProperty);
587 switchPaintProperty->UpdateSwitchPointColor(switchTheme->GetPointColor());
588 CHECK_NULL_VOID(paintMethod_);
589 auto switchModifier = paintMethod_->GetSwitchModifier();
590 CHECK_NULL_VOID(switchModifier);
591 switchModifier->InitializeParam();
592 host->MarkDirtyNode();
593 }
594
SetSwitchIsOn(bool ison)595 void SwitchPattern::SetSwitchIsOn(bool ison)
596 {
597 auto host = GetHost();
598 CHECK_NULL_VOID(host);
599 auto eventHub = host->GetEventHub<EventHub>();
600 CHECK_NULL_VOID(eventHub);
601 auto enabled = eventHub->IsEnabled();
602 if (!enabled) {
603 return;
604 }
605 auto paintProperty = host->GetPaintProperty<SwitchPaintProperty>();
606 CHECK_NULL_VOID(paintProperty);
607 paintProperty->UpdateIsOn(ison);
608 OnModifyDone();
609 }
610
FireBuilder()611 void SwitchPattern::FireBuilder()
612 {
613 auto host = GetHost();
614 CHECK_NULL_VOID(host);
615 if (!makeFunc_.has_value()) {
616 auto children = host->GetChildren();
617 for (const auto& child : children) {
618 if (child->GetId() == nodeId_) {
619 host->RemoveChildAndReturnIndex(child);
620 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
621 break;
622 }
623 }
624 return;
625 }
626 auto node = BuildContentModifierNode();
627 if (contentModifierNode_ == node) {
628 return;
629 }
630 auto renderContext = host->GetRenderContext();
631 CHECK_NULL_VOID(renderContext);
632 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
633 host->RemoveChildAndReturnIndex(contentModifierNode_);
634 contentModifierNode_ = node;
635 CHECK_NULL_VOID(contentModifierNode_);
636 nodeId_ = contentModifierNode_->GetId();
637 host->AddChild(contentModifierNode_, 0);
638 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
639 }
640
BuildContentModifierNode()641 RefPtr<FrameNode> SwitchPattern::BuildContentModifierNode()
642 {
643 if (!makeFunc_.has_value()) {
644 return nullptr;
645 }
646 auto host = GetHost();
647 CHECK_NULL_RETURN(host, nullptr);
648 auto paintProperty = host->GetPaintProperty<SwitchPaintProperty>();
649 CHECK_NULL_RETURN(paintProperty, nullptr);
650 auto eventHub = host->GetEventHub<SwitchEventHub>();
651 CHECK_NULL_RETURN(eventHub, nullptr);
652 auto enabled = eventHub->IsEnabled();
653 bool isOn = false;
654 if (paintProperty->HasIsOn()) {
655 isOn = paintProperty->GetIsOnValue();
656 }
657 ToggleConfiguration toggleConfiguration(enabled, isOn);
658 return (makeFunc_.value())(toggleConfiguration);
659 }
660 } // namespace OHOS::Ace::NG
661