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