• 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 "base/utils/utf_helper.h"
17 #include "core/components_ng/pattern/button/toggle_button_pattern.h"
18 
19 #include "core/components/toggle/toggle_theme.h"
20 #include "core/components_ng/pattern/toggle/toggle_model.h"
21 #include "core/components/text/text_theme.h"
22 
23 namespace OHOS::Ace::NG {
24 namespace {
25 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
26 constexpr int32_t TOUCH_DURATION = 100;
27 constexpr int32_t MOUSE_HOVER_DURATION = 250;
28 constexpr int32_t TYPE_TOUCH = 0;
29 constexpr int32_t TYPE_HOVER = 1;
30 constexpr int32_t TYPE_CANCEL = 2;
31 }
32 
OnAttachToFrameNode()33 void ToggleButtonPattern::OnAttachToFrameNode()
34 {
35     InitParameters();
36 }
37 
InitParameters()38 void ToggleButtonPattern::InitParameters()
39 {
40     auto host = GetHost();
41     CHECK_NULL_VOID(host);
42     auto context = host->GetContext();
43     CHECK_NULL_VOID(context);
44     toggleTheme_ = context->GetTheme<ToggleTheme>(host->GetThemeScopeId());
45     CHECK_NULL_VOID(toggleTheme_);
46     checkedColor_ = toggleTheme_->GetCheckedColor();
47     unCheckedColor_ = toggleTheme_->GetBackgroundColor();
48     textMargin_ = toggleTheme_->GetTextMargin();
49     buttonRadius_ = toggleTheme_->GetButtonRadius();
50     textFontSize_ = toggleTheme_->GetTextFontSize();
51     textColor_ = toggleTheme_->GetTextColor();
52 }
53 
OnModifyDone()54 void ToggleButtonPattern::OnModifyDone()
55 {
56     Pattern::CheckLocalized();
57     CheckLocalizedBorderRadiuses();
58     InitParameters();
59     auto host = GetHost();
60     CHECK_NULL_VOID(host);
61     auto layoutProperty = host->GetLayoutProperty();
62     CHECK_NULL_VOID(layoutProperty);
63     if (layoutProperty->GetPositionProperty()) {
64         layoutProperty->UpdateAlignment(
65             layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER));
66     } else {
67         layoutProperty->UpdateAlignment(Alignment::CENTER);
68     }
69     auto buttonPaintProperty = GetPaintProperty<ToggleButtonPaintProperty>();
70     CHECK_NULL_VOID(buttonPaintProperty);
71     if (!isOn_.has_value()) {
72         isOn_ = buttonPaintProperty->GetIsOnValue();
73     }
74     bool changed = false;
75     if (buttonPaintProperty->HasIsOn()) {
76         bool isOn = buttonPaintProperty->GetIsOnValue();
77         changed = isOn ^ isOn_.value();
78         isOn_ = isOn;
79     }
80     const auto& renderContext = host->GetRenderContext();
81     CHECK_NULL_VOID(renderContext);
82     if (!UseContentModifier()) {
83         if (isOn_.value_or(false)) {
84             auto selectedColor = buttonPaintProperty->GetSelectedColor().value_or(checkedColor_);
85             renderContext->UpdateBackgroundColor(selectedColor);
86         } else {
87             auto bgColor = buttonPaintProperty->GetBackgroundColor().value_or(unCheckedColor_);
88             renderContext->UpdateBackgroundColor(bgColor);
89         }
90         HandleOnOffStyle(!isOn_.value(), isFocus_);
91     }
92     if (changed) {
93         auto toggleButtonEventHub = GetOrCreateEventHub<ToggleButtonEventHub>();
94         CHECK_NULL_VOID(toggleButtonEventHub);
95         toggleButtonEventHub->UpdateChangeEvent(isOn_.value());
96     }
97     GetIsTextFade();
98     FireBuilder();
99     InitEvent();
100     SetAccessibilityAction();
101 }
102 
InitEvent()103 void ToggleButtonPattern::InitEvent()
104 {
105     InitButtonAndText();
106     HandleEnabled();
107     InitClickEvent();
108     HandleOverlayStyle();
109     InitTouchEvent();
110     InitHoverEvent();
111     InitOnKeyEvent();
112 }
113 
GetIsTextFade()114 void ToggleButtonPattern::GetIsTextFade()
115 {
116     auto host = GetHost();
117     CHECK_NULL_VOID(host);
118     auto pipeline = host->GetContextRefPtr();
119     CHECK_NULL_VOID(pipeline);
120     auto textTheme = pipeline->GetTheme<TextTheme>();
121     CHECK_NULL_VOID(textTheme);
122     isTextFadeOut_ = textTheme->GetIsTextFadeout();
123 }
124 
UpdateTexOverflow(bool isMarqueeStart,RefPtr<TextLayoutProperty> & textLayoutProperty)125 void ToggleButtonPattern::UpdateTexOverflow(bool isMarqueeStart, RefPtr<TextLayoutProperty>& textLayoutProperty)
126 {
127     if (isTextFadeOut_ && textLayoutProperty) {
128         textLayoutProperty->UpdateTextOverflow(TextOverflow::MARQUEE);
129         textLayoutProperty->UpdateTextMarqueeFadeout(true);
130         textLayoutProperty->UpdateTextMarqueeStart(isMarqueeStart);
131         textLayoutProperty->UpdateTextMarqueeStartPolicy(MarqueeStartPolicy::DEFAULT);
132     }
133 }
134 
InitHoverEvent()135 void ToggleButtonPattern::InitHoverEvent()
136 {
137     if (UseContentModifier()) {
138         return;
139     }
140     auto host = GetHost();
141     CHECK_NULL_VOID(host);
142     auto eventHub = host->GetOrCreateEventHub<ToggleButtonEventHub>();
143     CHECK_NULL_VOID(eventHub);
144     auto inputHub = eventHub->GetOrCreateInputEventHub();
145     CHECK_NULL_VOID(inputHub);
146     auto hoverEffect = inputHub->GetHoverEffect();
147     inputHub->SetHoverEffect(hoverEffect == HoverEffectType::BOARD ? HoverEffectType::AUTO : hoverEffect);
148     if (hoverListener_) {
149         return;
150     }
151     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
152         TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "button hover %{public}d", isHover);
153         auto pattern = weak.Upgrade();
154         if (pattern) {
155             pattern->HandleHoverEvent(isHover);
156         }
157     };
158 
159     hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
160     inputHub->AddOnHoverEvent(hoverListener_);
161 }
162 
HandleHoverEvent(bool isHover)163 void ToggleButtonPattern::HandleHoverEvent(bool isHover)
164 {
165     isHover_ = isHover;
166     auto host = GetHost();
167     CHECK_NULL_VOID(host);
168     auto eventHub = host->GetOrCreateEventHub<EventHub>();
169     CHECK_NULL_VOID(eventHub);
170     auto enabled = eventHub->IsEnabled();
171     auto inputEventHub = host->GetOrCreateInputEventHub();
172     CHECK_NULL_VOID(inputEventHub);
173     auto hoverEffect = inputEventHub->GetHoverEffect();
174     if (hoverEffect == HoverEffectType::NONE || hoverEffect == HoverEffectType::SCALE) {
175         return;
176     }
177     if (!isPress_ && (enabled || !isHover)) {
178         auto renderContext = host->GetRenderContext();
179         CHECK_NULL_VOID(renderContext);
180         AnimateTouchAndHover(renderContext, isHover ? TYPE_CANCEL : TYPE_HOVER, isHover ? TYPE_HOVER : TYPE_CANCEL,
181             MOUSE_HOVER_DURATION, Curves::FRICTION);
182         if (isHover) {
183             SetToggleScale(renderContext);
184         } else {
185             if (isScale_) {
186                 isScale_ = false;
187                 renderContext->SetScale(1.0f, 1.0f);
188             }
189         }
190     }
191     auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
192     CHECK_NULL_VOID(textNode);
193     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
194     CHECK_NULL_VOID(textLayoutProperty);
195     UpdateTexOverflow((isHover_ || isFocus_), textLayoutProperty);
196     textNode->MarkDirtyNode();
197 }
198 
HandleOverlayStyle()199 void ToggleButtonPattern::HandleOverlayStyle()
200 {
201     HandleBorderAndShadow();
202     HandleFocusStyle();
203 }
204 
HandleBorderAndShadow()205 void ToggleButtonPattern::HandleBorderAndShadow()
206 {
207     CHECK_NULL_VOID(toggleTheme_);
208     auto host = GetHost();
209     CHECK_NULL_VOID(host);
210     auto renderContext = host->GetRenderContext();
211     CHECK_NULL_VOID(renderContext);
212     auto paintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>();
213     CHECK_NULL_VOID(paintProperty);
214     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
215     CHECK_NULL_VOID(layoutProperty);
216     if (!layoutProperty->GetBorderWidthProperty()) {
217         if (!renderContext->HasBorderWidth()) {
218             BorderWidthProperty borderWidth;
219             borderWidth.SetBorderWidth(toggleTheme_->GetBorderWidth());
220             layoutProperty->UpdateBorderWidth(borderWidth);
221             renderContext->UpdateBorderWidth(borderWidth);
222         }
223         if (!renderContext->HasBorderColor()) {
224             BorderColorProperty borderColor;
225             Color color = paintProperty->GetIsOnValue(false) ?
226                 toggleTheme_->GetBorderColorChecked() : toggleTheme_->GetBorderColorUnchecked();
227             borderColor.SetColor(color);
228             renderContext->UpdateBorderColor(borderColor);
229         }
230     }
231 
232     auto&& graphics = renderContext->GetOrCreateGraphics();
233     CHECK_NULL_VOID(graphics);
234     CHECK_NULL_VOID(paintProperty->GetIsOn());
235     if (!graphics->HasBackShadow()) {
236         ShadowStyle shadowStyle = ShadowStyle::None;
237         if (paintProperty->GetIsOnValue(false)) {
238             shadowStyle = static_cast<ShadowStyle>(toggleTheme_->GetShadowNormal());
239         }
240         Shadow shadow = Shadow::CreateShadow(shadowStyle);
241         renderContext->UpdateBackShadow(shadow);
242     }
243 }
244 
AddIsFocusActiveUpdateEvent()245 void ToggleButtonPattern::AddIsFocusActiveUpdateEvent()
246 {
247     if (!isFocusActiveUpdateEvent_) {
248         isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
249             auto pattern = weak.Upgrade();
250             CHECK_NULL_VOID(pattern);
251             pattern->SetIsFocus(isFocusAcitve);
252             pattern->UpdateButtonStyle();
253         };
254     }
255     auto host = GetHost();
256     CHECK_NULL_VOID(host);
257     auto pipeline = host->GetContextRefPtr();
258     CHECK_NULL_VOID(pipeline);
259     pipeline->AddIsFocusActiveUpdateEvent(host, isFocusActiveUpdateEvent_);
260 }
261 
RemoveIsFocusActiveUpdateEvent()262 void ToggleButtonPattern::RemoveIsFocusActiveUpdateEvent()
263 {
264     auto host = GetHost();
265     CHECK_NULL_VOID(host);
266     auto pipeline = host->GetContextRefPtr();
267     CHECK_NULL_VOID(pipeline);
268     pipeline->RemoveIsFocusActiveUpdateEvent(host);
269 }
270 
UpdateButtonStyle()271 void ToggleButtonPattern::UpdateButtonStyle()
272 {
273     auto host = GetHost();
274     CHECK_NULL_VOID(host);
275     auto renderContext = host->GetRenderContext();
276     CHECK_NULL_VOID(renderContext);
277     auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
278     CHECK_NULL_VOID(textNode);
279     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
280     CHECK_NULL_VOID(textLayoutProperty);
281     auto paintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>();
282     CHECK_NULL_VOID(paintProperty);
283     bool isOffState = paintProperty->GetIsOnValue(false);
284     UpdateTexOverflow((isHover_ || isFocus_), textLayoutProperty);
285     if (isFocus_) {
286         SetFocusButtonStyle(textNode, textLayoutProperty, isOffState, renderContext);
287     } else {
288         SetBlurButtonStyle(textNode, textLayoutProperty, isOffState, renderContext);
289     }
290     textNode->MarkDirtyNode();
291 }
292 
SetBlurButtonStyle(RefPtr<FrameNode> & textNode,RefPtr<TextLayoutProperty> & textLayoutProperty,bool isOffState,RefPtr<RenderContext> & renderContext)293 void ToggleButtonPattern::SetBlurButtonStyle(RefPtr<FrameNode>& textNode,
294     RefPtr<TextLayoutProperty>& textLayoutProperty,
295     bool isOffState, RefPtr<RenderContext>& renderContext)
296 {
297     CHECK_NULL_VOID(toggleTheme_);
298     CHECK_NULL_VOID(renderContext);
299     if (isCheckedShadow_ && isOn_.value_or(false)) {
300         isCheckedShadow_ = false;
301         ShadowStyle shadowStyle = static_cast<ShadowStyle>(toggleTheme_->GetShadowNormal());
302         renderContext->UpdateBackShadow(Shadow::CreateShadow(shadowStyle));
303     }
304     if (isShadow_ && !isOn_.value_or(false)) {
305         isShadow_ = false;
306         renderContext->UpdateBackShadow(Shadow::CreateShadow(ShadowStyle::None));
307     }
308     if (isScale_) {
309         isScale_ = false;
310         renderContext->SetScale(1.0, 1.0);
311     }
312     isbgColorFocus_ = renderContext->GetBackgroundColor() == (isOffState ?
313         toggleTheme_->GetBackgroundColorFocusChecked() : toggleTheme_->GetBackgroundColorFocusUnchecked());
314     if (isbgColorFocus_) {
315         Color color =
316             isOffState ? toggleTheme_->GetCheckedColor() : toggleTheme_->GetBackgroundColor();
317         renderContext->UpdateBackgroundColor(color);
318     }
319     isTextColor_ = textLayoutProperty->GetTextColor() == toggleTheme_->GetTextColorFocus();
320     if (isTextColor_) {
321         textLayoutProperty->UpdateTextColor(toggleTheme_->GetTextColor());
322         textNode->MarkModifyDone();
323         textNode->MarkDirtyNode();
324     }
325 }
326 
SetFocusButtonStyle(RefPtr<FrameNode> & textNode,RefPtr<TextLayoutProperty> & textLayoutProperty,bool isOffState,RefPtr<RenderContext> & renderContext)327 void ToggleButtonPattern::SetFocusButtonStyle(RefPtr<FrameNode>& textNode,
328     RefPtr<TextLayoutProperty>& textLayoutProperty,
329     bool isOffState, RefPtr<RenderContext>& renderContext)
330 {
331     CHECK_NULL_VOID(textNode);
332     CHECK_NULL_VOID(textLayoutProperty);
333     CHECK_NULL_VOID(toggleTheme_);
334     CHECK_NULL_VOID(renderContext);
335 
336     isTextColor_ = textLayoutProperty->GetTextColor() == toggleTheme_->GetTextColor();
337     if (isTextColor_) {
338         textLayoutProperty->UpdateTextColor(toggleTheme_->GetTextColorFocus());
339         textNode->MarkModifyDone();
340         textNode->MarkDirtyNode();
341     }
342     SetToggleScale(renderContext);
343     Shadow shadowValue = isOffState
344         ? Shadow::CreateShadow(static_cast<ShadowStyle>(toggleTheme_->GetShadowNormal()))
345         : Shadow::CreateShadow(ShadowStyle::None);
346     isbgColorFocus_ = renderContext->GetBackgroundColor() ==
347         (isOffState ? toggleTheme_->GetCheckedColor() : toggleTheme_->GetBackgroundColor());
348     HandleFocusShadowStyle(isOffState, renderContext, shadowValue, isbgColorFocus_);
349 }
350 
HandleFocusShadowStyle(bool isOffState,RefPtr<RenderContext> & renderContext,Shadow shadowValue,bool isbgColorFocus)351 void ToggleButtonPattern::HandleFocusShadowStyle(bool isOffState, RefPtr<RenderContext>& renderContext,
352     Shadow shadowValue, bool isbgColorFocus)
353 {
354     CHECK_NULL_VOID(renderContext);
355     auto&& graphics = renderContext->GetOrCreateGraphics();
356     CHECK_NULL_VOID(graphics);
357     auto isNeedShadow = !graphics->HasBackShadow() || graphics->GetBackShadowValue() == shadowValue;
358     if (isNeedShadow) {
359         isOffState ? isCheckedShadow_ = isNeedShadow : isShadow_ = isNeedShadow;
360         ShadowStyle focusShadowStyle = static_cast<ShadowStyle>(toggleTheme_->GetShadowFocus());
361         renderContext->UpdateBackShadow(Shadow::CreateShadow(focusShadowStyle));
362     }
363     if (isbgColorFocus) {
364         renderContext->UpdateBackgroundColor(isOffState ? toggleTheme_->GetBackgroundColorFocusChecked()
365             : toggleTheme_->GetBackgroundColorFocusUnchecked());
366     }
367 }
368 
HandleFocusStyle()369 void ToggleButtonPattern::HandleFocusStyle()
370 {
371     auto host = GetHost();
372     CHECK_NULL_VOID(host);
373     auto focusHub = host->GetOrCreateFocusHub();
374     CHECK_NULL_VOID(focusHub);
375     auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
376         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "status button handle focus event");
377         auto pattern = weak.Upgrade();
378         CHECK_NULL_VOID(pattern);
379         pattern->HandleFocusEvent();
380     };
381     focusHub->SetOnFocusInternal(focusTask);
382     auto blurTask = [weak = WeakClaim(this)]() {
383         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "status button handle blur event");
384         auto pattern = weak.Upgrade();
385         CHECK_NULL_VOID(pattern);
386         pattern->HandleBlurEvent();
387     };
388     focusHub->SetOnBlurInternal(blurTask);
389 }
390 
391 
HandleFocusEvent()392 void ToggleButtonPattern::HandleFocusEvent()
393 {
394     auto host = GetHost();
395     CHECK_NULL_VOID(host);
396     auto pipeline = host->GetContextRefPtr();
397     CHECK_NULL_VOID(pipeline);
398     AddIsFocusActiveUpdateEvent();
399     if (pipeline->GetIsFocusActive()) {
400         SetIsFocus(true);
401         UpdateButtonStyle();
402     }
403 }
404 
HandleBlurEvent()405 void ToggleButtonPattern::HandleBlurEvent()
406 {
407     SetIsFocus(false);
408     RemoveIsFocusActiveUpdateEvent();
409     UpdateButtonStyle();
410 }
411 
SetToggleScale(RefPtr<RenderContext> & renderContext)412 void ToggleButtonPattern::SetToggleScale(RefPtr<RenderContext>& renderContext)
413 {
414     CHECK_NULL_VOID(toggleTheme_);
415     auto&& transform = renderContext->GetOrCreateTransform();
416     CHECK_NULL_VOID(transform);
417     float sacleHoverOrFocus = toggleTheme_->GetScaleHoverOrFocus();
418     VectorF scale(sacleHoverOrFocus, sacleHoverOrFocus);
419     if (!transform->HasTransformScale() || transform->GetTransformScaleValue() == scale) {
420         isScale_ = true;
421         renderContext->SetScale(sacleHoverOrFocus, sacleHoverOrFocus);
422     }
423 }
424 
SetAccessibilityAction()425 void ToggleButtonPattern::SetAccessibilityAction()
426 {
427     auto host = GetHost();
428     CHECK_NULL_VOID(host);
429     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
430     CHECK_NULL_VOID(accessibilityProperty);
431     accessibilityProperty->SetActionSelect([weakPtr = WeakClaim(this)]() {
432         const auto& pattern = weakPtr.Upgrade();
433         CHECK_NULL_VOID(pattern);
434         pattern->UpdateSelectStatus(true);
435     });
436 
437     accessibilityProperty->SetActionClearSelection([weakPtr = WeakClaim(this)]() {
438         const auto& pattern = weakPtr.Upgrade();
439         CHECK_NULL_VOID(pattern);
440         pattern->UpdateSelectStatus(false);
441     });
442 }
443 
UpdateSelectStatus(bool isSelected)444 void ToggleButtonPattern::UpdateSelectStatus(bool isSelected)
445 {
446     auto host = GetHost();
447     CHECK_NULL_VOID(host);
448     auto context = host->GetRenderContext();
449     CHECK_NULL_VOID(context);
450     MarkIsSelected(isSelected);
451     context->OnMouseSelectUpdate(isSelected, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
452 }
453 
MarkIsSelected(bool isSelected)454 void ToggleButtonPattern::MarkIsSelected(bool isSelected)
455 {
456     if (isOn_ == isSelected) {
457         return;
458     }
459     isOn_ = isSelected;
460     auto eventHub = GetOrCreateEventHub<ToggleButtonEventHub>();
461     CHECK_NULL_VOID(eventHub);
462     eventHub->UpdateChangeEvent(isSelected);
463     auto host = GetHost();
464     CHECK_NULL_VOID(host);
465     if (isSelected) {
466         eventHub->SetCurrentUIState(UI_STATE_SELECTED, isSelected);
467         host->OnAccessibilityEvent(AccessibilityEventType::SELECTED);
468     } else {
469         eventHub->SetCurrentUIState(UI_STATE_SELECTED, isSelected);
470         host->OnAccessibilityEvent(AccessibilityEventType::CHANGE);
471     }
472 }
473 
OnAfterModifyDone()474 void ToggleButtonPattern::OnAfterModifyDone()
475 {
476     auto host = GetHost();
477     CHECK_NULL_VOID(host);
478     auto inspectorId = host->GetInspectorId().value_or("");
479     if (!inspectorId.empty()) {
480         Recorder::NodeDataCache::Get().PutBool(host, inspectorId, isOn_.value_or(false));
481     }
482 }
483 
InitTouchEvent()484 void ToggleButtonPattern::InitTouchEvent()
485 {
486     if (touchListener_) {
487         return;
488     }
489     auto host = GetHost();
490     CHECK_NULL_VOID(host);
491     auto gesture = host->GetOrCreateGestureEventHub();
492     CHECK_NULL_VOID(gesture);
493     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
494         auto buttonPattern = weak.Upgrade();
495         CHECK_NULL_VOID(buttonPattern);
496         if (info.GetTouches().empty()) {
497             return;
498         }
499         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
500             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch down");
501             buttonPattern->OnTouchDown();
502         }
503         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
504             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
505             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch up");
506             buttonPattern->OnTouchUp();
507         }
508     };
509     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
510     gesture->AddTouchEvent(touchListener_);
511 }
512 
OnTouchDown()513 void ToggleButtonPattern::OnTouchDown()
514 {
515     isPress_ = true;
516     FireBuilder();
517     if (UseContentModifier()) {
518         return;
519     }
520     auto host = GetHost();
521     CHECK_NULL_VOID(host);
522     auto buttonEventHub = GetOrCreateEventHub<ButtonEventHub>();
523     CHECK_NULL_VOID(buttonEventHub);
524     if (buttonEventHub->GetStateEffect()) {
525         auto renderContext = host->GetRenderContext();
526         CHECK_NULL_VOID(renderContext);
527         backgroundColor_ = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT);
528         if (clickedColor_.has_value()) {
529             // for user self-defined
530             renderContext->UpdateBackgroundColor(clickedColor_.value());
531             return;
532         }
533         // for system default
534         auto isNeedToHandleHoverOpacity = false;
535         AnimateTouchAndHover(renderContext, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL, TYPE_TOUCH,
536             TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
537     }
538 }
539 
OnTouchUp()540 void ToggleButtonPattern::OnTouchUp()
541 {
542     isPress_ = false;
543     FireBuilder();
544     if (UseContentModifier()) {
545         return;
546     }
547     auto host = GetHost();
548     CHECK_NULL_VOID(host);
549     auto buttonEventHub = GetOrCreateEventHub<ButtonEventHub>();
550     CHECK_NULL_VOID(buttonEventHub);
551     if (buttonEventHub->GetStateEffect()) {
552         auto renderContext = host->GetRenderContext();
553         if (clickedColor_.has_value()) {
554             renderContext->UpdateBackgroundColor(backgroundColor_);
555             return;
556         }
557         if (buttonEventHub->IsEnabled()) {
558             auto isNeedToHandleHoverOpacity = false;
559             AnimateTouchAndHover(renderContext, TYPE_TOUCH, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL,
560                 TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
561         } else {
562             AnimateTouchAndHover(renderContext, TYPE_TOUCH, TYPE_CANCEL, TOUCH_DURATION, Curves::FRICTION);
563         }
564     }
565 }
566 
InitClickEvent()567 void ToggleButtonPattern::InitClickEvent()
568 {
569     if (clickListener_) {
570         return;
571     }
572     auto host = GetHost();
573     CHECK_NULL_VOID(host);
574     auto gesture = host->GetOrCreateGestureEventHub();
575     CHECK_NULL_VOID(gesture);
576     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
577         auto buttonPattern = weak.Upgrade();
578         CHECK_NULL_VOID(buttonPattern);
579         buttonPattern->OnClick();
580     };
581     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
582     gesture->AddClickEvent(clickListener_);
583 }
584 
OnClick()585 void ToggleButtonPattern::OnClick()
586 {
587     if (UseContentModifier()) {
588         return;
589     }
590     auto host = GetHost();
591     CHECK_NULL_VOID(host);
592     auto paintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>();
593     CHECK_NULL_VOID(paintProperty);
594     bool isLastSelected = false;
595     if (paintProperty->HasIsOn()) {
596         isLastSelected = paintProperty->GetIsOnValue();
597     }
598     const auto& renderContext = host->GetRenderContext();
599     CHECK_NULL_VOID(renderContext);
600     Color selectedColor;
601     auto buttonPaintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>();
602     CHECK_NULL_VOID(buttonPaintProperty);
603     if (isLastSelected) {
604         selectedColor = buttonPaintProperty->GetBackgroundColor().value_or(unCheckedColor_);
605     } else {
606         selectedColor = buttonPaintProperty->GetSelectedColor().value_or(checkedColor_);
607     }
608     paintProperty->UpdateIsOn(!isLastSelected);
609     isOn_ = !isLastSelected;
610     renderContext->UpdateBackgroundColor(selectedColor);
611     auto buttonEventHub = GetOrCreateEventHub<ToggleButtonEventHub>();
612     CHECK_NULL_VOID(buttonEventHub);
613     buttonEventHub->UpdateChangeEvent(!isLastSelected);
614     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
615     HandleOnOffStyle(!isOn_.value(), isFocus_);
616 }
617 
HandleOnOffStyle(bool isOnToOff,bool isFocus)618 void ToggleButtonPattern::HandleOnOffStyle(bool isOnToOff, bool isFocus)
619 {
620     auto host = GetHost();
621     CHECK_NULL_VOID(host);
622     auto renderContext = host->GetRenderContext();
623     CHECK_NULL_VOID(renderContext);
624     CHECK_NULL_VOID(toggleTheme_);
625     UpdateButtonStyle();
626     BorderColorProperty borderColor;
627     borderColor.SetColor(isOnToOff ? toggleTheme_->GetBorderColorChecked() : toggleTheme_->GetBorderColorUnchecked());
628     if (!renderContext->HasBorderColor() || renderContext->GetBorderColor() == borderColor) {
629         BorderColorProperty color;
630         color.SetColor(isOnToOff ? toggleTheme_->GetBorderColorUnchecked() : toggleTheme_->GetBorderColorChecked());
631         renderContext->UpdateBorderColor(color);
632     }
633 }
634 
InitButtonAndText()635 void ToggleButtonPattern::InitButtonAndText()
636 {
637     auto host = GetHost();
638     CHECK_NULL_VOID(host);
639     auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>();
640     CHECK_NULL_VOID(layoutProperty);
641     if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
642         layoutProperty->UpdateType(ButtonType::ROUNDED_RECTANGLE);
643     } else {
644         layoutProperty->UpdateType(ButtonType::CAPSULE);
645     }
646 
647     auto renderContext = host->GetRenderContext();
648     CHECK_NULL_VOID(renderContext);
649     if (!renderContext->HasBorderRadius()) {
650         renderContext->UpdateBorderRadius({ buttonRadius_, buttonRadius_, buttonRadius_, buttonRadius_ });
651     }
652     if (!host->GetFirstChild()) {
653         return;
654     }
655     auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
656     CHECK_NULL_VOID(textNode);
657     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
658     CHECK_NULL_VOID(textLayoutProperty);
659     if (textLayoutProperty->HasFontSize()) {
660         layoutProperty->UpdateFontSize(textLayoutProperty->GetFontSizeValue(textFontSize_));
661     }
662     layoutProperty->UpdateLabel(UtfUtils::Str16ToStr8(textLayoutProperty->GetContentValue(u"")));
663     if (!textLayoutProperty->GetTextColorFlagByUserValue(false)) {
664         textLayoutProperty->UpdateTextColor(textColor_);
665     }
666 
667     if (!textLayoutProperty->GetMarginProperty()) {
668         MarginProperty margin;
669         margin.left = CalcLength(textMargin_.ConvertToPx());
670         margin.right = CalcLength(textMargin_.ConvertToPx());
671         textLayoutProperty->UpdateMargin(margin);
672     }
673     UpdateTexOverflow(false, textLayoutProperty);
674     textNode->MarkModifyDone();
675     textNode->MarkDirtyNode();
676 }
677 
InitOnKeyEvent()678 void ToggleButtonPattern::InitOnKeyEvent()
679 {
680     auto host = GetHost();
681     CHECK_NULL_VOID(host);
682     auto focusHub = host->GetOrCreateFocusHub();
683     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
684         auto pattern = wp.Upgrade();
685         if (!pattern) {
686             return false;
687         }
688         return pattern->OnKeyEvent(event);
689     };
690     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
691 }
692 
OnKeyEvent(const KeyEvent & event)693 bool ToggleButtonPattern::OnKeyEvent(const KeyEvent& event)
694 {
695     if (event.action != KeyAction::DOWN) {
696         return false;
697     }
698     if (event.code == KeyCode::KEY_SPACE || event.code == KeyCode::KEY_ENTER) {
699         OnClick();
700         return true;
701     }
702     return false;
703 }
704 
ProvideRestoreInfo()705 std::string ToggleButtonPattern::ProvideRestoreInfo()
706 {
707     auto jsonObj = JsonUtil::Create(true);
708     jsonObj->Put("IsOn", isOn_.value_or(false));
709     return jsonObj->ToString();
710 }
711 
OnRestoreInfo(const std::string & restoreInfo)712 void ToggleButtonPattern::OnRestoreInfo(const std::string& restoreInfo)
713 {
714     auto toggleButtonPaintProperty = GetPaintProperty<ToggleButtonPaintProperty>();
715     CHECK_NULL_VOID(toggleButtonPaintProperty);
716     auto info = JsonUtil::ParseJsonString(restoreInfo);
717     if (!info->IsValid() || !info->IsObject()) {
718         return;
719     }
720     auto jsonIsOn = info->GetValue("IsOn");
721     toggleButtonPaintProperty->UpdateIsOn(jsonIsOn->GetBool());
722     OnModifyDone();
723 }
724 
OnColorConfigurationUpdate()725 void ToggleButtonPattern::OnColorConfigurationUpdate()
726 {
727     OnModifyDone();
728     if (SystemProperties::ConfigChangePerform()) {
729         auto host = GetHost();
730         CHECK_NULL_VOID(host);
731         auto pipeline = host->GetContext();
732         CHECK_NULL_VOID(pipeline);
733         auto theme = pipeline->GetTheme<ToggleTheme>();
734         CHECK_NULL_VOID(theme);
735         auto pops = host->GetPaintProperty<ToggleButtonPaintProperty>();
736         CHECK_NULL_VOID(pops);
737         if (!pops->GetSelectedColorSetByUserValue(false)) {
738             Color color = theme->GetCheckedColor();
739             pops->UpdateSelectedColor(color);
740         }
741         host->MarkModifyDone();
742         host->MarkDirtyNode();
743     }
744 }
745 
OnThemeScopeUpdate(int32_t themeScopeId)746 bool ToggleButtonPattern::OnThemeScopeUpdate(int32_t themeScopeId)
747 {
748     InitParameters();
749     bool result = false;
750     auto host = GetHost();
751     CHECK_NULL_RETURN(host, false);
752     auto renderContext = host->GetRenderContext();
753     CHECK_NULL_RETURN(renderContext, false);
754 
755     auto paintProperty = GetPaintProperty<ToggleButtonPaintProperty>();
756     CHECK_NULL_RETURN(paintProperty, false);
757 
758     if (isOn_.value_or(false) && !paintProperty->HasSelectedColor()) {
759         renderContext->UpdateBackgroundColor(checkedColor_);
760         result = true;
761     }
762     if (!isOn_.value_or(false) && !paintProperty->HasBackgroundColor()) {
763         renderContext->UpdateBackgroundColor(unCheckedColor_);
764         result = true;
765     }
766     host->MarkDirtyNode();
767     return result;
768 }
769 
SetButtonPress(bool isSelected)770 void ToggleButtonPattern::SetButtonPress(bool isSelected)
771 {
772     auto host = GetHost();
773     CHECK_NULL_VOID(host);
774     auto eventHub = host->GetOrCreateEventHub<EventHub>();
775     CHECK_NULL_VOID(eventHub);
776     auto enabled = eventHub->IsEnabled();
777     if (!enabled) {
778         return;
779     }
780     auto paintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>();
781     CHECK_NULL_VOID(paintProperty);
782     paintProperty->UpdateIsOn(isSelected);
783     OnModifyDone();
784 }
785 
FireBuilder()786 void ToggleButtonPattern::FireBuilder()
787 {
788     auto host = GetHost();
789     CHECK_NULL_VOID(host);
790     if (!toggleMakeFunc_.has_value()) {
791         auto children = host->GetChildren();
792         for (const auto& child : children) {
793             if (child->GetId() == nodeId_) {
794                 host->RemoveChildAndReturnIndex(child);
795                 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
796                 break;
797             }
798         }
799         return;
800     }
801     auto node = BuildContentModifierNode();
802     if (contentModifierNode_ == node) {
803         return;
804     }
805     auto renderContext = host->GetRenderContext();
806     CHECK_NULL_VOID(renderContext);
807     renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
808     host->RemoveChildAndReturnIndex(contentModifierNode_);
809     contentModifierNode_ = node;
810     CHECK_NULL_VOID(contentModifierNode_);
811     nodeId_ = contentModifierNode_->GetId();
812     host->AddChild(contentModifierNode_, 0);
813     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
814 }
815 
BuildContentModifierNode()816 RefPtr<FrameNode> ToggleButtonPattern::BuildContentModifierNode()
817 {
818     if (!toggleMakeFunc_.has_value()) {
819         return nullptr;
820     }
821     auto host = GetHost();
822     CHECK_NULL_RETURN(host, nullptr);
823     auto eventHub = host->GetOrCreateEventHub<EventHub>();
824     CHECK_NULL_RETURN(eventHub, nullptr);
825     auto enabled = eventHub->IsEnabled();
826     auto paintProperty = host->GetPaintProperty<ToggleButtonPaintProperty>();
827     CHECK_NULL_RETURN(paintProperty, nullptr);
828     bool isSelected = false;
829     if (paintProperty->HasIsOn()) {
830         isSelected = paintProperty->GetIsOnValue();
831     } else {
832         isSelected = false;
833     }
834     return (toggleMakeFunc_.value())(ToggleConfiguration(enabled, isSelected));
835 }
836 
SetToggleBuilderFunc(SwitchMakeCallback && toggleMakeFunc)837 void ToggleButtonPattern::SetToggleBuilderFunc(SwitchMakeCallback&& toggleMakeFunc)
838 {
839     if (toggleMakeFunc == nullptr) {
840         toggleMakeFunc_ = std::nullopt;
841         contentModifierNode_ = nullptr;
842         auto host = GetHost();
843         CHECK_NULL_VOID(host);
844         for (auto child : host->GetChildren()) {
845             auto childNode = DynamicCast<FrameNode>(child);
846             if (childNode) {
847                 childNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
848             }
849         }
850         OnModifyDone();
851         return;
852     }
853     toggleMakeFunc_ = std::move(toggleMakeFunc);
854 }
855 
ToTreeJson(std::unique_ptr<JsonValue> & json,const InspectorConfig & config) const856 void ToggleButtonPattern::ToTreeJson(std::unique_ptr<JsonValue>& json, const InspectorConfig& config) const
857 {
858     Pattern::ToTreeJson(json, config);
859     json->Put(TreeKey::CHECKED, isOn_ ? "true" : "false");
860 }
861 } // namespace OHOS::Ace::NG
862