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