1 /*
2  * Copyright (c) 2021 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/drag_bar/render_drag_bar.h"
17 
18 #include "core/components/drag_bar/drag_bar_component.h"
19 
20 namespace OHOS::Ace {
21 namespace {
22 
23 constexpr Dimension DRAG_ICON_WIDTH = 64.0_vp;
24 constexpr Dimension DRAG_ICON_HEIGHT = 24.0_vp;
25 constexpr Dimension HOT_REGION_WIDTH = 64.0_vp;
26 constexpr Dimension HOT_REGION_HEIGHT = 24.0_vp;
27 constexpr Dimension PAINT_WIDTH = 56.0_vp;
28 constexpr Dimension PAINT_HEIGHT = 8.0_vp;
29 constexpr Dimension MAX_DRAG_X = 10.0_vp;
30 constexpr Dimension MAX_DRAG_Y = 4.0_vp;
31 constexpr double DRAG_X_RATIO = 0.4;
32 constexpr double DRAG_Y_RATIO = 0.2;
33 constexpr double SCALE_ICON = 1.15;
34 constexpr double SCALE_WIDTH = 1.5 / SCALE_ICON;
35 constexpr int32_t DOWN_DURATION = 150;
36 constexpr int32_t RESET_DURATION = 250;
37 constexpr int32_t STYLE_DURATION = 200;
38 
39 // For DragBar Shrink State Point.
40 const Offset POINT_L_SHRINK = Offset(17.0, 15.0); // Left Point position.
41 const Offset POINT_C_SHRINK = Offset(32.0, 9.0);  // Center Point position.
42 const Offset POINT_R_SHRINK = Offset(47.0, 15.0); // Right Point position.
43 
44 // For DragBar Initial State Point.
45 const Offset POINT_L_INITIAL = Offset(18.0, 12.0); // Left Point position.
46 const Offset POINT_C_INITIAL = Offset(32.0, 12.0); // Center Point position.
47 const Offset POINT_R_INITIAL = Offset(46.0, 12.0); // Right Point position.
48 
49 // For DragBar Expand State Point.
50 const Offset POINT_L_EXPAND = Offset(17.0, 9.0);  // Left Point position.
51 const Offset POINT_C_EXPAND = Offset(32.0, 15.0); // Center Point position.
52 const Offset POINT_R_EXPAND = Offset(47.0, 9.0);  // Right Point position.
53 
54 const Size DRAG_BAR_SIZE = Size(64.0, 24.0);
55 
56 constexpr double OPACITY_DEFAULT = 0.2;
57 
58 } // namespace
59 
Update(const RefPtr<Component> & component)60 void RenderDragBar::Update(const RefPtr<Component>& component)
61 {
62     if (!animator_) {
63         animator_ = CREATE_ANIMATOR(GetContext());
64     }
65     if (!barTouchController_) {
66         barTouchController_ = CREATE_ANIMATOR(GetContext());
67         auto touchAnimation = AceType::MakeRefPtr<CurveAnimation<double>>(1.0, SCALE_ICON, Curves::SHARP);
68         touchAnimation->AddListener([weak = AceType::WeakClaim(this)](double value) {
69             auto dragBar = weak.Upgrade();
70             if (dragBar) {
71                 dragBar->scaleIcon_ = value;
72                 dragBar->scaleWidth_ = 1.0 + (value - 1.0) / (SCALE_ICON - 1.0) * (SCALE_WIDTH - 1.0);
73                 dragBar->MarkNeedRender();
74             }
75         });
76         barTouchController_->ClearInterpolators();
77         barTouchController_->AddInterpolator(touchAnimation);
78         barTouchController_->SetFillMode(FillMode::FORWARDS);
79     }
80     if (!barRangeController_) {
81         barRangeController_ = CREATE_ANIMATOR(GetContext());
82         barRangeController_->SetFillMode(FillMode::FORWARDS);
83         barRangeController_->SetDuration(RESET_DURATION);
84     }
85     if (!barStyleController_) {
86         barStyleController_ = CREATE_ANIMATOR(GetContext());
87         barStyleController_->SetFillMode(FillMode::FORWARDS);
88         barStyleController_->SetDuration(STYLE_DURATION);
89     }
90     hotRegionHeight_ = HOT_REGION_HEIGHT;
91     dragRangeX_ = NormalizeToPx(MAX_DRAG_X);
92     dragRangeY_ = NormalizeToPx(MAX_DRAG_Y);
93     alpha_ = std::floor(UINT8_MAX * OPACITY_DEFAULT);
94     auto dragBar = AceType::DynamicCast<DragBarComponent>(component);
95     if (dragBar) {
96         showMode_ = dragBar->GetPanelMode();
97         hasDragBar_ = dragBar->HasDragBar();
98     }
99     InitializeRecognizer();
100     UpdateDrawPoint();
101     MarkNeedLayout();
102 }
103 
PerformLayout()104 void RenderDragBar::PerformLayout()
105 {
106     Size dragBarSize;
107     if (hasDragBar_) {
108         dragBarSize = Size(NormalizeToPx(HOT_REGION_WIDTH), NormalizeToPx(hotRegionHeight_));
109     }
110     if (fullScreenMode_) {
111         dragBarSize = Size(GetLayoutParam().GetMaxSize().Width(), NormalizeToPx(hotRegionHeight_));
112     }
113     auto realSize = Size(NormalizeToPx(DRAG_ICON_WIDTH), NormalizeToPx(DRAG_ICON_HEIGHT));
114     iconOffset_ = Alignment::GetAlignPosition(dragBarSize, realSize, Alignment::CENTER);
115     scaleX_ = realSize.Width() / DRAG_BAR_SIZE.Width();
116     scaleY_ = realSize.Height() / DRAG_BAR_SIZE.Height();
117     SetLayoutSize(dragBarSize);
118     imgTouchRegion_ = GetPaintRect();
119 }
120 
ShowArrow(bool show)121 void RenderDragBar::ShowArrow(bool show)
122 {
123     PanelMode mode = PanelMode::HALF;
124     if (show) {
125         mode = PanelMode::FULL;
126     } else {
127         mode = PanelMode::HALF;
128     }
129     ShowInPanelMode(mode);
130 }
131 
ShowInPanelMode(PanelMode mode)132 void RenderDragBar::ShowInPanelMode(PanelMode mode)
133 {
134     if (showMode_ == mode) {
135         return;
136     }
137     showMode_ = mode;
138     UpdateDrawPoint();
139     MarkNeedRender();
140 }
141 
UpdateDrawPoint()142 void RenderDragBar::UpdateDrawPoint()
143 {
144     Offset leftPoint, centerPoint, rightPoint;
145     switch (showMode_) {
146         case PanelMode::MINI:
147             leftPoint = POINT_L_SHRINK;
148             centerPoint = POINT_C_SHRINK;
149             rightPoint = POINT_R_SHRINK;
150             break;
151         case PanelMode::HALF:
152             leftPoint = POINT_L_INITIAL;
153             centerPoint = POINT_C_INITIAL;
154             rightPoint = POINT_R_INITIAL;
155             break;
156         case PanelMode::FULL:
157             leftPoint = POINT_L_EXPAND;
158             centerPoint = POINT_C_EXPAND;
159             rightPoint = POINT_R_EXPAND;
160             break;
161         default:
162             LOGE("Unsupported Show Mode:%{public}d", showMode_);
163             return;
164     }
165     if (barLeftPoint_ == Offset()) {
166         // No need to do animation when first time to display.
167         barLeftPoint_ = leftPoint;
168         barCenterPoint_ = centerPoint;
169         barRightPoint_ = rightPoint;
170     } else {
171         DoStyleAnimation(leftPoint, centerPoint, rightPoint);
172     }
173 }
174 
DoStyleAnimation(const Offset & left,const Offset & center,const Offset & right)175 void RenderDragBar::DoStyleAnimation(const Offset& left, const Offset& center, const Offset& right)
176 {
177     if (barStyleController_->IsRunning()) {
178         barStyleController_->Stop();
179     }
180     auto leftAnimation = AceType::MakeRefPtr<CurveAnimation<Offset>>(barLeftPoint_, left, Curves::SHARP);
181     leftAnimation->AddListener([weak = AceType::WeakClaim(this)](const Offset& value) {
182         auto dragBar = weak.Upgrade();
183         if (dragBar) {
184             dragBar->barLeftPoint_ = value;
185             dragBar->MarkNeedRender();
186         }
187     });
188     auto centerAnimation = AceType::MakeRefPtr<CurveAnimation<Offset>>(barCenterPoint_, center, Curves::SHARP);
189     centerAnimation->AddListener([weak = AceType::WeakClaim(this)](const Offset& value) {
190         auto dragBar = weak.Upgrade();
191         if (dragBar) {
192             dragBar->barCenterPoint_ = value;
193         }
194     });
195     auto rightAnimation = AceType::MakeRefPtr<CurveAnimation<Offset>>(barRightPoint_, right, Curves::SHARP);
196     rightAnimation->AddListener([weak = AceType::WeakClaim(this)](const Offset& value) {
197         auto dragBar = weak.Upgrade();
198         if (dragBar) {
199             dragBar->barRightPoint_ = value;
200         }
201     });
202     barStyleController_->ClearInterpolators();
203     barStyleController_->AddInterpolator(leftAnimation);
204     barStyleController_->AddInterpolator(centerAnimation);
205     barStyleController_->AddInterpolator(rightAnimation);
206     barStyleController_->Play();
207 }
208 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)209 void RenderDragBar::OnTouchTestHit(
210     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
211 {
212     if (fullScreenMode_) {
213         return;
214     }
215     if (clickDetector_) {
216         clickDetector_->SetCoordinateOffset(coordinateOffset);
217         result.emplace_back(clickDetector_);
218     }
219     if (touchDetector_) {
220         touchDetector_->SetCoordinateOffset(coordinateOffset);
221         result.emplace_back(touchDetector_);
222     }
223 }
224 
InitializeRecognizer()225 void RenderDragBar::InitializeRecognizer()
226 {
227     if (!clickDetector_) {
228         clickDetector_ = AceType::MakeRefPtr<ClickRecognizer>();
229         clickDetector_->SetOnClick([weak = WeakClaim(this)](const ClickInfo& info) {
230             auto dragBar = weak.Upgrade();
231             if (dragBar) {
232                 dragBar->HandleClick(info.GetLocalLocation());
233             }
234         });
235     }
236     if (!touchDetector_) {
237         touchDetector_ = AceType::MakeRefPtr<RawRecognizer>();
238         touchDetector_->SetOnTouchDown([weak = AceType::WeakClaim(this)](const TouchEventInfo& info) {
239             auto dragBar = weak.Upgrade();
240             if (dragBar && !info.GetTouches().empty()) {
241                 dragBar->HandleTouchDown(info.GetTouches().front().GetGlobalLocation());
242             }
243         });
244         touchDetector_->SetOnTouchMove([weakDrag = AceType::WeakClaim(this)](const TouchEventInfo& info) {
245             auto dragBar = weakDrag.Upgrade();
246             if (dragBar && !info.GetTouches().empty()) {
247                 dragBar->HandleTouchMove(info.GetTouches().front().GetGlobalLocation());
248             }
249         });
250         touchDetector_->SetOnTouchUp([weakDrag = AceType::WeakClaim(this)](const TouchEventInfo& info) {
251             auto dragBar = weakDrag.Upgrade();
252             if (dragBar) {
253                 dragBar->HandleTouchUp();
254             }
255         });
256         touchDetector_->SetOnTouchCancel([weakDrag = AceType::WeakClaim(this)](const TouchEventInfo& info) {
257             auto dragBar = weakDrag.Upgrade();
258             if (dragBar) {
259                 dragBar->HandleTouchUp();
260             }
261         });
262     }
263 }
264 
HandleClick(const Offset & clickPosition)265 void RenderDragBar::HandleClick(const Offset& clickPosition)
266 {
267     if (!clickArrowCallback_) {
268         return;
269     }
270     clickArrowCallback_();
271 }
272 
HandleTouchDown(const Offset & downPoint)273 void RenderDragBar::HandleTouchDown(const Offset& downPoint)
274 {
275     // Display the click-to-magnify effect.
276     downPoint_ = downPoint;
277     barTouchController_->SetDuration(DOWN_DURATION);
278     barTouchController_->Forward();
279 }
280 
HandleTouchMove(const Offset & movePoint)281 void RenderDragBar::HandleTouchMove(const Offset& movePoint)
282 {
283     // Display the dragging offset effect.
284     Offset distance = movePoint - downPoint_;
285     Offset dragOffset;
286     dragOffset.SetX(std::clamp(distance.GetX() * DRAG_X_RATIO, -dragRangeX_, dragRangeX_));
287     dragOffset.SetY(std::clamp(distance.GetY() * DRAG_Y_RATIO, -dragRangeY_, dragRangeY_));
288     if (dragOffset_ != dragOffset) {
289         dragOffset_ = dragOffset;
290         MarkNeedRender();
291     }
292 }
293 
HandleTouchUp()294 void RenderDragBar::HandleTouchUp()
295 {
296     // Restore the click-to-magnify effect.
297     barTouchController_->SetDuration(RESET_DURATION);
298     barTouchController_->Backward();
299 
300     // Restore the dragging offset effect.
301     if (dragOffset_ == Offset()) {
302         return; // No need to back to center with animation.
303     }
304     auto dragAnimation = AceType::MakeRefPtr<CurveAnimation<Offset>>(dragOffset_, Offset(), Curves::SHARP);
305     dragAnimation->AddListener([weak = AceType::WeakClaim(this)](Offset value) {
306         auto dragBar = weak.Upgrade();
307         if (dragBar) {
308             dragBar->dragOffset_ = value;
309             dragBar->MarkNeedRender();
310         }
311     });
312     barRangeController_->ClearInterpolators();
313     barRangeController_->AddInterpolator(dragAnimation);
314     barRangeController_->Play();
315 }
316 
FadingOut()317 void RenderDragBar::FadingOut()
318 {
319     auto keyframeFrom = AceType::MakeRefPtr<Keyframe<double>>(0.0, 1.0);
320     auto keyframeTo = AceType::MakeRefPtr<Keyframe<double>>(1.0, 0.0);
321     auto animation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
322     animation->AddKeyframe(keyframeFrom);
323     animation->AddKeyframe(keyframeTo);
324     animation->AddListener([weak = AceType::WeakClaim(this)](const double& opacity) {
325         auto dragBar = weak.Upgrade();
326         if (dragBar) {
327             dragBar->opacity_ = opacity;
328         }
329     });
330     animator_->AddInterpolator(animation);
331 }
332 
Stretching()333 void RenderDragBar::Stretching()
334 {
335     auto context = GetContext().Upgrade();
336     if (!context) {
337         LOGE("Animate to status bar failed. context is null.");
338         return;
339     }
340     auto keyframeFrom = AceType::MakeRefPtr<Keyframe<double>>(0.0, hotRegionHeight_.Value());
341     auto keyframeTo = AceType::MakeRefPtr<Keyframe<double>>(1.0, context->GetStatusBarHeight());
342     auto animation = AceType::MakeRefPtr<KeyframeAnimation<double>>();
343     animation->AddKeyframe(keyframeFrom);
344     animation->AddKeyframe(keyframeTo);
345     animation->AddListener([weak = AceType::WeakClaim(this)](const double& height) {
346         auto dragBar = weak.Upgrade();
347         if (!dragBar) {
348             return;
349         }
350         dragBar->hotRegionHeight_.SetValue(height);
351         dragBar->MarkNeedLayout();
352     });
353     animator_->AddStopListener([weak = AceType::WeakClaim(this)]() {
354         auto dragBar = weak.Upgrade();
355         if (!dragBar) {
356             return;
357         }
358         dragBar->SetFullScreenMode(true);
359         dragBar->MarkNeedLayout();
360     });
361     animator_->AddInterpolator(animation);
362 }
363 
AnimateToStatusBarPadding(int32_t duration)364 void RenderDragBar::AnimateToStatusBarPadding(int32_t duration)
365 {
366     if (animator_->IsRunning()) {
367         animator_->Finish();
368     }
369     animator_->ClearAllListeners();
370     animator_->ClearInterpolators();
371     Stretching();
372     FadingOut();
373     animator_->SetFillMode(FillMode::FORWARDS);
374     animator_->SetDuration(duration);
375     animator_->Forward();
376     SetDisableTouchEvent(true);
377 }
378 
SetStatusBarHeight(double height)379 void RenderDragBar::SetStatusBarHeight(double height)
380 {
381     // Reset full window animation.
382     if (animator_->IsRunning()) {
383         animator_->ClearAllListeners();
384         animator_->ClearInterpolators();
385         Stretching();
386         FadingOut();
387     }
388     if (GreatOrEqual(height, 0.0) && !NearEqual(statusBarHeight_.Value(), height)) {
389         statusBarHeight_.SetValue(height);
390         MarkNeedLayout();
391     }
392 }
393 
OnMouseHoverEnterTest()394 void RenderDragBar::OnMouseHoverEnterTest()
395 {
396     MarkNeedRender();
397 }
398 
OnMouseHoverExitTest()399 void RenderDragBar::OnMouseHoverExitTest()
400 {
401     MarkNeedRender();
402 }
403 
OnPaintFinish()404 void RenderDragBar::OnPaintFinish()
405 {
406     if (GetLayoutSize().IsEmpty()) {
407         return;
408     }
409     auto context = context_.Upgrade();
410     if (!context) {
411         return;
412     }
413     if (renderStatus_ == RenderStatus::FOCUS) {
414         Offset offset = GetPosition();
415         Size size = Size(NormalizeToPx(PAINT_WIDTH), NormalizeToPx(PAINT_HEIGHT));
416         auto alignOffset = Alignment::GetAlignPosition(GetLayoutSize(), size, Alignment::CENTER);
417         Offset globalOffset = GetGlobalOffset() + alignOffset;
418         RRect rrect = RRect::MakeRect(Rect(offset, size));
419         auto radius = Radius(size.Height() / 2);
420         rrect.SetCorner({ radius, radius, radius, radius });
421         context->ShowFocusAnimation(rrect, Color::BLUE, globalOffset);
422     }
423 }
424 
OnStatusChanged(RenderStatus renderStatus)425 void RenderDragBar::OnStatusChanged(RenderStatus renderStatus)
426 {
427     if (renderStatus_ != renderStatus) {
428         renderStatus_ = renderStatus;
429         MarkNeedRender();
430     }
431 }
432 
433 } // namespace OHOS::Ace
434