• 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/ng/point_t.h"
19 #include "base/geometry/ng/size_t.h"
20 #include "base/geometry/offset.h"
21 #include "base/i18n/localization.h"
22 #include "base/utils/utf_helper.h"
23 #include "base/utils/utils.h"
24 #include "core/common/container.h"
25 #include "core/common/vibrator/vibrator_utils.h"
26 #include "core/components/slider/slider_theme.h"
27 #include "core/components/theme/app_theme.h"
28 #include "core/components_ng/pattern/image/image_layout_property.h"
29 #include "core/components_ng/pattern/image/image_pattern.h"
30 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
31 #include "core/components_ng/pattern/slider/slider_accessibility_property.h"
32 #include "core/components_ng/pattern/slider/slider_layout_property.h"
33 #include "core/components_ng/pattern/slider/slider_paint_property.h"
34 #include "core/components_ng/pattern/slider/slider_style.h"
35 #include "core/components_ng/pattern/text/text_layout_property.h"
36 #include "core/components_ng/pattern/text/text_pattern.h"
37 #include "core/components_ng/pattern/text/text_styles.h"
38 #include "core/components_ng/property/property.h"
39 #include "core/components_v2/inspector/inspector_constants.h"
40 #include "core/pipeline/pipeline_base.h"
41 #include "core/pipeline_ng/pipeline_context.h"
42 
43 namespace OHOS::Ace::NG {
44 namespace {
45 constexpr float HALF = 0.5;
46 constexpr float SLIDER_MIN = .0f;
47 constexpr float SLIDER_MAX = 100.0f;
48 constexpr Dimension BUBBLE_TO_SLIDER_DISTANCE = 10.0_vp;
49 constexpr Dimension FORM_PAN_DISTANCE = 1.0_vp;
50 constexpr double DEFAULT_SLIP_FACTOR = 50.0;
51 constexpr double SLIP_FACTOR_COEFFICIENT = 1.07;
52 constexpr uint64_t SCREEN_READ_SENDEVENT_TIMESTAMP = 400;
53 const std::string STR_SCREEN_READ_SENDEVENT = "ArkUISliderSendAccessibilityValueEvent";
54 const std::string SLIDER_EFFECT_ID_NAME = "haptic.slide";
55 #ifdef SUPPORT_DIGITAL_CROWN
56 constexpr float CROWN_SENSITIVITY_LOW = 0.5f;
57 constexpr float CROWN_SENSITIVITY_MEDIUM = 1.0f;
58 constexpr float CROWN_SENSITIVITY_HIGH = 2.0f;
59 constexpr int64_t CROWN_TIME_THRESH = 30;
60 constexpr char CROWN_VIBRATOR_WEAK[] = "watchhaptic.feedback.crown.strength2";
61 #endif
62 
GetReverseValue(RefPtr<SliderLayoutProperty> layoutProperty)63 bool GetReverseValue(RefPtr<SliderLayoutProperty> layoutProperty)
64 {
65     auto reverse = layoutProperty->GetReverseValue(false);
66     auto direction = layoutProperty->GetLayoutDirection();
67     auto axis = layoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
68     if (direction == TextDirection::AUTO && axis == Axis::HORIZONTAL) {
69         return AceApplicationInfo::GetInstance().IsRightToLeft() ? !reverse : reverse;
70     }
71     return direction == TextDirection::RTL ? !reverse : reverse;
72 }
73 } // namespace
74 
OnModifyDone()75 void SliderPattern::OnModifyDone()
76 {
77     Pattern::OnModifyDone();
78     FireBuilder();
79     auto host = GetHost();
80     CHECK_NULL_VOID(host);
81     auto hub = host->GetEventHub<EventHub>();
82     CHECK_NULL_VOID(hub);
83     auto gestureHub = hub->GetOrCreateGestureEventHub();
84     CHECK_NULL_VOID(gestureHub);
85     auto inputEventHub = hub->GetOrCreateInputEventHub();
86     CHECK_NULL_VOID(inputEventHub);
87     auto layoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
88     CHECK_NULL_VOID(layoutProperty);
89     layoutProperty->UpdateAlignment(Alignment::CENTER);
90     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
91     CHECK_NULL_VOID(sliderPaintProperty);
92     showTips_ = sliderPaintProperty->GetShowTips().value_or(false);
93     sliderInteractionMode_ =
94         sliderPaintProperty->GetSliderInteractionModeValue(SliderModelNG::SliderInteraction::SLIDE_AND_CLICK);
95     minResponse_ = sliderPaintProperty->GetMinResponsiveDistance().value_or(0.0f);
96     if (!panMoveFlag_) {
97         UpdateToValidValue();
98     }
99     UpdateBlock();
100     InitClickEvent(gestureHub);
101     InitTouchEvent(gestureHub);
102     InitPanEvent(gestureHub);
103     InitMouseEvent(inputEventHub);
104     auto focusHub = hub->GetFocusHub();
105     CHECK_NULL_VOID(focusHub);
106     InitOnKeyEvent(focusHub);
107     InitializeBubble();
108     SetAccessibilityAction();
109 #ifdef SUPPORT_DIGITAL_CROWN
110     crownSensitivity_ = sliderPaintProperty->GetDigitalCrownSensitivity().value_or(CrownSensitivity::MEDIUM);
111     InitDigitalCrownEvent(focusHub);
112 #endif
113     InitAccessibilityHoverEvent();
114     AccessibilityVirtualNodeRenderTask();
115     InitSliderAccessibilityEnabledRegister();
116     InitOrRefreshSlipFactor();
117     InitHapticController();
118 }
119 
PlayHapticFeedback(bool isShowSteps,float step,float oldValue)120 void SliderPattern::PlayHapticFeedback(bool isShowSteps, float step, float oldValue)
121 {
122     if (!isEnableHaptic_ || !hapticApiEnabled) {
123         return;
124     }
125     if (isShowSteps || NearEqual(valueRatio_, 1) || NearEqual(valueRatio_, 0)) {
126         VibratorUtils::StartViratorDirectly(SLIDER_EFFECT_ID_NAME);
127     }
128 }
InitHapticController()129 void SliderPattern::InitHapticController()
130 {
131     auto host = GetHost();
132     CHECK_NULL_VOID(host);
133     if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
134         hapticApiEnabled = true;
135     }
136 }
137 
HandleEnabled()138 void SliderPattern::HandleEnabled()
139 {
140     if (UseContentModifier()) {
141         return;
142     }
143     auto host = GetHost();
144     CHECK_NULL_VOID(host);
145     auto eventHub = host->GetEventHub<EventHub>();
146     CHECK_NULL_VOID(eventHub);
147     auto enabled = eventHub->IsEnabled();
148     auto renderContext = host->GetRenderContext();
149     CHECK_NULL_VOID(renderContext);
150     auto originalOpacity = renderContext->GetOpacityValue(1.0f);
151     if (enabled) {
152         renderContext->OnOpacityUpdate(originalOpacity);
153         return;
154     }
155     auto pipeline = host->GetContextWithCheck();
156     CHECK_NULL_VOID(pipeline);
157     auto theme = pipeline->GetTheme<SliderTheme>();
158     CHECK_NULL_VOID(theme);
159     auto alpha = theme->GetDisabledAlpha();
160     renderContext->OnOpacityUpdate(alpha * originalOpacity);
161 }
162 
InitAccessibilityHoverEvent()163 void SliderPattern::InitAccessibilityHoverEvent()
164 {
165     auto host = GetHost();
166     CHECK_NULL_VOID(host);
167     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
168     CHECK_NULL_VOID(accessibilityProperty);
169     auto level = accessibilityProperty->GetAccessibilityLevel();
170     auto eventHub = host->GetOrCreateInputEventHub();
171     CHECK_NULL_VOID(eventHub);
172     if (level == AccessibilityProperty::Level::NO_STR || level == AccessibilityProperty::Level::NO_HIDE_DESCENDANTS) {
173         ClearSliderVirtualNode();
174         return;
175     }
176 }
177 
178 class SliderAccessibilitySAObserverCallback : public AccessibilitySAObserverCallback {
179 public:
SliderAccessibilitySAObserverCallback(const WeakPtr<SliderPattern> & weakSliderPattern,int64_t accessibilityId)180     SliderAccessibilitySAObserverCallback(
181         const WeakPtr<SliderPattern> &weakSliderPattern, int64_t accessibilityId)
182         : AccessibilitySAObserverCallback(accessibilityId), weakSliderPattern_(weakSliderPattern)
183     {}
184 
185     ~SliderAccessibilitySAObserverCallback() override = default;
186 
OnState(bool state)187     bool OnState(bool state) override
188     {
189         auto sliderPattern = weakSliderPattern_.Upgrade();
190         CHECK_NULL_RETURN(sliderPattern, false);
191         if (state) {
192             sliderPattern->InitAccessibilityVirtualNodeTask();
193         }
194         sliderPattern->SetIsAccessibilityOn(state);
195         return true;
196     }
197 private:
198     WeakPtr<SliderPattern> weakSliderPattern_;
199 };
200 
InitSliderAccessibilityEnabledRegister()201 void SliderPattern::InitSliderAccessibilityEnabledRegister()
202 {
203     auto host = GetHost();
204     CHECK_NULL_VOID(host);
205     auto pipeline = host->GetContextRefPtr();
206     CHECK_NULL_VOID(pipeline);
207     auto accessibilityManager = pipeline->GetAccessibilityManager();
208     CHECK_NULL_VOID(accessibilityManager);
209     accessibilitySAObserverCallback_ = std::make_shared<SliderAccessibilitySAObserverCallback>(
210         WeakClaim(this), host->GetAccessibilityId());
211     accessibilityManager->RegisterAccessibilitySAObserverCallback(host->GetAccessibilityId(),
212         accessibilitySAObserverCallback_);
213 }
214 
InitAccessibilityVirtualNodeTask()215 void SliderPattern::InitAccessibilityVirtualNodeTask()
216 {
217     if (!isInitAccessibilityVirtualNode_ && CheckCreateAccessibilityVirtualNode()) {
218         auto host = GetHost();
219         CHECK_NULL_VOID(host);
220         auto pipeline = host->GetContextRefPtr();
221         CHECK_NULL_VOID(pipeline);
222         pipeline->AddAfterRenderTask(
223             [weak = WeakClaim(this)]() {
224                 auto sliderPattern = weak.Upgrade();
225                 CHECK_NULL_VOID(sliderPattern);
226                 sliderPattern->isInitAccessibilityVirtualNode_ = sliderPattern->InitAccessibilityVirtualNode();
227             });
228     }
229 }
230 
AccessibilityVirtualNodeRenderTask()231 void SliderPattern::AccessibilityVirtualNodeRenderTask()
232 {
233     if (isInitAccessibilityVirtualNode_ && CheckCreateAccessibilityVirtualNode()) {
234         auto host = GetHost();
235         CHECK_NULL_VOID(host);
236         auto pipeline = host->GetContextRefPtr();
237         CHECK_NULL_VOID(pipeline);
238         pipeline->AddAfterRenderTask([weak = WeakClaim(this)]() {
239             auto sliderPattern = weak.Upgrade();
240             CHECK_NULL_VOID(sliderPattern);
241             sliderPattern->ModifyAccessibilityVirtualNode();
242         });
243     }
244 }
245 
CheckCreateAccessibilityVirtualNode()246 bool SliderPattern::CheckCreateAccessibilityVirtualNode()
247 {
248     auto host = GetHost();
249     CHECK_NULL_RETURN(host, false);
250     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
251     CHECK_NULL_RETURN(sliderPaintProperty, false);
252     bool isShowSteps = sliderPaintProperty->GetShowStepsValue(false);
253     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
254     CHECK_NULL_RETURN(accessibilityProperty, false);
255     auto level = accessibilityProperty->GetAccessibilityLevel();
256     if (!AceApplicationInfo::GetInstance().IsAccessibilityEnabled() || UseContentModifier() || !isShowSteps ||
257         (level == AccessibilityProperty::Level::NO_STR) ||
258         (level == AccessibilityProperty::Level::NO_HIDE_DESCENDANTS)) {
259         return false;
260     }
261     return true;
262 }
263 
InitAccessibilityVirtualNode()264 bool SliderPattern::InitAccessibilityVirtualNode()
265 {
266     auto host = GetHost();
267     CHECK_NULL_RETURN(host, false);
268     parentAccessibilityNode_ = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG,
269         ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<LinearLayoutPattern>(true));
270     CHECK_NULL_RETURN(parentAccessibilityNode_, false);
271     auto parentNodeContext = parentAccessibilityNode_->GetRenderContext();
272     CHECK_NULL_RETURN(parentNodeContext, false);
273     parentNodeContext->UpdatePosition(OffsetT(Dimension(0.0f), Dimension(0.0f)));
274     AddStepPointsAccessibilityVirtualNode();
275     UpdateStepAccessibilityVirtualNode();
276     UpdateParentNodeSize();
277     parentAccessibilityNode_->SetAccessibilityNodeVirtual();
278     parentAccessibilityNode_->SetAccessibilityVirtualNodeParent(AceType::DynamicCast<NG::UINode>(host));
279     parentAccessibilityNode_->SetFirstAccessibilityVirtualNode();
280 
281     FrameNode::ProcessOffscreenNode(parentAccessibilityNode_);
282     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
283     accessibilityProperty->SaveAccessibilityVirtualNode(parentAccessibilityNode_);
284     ModifyAccessibilityVirtualNode();
285     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
286     return true;
287 }
288 
UpdateParentNodeSize()289 void SliderPattern::UpdateParentNodeSize()
290 {
291     auto pointCount = pointAccessibilityNodeEventVec_.size();
292     if (pointCount > 0) {
293         auto pointSize = GetStepPointAccessibilityVirtualNodeSize();
294         auto rowWidth = pointSize.Width();
295         auto rowHeight = pointSize.Height();
296         if (direction_ == Axis::HORIZONTAL) {
297             rowWidth = rowWidth * pointCount;
298         } else {
299             rowHeight = rowHeight * pointCount;
300         }
301         CHECK_NULL_VOID(parentAccessibilityNode_);
302         auto rowProperty = parentAccessibilityNode_->GetLayoutProperty<LinearLayoutProperty>();
303         CHECK_NULL_VOID(rowProperty);
304         rowProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(rowWidth), CalcLength(rowHeight)));
305     }
306 }
307 
ModifyAccessibilityVirtualNode()308 void SliderPattern::ModifyAccessibilityVirtualNode()
309 {
310     if (pointAccessibilityNodeVec_.empty()) {
311         return;
312     }
313     UpdateStepPointsAccessibilityVirtualNodeSelected();
314     auto host = GetHost();
315     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
316 }
317 
AddStepPointsAccessibilityVirtualNode()318 void SliderPattern::AddStepPointsAccessibilityVirtualNode()
319 {
320     CHECK_NULL_VOID(parentAccessibilityNode_);
321     CHECK_NULL_VOID(sliderContentModifier_);
322     parentAccessibilityNode_->GetRenderContext()->ClearChildren();
323     pointAccessibilityNodeVec_.clear();
324     pointAccessibilityNodeEventVec_.clear();
325     for (uint32_t i = 0; i < sliderContentModifier_->GetStepPointVec().size(); i++) {
326         auto pointNode = FrameNode::CreateFrameNode(
327             V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
328         parentAccessibilityNode_->AddChild(pointNode);
329         pointAccessibilityNodeVec_.emplace_back(pointNode);
330         pointAccessibilityNodeEventVec_.emplace_back(nullptr);
331     }
332 }
333 
UpdateStepAccessibilityVirtualNode()334 void SliderPattern::UpdateStepAccessibilityVirtualNode()
335 {
336     auto host = GetHost();
337     CHECK_NULL_VOID(host);
338     CHECK_NULL_VOID(parentAccessibilityNode_);
339     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
340     CHECK_NULL_VOID(sliderPaintProperty);
341     float step = sliderPaintProperty->GetStep().value_or(1.0f);
342     if (pointAccessibilityNodeVec_.empty() || NearZero(step)) {
343         return;
344     }
345     auto pointSize = GetStepPointAccessibilityVirtualNodeSize();
346     auto pointOffsetWidth = pointSize.Width() * HALF;
347     auto pointOffsetHeight = pointSize.Height() * HALF;
348     uint32_t pointCount = pointAccessibilityNodeVec_.size();
349     auto min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
350     auto max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
351     const std::vector<PointF>& stepPointVec = sliderContentModifier_->GetStepPointVec();
352     if (pointCount != stepPointVec.size()) {
353         return;
354     }
355     for (uint32_t i = 0; i < pointCount; i++) {
356         std::string txt = GetPointAccessibilityTxt(i, step, min, max);
357         SetStepPointAccessibilityVirtualNode(pointAccessibilityNodeVec_[i], pointSize,
358             PointF(stepPointVec[i].GetX() - pointOffsetWidth, stepPointVec[i].GetY() - pointOffsetHeight), txt);
359     }
360     parentAccessibilityNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
361 }
362 
GetPointAccessibilityTxt(uint32_t pointIndex,float step,float min,float max)363 std::string SliderPattern::GetPointAccessibilityTxt(uint32_t pointIndex, float step, float min, float max)
364 {
365     auto pointValue = min + pointIndex * step;
366     pointValue = std::round(std::clamp(pointValue, min, max) * 100.0f);
367     std::string str = std::to_string(pointValue / 100.0f);
368     size_t pos = str.find('.');
369     if (pos != std::string::npos) {
370         str.erase(str.find_last_not_of('0') + 1);
371         if (str.back() == '.') {
372             str.pop_back();
373         }
374     }
375     return str;
376 }
377 
SetStepPointAccessibilityVirtualNode(const RefPtr<FrameNode> & pointNode,const SizeF & size,const PointF & point,const std::string & txt)378 void SliderPattern::SetStepPointAccessibilityVirtualNode(
379     const RefPtr<FrameNode>& pointNode, const SizeF& size, const PointF& point, const std::string& txt)
380 {
381     CHECK_NULL_VOID(pointNode);
382     auto pointNodeProperty = pointNode->GetLayoutProperty<TextLayoutProperty>();
383     CHECK_NULL_VOID(pointNodeProperty);
384     pointNodeProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(size.Width()), CalcLength(size.Height())));
385     pointNodeProperty->UpdateContent(txt);
386     auto pointNodeContext = pointNode->GetRenderContext();
387     CHECK_NULL_VOID(pointNodeContext);
388     pointNodeContext->UpdatePosition(OffsetT(Dimension(point.GetX()), Dimension(point.GetY())));
389     auto pointAccessibilityProperty = pointNode->GetAccessibilityProperty<AccessibilityProperty>();
390     CHECK_NULL_VOID(pointAccessibilityProperty);
391     pointAccessibilityProperty->SetAccessibilityText(txt);
392 }
393 
UpdateStepPointsAccessibilityVirtualNodeSelected()394 void SliderPattern::UpdateStepPointsAccessibilityVirtualNodeSelected()
395 {
396     auto host = GetHost();
397     CHECK_NULL_VOID(host);
398     CHECK_NULL_VOID(parentAccessibilityNode_);
399     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
400     CHECK_NULL_VOID(sliderPaintProperty);
401     uint32_t pointCount = pointAccessibilityNodeVec_.size();
402     float step = sliderPaintProperty->GetStep().value_or(1.0f);
403     if (pointAccessibilityNodeVec_.empty() || NearZero(step)) {
404         return;
405     }
406     uint32_t rangeFromPointIndex = 0;
407     uint32_t rangeToPointIndex = pointCount;
408     uint32_t currentStepIndex = GetCurrentStepIndex();
409     auto reverse = GetReverseValue(GetLayoutProperty<SliderLayoutProperty>());
410     if (sliderPaintProperty->GetValidSlideRange().has_value()) {
411         auto range = sliderPaintProperty->GetValidSlideRange().value();
412         CHECK_NULL_VOID(range);
413         rangeFromPointIndex = range->GetFromValue() / step;
414         rangeToPointIndex = range->GetToValue() / step;
415     }
416     auto pipeline = GetContext();
417     CHECK_NULL_VOID(pipeline);
418     auto theme = pipeline->GetTheme<SliderTheme>();
419     CHECK_NULL_VOID(theme);
420     auto selectedTxt = theme->GetSelectedTxt();
421     auto unSelectedTxt = theme->GetUnselectedTxt();
422     auto unSelectedDesc = theme->GetUnselectedDesc();
423     auto disabledDesc = theme->GetDisabelDesc();
424     for (uint32_t i = 0; i < pointCount; i++) {
425         RefPtr<FrameNode>& pointNode = pointAccessibilityNodeVec_[i];
426         auto pointAccessibilityProperty = pointNode->GetAccessibilityProperty<TextAccessibilityProperty>();
427         pointAccessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::YES_STR);
428 
429         auto pointNodeProperty = pointNode->GetLayoutProperty<TextLayoutProperty>();
430         CHECK_NULL_VOID(pointNodeProperty);
431         auto valueTxt = UtfUtils::Str16ToStr8(pointNodeProperty->GetContent().value_or(u""));
432         if (currentStepIndex == i) {
433             pointAccessibilityProperty->SetAccessibilityText(selectedTxt + valueTxt);
434             pointAccessibilityProperty->SetAccessibilityDescription(" ");
435             SetStepPointsAccessibilityVirtualNodeEvent(pointNode, i, false, reverse);
436         } else if (i >= rangeFromPointIndex && i <= rangeToPointIndex) {
437             pointAccessibilityProperty->SetAccessibilityText(unSelectedTxt + valueTxt);
438             pointAccessibilityProperty->SetAccessibilityDescription(unSelectedDesc);
439             SetStepPointsAccessibilityVirtualNodeEvent(pointNode, i, true, reverse);
440         } else {
441             pointAccessibilityProperty->SetAccessibilityText(unSelectedTxt + valueTxt);
442             pointAccessibilityProperty->SetAccessibilityDescription(disabledDesc);
443         }
444     }
445 }
446 
SetStepPointsAccessibilityVirtualNodeEvent(const RefPtr<FrameNode> & pointNode,uint32_t index,bool isClickAbled,bool reverse)447 void SliderPattern::SetStepPointsAccessibilityVirtualNodeEvent(
448     const RefPtr<FrameNode>& pointNode, uint32_t index, bool isClickAbled, bool reverse)
449 {
450     CHECK_NULL_VOID(pointNode);
451     auto gestureHub = pointNode->GetOrCreateGestureEventHub();
452     CHECK_NULL_VOID(gestureHub);
453     if (isClickAbled && !pointAccessibilityNodeEventVec_[index]) {
454         auto clickHandle = [weak = WeakClaim(this), index, reverse](GestureEvent& info) {
455             auto pattern = weak.Upgrade();
456             CHECK_NULL_VOID(pattern);
457             pattern->FireChangeEvent(SliderChangeMode::Begin);
458             auto offsetStep = index - pattern->GetCurrentStepIndex();
459             pattern->MoveStep(offsetStep);
460             pattern->FireChangeEvent(SliderChangeMode::End);
461             if (pattern->showTips_) {
462                 pattern->bubbleFlag_ = true;
463                 pattern->InitializeBubble();
464             }
465             pattern->PaintFocusState();
466             pattern->UpdateStepPointsAccessibilityVirtualNodeSelected();
467         };
468         gestureHub->SetUserOnClick(clickHandle);
469         pointAccessibilityNodeEventVec_[index] = clickHandle;
470     } else if (!isClickAbled && pointAccessibilityNodeEventVec_[index]) {
471         gestureHub->ClearUserOnClick();
472         pointAccessibilityNodeEventVec_[index] = nullptr;
473     }
474 }
475 
GetCurrentStepIndex()476 uint32_t SliderPattern::GetCurrentStepIndex()
477 {
478     auto host = GetHost();
479     CHECK_NULL_RETURN(host, false);
480     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
481     const float step = sliderPaintProperty->GetStep().value_or(1.0f);
482     const float currentValue = sliderPaintProperty->GetValueValue(value_);
483     const double min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
484     if (NearZero(step)) {
485         return 0;
486     }
487     return static_cast<uint32_t>(std::ceil((currentValue - min) / step));
488 }
489 
GetStepPointAccessibilityVirtualNodeSize()490 SizeF SliderPattern::GetStepPointAccessibilityVirtualNodeSize()
491 {
492     auto host = GetHost();
493     CHECK_NULL_RETURN(host, SizeF());
494     auto pointCount = pointAccessibilityNodeEventVec_.size();
495     if (pointCount <= 1) {
496         return SizeF();
497     }
498     float pointNodeHeight = sliderLength_ / (pointCount - 1);
499     float pointNodeWidth = pointNodeHeight;
500     auto geometryNode = host->GetGeometryNode();
501     CHECK_NULL_RETURN(geometryNode, SizeF());
502     auto& hostContent = geometryNode->GetContent();
503     CHECK_NULL_RETURN(hostContent, SizeF());
504     if (direction_ == Axis::HORIZONTAL) {
505         pointNodeHeight = hostContent->GetRect().Height();
506     } else {
507         pointNodeWidth = hostContent->GetRect().Width();
508     }
509     return SizeF(pointNodeWidth, pointNodeHeight);
510 }
511 
CalcSliderValue()512 void SliderPattern::CalcSliderValue()
513 {
514     auto host = GetHost();
515     CHECK_NULL_VOID(host);
516     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
517     CHECK_NULL_VOID(sliderPaintProperty);
518     float min = sliderPaintProperty->GetMin().value_or(0.0f);
519     float max = sliderPaintProperty->GetMax().value_or(100.0f);
520     value_ = sliderPaintProperty->GetValue().value_or(min);
521     float step = sliderPaintProperty->GetStep().value_or(1.0f);
522     CancelExceptionValue(min, max, step);
523     valueRatio_ = (value_ - min) / (max - min);
524 }
525 
CancelExceptionValue(float & min,float & max,float & step)526 void SliderPattern::CancelExceptionValue(float& min, float& max, float& step)
527 {
528     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
529     CHECK_NULL_VOID(sliderPaintProperty);
530     if (GreatOrEqual(min, max)) {
531         min = SLIDER_MIN;
532         max = SLIDER_MAX;
533         sliderPaintProperty->UpdateMin(min);
534         sliderPaintProperty->UpdateMax(max);
535     }
536     if (LessOrEqual(step, 0.0) || step > max - min) {
537         step = 1;
538         sliderPaintProperty->UpdateStep(step);
539     }
540     if (value_ < min || value_ > max) {
541         value_ = std::clamp(value_, min, max);
542         sliderPaintProperty->UpdateValue(value_);
543         auto host = GetHost();
544         CHECK_NULL_VOID(host);
545         auto context = host->GetContext();
546         CHECK_NULL_VOID(context);
547         context->AddAfterRenderTask([weak = WeakClaim(this)]() {
548             auto pattern = weak.Upgrade();
549             CHECK_NULL_VOID(pattern);
550             pattern->FireChangeEvent(SliderChangeMode::End);
551         });
552     }
553 }
554 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool)555 bool SliderPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool /*skipLayout*/)
556 {
557     if (skipMeasure || dirty->SkipMeasureContent()) {
558         return false;
559     }
560 
561     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
562     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
563     auto sliderLayoutAlgorithm = DynamicCast<SliderLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
564     CHECK_NULL_RETURN(sliderLayoutAlgorithm, false);
565     trackThickness_ = sliderLayoutAlgorithm->GetTrackThickness();
566     blockSize_ = sliderLayoutAlgorithm->GetBlockSize();
567     blockHotSize_ = sliderLayoutAlgorithm->GetBlockHotSize();
568     return UpdateParameters();
569 }
570 
ClearSliderVirtualNode()571 void SliderPattern::ClearSliderVirtualNode()
572 {
573     auto host = GetHost();
574     CHECK_NULL_VOID(host);
575     pointAccessibilityNodeVec_.clear();
576     pointAccessibilityNodeEventVec_.clear();
577     isInitAccessibilityVirtualNode_ = false;
578     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
579     CHECK_NULL_VOID(accessibilityProperty);
580     accessibilityProperty->SaveAccessibilityVirtualNode(nullptr);
581     auto eventHub = host->GetOrCreateInputEventHub();
582     CHECK_NULL_VOID(eventHub);
583     eventHub->ClearUserOnAccessibilityHover();
584 }
585 
UpdateParameters()586 bool SliderPattern::UpdateParameters()
587 {
588     auto host = GetHost();
589     CHECK_NULL_RETURN(host, false);
590     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
591     CHECK_NULL_RETURN(sliderLayoutProperty, false);
592     std::optional<SizeF> contentSize = GetHostContentSize();
593     CHECK_NULL_RETURN(contentSize.has_value(), false);
594     float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
595                        ? contentSize.value().Width()
596                        : contentSize.value().Height();
597 
598     auto pipeline = GetContext();
599     CHECK_NULL_RETURN(pipeline, false);
600     auto theme = pipeline->GetTheme<SliderTheme>();
601     CHECK_NULL_RETURN(theme, false);
602     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
603     Dimension hotBlockShadowWidth = sliderMode == SliderModel::SliderMode::OUTSET
604                                         ? theme->GetOutsetHotBlockShadowWidth()
605                                         : theme->GetInsetHotBlockShadowWidth();
606 
607     auto direction = sliderLayoutProperty->GetDirectionValue(Axis::HORIZONTAL);
608     auto blockLength = direction == Axis::HORIZONTAL ? blockSize_.Width() : blockSize_.Height();
609 
610     hotBlockShadowWidth_ = static_cast<float>(hotBlockShadowWidth.ConvertToPx());
611     if (sliderMode_ != sliderMode && isAccessibilityOn_) {
612         ClearSliderVirtualNode();
613         InitAccessibilityVirtualNodeTask();
614         InitAccessibilityHoverEvent();
615         sliderMode_ = sliderMode;
616     }
617     if (sliderMode == SliderModel::SliderMode::OUTSET) {
618         borderBlank_ = std::max(trackThickness_, blockLength + hotBlockShadowWidth_ / HALF);
619     } else if (sliderMode == SliderModel::SliderMode::INSET) {
620         borderBlank_ = trackThickness_ + hotBlockShadowWidth_ / HALF;
621     } else {
622         borderBlank_ = 0;
623     }
624     // slider track length
625     sliderLength_ = length >= borderBlank_ ? length - borderBlank_ : 1;
626     borderBlank_ = (length - sliderLength_) * HALF;
627 
628     return true;
629 }
630 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)631 void SliderPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
632 {
633     if (type == WindowSizeChangeReason::ROTATION &&
634         Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
635         SetSkipGestureEvents();
636     }
637 }
638 
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)639 void SliderPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
640 {
641     if (clickListener_) {
642         return;
643     }
644     auto clickCallback = [](const GestureEvent& info) {};
645     clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
646     gestureHub->AddClickEvent(clickListener_);
647 }
648 
InitTouchEvent(const RefPtr<GestureEventHub> & gestureHub)649 void SliderPattern::InitTouchEvent(const RefPtr<GestureEventHub>& gestureHub)
650 {
651     if (UseContentModifier()) {
652         if (touchEvent_) {
653             gestureHub->RemoveTouchEvent(touchEvent_);
654             touchEvent_ = nullptr;
655         }
656         return;
657     }
658     if (touchEvent_) {
659         return;
660     }
661     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
662         auto pattern = weak.Upgrade();
663         CHECK_NULL_VOID(pattern);
664         pattern->HandleTouchEvent(info);
665     };
666     gestureHub->RemoveTouchEvent(touchEvent_);
667     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
668     gestureHub->AddTouchEvent(touchEvent_);
669 }
670 
AtMousePanArea(const Offset & offsetInFrame)671 bool SliderPattern::AtMousePanArea(const Offset& offsetInFrame)
672 {
673     auto host = GetHost();
674     CHECK_NULL_RETURN(host, false);
675     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
676     CHECK_NULL_RETURN(sliderLayoutProperty, false);
677     const auto& content = host->GetGeometryNode()->GetContent();
678     CHECK_NULL_RETURN(content, false);
679     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
680     auto contentOffset = content->GetRect().GetOffset();
681     auto offset = Offset(offsetInFrame.GetX() - contentOffset.GetX(), offsetInFrame.GetY() - contentOffset.GetY());
682     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
683     CHECK_NULL_RETURN(paintProperty, false);
684     auto blockType = paintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT);
685     if (sliderMode == SliderModel::SliderMode::NONE) {
686         float sideHotSizeX = blockHotSize_.Width() * HALF;
687         float sideHotSizeY = blockHotSize_.Height() * HALF;
688         return !(circleCenter_.GetX() - sideHotSizeX > offset.GetX() ||
689                  circleCenter_.GetY() - sideHotSizeY > offset.GetY() ||
690                  circleCenter_.GetX() + sideHotSizeX < offset.GetX() ||
691                  circleCenter_.GetY() + sideHotSizeY < offset.GetY());
692     } else if (blockType == SliderModelNG::BlockStyleType::DEFAULT) {
693         double distanceCircle = std::min(blockSize_.Width(), blockSize_.Height()) * HALF + hotBlockShadowWidth_;
694         auto diffX = circleCenter_.GetX() - offset.GetX();
695         auto diffY = circleCenter_.GetY() - offset.GetY();
696         return diffX * diffX + diffY * diffY <= distanceCircle * distanceCircle;
697     } else {
698         float sideHotSizeX = blockSize_.Width() * HALF;
699         float sideHotSizeY = blockSize_.Height() * HALF;
700         return !(circleCenter_.GetX() - sideHotSizeX > offset.GetX() ||
701                  circleCenter_.GetY() - sideHotSizeY > offset.GetY() ||
702                  circleCenter_.GetX() + sideHotSizeX < offset.GetX() ||
703                  circleCenter_.GetY() + sideHotSizeY < offset.GetY());
704     }
705 }
706 
AtTouchPanArea(const Offset & offsetInFrame)707 bool SliderPattern::AtTouchPanArea(const Offset& offsetInFrame)
708 {
709     const auto& content = GetHost()->GetGeometryNode()->GetContent();
710     CHECK_NULL_RETURN(content, false);
711     auto contentOffset = content->GetRect().GetOffset();
712     auto offset = Offset(offsetInFrame.GetX() - contentOffset.GetX(), offsetInFrame.GetY() - contentOffset.GetY());
713     float sideHotSizeX = blockHotSize_.Width() * HALF;
714     float sideHotSizeY = blockHotSize_.Height() * HALF;
715     return !(circleCenter_.GetX() - sideHotSizeX > offset.GetX() ||
716         circleCenter_.GetY() - sideHotSizeY > offset.GetY() ||
717         circleCenter_.GetX() + sideHotSizeX < offset.GetX() ||
718         circleCenter_.GetY() + sideHotSizeY < offset.GetY());
719 }
720 
AtPanArea(const Offset & offset,const SourceType & sourceType)721 bool SliderPattern::AtPanArea(const Offset& offset, const SourceType& sourceType)
722 {
723     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
724     CHECK_NULL_RETURN(sliderPaintProperty, false);
725     auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
726     CHECK_NULL_RETURN(sliderLayoutProperty, false);
727     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
728     if (sliderPaintProperty->GetSliderInteractionModeValue(SliderModelNG::SliderInteraction::SLIDE_AND_CLICK) ==
729         SliderModelNG::SliderInteraction::SLIDE_AND_CLICK &&
730         (sliderPaintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT) !=
731         SliderModelNG::BlockStyleType::DEFAULT ||
732         sliderMode == SliderModel::SliderMode::NONE)) {
733         return false;
734     }
735     bool flag = false;
736     switch (sourceType) {
737         case SourceType::MOUSE:
738             flag = AtMousePanArea(offset);
739             break;
740         case SourceType::TOUCH:
741             flag = AtTouchPanArea(offset);
742             break;
743         case SourceType::NONE:
744         default:
745             break;
746     }
747     return flag;
748 }
749 
HandleTouchEvent(const TouchEventInfo & info)750 void SliderPattern::HandleTouchEvent(const TouchEventInfo& info)
751 {
752     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider handle touch event");
753     auto touchList = info.GetChangedTouches();
754     CHECK_NULL_VOID(!touchList.empty());
755     auto touchInfo = touchList.front();
756     auto touchType = touchInfo.GetTouchType();
757     if (touchType == TouchType::DOWN) {
758         ResetSkipGestureEvents();
759         if (fingerId_ != -1) {
760             return;
761         }
762         fingerId_ = touchInfo.GetFingerId();
763         HandleTouchDown(touchInfo.GetLocalLocation(), info.GetSourceDevice());
764     } else if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
765         ResetSkipGestureEvents();
766         if (fingerId_ != touchInfo.GetFingerId()) {
767             return;
768         }
769         HandleTouchUp(touchInfo.GetLocalLocation(), info.GetSourceDevice());
770         fingerId_ = -1;
771     }
772     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
773 }
774 
HandleTouchDown(const Offset & location,SourceType sourceType)775 void SliderPattern::HandleTouchDown(const Offset& location, SourceType sourceType)
776 {
777     axisFlag_ = false;
778     if (sliderInteractionMode_ == SliderModelNG::SliderInteraction::SLIDE_AND_CLICK) {
779         allowDragEvents_ = true;
780         if (!AtPanArea(location, sourceType)) {
781             UpdateValueByLocalLocation(location);
782         }
783     } else if (sliderInteractionMode_ == SliderModelNG::SliderInteraction::SLIDE_AND_CLICK_UP) {
784         lastTouchLocation_ = location;
785     }
786     if (showTips_) {
787         bubbleFlag_ = true;
788         UpdateBubble();
789     }
790     mousePressedFlag_ = true;
791     FireChangeEvent(SliderChangeMode::Begin);
792     OpenTranslateAnimation(SliderStatus::CLICK);
793     CHECK_NULL_VOID(sliderContentModifier_);
794     sliderContentModifier_->SetIsPressed(true);
795 }
796 
NeedFireClickEvent(const Offset & downLocation,const Offset & upLocation)797 bool NeedFireClickEvent(const Offset& downLocation, const Offset& upLocation)
798 {
799     auto diff = downLocation - upLocation;
800     return diff.GetDistance() < DEFAULT_PAN_DISTANCE.ConvertToPx();
801 }
802 
HandleTouchUp(const Offset & location,SourceType sourceType)803 void SliderPattern::HandleTouchUp(const Offset& location, SourceType sourceType)
804 {
805     if (sliderInteractionMode_ == SliderModelNG::SliderInteraction::SLIDE_AND_CLICK_UP &&
806         lastTouchLocation_.has_value() && NeedFireClickEvent(lastTouchLocation_.value(), location)) {
807         allowDragEvents_ = true;
808         if (!AtPanArea(location, sourceType)) {
809             UpdateValueByLocalLocation(location);
810         }
811         UpdateToValidValue();
812         FireChangeEvent(SliderChangeMode::Click);
813     } else {
814         UpdateToValidValue();
815     }
816     if (bubbleFlag_ && !isFocusActive_) {
817         bubbleFlag_ = false;
818     }
819     mousePressedFlag_ = false;
820     if (sliderInteractionMode_ != SliderModelNG::SliderInteraction::SLIDE_AND_CLICK_UP) {
821         FireChangeEvent(SliderChangeMode::Click);
822     }
823     isTouchUpFlag_ = true;
824     FireChangeEvent(SliderChangeMode::End);
825     CloseTranslateAnimation();
826     CHECK_NULL_VOID(sliderContentModifier_);
827     sliderContentModifier_->SetIsPressed(false);
828 }
829 
InitializeBubble()830 void SliderPattern::InitializeBubble()
831 {
832     CHECK_NULL_VOID(showTips_);
833     auto frameNode = GetHost();
834     CHECK_NULL_VOID(frameNode);
835     auto pipeline = frameNode->GetContext();
836     CHECK_NULL_VOID(pipeline);
837     auto sliderTheme = pipeline->GetTheme<SliderTheme>();
838     CHECK_NULL_VOID(sliderTheme);
839     valueRatio_ = std::clamp(valueRatio_, 0.0f, 1.0f);
840     std::string content = std::to_string(static_cast<int>(std::round(valueRatio_ * 100.0f))) + '%';
841     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
842     sliderPaintProperty->UpdatePadding(sliderTheme->GetTipTextPadding());
843     sliderPaintProperty->UpdateTipColor(sliderTheme->GetTipColor());
844     sliderPaintProperty->UpdateTextColor(sliderTheme->GetTipTextColor());
845     sliderPaintProperty->UpdateFontSize(sliderTheme->GetTipFontSize());
846     sliderPaintProperty->UpdateContent(content);
847 }
848 
HandlingGestureStart(const GestureEvent & info)849 void SliderPattern::HandlingGestureStart(const GestureEvent& info)
850 {
851     eventSourceDevice_ = info.GetSourceDevice();
852     eventLocalLocation_ = info.GetLocalLocation();
853     allowDragEvents_ = (sliderInteractionMode_ != SliderModelNG::SliderInteraction::SLIDE_ONLY ||
854                         AtPanArea(eventLocalLocation_, eventSourceDevice_));
855     if (info.GetInputEventType() != InputEventType::AXIS) {
856         minResponseStartValue_ = value_;
857         isMinResponseExceedFlag_ = false;
858         if (allowDragEvents_ && isMinResponseExceed(eventLocalLocation_)) {
859             UpdateValueByLocalLocation(eventLocalLocation_);
860             UpdateBubble();
861         }
862     }
863     panMoveFlag_ = allowDragEvents_;
864     if (panMoveFlag_) {
865         auto host = GetHost();
866         CHECK_NULL_VOID(host);
867         host->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
868     }
869     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
870 }
871 
HandlingGestureEvent(const GestureEvent & info)872 void SliderPattern::HandlingGestureEvent(const GestureEvent& info)
873 {
874     if (info.GetInputEventType() == InputEventType::AXIS) {
875         auto reverse = GetReverseValue(GetLayoutProperty<SliderLayoutProperty>());
876         if (info.GetSourceTool() == SourceTool::MOUSE) {
877             auto offset = NearZero(info.GetOffsetX()) ? info.GetOffsetY() : info.GetOffsetX();
878             if (direction_ == Axis::HORIZONTAL) {
879                 offset > 0.0 ? MoveStep(1) : MoveStep(-1);
880             } else {
881                 reverse ? (offset > 0.0 ? MoveStep(1) : MoveStep(-1)) : (offset > 0.0 ? MoveStep(-1) : MoveStep(1));
882             }
883         } else {
884             auto offset = (direction_ == Axis::HORIZONTAL ? info.GetOffsetX() : info.GetOffsetY()) - axisOffset_;
885             auto slipfactor = slipfactor_ > 0 ? slipfactor_ : DEFAULT_SLIP_FACTOR;
886             if (std::abs(offset) > slipfactor) {
887                 auto stepCount = static_cast<int32_t>(offset / slipfactor);
888                 MoveStep(reverse ? -stepCount : stepCount);
889                 axisOffset_ += slipfactor * stepCount;
890             }
891         }
892         if (hotFlag_) {
893             axisFlag_ = true;
894         }
895         if (showTips_ && axisFlag_) {
896             bubbleFlag_ = true;
897             InitializeBubble();
898         }
899     } else {
900         auto fingerList = info.GetFingerList();
901         panMoveFlag_ = false;
902         if (fingerList.size() > 0) {
903             for (auto fingerInfo : fingerList) {
904                 if (fingerInfo.fingerId_ == fingerId_) {
905                     if (allowDragEvents_ && isMinResponseExceed(fingerInfo.localLocation_)) {
906                         UpdateValueByLocalLocation(fingerInfo.localLocation_);
907                         UpdateBubble();
908                         panMoveFlag_ = true;
909                         UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
910                     }
911                 }
912             }
913         } else {
914             if (allowDragEvents_ && isMinResponseExceed(info.GetLocalLocation())) {
915                 UpdateValueByLocalLocation(info.GetLocalLocation());
916                 UpdateBubble();
917                 panMoveFlag_ = true;
918                 UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
919             }
920         }
921     }
922 }
923 
HandledGestureEvent()924 void SliderPattern::HandledGestureEvent()
925 {
926     panMoveFlag_ = false;
927     axisOffset_ = 0.0;
928     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
929 }
930 
CalculateGlobalSafeOffset()931 OffsetF SliderPattern::CalculateGlobalSafeOffset()
932 {
933     auto host = GetHost();
934     CHECK_NULL_RETURN(host, OffsetF());
935     auto overlayGlobalOffset = host->GetPaintRectOffset(false, true);
936     auto pipelineContext = host->GetContext();
937     CHECK_NULL_RETURN(pipelineContext, OffsetF());
938     auto safeAreaManger = pipelineContext->GetSafeAreaManager();
939     CHECK_NULL_RETURN(safeAreaManger, OffsetF());
940     auto top = safeAreaManger->GetSystemSafeArea().top_.Length();
941     overlayGlobalOffset.SetY(overlayGlobalOffset.GetY() - top);
942     auto windowWrapperOffset = safeAreaManger->GetWindowWrapperOffset();
943     overlayGlobalOffset -= windowWrapperOffset;
944     return overlayGlobalOffset;
945 }
946 
isMinResponseExceed(const std::optional<Offset> & localLocation)947 bool SliderPattern::isMinResponseExceed(const std::optional<Offset>& localLocation)
948 {
949     if (isMinResponseExceedFlag_) {
950         return true;
951     }
952     if (LessOrEqual(minResponse_, 0.0f)) {
953         isMinResponseExceedFlag_ = true;
954         return true;
955     }
956     CHECK_NULL_RETURN(allowDragEvents_, false);
957     CHECK_NULL_RETURN(localLocation.has_value(), false);
958     auto host = GetHost();
959     CHECK_NULL_RETURN(host, false);
960     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
961     CHECK_NULL_RETURN(sliderLayoutProperty, false);
962     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
963     CHECK_NULL_RETURN(sliderPaintProperty, false);
964     const auto& content = host->GetGeometryNode()->GetContent();
965     CHECK_NULL_RETURN(content, false);
966     auto contentOffset = content->GetRect().GetOffset();
967     float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
968                        ? static_cast<float>(localLocation->GetX() - contentOffset.GetX())
969                        : static_cast<float>(localLocation->GetY() - contentOffset.GetY());
970     float touchLength =
971         GetReverseValue(sliderLayoutProperty) ? borderBlank_ + sliderLength_ - length : length - borderBlank_;
972     float min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
973     float max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
974     CHECK_NULL_RETURN(GreatNotEqual(sliderLength_, 0.0f), false);
975     float valueRatio = touchLength / sliderLength_;
976     float value = valueRatio * (max - min) + min;
977     if (GreatOrEqual(std::abs(minResponseStartValue_ - value), minResponse_)) {
978         isMinResponseExceedFlag_ = true;
979         return true;
980     }
981     return false;
982 }
983 
UpdateValueByLocalLocation(const std::optional<Offset> & localLocation)984 void SliderPattern::UpdateValueByLocalLocation(const std::optional<Offset>& localLocation)
985 {
986     CHECK_NULL_VOID(localLocation.has_value());
987     auto host = GetHost();
988     CHECK_NULL_VOID(host);
989     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
990     CHECK_NULL_VOID(sliderLayoutProperty);
991     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
992     CHECK_NULL_VOID(sliderPaintProperty);
993     auto geometryNode = host->GetGeometryNode();
994     CHECK_NULL_VOID(geometryNode);
995     const auto& content = geometryNode->GetContent();
996     CHECK_NULL_VOID(content);
997     auto contentOffset = content->GetRect().GetOffset();
998     float length = sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL
999                        ? static_cast<float>(localLocation->GetX() - contentOffset.GetX())
1000                        : static_cast<float>(localLocation->GetY() - contentOffset.GetY());
1001     float touchLength =
1002         GetReverseValue(sliderLayoutProperty) ? borderBlank_ + sliderLength_ - length : length - borderBlank_;
1003     float min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
1004     float max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
1005     float step = sliderPaintProperty->GetStep().value_or(1.0f);
1006     touchLength = std::clamp(touchLength, 0.0f, sliderLength_);
1007     CHECK_NULL_VOID(sliderLength_ != 0);
1008     valueRatio_ = touchLength / sliderLength_;
1009     auto stepRatio = sliderPaintProperty->GetStepRatio();
1010     CHECK_NULL_VOID(stepRatio != 0);
1011     valueRatio_ = NearEqual(valueRatio_, 1) ? 1 : std::round(valueRatio_ / stepRatio) * stepRatio;
1012 
1013     float oldValue = value_;
1014     value_ = NearEqual(valueRatio_, 1) ? max : (std::round(valueRatio_ / stepRatio) * step + min);
1015     value_ = std::clamp(value_, min, max);
1016     sliderPaintProperty->UpdateValue(value_);
1017     valueChangeFlag_ = !NearEqual(oldValue, value_);
1018     bool isShowSteps = sliderPaintProperty->GetShowStepsValue(false);
1019     if (valueChangeFlag_) {
1020         PlayHapticFeedback(isShowSteps, step, oldValue);
1021     }
1022     UpdateCircleCenterOffset();
1023 }
1024 
UpdateToValidValue()1025 void SliderPattern::UpdateToValidValue()
1026 {
1027     auto host = GetHost();
1028     CHECK_NULL_VOID(host);
1029     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
1030     CHECK_NULL_VOID(sliderPaintProperty);
1031 
1032     float min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
1033     float max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
1034     float oldValue = value_;
1035     auto value = sliderPaintProperty->GetValueValue(value_);
1036     value_ = GetValueInValidRange(sliderPaintProperty, value, min, max);
1037     valueRatio_ = (value_ - min) / (max - min);
1038     sliderPaintProperty->UpdateValue(value_);
1039     valueChangeFlag_ = !NearEqual(oldValue, value_);
1040     UpdateCircleCenterOffset();
1041     UpdateBubble();
1042 }
1043 
GetValueInValidRange(const RefPtr<SliderPaintProperty> & paintProperty,float value,float min,float max)1044 float SliderPattern::GetValueInValidRange(
1045     const RefPtr<SliderPaintProperty>& paintProperty, float value, float min, float max)
1046 {
1047     CHECK_NULL_RETURN(paintProperty, value);
1048     if (paintProperty->GetValidSlideRange().has_value()) {
1049         auto range = paintProperty->GetValidSlideRange().value();
1050         if (range->HasValidValues()) {
1051             CHECK_NULL_RETURN(range, value);
1052             auto fromValue = range->GetFromValue();
1053             auto toValue = range->GetToValue();
1054             float step = paintProperty->GetStepRatio() * (max - min);
1055             if (NearEqual(step, 0.0f)) {
1056                 step = 1.0f;
1057             }
1058             auto toValueCorrection = NearEqual(toValue - step * std::floor(toValue / step), 0) ? 0 : 1;
1059             fromValue = LessOrEqual(fromValue, min) ? min : std::floor(fromValue / step) * step;
1060             toValue = GreatOrEqual(toValue, max) ? max : (std::floor(toValue / step) + toValueCorrection) * step;
1061             return LessNotEqual(value, fromValue) ? fromValue : GreatNotEqual(value, toValue) ? toValue : value;
1062         }
1063     }
1064     return value;
1065 }
1066 
UpdateTipsValue()1067 void SliderPattern::UpdateTipsValue()
1068 {
1069     CHECK_NULL_VOID(valueChangeFlag_);
1070     CHECK_NULL_VOID(showTips_);
1071     CHECK_NULL_VOID(bubbleFlag_);
1072     auto frameNode = GetHost();
1073     CHECK_NULL_VOID(frameNode);
1074     valueRatio_ = std::clamp(valueRatio_, 0.0f, 1.0f);
1075     std::string content = std::to_string(static_cast<int>(std::round(valueRatio_ * 100.0f))) + '%';
1076     frameNode->GetPaintProperty<SliderPaintProperty>()->UpdateContent(content);
1077 }
1078 
UpdateCircleCenterOffset()1079 void SliderPattern::UpdateCircleCenterOffset()
1080 {
1081     auto host = GetHost();
1082     CHECK_NULL_VOID(host);
1083     auto contentSize = GetHostContentSize();
1084     CHECK_NULL_VOID(contentSize.has_value());
1085     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
1086     CHECK_NULL_VOID(sliderPaintProperty);
1087     auto touchLength = valueRatio_ * sliderLength_;
1088     auto touchOffset = GetReverseValue(GetLayoutProperty<SliderLayoutProperty>())
1089                            ? sliderLength_ - touchLength + borderBlank_
1090                            : touchLength + borderBlank_;
1091     if (sliderPaintProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::HORIZONTAL) {
1092         circleCenter_.SetX(touchOffset);
1093         circleCenter_.SetY(contentSize->Height() * HALF);
1094     } else {
1095         circleCenter_.SetX(contentSize->Width() * HALF);
1096         circleCenter_.SetY(touchOffset);
1097     }
1098 }
1099 
UpdateBubble()1100 void SliderPattern::UpdateBubble()
1101 {
1102     CHECK_NULL_VOID(bubbleFlag_);
1103     // update the tip value according to the slider value, update the tip position according to current block position
1104     UpdateTipsValue();
1105     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
1106 }
1107 
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)1108 void SliderPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1109 {
1110     if (UseContentModifier()) {
1111         if (panEvent_) {
1112             gestureHub->RemovePanEvent(panEvent_);
1113             panEvent_ = nullptr;
1114         }
1115         return;
1116     }
1117     if (direction_ == GetDirection() && panEvent_) return;
1118     direction_ = GetDirection();
1119 
1120     if (panEvent_) {
1121         gestureHub->RemovePanEvent(panEvent_);
1122     }
1123     panEvent_ = CreatePanEvent();
1124 
1125     PanDirection panDirection;
1126     panDirection.type = direction_ == Axis::HORIZONTAL ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
1127     auto host = GetHost();
1128     CHECK_NULL_VOID(host);
1129     auto pipeline = host->GetContextWithCheck();
1130     CHECK_NULL_VOID(pipeline);
1131     gestureHub->AddPanEvent(
1132         panEvent_, panDirection, 1, pipeline->IsFormRender() ? FORM_PAN_DISTANCE : DEFAULT_PAN_DISTANCE);
1133 }
1134 
CreatePanEvent()1135 RefPtr<PanEvent> SliderPattern::CreatePanEvent()
1136 {
1137     auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1138         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider handle action start");
1139         auto pattern = weak.Upgrade();
1140         CHECK_NULL_VOID(pattern);
1141         pattern->HandlingGestureStart(info);
1142         if (info.GetInputEventType() == InputEventType::AXIS) {
1143             pattern->FireChangeEvent(SliderChangeMode::Begin);
1144         }
1145         pattern->OpenTranslateAnimation(SliderStatus::MOVE);
1146     };
1147     auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1148         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider handle action update");
1149         auto pattern = weak.Upgrade();
1150         CHECK_NULL_VOID(pattern);
1151         if (!pattern->IsSkipGestureEvents()) {
1152             pattern->HandlingGestureEvent(info);
1153             pattern->FireChangeEvent(SliderChangeMode::Moving);
1154             pattern->OpenTranslateAnimation(SliderStatus::MOVE);
1155         }
1156     };
1157     auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1158         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider handle action end");
1159         auto pattern = weak.Upgrade();
1160         CHECK_NULL_VOID(pattern);
1161         pattern->HandledGestureEvent();
1162         if (info.GetInputEventType() == InputEventType::AXIS) {
1163             pattern->FireChangeEvent(SliderChangeMode::End);
1164         }
1165         pattern->CloseTranslateAnimation();
1166     };
1167     auto actionCancelTask = [weak = WeakClaim(this)]() {
1168         auto pattern = weak.Upgrade();
1169         CHECK_NULL_VOID(pattern);
1170         pattern->HandledGestureEvent();
1171         pattern->FireChangeEvent(SliderChangeMode::End);
1172         pattern->axisFlag_ = false;
1173         pattern->CloseTranslateAnimation();
1174     };
1175     return MakeRefPtr<PanEvent>(
1176         std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1177 }
1178 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1179 void SliderPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1180 {
1181     if (UseContentModifier()) {
1182         focusHub->SetInnerFocusPaintRectCallback(nullptr);
1183         focusHub->SetOnKeyEventInternal(nullptr);
1184         focusHub->SetOnFocusInternal(nullptr);
1185         focusHub->SetOnBlurInternal(nullptr);
1186         return;
1187     }
1188     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
1189         auto pattern = wp.Upgrade();
1190         CHECK_NULL_VOID(pattern);
1191         pattern->GetInnerFocusPaintRect(paintRect);
1192     };
1193     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
1194 
1195     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1196         auto pattern = wp.Upgrade();
1197         CHECK_NULL_RETURN(pattern, false);
1198         return pattern->OnKeyEvent(event);
1199     };
1200     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1201 
1202     auto onFocus = [wp = WeakClaim(this)]() {
1203         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider on focus");
1204         auto pattern = wp.Upgrade();
1205         CHECK_NULL_VOID(pattern);
1206         pattern->focusFlag_ = true;
1207         pattern->UpdateTipState();
1208         pattern->UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
1209         pattern->AddIsFocusActiveUpdateEvent();
1210     };
1211     focusHub->SetOnFocusInternal(std::move(onFocus));
1212 
1213     auto onBlur = [wp = WeakClaim(this)]() {
1214         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider on blur");
1215         auto pattern = wp.Upgrade();
1216         CHECK_NULL_VOID(pattern);
1217         pattern->focusFlag_ = false;
1218         pattern->UpdateTipState();
1219         pattern->UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
1220         pattern->RemoveIsFocusActiveUpdateEvent();
1221     };
1222     focusHub->SetOnBlurInternal(std::move(onBlur));
1223 }
1224 
GetInnerFocusPaintRect(RoundRect & paintRect)1225 void SliderPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
1226 {
1227     auto host = GetHost();
1228     CHECK_NULL_VOID(host);
1229     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
1230     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
1231     if (sliderMode == SliderModel::SliderMode::OUTSET) {
1232         GetOutsetInnerFocusPaintRect(paintRect);
1233     } else {
1234         GetInsetAndNoneInnerFocusPaintRect(paintRect);
1235     }
1236 }
1237 
GetOutsetInnerFocusPaintRect(RoundRect & paintRect)1238 void SliderPattern::GetOutsetInnerFocusPaintRect(RoundRect& paintRect)
1239 {
1240     UpdateCircleCenterOffset();
1241     const auto& content = GetHost()->GetGeometryNode()->GetContent();
1242     CHECK_NULL_VOID(content);
1243     auto contentOffset = content->GetRect().GetOffset();
1244     auto theme = PipelineBase::GetCurrentContext()->GetTheme<SliderTheme>();
1245     CHECK_NULL_VOID(theme);
1246     auto appTheme = PipelineBase::GetCurrentContext()->GetTheme<AppTheme>();
1247     CHECK_NULL_VOID(appTheme);
1248     auto paintWidth = appTheme->GetFocusWidthVp();
1249     auto focusSideDistance = theme->GetFocusSideDistance();
1250     auto focusDistance = paintWidth * HALF + focusSideDistance;
1251     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
1252     CHECK_NULL_VOID(paintProperty);
1253     auto blockType = paintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT);
1254     if (!theme->ShowFocusFrame()) {
1255         auto halfWidth = blockSize_.Width() * HALF + static_cast<float>(focusDistance.ConvertToPx());
1256         auto halfHeight = blockSize_.Height() * HALF + static_cast<float>(focusDistance.ConvertToPx());
1257         paintRect.SetRect(RectF(circleCenter_.GetX() - halfWidth + contentOffset.GetX(),
1258             circleCenter_.GetY() - halfHeight + contentOffset.GetY(), halfWidth / HALF, halfHeight / HALF));
1259         paintRect.SetCornerRadius(focusDistance.ConvertToPx());
1260         if (blockType == SliderModelNG::BlockStyleType::DEFAULT) {
1261             auto focusRadius = std::min(blockSize_.Width(), blockSize_.Height()) * HALF +
1262                                static_cast<float>(focusDistance.ConvertToPx());
1263             paintRect.SetRect(RectF(circleCenter_.GetX() - focusRadius + contentOffset.GetX(),
1264                 circleCenter_.GetY() - focusRadius + contentOffset.GetY(), focusRadius / HALF, focusRadius / HALF));
1265             paintRect.SetCornerRadius(focusRadius);
1266         }
1267     }
1268     if (blockType == SliderModelNG::BlockStyleType::SHAPE) {
1269         auto shape = paintProperty->GetBlockShape();
1270         if (shape.has_value() && shape.value()->GetBasicShapeType() == BasicShapeType::CIRCLE) {
1271             auto circle = DynamicCast<Circle>(shape.value());
1272             CHECK_NULL_VOID(circle);
1273             float focusRadius;
1274             if (circle->GetRadius().IsValid()) {
1275                 focusRadius = circle->GetRadius().ConvertToPx() + focusDistance.ConvertToPx();
1276             } else {
1277                 focusRadius = std::min(circle->GetWidth().ConvertToPx(), circle->GetHeight().ConvertToPx()) * HALF +
1278                               focusDistance.ConvertToPx();
1279             }
1280             paintRect.SetRect(RectF(circleCenter_.GetX() - focusRadius + contentOffset.GetX(),
1281                 circleCenter_.GetY() - focusRadius + contentOffset.GetY(), focusRadius / HALF, focusRadius / HALF));
1282             paintRect.SetCornerRadius(focusRadius);
1283         }
1284     }
1285 }
1286 
GetInsetAndNoneInnerFocusPaintRect(RoundRect & paintRect)1287 void SliderPattern::GetInsetAndNoneInnerFocusPaintRect(RoundRect& paintRect)
1288 {
1289     auto frameNode = GetHost();
1290     CHECK_NULL_VOID(frameNode);
1291     const auto& content = frameNode->GetGeometryNode()->GetContent();
1292     CHECK_NULL_VOID(content);
1293     auto theme = PipelineBase::GetCurrentContext()->GetTheme<SliderTheme>();
1294     CHECK_NULL_VOID(theme);
1295     auto sliderLayoutProperty = frameNode->GetLayoutProperty<SliderLayoutProperty>();
1296     CHECK_NULL_VOID(sliderLayoutProperty);
1297     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
1298     auto focusSideDistance = theme->GetFocusSideDistance();
1299     auto appTheme = PipelineBase::GetCurrentContext()->GetTheme<AppTheme>();
1300     CHECK_NULL_VOID(appTheme);
1301     auto paintWidth = appTheme->GetFocusWidthVp();
1302     auto focusDistance = paintWidth * HALF + focusSideDistance;
1303     // use content area
1304     float offsetX = content->GetRect().GetX();
1305     float offsetY = content->GetRect().GetY();
1306     float width = content->GetRect().Width();
1307     float height = content->GetRect().Height();
1308     float focusRadius = trackThickness_ * HALF + static_cast<float>(focusDistance.ConvertToPx());
1309     auto paintProperty = frameNode->GetPaintProperty<SliderPaintProperty>();
1310     if (paintProperty && paintProperty->GetTrackBorderRadius().has_value()) {
1311         focusRadius = static_cast<float>(paintProperty->GetTrackBorderRadius().value().ConvertToPx()) +
1312                       static_cast<float>(focusDistance.ConvertToPx());
1313     }
1314     if (direction_ == Axis::HORIZONTAL) {
1315         if (sliderMode == SliderModel::SliderMode::INSET) {
1316             offsetX += borderBlank_ - trackThickness_ * HALF - static_cast<float>(focusDistance.ConvertToPx());
1317             width = sliderLength_ + trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
1318         } else {
1319             offsetX -= static_cast<float>(focusDistance.ConvertToPx());
1320             width += static_cast<float>(focusDistance.ConvertToPx()) / HALF;
1321         }
1322         offsetY += (height - trackThickness_) * HALF - static_cast<float>(focusDistance.ConvertToPx());
1323         height = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
1324     } else {
1325         offsetX += (width - trackThickness_) * HALF - static_cast<float>(focusDistance.ConvertToPx());
1326         width = trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
1327         if (sliderMode == SliderModel::SliderMode::INSET) {
1328             offsetY += borderBlank_ - trackThickness_ * HALF - static_cast<float>(focusDistance.ConvertToPx());
1329             height = sliderLength_ + trackThickness_ + static_cast<float>(focusDistance.ConvertToPx()) / HALF;
1330         } else {
1331             offsetY -= static_cast<float>(focusDistance.ConvertToPx());
1332             height += static_cast<float>(focusDistance.ConvertToPx()) / HALF;
1333         }
1334     }
1335     UpdatePaintRect(theme, sliderMode, paintRect, RectF(offsetX, offsetY, width, height), focusRadius);
1336 }
1337 
UpdatePaintRect(RefPtr<SliderTheme> theme,SliderModel::SliderMode & sliderMode,RoundRect & paintRect,const RectF & rect,float rectRadius)1338 void SliderPattern::UpdatePaintRect(RefPtr<SliderTheme> theme, SliderModel::SliderMode& sliderMode,
1339     RoundRect& paintRect, const RectF& rect, float rectRadius)
1340 {
1341     if (theme->ShowFocusFrame()) {
1342         if (sliderMode == SliderModel::SliderMode::INSET) {
1343             paintRect.SetRect(rect);
1344             paintRect.SetCornerRadius(rectRadius);
1345         }
1346     } else {
1347         paintRect.SetRect(rect);
1348         paintRect.SetCornerRadius(rectRadius);
1349     }
1350 }
1351 
PaintFocusState()1352 void SliderPattern::PaintFocusState()
1353 {
1354     auto host = GetHost();
1355     CHECK_NULL_VOID(host);
1356     RoundRect focusRect;
1357     GetInnerFocusPaintRect(focusRect);
1358 
1359     auto focusHub = host->GetFocusHub();
1360     CHECK_NULL_VOID(focusHub);
1361     focusHub->PaintInnerFocusState(focusRect);
1362 
1363     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1364 }
1365 
OnKeyEvent(const KeyEvent & event)1366 bool SliderPattern::OnKeyEvent(const KeyEvent& event)
1367 {
1368     auto reverse = GetReverseValue(GetLayoutProperty<SliderLayoutProperty>());
1369     if (event.action == KeyAction::DOWN) {
1370         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider on key event %{public}d", event.code);
1371         if ((direction_ == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_LEFT) ||
1372             (direction_ == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_UP)) {
1373             FireChangeEvent(SliderChangeMode::Begin);
1374             reverse ? MoveStep(1) : MoveStep(-1);
1375             FireChangeEvent(SliderChangeMode::End);
1376             if (showTips_) {
1377                 InitializeBubble();
1378             }
1379             PaintFocusState();
1380             return true;
1381         }
1382         if ((direction_ == Axis::HORIZONTAL && event.code == KeyCode::KEY_DPAD_RIGHT) ||
1383             (direction_ == Axis::VERTICAL && event.code == KeyCode::KEY_DPAD_DOWN)) {
1384             FireChangeEvent(SliderChangeMode::Begin);
1385             reverse ? MoveStep(-1) : MoveStep(1);
1386             FireChangeEvent(SliderChangeMode::End);
1387             if (showTips_) {
1388                 InitializeBubble();
1389             }
1390             PaintFocusState();
1391             return true;
1392         }
1393     }
1394     return false;
1395 }
1396 
MoveStep(int32_t stepCount)1397 bool SliderPattern::MoveStep(int32_t stepCount)
1398 {
1399     // stepCount > 0, slider value increases, block moves in the direction of growth
1400     auto host = GetHost();
1401     CHECK_NULL_RETURN(host, false);
1402     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
1403     CHECK_NULL_RETURN(sliderPaintProperty, false);
1404     float step = sliderPaintProperty->GetStep().value_or(1.0f);
1405     float min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
1406     float max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
1407     if (NearZero(step)) {
1408         return false;
1409     }
1410     float nextValue = value_ + static_cast<float>(stepCount) * step;
1411     auto oldStep = (value_ - min) / step;
1412     if (!NearEqual(oldStep, std::round(oldStep))) {
1413         if (stepCount > 0) {
1414             nextValue = std::floor((nextValue - min) / step) * step + min;
1415         } else {
1416             nextValue = std::ceil((nextValue - min) / step) * step + min;
1417         }
1418     }
1419     auto validSlideRange = sliderPaintProperty->GetValidSlideRange();
1420     if (validSlideRange.has_value() && validSlideRange.value()->HasValidValues()) {
1421         nextValue =
1422             std::clamp(nextValue, validSlideRange.value()->GetFromValue(), validSlideRange.value()->GetToValue());
1423     } else {
1424         nextValue = std::clamp(nextValue, min, max);
1425     }
1426     if (NearEqual(nextValue, value_)) {
1427         return false;
1428     }
1429     value_ = nextValue;
1430     sliderPaintProperty->UpdateValue(value_);
1431     valueRatio_ = (value_ - min) / (max - min);
1432     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
1433     return true;
1434 }
1435 
InitMouseEvent(const RefPtr<InputEventHub> & inputEventHub)1436 void SliderPattern::InitMouseEvent(const RefPtr<InputEventHub>& inputEventHub)
1437 {
1438     if (UseContentModifier()) {
1439         if (hoverEvent_) {
1440             inputEventHub->RemoveOnHoverEvent(hoverEvent_);
1441             hoverEvent_ = nullptr;
1442         }
1443         if (mouseEvent_) {
1444             inputEventHub->RemoveOnMouseEvent(mouseEvent_);
1445             mouseEvent_ = nullptr;
1446         }
1447         return;
1448     }
1449     auto hoverEvent = [weak = WeakClaim(this)](bool isHover) {
1450         auto pattern = weak.Upgrade();
1451         CHECK_NULL_VOID(pattern);
1452         pattern->HandleHoverEvent(isHover);
1453     };
1454     if (hoverEvent_) {
1455         inputEventHub->RemoveOnHoverEvent(hoverEvent_);
1456     }
1457     hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverEvent));
1458     inputEventHub->AddOnHoverEvent(hoverEvent_);
1459 
1460     auto mouseEvent = [weak = WeakClaim(this)](MouseInfo& info) {
1461         auto pattern = weak.Upgrade();
1462         CHECK_NULL_VOID(pattern);
1463         pattern->HandleMouseEvent(info);
1464     };
1465     if (mouseEvent_) {
1466         inputEventHub->RemoveOnMouseEvent(mouseEvent_);
1467     }
1468     mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseEvent));
1469     inputEventHub->AddOnMouseEvent(mouseEvent_);
1470 }
1471 
HandleHoverEvent(bool isHover)1472 void SliderPattern::HandleHoverEvent(bool isHover)
1473 {
1474     hotFlag_ = isHover;
1475     mouseHoverFlag_ = mouseHoverFlag_ && isHover;
1476     CHECK_NULL_VOID(sliderContentModifier_);
1477     sliderContentModifier_->SetIsHovered(true);
1478     if (!mouseHoverFlag_) {
1479         axisFlag_ = false;
1480         sliderContentModifier_->SetIsHovered(false);
1481     }
1482     if (!mouseHoverFlag_ && !axisFlag_ && !isFocusActive_ && !mousePressedFlag_) {
1483         bubbleFlag_ = false;
1484         sliderContentModifier_->SetIsHovered(false);
1485     }
1486     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
1487 }
1488 
HandleMouseEvent(const MouseInfo & info)1489 void SliderPattern::HandleMouseEvent(const MouseInfo& info)
1490 {
1491     UpdateCircleCenterOffset();
1492     // MouseInfo's LocalLocation is relative to the frame area, circleCenter_ is relative to the content area
1493     mouseHoverFlag_ = AtMousePanArea(info.GetLocalLocation());
1494     if (mouseHoverFlag_) {
1495         if (showTips_) {
1496             bubbleFlag_ = true;
1497             InitializeBubble();
1498             CHECK_NULL_VOID(sliderContentModifier_);
1499             sliderContentModifier_->SetIsHovered(true);
1500         }
1501     }
1502     // when mouse hovers over slider, distinguish between hover block and Wheel operation.
1503     if (!mouseHoverFlag_ && !axisFlag_ && !isFocusActive_ && !mousePressedFlag_) {
1504         bubbleFlag_ = false;
1505         CHECK_NULL_VOID(sliderContentModifier_);
1506         sliderContentModifier_->SetIsHovered(false);
1507     }
1508 
1509     UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
1510 }
1511 
FireChangeEvent(int32_t mode)1512 void SliderPattern::FireChangeEvent(int32_t mode)
1513 {
1514     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider fire change %{public}d %{public}f", mode, value_);
1515     auto sliderEventHub = GetEventHub<SliderEventHub>();
1516     CHECK_NULL_VOID(sliderEventHub);
1517     if ((mode == SliderChangeMode::Click || mode == SliderChangeMode::Moving) &&
1518         NearEqual(value_, sliderEventHub->GetValue())) {
1519         return;
1520     }
1521     sliderEventHub->FireChangeEvent(static_cast<float>(value_), mode);
1522     valueChangeFlag_ = false;
1523     SendAccessibilityValueEvent(mode);
1524 }
1525 
SendAccessibilityValueEvent(int32_t mode)1526 void SliderPattern::SendAccessibilityValueEvent(int32_t mode)
1527 {
1528     accessibilityValue_ = value_;
1529     auto currentTime = GetMilliseconds();
1530     if (currentTime - lastSendPostValueTime_ < SCREEN_READ_SENDEVENT_TIMESTAMP && !isTouchUpFlag_) {
1531         return;
1532     }
1533     isTouchUpFlag_ = false;
1534     lastSendPostValueTime_ = currentTime;
1535     auto pipeline = GetContext();
1536     CHECK_NULL_VOID(pipeline);
1537     auto taskExecutor = pipeline->GetTaskExecutor();
1538     CHECK_NULL_VOID(taskExecutor);
1539     taskExecutor->PostDelayedTask(
1540         [weak = WeakClaim(this)]() {
1541             auto pattern = weak.Upgrade();
1542             CHECK_NULL_VOID(pattern);
1543             auto host = pattern->GetHost();
1544             CHECK_NULL_VOID(host);
1545             host->OnAccessibilityEvent(AccessibilityEventType::COMPONENT_CHANGE);
1546         },
1547         TaskExecutor::TaskType::UI, SCREEN_READ_SENDEVENT_TIMESTAMP, STR_SCREEN_READ_SENDEVENT);
1548 }
1549 
UpdateMarkDirtyNode(const PropertyChangeFlag & Flag)1550 void SliderPattern::UpdateMarkDirtyNode(const PropertyChangeFlag& Flag)
1551 {
1552     auto host = GetHost();
1553     CHECK_NULL_VOID(host);
1554     host->MarkDirtyNode(Flag);
1555 }
1556 
GetDirection() const1557 Axis SliderPattern::GetDirection() const
1558 {
1559     auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
1560     CHECK_NULL_RETURN(sliderLayoutProperty, Axis::HORIZONTAL);
1561     return sliderLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL);
1562 }
1563 
1564 #ifdef SUPPORT_DIGITAL_CROWN
GetCrownRotatePx(const CrownEvent & event) const1565 double SliderPattern::GetCrownRotatePx(const CrownEvent& event) const
1566 {
1567     double px = -event.degree * crownDisplayControlRatio_;
1568     switch (crownSensitivity_) {
1569         case CrownSensitivity::LOW:
1570             px *= CROWN_SENSITIVITY_LOW;
1571             break;
1572         case CrownSensitivity::MEDIUM:
1573             px *= CROWN_SENSITIVITY_MEDIUM;
1574             break;
1575         case CrownSensitivity::HIGH:
1576             px *= CROWN_SENSITIVITY_HIGH;
1577             break;
1578         default:
1579             break;
1580     }
1581     return px;
1582 }
1583 
HandleCrownAction(double mainDelta)1584 void SliderPattern::HandleCrownAction(double mainDelta)
1585 {
1586     CHECK_NULL_VOID(sliderLength_ != 0);
1587     auto host = GetHost();
1588     CHECK_NULL_VOID(host);
1589     auto sliderLayoutProperty = host->GetLayoutProperty<SliderLayoutProperty>();
1590     CHECK_NULL_VOID(sliderLayoutProperty);
1591     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
1592     CHECK_NULL_VOID(sliderPaintProperty);
1593     float min = sliderPaintProperty->GetMin().value_or(SLIDER_MIN);
1594     float max = sliderPaintProperty->GetMax().value_or(SLIDER_MAX);
1595     crownMovingLength_ += mainDelta;
1596     crownMovingLength_ = std::clamp(crownMovingLength_, 0.0, static_cast<double>(sliderLength_));
1597     valueRatio_ = crownMovingLength_ / sliderLength_;
1598     auto stepRatio = sliderPaintProperty->GetStepRatio();
1599     CHECK_NULL_VOID(stepRatio != 0);
1600     valueRatio_ = NearEqual(valueRatio_, 1) ? 1 : std::round(valueRatio_ / stepRatio) * stepRatio;
1601     float oldValue = value_;
1602     value_ = std::clamp(valueRatio_ * (max - min) + min, min, max);
1603     sliderPaintProperty->UpdateValue(value_);
1604     valueChangeFlag_ = !NearEqual(oldValue, value_);
1605     UpdateCircleCenterOffset();
1606     reachBoundary_ = NearEqual(value_, min) || NearEqual(value_, max);
1607     if (showTips_) {
1608         bubbleFlag_ = true;
1609         UpdateBubble();
1610     }
1611 }
1612 
StartVibrateFeedback()1613 void SliderPattern::StartVibrateFeedback()
1614 {
1615     timeStampCur_ = GetCurrentTimestamp();
1616     if (!reachBoundary_ && (timeStampCur_ - timeStampPre_ >= CROWN_TIME_THRESH)) {
1617         VibratorUtils::StartVibraFeedback(CROWN_VIBRATOR_WEAK);
1618         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider StartVibrateFeedback %{public}s", CROWN_VIBRATOR_WEAK);
1619         timeStampPre_ = timeStampCur_;
1620     }
1621 }
1622 #endif
1623 
CreateAccessibilityProperty()1624 RefPtr<AccessibilityProperty> SliderPattern::CreateAccessibilityProperty()
1625 {
1626     return MakeRefPtr<SliderAccessibilityProperty>();
1627 }
1628 
UpdateContentParameters()1629 SliderContentModifier::Parameters SliderPattern::UpdateContentParameters()
1630 {
1631     auto paintProperty = GetPaintProperty<SliderPaintProperty>();
1632     CHECK_NULL_RETURN(paintProperty, SliderContentModifier::Parameters());
1633     auto pipeline = GetContext();
1634     CHECK_NULL_RETURN(pipeline, SliderContentModifier::Parameters());
1635     auto theme = pipeline->GetTheme<SliderTheme>();
1636     CHECK_NULL_RETURN(theme, SliderContentModifier::Parameters());
1637     auto stepRatio = paintProperty->GetStepRatio();
1638     SliderContentModifier::Parameters parameters { trackThickness_, blockSize_, stepRatio, hotBlockShadowWidth_,
1639         mouseHoverFlag_, mousePressedFlag_, PointF(), PointF(), PointF(), PointF(), PointF(), Gradient(),
1640         Gradient(), Color::TRANSPARENT };
1641     auto contentSize = GetHostContentSize();
1642     CHECK_NULL_RETURN(contentSize, SliderContentModifier::Parameters());
1643     const auto& content = GetHost()->GetGeometryNode()->GetContent();
1644     CHECK_NULL_RETURN(content, SliderContentModifier::Parameters());
1645     auto contentOffset = content->GetRect().GetOffset();
1646     // Distance between slide track and Content boundary
1647     auto centerWidth = direction_ == Axis::HORIZONTAL ? contentSize->Height() : contentSize->Width();
1648     centerWidth *= HALF;
1649 
1650     auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
1651     CHECK_NULL_RETURN(sliderLayoutProperty, SliderContentModifier::Parameters());
1652     auto sliderMode = sliderLayoutProperty->GetSliderMode().value_or(SliderModel::SliderMode::OUTSET);
1653     Color trackColor = theme->GetTrackSelectedColor();
1654     if (sliderMode == SliderModel::SliderMode::OUTSET) {
1655         trackColor = theme->GetOutsetModeSelectedTrackColor();
1656     }
1657     if (sliderMode == SliderModel::SliderMode::NONE) {
1658         trackColor = theme->GetNoneModeSelectedTrackColor();
1659     }
1660     Gradient defaultSelectGradientColor = SliderModelNG::CreateSolidGradient(theme->GetTrackSelectedColor());
1661     parameters.selectGradientColor = paintProperty->GetSelectGradientColor().value_or(defaultSelectGradientColor);
1662     Gradient defaultValue = SliderModelNG::CreateSolidGradient(theme->GetTrackBgColor());
1663     parameters.trackBackgroundColor = paintProperty->GetTrackBackgroundColor().value_or(defaultValue);
1664     parameters.blockColor = paintProperty->GetBlockColor().value_or(theme->GetBlockColor());
1665 
1666     UpdateParameters();
1667     GetSelectPosition(parameters, centerWidth, contentOffset);
1668     GetBackgroundPosition(parameters, centerWidth, contentOffset);
1669     GetCirclePosition(parameters, centerWidth, contentOffset);
1670     UpdateCircleCenterOffset();
1671     return parameters;
1672 }
1673 
GetSelectPosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)1674 void SliderPattern::GetSelectPosition(
1675     SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
1676 {
1677     float sliderSelectLength = std::clamp(sliderLength_ * valueRatio_, 0.0f, sliderLength_);
1678     PointF start;
1679     PointF end;
1680     if (!GetReverseValue(GetLayoutProperty<SliderLayoutProperty>())) {
1681         start = direction_ == Axis::HORIZONTAL ? PointF(offset.GetX() + borderBlank_, offset.GetY() + centerWidth)
1682                                                : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_);
1683         end = direction_ == Axis::HORIZONTAL
1684                   ? PointF(offset.GetX() + borderBlank_ + sliderSelectLength, offset.GetY() + centerWidth)
1685                   : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderSelectLength);
1686     } else {
1687         start = direction_ == Axis::HORIZONTAL
1688                     ? PointF(offset.GetX() + borderBlank_ + sliderLength_, offset.GetY() + centerWidth)
1689                     : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_);
1690         end =
1691             direction_ == Axis::HORIZONTAL ?
1692                 PointF(offset.GetX() + borderBlank_ + sliderLength_ - sliderSelectLength, offset.GetY() + centerWidth) :
1693                 PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_ - sliderSelectLength);
1694     }
1695     parameters.selectStart = start;
1696     parameters.selectEnd = end;
1697 }
1698 
GetBackgroundPosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)1699 void SliderPattern::GetBackgroundPosition(
1700     SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
1701 {
1702     auto startPointX = offset.GetX();
1703     auto startPointY = offset.GetY();
1704     auto start = direction_ == Axis::HORIZONTAL ? PointF(startPointX + borderBlank_, startPointY + centerWidth)
1705                                                 : PointF(startPointX + centerWidth, startPointY + borderBlank_);
1706     auto end = direction_ == Axis::HORIZONTAL
1707                    ? PointF(startPointX + borderBlank_ + sliderLength_, startPointY + centerWidth)
1708                    : PointF(startPointX + centerWidth, startPointY + borderBlank_ + sliderLength_);
1709     parameters.backStart = start;
1710     parameters.backEnd = end;
1711 }
1712 
GetCirclePosition(SliderContentModifier::Parameters & parameters,float centerWidth,const OffsetF & offset)1713 void SliderPattern::GetCirclePosition(
1714     SliderContentModifier::Parameters& parameters, float centerWidth, const OffsetF& offset)
1715 {
1716     float sliderSelectLength = std::clamp(sliderLength_ * valueRatio_, 0.0f, sliderLength_);
1717     PointF center;
1718     if (!GetReverseValue(GetLayoutProperty<SliderLayoutProperty>())) {
1719         center = direction_ == Axis::HORIZONTAL
1720                      ? PointF(offset.GetX() + borderBlank_ + sliderSelectLength, offset.GetY() + centerWidth)
1721                      : PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderSelectLength);
1722     } else {
1723         center =
1724             direction_ == Axis::HORIZONTAL ?
1725                 PointF(offset.GetX() + borderBlank_ + sliderLength_ - sliderSelectLength, offset.GetY() + centerWidth) :
1726                 PointF(offset.GetX() + centerWidth, offset.GetY() + borderBlank_ + sliderLength_ - sliderSelectLength);
1727     }
1728     parameters.circleCenter = center;
1729 }
1730 
UpdateBlock()1731 void SliderPattern::UpdateBlock()
1732 {
1733     auto host = GetHost();
1734     CHECK_NULL_VOID(host);
1735     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
1736     CHECK_NULL_VOID(sliderPaintProperty);
1737     auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
1738     CHECK_NULL_VOID(sliderLayoutProperty);
1739     auto sliderMode = sliderLayoutProperty->GetSliderModeValue(SliderModel::SliderMode::OUTSET);
1740     if (sliderPaintProperty->GetBlockTypeValue(SliderModelNG::BlockStyleType::DEFAULT) ==
1741         SliderModelNG::BlockStyleType::IMAGE && sliderMode != SliderModel::SliderMode::NONE) {
1742         if (imageFrameNode_ == nullptr) {
1743             auto imageId = ElementRegister::GetInstance()->MakeUniqueId();
1744             imageFrameNode_ =
1745                 FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, imageId, AceType::MakeRefPtr<ImagePattern>());
1746             imageFrameNode_->MountToParent(host);
1747         }
1748         if (imageFrameNode_ != nullptr) {
1749             auto imageLayoutProperty = DynamicCast<ImageLayoutProperty>(imageFrameNode_->GetLayoutProperty());
1750             CHECK_NULL_VOID(imageLayoutProperty);
1751             imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(sliderPaintProperty->GetBlockImageValue(""),
1752                 sliderPaintProperty->GetBlockImageBundleNameValue(""),
1753                 sliderPaintProperty->GetBlockImageModuleNameValue("")));
1754             imageLayoutProperty->UpdateImageFit(ImageFit::COVER);
1755             imageLayoutProperty->UpdateAutoResize(true);
1756             imageFrameNode_->MarkModifyDone();
1757         }
1758     } else {
1759         if (imageFrameNode_ != nullptr) {
1760             host->RemoveChild(imageFrameNode_);
1761             imageFrameNode_ = nullptr;
1762         }
1763     }
1764 }
1765 
ProvideRestoreInfo()1766 std::string SliderPattern::ProvideRestoreInfo()
1767 {
1768     auto jsonObj = JsonUtil::Create(true);
1769     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
1770     CHECK_NULL_RETURN(sliderPaintProperty, "");
1771     jsonObj->Put("value", sliderPaintProperty->GetValue().value_or(0.0f));
1772     return jsonObj->ToString();
1773 }
1774 
OnRestoreInfo(const std::string & restoreInfo)1775 void SliderPattern::OnRestoreInfo(const std::string& restoreInfo)
1776 {
1777     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
1778     CHECK_NULL_VOID(sliderPaintProperty);
1779     auto info = JsonUtil::ParseJsonString(restoreInfo);
1780     CHECK_NULL_VOID(info);
1781     if (!info->IsValid() || !info->IsObject()) {
1782         return;
1783     }
1784     auto jsonValue = info->GetValue("value");
1785     sliderPaintProperty->UpdateValue(jsonValue->GetDouble());
1786     OnModifyDone();
1787 }
1788 
LayoutImageNode()1789 void SliderPattern::LayoutImageNode()
1790 {
1791     auto host = GetHost();
1792     CHECK_NULL_VOID(host);
1793     host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1794 }
1795 
UpdateImagePositionX(float centerX)1796 void SliderPattern::UpdateImagePositionX(float centerX)
1797 {
1798     CHECK_NULL_VOID(imageFrameNode_);
1799     auto renderContext = imageFrameNode_->GetRenderContext();
1800     CHECK_NULL_VOID(renderContext);
1801     auto geometryNode = imageFrameNode_->GetGeometryNode();
1802     CHECK_NULL_VOID(geometryNode);
1803 
1804     auto offset = geometryNode->GetMarginFrameOffset();
1805     offset.SetX(centerX - blockSize_.Width() * HALF);
1806     geometryNode->SetMarginFrameOffset(offset);
1807     renderContext->SavePaintRect();
1808     renderContext->SyncGeometryProperties(nullptr);
1809 }
1810 
UpdateImagePositionY(float centerY)1811 void SliderPattern::UpdateImagePositionY(float centerY)
1812 {
1813     CHECK_NULL_VOID(imageFrameNode_);
1814     auto renderContext = imageFrameNode_->GetRenderContext();
1815     CHECK_NULL_VOID(renderContext);
1816     auto geometryNode = imageFrameNode_->GetGeometryNode();
1817     CHECK_NULL_VOID(geometryNode);
1818 
1819     auto offset = geometryNode->GetMarginFrameOffset();
1820     offset.SetY(centerY - blockSize_.Height() * HALF);
1821     geometryNode->SetMarginFrameOffset(offset);
1822     renderContext->SavePaintRect();
1823     renderContext->SyncGeometryProperties(nullptr);
1824 }
1825 
OpenTranslateAnimation(SliderStatus status)1826 void SliderPattern::OpenTranslateAnimation(SliderStatus status)
1827 {
1828     CHECK_NULL_VOID(sliderContentModifier_);
1829     sliderContentModifier_->SetAnimatorStatus(status);
1830 }
1831 
CloseTranslateAnimation()1832 void SliderPattern::CloseTranslateAnimation()
1833 {
1834     CHECK_NULL_VOID(sliderContentModifier_);
1835     sliderContentModifier_->SetAnimatorStatus(SliderStatus::DEFAULT);
1836 }
1837 
GetBubbleVertexPosition(const OffsetF & blockCenter,float trackThickness,const SizeF & blockSize)1838 std::pair<OffsetF, float> SliderPattern::GetBubbleVertexPosition(
1839     const OffsetF& blockCenter, float trackThickness, const SizeF& blockSize)
1840 {
1841     OffsetF bubbleVertex = blockCenter;
1842     auto sliderLayoutProperty = GetLayoutProperty<SliderLayoutProperty>();
1843     float vertexOffsetFromBlock = 0;
1844     if (!sliderLayoutProperty) {
1845         return std::pair<OffsetF, float>();
1846     }
1847     auto sliderMode = sliderLayoutProperty->GetSliderModeValue(SliderModel::SliderMode::OUTSET);
1848     if (sliderMode == SliderModel::SliderMode::OUTSET) {
1849         if (direction_ == Axis::HORIZONTAL) {
1850             vertexOffsetFromBlock = blockSize.Height() * HALF + BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx();
1851             bubbleVertex.AddY(0 - vertexOffsetFromBlock);
1852         } else {
1853             vertexOffsetFromBlock = blockSize.Width() * HALF + BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx();
1854             bubbleVertex.AddX(0 - vertexOffsetFromBlock);
1855         }
1856     } else {
1857         vertexOffsetFromBlock = trackThickness * HALF + BUBBLE_TO_SLIDER_DISTANCE.ConvertToPx();
1858         if (direction_ == Axis::HORIZONTAL) {
1859             bubbleVertex.AddY(0 - vertexOffsetFromBlock);
1860         } else {
1861             bubbleVertex.AddX(0 - vertexOffsetFromBlock);
1862         }
1863     }
1864     return std::pair<OffsetF, float>(bubbleVertex, vertexOffsetFromBlock);
1865 }
1866 
SetAccessibilityAction()1867 void SliderPattern::SetAccessibilityAction()
1868 {
1869     auto host = GetHost();
1870     CHECK_NULL_VOID(host);
1871     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
1872     CHECK_NULL_VOID(accessibilityProperty);
1873     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
1874         const auto& pattern = weakPtr.Upgrade();
1875         CHECK_NULL_VOID(pattern);
1876         pattern->FireChangeEvent(SliderChangeMode::Begin);
1877         pattern->MoveStep(1);
1878         pattern->FireChangeEvent(SliderChangeMode::End);
1879 
1880         if (pattern->showTips_) {
1881             pattern->bubbleFlag_ = true;
1882             pattern->InitializeBubble();
1883         }
1884         pattern->PaintFocusState();
1885     });
1886 
1887     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
1888         const auto& pattern = weakPtr.Upgrade();
1889         CHECK_NULL_VOID(pattern);
1890         pattern->FireChangeEvent(SliderChangeMode::Begin);
1891         pattern->MoveStep(-1);
1892         pattern->FireChangeEvent(SliderChangeMode::End);
1893 
1894         if (pattern->showTips_) {
1895             pattern->bubbleFlag_ = true;
1896             pattern->InitializeBubble();
1897         }
1898         pattern->PaintFocusState();
1899     });
1900 }
1901 
SetSliderValue(double value,int32_t mode)1902 void SliderPattern::SetSliderValue(double value, int32_t mode)
1903 {
1904     auto host = GetHost();
1905     CHECK_NULL_VOID(host);
1906     auto eventHub = host->GetEventHub<EventHub>();
1907     CHECK_NULL_VOID(eventHub);
1908     auto enabled = eventHub->IsEnabled();
1909     if (!enabled) {
1910         return;
1911     }
1912     UpdateValue(value);
1913     FireChangeEvent(mode);
1914     OnModifyDone();
1915 }
1916 
UpdateValue(float value)1917 void SliderPattern::UpdateValue(float value)
1918 {
1919     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "slider update value %{public}d %{public}f", panMoveFlag_, value_);
1920     if (!panMoveFlag_) {
1921         auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
1922         CHECK_NULL_VOID(sliderPaintProperty);
1923         sliderPaintProperty->UpdateValue(value);
1924     }
1925     CalcSliderValue();
1926     FireBuilder();
1927 }
1928 
OnAttachToFrameNode()1929 void SliderPattern::OnAttachToFrameNode()
1930 {
1931     RegisterVisibleAreaChange();
1932     InitHapticController();
1933 }
1934 
StartAnimation()1935 void SliderPattern::StartAnimation()
1936 {
1937     CHECK_NULL_VOID(sliderContentModifier_);
1938     if (sliderContentModifier_->GetVisible()) {
1939         return;
1940     }
1941     if (IsSliderVisible()) {
1942         sliderContentModifier_->SetVisible(true);
1943         auto host = GetHost();
1944         CHECK_NULL_VOID(host);
1945         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1946     }
1947 }
1948 
StopAnimation()1949 void SliderPattern::StopAnimation()
1950 {
1951     CHECK_NULL_VOID(sliderContentModifier_);
1952     if (!sliderContentModifier_->GetVisible()) {
1953         return;
1954     }
1955     sliderContentModifier_->SetVisible(false);
1956     auto host = GetHost();
1957     CHECK_NULL_VOID(host);
1958     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1959 }
1960 
RegisterVisibleAreaChange()1961 void SliderPattern::RegisterVisibleAreaChange()
1962 {
1963     if (hasVisibleChangeRegistered_) {
1964         return;
1965     }
1966 
1967     auto pipeline = GetContext();
1968     CHECK_NULL_VOID(pipeline);
1969     auto callback = [weak = WeakClaim(this)](bool visible, double ratio) {
1970         auto pattern = weak.Upgrade();
1971         CHECK_NULL_VOID(pattern);
1972         pattern->isVisibleArea_ = visible;
1973         visible ? pattern->StartAnimation() : pattern->StopAnimation();
1974     };
1975     auto host = GetHost();
1976     CHECK_NULL_VOID(host);
1977     std::vector<double> ratioList = {0.0};
1978     pipeline->AddVisibleAreaChangeNode(host, ratioList, callback, false, true);
1979     pipeline->AddWindowStateChangedCallback(host->GetId());
1980     pipeline->AddWindowSizeChangeCallback(host->GetId());
1981     hasVisibleChangeRegistered_ = true;
1982     auto renderContext = host->GetRenderContext();
1983     CHECK_NULL_VOID(renderContext);
1984     renderContext->SetAlphaOffscreen(true);
1985 }
1986 
OnWindowHide()1987 void SliderPattern::OnWindowHide()
1988 {
1989     isShow_ = false;
1990     StopAnimation();
1991 }
1992 
OnWindowShow()1993 void SliderPattern::OnWindowShow()
1994 {
1995     isShow_ = true;
1996     StartAnimation();
1997 }
1998 
IsSliderVisible()1999 bool SliderPattern::IsSliderVisible()
2000 {
2001     return isVisibleArea_ && isShow_;
2002 }
2003 
UpdateTipState()2004 void SliderPattern::UpdateTipState()
2005 {
2006     if (focusFlag_) {
2007         auto context = GetContext();
2008         CHECK_NULL_VOID(context);
2009         isFocusActive_ = context->GetIsFocusActive();
2010     } else {
2011         isFocusActive_ = false;
2012     }
2013 
2014     bool showBubble = false;
2015     if (showTips_ && focusFlag_) {
2016         showBubble = isFocusActive_ || mousePressedFlag_;
2017     }
2018     if (showBubble != bubbleFlag_) {
2019         bubbleFlag_ = showBubble;
2020         UpdateBubble();
2021     }
2022     CHECK_NULL_VOID(sliderContentModifier_);
2023     sliderContentModifier_->SetIsFocused(isFocusActive_);
2024 }
2025 
OnIsFocusActiveUpdate(bool isFocusActive)2026 void SliderPattern::OnIsFocusActiveUpdate(bool isFocusActive)
2027 {
2028     if (!focusFlag_) {
2029         return;
2030     }
2031     isFocusActive_ = isFocusActive;
2032     bool showBubble = false;
2033     if (showTips_) {
2034         showBubble = isFocusActive_ || mousePressedFlag_;
2035     }
2036     if (showBubble != bubbleFlag_) {
2037         bubbleFlag_ = showBubble;
2038         UpdateBubble();
2039         UpdateMarkDirtyNode(PROPERTY_UPDATE_RENDER);
2040     }
2041     CHECK_NULL_VOID(sliderContentModifier_);
2042     sliderContentModifier_->SetIsFocused(isFocusActive);
2043 }
2044 
AddIsFocusActiveUpdateEvent()2045 void SliderPattern::AddIsFocusActiveUpdateEvent()
2046 {
2047     if (!isFocusActiveUpdateEvent_) {
2048         isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
2049             auto pattern = weak.Upgrade();
2050             CHECK_NULL_VOID(pattern);
2051             pattern->OnIsFocusActiveUpdate(isFocusAcitve);
2052         };
2053     }
2054     auto host = GetHost();
2055     CHECK_NULL_VOID(host);
2056     auto pipline = host->GetContext();
2057     CHECK_NULL_VOID(pipline);
2058     pipline->AddIsFocusActiveUpdateEvent(GetHost(), isFocusActiveUpdateEvent_);
2059 }
2060 
RemoveIsFocusActiveUpdateEvent()2061 void SliderPattern::RemoveIsFocusActiveUpdateEvent()
2062 {
2063     auto host = GetHost();
2064     CHECK_NULL_VOID(host);
2065     auto pipline = host->GetContext();
2066     CHECK_NULL_VOID(pipline);
2067     pipline->RemoveIsFocusActiveUpdateEvent(host);
2068 }
2069 
FireBuilder()2070 void SliderPattern::FireBuilder()
2071 {
2072     auto host = GetHost();
2073     CHECK_NULL_VOID(host);
2074     if (!makeFunc_.has_value()) {
2075         host->RemoveChildAndReturnIndex(contentModifierNode_);
2076         contentModifierNode_ = nullptr;
2077         host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
2078         return;
2079     }
2080     auto node = BuildContentModifierNode();
2081     if (contentModifierNode_ == node) {
2082         return;
2083     }
2084     host->RemoveChildAndReturnIndex(contentModifierNode_);
2085     contentModifierNode_ = node;
2086     CHECK_NULL_VOID(contentModifierNode_);
2087     host->AddChild(contentModifierNode_, 0);
2088     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
2089 }
2090 
BuildContentModifierNode()2091 RefPtr<FrameNode> SliderPattern::BuildContentModifierNode()
2092 {
2093     if (!makeFunc_.has_value()) {
2094         return nullptr;
2095     }
2096     auto sliderPaintProperty = GetPaintProperty<SliderPaintProperty>();
2097     CHECK_NULL_RETURN(sliderPaintProperty, nullptr);
2098     auto min = sliderPaintProperty->GetMin().value_or(0.0f);
2099     auto max = sliderPaintProperty->GetMax().value_or(100.0f);
2100     auto step = sliderPaintProperty->GetStep().value_or(1.0f);
2101     auto value = sliderPaintProperty->GetValue().value_or(min);
2102     auto host = GetHost();
2103     CHECK_NULL_RETURN(host, nullptr);
2104     auto eventHub = host->GetEventHub<EventHub>();
2105     CHECK_NULL_RETURN(eventHub, nullptr);
2106     auto enabled = eventHub->IsEnabled();
2107     SliderConfiguration sliderConfiguration(value, min, max, step, enabled);
2108     return (makeFunc_.value())(sliderConfiguration);
2109 }
2110 
OnDetachFromFrameNode(FrameNode * frameNode)2111 void SliderPattern::OnDetachFromFrameNode(FrameNode* frameNode)
2112 {
2113     auto pipeline = frameNode->GetContext();
2114     CHECK_NULL_VOID(pipeline);
2115     pipeline->RemoveVisibleAreaChangeNode(frameNode->GetId());
2116     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
2117     pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
2118     hasVisibleChangeRegistered_ = false;
2119 
2120     auto accessibilityManager = pipeline->GetAccessibilityManager();
2121     CHECK_NULL_VOID(accessibilityManager);
2122     accessibilityManager->DeregisterAccessibilitySAObserverCallback(frameNode->GetAccessibilityId());
2123     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "Slider OnDetachFromFrameNode OK");
2124 }
2125 
InitOrRefreshSlipFactor()2126 void SliderPattern::InitOrRefreshSlipFactor()
2127 {
2128     auto host = GetHost();
2129     CHECK_NULL_VOID(host);
2130     auto sliderPaintProperty = host->GetPaintProperty<SliderPaintProperty>();
2131     CHECK_NULL_VOID(sliderPaintProperty);
2132     float min = sliderPaintProperty->GetMin().value_or(0.0f);
2133     float max = sliderPaintProperty->GetMax().value_or(100.0f);
2134     float step = sliderPaintProperty->GetStep().value_or(1.0f);
2135     if (step == 0) {
2136         return;
2137     }
2138     auto totalStepCount = static_cast<int32_t>((max - min) / step) + 1;
2139     if (NearZero(totalStepCount)) {
2140         return;
2141     }
2142     auto pipeline = host->GetContextWithCheck();
2143     CHECK_NULL_VOID(pipeline);
2144     auto theme = pipeline->GetTheme<SliderTheme>();
2145     CHECK_NULL_VOID(theme);
2146     auto sliderPPI = theme->GetSliderPPI();
2147     slipfactor_ = sliderPPI * SLIP_FACTOR_COEFFICIENT / totalStepCount;
2148 }
2149 } // namespace OHOS::Ace::NG
2150