1 /*
2 * Copyright (c) 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 "frameworks/bridge/declarative_frontend/jsview/models/button_model_impl.h"
17
18 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
19 #include "bridge/declarative_frontend/view_stack_processor.h"
20 #include "core/components/box/box_component_helper.h"
21 #include "core/components/button/button_component.h"
22 #include "core/components/padding/padding_component.h"
23 #include "core/pipeline/pipeline_base.h"
24
25 namespace OHOS::Ace::Framework {
SetFontSize(const Dimension & fontSize)26 void ButtonModelImpl::SetFontSize(const Dimension& fontSize)
27 {
28 auto textComponent = GetTextComponent();
29 if (textComponent) {
30 auto textStyle = textComponent->GetTextStyle();
31 textStyle.SetFontSize(fontSize);
32 textStyle.SetAdaptTextSize(fontSize, fontSize);
33 textComponent->SetTextStyle(textStyle);
34 }
35
36 auto stack = ViewStackProcessor::GetInstance();
37 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
38 if (!buttonComponent) {
39 return;
40 }
41 if (buttonComponent->NeedResetHeight()) {
42 ResetButtonHeight();
43 }
44 }
45
SetFontWeight(const Ace::FontWeight & fontWeight)46 void ButtonModelImpl::SetFontWeight(const Ace::FontWeight& fontWeight)
47 {
48 auto textComponent = GetTextComponent();
49 if (textComponent) {
50 auto textStyle = textComponent->GetTextStyle();
51 textStyle.SetFontWeight(fontWeight);
52 textComponent->SetTextStyle(textStyle);
53 }
54 }
55
SetFontStyle(const Ace::FontStyle & fontStyle)56 void ButtonModelImpl::SetFontStyle(const Ace::FontStyle& fontStyle)
57 {
58 auto textComponent = GetTextComponent();
59 if (textComponent) {
60 auto textStyle = textComponent->GetTextStyle();
61 textStyle.SetFontStyle(fontStyle);
62 textComponent->SetTextStyle(textStyle);
63 }
64 }
65
SetFontFamily(const std::vector<std::string> & fontFamily)66 void ButtonModelImpl::SetFontFamily(const std::vector<std::string>& fontFamily)
67 {
68 auto textComponent = GetTextComponent();
69 if (textComponent) {
70 auto textStyle = textComponent->GetTextStyle();
71 textStyle.SetFontFamilies(fontFamily);
72 textComponent->SetTextStyle(textStyle);
73 }
74 }
75
SetFontColor(const Color & textColor)76 void ButtonModelImpl::SetFontColor(const Color& textColor)
77 {
78 auto textComponent = GetTextComponent();
79 if (textComponent) {
80 auto textStyle = textComponent->GetTextStyle();
81 textStyle.SetTextColor(textColor);
82 textComponent->SetTextStyle(textStyle);
83 }
84 }
85
SetType(const int value)86 void ButtonModelImpl::SetType(const int value)
87 {
88 auto stack = ViewStackProcessor::GetInstance();
89 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
90 if (buttonComponent) {
91 buttonComponent->SetType((ButtonType)value);
92 }
93 }
94
SetStateEffect(const bool stateEffect)95 void ButtonModelImpl::SetStateEffect(const bool stateEffect)
96 {
97 auto stack = ViewStackProcessor::GetInstance();
98 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
99 if (buttonComponent) {
100 buttonComponent->SetStateEffect(stateEffect);
101 }
102 }
103
CreateWithLabel(const CreateWithPara & para,std::list<RefPtr<Component>> & buttonChildren)104 void ButtonModelImpl::CreateWithLabel(const CreateWithPara& para, std::list<RefPtr<Component>>& buttonChildren)
105 {
106 if (para.parseSuccess.value()) {
107 auto textComponent = AceType::MakeRefPtr<TextComponent>(para.label.value());
108 auto pipeline = PipelineBase::GetCurrentContext();
109 CHECK_NULL_VOID(pipeline);
110 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
111 CHECK_NULL_VOID(buttonTheme);
112 auto textStyle = buttonTheme ? buttonTheme->GetTextStyle() : textComponent->GetTextStyle();
113 textStyle.SetMaxLines(buttonTheme ? buttonTheme->GetTextMaxLines() : 1);
114 textStyle.SetTextOverflow(TextOverflow::ELLIPSIS);
115 textComponent->SetTextStyle(textStyle);
116 auto padding = AceType::MakeRefPtr<PaddingComponent>();
117 padding->SetPadding(buttonTheme ? buttonTheme->GetPadding() : Edge());
118 padding->SetChild(textComponent);
119 Component::MergeRSNode(padding, textComponent);
120 buttonChildren.emplace_back(padding);
121 }
122 }
123
Create(const CreateWithPara & para,std::list<RefPtr<Component>> & buttonChildren)124 void ButtonModelImpl::Create(const CreateWithPara& para, std::list<RefPtr<Component>>& buttonChildren)
125 {
126 auto buttonComponent = AceType::MakeRefPtr<ButtonComponent>(buttonChildren);
127 ViewStackProcessor::GetInstance()->ClaimElementId(buttonComponent);
128 buttonComponent->SetHasCustomChild(false);
129 buttonComponent->SetCatchMode(false);
130 SetDefaultAttributes(buttonComponent);
131 SetTypeAndStateEffect(para.type, para.stateEffect, buttonComponent);
132 ViewStackProcessor::GetInstance()->Push(buttonComponent);
133 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent();
134 if (focusableComponent) {
135 focusableComponent->SetFocusable(true);
136 }
137 auto focusNodeComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent(false);
138 if (focusNodeComponent) {
139 focusNodeComponent->SetFocusNode(false);
140 }
141
142 buttonComponent->SetMouseAnimationType(HoverAnimationType::SCALE);
143 }
144
CreateWithChild(const CreateWithPara & para)145 void ButtonModelImpl::CreateWithChild(const CreateWithPara& para)
146 {
147 std::list<RefPtr<Component>> buttonChildren;
148 auto buttonComponent = AceType::MakeRefPtr<ButtonComponent>(buttonChildren);
149 ViewStackProcessor::GetInstance()->ClaimElementId(buttonComponent);
150 buttonComponent->SetHasCustomChild(true);
151 buttonComponent->SetCatchMode(false);
152 SetDefaultAttributes(buttonComponent);
153 SetTypeAndStateEffect(para.type, para.stateEffect, buttonComponent);
154 ViewStackProcessor::GetInstance()->Push(buttonComponent);
155 JSInteractableView::SetFocusable(true);
156 JSInteractableView::SetFocusNode(true);
157 buttonComponent->SetMouseAnimationType(HoverAnimationType::SCALE);
158 if (buttonComponent->NeedResetHeight()) {
159 ResetButtonHeight();
160 }
161 }
162
Padding(const NG::PaddingProperty & paddingNew,const Edge & paddingOld)163 void ButtonModelImpl::Padding(const NG::PaddingProperty& paddingNew, const Edge& paddingOld)
164 {
165 auto stack = ViewStackProcessor::GetInstance();
166 auto component = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
167 if (component) {
168 auto paddingChild = AceType::DynamicCast<PaddingComponent>(component->GetChildren().front());
169 if (paddingChild) {
170 paddingChild->SetPadding(paddingOld);
171 }
172 if (component->NeedResetHeight()) {
173 ResetButtonHeight();
174 }
175 }
176 }
177
OnClick(GestureEventFunc && tapEventFunc,ClickEventFunc && clickEventFunc)178 void ButtonModelImpl::OnClick(GestureEventFunc&& tapEventFunc, ClickEventFunc&& clickEventFunc)
179 {
180 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
181 CHECK_NULL_VOID(inspector);
182 auto impl = inspector->GetInspectorFunctionImpl();
183 RefPtr<Gesture> tapGesture = AceType::MakeRefPtr<TapGesture>(1, 1);
184 tapGesture->SetOnActionId([func = std::move(tapEventFunc), impl](GestureEvent& info) {
185 if (impl) {
186 impl->UpdateEventInfo(info);
187 }
188 func(info);
189 });
190 auto click = ViewStackProcessor::GetInstance()->GetBoxComponent();
191 click->SetOnClick(tapGesture);
192
193 auto onClickId = EventMarker([func = std::move(clickEventFunc), impl](const BaseEventInfo* info) {
194 const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
195 if (!clickInfo) {
196 return;
197 }
198 auto newInfo = *clickInfo;
199 if (impl) {
200 impl->UpdateEventInfo(newInfo);
201 }
202 func(clickInfo);
203 });
204 auto buttonComponent =
205 AceType::DynamicCast<ButtonComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
206 if (buttonComponent) {
207 buttonComponent->SetKeyEnterEventId(onClickId);
208 }
209 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent(false);
210 if (focusableComponent) {
211 focusableComponent->SetOnClickId(onClickId);
212 }
213 }
214
BackgroundColor(const Color & color,const bool & colorFlag)215 void ButtonModelImpl::BackgroundColor(const Color& color, const bool& colorFlag)
216 {
217 if (!colorFlag) {
218 return;
219 }
220
221 auto stack = ViewStackProcessor::GetInstance();
222 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
223 AnimationOption option = ViewStackProcessor::GetInstance()->GetImplicitAnimationOption();
224 CHECK_NULL_VOID(buttonComponent);
225
226 if (!stack->IsVisualStateSet()) {
227 buttonComponent->SetBackgroundColor(color);
228 auto pipeline = PipelineBase::GetCurrentContext();
229 CHECK_NULL_VOID(pipeline);
230 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
231 if (buttonTheme) {
232 Color blendColor = buttonTheme->GetClickedColor();
233 buttonComponent->SetClickedColor(buttonComponent->GetBackgroundColor().BlendColor(blendColor));
234 }
235 } else {
236 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableColor>(
237 ButtonStateAttribute::COLOR, AnimatableColor(color, option), stack->GetVisualState());
238 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::COLOR, VisualState::NORMAL)) {
239 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableColor>(ButtonStateAttribute::COLOR,
240 AnimatableColor(buttonComponent->GetBackgroundColor(), option), VisualState::NORMAL);
241 }
242 }
243 }
244
SetWidth(const Dimension & width)245 void ButtonModelImpl::SetWidth(const Dimension& width)
246 {
247 auto stack = ViewStackProcessor::GetInstance();
248 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
249 AnimationOption option = stack->GetImplicitAnimationOption();
250 CHECK_NULL_VOID(buttonComponent);
251 if (!stack->IsVisualStateSet()) {
252 buttonComponent->SetWidth(width, stack->GetImplicitAnimationOption());
253 } else {
254 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
255 ButtonStateAttribute::WIDTH, AnimatableDimension(width, option), stack->GetVisualState());
256 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::WIDTH, VisualState::NORMAL)) {
257 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(ButtonStateAttribute::WIDTH,
258 AnimatableDimension(buttonComponent->GetWidth(), option), VisualState::NORMAL);
259 }
260 }
261 }
262
SetHeight(const Dimension & height)263 void ButtonModelImpl::SetHeight(const Dimension& height)
264 {
265 auto stack = ViewStackProcessor::GetInstance();
266 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
267 auto option = stack->GetImplicitAnimationOption();
268 CHECK_NULL_VOID(buttonComponent);
269 buttonComponent->IsNeedResetHeight(false);
270 if (!stack->IsVisualStateSet()) {
271 buttonComponent->SetHeight(height, option);
272 buttonComponent->SetDeclareHeight(true);
273 } else {
274 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
275 ButtonStateAttribute::HEIGHT, AnimatableDimension(height, option), stack->GetVisualState());
276 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::HEIGHT, VisualState::NORMAL)) {
277 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(ButtonStateAttribute::HEIGHT,
278 AnimatableDimension(buttonComponent->GetHeight(), option), VisualState::NORMAL);
279 }
280 }
281 }
282
SetAspectRatio(const double & ratio)283 void ButtonModelImpl::SetAspectRatio(const double& ratio)
284 {
285 auto stack = ViewStackProcessor::GetInstance();
286 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
287 CHECK_NULL_VOID(buttonComponent);
288 buttonComponent->SetAspectRatio(ratio);
289 }
290
SetSize(const std::optional<Dimension> & width,const std::optional<Dimension> & height)291 void ButtonModelImpl::SetSize(const std::optional<Dimension>& width, const std::optional<Dimension>& height)
292 {
293 if (width.has_value()) {
294 SetWidth(width.value());
295 } else {
296 SetHeight(height.value());
297 }
298 }
299
SetBorderRadius(const Dimension & radius)300 void ButtonModelImpl::SetBorderRadius(const Dimension& radius)
301 {
302 auto stack = ViewStackProcessor::GetInstance();
303 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
304 auto option = stack->GetImplicitAnimationOption();
305 CHECK_NULL_VOID(buttonComponent);
306 buttonComponent->SetRadiusState(true);
307 if (!stack->IsVisualStateSet()) {
308 buttonComponent->SetRectRadius(radius);
309 ViewAbstractModel::GetInstance()->SetBorderRadius(radius);
310 } else {
311 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
312 ButtonStateAttribute::RADIUS, AnimatableDimension(radius, option), stack->GetVisualState());
313 auto boxComponent = stack->GetBoxComponent();
314 boxComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
315 BoxStateAttribute::BORDER_RADIUS, AnimatableDimension(radius, option), stack->GetVisualState());
316
317 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::RADIUS, VisualState::NORMAL)) {
318 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(ButtonStateAttribute::RADIUS,
319 AnimatableDimension(buttonComponent->GetRectRadius(), option), VisualState::NORMAL);
320 auto defaultRadius = BoxComponentHelper::GetBorderRadius(boxComponent->GetBackDecoration());
321 boxComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(BoxStateAttribute::BORDER_RADIUS,
322 AnimatableDimension(defaultRadius.GetX(), option), VisualState::NORMAL);
323 }
324 }
325 }
326
GetTextComponent()327 RefPtr<TextComponent> ButtonModelImpl::GetTextComponent()
328 {
329 auto stack = ViewStackProcessor::GetInstance();
330 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
331 if (buttonComponent == nullptr) {
332 LOGE("Button component create failed");
333 return nullptr;
334 }
335 auto paddingComponent = AceType::DynamicCast<PaddingComponent>(buttonComponent->GetChildren().front());
336 if (!paddingComponent) {
337 LOGE("Padding component create failed");
338 return nullptr;
339 }
340 auto textComponent = AceType::DynamicCast<TextComponent>(paddingComponent->GetChild());
341 return textComponent;
342 }
343
ResetButtonHeight()344 void ButtonModelImpl::ResetButtonHeight()
345 {
346 auto stack = ViewStackProcessor::GetInstance();
347 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
348 if (buttonComponent) {
349 if (buttonComponent->GetType() == ButtonType::CIRCLE) {
350 return;
351 }
352 const Dimension initialHeight = Dimension(-1.0, DimensionUnit::VP);
353 buttonComponent->SetHeight(initialHeight);
354 }
355 }
356
SetTypeAndStateEffect(const std::optional<ButtonType> & type,const std::optional<bool> & stateEffect,const RefPtr<ButtonComponent> & buttonComponent)357 void ButtonModelImpl::SetTypeAndStateEffect(const std::optional<ButtonType>& type,
358 const std::optional<bool>& stateEffect, const RefPtr<ButtonComponent>& buttonComponent)
359 {
360 if (type.has_value()) {
361 buttonComponent->SetType(type.value());
362 } else {
363 // undefined use capsule type.
364 buttonComponent->SetType(ButtonType::CAPSULE);
365 }
366
367 if (stateEffect.has_value()) {
368 buttonComponent->SetStateEffect(stateEffect.value());
369 }
370 }
371
SetDefaultAttributes(const RefPtr<ButtonComponent> & buttonComponent)372 void ButtonModelImpl::SetDefaultAttributes(const RefPtr<ButtonComponent>& buttonComponent)
373 {
374 buttonComponent->SetType(ButtonType::CAPSULE);
375 buttonComponent->SetDeclarativeFlag(true);
376 auto pipeline = PipelineBase::GetCurrentContext();
377 CHECK_NULL_VOID(pipeline);
378 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
379 CHECK_NULL_VOID(buttonTheme);
380 buttonComponent->SetHeight(buttonTheme->GetHeight());
381 buttonComponent->SetBackgroundColor(buttonTheme->GetBgColor());
382 buttonComponent->SetClickedColor(buttonComponent->GetBackgroundColor().BlendColor(buttonTheme->GetClickedColor()));
383 buttonComponent->SetHoverColor(buttonTheme->GetHoverColor());
384 }
385
SetRemoteMessage(RemoteCallback && remoteCallback)386 void ButtonModelImpl::SetRemoteMessage(RemoteCallback&& remoteCallback)
387 {
388 EventMarker remoteMessageEventId(std::move(remoteCallback));
389 auto stack = ViewStackProcessor::GetInstance();
390 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
391 if (buttonComponent) {
392 buttonComponent->SetRemoteMessageEventId(remoteMessageEventId);
393 }
394 }
395 } // namespace OHOS::Ace::Framework
396