• 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 <valarray>
19 
20 #include "base/geometry/offset.h"
21 #include "base/i18n/localization.h"
22 #include "base/utils/utils.h"
23 #include "core/components/theme/app_theme.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/text/text_styles.h"
28 #include "core/components_ng/property/property.h"
29 #include "core/components_v2/inspector/inspector_constants.h"
30 #include "core/pipeline/pipeline_base.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr float HALF = 0.5;
36 constexpr Dimension ARROW_WIDTH = 32.0_vp;
37 constexpr Dimension ARROW_HEIGHT = 8.0_vp;
38 constexpr float SLIDER_MIN = .0f;
39 constexpr float SLIDER_MAX = 100.0f;
40 } // namespace
41 
OnModifyDone()42 void SliderPattern::OnModifyDone()
43 {
44     auto host = GetHost();
45     CHECK_NULL_VOID(host);
46     auto hub = host->GetEventHub<EventHub>();
47     CHECK_NULL_VOID(hub);
48     auto gestureHub = hub->GetOrCreateGestureEventHub();
49     CHECK_NULL_VOID(gestureHub);
50     auto inputEventHub = hub->GetOrCreateInputEventHub();
51     CHECK_NULL_VOID(inputEventHub);
52     auto layoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
53     CHECK_NULL_VOID(layoutProperty);
54     layoutProperty->UpdateAlignment(Alignment::CENTER);
55     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
56     CHECK_NULL_VOID(sliderPaintProperty);
57     showTips_ = sliderPaintProperty->GetShowTips().value_or(false);
58     value_ = sliderPaintProperty->GetValue().value_or(0.0f);
59     float min = sliderPaintProperty->GetMin().value_or(0.0f);
60     float max = sliderPaintProperty->GetMax().value_or(100.0f);
61     float step = sliderPaintProperty->GetStep().value_or(1.0f);
62     CancelExceptionValue(min, max, step);
63     valueRatio_ = (value_ - min) / (max - min);
64     stepRatio_ = step / (max - min);
65     InitTouchEvent(gestureHub);
66     InitClickEvent(gestureHub);
67     InitPanEvent(gestureHub);
68     InitMouseEvent(inputEventHub);
69     auto focusHub = hub->GetFocusHub();
70     CHECK_NULL_VOID_NOLOG(focusHub);
71     InitOnKeyEvent(focusHub);
72 }
73 
CancelExceptionValue(float & min,float & max,float & step)74 void SliderPattern::CancelExceptionValue(float& min, float& max, float& step)
75 {
76     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
77     CHECK_NULL_VOID(sliderPaintProperty);
78     if (GreatOrEqual(min, max)) {
79         min = SLIDER_MIN;
80         max = SLIDER_MAX;
81         sliderPaintProperty->UpdateMin(min);
82         sliderPaintProperty->UpdateMax(max);
83     }
84     if (LessOrEqual(step, 0.0) || step > max - min) {
85         step = 1;
86         sliderPaintProperty->UpdateStep(step);
87     }
88     if (value_ < min || value_ > max) {
89         value_ = std::clamp(value_, min, max);
90         sliderPaintProperty->UpdateValue(value_);
91         FireChangeEvent(SliderChangeMode::End);
92     }
93 }
94 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool)95 bool SliderPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool /*skipLayout*/)
96 {
97     if (skipMeasure || dirty->SkipMeasureContent()) {
98         return false;
99     }
100 
101     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
102     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
103     auto sliderLayoutAlgorithm = DynamicCast<SliderLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
104     CHECK_NULL_RETURN(sliderLayoutAlgorithm, false);
105     trackThickness_ = sliderLayoutAlgorithm->GetTrackThickness();
106     blockDiameter_ = sliderLayoutAlgorithm->GetBlockDiameter();
107     blockHotSize_ = sliderLayoutAlgorithm->GetBlockHotSize();
108 
109     auto host = GetHost();
110     CHECK_NULL_RETURN(host, false);
111     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
112     CHECK_NULL_RETURN(sliderLayoutProperty, false);
113     std::optional<SizeF> contentSize = GetHostContentSize();
114     CHECK_NULL_RETURN(contentSize.has_value(), false);
115     float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
116                        ? contentSize.value().Width()
117                        : contentSize.value().Height();
118 
119     auto pipeline = PipelineContext::GetCurrentContext();
120     CHECK_NULL_RETURN(pipeline, false);
121     auto theme = pipeline->GetTheme<SliderTheme>();
122     CHECK_NULL_RETURN(theme, false);
123     Dimension hotBlockShadowWidth = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET) ==
124                                             SliderModel::SliderMode::OUTSET
125                                         ? theme->GetOutsetHotBlockShadowWidth()
126                                         : theme->GetInsetHotBlockShadowWidth();
127 
128     hotBlockShadowWidth_ = static_cast<float>(hotBlockShadowWidth.ConvertToPx());
129     borderBlank_ = std::max(trackThickness_, blockDiameter_ + hotBlockShadowWidth_ / HALF);
130     // slider track length
131     sliderLength_ = length >= borderBlank_ ? length - borderBlank_ : 1;
132     borderBlank_ = (length - sliderLength_) * HALF;
133 
134     return true;
135 }
136 
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)137 void SliderPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
138 {
139     if (touchEvent_) {
140         return;
141     }
142     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
143         auto pattern = weak.Upgrade();
144         CHECK_NULL_VOID_NOLOG(pattern);
145         pattern->HandleTouchEvent(info);
146     };
147     gestureHub->RemoveTouchEvent(touchEvent_);
148     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
149     gestureHub->AddTouchEvent(touchEvent_);
150 }
151 
HandleTouchEvent(const TouchEventInfo & info)152 void SliderPattern::HandleTouchEvent(const TouchEventInfo& info)
153 {
154     auto touchType = info.GetTouches().front().GetTouchType();
155     if (touchType == TouchType::DOWN) {
156         hotFlag_ = true;
157         UpdateValueByLocalLocation(info.GetChangedTouches().front().GetLocalLocation());
158         if (showTips_) {
159             bubbleFlag_ = true;
160             InitializeBubble();
161         }
162         mousePressedFlag_ = true;
163         FireChangeEvent(SliderChangeMode::Begin);
164         OpenTranslateAnimation();
165     } else if (touchType == TouchType::UP) {
166         hotFlag_ = false;
167         if (bubbleFlag_) {
168             bubbleFlag_ = false;
169         }
170         mousePressedFlag_ = false;
171         CloseTranslateAnimation();
172     }
173     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
174 }
175 
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)176 void SliderPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
177 {
178     if (clickListener_) {
179         return;
180     }
181     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
182         auto pattern = weak.Upgrade();
183         CHECK_NULL_VOID(pattern);
184         pattern->HandleClickEvent();
185     };
186     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
187     gestureHub->AddClickEvent(clickListener_);
188 }
189 
HandleClickEvent()190 void SliderPattern::HandleClickEvent()
191 {
192     FireChangeEvent(SliderChangeMode::Click);
193     FireChangeEvent(SliderChangeMode::End);
194 }
195 
InitializeBubble()196 void SliderPattern::InitializeBubble()
197 {
198     CHECK_NULL_VOID(bubbleFlag_);
199     auto frameNode = GetHost();
200     CHECK_NULL_VOID(frameNode);
201     auto pipeline = PipelineBase::GetCurrentContext();
202     CHECK_NULL_VOID(pipeline);
203     auto sliderTheme = pipeline->GetTheme<SliderTheme>();
204     CHECK_NULL_VOID(sliderTheme);
205     std::string content = std::to_string(static_cast<int>(std::round(valueRatio_ * 100.0f))) + '%';
206     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
207     sliderPaintProperty->UpdatePadding(sliderTheme->GetTipTextPadding());
208     sliderPaintProperty->UpdateTipColor(sliderTheme->GetTipColor());
209     sliderPaintProperty->UpdateTextColor(sliderTheme->GetTipTextColor());
210     sliderPaintProperty->UpdateFontSize(sliderTheme->GetTipFontSize());
211     sliderPaintProperty->UpdateContent(content);
212     UpdateBubble();
213 }
214 
HandlingGestureEvent(const GestureEvent & info)215 void SliderPattern::HandlingGestureEvent(const GestureEvent& info)
216 {
217     if (info.GetInputEventType() == InputEventType::AXIS) {
218         info.GetMainDelta() > 0.0 ? MoveStep(-1) : MoveStep(1);
219     } else {
220         UpdateValueByLocalLocation(info.GetLocalLocation());
221         UpdateBubble();
222     }
223     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
224 }
225 
HandledGestureEvent()226 void SliderPattern::HandledGestureEvent()
227 {
228     hotFlag_ = false;
229     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
230 }
231 
UpdateValueByLocalLocation(const std::optional<Offset> & localLocation)232 void SliderPattern::UpdateValueByLocalLocation(const std::optional<Offset>& localLocation)
233 {
234     CHECK_NULL_VOID(localLocation.has_value());
235     auto host = GetHost();
236     CHECK_NULL_VOID(host);
237     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
238     CHECK_NULL_VOID(sliderLayoutProperty);
239     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
240     float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
241                        ? static_cast<float>(localLocation->GetX())
242                        : static_cast<float>(localLocation->GetY());
243     float touchLength = sliderPaintProperty->GetReverse().value_or(false) ? borderBlank_ + sliderLength_ - length
244                                                                           : length - borderBlank_;
245     float min = sliderPaintProperty->GetMin().value_or(0.0f);
246     float max = sliderPaintProperty->GetMax().value_or(100.0f);
247     touchLength = std::clamp(touchLength, 0.0f, sliderLength_);
248     CHECK_NULL_VOID(sliderLength_ != 0);
249     valueRatio_ = touchLength / sliderLength_;
250     CHECK_NULL_VOID(stepRatio_ != 0);
251     valueRatio_ = NearEqual(valueRatio_, 1) ? 1 : std::round(valueRatio_ / stepRatio_) * stepRatio_;
252     float oldValue = value_;
253     value_ = valueRatio_ * (max - min) + min;
254     valueChangeFlag_ = !NearEqual(oldValue, value_);
255 }
256 
UpdateTipsValue()257 void SliderPattern::UpdateTipsValue()
258 {
259     CHECK_NULL_VOID_NOLOG(valueChangeFlag_);
260     CHECK_NULL_VOID_NOLOG(showTips_);
261     CHECK_NULL_VOID(bubbleFlag_);
262     auto frameNode = GetHost();
263     CHECK_NULL_VOID(frameNode);
264     std::string content = std::to_string(static_cast<int>(std::round(valueRatio_ * 100.0f))) + '%';
265     frameNode->GetPaintProperty<SliderPaintProperty>()->UpdateContent(content);
266 }
267 
UpdateCircleCenterOffset()268 void SliderPattern::UpdateCircleCenterOffset()
269 {
270     auto host = GetHost();
271     CHECK_NULL_VOID(host);
272     auto contentSize = GetHostContentSize();
273     CHECK_NULL_VOID(contentSize.has_value());
274     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
275     CHECK_NULL_VOID(sliderPaintProperty);
276     auto touchLength = valueRatio_ * sliderLength_;
277     auto touchOffset = sliderPaintProperty->GetReverse().value_or(false) ? sliderLength_ - touchLength + borderBlank_
278                                                                          : touchLength + borderBlank_;
279     if (sliderPaintProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
280         circleCenter_.SetX(touchOffset);
281         circleCenter_.SetY(contentSize->Height() * HALF);
282     } else {
283         circleCenter_.SetX(contentSize->Width() * HALF);
284         circleCenter_.SetY(touchOffset);
285     }
286 }
287 
UpdateBubbleSizeAndLayout()288 void SliderPattern::UpdateBubbleSizeAndLayout()
289 {
290     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
291     CHECK_NULL_VOID(paintProperty);
292     auto pipeline = PipelineBase::GetCurrentContext();
293     CHECK_NULL_VOID(pipeline);
294     auto theme = pipeline->GetTheme<SliderTheme>();
295     CHECK_NULL_VOID(theme);
296     SizeF textSize = { 0, 0 };
297     if (paragraph_) {
298         textSize = SizeF(paragraph_->GetMaxIntrinsicWidth(), paragraph_->GetHeight());
299     }
300     OffsetF textOffsetInBubble = { 0, 0 };
301     auto padding = static_cast<float>(paintProperty->GetPadding().value_or(0.0_vp).ConvertToPx());
302     float bubbleSizeHeight = textSize.Height() + padding + padding;
303     float bubbleSizeWidth = textSize.Width();
304     if (paintProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
305         bubbleSizeWidth = std::max(static_cast<float>(ARROW_WIDTH.ConvertToPx()), bubbleSizeWidth);
306         bubbleSize_ = SizeF(
307             bubbleSizeWidth + bubbleSizeHeight, bubbleSizeHeight + static_cast<float>(ARROW_HEIGHT.ConvertToPx()));
308         textOffsetInBubble.SetX((bubbleSize_.Width() - textSize.Width()) * HALF);
309         textOffsetInBubble.SetY(padding);
310 
311         bubbleOffset_.SetX(circleCenter_.GetX() - bubbleSize_.Width() * HALF);
312         bubbleOffset_.SetY(circleCenter_.GetY() -
313                            static_cast<float>(theme->GetBubbleToCircleCenterDistance().ConvertToPx()) -
314                            bubbleSize_.Height());
315     } else {
316         bubbleSizeHeight = std::max(static_cast<float>(ARROW_WIDTH.ConvertToPx()), bubbleSizeHeight);
317         bubbleSize_ =
318             SizeF(bubbleSizeWidth + static_cast<float>(ARROW_HEIGHT.ConvertToPx()), bubbleSizeHeight + bubbleSizeWidth);
319         textOffsetInBubble.SetY((bubbleSize_.Height() - textSize.Height()) * HALF);
320 
321         bubbleOffset_.SetY(circleCenter_.GetY() - bubbleSize_.Height() * HALF);
322         bubbleOffset_.SetX(circleCenter_.GetX() -
323                            static_cast<float>(theme->GetBubbleToCircleCenterDistance().ConvertToPx()) -
324                            bubbleSize_.Width());
325     }
326     textOffset_ = bubbleOffset_ + textOffsetInBubble;
327 }
328 
UpdateBubble()329 void SliderPattern::UpdateBubble()
330 {
331     CHECK_NULL_VOID_NOLOG(showTips_);
332     UpdateTipsValue();
333     CreateParagraphFunc();
334     UpdateCircleCenterOffset();
335     UpdateBubbleSizeAndLayout();
336     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
337 }
338 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)339 void SliderPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
340 {
341     if (direction_ == GetDirection() && panEvent_) {
342         return;
343     }
344     direction_ = GetDirection();
345     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
346         auto pattern = weak.Upgrade();
347         CHECK_NULL_VOID_NOLOG(pattern);
348         pattern->HandlingGestureEvent(info);
349     };
350     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
351         auto pattern = weak.Upgrade();
352         CHECK_NULL_VOID_NOLOG(pattern);
353         pattern->HandlingGestureEvent(info);
354         pattern->FireChangeEvent(SliderChangeMode::Moving);
355         pattern->CloseTranslateAnimation();
356     };
357     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& /*info*/) {
358         auto pattern = weak.Upgrade();
359         CHECK_NULL_VOID_NOLOG(pattern);
360         pattern->HandledGestureEvent();
361         pattern->FireChangeEvent(SliderChangeMode::End);
362     };
363     auto actionCancelTask = [weak = WeakClaim(this)]() {
364         auto pattern = weak.Upgrade();
365         CHECK_NULL_VOID_NOLOG(pattern);
366         pattern->HandledGestureEvent();
367         pattern->FireChangeEvent(SliderChangeMode::End);
368     };
369     if (panEvent_) {
370         gestureHub->RemovePanEvent(panEvent_);
371     }
372     panEvent_ = MakeRefPtr<PanEvent>(
373         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
374 
375     PanDirection panDirection;
376     panDirection.type = PanDirection::ALL;
377     float distance = static_cast<float>(Dimension(DEFAULT_PAN_DISTANCE, DimensionUnit::VP).ConvertToPx());
378     gestureHub->AddPanEvent(panEvent_, panDirection, 1, distance);
379 }
380 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)381 void SliderPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
382 {
383     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
384         auto pattern = wp.Upgrade();
385         CHECK_NULL_VOID_NOLOG(pattern);
386         pattern->GetInnerFocusPaintRect(paintRect);
387     };
388     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
389 
390     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
391         auto pattern = wp.Upgrade();
392         CHECK_NULL_RETURN_NOLOG(pattern, false);
393         return pattern->OnKeyEvent(event);
394     };
395     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
396 }
397 
GetInnerFocusPaintRect(RoundRect & paintRect)398 void SliderPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
399 {
400     auto host = GetHost();
401     CHECK_NULL_VOID(host);
402     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
403     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
404     if (sliderMode == SliderModel::SliderMode::OUTSET) {
405         GetOutsetInnerFocusPaintRect(paintRect);
406     } else {
407         GetInsetInnerFocusPaintRect(paintRect);
408     }
409 }
410 
GetOutsetInnerFocusPaintRect(RoundRect & paintRect)411 void SliderPattern::GetOutsetInnerFocusPaintRect(RoundRect& paintRect)
412 {
413     UpdateCircleCenterOffset();
414     const auto& content = GetHost()->GetGeometryNode()->GetContent();
415     CHECK_NULL_VOID(content);
416     auto contentOffset = content->GetRect().GetOffset();
417     auto theme = PipelineBase::GetCurrentContext()->GetTheme<SliderTheme>();
418     CHECK_NULL_VOID(theme);
419     auto appTheme = PipelineBase::GetCurrentContext()->GetTheme<AppTheme>();
420     CHECK_NULL_VOID(appTheme);
421     auto paintWidth = appTheme->GetFocusWidthVp();
422     auto focusSideDistance = theme->GetFocusSideDistance();
423     auto focusDistance = paintWidth * HALF + focusSideDistance;
424     auto focusRadius = blockDiameter_ * HALF + static_cast<float>(focusDistance.ConvertToPx());
425     paintRect.SetRect(RectF(circleCenter_.GetX() - focusRadius + contentOffset.GetX(),
426         circleCenter_.GetY() - focusRadius + contentOffset.GetY(), focusRadius / HALF, focusRadius / HALF));
427     paintRect.SetCornerRadius(focusRadius);
428 }
429 
GetInsetInnerFocusPaintRect(RoundRect & paintRect)430 void SliderPattern::GetInsetInnerFocusPaintRect(RoundRect& paintRect)
431 {
432     auto frameSize = GetHostFrameSize();
433     CHECK_NULL_VOID(frameSize);
434     auto theme = PipelineBase::GetCurrentContext()->GetTheme<SliderTheme>();
435     CHECK_NULL_VOID(theme);
436     auto focusSideDistance = theme->GetFocusSideDistance();
437     auto appTheme = PipelineBase::GetCurrentContext()->GetTheme<AppTheme>();
438     CHECK_NULL_VOID(appTheme);
439     auto paintWidth = appTheme->GetFocusWidthVp();
440     auto focusDistance = paintWidth * HALF + focusSideDistance;
441     float offsetX = 0;
442     float offsetY = 0;
443     float width = frameSize->Width();
444     float height = frameSize->Height();
445     float focusRadius = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
446     if (direction_ == Axis::HORIZONTAL) {
447         offsetX = borderBlank_ - trackThickness_ * HALF - static_cast<float>(focusDistance.ConvertToPx());
448         offsetY = (frameSize->Height() - trackThickness_) * HALF - static_cast<float>(focusDistance.ConvertToPx());
449         width = sliderLength_ + trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
450         height = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
451     } else {
452         offsetX = (frameSize->Width() - trackThickness_) * HALF - static_cast<float>(focusDistance.ConvertToPx());
453         offsetY = borderBlank_ - trackThickness_ * HALF - static_cast<float>(focusDistance.ConvertToPx());
454         width = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
455         height = sliderLength_ + trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
456     }
457     paintRect.SetRect(RectF(offsetX, offsetY, width, height));
458     paintRect.SetCornerRadius(focusRadius);
459 }
460 
PaintFocusState()461 void SliderPattern::PaintFocusState()
462 {
463     auto host = GetHost();
464     CHECK_NULL_VOID(host);
465     RoundRect focusRect;
466     GetInnerFocusPaintRect(focusRect);
467 
468     auto focusHub = host->GetFocusHub();
469     CHECK_NULL_VOID(focusHub);
470     focusHub->PaintInnerFocusState(focusRect);
471 
472     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
473 }
474 
OnKeyEvent(const KeyEvent & event)475 bool SliderPattern::OnKeyEvent(const KeyEvent& event)
476 {
477     if (event.action != KeyAction::DOWN) {
478         return false;
479     }
480     if ((direction_ == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
481         (direction_ == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
482         MoveStep(-1);
483         PaintFocusState();
484     }
485     if ((direction_ == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
486         (direction_ == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
487         MoveStep(1);
488         PaintFocusState();
489     }
490     return false;
491 }
492 
MoveStep(int32_t stepCount)493 bool SliderPattern::MoveStep(int32_t stepCount)
494 {
495     auto host = GetHost();
496     CHECK_NULL_RETURN(host, false);
497     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
498     CHECK_NULL_RETURN(sliderPaintProperty, false);
499     float step = sliderPaintProperty->GetStep().value_or(1.0f);
500     float min = sliderPaintProperty->GetMin().value_or(0.0f);
501     float max = sliderPaintProperty->GetMax().value_or(100.0f);
502     if (NearZero(step)) {
503         return false;
504     }
505     float nextValue = -1.0;
506     nextValue = value_ + static_cast<float>(stepCount) * step;
507     if (NearEqual(nextValue, -1.0)) {
508         return false;
509     }
510     nextValue = std::clamp(nextValue, min, max);
511     nextValue = std::round(nextValue / step) * step;
512     if (NearEqual(nextValue, value_)) {
513         return false;
514     }
515     value_ = nextValue;
516     valueRatio_ = (value_ - min) / (max - min);
517     LOGD("Move %{public}d steps, Value change to %{public}f", stepCount, value_);
518     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
519     return true;
520 }
521 
InitMouseEvent(const RefPtr<InputEventHub> & inputEventHub)522 void SliderPattern::InitMouseEvent(const RefPtr<InputEventHub>& inputEventHub)
523 {
524     auto hoverEvent = [weak = WeakClaim(this)](bool isHover) {
525         auto pattern = weak.Upgrade();
526         CHECK_NULL_VOID_NOLOG(pattern);
527         pattern->HandleHoverEvent(isHover);
528     };
529     if (hoverEvent_) {
530         inputEventHub->RemoveOnHoverEvent(hoverEvent_);
531     }
532     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverEvent));
533     inputEventHub->AddOnHoverEvent(hoverEvent_);
534 
535     auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
536         auto pattern = weak.Upgrade();
537         CHECK_NULL_VOID_NOLOG(pattern);
538         pattern->HandleMouseEvent(info);
539     };
540     if (mouseEvent_) {
541         inputEventHub->RemoveOnMouseEvent(mouseEvent_);
542     }
543     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
544     inputEventHub->AddOnMouseEvent(mouseEvent_);
545 }
546 
HandleHoverEvent(bool isHover)547 void SliderPattern::HandleHoverEvent(bool isHover)
548 {
549     mouseHoverFlag_ = mouseHoverFlag_ && isHover;
550     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
551 }
552 
HandleMouseEvent(const MouseInfo & info)553 void SliderPattern::HandleMouseEvent(const MouseInfo& info)
554 {
555     UpdateCircleCenterOffset();
556     auto mouseToCenterDistanceX = static_cast<float>(std::abs(info.GetLocalLocation().GetX() - circleCenter_.GetX()));
557     auto mouseToCenterDistanceY = static_cast<float>(std::abs(info.GetLocalLocation().GetY() - circleCenter_.GetY()));
558     float mouseToCenterDistance = std::max(mouseToCenterDistanceX, mouseToCenterDistanceY);
559     mouseHoverFlag_ = LessOrEqual(mouseToCenterDistance, blockHotSize_ * HALF);
560     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
561 }
562 
FireChangeEvent(int32_t mode)563 void SliderPattern::FireChangeEvent(int32_t mode)
564 {
565     auto sliderEventHub = GetEventHub<SliderEventHub>();
566     CHECK_NULL_VOID(sliderEventHub);
567     if ((mode == SliderChangeMode::Click || mode == SliderChangeMode::Moving) &&
568         NearEqual(value_, sliderEventHub->GetValue())) {
569         return;
570     }
571     sliderEventHub->FireChangeEvent(static_cast<float>(value_), mode);
572     valueChangeFlag_ = false;
573 }
574 
UpdateMarkDirtyNode(const PropertyChangeFlag & Flag)575 void SliderPattern::UpdateMarkDirtyNode(const PropertyChangeFlag& Flag)
576 {
577     auto host = GetHost();
578     CHECK_NULL_VOID(host);
579     host->MarkDirtyNode(Flag);
580 }
581 
GetDirection() const582 Axis SliderPattern::GetDirection() const
583 {
584     auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
585     CHECK_NULL_RETURN(sliderLayoutProperty, Axis::HORIZONTAL);
586     return sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
587 }
588 
CreateAccessibilityProperty()589 RefPtr<AccessibilityProperty> SliderPattern::CreateAccessibilityProperty()
590 {
591     return MakeRefPtr<SliderAccessibilityProperty>();
592 }
593 
CreateParagraphFunc()594 void SliderPattern::CreateParagraphFunc()
595 {
596     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
597     CHECK_NULL_VOID(paintProperty);
598     auto pipeline = PipelineBase::GetCurrentContext();
599     CHECK_NULL_VOID(pipeline);
600     auto sliderTheme = pipeline->GetTheme<SliderTheme>();
601     CHECK_NULL_VOID(sliderTheme);
602     auto fontStyle = std::make_unique<NG::FontStyle>();
603     fontStyle->UpdateTextColor(paintProperty->GetTextColor().value_or(sliderTheme->GetTipTextColor()));
604     TextStyle textStyle = CreateTextStyleUsingTheme(fontStyle, nullptr, pipeline->GetTheme<TextTheme>());
605     auto layoutProperty = GetLayoutProperty<SliderLayoutProperty>();
606     auto contentSize = layoutProperty->CreateContentConstraint();
607     CreateParagraphAndLayout(textStyle, paintProperty->GetContent().value_or(""), contentSize);
608 }
609 
CreateParagraphAndLayout(const TextStyle & textStyle,const std::string & content,const LayoutConstraintF & contentConstraint)610 void SliderPattern::CreateParagraphAndLayout(
611     const TextStyle& textStyle, const std::string& content, const LayoutConstraintF& contentConstraint)
612 {
613     if (!CreateParagraph(textStyle, content)) {
614         return;
615     }
616     CHECK_NULL_VOID(paragraph_);
617     auto size = contentConstraint.selfIdealSize;
618     size.UpdateIllegalSizeWithCheck(contentConstraint.maxSize);
619     auto maxSize = size.ConvertToSizeT();
620     paragraph_->Layout(maxSize.Width());
621 }
622 
CreateParagraph(const TextStyle & textStyle,std::string content)623 bool SliderPattern::CreateParagraph(const TextStyle& textStyle, std::string content)
624 {
625     ParagraphStyle paraStyle = { .direction = TextDirection::LTR,
626         .align = textStyle.GetTextAlign(),
627         .maxLines = textStyle.GetMaxLines(),
628         .fontLocale = Localization::GetInstance()->GetFontLocale(),
629         .wordBreak = textStyle.GetWordBreak(),
630         .textOverflow = textStyle.GetTextOverflow() };
631     paragraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
632     CHECK_NULL_RETURN(paragraph_, false);
633     paragraph_->PushStyle(textStyle);
634     StringUtils::TransformStrCase(content, static_cast<int32_t>(textStyle.GetTextCase()));
635     paragraph_->AddText(StringUtils::Str8ToStr16(content));
636     paragraph_->Build();
637     return true;
638 }
639 
UpdateContentParameters()640 SliderContentModifier::Parameters SliderPattern::UpdateContentParameters()
641 {
642     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
643     CHECK_NULL_RETURN(paintProperty, SliderContentModifier::Parameters());
644     auto pipeline = PipelineBase::GetCurrentContext();
645     CHECK_NULL_RETURN(pipeline, SliderContentModifier::Parameters());
646     auto theme = pipeline->GetTheme<SliderTheme>();
647     CHECK_NULL_RETURN(theme, SliderContentModifier::Parameters());
648     SliderContentModifier::Parameters parameters { trackThickness_, blockDiameter_, stepRatio_, hotBlockShadowWidth_,
649         mouseHoverFlag_, mousePressedFlag_ };
650     auto contentSize = GetHostContentSize();
651     auto contentOffset = GetHost()->GetGeometryNode()->GetContent()->GetRect().GetOffset();
652     // Distance between slide track and Content boundary
653     auto centerWidth = direction_ == Axis::HORIZONTAL ? contentSize->Height() : contentSize->Width();
654     centerWidth *= HALF;
655     parameters.selectColor = paintProperty->GetSelectColor().value_or(theme->GetTrackSelectedColor());
656     parameters.trackBackgroundColor = paintProperty->GetTrackBackgroundColor().value_or(theme->GetTrackBgColor());
657     parameters.blockColor = paintProperty->GetBlockColor().value_or(theme->GetBlockColor());
658 
659     GetSelectPosition(parameters, centerWidth, contentOffset);
660     GetBackgroundPosition(parameters, centerWidth, contentOffset);
661     GetCirclePosition(parameters, centerWidth, contentOffset);
662     return parameters;
663 }
664 
GetSelectPosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)665 void SliderPattern::GetSelectPosition(
666     SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
667 {
668     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
669     CHECK_NULL_VOID(paintProperty);
670     float sliderSelectLength = std::clamp(sliderLength_ * valueRatio_, 0.0f, sliderLength_);
671     PointF start;
672     PointF end;
673     if (!paintProperty->GetReverseValue(false)) {
674         start = direction_ == Axis::HORIZONTAL ? PointF(offset.GetX() + borderBlank_, offset.GetY() + centerWidth)
675                                                : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_);
676         end = direction_ == Axis::HORIZONTAL
677                   ? PointF(offset.GetX() + borderBlank_ + sliderSelectLength, offset.GetY() + centerWidth)
678                   : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderSelectLength);
679     } else {
680         start = direction_ == Axis::HORIZONTAL
681                     ? PointF(offset.GetX() + borderBlank_ + sliderLength_, offset.GetY() + centerWidth)
682                     : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_);
683         end =
684             direction_ == Axis::HORIZONTAL ?
685                 PointF(offset.GetX() + borderBlank_ + sliderLength_ - sliderSelectLength, offset.GetY() + centerWidth) :
686                 PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_ - sliderSelectLength);
687     }
688     parameters.selectStart = start;
689     parameters.selectEnd = end;
690 }
691 
GetBackgroundPosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)692 void SliderPattern::GetBackgroundPosition(
693     SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
694 {
695     auto startPointX = offset.GetX();
696     auto startPointY = offset.GetY();
697     auto start = direction_ == Axis::HORIZONTAL ? PointF(startPointX + borderBlank_, startPointY + centerWidth)
698                                                 : PointF(startPointX + centerWidth, startPointY + borderBlank_);
699     auto end = direction_ == Axis::HORIZONTAL
700                    ? PointF(startPointX + borderBlank_ + sliderLength_, startPointY + centerWidth)
701                    : PointF(startPointX + centerWidth, startPointY + borderBlank_ + sliderLength_);
702     parameters.backStart = start;
703     parameters.backEnd = end;
704 }
705 
GetCirclePosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)706 void SliderPattern::GetCirclePosition(
707     SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
708 {
709     float sliderSelectLength = std::clamp(sliderLength_ * valueRatio_, 0.0f, sliderLength_);
710     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
711     CHECK_NULL_VOID(paintProperty);
712     PointF center;
713     if (!paintProperty->GetReverseValue(false)) {
714         center = direction_ == Axis::HORIZONTAL
715                      ? PointF(offset.GetX() + borderBlank_ + sliderSelectLength, offset.GetY() + centerWidth)
716                      : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderSelectLength);
717     } else {
718         center =
719             direction_ == Axis::HORIZONTAL ?
720                 PointF(offset.GetX() + borderBlank_ + sliderLength_ - sliderSelectLength, offset.GetY() + centerWidth) :
721                 PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_ - sliderSelectLength);
722     }
723     parameters.circleCenter = center;
724 }
725 
OpenTranslateAnimation()726 void SliderPattern::OpenTranslateAnimation()
727 {
728     CHECK_NULL_VOID(sliderContentModifier_);
729     sliderContentModifier_->SetAnimated();
730 }
731 
CloseTranslateAnimation()732 void SliderPattern::CloseTranslateAnimation()
733 {
734     CHECK_NULL_VOID(sliderContentModifier_);
735     sliderContentModifier_->SetNotAnimated();
736 }
737 } // namespace OHOS::Ace::NG
738