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