• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/button/button_pattern.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components/button/button_theme.h"
20 #include "core/components/common/layout/constants.h"
21 #include "core/components/common/properties/color.h"
22 #include "core/components_ng/pattern/button/button_event_hub.h"
23 #include "core/components_ng/pattern/button/toggle_button_pattern.h"
24 #include "core/components_ng/pattern/text/text_layout_property.h"
25 #include "core/components_ng/property/property.h"
26 #include "core/pipeline/pipeline_base.h"
27 
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr float START_OPACITY = 0.0f;
31 constexpr float END_OPACITY = 0.1f;
32 constexpr int32_t DURATION = 100;
33 } // namespace
34 
OnAttachToFrameNode()35 void ButtonPattern::OnAttachToFrameNode()
36 {
37     auto host = GetHost();
38     CHECK_NULL_VOID(host);
39     auto pipeline = PipelineBase::GetCurrentContext();
40     CHECK_NULL_VOID(pipeline);
41     SetDefaultAttributes(host, pipeline);
42     host->GetRenderContext()->SetClipToFrame(true);
43     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
44     CHECK_NULL_VOID(buttonTheme);
45     clickedColor_ = buttonTheme->GetClickedColor();
46 }
47 
SetDefaultAttributes(const RefPtr<FrameNode> & buttonNode,const RefPtr<PipelineBase> & pipeline)48 void ButtonPattern::SetDefaultAttributes(const RefPtr<FrameNode>& buttonNode, const RefPtr<PipelineBase>& pipeline)
49 {
50     auto renderContext = buttonNode->GetRenderContext();
51     CHECK_NULL_VOID(renderContext);
52     auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
53     CHECK_NULL_VOID(buttonLayoutProperty);
54     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
55     CHECK_NULL_VOID(buttonTheme);
56 
57     // Init button default style
58     buttonLayoutProperty->UpdateType(ButtonType::CAPSULE);
59     renderContext->UpdateBackgroundColor(buttonTheme->GetBgColor());
60 }
61 
InitButtonLabel()62 void ButtonPattern::InitButtonLabel()
63 {
64     auto host = GetHost();
65     CHECK_NULL_VOID(host);
66     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
67     CHECK_NULL_VOID(layoutProperty);
68     if (!layoutProperty->GetLabel().has_value()) {
69         LOGI("No label, no need to initialize label.");
70         return;
71     }
72     auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
73     CHECK_NULL_VOID(textNode);
74     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
75     CHECK_NULL_VOID(textLayoutProperty);
76     auto label = layoutProperty->GetLabelValue("");
77     textLayoutProperty->UpdateContent(label);
78 
79     if (layoutProperty->GetFontSize().has_value()) {
80         textLayoutProperty->UpdateFontSize(layoutProperty->GetFontSize().value());
81     }
82     if (layoutProperty->GetFontWeight().has_value()) {
83         textLayoutProperty->UpdateFontWeight(layoutProperty->GetFontWeight().value());
84     }
85     if (layoutProperty->GetFontColor().has_value()) {
86         textLayoutProperty->UpdateTextColor(layoutProperty->GetFontColor().value());
87     }
88     if (layoutProperty->GetFontStyle().has_value()) {
89         textLayoutProperty->UpdateItalicFontStyle(layoutProperty->GetFontStyle().value());
90     }
91     if (layoutProperty->GetFontFamily().has_value()) {
92         textLayoutProperty->UpdateFontFamily(layoutProperty->GetFontFamily().value());
93     }
94     textNode->MarkModifyDone();
95     textNode->MarkDirtyNode();
96 }
97 
OnModifyDone()98 void ButtonPattern::OnModifyDone()
99 {
100     auto host = GetHost();
101     CHECK_NULL_VOID(host);
102     InitButtonLabel();
103     HandleEnabled();
104     InitTouchEvent();
105 }
106 
InitTouchEvent()107 void ButtonPattern::InitTouchEvent()
108 {
109     if (touchListener_) {
110         return;
111     }
112     auto host = GetHost();
113     CHECK_NULL_VOID(host);
114     auto gesture = host->GetOrCreateGestureEventHub();
115     CHECK_NULL_VOID(gesture);
116     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
117         auto buttonPattern = weak.Upgrade();
118         CHECK_NULL_VOID(buttonPattern);
119         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
120             buttonPattern->OnTouchDown();
121         }
122         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
123             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
124             buttonPattern->OnTouchUp();
125         }
126     };
127     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
128     gesture->AddTouchEvent(touchListener_);
129 }
130 
OnTouchDown()131 void ButtonPattern::OnTouchDown()
132 {
133     auto host = GetHost();
134     CHECK_NULL_VOID(host);
135     auto buttonEventHub = GetEventHub<ButtonEventHub>();
136     CHECK_NULL_VOID(buttonEventHub);
137     if (buttonEventHub->GetStateEffect()) {
138         const auto& renderContext = host->GetRenderContext();
139         CHECK_NULL_VOID(renderContext);
140         backgroundColor_ = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT);
141         if (isSetClickedColor_) {
142             // for user self-defined
143             renderContext->UpdateBackgroundColor(clickedColor_);
144             return;
145         }
146         // for system default
147         AnimateTouchEffectBoard(START_OPACITY, END_OPACITY, DURATION, Curves::SHARP);
148     }
149 }
150 
OnTouchUp()151 void ButtonPattern::OnTouchUp()
152 {
153     auto host = GetHost();
154     CHECK_NULL_VOID(host);
155     auto buttonEventHub = GetEventHub<ButtonEventHub>();
156     CHECK_NULL_VOID(buttonEventHub);
157     if (buttonEventHub->GetStateEffect()) {
158         const auto& renderContext = host->GetRenderContext();
159         if (isSetClickedColor_) {
160             renderContext->UpdateBackgroundColor(backgroundColor_);
161             return;
162         }
163         AnimateTouchEffectBoard(END_OPACITY, START_OPACITY, DURATION, Curves::SHARP);
164     }
165 }
166 
HandleEnabled()167 void ButtonPattern::HandleEnabled()
168 {
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 renderContext = host->GetRenderContext();
175     CHECK_NULL_VOID(renderContext);
176     auto pipeline = PipelineBase::GetCurrentContext();
177     CHECK_NULL_VOID(pipeline);
178     auto theme = pipeline->GetTheme<ButtonTheme>();
179     CHECK_NULL_VOID(theme);
180     auto alpha = theme->GetBgDisabledAlpha();
181     auto backgroundColor = renderContext->GetBackgroundColor().value_or(theme->GetBgColor());
182     if (!enabled) {
183         renderContext->OnBackgroundColorUpdate(backgroundColor.BlendOpacity(alpha));
184     } else {
185         renderContext->OnBackgroundColorUpdate(backgroundColor);
186     }
187 }
188 
AnimateTouchEffectBoard(float startOpacity,float endOpacity,int32_t duration,const RefPtr<Curve> & curve)189 void ButtonPattern::AnimateTouchEffectBoard(
190     float startOpacity, float endOpacity, int32_t duration, const RefPtr<Curve>& curve)
191 {
192     auto host = GetHost();
193     CHECK_NULL_VOID(host);
194     auto renderContext = host->GetRenderContext();
195     CHECK_NULL_VOID(renderContext);
196     Color touchColorFrom = Color::FromRGBO(0, 0, 0, startOpacity);
197     Color touchColorTo = Color::FromRGBO(0, 0, 0, endOpacity);
198     if (startOpacity > endOpacity) {
199         auto toggleButtonPattern = host->GetPattern<ToggleButtonPattern>();
200         if (toggleButtonPattern) {
201             toggleButtonPattern->OnClick();
202         }
203     }
204     Color highlightStart = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT).BlendColor(touchColorFrom);
205     Color highlightEnd = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT).BlendColor(touchColorTo);
206     renderContext->OnBackgroundColorUpdate(highlightStart);
207     AnimationOption option = AnimationOption();
208     option.SetDuration(duration);
209     option.SetCurve(curve);
210     AnimationUtils::Animate(
211         option, [renderContext, highlightEnd]() { renderContext->OnBackgroundColorUpdate(highlightEnd); });
212 }
213 
214 } // namespace OHOS::Ace::NG
215