1 /*
2 * Copyright (c) 2022-2023 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_ng/pattern/slider/slider_pattern.h"
17
18 #include "base/geometry/offset.h"
19 #include "base/i18n/localization.h"
20 #include "base/utils/utils.h"
21 #include "core/components/theme/app_theme.h"
22 #include "core/components_ng/pattern/image/image_layout_property.h"
23 #include "core/components_ng/pattern/image/image_pattern.h"
24 #include "core/components_ng/pattern/slider/slider_accessibility_property.h"
25 #include "core/components_ng/pattern/slider/slider_layout_property.h"
26 #include "core/components_ng/pattern/slider/slider_paint_property.h"
27 #include "core/components_ng/pattern/slider/slider_style.h"
28 #include "core/components_ng/pattern/text/text_styles.h"
29 #include "core/components_ng/property/property.h"
30 #include "core/components_v2/inspector/inspector_constants.h"
31 #include "core/pipeline/pipeline_base.h"
32 #include "core/pipeline_ng/pipeline_context.h"
33
34 namespace OHOS::Ace::NG {
35 namespace {
36 constexpr float HALF = 0.5;
37 constexpr float SLIDER_MIN = .0f;
38 constexpr float SLIDER_MAX = 100.0f;
39 constexpr Dimension BUBBLE_TO_SLIDER_DISTANCE = 10.0_vp;
40 } // namespace
41
OnModifyDone()42 void SliderPattern::OnModifyDone()
43 {
44 Pattern::OnModifyDone();
45 auto host = GetHost();
46 CHECK_NULL_VOID(host);
47 auto hub = host->GetEventHub<EventHub>();
48 CHECK_NULL_VOID(hub);
49 auto gestureHub = hub->GetOrCreateGestureEventHub();
50 CHECK_NULL_VOID(gestureHub);
51 auto inputEventHub = hub->GetOrCreateInputEventHub();
52 CHECK_NULL_VOID(inputEventHub);
53 auto layoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
54 CHECK_NULL_VOID(layoutProperty);
55 layoutProperty->UpdateAlignment(Alignment::CENTER);
56 auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
57 CHECK_NULL_VOID(sliderPaintProperty);
58 showTips_ = sliderPaintProperty->GetShowTips().value_or(false);
59 float min = sliderPaintProperty->GetMin().value_or(0.0f);
60 float max = sliderPaintProperty->GetMax().value_or(100.0f);
61 value_ = sliderPaintProperty->GetValue().value_or(min);
62 float step = sliderPaintProperty->GetStep().value_or(1.0f);
63 CancelExceptionValue(min, max, step);
64 valueRatio_ = (value_ - min) / (max - min);
65 stepRatio_ = step / (max - min);
66 UpdateCircleCenterOffset();
67 UpdateBlock();
68 InitTouchEvent(gestureHub);
69 InitPanEvent(gestureHub);
70 InitMouseEvent(inputEventHub);
71 auto focusHub = hub->GetFocusHub();
72 CHECK_NULL_VOID_NOLOG(focusHub);
73 InitOnKeyEvent(focusHub);
74 InitializeBubble();
75 SetAccessibilityAction();
76 }
77
CancelExceptionValue(float & min,float & max,float & step)78 void SliderPattern::CancelExceptionValue(float& min, float& max, float& step)
79 {
80 auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
81 CHECK_NULL_VOID(sliderPaintProperty);
82 if (GreatOrEqual(min, max)) {
83 min = SLIDER_MIN;
84 max = SLIDER_MAX;
85 sliderPaintProperty->UpdateMin(min);
86 sliderPaintProperty->UpdateMax(max);
87 }
88 if (LessOrEqual(step, 0.0) || step > max - min) {
89 step = 1;
90 sliderPaintProperty->UpdateStep(step);
91 }
92 if (value_ < min || value_ > max) {
93 value_ = std::clamp(value_, min, max);
94 sliderPaintProperty->UpdateValue(value_);
95 FireChangeEvent(SliderChangeMode::End);
96 }
97 }
98
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool)99 bool SliderPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool /*skipLayout*/)
100 {
101 if (skipMeasure || dirty->SkipMeasureContent()) {
102 return false;
103 }
104
105 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
106 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
107 auto sliderLayoutAlgorithm = DynamicCast<SliderLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
108 CHECK_NULL_RETURN(sliderLayoutAlgorithm, false);
109 trackThickness_ = sliderLayoutAlgorithm->GetTrackThickness();
110 blockSize_ = sliderLayoutAlgorithm->GetBlockSize();
111 blockHotSize_ = sliderLayoutAlgorithm->GetBlockHotSize();
112
113 auto host = GetHost();
114 CHECK_NULL_RETURN(host, false);
115 auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
116 CHECK_NULL_RETURN(sliderLayoutProperty, false);
117 std::optional<SizeF> contentSize = GetHostContentSize();
118 CHECK_NULL_RETURN(contentSize.has_value(), false);
119 float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
120 ? contentSize.value().Width()
121 : contentSize.value().Height();
122
123 auto pipeline = PipelineBase::GetCurrentContext();
124 CHECK_NULL_RETURN(pipeline, false);
125 auto theme = pipeline->GetTheme<SliderTheme>();
126 CHECK_NULL_RETURN(theme, false);
127 auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
128 Dimension hotBlockShadowWidth = sliderMode == SliderModel::SliderMode::OUTSET
129 ? theme->GetOutsetHotBlockShadowWidth()
130 : theme->GetInsetHotBlockShadowWidth();
131
132 auto direction = sliderLayoutProperty->GetDirectionValue(Axis::HORIZONTAL);
133 auto blockLength = direction == Axis::HORIZONTAL ? blockSize_.Width() : blockSize_.Height();
134
135 hotBlockShadowWidth_ = static_cast<float>(hotBlockShadowWidth.ConvertToPx());
136 if (sliderMode == SliderModel::SliderMode::OUTSET) {
137 borderBlank_ = std::max(trackThickness_, blockLength + hotBlockShadowWidth_ / HALF);
138 } else {
139 borderBlank_ = trackThickness_ + hotBlockShadowWidth_ / HALF;
140 }
141 // slider track length
142 sliderLength_ = length >= borderBlank_ ? length - borderBlank_ : 1;
143 borderBlank_ = (length - sliderLength_) * HALF;
144 auto children = dirty->GetAllChildrenWithBuild();
145 if (!children.empty()) {
146 CHECK_NULL_RETURN(imageFrameNode_, true);
147 auto child = children.front();
148 auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
149 OffsetF childOffset(
150 circleCenter_.GetX() - childSize.Width() * HALF, circleCenter_.GetY() - childSize.Height() * HALF);
151 child->GetGeometryNode()->SetMarginFrameOffset(childOffset);
152 imageFrameNode_->MarkModifyDone();
153 imageFrameNode_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
154 }
155
156 return true;
157 }
158
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)159 void SliderPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
160 {
161 if (touchEvent_) {
162 return;
163 }
164 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
165 auto pattern = weak.Upgrade();
166 CHECK_NULL_VOID_NOLOG(pattern);
167 pattern->HandleTouchEvent(info);
168 };
169 gestureHub->RemoveTouchEvent(touchEvent_);
170 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
171 gestureHub->AddTouchEvent(touchEvent_);
172 }
173
AtMousePanArea(const Offset & offsetInFrame)174 bool SliderPattern::AtMousePanArea(const Offset& offsetInFrame)
175 {
176 const auto& content = GetHost()->GetGeometryNode()->GetContent();
177 CHECK_NULL_RETURN(content, false);
178 auto contentOffset = content->GetRect().GetOffset();
179 auto offset = Offset(offsetInFrame.GetX() - contentOffset.GetX(), offsetInFrame.GetY() - contentOffset.GetY());
180 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
181 CHECK_NULL_RETURN(paintProperty, false);
182 auto blockType = paintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT);
183 if (blockType == SliderModelNG::BlockStyleType::DEFAULT) {
184 double distanceCircle = std::min(blockSize_.Width(), blockSize_.Height()) * HALF + hotBlockShadowWidth_;
185 auto diffX = circleCenter_.GetX() - offset.GetX();
186 auto diffY = circleCenter_.GetY() - offset.GetY();
187 return diffX * diffX + diffY * diffY <= distanceCircle * distanceCircle;
188 } else {
189 float sideHotSizeX = blockSize_.Width() * HALF;
190 float sideHotSizeY = blockSize_.Height() * HALF;
191 return !(circleCenter_.GetX() - sideHotSizeX > offset.GetX() ||
192 circleCenter_.GetY() - sideHotSizeY > offset.GetY() ||
193 circleCenter_.GetX() + sideHotSizeX < offset.GetX() ||
194 circleCenter_.GetY() + sideHotSizeY < offset.GetY());
195 }
196 }
197
AtTouchPanArea(const Offset & offsetInFrame)198 bool SliderPattern::AtTouchPanArea(const Offset& offsetInFrame)
199 {
200 const auto& content = GetHost()->GetGeometryNode()->GetContent();
201 CHECK_NULL_RETURN(content, false);
202 auto contentOffset = content->GetRect().GetOffset();
203 auto offset = Offset(offsetInFrame.GetX() - contentOffset.GetX(), offsetInFrame.GetY() - contentOffset.GetY());
204 float sideHotSizeX = blockHotSize_.Width() * HALF;
205 float sideHotSizeY = blockHotSize_.Height() * HALF;
206 return !(circleCenter_.GetX() - sideHotSizeX > offset.GetX() ||
207 circleCenter_.GetY() - sideHotSizeY > offset.GetY() ||
208 circleCenter_.GetX() + sideHotSizeX < offset.GetX() ||
209 circleCenter_.GetY() + sideHotSizeY < offset.GetY());
210 }
211
AtPanArea(const Offset & offset,const SourceType & sourceType)212 bool SliderPattern::AtPanArea(const Offset& offset, const SourceType& sourceType)
213 {
214 auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
215 CHECK_NULL_RETURN(sliderPaintProperty, false);
216 if (sliderPaintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT) !=
217 SliderModelNG::BlockStyleType::DEFAULT) {
218 return false;
219 }
220 bool flag = false;
221 switch (sourceType) {
222 case SourceType::MOUSE:
223 flag = AtMousePanArea(offset);
224 break;
225 case SourceType::TOUCH:
226 flag = AtTouchPanArea(offset);
227 break;
228 case SourceType::NONE:
229 default:
230 break;
231 }
232 return flag;
233 }
234
HandleTouchEvent(const TouchEventInfo & info)235 void SliderPattern::HandleTouchEvent(const TouchEventInfo& info)
236 {
237 auto touchList = info.GetChangedTouches();
238 CHECK_NULL_VOID(!touchList.empty());
239 auto touchInfo = touchList.front();
240 auto touchType = touchInfo.GetTouchType();
241 if (touchType == TouchType::DOWN) {
242 axisFlag_ = false;
243 // when Touch Down area is at Pan Area, value is unchanged.
244 if (!AtPanArea(touchInfo.GetLocalLocation(), info.GetSourceDevice())) {
245 UpdateValueByLocalLocation(touchInfo.GetLocalLocation());
246 }
247 if (showTips_) {
248 bubbleFlag_ = true;
249 UpdateBubble();
250 }
251 mousePressedFlag_ = true;
252 FireChangeEvent(SliderChangeMode::Begin);
253 OpenTranslateAnimation();
254 } else if (touchType == TouchType::UP) {
255 if (bubbleFlag_) {
256 bubbleFlag_ = false;
257 }
258 mousePressedFlag_ = false;
259 FireChangeEvent(SliderChangeMode::Click);
260 FireChangeEvent(SliderChangeMode::End);
261 CloseTranslateAnimation();
262 }
263 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
264 }
265
InitializeBubble()266 void SliderPattern::InitializeBubble()
267 {
268 CHECK_NULL_VOID_NOLOG(showTips_);
269 auto frameNode = GetHost();
270 CHECK_NULL_VOID(frameNode);
271 auto pipeline = PipelineBase::GetCurrentContext();
272 CHECK_NULL_VOID(pipeline);
273 auto sliderTheme = pipeline->GetTheme<SliderTheme>();
274 CHECK_NULL_VOID(sliderTheme);
275 std::string content = std::to_string(static_cast<int>(std::round(valueRatio_ * 100.0f))) + '%';
276 auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
277 sliderPaintProperty->UpdatePadding(sliderTheme->GetTipTextPadding());
278 sliderPaintProperty->UpdateTipColor(sliderTheme->GetTipColor());
279 sliderPaintProperty->UpdateTextColor(sliderTheme->GetTipTextColor());
280 sliderPaintProperty->UpdateFontSize(sliderTheme->GetTipFontSize());
281 sliderPaintProperty->UpdateContent(content);
282 }
283
HandlingGestureStart(const GestureEvent & info)284 void SliderPattern::HandlingGestureStart(const GestureEvent& info)
285 {
286 if (info.GetInputEventType() != InputEventType::AXIS) {
287 UpdateValueByLocalLocation(info.GetLocalLocation());
288 UpdateBubble();
289 }
290 panMoveFlag_ = true;
291 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
292 }
293
HandlingGestureEvent(const GestureEvent & info)294 void SliderPattern::HandlingGestureEvent(const GestureEvent& info)
295 {
296 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
297 CHECK_NULL_VOID(paintProperty);
298 if (info.GetInputEventType() == InputEventType::AXIS) {
299 auto offset = NearZero(info.GetOffsetX()) ? info.GetOffsetY() : info.GetOffsetX();
300 // offset > 0 when Wheel Up, offset < 0 when Wheel Down
301 if (direction_ == Axis::HORIZONTAL) {
302 offset > 0.0 ? MoveStep(1) : MoveStep(-1);
303 } else {
304 auto reverse = paintProperty->GetReverseValue(false);
305 reverse ? (offset > 0.0 ? MoveStep(1) : MoveStep(-1)) : (offset > 0.0 ? MoveStep(-1) : MoveStep(1));
306 }
307 if (hotFlag_) {
308 // Only when the mouse hovers over the slider, axisFlag_ can be set true
309 axisFlag_ = true;
310 }
311 if (showTips_ && axisFlag_) {
312 bubbleFlag_ = true;
313 InitializeBubble();
314 }
315 } else {
316 UpdateValueByLocalLocation(info.GetLocalLocation());
317 UpdateBubble();
318 }
319 panMoveFlag_ = true;
320 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
321 }
322
HandledGestureEvent()323 void SliderPattern::HandledGestureEvent()
324 {
325 panMoveFlag_ = false;
326
327 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
328 }
329
UpdateValueByLocalLocation(const std::optional<Offset> & localLocation)330 void SliderPattern::UpdateValueByLocalLocation(const std::optional<Offset>& localLocation)
331 {
332 CHECK_NULL_VOID(localLocation.has_value());
333 auto host = GetHost();
334 CHECK_NULL_VOID(host);
335 auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
336 CHECK_NULL_VOID(sliderLayoutProperty);
337 auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
338 CHECK_NULL_VOID(sliderPaintProperty);
339 const auto& content = GetHost()->GetGeometryNode()->GetContent();
340 CHECK_NULL_VOID(content);
341 auto contentOffset = content->GetRect().GetOffset();
342 float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
343 ? static_cast<float>(localLocation->GetX() - contentOffset.GetX())
344 : static_cast<float>(localLocation->GetY() - contentOffset.GetY());
345 float touchLength = sliderPaintProperty->GetReverse().value_or(false) ? borderBlank_ + sliderLength_ - length
346 : length - borderBlank_;
347 float min = sliderPaintProperty->GetMin().value_or(0.0f);
348 float max = sliderPaintProperty->GetMax().value_or(100.0f);
349 touchLength = std::clamp(touchLength, 0.0f, sliderLength_);
350 CHECK_NULL_VOID(sliderLength_ != 0);
351 valueRatio_ = touchLength / sliderLength_;
352 CHECK_NULL_VOID(stepRatio_ != 0);
353 valueRatio_ = NearEqual(valueRatio_, 1) ? 1 : std::round(valueRatio_ / stepRatio_) * stepRatio_;
354 float oldValue = value_;
355 value_ = valueRatio_ * (max - min) + min;
356 sliderPaintProperty->UpdateValue(value_);
357 valueChangeFlag_ = !NearEqual(oldValue, value_);
358 UpdateCircleCenterOffset();
359 }
360
UpdateTipsValue()361 void SliderPattern::UpdateTipsValue()
362 {
363 CHECK_NULL_VOID_NOLOG(valueChangeFlag_);
364 CHECK_NULL_VOID_NOLOG(showTips_);
365 CHECK_NULL_VOID(bubbleFlag_);
366 auto frameNode = GetHost();
367 CHECK_NULL_VOID(frameNode);
368 std::string content = std::to_string(static_cast<int>(std::round(valueRatio_ * 100.0f))) + '%';
369 frameNode->GetPaintProperty<SliderPaintProperty>()->UpdateContent(content);
370 }
371
UpdateCircleCenterOffset()372 void SliderPattern::UpdateCircleCenterOffset()
373 {
374 auto host = GetHost();
375 CHECK_NULL_VOID(host);
376 auto contentSize = GetHostContentSize();
377 CHECK_NULL_VOID(contentSize.has_value());
378 auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
379 CHECK_NULL_VOID(sliderPaintProperty);
380 auto touchLength = valueRatio_ * sliderLength_;
381 auto touchOffset = sliderPaintProperty->GetReverse().value_or(false) ? sliderLength_ - touchLength + borderBlank_
382 : touchLength + borderBlank_;
383 if (sliderPaintProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
384 circleCenter_.SetX(touchOffset);
385 circleCenter_.SetY(contentSize->Height() * HALF);
386 } else {
387 circleCenter_.SetX(contentSize->Width() * HALF);
388 circleCenter_.SetY(touchOffset);
389 }
390 }
391
UpdateBubble()392 void SliderPattern::UpdateBubble()
393 {
394 CHECK_NULL_VOID_NOLOG(bubbleFlag_);
395 // update the tip value according to the slider value, update the tip position according to current block position
396 UpdateTipsValue();
397 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
398 }
399
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)400 void SliderPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
401 {
402 if (direction_ == GetDirection() && panEvent_) {
403 return;
404 }
405 direction_ = GetDirection();
406 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
407 auto pattern = weak.Upgrade();
408 CHECK_NULL_VOID_NOLOG(pattern);
409 pattern->HandlingGestureStart(info);
410 pattern->OpenTranslateAnimation();
411 };
412 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
413 auto pattern = weak.Upgrade();
414 CHECK_NULL_VOID_NOLOG(pattern);
415 pattern->HandlingGestureEvent(info);
416 pattern->FireChangeEvent(SliderChangeMode::Moving);
417 pattern->OpenTranslateAnimation();
418 };
419 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& /*info*/) {
420 auto pattern = weak.Upgrade();
421 CHECK_NULL_VOID_NOLOG(pattern);
422 pattern->HandledGestureEvent();
423 pattern->CloseTranslateAnimation();
424 };
425 auto actionCancelTask = [weak = WeakClaim(this)]() {
426 auto pattern = weak.Upgrade();
427 CHECK_NULL_VOID_NOLOG(pattern);
428 pattern->HandledGestureEvent();
429 pattern->FireChangeEvent(SliderChangeMode::End);
430 pattern->axisFlag_ = false;
431 pattern->CloseTranslateAnimation();
432 };
433 if (panEvent_) {
434 gestureHub->RemovePanEvent(panEvent_);
435 }
436 panEvent_ = MakeRefPtr<PanEvent>(
437 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
438
439 PanDirection panDirection;
440 panDirection.type = PanDirection::ALL;
441 gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
442 }
443
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)444 void SliderPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
445 {
446 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
447 auto pattern = wp.Upgrade();
448 CHECK_NULL_VOID_NOLOG(pattern);
449 pattern->GetInnerFocusPaintRect(paintRect);
450 };
451 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
452
453 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
454 auto pattern = wp.Upgrade();
455 CHECK_NULL_RETURN_NOLOG(pattern, false);
456 return pattern->OnKeyEvent(event);
457 };
458 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
459
460 auto onBlur = [wp = WeakClaim(this)]() {
461 auto pattern = wp.Upgrade();
462 CHECK_NULL_VOID_NOLOG(pattern);
463 pattern->bubbleFlag_ = false;
464 pattern->focusFlag_ = false;
465 pattern->UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
466 };
467 focusHub->SetOnBlurInternal(std::move(onBlur));
468 }
469
GetInnerFocusPaintRect(RoundRect & paintRect)470 void SliderPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
471 {
472 auto host = GetHost();
473 CHECK_NULL_VOID(host);
474 auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
475 auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
476 if (sliderMode == SliderModel::SliderMode::OUTSET) {
477 GetOutsetInnerFocusPaintRect(paintRect);
478 } else {
479 GetInsetInnerFocusPaintRect(paintRect);
480 }
481 }
482
GetOutsetInnerFocusPaintRect(RoundRect & paintRect)483 void SliderPattern::GetOutsetInnerFocusPaintRect(RoundRect& paintRect)
484 {
485 UpdateCircleCenterOffset();
486 const auto& content = GetHost()->GetGeometryNode()->GetContent();
487 CHECK_NULL_VOID(content);
488 auto contentOffset = content->GetRect().GetOffset();
489 auto theme = PipelineBase::GetCurrentContext()->GetTheme<SliderTheme>();
490 auto appTheme = PipelineBase::GetCurrentContext()->GetTheme<AppTheme>();
491 auto paintWidth = appTheme->GetFocusWidthVp();
492 auto focusSideDistance = theme->GetFocusSideDistance();
493 auto focusDistance = paintWidth * HALF + focusSideDistance;
494 auto halfWidth = blockSize_.Width() * HALF + static_cast<float>(focusDistance.ConvertToPx());
495 auto halfHeight = blockSize_.Height() * HALF + static_cast<float>(focusDistance.ConvertToPx());
496 paintRect.SetRect(RectF(circleCenter_.GetX() - halfWidth + contentOffset.GetX(),
497 circleCenter_.GetY() - halfHeight + contentOffset.GetY(), halfWidth / HALF, halfHeight / HALF));
498 paintRect.SetCornerRadius(focusDistance.ConvertToPx());
499 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
500 CHECK_NULL_VOID(paintProperty);
501 auto blockType = paintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT);
502 if (blockType == SliderModelNG::BlockStyleType::DEFAULT) {
503 auto focusRadius =
504 std::min(blockSize_.Width(), blockSize_.Height()) * HALF + static_cast<float>(focusDistance.ConvertToPx());
505 paintRect.SetRect(RectF(circleCenter_.GetX() - focusRadius + contentOffset.GetX(),
506 circleCenter_.GetY() - focusRadius + contentOffset.GetY(), focusRadius / HALF, focusRadius / HALF));
507 paintRect.SetCornerRadius(focusRadius);
508 } else if (blockType == SliderModelNG::BlockStyleType::SHAPE) {
509 auto shape = paintProperty->GetBlockShape();
510 if (shape.has_value() && shape.value()->GetBasicShapeType() == BasicShapeType::CIRCLE) {
511 auto circle = DynamicCast<Circle>(shape.value());
512 CHECK_NULL_VOID(circle);
513 float focusRadius;
514 if (circle->GetRadius().IsValid()) {
515 focusRadius = circle->GetRadius().ConvertToPx() + focusDistance.ConvertToPx();
516 } else {
517 focusRadius = std::min(circle->GetWidth().ConvertToPx(), circle->GetHeight().ConvertToPx()) * HALF +
518 focusDistance.ConvertToPx();
519 }
520 paintRect.SetRect(RectF(circleCenter_.GetX() - focusRadius + contentOffset.GetX(),
521 circleCenter_.GetY() - focusRadius + contentOffset.GetY(), focusRadius / HALF, focusRadius / HALF));
522 paintRect.SetCornerRadius(focusRadius);
523 }
524 }
525 }
526
GetInsetInnerFocusPaintRect(RoundRect & paintRect)527 void SliderPattern::GetInsetInnerFocusPaintRect(RoundRect& paintRect)
528 {
529 auto frameNode = GetHost();
530 CHECK_NULL_VOID(frameNode);
531 const auto& content = frameNode->GetGeometryNode()->GetContent();
532 CHECK_NULL_VOID(content);
533 auto theme = PipelineBase::GetCurrentContext()->GetTheme<SliderTheme>();
534 CHECK_NULL_VOID(theme);
535 auto focusSideDistance = theme->GetFocusSideDistance();
536 auto appTheme = PipelineBase::GetCurrentContext()->GetTheme<AppTheme>();
537 CHECK_NULL_VOID(appTheme);
538 auto paintWidth = appTheme->GetFocusWidthVp();
539 auto focusDistance = paintWidth * HALF + focusSideDistance;
540 // use content area
541 float offsetX = content->GetRect().GetX();
542 float offsetY = content->GetRect().GetY();
543 float width = content->GetRect().Width();
544 float height = content->GetRect().Height();
545 float focusRadius = trackThickness_ * HALF + static_cast<float>(focusDistance.ConvertToPx());
546 auto paintProperty = frameNode->GetPaintProperty<SliderPaintProperty>();
547 if (paintProperty && paintProperty->GetTrackBorderRadius().has_value()) {
548 focusRadius = static_cast<float>(paintProperty->GetTrackBorderRadius().value().ConvertToPx()) +
549 static_cast<float>(focusDistance.ConvertToPx());
550 }
551 if (direction_ == Axis::HORIZONTAL) {
552 offsetX += borderBlank_ - trackThickness_ * HALF - static_cast<float>(focusDistance.ConvertToPx());
553 offsetY += (height - trackThickness_) * HALF - static_cast<float>(focusDistance.ConvertToPx());
554 width = sliderLength_ + trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
555 height = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
556 } else {
557 offsetX += (width - trackThickness_) * HALF - static_cast<float>(focusDistance.ConvertToPx());
558 offsetY += borderBlank_ - trackThickness_ * HALF - static_cast<float>(focusDistance.ConvertToPx());
559 width = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
560 height = sliderLength_ + trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
561 }
562 paintRect.SetRect(RectF(offsetX, offsetY, width, height));
563 paintRect.SetCornerRadius(focusRadius);
564 }
565
PaintFocusState()566 void SliderPattern::PaintFocusState()
567 {
568 focusFlag_ = true;
569 auto host = GetHost();
570 CHECK_NULL_VOID(host);
571 RoundRect focusRect;
572 GetInnerFocusPaintRect(focusRect);
573
574 auto focusHub = host->GetFocusHub();
575 CHECK_NULL_VOID(focusHub);
576 focusHub->PaintInnerFocusState(focusRect);
577
578 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
579 }
580
OnKeyEvent(const KeyEvent & event)581 bool SliderPattern::OnKeyEvent(const KeyEvent& event)
582 {
583 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
584 CHECK_NULL_RETURN(paintProperty, false);
585 auto reverse = paintProperty->GetReverseValue(false);
586 if (event.action == KeyAction::DOWN) {
587 if ((direction_ == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
588 (direction_ == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
589 reverse ? MoveStep(1) : MoveStep(-1);
590 if (showTips_) {
591 InitializeBubble();
592 }
593 PaintFocusState();
594 return true;
595 }
596 if ((direction_ == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
597 (direction_ == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
598 reverse ? MoveStep(-1) : MoveStep(1);
599 if (showTips_) {
600 InitializeBubble();
601 }
602 PaintFocusState();
603 return true;
604 }
605 } else if (event.action == KeyAction::UP) {
606 if (showTips_) {
607 bubbleFlag_ = true;
608 InitializeBubble();
609 }
610 PaintFocusState();
611 }
612 return false;
613 }
614
MoveStep(int32_t stepCount)615 bool SliderPattern::MoveStep(int32_t stepCount)
616 {
617 // stepCount > 0, slider value increases, block moves in the direction of growth
618 auto host = GetHost();
619 CHECK_NULL_RETURN(host, false);
620 auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
621 CHECK_NULL_RETURN(sliderPaintProperty, false);
622 float step = sliderPaintProperty->GetStep().value_or(1.0f);
623 float min = sliderPaintProperty->GetMin().value_or(0.0f);
624 float max = sliderPaintProperty->GetMax().value_or(100.0f);
625 if (NearZero(step)) {
626 return false;
627 }
628 float nextValue = -1.0;
629 nextValue = value_ + static_cast<float>(stepCount) * step;
630 if (NearEqual(nextValue, -1.0)) {
631 return false;
632 }
633 nextValue = std::clamp(nextValue, min, max);
634 nextValue = std::round(nextValue / step) * step;
635 if (NearEqual(nextValue, value_)) {
636 return false;
637 }
638 value_ = nextValue;
639 sliderPaintProperty->UpdateValue(value_);
640 valueRatio_ = (value_ - min) / (max - min);
641 FireChangeEvent(SliderChangeMode::Begin);
642 FireChangeEvent(SliderChangeMode::End);
643 LOGD("Move %{public}d steps, Value change to %{public}f", stepCount, value_);
644 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
645 return true;
646 }
647
InitMouseEvent(const RefPtr<InputEventHub> & inputEventHub)648 void SliderPattern::InitMouseEvent(const RefPtr<InputEventHub>& inputEventHub)
649 {
650 auto hoverEvent = [weak = WeakClaim(this)](bool isHover) {
651 auto pattern = weak.Upgrade();
652 CHECK_NULL_VOID_NOLOG(pattern);
653 pattern->HandleHoverEvent(isHover);
654 };
655 if (hoverEvent_) {
656 inputEventHub->RemoveOnHoverEvent(hoverEvent_);
657 }
658 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverEvent));
659 inputEventHub->AddOnHoverEvent(hoverEvent_);
660
661 auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
662 auto pattern = weak.Upgrade();
663 CHECK_NULL_VOID_NOLOG(pattern);
664 pattern->HandleMouseEvent(info);
665 };
666 if (mouseEvent_) {
667 inputEventHub->RemoveOnMouseEvent(mouseEvent_);
668 }
669 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
670 inputEventHub->AddOnMouseEvent(mouseEvent_);
671 }
672
HandleHoverEvent(bool isHover)673 void SliderPattern::HandleHoverEvent(bool isHover)
674 {
675 hotFlag_ = isHover;
676 mouseHoverFlag_ = mouseHoverFlag_ && isHover;
677 if (!mouseHoverFlag_) {
678 bubbleFlag_ = false;
679 axisFlag_ = false;
680 }
681 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
682 }
683
HandleMouseEvent(const MouseInfo & info)684 void SliderPattern::HandleMouseEvent(const MouseInfo& info)
685 {
686 UpdateCircleCenterOffset();
687 // MouseInfo's LocalLocation is relative to the frame area, circleCenter_ is relative to the content area
688 mouseHoverFlag_ = AtMousePanArea(info.GetLocalLocation());
689 if (mouseHoverFlag_) {
690 if (showTips_) {
691 bubbleFlag_ = true;
692 InitializeBubble();
693 }
694 }
695 // when mouse hovers over slider, distinguish between hover block and Wheel operation.
696 if (!mouseHoverFlag_ && !axisFlag_) {
697 bubbleFlag_ = false;
698 }
699
700 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
701 }
702
FireChangeEvent(int32_t mode)703 void SliderPattern::FireChangeEvent(int32_t mode)
704 {
705 auto sliderEventHub = GetEventHub<SliderEventHub>();
706 CHECK_NULL_VOID(sliderEventHub);
707 if ((mode == SliderChangeMode::Click || mode == SliderChangeMode::Moving) &&
708 NearEqual(value_, sliderEventHub->GetValue())) {
709 return;
710 }
711 sliderEventHub->FireChangeEvent(static_cast<float>(value_), mode);
712 valueChangeFlag_ = false;
713
714 auto host = GetHost();
715 CHECK_NULL_VOID(host);
716 if (mode == SliderChangeMode::Begin) {
717 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_START);
718 } else if (mode == SliderChangeMode::End) {
719 host->OnAccessibilityEvent(AccessibilityEventType::SCROLL_END);
720 }
721 }
722
UpdateMarkDirtyNode(const PropertyChangeFlag & Flag)723 void SliderPattern::UpdateMarkDirtyNode(const PropertyChangeFlag& Flag)
724 {
725 auto host = GetHost();
726 CHECK_NULL_VOID(host);
727 host->MarkDirtyNode(Flag);
728 }
729
GetDirection() const730 Axis SliderPattern::GetDirection() const
731 {
732 auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
733 CHECK_NULL_RETURN(sliderLayoutProperty, Axis::HORIZONTAL);
734 return sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
735 }
736
CreateAccessibilityProperty()737 RefPtr<AccessibilityProperty> SliderPattern::CreateAccessibilityProperty()
738 {
739 return MakeRefPtr<SliderAccessibilityProperty>();
740 }
741
UpdateContentParameters()742 SliderContentModifier::Parameters SliderPattern::UpdateContentParameters()
743 {
744 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
745 CHECK_NULL_RETURN(paintProperty, SliderContentModifier::Parameters());
746 auto pipeline = PipelineBase::GetCurrentContext();
747 CHECK_NULL_RETURN(pipeline, SliderContentModifier::Parameters());
748 auto theme = pipeline->GetTheme<SliderTheme>();
749 CHECK_NULL_RETURN(theme, SliderContentModifier::Parameters());
750 SliderContentModifier::Parameters parameters { trackThickness_, blockSize_, stepRatio_, hotBlockShadowWidth_,
751 mouseHoverFlag_, mousePressedFlag_ };
752 auto contentSize = GetHostContentSize();
753 CHECK_NULL_RETURN(contentSize, SliderContentModifier::Parameters());
754 const auto& content = GetHost()->GetGeometryNode()->GetContent();
755 CHECK_NULL_RETURN(content, SliderContentModifier::Parameters());
756 auto contentOffset = content->GetRect().GetOffset();
757 // Distance between slide track and Content boundary
758 auto centerWidth = direction_ == Axis::HORIZONTAL ? contentSize->Height() : contentSize->Width();
759 centerWidth *= HALF;
760 parameters.selectColor = paintProperty->GetSelectColor().value_or(theme->GetTrackSelectedColor());
761 parameters.trackBackgroundColor = paintProperty->GetTrackBackgroundColor().value_or(theme->GetTrackBgColor());
762 parameters.blockColor = paintProperty->GetBlockColor().value_or(theme->GetBlockColor());
763
764 GetSelectPosition(parameters, centerWidth, contentOffset);
765 GetBackgroundPosition(parameters, centerWidth, contentOffset);
766 GetCirclePosition(parameters, centerWidth, contentOffset);
767 UpdateCircleCenterOffset();
768 return parameters;
769 }
770
GetSelectPosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)771 void SliderPattern::GetSelectPosition(
772 SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
773 {
774 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
775 CHECK_NULL_VOID(paintProperty);
776 float sliderSelectLength = std::clamp(sliderLength_ * valueRatio_, 0.0f, sliderLength_);
777 PointF start;
778 PointF end;
779 if (!paintProperty->GetReverseValue(false)) {
780 start = direction_ == Axis::HORIZONTAL ? PointF(offset.GetX() + borderBlank_, offset.GetY() + centerWidth)
781 : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_);
782 end = direction_ == Axis::HORIZONTAL
783 ? PointF(offset.GetX() + borderBlank_ + sliderSelectLength, offset.GetY() + centerWidth)
784 : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderSelectLength);
785 } else {
786 start = direction_ == Axis::HORIZONTAL
787 ? PointF(offset.GetX() + borderBlank_ + sliderLength_, offset.GetY() + centerWidth)
788 : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_);
789 end =
790 direction_ == Axis::HORIZONTAL ?
791 PointF(offset.GetX() + borderBlank_ + sliderLength_ - sliderSelectLength, offset.GetY() + centerWidth) :
792 PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_ - sliderSelectLength);
793 }
794 parameters.selectStart = start;
795 parameters.selectEnd = end;
796 }
797
GetBackgroundPosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)798 void SliderPattern::GetBackgroundPosition(
799 SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
800 {
801 auto startPointX = offset.GetX();
802 auto startPointY = offset.GetY();
803 auto start = direction_ == Axis::HORIZONTAL ? PointF(startPointX + borderBlank_, startPointY + centerWidth)
804 : PointF(startPointX + centerWidth, startPointY + borderBlank_);
805 auto end = direction_ == Axis::HORIZONTAL
806 ? PointF(startPointX + borderBlank_ + sliderLength_, startPointY + centerWidth)
807 : PointF(startPointX + centerWidth, startPointY + borderBlank_ + sliderLength_);
808 parameters.backStart = start;
809 parameters.backEnd = end;
810 }
811
GetCirclePosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)812 void SliderPattern::GetCirclePosition(
813 SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
814 {
815 float sliderSelectLength = std::clamp(sliderLength_ * valueRatio_, 0.0f, sliderLength_);
816 auto paintProperty = GetPaintProperty<SliderPaintProperty>();
817 CHECK_NULL_VOID(paintProperty);
818 PointF center;
819 if (!paintProperty->GetReverseValue(false)) {
820 center = direction_ == Axis::HORIZONTAL
821 ? PointF(offset.GetX() + borderBlank_ + sliderSelectLength, offset.GetY() + centerWidth)
822 : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderSelectLength);
823 } else {
824 center =
825 direction_ == Axis::HORIZONTAL ?
826 PointF(offset.GetX() + borderBlank_ + sliderLength_ - sliderSelectLength, offset.GetY() + centerWidth) :
827 PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_ - sliderSelectLength);
828 }
829 parameters.circleCenter = center;
830 }
831
UpdateBlock()832 void SliderPattern::UpdateBlock()
833 {
834 auto host = GetHost();
835 CHECK_NULL_VOID(host);
836 auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
837 CHECK_NULL_VOID(sliderPaintProperty);
838
839 if (sliderPaintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT) ==
840 SliderModelNG::BlockStyleType::IMAGE) {
841 if (imageFrameNode_ == nullptr) {
842 auto imageId = ElementRegister::GetInstance()->MakeUniqueId();
843 imageFrameNode_ =
844 FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, imageId, AceType::MakeRefPtr<ImagePattern>());
845 imageFrameNode_->MountToParent(host);
846 }
847 if (imageFrameNode_ != nullptr) {
848 auto imageLayoutProperty = DynamicCast<ImageLayoutProperty>(imageFrameNode_->GetLayoutProperty());
849 imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(sliderPaintProperty->GetBlockImage().value()));
850 imageLayoutProperty->UpdateImageFit(ImageFit::COVER);
851 imageLayoutProperty->UpdateAutoResize(true);
852 imageFrameNode_->MarkModifyDone();
853 }
854 } else {
855 if (imageFrameNode_ != nullptr) {
856 host->RemoveChild(imageFrameNode_);
857 imageFrameNode_ = nullptr;
858 }
859 }
860 }
861
ProvideRestoreInfo()862 std::string SliderPattern::ProvideRestoreInfo()
863 {
864 auto jsonObj = JsonUtil::Create(true);
865 auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
866 CHECK_NULL_RETURN(sliderPaintProperty, "");
867 jsonObj->Put("value", sliderPaintProperty->GetValue().value_or(0.0f));
868 return jsonObj->ToString();
869 }
870
OnRestoreInfo(const std::string & restoreInfo)871 void SliderPattern::OnRestoreInfo(const std::string& restoreInfo)
872 {
873 auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
874 CHECK_NULL_VOID(sliderPaintProperty);
875 auto info = JsonUtil::ParseJsonString(restoreInfo);
876 if (!info->IsValid() || !info->IsObject()) {
877 return;
878 }
879 auto jsonValue = info->GetValue("value");
880 sliderPaintProperty->UpdateValue(jsonValue->GetDouble());
881 OnModifyDone();
882 }
883
LayoutImageNode()884 void SliderPattern::LayoutImageNode()
885 {
886 auto host = GetHost();
887 CHECK_NULL_VOID(host);
888 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
889 }
890
OpenTranslateAnimation()891 void SliderPattern::OpenTranslateAnimation()
892 {
893 CHECK_NULL_VOID(sliderContentModifier_);
894 sliderContentModifier_->SetAnimated();
895 }
896
CloseTranslateAnimation()897 void SliderPattern::CloseTranslateAnimation()
898 {
899 CHECK_NULL_VOID(sliderContentModifier_);
900 sliderContentModifier_->SetNotAnimated();
901 }
902
GetBubbleVertexPosition(const OffsetF & blockCenter,float trackThickness,const SizeF & blockSize)903 OffsetF SliderPattern::GetBubbleVertexPosition(const OffsetF& blockCenter, float trackThickness, const SizeF& blockSize)
904 {
905 OffsetF bubbleVertex = blockCenter;
906 auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
907 CHECK_NULL_RETURN(sliderLayoutProperty, bubbleVertex);
908 auto sliderMode = sliderLayoutProperty->GetSliderModeValue(SliderModel::SliderMode::OUTSET);
909 if (sliderMode == SliderModel::SliderMode::OUTSET) {
910 if (direction_ == Axis::HORIZONTAL) {
911 bubbleVertex.AddY(0 - blockSize.Height() * HALF - BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx());
912 } else {
913 bubbleVertex.AddX(0 - blockSize.Width() * HALF - BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx());
914 }
915 } else {
916 if (direction_ == Axis::HORIZONTAL) {
917 bubbleVertex.AddY(0 - trackThickness * HALF - BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx());
918 } else {
919 bubbleVertex.AddX(0 - trackThickness * HALF - BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx());
920 }
921 }
922 return bubbleVertex;
923 }
924
SetAccessibilityAction()925 void SliderPattern::SetAccessibilityAction()
926 {
927 auto host = GetHost();
928 CHECK_NULL_VOID(host);
929 auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
930 CHECK_NULL_VOID(accessibilityProperty);
931 accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
932 const auto& pattern = weakPtr.Upgrade();
933 CHECK_NULL_VOID(pattern);
934 pattern->MoveStep(1);
935
936 if (pattern->showTips_) {
937 pattern->bubbleFlag_ = true;
938 pattern->InitializeBubble();
939 }
940 pattern->PaintFocusState();
941 });
942
943 accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
944 const auto& pattern = weakPtr.Upgrade();
945 CHECK_NULL_VOID(pattern);
946 pattern->MoveStep(-1);
947
948 if (pattern->showTips_) {
949 pattern->bubbleFlag_ = true;
950 pattern->InitializeBubble();
951 }
952 pattern->PaintFocusState();
953 });
954 }
955
UpdateValue(float value)956 void SliderPattern::UpdateValue(float value)
957 {
958 if (panMoveFlag_) {
959 return;
960 }
961 auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
962 CHECK_NULL_VOID(sliderPaintProperty);
963 sliderPaintProperty->UpdateValue(value);
964 }
965
OnAttachToFrameNode()966 void SliderPattern::OnAttachToFrameNode()
967 {
968 RegisterVisibleAreaChange();
969 }
970
OnVisibleChange(bool isVisible)971 void SliderPattern::OnVisibleChange(bool isVisible)
972 {
973 isVisible_ = isVisible;
974 LOGD("Slider OnVisibleChange: isVisible = %d", isVisible_);
975 isVisible_ ? StartAnimation() : StopAnimation();
976 }
977
StartAnimation()978 void SliderPattern::StartAnimation()
979 {
980 CHECK_NULL_VOID(sliderContentModifier_);
981 LOGD("Slider StartAnimation: isVisibleArea_ = %d, isVisible_ = %d, isShow_ = %d", isVisibleArea_, isVisible_,
982 isShow_);
983 if (sliderContentModifier_->GetVisible()) {
984 return;
985 }
986 if (IsSliderVisible()) {
987 sliderContentModifier_->SetVisible(true);
988 auto host = GetHost();
989 CHECK_NULL_VOID(host);
990 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
991 }
992 }
993
StopAnimation()994 void SliderPattern::StopAnimation()
995 {
996 CHECK_NULL_VOID(sliderContentModifier_);
997 if (!sliderContentModifier_->GetVisible()) {
998 return;
999 }
1000 LOGD("Slider StopAnimation");
1001 sliderContentModifier_->SetVisible(false);
1002 auto host = GetHost();
1003 CHECK_NULL_VOID(host);
1004 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1005 }
1006
RegisterVisibleAreaChange()1007 void SliderPattern::RegisterVisibleAreaChange()
1008 {
1009 if (hasVisibleChangeRegistered_) {
1010 return;
1011 }
1012
1013 auto pipeline = PipelineContext::GetCurrentContext();
1014 CHECK_NULL_VOID(pipeline);
1015 auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
1016 auto pattern = weak.Upgrade();
1017 CHECK_NULL_VOID(pattern);
1018 LOGD("Slider VisibleAreaChange CallBack: visible = %d", visible);
1019 pattern->isVisibleArea_ = visible;
1020 visible ? pattern->StartAnimation() : pattern->StopAnimation();
1021 };
1022 auto host = GetHost();
1023 CHECK_NULL_VOID(host);
1024 pipeline->RemoveVisibleAreaChangeNode(host->GetId());
1025 pipeline->AddVisibleAreaChangeNode(host, 0.0f, callback);
1026
1027 pipeline->AddWindowStateChangedCallback(host->GetId());
1028 hasVisibleChangeRegistered_ = true;
1029 }
1030
OnWindowHide()1031 void SliderPattern::OnWindowHide()
1032 {
1033 isShow_ = false;
1034 LOGD("Slider OnWindowHide");
1035 StopAnimation();
1036 }
1037
OnWindowShow()1038 void SliderPattern::OnWindowShow()
1039 {
1040 isShow_ = true;
1041 LOGD("Slider OnWindowShow");
1042 StartAnimation();
1043 }
1044
IsSliderVisible()1045 bool SliderPattern::IsSliderVisible()
1046 {
1047 return isVisibleArea_ && isVisible_ && isShow_;
1048 }
1049 } // namespace OHOS::Ace::NG
1050