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,double distanceThreshold)178 void ButtonModelImpl::OnClick(GestureEventFunc&& tapEventFunc, ClickEventFunc&& clickEventFunc,
179 double distanceThreshold)
180 {
181 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
182 CHECK_NULL_VOID(inspector);
183 auto impl = inspector->GetInspectorFunctionImpl();
184 RefPtr<Gesture> tapGesture = AceType::MakeRefPtr<TapGesture>(1, 1);
185 tapGesture->SetOnActionId([func = std::move(tapEventFunc), impl](GestureEvent& info) {
186 if (impl) {
187 impl->UpdateEventInfo(info);
188 }
189 func(info);
190 });
191 auto click = ViewStackProcessor::GetInstance()->GetBoxComponent();
192 click->SetOnClick(tapGesture);
193
194 auto onClickId = EventMarker([func = std::move(clickEventFunc), impl](const BaseEventInfo* info) {
195 const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
196 if (!clickInfo) {
197 return;
198 }
199 auto newInfo = *clickInfo;
200 if (impl) {
201 impl->UpdateEventInfo(newInfo);
202 }
203 func(clickInfo);
204 });
205 auto buttonComponent =
206 AceType::DynamicCast<ButtonComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
207 if (buttonComponent) {
208 buttonComponent->SetKeyEnterEventId(onClickId);
209 }
210 auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent(false);
211 if (focusableComponent) {
212 focusableComponent->SetOnClickId(onClickId);
213 }
214 }
215
BackgroundColor(const Color & color,const bool & colorFlag)216 void ButtonModelImpl::BackgroundColor(const Color& color, const bool& colorFlag)
217 {
218 if (!colorFlag) {
219 return;
220 }
221
222 auto stack = ViewStackProcessor::GetInstance();
223 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
224 AnimationOption option = ViewStackProcessor::GetInstance()->GetImplicitAnimationOption();
225 CHECK_NULL_VOID(buttonComponent);
226
227 if (!stack->IsVisualStateSet()) {
228 buttonComponent->SetBackgroundColor(color);
229 auto pipeline = PipelineBase::GetCurrentContext();
230 CHECK_NULL_VOID(pipeline);
231 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
232 if (buttonTheme) {
233 Color blendColor = buttonTheme->GetClickedColor();
234 buttonComponent->SetClickedColor(buttonComponent->GetBackgroundColor().BlendColor(blendColor));
235 }
236 } else {
237 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableColor>(
238 ButtonStateAttribute::COLOR, AnimatableColor(color, option), stack->GetVisualState());
239 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::COLOR, VisualState::NORMAL)) {
240 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableColor>(ButtonStateAttribute::COLOR,
241 AnimatableColor(buttonComponent->GetBackgroundColor(), option), VisualState::NORMAL);
242 }
243 }
244 }
245
SetWidth(const Dimension & width)246 void ButtonModelImpl::SetWidth(const Dimension& width)
247 {
248 auto stack = ViewStackProcessor::GetInstance();
249 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
250 AnimationOption option = stack->GetImplicitAnimationOption();
251 CHECK_NULL_VOID(buttonComponent);
252 if (!stack->IsVisualStateSet()) {
253 buttonComponent->SetWidth(width, stack->GetImplicitAnimationOption());
254 } else {
255 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
256 ButtonStateAttribute::WIDTH, AnimatableDimension(width, option), stack->GetVisualState());
257 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::WIDTH, VisualState::NORMAL)) {
258 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(ButtonStateAttribute::WIDTH,
259 AnimatableDimension(buttonComponent->GetWidth(), option), VisualState::NORMAL);
260 }
261 }
262 }
263
SetHeight(const Dimension & height)264 void ButtonModelImpl::SetHeight(const Dimension& height)
265 {
266 auto stack = ViewStackProcessor::GetInstance();
267 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
268 auto option = stack->GetImplicitAnimationOption();
269 CHECK_NULL_VOID(buttonComponent);
270 buttonComponent->IsNeedResetHeight(false);
271 if (!stack->IsVisualStateSet()) {
272 buttonComponent->SetHeight(height, option);
273 buttonComponent->SetDeclareHeight(true);
274 } else {
275 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
276 ButtonStateAttribute::HEIGHT, AnimatableDimension(height, option), stack->GetVisualState());
277 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::HEIGHT, VisualState::NORMAL)) {
278 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(ButtonStateAttribute::HEIGHT,
279 AnimatableDimension(buttonComponent->GetHeight(), option), VisualState::NORMAL);
280 }
281 }
282 }
283
SetAspectRatio(const double & ratio)284 void ButtonModelImpl::SetAspectRatio(const double& ratio)
285 {
286 auto stack = ViewStackProcessor::GetInstance();
287 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
288 CHECK_NULL_VOID(buttonComponent);
289 buttonComponent->SetAspectRatio(ratio);
290 }
291
SetSize(const std::optional<Dimension> & width,const std::optional<Dimension> & height)292 void ButtonModelImpl::SetSize(const std::optional<Dimension>& width, const std::optional<Dimension>& height)
293 {
294 if (width.has_value()) {
295 SetWidth(width.value());
296 }
297 if (height.has_value()) {
298 SetHeight(height.value());
299 }
300 }
301
SetBorderRadius(const Dimension & radius)302 void ButtonModelImpl::SetBorderRadius(const Dimension& radius)
303 {
304 auto stack = ViewStackProcessor::GetInstance();
305 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
306 auto option = stack->GetImplicitAnimationOption();
307 CHECK_NULL_VOID(buttonComponent);
308 buttonComponent->SetRadiusState(true);
309 if (!stack->IsVisualStateSet()) {
310 buttonComponent->SetRectRadius(radius);
311 ViewAbstractModel::GetInstance()->SetBorderRadius(radius);
312 } else {
313 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
314 ButtonStateAttribute::RADIUS, AnimatableDimension(radius, option), stack->GetVisualState());
315 auto boxComponent = stack->GetBoxComponent();
316 boxComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(
317 BoxStateAttribute::BORDER_RADIUS, AnimatableDimension(radius, option), stack->GetVisualState());
318
319 if (!buttonComponent->GetStateAttributes()->HasAttribute(ButtonStateAttribute::RADIUS, VisualState::NORMAL)) {
320 buttonComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(ButtonStateAttribute::RADIUS,
321 AnimatableDimension(buttonComponent->GetRectRadius(), option), VisualState::NORMAL);
322 auto defaultRadius = BoxComponentHelper::GetBorderRadius(boxComponent->GetBackDecoration());
323 boxComponent->GetStateAttributes()->AddAttribute<AnimatableDimension>(BoxStateAttribute::BORDER_RADIUS,
324 AnimatableDimension(defaultRadius.GetX(), option), VisualState::NORMAL);
325 }
326 }
327 }
328
GetTextComponent()329 RefPtr<TextComponent> ButtonModelImpl::GetTextComponent()
330 {
331 auto stack = ViewStackProcessor::GetInstance();
332 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
333 if (buttonComponent == nullptr) {
334 LOGE("Button component create failed");
335 return nullptr;
336 }
337 auto paddingComponent = AceType::DynamicCast<PaddingComponent>(buttonComponent->GetChildren().front());
338 if (!paddingComponent) {
339 LOGE("Padding component create failed");
340 return nullptr;
341 }
342 auto textComponent = AceType::DynamicCast<TextComponent>(paddingComponent->GetChild());
343 return textComponent;
344 }
345
ResetButtonHeight()346 void ButtonModelImpl::ResetButtonHeight()
347 {
348 auto stack = ViewStackProcessor::GetInstance();
349 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
350 if (buttonComponent) {
351 if (buttonComponent->GetType() == ButtonType::CIRCLE) {
352 return;
353 }
354 const Dimension initialHeight = Dimension(-1.0, DimensionUnit::VP);
355 buttonComponent->SetHeight(initialHeight);
356 }
357 }
358
SetTypeAndStateEffect(const std::optional<ButtonType> & type,const std::optional<bool> & stateEffect,const RefPtr<ButtonComponent> & buttonComponent)359 void ButtonModelImpl::SetTypeAndStateEffect(const std::optional<ButtonType>& type,
360 const std::optional<bool>& stateEffect, const RefPtr<ButtonComponent>& buttonComponent)
361 {
362 if (type.has_value()) {
363 buttonComponent->SetType(type.value());
364 } else {
365 // undefined use capsule type.
366 buttonComponent->SetType(ButtonType::CAPSULE);
367 }
368
369 if (stateEffect.has_value()) {
370 buttonComponent->SetStateEffect(stateEffect.value());
371 }
372 }
373
SetDefaultAttributes(const RefPtr<ButtonComponent> & buttonComponent)374 void ButtonModelImpl::SetDefaultAttributes(const RefPtr<ButtonComponent>& buttonComponent)
375 {
376 buttonComponent->SetType(ButtonType::CAPSULE);
377 buttonComponent->SetDeclarativeFlag(true);
378 auto pipeline = PipelineBase::GetCurrentContext();
379 CHECK_NULL_VOID(pipeline);
380 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
381 CHECK_NULL_VOID(buttonTheme);
382 buttonComponent->SetHeight(buttonTheme->GetHeight());
383 buttonComponent->SetBackgroundColor(buttonTheme->GetBgColor());
384 buttonComponent->SetClickedColor(buttonComponent->GetBackgroundColor().BlendColor(buttonTheme->GetClickedColor()));
385 buttonComponent->SetHoverColor(buttonTheme->GetHoverColor());
386 }
387
SetRemoteMessage(RemoteCallback && remoteCallback)388 void ButtonModelImpl::SetRemoteMessage(RemoteCallback&& remoteCallback)
389 {
390 EventMarker remoteMessageEventId(std::move(remoteCallback));
391 auto stack = ViewStackProcessor::GetInstance();
392 auto buttonComponent = AceType::DynamicCast<ButtonComponent>(stack->GetMainComponent());
393 if (buttonComponent) {
394 buttonComponent->SetRemoteMessageEventId(remoteMessageEventId);
395 }
396 }
397 } // namespace OHOS::Ace::Framework
398