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