• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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/toggle/render_toggle.h"
17 
18 #include "base/log/log.h"
19 #include "core/components/common/properties/alignment.h"
20 #include "core/event/ace_event_helper.h"
21 
22 namespace OHOS::Ace {
23 namespace {
24 
25 constexpr int32_t HOVER_ANIMATION_DURATION = 250;
26 
27 } // namespace
28 
RenderToggle()29 RenderToggle::RenderToggle()
30 {
31     clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
32     clickRecognizer_->SetOnClick([wp = AceType::WeakClaim(this)](const ClickInfo&) {
33         auto toggle = wp.Upgrade();
34         if (toggle) {
35             toggle->HandleClickEvent();
36         }
37     });
38     auto wp = AceType::WeakClaim(this);
39     touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
40     touchRecognizer_->SetOnTouchDown([wp](const TouchEventInfo&) {
41         auto toggle = wp.Upgrade();
42         if (toggle) {
43             toggle->HandleTouchEvent(true);
44         }
45     });
46     touchRecognizer_->SetOnTouchUp([wp](const TouchEventInfo&) {
47         auto toggle = wp.Upgrade();
48         if (toggle) {
49             toggle->HandleTouchEvent(false);
50         }
51     });
52     touchRecognizer_->SetOnTouchMove([wp](const TouchEventInfo& info) {
53         auto toggle = wp.Upgrade();
54         if (toggle) {
55             toggle->HandleMoveEvent(info);
56         }
57     });
58 }
59 
HandleClickEvent()60 void RenderToggle::HandleClickEvent()
61 {
62     if (disabled_) {
63         return;
64     }
65     if (onClick_) {
66         onClick_();
67     }
68     auto checkValue = toggleComponent_->GetCheckedState();
69     toggleComponent_->SetCheckedState(!checkValue);
70     MarkNeedRender();
71     std::string checked = (!checkValue) ? "true" : "false";
72     std::string result = std::string(R"("change",{"checked":)").append(checked.append("},null"));
73     if (onChange_) {
74         onChange_(result);
75     }
76     if (onChangeToggle_) {
77         onChangeToggle_(!checkValue);
78     }
79     auto accessibilityNode = accessibilityNode_.Upgrade();
80     if (accessibilityNode) {
81         accessibilityNode->SetCheckedState(!checkValue);
82     }
83 }
84 
HandleTouchEvent(bool touched)85 void RenderToggle::HandleTouchEvent(bool touched)
86 {
87     if (disabled_) {
88         return;
89     }
90     isPressed_ = touched;
91     if (isPressed_) {
92         isMoveEventValid_ = true;
93     }
94     if (isMoveEventValid_) {
95         MarkNeedRender();
96     }
97 }
98 
HandleMoveEvent(const TouchEventInfo & info)99 void RenderToggle::HandleMoveEvent(const TouchEventInfo& info)
100 {
101     if (disabled_) {
102         return;
103     }
104     if (!isMoveEventValid_ || info.GetTouches().empty()) {
105         return;
106     }
107     const auto& locationInfo = info.GetTouches().front();
108     double moveX = locationInfo.GetLocalLocation().GetX();
109     double moveY = locationInfo.GetLocalLocation().GetY();
110     if ((LessNotEqual(moveX, 0.0) || GreatNotEqual(moveX, toggleSize_.Width()))
111         || (LessNotEqual(moveY, 0.0) || GreatNotEqual(moveY, toggleSize_.Height()))) {
112         isPressed_ = false;
113         isMoveEventValid_ = false;
114         MarkNeedRender();
115     }
116 }
117 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)118 void RenderToggle::OnTouchTestHit(
119     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
120 {
121     if ((!touchRecognizer_) || (!clickRecognizer_)) {
122         return;
123     }
124     touchRecognizer_->SetCoordinateOffset(coordinateOffset);
125     clickRecognizer_->SetCoordinateOffset(coordinateOffset);
126     result.emplace_back(touchRecognizer_);
127     result.emplace_back(clickRecognizer_);
128 }
129 
UpdateFocusAnimation()130 void RenderToggle::UpdateFocusAnimation()
131 {
132     auto context = context_.Upgrade();
133     if (!context) {
134         return;
135     }
136     double radius = toggleSize_.Height() / 2.0;
137     context->ShowFocusAnimation(RRect::MakeRRect(Rect(Offset(0, 0), toggleSize_), Radius(radius)),
138         Color(), GetGlobalOffset());
139     context->ShowShadow(RRect::MakeRRect(Rect(Offset(0, 0), toggleSize_), Radius(radius)), GetGlobalOffset());
140 }
141 
OnMouseHoverEnterTest()142 void RenderToggle::OnMouseHoverEnterTest()
143 {
144     ResetController(hoverControllerExit_);
145     if (!hoverControllerEnter_) {
146         hoverControllerEnter_ = CREATE_ANIMATOR(context_);
147     }
148     scaleAnimationEnter_ = AceType::MakeRefPtr<KeyframeAnimation<float>>();
149     CreateFloatAnimation(scaleAnimationEnter_, 1.0, 1.05);
150     hoverControllerEnter_->AddInterpolator(scaleAnimationEnter_);
151     hoverControllerEnter_->SetDuration(HOVER_ANIMATION_DURATION);
152     hoverControllerEnter_->Play();
153     hoverControllerEnter_->SetFillMode(FillMode::FORWARDS);
154 }
155 
OnMouseHoverExitTest()156 void RenderToggle::OnMouseHoverExitTest()
157 {
158     ResetController(hoverControllerEnter_);
159     if (!hoverControllerExit_) {
160         hoverControllerExit_ = CREATE_ANIMATOR(context_);
161     }
162     scaleAnimationExit_ = AceType::MakeRefPtr<KeyframeAnimation<float>>();
163     auto begin = scale_;
164     CreateFloatAnimation(scaleAnimationExit_, begin, 1.0);
165     hoverControllerExit_->AddInterpolator(scaleAnimationExit_);
166     hoverControllerExit_->SetDuration(HOVER_ANIMATION_DURATION);
167     hoverControllerExit_->Play();
168     hoverControllerExit_->SetFillMode(FillMode::FORWARDS);
169 }
170 
OnMouseClickDownAnimation()171 void RenderToggle::OnMouseClickDownAnimation()
172 {
173     ResetController(clickControllerUp_);
174     if (!clickControllerDown_) {
175         clickControllerDown_ = CREATE_ANIMATOR(context_);
176     }
177     scaleAnimationDown_ = AceType::MakeRefPtr<KeyframeAnimation<float>>();
178     auto begin = scale_;
179     CreateFloatAnimation(scaleAnimationDown_, begin, 1.0);
180     clickControllerDown_->AddInterpolator(scaleAnimationDown_);
181     clickControllerDown_->SetDuration(HOVER_ANIMATION_DURATION);
182     clickControllerDown_->Play();
183     clickControllerDown_->SetFillMode(FillMode::FORWARDS);
184 }
185 
OnMouseClickUpAnimation()186 void RenderToggle::OnMouseClickUpAnimation()
187 {
188     ResetController(clickControllerDown_);
189     if (!clickControllerUp_) {
190         clickControllerUp_ = CREATE_ANIMATOR(context_);
191     }
192     scaleAnimationUp_ = AceType::MakeRefPtr<KeyframeAnimation<float>>();
193     auto begin = scale_;
194     CreateFloatAnimation(scaleAnimationUp_, begin, 1.05);
195     clickControllerUp_->AddInterpolator(scaleAnimationUp_);
196     clickControllerUp_->SetDuration(HOVER_ANIMATION_DURATION);
197     clickControllerUp_->Play();
198     clickControllerUp_->SetFillMode(FillMode::FORWARDS);
199 }
200 
CreateFloatAnimation(RefPtr<KeyframeAnimation<float>> & floatAnimation,float beginValue,float endValue)201 void RenderToggle::CreateFloatAnimation(RefPtr<KeyframeAnimation<float>>& floatAnimation, float beginValue,
202     float endValue)
203 {
204     if (!floatAnimation) {
205         return;
206     }
207     auto keyframeBegin = AceType::MakeRefPtr<Keyframe<float>>(0.0, beginValue);
208     auto keyframeEnd = AceType::MakeRefPtr<Keyframe<float>>(1.0, endValue);
209     floatAnimation->AddKeyframe(keyframeBegin);
210     floatAnimation->AddKeyframe(keyframeEnd);
211     floatAnimation->AddListener([weakToggle = AceType::WeakClaim(this)](float value) {
212         auto toggle = weakToggle.Upgrade();
213         if (toggle) {
214             toggle->scale_ = value;
215             toggle->MarkNeedRender();
216         }
217     });
218 }
219 
ResetController(RefPtr<Animator> & controller)220 void RenderToggle::ResetController(RefPtr<Animator>& controller)
221 {
222     if (controller) {
223         if (!controller->IsStopped()) {
224             controller->Stop();
225         }
226         controller->ClearInterpolators();
227     }
228 }
229 
Update(const RefPtr<Component> & component)230 void RenderToggle::Update(const RefPtr<Component>& component)
231 {
232     toggleComponent_ = AceType::DynamicCast<ToggleComponent>(component);
233     widthDefined_ = !NearZero(toggleComponent_->GetWidth().Value());
234     heightDefined_ = !NearZero(toggleComponent_->GetHeight().Value());
235     onClick_ = AceAsyncEvent<void()>::Create(toggleComponent_->GetClickEvent(), context_);
236     auto catchMode = toggleComponent_->GetClickEvent().IsEmpty() || toggleComponent_->GetClickEvent().GetCatchMode();
237     static const int32_t bubbleModeVersion = 6;
238     auto pipeline = context_.Upgrade();
239     if (!catchMode) {
240         if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
241             catchMode = false;
242         } else {
243             catchMode = true;
244         }
245     }
246     clickRecognizer_->SetUseCatchMode(catchMode);
247     onChange_ = AceAsyncEvent<void(const std::string)>::Create(toggleComponent_->GetChangeEvent(), context_);
248     if (toggleComponent_->GetOnChange()) {
249         onChangeToggle_ = *toggleComponent_->GetOnChange();
250     }
251     disabled_ = toggleComponent_->IsDisabled();
252     ApplyRestoreInfo();
253     SetAccessibilityClickImpl();
254     MarkNeedLayout();
255 }
256 
PerformLayout()257 void RenderToggle::PerformLayout()
258 {
259     toggleSize_ = Size(NormalizeToPx(toggleComponent_->GetWidth()), NormalizeToPx(toggleComponent_->GetHeight()));
260     Measure();
261     LayoutParam innerLayoutParam;
262     double maxWidth = widthDefined_ ? toggleSize_.Width() : GetLayoutParam().GetMaxSize().Width();
263     innerLayoutParam.SetMaxSize(Size(maxWidth, toggleSize_.Height()));
264     RefPtr<RenderNode> child;
265     Size childrenSize;
266     if (!GetChildren().empty()) {
267         child = GetChildren().front();
268         if (child) {
269             child->Layout(innerLayoutParam);
270             childrenSize.SetWidth(child->GetLayoutSize().Width());
271             childrenSize.SetHeight(child->GetLayoutSize().Height());
272         }
273     }
274     double width = widthDefined_ ? toggleSize_.Width() : childrenSize.Width();
275     double height = toggleSize_.Height();
276     if (!heightDefined_ && toggleComponent_->GetFontDefinedState()) {
277         height = childrenSize.Height();
278     }
279     Size layoutSize = Size(width, height);
280     layoutSize = GetLayoutParam().Constrain(layoutSize);
281     SetLayoutSize(layoutSize);
282     toggleSize_ = GetLayoutSize();
283     if (child) {
284         child->SetPosition(Alignment::GetAlignPosition(GetLayoutSize(), child->GetLayoutSize(), Alignment::CENTER));
285     }
286 }
287 
SetAccessibilityClickImpl()288 void RenderToggle::SetAccessibilityClickImpl()
289 {
290     auto accessibilityNode = accessibilityNode_.Upgrade();
291     if (accessibilityNode) {
292         auto weakPtr = AceType::WeakClaim(AceType::RawPtr(clickRecognizer_));
293         accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
294         accessibilityNode->SetClickableState(true);
295         accessibilityNode->SetCheckableState(true);
296         accessibilityNode->SetActionClickImpl([weakPtr]() {
297             auto click = weakPtr.Upgrade();
298             if (click) {
299                 click->OnAccepted();
300             }
301         });
302     }
303 }
304 
ProvideRestoreInfo()305 std::string RenderToggle::ProvideRestoreInfo()
306 {
307     auto jsonObj = JsonUtil::Create(true);
308     jsonObj->Put("checked", toggleComponent_->GetCheckedState());
309     jsonObj->Put("isPressed", isPressed_);
310 
311     return jsonObj->ToString();
312 }
313 
ApplyRestoreInfo()314 void RenderToggle::ApplyRestoreInfo()
315 {
316     if (GetRestoreInfo().empty()) {
317         return;
318     }
319     auto info = JsonUtil::ParseJsonString(GetRestoreInfo());
320     if (!info->IsValid() || !info->IsObject()) {
321         LOGW("RenderRadio:: restore info is invalid");
322         return;
323     }
324 
325     auto jsonChecked = info->GetValue("checked");
326     auto jsonIsPressed = info->GetValue("isPressed");
327 
328     toggleComponent_->SetCheckedState(jsonChecked->GetBool());
329     isPressed_ = jsonIsPressed->GetBool();
330     SetRestoreInfo("");
331 }
332 
333 } // namespace OHOS::Ace
334