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