• 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/checkable/render_checkable.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/components/common/properties/alignment.h"
20 #include "core/components/common/properties/color.h"
21 #include "core/event/ace_event_helper.h"
22 
23 namespace OHOS::Ace {
24 
Update(const RefPtr<Component> & component)25 void RenderCheckable::Update(const RefPtr<Component>& component)
26 {
27     auto checkable = AceType::DynamicCast<CheckableComponent>(component);
28     if (!checkable) {
29         LOGW("component is null");
30         return;
31     }
32     auto context = context_.Upgrade();
33     if (!context) {
34         return;
35     }
36     isDeclarative_ = context->GetIsDeclarative();
37     pointColor_ = checkable->GetPointColor().GetValue();
38     activeColor_ = checkable->GetActiveColor().GetValue();
39     pointColorInspector_ = checkable->GetPointColor();
40     activeColorInspector_ = checkable->GetActiveColor();
41     inactiveColor_ = checkable->GetInactiveColor().GetValue();
42     inactivePointColor_ = checkable->GetInactivePointColor().GetValue();
43     focusColor_ = checkable->GetFocusColor().GetValue();
44     shadowColor_ = checkable->GetShadowColor().GetValue();
45     shadowWidth_ = checkable->GetShadowWidth();
46     defaultWidth_ = checkable->GetDefaultWidth();
47     defaultHeight_ = checkable->GetDefaultHeight();
48     aspectRatio_ = checkable->GetAspectRatio();
49     backgroundSolid_ = checkable->IsBackgroundSolid();
50     hotZoneHorizontalPadding_ = checkable->GetHotZoneHorizontalPadding();
51     hotZoneVerticalPadding_ = checkable->GetHotZoneVerticalPadding();
52     if (isDeclarative_) {
53         disabled_ = checkable->IsDisabledStatus();
54     } else {
55         disabled_ = checkable->IsDisabled();
56     }
57     hoverAnimationType_ = checkable->GetMouseAnimationType();
58     auto clickId = checkable->GetClickEvent();
59     auto catchMode = true;
60     if (!clickId.IsEmpty()) {
61         catchMode = clickId.GetCatchMode();
62     }
63     clickEvent_ = AceAsyncEvent<void()>::Create(clickId, context_);
64     changeEvent_ = AceAsyncEvent<void(const std::string)>::Create(checkable->GetChangeEvent(), context_);
65     valueChangeEvent_ = checkable->GetChangeEvent().GetUiStrFunction();
66     domChangeEvent_ = AceAsyncEvent<void(const std::string&)>::Create(checkable->GetDomChangeEvent(), context_);
67     needFocus_ = checkable->GetNeedFocus();
68     if (checkable->GetOnChange()) {
69         onChange_ = *checkable->GetOnChange();
70     } else {
71         onChange_ = nullptr;
72     }
73     if (checkable->GetOnClick()) {
74         onClick_ = *checkable->GetOnClick();
75     }
76     InitTouchRecognizer();
77     InitClickRecognizer(catchMode);
78     AddAccessibilityAction();
79     MarkNeedLayout();
80 }
81 
AddAccessibilityAction()82 void RenderCheckable::AddAccessibilityAction()
83 {
84     auto accessibilityNode = GetAccessibilityNode().Upgrade();
85     if (!accessibilityNode) {
86         return;
87     }
88     accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
89     accessibilityNode->SetActionClickImpl([weakPtr = AceType::WeakClaim(this)]() {
90         auto renderCheckable = weakPtr.Upgrade();
91         if (renderCheckable) {
92             renderCheckable->HandleClick();
93         }
94     });
95 }
96 
InitSize()97 void RenderCheckable::InitSize()
98 {
99     // Get parent(box)'s layoutParam.GetMaxSize as self size.
100     width_ = GetLayoutParam().GetMaxSize().Width();
101     if (NearEqual(Size::INFINITE_SIZE, width_)) {
102         width_ = NormalizeToPx(defaultWidth_);
103     }
104     height_ = GetLayoutParam().GetMaxSize().Height();
105     if (NearEqual(Size::INFINITE_SIZE, height_)) {
106         height_ = NormalizeToPx(defaultHeight_);
107     }
108 }
109 
CalculateSize()110 void RenderCheckable::CalculateSize()
111 {
112     // Fit hot zone to real size.
113     double hotZoneHorizontalPadding = NormalizePercentToPx(hotZoneHorizontalPadding_, false);
114     double hotZoneVerticalPadding = NormalizePercentToPx(hotZoneVerticalPadding_, true);
115     auto defaultWidth = NormalizeToPx(defaultWidth_);
116     auto defaultHeight = NormalizeToPx(defaultHeight_);
117     if ((width_ < defaultWidth) && (!NearZero(defaultWidth))) {
118         hotZoneHorizontalPadding *= width_ / defaultWidth;
119     }
120     if ((height_ < defaultHeight) && (!NearZero(defaultHeight))) {
121         hotZoneVerticalPadding *= height_ / defaultHeight;
122     }
123 
124     // Calculate draw size with hot zone and ratio of (width / height).
125     double width = width_ - 2 * hotZoneHorizontalPadding;
126     width = width > 0 ? width : 0;
127     double height = height_ - 2 * hotZoneVerticalPadding;
128     height = height > 0 ? height : 0;
129     drawSize_ = Size(width, height);
130     ApplyAspectRatio(drawSize_);
131     paintPosition_ = Alignment::GetAlignPosition(Size(width_, height_), drawSize_, Alignment::CENTER);
132 }
133 
InitTouchRecognizer()134 void RenderCheckable::InitTouchRecognizer()
135 {
136     auto wp = AceType::WeakClaim(this);
137     touchRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
138     touchRecognizer_->SetOnTouchDown([wp](const TouchEventInfo&) {
139         auto renderCheckable = wp.Upgrade();
140         if (renderCheckable) {
141             renderCheckable->isTouch_ = true;
142             renderCheckable->MarkNeedLayout();
143         }
144     });
145     touchRecognizer_->SetOnTouchUp([wp](const TouchEventInfo&) {
146         auto renderCheckable = wp.Upgrade();
147         if (renderCheckable) {
148             renderCheckable->isTouch_ = false;
149             renderCheckable->MarkNeedLayout();
150         }
151     });
152     touchRecognizer_->SetOnTouchCancel([wp](const TouchEventInfo&) {
153         auto renderCheckable = wp.Upgrade();
154         if (renderCheckable) {
155             renderCheckable->isTouch_ = false;
156             renderCheckable->MarkNeedLayout();
157         }
158     });
159     touchRecognizer_->SetOnTouchMove([wp](const TouchEventInfo& info) {
160         auto renderCheckable = wp.Upgrade();
161         if (renderCheckable) {
162             if (info.GetTouches().empty()) {
163                 return;
164             }
165             const auto& locationInfo = info.GetTouches().front();
166             double moveDeltaX = locationInfo.GetLocalLocation().GetX();
167             double moveDeltaY = locationInfo.GetLocalLocation().GetY();
168             if ((moveDeltaX < 0 || moveDeltaX > renderCheckable->width_)
169                 || (moveDeltaY < 0 || moveDeltaY > renderCheckable->height_)) {
170                 renderCheckable->isTouch_ = false;
171                 renderCheckable->MarkNeedLayout();
172             }
173         }
174     });
175 }
176 
InitClickRecognizer(bool catchMode)177 void RenderCheckable::InitClickRecognizer(bool catchMode)
178 {
179     if (!disabled_ && !clickRecognizer_) {
180         clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
181         clickRecognizer_->SetOnClick([weak = AceType::WeakClaim(this)](const ClickInfo& info) {
182             auto renderCheckable = weak.Upgrade();
183             if (renderCheckable) {
184                 renderCheckable->HandleClick();
185             }
186         });
187         static const int32_t bubbleModeVersion = 6;
188         auto pipeline = context_.Upgrade();
189         if (!catchMode && pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
190             clickRecognizer_->SetUseCatchMode(false);
191         } else {
192             clickRecognizer_->SetUseCatchMode(true);
193         }
194     } else if (disabled_ && clickRecognizer_) {
195         clickRecognizer_ = nullptr;
196     }
197 }
198 
ApplyAspectRatio(Size & drawSize) const199 void RenderCheckable::ApplyAspectRatio(Size& drawSize) const
200 {
201     // Protect from drawSize.Height() being zero.
202     double drawAreaAspectRatio = Size::INFINITE_SIZE;
203     if (!drawSize.IsValid()) {
204         return;
205     }
206     drawAreaAspectRatio = drawSize.Width() / drawSize.Height();
207     if (drawAreaAspectRatio > aspectRatio_) {
208         drawSize.SetWidth(drawSize.Height() * aspectRatio_);
209     } else if (!NearZero(aspectRatio_)) {
210         drawSize.SetHeight(drawSize.Width() / aspectRatio_);
211     }
212 }
213 
PerformLayout()214 void RenderCheckable::PerformLayout()
215 {
216     InitSize();
217     CalculateSize();
218     Size constrainSize = GetLayoutParam().Constrain(Size(width_, height_));
219     SetLayoutSize(constrainSize);
220 }
221 
OnStatusChanged(RenderStatus renderStatus)222 void RenderCheckable::OnStatusChanged(RenderStatus renderStatus)
223 {
224     onFocus_ = renderStatus == RenderStatus::FOCUS;
225     auto context = context_.Upgrade();
226     if (context && context->GetRenderFocusAnimation() && (renderStatus == RenderStatus::BLUR)) {
227         context->GetRenderFocusAnimation()->CancelFocusAnimation();
228     }
229     UpdateUIStatus();
230     MarkNeedRender();
231 }
232 
HandleClick()233 void RenderCheckable::HandleClick()
234 {
235     auto result = UpdateChangedResult();
236     if (!result.empty()) {
237         MarkNeedRender();
238         auto resultForChangeEvent = std::string(R"("change",{"checked":)").append(result.append("},null"));
239         OnHandleChangedResult(resultForChangeEvent);
240         if (changeEvent_) {
241             changeEvent_(resultForChangeEvent);
242         }
243         if (valueChangeEvent_) {
244             valueChangeEvent_(result);
245         }
246     }
247     if (onChange_) {
248         onChange_(checked_);
249     }
250 
251     if (clickEvent_) {
252         clickEvent_();
253     }
254 }
255 
OnHandleChangedResult(const std::string & result)256 void RenderCheckable::OnHandleChangedResult(const std::string& result)
257 {
258     if (domChangeEvent_) {
259         domChangeEvent_(result);
260     }
261 }
262 
UpdateChangedResult()263 std::string RenderCheckable::UpdateChangedResult()
264 {
265     LOGD("handle click");
266     checked_ = !checked_;
267     UpdateUIStatus();
268 
269     return checked_ ? "true" : "false";
270 }
271 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)272 void RenderCheckable::OnTouchTestHit(
273     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
274 {
275     LOGD("on touch test hit");
276     if (dragRecognizer_) {
277         dragRecognizer_->SetCoordinateOffset(coordinateOffset);
278         result.emplace_back(dragRecognizer_);
279     }
280     if (clickRecognizer_) {
281         clickRecognizer_->SetCoordinateOffset(coordinateOffset);
282         result.emplace_back(clickRecognizer_);
283     }
284     if (touchRecognizer_) {
285         touchRecognizer_->SetCoordinateOffset(coordinateOffset);
286         result.emplace_back(touchRecognizer_);
287     }
288 }
289 
AnimateMouseHoverEnter()290 void RenderCheckable::AnimateMouseHoverEnter()
291 {
292     isHover_ = true;
293     MarkNeedLayout();
294 }
295 
AnimateMouseHoverExit()296 void RenderCheckable::AnimateMouseHoverExit()
297 {
298     isHover_ = false;
299     MarkNeedLayout();
300 }
301 
OnMouseHoverEnterTest()302 void RenderCheckable::OnMouseHoverEnterTest()
303 {
304     MarkNeedRender();
305 }
306 
OnMouseHoverExitTest()307 void RenderCheckable::OnMouseHoverExitTest()
308 {
309     MarkNeedRender();
310 }
311 
RequestFocusBorder(const Offset & focusOffset,const Size & focusSize,double borderRadius)312 void RenderCheckable::RequestFocusBorder(const Offset& focusOffset, const Size& focusSize, double borderRadius)
313 {
314     auto context = context_.Upgrade();
315     if (!context) {
316         LOGE("Pipeline context upgrade fail!");
317         return;
318     }
319     if (!context->GetRenderFocusAnimation()) {
320         LOGE("focusAnimation is null!");
321         EventReport::SendRenderException(RenderExcepType::RENDER_ANIMATION_ERR);
322         return;
323     }
324     context->ShowFocusAnimation(RRect::MakeRRect(Rect(Offset(), focusSize), borderRadius, borderRadius), Color::BLUE,
325         focusOffset + GetGlobalOffset());
326 }
327 
328 } // namespace OHOS::Ace
329