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