• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/log/dump_log.h"
19 #include "core/common/recorder/node_data_cache.h"
20 #include "core/components/toggle/toggle_theme.h"
21 #include "core/pipeline_ng/pipeline_context.h"
22 
23 namespace OHOS::Ace::NG {
24 namespace {
25 constexpr int32_t DEFAULT_DURATION = 200;
26 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
27 constexpr double NUMBER_TWO = 2.0;
28 constexpr int32_t  HOTZONE_SPACE = 2;
29 } // namespace
30 
OnAttachToFrameNode()31 void SwitchPattern::OnAttachToFrameNode()
32 {
33     auto host = GetHost();
34     CHECK_NULL_VOID(host);
35     auto renderContext = host->GetRenderContext();
36     CHECK_NULL_VOID(renderContext);
37     renderContext->SetAlphaOffscreen(true);
38 }
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->GetOrCreateEventHub<EventHub>();
77     CHECK_NULL_VOID(hub);
78     auto gestureHub = hub->GetOrCreateGestureEventHub();
79     CHECK_NULL_VOID(gestureHub);
80     auto pipeline = host->GetContextRefPtr();
81     CHECK_NULL_VOID(pipeline);
82     switchTheme_ = pipeline->GetTheme<SwitchTheme>(host->GetThemeScopeId());
83     InitPanEvent(gestureHub);
84     InitTouchEvent();
85     InitMouseEvent();
86     InitFocusEvent();
87     auto focusHub = host->GetFocusHub();
88     CHECK_NULL_VOID(focusHub);
89     InitOnKeyEvent(focusHub);
90     SetAccessibilityAction();
91     FireBuilder();
92     HandleEnabled();
93 }
94 
InitFocusEvent()95 void SwitchPattern::InitFocusEvent()
96 {
97     auto host = GetHost();
98     CHECK_NULL_VOID(host);
99     auto focusHub = host->GetOrCreateFocusHub();
100     CHECK_NULL_VOID(focusHub);
101     auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
102         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "switch button handle focus event");
103         auto pattern = weak.Upgrade();
104         CHECK_NULL_VOID(pattern);
105         pattern->HandleFocusEvent();
106     };
107     focusHub->SetOnFocusInternal(focusTask);
108 
109     auto blurTask = [weak = WeakClaim(this)]() {
110         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "switch button handle blur event");
111         auto pattern = weak.Upgrade();
112         CHECK_NULL_VOID(pattern);
113         pattern->HandleBlurEvent();
114     };
115     focusHub->SetOnBlurInternal(blurTask);
116 }
117 
HandleBlurEvent()118 void SwitchPattern::HandleBlurEvent()
119 {
120     RemoveIsFocusActiveUpdateEvent();
121     OnIsFocusActiveUpdate(false);
122 }
123 
HandleFocusEvent()124 void SwitchPattern::HandleFocusEvent()
125 {
126     auto host = GetHost();
127     CHECK_NULL_VOID(host);
128     auto pipeline = host->GetContextRefPtr();
129     CHECK_NULL_VOID(pipeline);
130     AddIsFocusActiveUpdateEvent();
131     if (pipeline->GetIsFocusActive()) {
132         OnIsFocusActiveUpdate(true);
133     }
134 }
135 
AddIsFocusActiveUpdateEvent()136 void SwitchPattern::AddIsFocusActiveUpdateEvent()
137 {
138     if (!isFocusActiveUpdateEvent_) {
139         isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
140             auto pattern = weak.Upgrade();
141             CHECK_NULL_VOID(pattern);
142             pattern->OnIsFocusActiveUpdate(isFocusAcitve);
143         };
144     }
145     auto host = GetHost();
146     CHECK_NULL_VOID(host);
147     auto pipeline = host->GetContextRefPtr();
148     CHECK_NULL_VOID(pipeline);
149     pipeline->AddIsFocusActiveUpdateEvent(host, isFocusActiveUpdateEvent_);
150 }
151 
RemoveIsFocusActiveUpdateEvent()152 void SwitchPattern::RemoveIsFocusActiveUpdateEvent()
153 {
154     auto host = GetHost();
155     CHECK_NULL_VOID(host);
156     auto pipeline = host->GetContextRefPtr();
157     CHECK_NULL_VOID(pipeline);
158     pipeline->RemoveIsFocusActiveUpdateEvent(host);
159 }
160 
OnIsFocusActiveUpdate(bool isFocusAcitve)161 void SwitchPattern::OnIsFocusActiveUpdate(bool isFocusAcitve)
162 {
163     if (isFocusAcitve) {
164         touchHoverType_ = TouchHoverAnimationType::FOCUS;
165     } else {
166         touchHoverType_ = TouchHoverAnimationType::NONE;
167     }
168     auto host = GetHost();
169     CHECK_NULL_VOID(host);
170     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
171 }
172 
HandleEnabled()173 void SwitchPattern::HandleEnabled()
174 {
175     if (UseContentModifier()) {
176         return;
177     }
178     auto host = GetHost();
179     CHECK_NULL_VOID(host);
180     auto eventHub = host->GetOrCreateEventHub<EventHub>();
181     CHECK_NULL_VOID(eventHub);
182     auto enabled = eventHub->IsEnabled();
183     auto renderContext = host->GetRenderContext();
184     CHECK_NULL_VOID(renderContext);
185     auto pipeline = host->GetContextWithCheck();
186     CHECK_NULL_VOID(pipeline);
187     auto theme = pipeline->GetTheme<ToggleTheme>();
188     CHECK_NULL_VOID(theme);
189     auto alpha = theme->GetDisabledAlpha();
190     auto originalOpacity = renderContext->GetOpacityValue(1.0);
191     renderContext->OnOpacityUpdate(enabled ? originalOpacity : alpha * originalOpacity);
192 }
193 
UpdateSwitchPaintProperty()194 void SwitchPattern::UpdateSwitchPaintProperty()
195 {
196     auto host = GetHost();
197     CHECK_NULL_VOID(host);
198     auto switchPaintProperty = host->GetPaintProperty<SwitchPaintProperty>();
199     CHECK_NULL_VOID(switchPaintProperty);
200     auto geometryNode = host->GetGeometryNode();
201     CHECK_NULL_VOID(geometryNode);
202     if (!isOn_.has_value()) {
203         isOn_ = switchPaintProperty->GetIsOnValue(false);
204     }
205     auto isOn = switchPaintProperty->GetIsOnValue(false);
206     if (isOn != isOn_.value_or(false)) {
207         isOn_ = isOn;
208         OnChange();
209     }
210 }
211 
UpdateSwitchLayoutProperty()212 void SwitchPattern::UpdateSwitchLayoutProperty()
213 {
214     auto pipeline = GetContext();
215     CHECK_NULL_VOID(pipeline);
216     auto switchTheme = pipeline->GetTheme<SwitchTheme>();
217     CHECK_NULL_VOID(switchTheme);
218     hotZoneHorizontalPadding_ = switchTheme->GetHotZoneHorizontalPadding();
219     hotZoneVerticalPadding_ = switchTheme->GetHotZoneVerticalPadding();
220     hotZoneHorizontalSize_ = switchTheme->GetHotZoneHorizontalSize();
221     hotZoneVerticalSize_ = switchTheme->GetHotZoneVerticalSize();
222     auto host = GetHost();
223     CHECK_NULL_VOID(host);
224     auto layoutProperty = host->GetLayoutProperty();
225     CHECK_NULL_VOID(layoutProperty);
226     direction_ = layoutProperty->GetNonAutoLayoutDirection();
227     InitDefaultMargin();
228     if (layoutProperty->GetPositionProperty()) {
229         layoutProperty->UpdateAlignment(
230             layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER));
231     } else {
232         layoutProperty->UpdateAlignment(Alignment::CENTER);
233     }
234 }
235 
InitDefaultMargin()236 void SwitchPattern::InitDefaultMargin()
237 {
238     if (makeFunc_.has_value()) {
239         ResetDefaultMargin();
240         return;
241     }
242     auto host = GetHost();
243     CHECK_NULL_VOID(host);
244     auto layoutProperty = host->GetLayoutProperty();
245     CHECK_NULL_VOID(layoutProperty);
246     MarginProperty margin;
247     margin.left = CalcLength(hotZoneHorizontalPadding_.Value());
248     margin.right = CalcLength(hotZoneHorizontalPadding_.Value());
249     margin.top = CalcLength(hotZoneVerticalPadding_.Value());
250     margin.bottom = CalcLength(hotZoneVerticalPadding_.Value());
251     auto& setMargin = layoutProperty->GetMarginProperty();
252     if (setMargin) {
253         if (setMargin->left.has_value()) {
254             margin.left = setMargin->left;
255         }
256         if (setMargin->right.has_value()) {
257             margin.right = setMargin->right;
258         }
259         if (setMargin->top.has_value()) {
260             margin.top = setMargin->top;
261         }
262         if (setMargin->bottom.has_value()) {
263             margin.bottom = setMargin->bottom;
264         }
265     }
266     layoutProperty->UpdateMargin(margin);
267 }
268 
ResetDefaultMargin()269 void SwitchPattern::ResetDefaultMargin()
270 {
271     if (isUserSetMargin_) {
272         return;
273     }
274     auto host = GetHost();
275     CHECK_NULL_VOID(host);
276     auto layoutProperty = host->GetLayoutProperty();
277     CHECK_NULL_VOID(layoutProperty);
278     MarginProperty margin;
279     layoutProperty->UpdateMargin(margin);
280 }
281 
SetAccessibilityAction()282 void SwitchPattern::SetAccessibilityAction()
283 {
284     auto host = GetHost();
285     CHECK_NULL_VOID(host);
286     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
287     CHECK_NULL_VOID(accessibilityProperty);
288     accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
289         const auto& pattern = weakPtr.Upgrade();
290         CHECK_NULL_VOID(pattern);
291         pattern->UpdateSelectStatus(true);
292     });
293 
294     accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
295         const auto& pattern = weakPtr.Upgrade();
296         CHECK_NULL_VOID(pattern);
297         pattern->UpdateSelectStatus(false);
298     });
299     FireBuilder();
300 }
301 
UpdateSelectStatus(bool isSelected)302 void SwitchPattern::UpdateSelectStatus(bool isSelected)
303 {
304     auto host = GetHost();
305     CHECK_NULL_VOID(host);
306     auto context = host->GetRenderContext();
307     CHECK_NULL_VOID(context);
308     MarkIsSelected(isSelected);
309     context->OnMouseSelectUpdate(isSelected, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
310 }
311 
MarkIsSelected(bool isSelected)312 void SwitchPattern::MarkIsSelected(bool isSelected)
313 {
314     if (isOn_ == isSelected) {
315         return;
316     }
317     isOn_ = isSelected;
318     auto eventHub = GetOrCreateEventHub<SwitchEventHub>();
319     CHECK_NULL_VOID(eventHub);
320     eventHub->UpdateChangeEvent(isSelected);
321     auto host = GetHost();
322     CHECK_NULL_VOID(host);
323     eventHub->SetCurrentUIState(UI_STATE_SELECTED, isSelected);
324     host->OnAccessibilityEvent(AccessibilityEventType::COMPONENT_CHANGE);
325 }
326 
OnAfterModifyDone()327 void SwitchPattern::OnAfterModifyDone()
328 {
329     auto host = GetHost();
330     CHECK_NULL_VOID(host);
331     auto inspectorId = host->GetInspectorId().value_or("");
332     if (!inspectorId.empty()) {
333         Recorder::NodeDataCache::Get().PutBool(host, inspectorId, isOn_.value_or(false));
334     }
335 }
336 
GetCurve() const337 RefPtr<Curve> SwitchPattern::GetCurve() const
338 {
339     auto switchPaintProperty = GetPaintProperty<SwitchPaintProperty>();
340     CHECK_NULL_RETURN(switchPaintProperty, nullptr);
341     return switchPaintProperty->GetCurve().value_or(nullptr);
342 }
343 
GetDuration() const344 int32_t SwitchPattern::GetDuration() const
345 {
346     auto switchPaintProperty = GetPaintProperty<SwitchPaintProperty>();
347     CHECK_NULL_RETURN(switchPaintProperty, DEFAULT_DURATION);
348     return switchPaintProperty->GetDuration().value_or(DEFAULT_DURATION);
349 }
350 
OnChange()351 void SwitchPattern::OnChange()
352 {
353     auto host = GetHost();
354     CHECK_NULL_VOID(host);
355     auto switchPaintProperty = host->GetPaintProperty<SwitchPaintProperty>();
356     CHECK_NULL_VOID(switchPaintProperty);
357     CHECK_NULL_VOID(paintMethod_);
358     auto switchModifier = paintMethod_->GetSwitchModifier();
359     CHECK_NULL_VOID(switchModifier);
360     switchModifier->SetIsOn(isOn_.value_or(false));
361     switchPaintProperty->UpdateIsOn(isOn_.value_or(false));
362     UpdateChangeEvent();
363     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
364 }
365 
GetSwitchWidth() const366 float SwitchPattern::GetSwitchWidth() const
367 {
368     auto host = GetHost();
369     CHECK_NULL_RETURN(host, false);
370     auto geometryNode = host->GetGeometryNode();
371     CHECK_NULL_RETURN(geometryNode, false);
372     auto switchWidth = geometryNode->GetContentSize().Width() - geometryNode->GetContentSize().Height();
373     return switchWidth;
374 }
375 
GetSwitchContentOffsetX() const376 float SwitchPattern::GetSwitchContentOffsetX() const
377 {
378     auto host = GetHost();
379     CHECK_NULL_RETURN(host, 0.0f);
380     auto geometryNode = host->GetGeometryNode();
381     CHECK_NULL_RETURN(geometryNode, 0.0f);
382     return geometryNode->GetContentOffset().GetX();
383 }
384 
UpdateChangeEvent() const385 void SwitchPattern::UpdateChangeEvent() const
386 {
387     auto switchEventHub = GetOrCreateEventHub<SwitchEventHub>();
388     CHECK_NULL_VOID(switchEventHub);
389     switchEventHub->UpdateChangeEvent(isOn_.value_or(false));
390 }
391 
OnClick()392 void SwitchPattern::OnClick()
393 {
394     if (UseContentModifier()) {
395         return;
396     }
397     isOn_ = !isOn_.value_or(false);
398     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch click result %{public}d", isOn_.value_or(false));
399     UpdateColorWhenIsOn(isOn_.value_or(false));
400     OnChange();
401     auto host = GetHost();
402     CHECK_NULL_VOID(host);
403     host->OnAccessibilityEvent(AccessibilityEventType::COMPONENT_CHANGE);
404 }
405 
UpdateColorWhenIsOn(bool isOn)406 void SwitchPattern::UpdateColorWhenIsOn(bool isOn)
407 {
408     auto host = GetHost();
409     CHECK_NULL_VOID(host);
410     auto switchPaintProperty = host->GetPaintProperty<SwitchPaintProperty>();
411     CHECK_NULL_VOID(switchPaintProperty);
412     CHECK_NULL_VOID(switchTheme_);
413     CHECK_NULL_VOID(paintMethod_);
414     auto switchModifier = paintMethod_->GetSwitchModifier();
415     CHECK_NULL_VOID(switchModifier);
416 
417     Color onBgColor = switchTheme_->GetActiveColor();
418     Color offBgColor = switchTheme_->GetInactiveColor();
419     if (isOn) {
420         if (switchPaintProperty->HasSelectedColor() && switchPaintProperty->GetSelectedColor() == onBgColor) {
421             switchPaintProperty->UpdateSelectedColor(onBgColor);
422         }
423     } else {
424         if (switchPaintProperty->HasUnselectedColor() && switchPaintProperty->GetUnselectedColor() == offBgColor) {
425             Color bgColor = isFocus_ ? switchTheme_->GetFocusedBGColorUnselected() : switchTheme_->GetInactiveColor();
426             switchPaintProperty->UpdateUnselectedColor(bgColor);
427         }
428         if (isFocus_) {
429             switchModifier->SetFocusPointColor(switchTheme_->GetPointColorUnselectedFocus());
430         }
431     }
432 }
433 
OnTouchDown()434 void SwitchPattern::OnTouchDown()
435 {
436     if (UseContentModifier()) {
437         return;
438     }
439     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch touch down hover status %{public}d", isHover_);
440     if (isHover_) {
441         touchHoverType_ = TouchHoverAnimationType::HOVER_TO_PRESS;
442     } else {
443         touchHoverType_ = TouchHoverAnimationType::PRESS;
444     }
445     auto host = GetHost();
446     CHECK_NULL_VOID(host);
447     isTouch_ = true;
448     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
449 }
450 
OnTouchUp()451 void SwitchPattern::OnTouchUp()
452 {
453     if (UseContentModifier()) {
454         return;
455     }
456     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch touch up hover status %{public}d", isHover_);
457     if (isHover_) {
458         touchHoverType_ = TouchHoverAnimationType::PRESS_TO_HOVER;
459     } else {
460         touchHoverType_ = TouchHoverAnimationType::NONE;
461     }
462     auto host = GetHost();
463     CHECK_NULL_VOID(host);
464     isTouch_ = false;
465     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
466     FireBuilder();
467 }
468 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)469 void SwitchPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
470 {
471     if (panEvent_) {
472         return;
473     }
474 
475     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
476         TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag start");
477         auto pattern = weak.Upgrade();
478         CHECK_NULL_VOID(pattern);
479         if (info.GetInputEventType() == InputEventType::AXIS) {
480             return;
481         }
482         pattern->HandleDragStart();
483     };
484 
485     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
486         auto pattern = weak.Upgrade();
487         CHECK_NULL_VOID(pattern);
488         pattern->HandleDragUpdate(info);
489     };
490 
491     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
492         TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag end");
493         auto pattern = weak.Upgrade();
494         CHECK_NULL_VOID(pattern);
495         if (info.GetInputEventType() == InputEventType::AXIS) {
496             return;
497         }
498         pattern->HandleDragEnd();
499     };
500 
501     auto actionCancelTask = [weak = WeakClaim(this)]() {
502         TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag cancel");
503         auto pattern = weak.Upgrade();
504         CHECK_NULL_VOID(pattern);
505         pattern->HandleDragEnd();
506     };
507 
508     PanDirection panDirection;
509     panDirection.type = PanDirection::HORIZONTAL;
510 
511     panEvent_ = MakeRefPtr<PanEvent>(
512         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
513     PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
514         { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
515     gestureHub->AddPanEvent(panEvent_, panDirection, 1, distanceMap);
516 }
517 
InitClickEvent()518 void SwitchPattern::InitClickEvent()
519 {
520     if (clickListener_) {
521         return;
522     }
523     auto host = GetHost();
524     CHECK_NULL_VOID(host);
525     auto gesture = host->GetOrCreateGestureEventHub();
526     CHECK_NULL_VOID(gesture);
527     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
528         auto switchPattern = weak.Upgrade();
529         CHECK_NULL_VOID(switchPattern);
530         switchPattern->OnClick();
531     };
532 
533     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
534     gesture->AddClickEvent(clickListener_);
535 }
536 
InitTouchEvent()537 void SwitchPattern::InitTouchEvent()
538 {
539     if (touchListener_) {
540         return;
541     }
542     auto host = GetHost();
543     CHECK_NULL_VOID(host);
544     auto gesture = host->GetOrCreateGestureEventHub();
545     CHECK_NULL_VOID(gesture);
546     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
547         auto switchPattern = weak.Upgrade();
548         CHECK_NULL_VOID(switchPattern);
549         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
550             switchPattern->OnTouchDown();
551         }
552         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
553             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
554             switchPattern->OnTouchUp();
555         }
556     };
557     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
558     gesture->AddTouchEvent(touchListener_);
559 }
560 
InitMouseEvent()561 void SwitchPattern::InitMouseEvent()
562 {
563     if (mouseEvent_) {
564         return;
565     }
566     auto host = GetHost();
567     CHECK_NULL_VOID(host);
568     auto gesture = host->GetOrCreateGestureEventHub();
569     CHECK_NULL_VOID(gesture);
570     auto eventHub = GetHost()->GetOrCreateEventHub<SwitchEventHub>();
571     auto inputHub = eventHub->GetOrCreateInputEventHub();
572 
573     auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
574         auto pattern = weak.Upgrade();
575         CHECK_NULL_VOID(pattern);
576         pattern->HandleMouseEvent(isHover);
577     };
578     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
579     inputHub->AddOnHoverEvent(mouseEvent_);
580 }
581 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)582 void SwitchPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
583 {
584     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
585         auto pattern = wp.Upgrade();
586         if (pattern) {
587             pattern->GetInnerFocusPaintRect(paintRect);
588         }
589     };
590     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
591     auto onKeyCallbackFunc = [wp = WeakClaim(this)](const KeyEvent& keyEventInfo) -> bool {
592         auto pattern = wp.Upgrade();
593         if (pattern) {
594             return pattern->OnKeyEvent(keyEventInfo);
595         }
596         TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "InitOnKeyEvent return false");
597         return false;
598     };
599     focusHub->SetOnKeyEventInternal(std::move(onKeyCallbackFunc));
600 }
601 
OnKeyEvent(const KeyEvent & keyEventInfo)602 bool SwitchPattern::OnKeyEvent(const KeyEvent& keyEventInfo)
603 {
604     if (keyEventInfo.action == KeyAction::DOWN && keyEventInfo.code == KeyCode::KEY_FUNCTION) {
605         this->OnClick();
606         return true;
607     }
608     return false;
609 }
610 
GetInnerFocusPaintRect(RoundRect & paintRect)611 void SwitchPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
612 {
613     auto pipelineContext = PipelineBase::GetCurrentContext();
614     CHECK_NULL_VOID(pipelineContext);
615     auto switchTheme = pipelineContext->GetTheme<SwitchTheme>();
616     CHECK_NULL_VOID(switchTheme);
617     auto focusPaintPadding = switchTheme->GetFocusPaintPadding().ConvertToPx();
618 
619     auto height = height_ + focusPaintPadding * 2;
620     auto width = width_ + focusPaintPadding * 2;
621     auto radio = height / 2.0;
622     auto offsetX = offset_.GetX() - focusPaintPadding;
623     auto offsetY = offset_.GetY() - focusPaintPadding;
624     CHECK_NULL_VOID(paintMethod_);
625     auto switchModifier = paintMethod_->GetSwitchModifier();
626     CHECK_NULL_VOID(switchModifier);
627     auto trackRadius = switchModifier->GetTrackRadius();
628     auto pointRadius = switchModifier->GetPointRadius();
629     if (pointRadius * NUMBER_TWO > height_) {
630         width = width_ - height_ + pointRadius * NUMBER_TWO + focusPaintPadding * NUMBER_TWO;
631         height = pointRadius * NUMBER_TWO + focusPaintPadding * NUMBER_TWO;
632         radio = pointRadius + focusPaintPadding;
633         offsetX = offset_.GetX() - focusPaintPadding - (pointRadius - height_ / NUMBER_TWO);
634         offsetY = offset_.GetY() - focusPaintPadding - (pointRadius - height_ / NUMBER_TWO);
635         if (width_ < height_) {
636             width = width_ + (pointRadius - trackRadius + focusPaintPadding) * NUMBER_TWO;
637             offsetX = offset_.GetX() - (pointRadius - trackRadius + focusPaintPadding);
638         }
639     } else {
640         if (SWITCH_ERROR_RADIUS != trackRadius) {
641             radio = trackRadius + focusPaintPadding;
642         }
643         if (width_ < height_ && pointRadius > trackRadius) {
644             width = width_ + (pointRadius - trackRadius + focusPaintPadding) * NUMBER_TWO;
645             offsetX = offset_.GetX() - (pointRadius - trackRadius + focusPaintPadding);
646         }
647     }
648     auto Rect = RectF(offsetX, offsetY, width, height);
649 
650     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, radio, radio);
651     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, radio, radio);
652     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, radio, radio);
653     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, radio, radio);
654     paintRect.SetRect(Rect);
655 }
656 
HandleMouseEvent(bool isHover)657 void SwitchPattern::HandleMouseEvent(bool isHover)
658 {
659     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch mouse event %{public}d", isHover);
660     isHover_ = isHover;
661     if (isHover) {
662         touchHoverType_ = TouchHoverAnimationType::HOVER;
663     } else {
664         touchHoverType_ = TouchHoverAnimationType::NONE;
665     }
666     auto host = GetHost();
667     CHECK_NULL_VOID(host);
668     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
669 }
670 
HandleDragStart()671 void SwitchPattern::HandleDragStart()
672 {
673     isDragEvent_ = true;
674 }
675 
HandleDragUpdate(const GestureEvent & info)676 void SwitchPattern::HandleDragUpdate(const GestureEvent& info)
677 {
678     dragOffsetX_ = static_cast<float>(info.GetLocalLocation().GetX());
679     TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "switch drag update %{public}f", dragOffsetX_);
680     auto host = GetHost();
681     CHECK_NULL_VOID(host);
682     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
683 }
684 
HandleDragEnd()685 void SwitchPattern::HandleDragEnd()
686 {
687     auto mainSize = GetSwitchWidth();
688     auto contentOffset = GetSwitchContentOffsetX();
689     if ((direction_ == TextDirection::RTL &&
690         ((isOn_.value_or(false) && dragOffsetX_ - contentOffset > mainSize / 2) ||
691         (!isOn_.value_or(false) && dragOffsetX_ - contentOffset <= mainSize / 2))) ||
692         (direction_ != TextDirection::RTL &&
693         ((isOn_.value_or(false) && dragOffsetX_ - contentOffset < mainSize / 2) ||
694         (!isOn_.value_or(false) && dragOffsetX_ - contentOffset >= mainSize / 2)))) {
695         OnClick();
696     }
697     isDragEvent_ = false;
698     dragOffsetX_ = 0.0f;
699     auto host = GetHost();
700     CHECK_NULL_VOID(host);
701     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
702 }
703 
IsOutOfBoundary(double mainOffset) const704 bool SwitchPattern::IsOutOfBoundary(double mainOffset) const
705 {
706     return mainOffset < 0 || mainOffset > GetSwitchWidth();
707 }
708 
709 // Set the default hot zone for the component.
AddHotZoneRect()710 void SwitchPattern::AddHotZoneRect()
711 {
712     hotZoneOffset_.SetX(offset_.GetX() - hotZoneHorizontalSize_.ConvertToPx());
713     hotZoneOffset_.SetY(offset_.GetY() - hotZoneVerticalSize_.ConvertToPx());
714     hotZoneSize_.SetWidth(size_.Width() + HOTZONE_SPACE * hotZoneHorizontalSize_.ConvertToPx());
715     hotZoneSize_.SetHeight(size_.Height() + HOTZONE_SPACE * hotZoneVerticalSize_.ConvertToPx());
716     DimensionRect hotZoneRegion;
717     hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize_.Width()), Dimension(hotZoneSize_.Height())));
718     hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset_.GetX()), Dimension(hotZoneOffset_.GetY())));
719     auto host = GetHost();
720     CHECK_NULL_VOID(host);
721     auto gestureHub = host->GetOrCreateGestureEventHub();
722     CHECK_NULL_VOID(gestureHub);
723     std::vector<DimensionRect> hotZoneRegions;
724     hotZoneRegions.emplace_back(hotZoneRegion);
725     gestureHub->SetResponseRegion(hotZoneRegions);
726 }
727 
RemoveLastHotZoneRect() const728 void SwitchPattern::RemoveLastHotZoneRect() const
729 {
730     auto host = GetHost();
731     CHECK_NULL_VOID(host);
732     host->RemoveLastHotZoneRect();
733 }
734 
ProvideRestoreInfo()735 std::string SwitchPattern::ProvideRestoreInfo()
736 {
737     auto jsonObj = JsonUtil::Create(true);
738     jsonObj->Put("IsOn", isOn_.value_or(false));
739     return jsonObj->ToString();
740 }
741 
OnRestoreInfo(const std::string & restoreInfo)742 void SwitchPattern::OnRestoreInfo(const std::string& restoreInfo)
743 {
744     auto switchPaintProperty = GetPaintProperty<SwitchPaintProperty>();
745     CHECK_NULL_VOID(switchPaintProperty);
746     auto info = JsonUtil::ParseJsonString(restoreInfo);
747     if (!info->IsValid() || !info->IsObject()) {
748         return;
749     }
750     auto jsonIsOn = info->GetValue("IsOn");
751     switchPaintProperty->UpdateIsOn(jsonIsOn->GetBool());
752     OnModifyDone();
753 }
754 
OnColorConfigurationUpdate()755 void SwitchPattern::OnColorConfigurationUpdate()
756 {
757     auto host = GetHost();
758     CHECK_NULL_VOID(host);
759     auto pipeline = PipelineBase::GetCurrentContext();
760     CHECK_NULL_VOID(pipeline);
761     auto switchTheme = pipeline->GetTheme<SwitchTheme>(host->GetThemeScopeId());
762     CHECK_NULL_VOID(switchTheme);
763     CHECK_NULL_VOID(paintMethod_);
764     auto switchModifier = paintMethod_->GetSwitchModifier();
765     CHECK_NULL_VOID(switchModifier);
766     switchModifier->InitializeParam(host->GetThemeScopeId());
767     if (SystemProperties::ConfigChangePerform()) {
768         auto pipeline = host->GetContext();
769         CHECK_NULL_VOID(pipeline);
770         auto theme = pipeline->GetTheme<SwitchTheme>();
771         CHECK_NULL_VOID(theme);
772         auto pops = host->GetPaintProperty<SwitchPaintProperty>();
773         CHECK_NULL_VOID(pops);
774         if (!pops->GetSelectedColorSetByUserValue(false)) {
775             Color color = theme->GetActiveColor();
776             pops->UpdateSelectedColor(color);
777         }
778         if (!pops->GetSwitchPointColorSetByUserValue(false)) {
779             Color color = theme->GetPointColor();
780             pops->UpdateSwitchPointColor(color);
781         }
782         if (!pops->GetUnselectedColorSetByUserValue(false)) {
783             Color color = theme->GetInactiveColor();
784             pops->UpdateUnselectedColor(color);
785         }
786     }
787     host->MarkDirtyNode();
788     host->SetNeedCallChildrenUpdate(false);
789 }
790 
OnThemeScopeUpdate(int32_t themeScopeId)791 bool SwitchPattern::OnThemeScopeUpdate(int32_t themeScopeId)
792 {
793     bool result = false;
794     auto host = GetHost();
795     CHECK_NULL_RETURN(host, false);
796     auto paintProperty = host->GetPaintProperty<SwitchPaintProperty>();
797     CHECK_NULL_RETURN(paintProperty, false);
798 
799     if (!paintProperty->HasSelectedColor() || !paintProperty->HasSwitchPointColor()) {
800         result = true;
801     }
802 
803     return result;
804 }
805 
DumpInfo()806 void SwitchPattern::DumpInfo()
807 {
808     auto paintProperty = GetPaintProperty<SwitchPaintProperty>();
809     CHECK_NULL_VOID(paintProperty);
810     if (paintProperty->HasIsOn()) {
811         DumpLog::GetInstance().AddDesc("IsOn: " + std::string(paintProperty->GetIsOn().value() ? "true" : "false"));
812     }
813     if (paintProperty->HasSelectedColor()) {
814         DumpLog::GetInstance().AddDesc("SelectedColor: " + paintProperty->GetSelectedColor().value().ToString());
815     }
816     if (paintProperty->HasUnselectedColor()) {
817         DumpLog::GetInstance().AddDesc("UnselectedColor: " + paintProperty->GetUnselectedColor().value().ToString());
818     }
819     if (paintProperty->HasSwitchPointColor()) {
820         DumpLog::GetInstance().AddDesc("SwitchPointColor: " + paintProperty->GetSwitchPointColor().value().ToString());
821     }
822     if (paintProperty->HasPointRadius()) {
823         DumpLog::GetInstance().AddDesc("PointRadius: " + paintProperty->GetPointRadius().value().ToString());
824     }
825     if (paintProperty->HasTrackBorderRadius()) {
826         DumpLog::GetInstance().AddDesc(
827             "TrackBorderRadius: " + paintProperty->GetTrackBorderRadius().value().ToString());
828     }
829 }
830 
SetSwitchIsOn(bool ison)831 void SwitchPattern::SetSwitchIsOn(bool ison)
832 {
833     auto host = GetHost();
834     CHECK_NULL_VOID(host);
835     auto eventHub = host->GetOrCreateEventHub<EventHub>();
836     CHECK_NULL_VOID(eventHub);
837     auto enabled = eventHub->IsEnabled();
838     if (!enabled) {
839         return;
840     }
841     auto paintProperty = host->GetPaintProperty<SwitchPaintProperty>();
842     CHECK_NULL_VOID(paintProperty);
843     paintProperty->UpdateIsOn(ison);
844     OnModifyDone();
845 }
846 
FireBuilder()847 void SwitchPattern::FireBuilder()
848 {
849     auto host = GetHost();
850     CHECK_NULL_VOID(host);
851     if (!makeFunc_.has_value()) {
852         auto children = host->GetChildren();
853         for (const auto& child : children) {
854             if (child->GetId() == nodeId_) {
855                 host->RemoveChildAndReturnIndex(child);
856                 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
857                 break;
858             }
859         }
860         return;
861     }
862     auto node = BuildContentModifierNode();
863     if (contentModifierNode_ == node) {
864         return;
865     }
866     auto renderContext = host->GetRenderContext();
867     CHECK_NULL_VOID(renderContext);
868     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
869     host->RemoveChildAndReturnIndex(contentModifierNode_);
870     contentModifierNode_ = node;
871     CHECK_NULL_VOID(contentModifierNode_);
872     nodeId_ = contentModifierNode_->GetId();
873     host->AddChild(contentModifierNode_, 0);
874     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
875 }
876 
BuildContentModifierNode()877 RefPtr<FrameNode> SwitchPattern::BuildContentModifierNode()
878 {
879     if (!makeFunc_.has_value()) {
880         return nullptr;
881     }
882     auto host = GetHost();
883     CHECK_NULL_RETURN(host, nullptr);
884     auto paintProperty = host->GetPaintProperty<SwitchPaintProperty>();
885     CHECK_NULL_RETURN(paintProperty, nullptr);
886     auto eventHub = host->GetOrCreateEventHub<SwitchEventHub>();
887     CHECK_NULL_RETURN(eventHub, nullptr);
888     auto enabled = eventHub->IsEnabled();
889     bool isOn = false;
890     if (paintProperty->HasIsOn()) {
891         isOn = paintProperty->GetIsOnValue();
892     }
893     ToggleConfiguration toggleConfiguration(enabled, isOn);
894     return (makeFunc_.value())(toggleConfiguration);
895 }
896 } // namespace OHOS::Ace::NG
897