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