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