• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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