• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_tip_modifier.h"
17 
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/i18n/localization.h"
20 #include "bridge/common/utils/utils.h"
21 #include "core/common/font_manager.h"
22 #include "core/components/common/layout/grid_system_manager.h"
23 #include "core/components/slider/slider_theme.h"
24 #include "core/components_ng/pattern/text/text_styles.h"
25 #include "core/components_ng/render/drawing_prop_convertor.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr Dimension CIRCULAR_HORIZON_OFFSET = 13.86_vp;
30 constexpr Dimension ARROW_HORIZON_OFFSET = 1.5_vp;
31 constexpr Dimension ARROW_VERTICAL_OFFSET = 0.68_vp;
32 constexpr Dimension ARROW_RADIUS = 2.0_vp;
33 constexpr Dimension ARROW_HEIGHT = 8.0_vp;
34 constexpr Dimension ARROW_WIDTH = 16.0_vp;
35 constexpr float HALF = 0.5f;
36 
37 constexpr float BUBBLE_SIZE_MIN_SCALE = 0.6f;
38 constexpr float BUBBLE_SIZE_MAX_SCALE = 1.0f;
39 constexpr float BUBBLE_OPACITY_MIN_SCALE = 0.0f;
40 constexpr float BUBBLE_OPACITY_MAX_SCALE = 1.0f;
41 constexpr int32_t BUBBLE_DISPLAY_SIZE_CHANGE_TIMER = 250;
42 constexpr int32_t BUBBLE_DISPLAY_OPACITY_CHANGE_TIMER = 150;
43 constexpr int32_t BUBBLE_DISAPPEAR_SIZE_CHANGE_TIMER = 250;
44 constexpr int32_t BUBBLE_DISAPPEAR_OPACITY_CHANGE_TIMER = 250;
45 constexpr Dimension BUBBLE_VERTICAL_WIDTH = 62.0_vp;
46 constexpr Dimension BUBBLE_VERTICAL_HEIGHT = 32.0_vp;
47 constexpr Dimension BUBBLE_HORIZONTAL_WIDTH = 48.0_vp;
48 constexpr Dimension BUBBLE_HORIZONTAL_HEIGHT = 40.0_vp;
49 constexpr Dimension BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_1_WIDTH = 92.0_vp;
50 constexpr Dimension BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_1_HEIGHT = 52.0_vp;
51 constexpr Dimension BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_1_WIDTH = 48.0_vp;
52 constexpr Dimension BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_1_HEIGHT = 60.0_vp;
53 constexpr Dimension BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_2_WIDTH = 96.0_vp;
54 constexpr Dimension BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_2_HEIGHT = 56.0_vp;
55 constexpr Dimension BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_2_WIDTH = 48.0_vp;
56 constexpr Dimension BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_2_HEIGHT = 64.0_vp;
57 constexpr Dimension TEXT_MAX = 36.0_vp;
58 constexpr Dimension TEXT_AGING_MAX = 72.0_vp;
59 constexpr int32_t MAX_LENGTH = 1;
60 constexpr float SUITABLEAGING_LEVEL_1_SCALE = 1.75f;
61 constexpr float SUITABLEAGING_LEVEL_2_SCALE = 2.0f;
62 constexpr Dimension SUITABLEAGING_LEVEL_1_TEXT_FONT_SIZE = 25.0_vp;
63 constexpr Dimension SUITABLEAGING_LEVEL_2_TEXT_FONT_SIZE = 28.0_vp;
64 
65 } // namespace
66 
SliderTipModifier(std::function<std::pair<OffsetF,float> ()> getBubbleVertexFunc)67 SliderTipModifier::SliderTipModifier(std::function<std::pair<OffsetF, float>()> getBubbleVertexFunc)
68     : tipFlag_(AceType::MakeRefPtr<PropertyBool>(false)),
69       contentOffset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
70       contentSize_(AceType::MakeRefPtr<PropertySizeF>(SizeF())),
71       sizeScale_(AceType::MakeRefPtr<AnimatablePropertyFloat>(BUBBLE_SIZE_MIN_SCALE)),
72       opacityScale_(AceType::MakeRefPtr<AnimatablePropertyFloat>(BUBBLE_OPACITY_MIN_SCALE)),
73       content_(AceType::MakeRefPtr<PropertyString>("")), bubbleVertex_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
74       sliderGlobalOffset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
75       getBubbleVertexFunc_(std::move(getBubbleVertexFunc))
76 {
77     AttachProperty(tipFlag_);
78     AttachProperty(contentOffset_);
79     AttachProperty(sizeScale_);
80     AttachProperty(opacityScale_);
81     AttachProperty(content_);
82     AttachProperty(bubbleVertex_);
83     AttachProperty(sliderGlobalOffset_);
84 }
85 
~SliderTipModifier()86 SliderTipModifier::~SliderTipModifier() {}
87 
UpdateThemeParams(const RefPtr<SliderTheme> & theme)88 void SliderTipModifier::UpdateThemeParams(const RefPtr<SliderTheme>& theme)
89 {
90     tipDelayTime_ = theme->GetTipDelayTime();
91 }
92 
PaintTip(DrawingContext & context)93 void SliderTipModifier::PaintTip(DrawingContext& context)
94 {
95     PaintBubble(context);
96     CHECK_NULL_VOID(paragraph_);
97     PaintText(context);
98     context.canvas.Restore();
99 }
100 
PaintText(DrawingContext & context)101 void SliderTipModifier::PaintText(DrawingContext& context)
102 {
103     auto arrowSizeWidth = static_cast<float>(ARROW_WIDTH.ConvertToPx());
104     auto arrowSizeHeight = static_cast<float>(ARROW_HEIGHT.ConvertToPx());
105     auto circularOffset = static_cast<float>(CIRCULAR_HORIZON_OFFSET.ConvertToPx());
106     auto pipeLine = PipelineBase::GetCurrentContextSafely();
107     CHECK_NULL_VOID(pipeLine);
108     auto fontScale = pipeLine->GetFontScale();
109     SizeF textSize = { 0, 0 };
110     if (paragraph_) {
111         auto width = static_cast<float>(TEXT_MAX.ConvertToPx());
112         if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) ||
113             (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE))) {
114             width = static_cast<float>(TEXT_AGING_MAX.ConvertToPx());
115         }
116         textSize = SizeF(std::min(paragraph_->GetLongestLine(), width), paragraph_->GetHeight());
117     }
118     if (axis_ == Axis::HORIZONTAL) {
119         textOffset_.SetX(vertex_.GetX() - textSize.Width() * HALF);
120         if (isMask_) {
121             textOffset_.SetY(vertex_.GetY() + (bubbleSize_.Height() - textSize.Height() + arrowSizeHeight) * HALF);
122         } else {
123             textOffset_.SetY(vertex_.GetY() - (bubbleSize_.Height() + textSize.Height() + arrowSizeHeight) * HALF);
124         }
125     } else {
126         textOffset_.SetY(vertex_.GetY() - textSize.Height() * HALF);
127         if (isMask_) {
128             textOffset_.SetX(
129                 vertex_.GetX() +
130                 (bubbleSize_.Width() - textSize.Width() + arrowSizeHeight + circularOffset - arrowSizeWidth) * HALF);
131         } else {
132             textOffset_.SetX(
133                 vertex_.GetX() -
134                 (bubbleSize_.Width() + textSize.Width() + arrowSizeHeight + circularOffset - arrowSizeWidth) * HALF);
135         }
136     }
137     paragraph_->Paint(context.canvas, textOffset_.GetX(), textOffset_.GetY());
138 }
139 
PaintHorizontalBubble(float vertexOffsetFromBlock,RSPath & path)140 void SliderTipModifier::PaintHorizontalBubble(float vertexOffsetFromBlock, RSPath& path)
141 {
142     float arrowRadius = static_cast<float>(ARROW_RADIUS.ConvertToPx());
143     auto arrowSizeWidth = static_cast<float>(ARROW_WIDTH.ConvertToPx());
144     auto arrowSizeHeight = static_cast<float>(ARROW_HEIGHT.ConvertToPx());
145     auto arrowHorizonOffset = static_cast<float>(ARROW_HORIZON_OFFSET.ConvertToPx());
146     auto arrowVerticalOffset = static_cast<float>(ARROW_VERTICAL_OFFSET.ConvertToPx());
147     float circularRadius = (bubbleSize_.Height() - arrowSizeHeight) * HALF;
148     if (sliderGlobalOffset_->Get().GetY() + vertex_.GetY() < bubbleSize_.Height()) {
149         vertex_.AddY(vertexOffsetFromBlock / HALF);
150         isMask_ = true;
151         path.MoveTo(vertex_.GetX(), vertex_.GetY());
152         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() + arrowHorizonOffset,
153             vertex_.GetY() + arrowVerticalOffset);
154         path.LineTo(vertex_.GetX() + arrowSizeWidth * HALF, vertex_.GetY() + arrowSizeHeight);
155         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
156             vertex_.GetX() + arrowSizeWidth * HALF, vertex_.GetY() + bubbleSize_.Height());
157         path.LineTo(vertex_.GetX() - arrowSizeWidth * HALF, vertex_.GetY() + bubbleSize_.Height());
158         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
159             vertex_.GetX() - arrowSizeWidth * HALF, vertex_.GetY() + arrowSizeHeight);
160         path.LineTo(vertex_.GetX() - arrowHorizonOffset * HALF, vertex_.GetY() + arrowVerticalOffset);
161     } else {
162         isMask_ = false;
163         path.MoveTo(vertex_.GetX(), vertex_.GetY());
164         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() - arrowHorizonOffset,
165             vertex_.GetY() - arrowVerticalOffset);
166         path.LineTo(vertex_.GetX() - arrowSizeWidth * HALF, vertex_.GetY() - arrowSizeHeight);
167         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
168             vertex_.GetX() - arrowSizeWidth * HALF, vertex_.GetY() - bubbleSize_.Height());
169         path.LineTo(vertex_.GetX() + arrowSizeWidth * HALF, vertex_.GetY() - bubbleSize_.Height());
170         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
171             vertex_.GetX() + arrowSizeWidth * HALF, vertex_.GetY() - arrowSizeHeight);
172         path.LineTo(vertex_.GetX() + arrowHorizonOffset * HALF, vertex_.GetY() - arrowVerticalOffset);
173     }
174     path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX(), vertex_.GetY());
175 }
176 
PaintVerticalBubble(float vertexOffsetFromBlock,RSPath & path)177 void SliderTipModifier::PaintVerticalBubble(float vertexOffsetFromBlock, RSPath& path)
178 {
179     auto arrowWidth = static_cast<float>(ARROW_WIDTH.ConvertToPx());
180     auto arrowHeight = static_cast<float>(ARROW_HEIGHT.ConvertToPx());
181     auto circularOffset = static_cast<float>(CIRCULAR_HORIZON_OFFSET.ConvertToPx());
182     auto arrowHorizonOffset = static_cast<float>(ARROW_HORIZON_OFFSET.ConvertToPx());
183     auto arrowVerticalOffset = static_cast<float>(ARROW_VERTICAL_OFFSET.ConvertToPx());
184     float arrowRadius = static_cast<float>(ARROW_RADIUS.ConvertToPx());
185     float circularRadius = bubbleSize_.Height() * HALF;
186     if (sliderGlobalOffset_->Get().GetX() + vertex_.GetX() < bubbleSize_.Width() ||
187         AceApplicationInfo::GetInstance().IsRightToLeft()) {
188         vertex_.AddX(vertexOffsetFromBlock / HALF);
189         isMask_ = true;
190         path.MoveTo(vertex_.GetX(), vertex_.GetY());
191         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() + arrowVerticalOffset,
192             vertex_.GetY() - arrowHorizonOffset);
193         path.LineTo(vertex_.GetX() + arrowHeight, vertex_.GetY() - arrowWidth * HALF);
194         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
195             vertex_.GetX() + arrowHeight + circularOffset, vertex_.GetY() - bubbleSize_.Height() * HALF);
196         path.LineTo(vertex_.GetX() + bubbleSize_.Width() - bubbleSize_.Height() * HALF,
197             vertex_.GetY() - bubbleSize_.Height() * HALF);
198         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
199             vertex_.GetX() + bubbleSize_.Width() - bubbleSize_.Height() * HALF,
200             vertex_.GetY() + bubbleSize_.Height() * HALF);
201         path.LineTo(vertex_.GetX() + arrowHeight + circularOffset, vertex_.GetY() + bubbleSize_.Height() * HALF);
202         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() + arrowHeight,
203             vertex_.GetY() + arrowWidth * HALF);
204         path.LineTo(vertex_.GetX() + arrowVerticalOffset, vertex_.GetY() + arrowHorizonOffset);
205     } else {
206         isMask_ = false;
207         path.MoveTo(vertex_.GetX(), vertex_.GetY());
208         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() - arrowVerticalOffset,
209             vertex_.GetY() + arrowHorizonOffset);
210         path.LineTo(vertex_.GetX() - arrowHeight, vertex_.GetY() + arrowWidth * HALF);
211         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
212             vertex_.GetX() - arrowHeight - circularOffset, vertex_.GetY() + bubbleSize_.Height() * HALF);
213         path.LineTo(vertex_.GetX() - bubbleSize_.Width() + bubbleSize_.Height() * HALF,
214             vertex_.GetY() + bubbleSize_.Height() * HALF);
215         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
216             vertex_.GetX() - bubbleSize_.Width() + bubbleSize_.Height() * HALF,
217             vertex_.GetY() - bubbleSize_.Height() * HALF);
218         path.LineTo(vertex_.GetX() - arrowHeight - circularOffset, vertex_.GetY() - bubbleSize_.Height() * HALF);
219         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() - arrowHeight,
220             vertex_.GetY() - arrowWidth * HALF);
221         path.LineTo(vertex_.GetX() - arrowVerticalOffset, vertex_.GetY() - arrowHorizonOffset);
222     }
223     path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX(), vertex_.GetY());
224 }
225 
PaintHorizontalBubbleSuitableAging(float vertexOffsetFromBlock,RSPath & path)226 void SliderTipModifier::PaintHorizontalBubbleSuitableAging(float vertexOffsetFromBlock, RSPath& path)
227 {
228     float arrowRadius = static_cast<float>(ARROW_RADIUS.ConvertToPx());
229     auto arrowSizeWidth = static_cast<float>(ARROW_WIDTH.ConvertToPx());
230     auto arrowSizeHeight = static_cast<float>(ARROW_HEIGHT.ConvertToPx());
231     auto arrowHorizonOffset = static_cast<float>(ARROW_HORIZON_OFFSET.ConvertToPx());
232     auto arrowVerticalOffset = static_cast<float>(ARROW_VERTICAL_OFFSET.ConvertToPx());
233     float circularRadius = (bubbleSize_.Height() - arrowSizeHeight) * (1.0f / 3.0f);
234     if (sliderGlobalOffset_->Get().GetY() + vertex_.GetY() < bubbleSize_.Height()) {
235         vertex_.AddY(vertexOffsetFromBlock / HALF);
236         isMask_ = true;
237         path.MoveTo(vertex_.GetX(), vertex_.GetY());
238         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() + arrowHorizonOffset,
239             vertex_.GetY() + arrowVerticalOffset);
240         path.LineTo(vertex_.GetX() + arrowSizeWidth * HALF, vertex_.GetY() + arrowSizeHeight);
241         path.LineTo(vertex_.GetX() + bubbleSize_.Width() * HALF, vertex_.GetY() + arrowSizeHeight);
242         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
243             vertex_.GetX() + bubbleSize_.Width() * HALF + circularRadius,
244             vertex_.GetY() + arrowSizeHeight + (bubbleSize_.Height() - arrowSizeHeight) * (1.0f / 3.0f));
245         path.LineTo(vertex_.GetX() + bubbleSize_.Width() * HALF + circularRadius,
246             vertex_.GetY() + arrowSizeHeight + (bubbleSize_.Height() - arrowSizeHeight) * (2.0f / 3.0f));
247         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
248             vertex_.GetX() + bubbleSize_.Width() * HALF, vertex_.GetY() + bubbleSize_.Height());
249         path.LineTo(vertex_.GetX() - bubbleSize_.Width() * HALF, vertex_.GetY() + bubbleSize_.Height());
250         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
251             vertex_.GetX() - bubbleSize_.Width() * HALF - circularRadius,
252             vertex_.GetY() + arrowSizeHeight + (bubbleSize_.Height() - arrowSizeHeight) * (2.0f / 3.0f));
253         path.LineTo(vertex_.GetX() - bubbleSize_.Width() * HALF - circularRadius,
254             vertex_.GetY() + arrowSizeHeight + (bubbleSize_.Height() - arrowSizeHeight) * (1.0f / 3.0f));
255         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
256             vertex_.GetX() - bubbleSize_.Width() * HALF, vertex_.GetY() + arrowSizeHeight);
257         path.LineTo(vertex_.GetX() - arrowSizeWidth * HALF, vertex_.GetY() + arrowSizeHeight);
258         path.LineTo(vertex_.GetX() - arrowHorizonOffset * HALF, vertex_.GetY() + arrowVerticalOffset);
259     } else {
260         isMask_ = false;
261         path.MoveTo(vertex_.GetX(), vertex_.GetY());
262         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() - arrowHorizonOffset,
263             vertex_.GetY() - arrowVerticalOffset);
264         path.LineTo(vertex_.GetX() - arrowSizeWidth * HALF, vertex_.GetY() - arrowSizeHeight);
265         path.LineTo(vertex_.GetX() - bubbleSize_.Width() * HALF, vertex_.GetY() - arrowSizeHeight);
266         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
267             vertex_.GetX() - bubbleSize_.Width() * HALF - circularRadius,
268             vertex_.GetY() - arrowSizeHeight - (bubbleSize_.Height() - arrowSizeHeight) * (1.0f / 3.0f));
269         path.LineTo(vertex_.GetX() - bubbleSize_.Width() * HALF - circularRadius,
270             vertex_.GetY() - arrowSizeHeight - (bubbleSize_.Height() - arrowSizeHeight) * (2.0f / 3.0f));
271         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
272             vertex_.GetX() - bubbleSize_.Width() * HALF, vertex_.GetY() - bubbleSize_.Height());
273         path.LineTo(vertex_.GetX() + bubbleSize_.Width() * HALF, vertex_.GetY() - bubbleSize_.Height());
274         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
275             vertex_.GetX() + bubbleSize_.Width() * HALF + circularRadius,
276             vertex_.GetY() - arrowSizeHeight - (bubbleSize_.Height() - arrowSizeHeight) * (2.0f / 3.0f));
277         path.LineTo(vertex_.GetX() + bubbleSize_.Width() * HALF + circularRadius,
278             vertex_.GetY() - arrowSizeHeight - (bubbleSize_.Height() - arrowSizeHeight) * (1.0f / 3.0f));
279         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
280             vertex_.GetX() + bubbleSize_.Width() * HALF, vertex_.GetY() - arrowSizeHeight);
281         path.LineTo(vertex_.GetX() + arrowSizeWidth * HALF, vertex_.GetY() - arrowSizeHeight);
282         path.LineTo(vertex_.GetX() + arrowHorizonOffset * HALF, vertex_.GetY() - arrowVerticalOffset);
283     }
284     path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX(), vertex_.GetY());
285 }
286 
PaintVerticalBubbleSuitableAging(float vertexOffsetFromBlock,RSPath & path)287 void SliderTipModifier::PaintVerticalBubbleSuitableAging(float vertexOffsetFromBlock, RSPath& path)
288 {
289     auto arrowWidth = static_cast<float>(ARROW_WIDTH.ConvertToPx());
290     auto arrowHeight = static_cast<float>(ARROW_HEIGHT.ConvertToPx());
291     auto arrowHorizonOffset = static_cast<float>(ARROW_HORIZON_OFFSET.ConvertToPx());
292     auto arrowVerticalOffset = static_cast<float>(ARROW_VERTICAL_OFFSET.ConvertToPx());
293     float arrowRadius = static_cast<float>(ARROW_RADIUS.ConvertToPx());
294     float circularRadius = bubbleSize_.Height() * (1.0f / 3.0f);
295     if (sliderGlobalOffset_->Get().GetX() + vertex_.GetX() < bubbleSize_.Width() ||
296         AceApplicationInfo::GetInstance().IsRightToLeft()) {
297         vertex_.AddX(vertexOffsetFromBlock / HALF);
298         isMask_ = true;
299         path.MoveTo(vertex_.GetX(), vertex_.GetY());
300         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() + arrowVerticalOffset,
301             vertex_.GetY() - arrowHorizonOffset);
302         path.LineTo(vertex_.GetX() + arrowHeight, vertex_.GetY() - arrowWidth * HALF);
303         path.LineTo(vertex_.GetX() + arrowHeight, vertex_.GetY() - bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
304         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
305             vertex_.GetX() + arrowHeight + circularRadius, vertex_.GetY() - bubbleSize_.Height() * HALF);
306         path.LineTo(
307             vertex_.GetX() + bubbleSize_.Width() - circularRadius, vertex_.GetY() - bubbleSize_.Height() * HALF);
308         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
309             vertex_.GetX() + bubbleSize_.Width(), vertex_.GetY() - bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
310         path.LineTo(vertex_.GetX() + bubbleSize_.Width(), vertex_.GetY() + bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
311         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
312             vertex_.GetX() + bubbleSize_.Width() - circularRadius, vertex_.GetY() + bubbleSize_.Height() * HALF);
313         path.LineTo(vertex_.GetX() + arrowHeight + circularRadius, vertex_.GetY() + bubbleSize_.Height() * HALF);
314         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() + arrowHeight,
315             vertex_.GetY() + bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
316         path.LineTo(vertex_.GetX() + arrowHeight, vertex_.GetY() + arrowWidth * HALF);
317         path.LineTo(vertex_.GetX() + arrowVerticalOffset, vertex_.GetY() + arrowHorizonOffset);
318     } else {
319         isMask_ = false;
320         path.MoveTo(vertex_.GetX(), vertex_.GetY());
321         path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() - arrowVerticalOffset,
322             vertex_.GetY() + arrowHorizonOffset);
323         path.LineTo(vertex_.GetX() - arrowHeight, vertex_.GetY() + arrowWidth * HALF);
324         path.LineTo(vertex_.GetX() - arrowHeight, vertex_.GetY() + bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
325         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
326             vertex_.GetX() - arrowHeight - circularRadius, vertex_.GetY() + bubbleSize_.Height() * HALF);
327         path.LineTo(
328             vertex_.GetX() - bubbleSize_.Width() + circularRadius, vertex_.GetY() + bubbleSize_.Height() * HALF);
329         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
330             vertex_.GetX() - bubbleSize_.Width(), vertex_.GetY() + bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
331         path.LineTo(vertex_.GetX() - bubbleSize_.Width(), vertex_.GetY() - bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
332         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION,
333             vertex_.GetX() - bubbleSize_.Width() + circularRadius, vertex_.GetY() - bubbleSize_.Height() * HALF);
334         path.LineTo(vertex_.GetX() - arrowHeight - circularRadius, vertex_.GetY() - bubbleSize_.Height() * HALF);
335         path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX() - arrowHeight,
336             vertex_.GetY() - bubbleSize_.Height() * (1.0f / 3.0f) * HALF);
337         path.LineTo(vertex_.GetX() - arrowHeight, vertex_.GetY() - arrowWidth * HALF);
338         path.LineTo(vertex_.GetX() - arrowVerticalOffset, vertex_.GetY() - arrowHorizonOffset);
339     }
340     path.ArcTo(arrowRadius, arrowRadius, 0.0f, RSPathDirection::CW_DIRECTION, vertex_.GetX(), vertex_.GetY());
341 }
342 
PaintBubble(DrawingContext & context)343 void SliderTipModifier::PaintBubble(DrawingContext& context)
344 {
345     auto sizeScale = sizeScale_->Get();
346     auto opacityScale = opacityScale_->Get();
347     RSPath path;
348     auto vertexPair = GetBubbleVertex();
349     vertex_ = vertexPair.first;
350     auto vertexOffsetFromBlock = vertexPair.second;
351     auto pipeline = PipelineBase::GetCurrentContext();
352     CHECK_NULL_VOID(pipeline);
353     auto fontScale = pipeline->GetFontScale();
354     if (axis_ == Axis::HORIZONTAL) {
355         if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE)) {
356             PaintHorizontalBubbleSuitableAging(vertexOffsetFromBlock, path);
357         } else {
358             PaintHorizontalBubble(vertexOffsetFromBlock, path);
359         }
360     } else {
361         if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE)) {
362             PaintVerticalBubbleSuitableAging(vertexOffsetFromBlock, path);
363         } else {
364             PaintVerticalBubble(vertexOffsetFromBlock, path);
365         }
366     }
367     context.canvas.Save();
368     context.canvas.Translate(vertex_.GetX(), vertex_.GetY());
369     context.canvas.Scale(sizeScale, sizeScale);
370     context.canvas.Translate(vertex_.GetX() * -1.0, vertex_.GetY() * -1.0);
371     RSPen pen;
372     pen.SetColor(ToRSColor(tipColor_.ChangeAlpha(std::round(tipColor_.GetAlpha() * opacityScale))));
373     pen.SetAntiAlias(true);
374     RSBrush brush;
375     brush.SetColor(ToRSColor(tipColor_.ChangeAlpha(std::round(tipColor_.GetAlpha() * opacityScale))));
376     auto& canvas = context.canvas;
377     canvas.AttachPen(pen);
378     canvas.AttachBrush(brush);
379     canvas.ClipPath(path, RSClipOp::INTERSECT, true);
380     canvas.DrawPath(path);
381     canvas.DetachBrush();
382     canvas.DetachPen();
383 }
384 
onDraw(DrawingContext & context)385 void SliderTipModifier::onDraw(DrawingContext& context)
386 {
387     if (tipFlag_->Get() || GreatNotEqual(sizeScale_->Get(), BUBBLE_SIZE_MIN_SCALE)) {
388         BuildParagraph();
389         UpdateBubbleSize();
390         PaintTip(context);
391     }
392 }
393 
SetBubbleDisplayAnimation(const RefPtr<FrameNode> & host)394 void SliderTipModifier::SetBubbleDisplayAnimation(const RefPtr<FrameNode>& host)
395 {
396     CHECK_NULL_VOID(host);
397     auto weak = AceType::WeakClaim(this);
398     AnimationOption option = AnimationOption();
399     option.SetDuration(BUBBLE_DISPLAY_SIZE_CHANGE_TIMER);
400     option.SetCurve(Curves::FRICTION);
401     AnimationUtils::Animate(option, [weak]() {
402         auto self = weak.Upgrade();
403         CHECK_NULL_VOID(self);
404         self->sizeScale_->Set(BUBBLE_SIZE_MAX_SCALE);
405     }, nullptr, nullptr, host->GetContextRefPtr());
406 
407     option.SetDuration(BUBBLE_DISPLAY_OPACITY_CHANGE_TIMER);
408     option.SetCurve(Curves::SHARP);
409     AnimationUtils::Animate(option, [weak]() {
410         auto self = weak.Upgrade();
411         CHECK_NULL_VOID(self);
412         self->opacityScale_->Set(BUBBLE_OPACITY_MAX_SCALE);
413     }, nullptr, nullptr, host->GetContextRefPtr());
414 }
415 
SetBubbleDisappearAnimation(const RefPtr<FrameNode> & host)416 void SliderTipModifier::SetBubbleDisappearAnimation(const RefPtr<FrameNode>& host)
417 {
418     CHECK_NULL_VOID(host);
419     auto weak = AceType::WeakClaim(this);
420     AnimationOption option = AnimationOption();
421     option.SetDuration(BUBBLE_DISAPPEAR_SIZE_CHANGE_TIMER);
422     option.SetCurve(Curves::FRICTION);
423     AnimationUtils::Animate(option, [weak]() {
424         auto self = weak.Upgrade();
425         CHECK_NULL_VOID(self);
426         self->sizeScale_->Set(BUBBLE_SIZE_MIN_SCALE);
427     }, nullptr, nullptr, host->GetContextRefPtr());
428 
429     option.SetDuration(BUBBLE_DISAPPEAR_OPACITY_CHANGE_TIMER);
430     option.SetCurve(Curves::SHARP);
431     AnimationUtils::Animate(option, [weak]() {
432         auto self = weak.Upgrade();
433         CHECK_NULL_VOID(self);
434         self->opacityScale_->Set(BUBBLE_OPACITY_MIN_SCALE);
435     }, nullptr, nullptr, host->GetContextRefPtr());
436 }
437 
SetTipFlag(bool flag,const RefPtr<FrameNode> & host)438 void SliderTipModifier::SetTipFlag(bool flag, const RefPtr<FrameNode>& host)
439 {
440     CHECK_NULL_VOID(tipFlag_);
441     if (tipFlag_->Get() == flag) {
442         return;
443     }
444     taskId_++;
445     if (flag) {
446         SetBubbleDisplayAnimation(host);
447     } else if (tipDelayTime_ > 0) {
448         auto pipeline = PipelineBase::GetCurrentContext();
449         CHECK_NULL_VOID(pipeline);
450         auto taskExecutor = pipeline->GetTaskExecutor();
451         CHECK_NULL_VOID(taskExecutor);
452         taskExecutor->PostDelayedTask(
453             [weak = WeakClaim(this), taskId = taskId_, weakHost = AceType::WeakClaim(AceType::RawPtr(host))]() {
454                 auto modifier = weak.Upgrade();
455                 CHECK_NULL_VOID(modifier);
456                 auto host = weakHost.Upgrade();
457                 CHECK_NULL_VOID(host);
458                 if (modifier->taskId_ != taskId) {
459                     return;
460                 }
461                 modifier->SetBubbleDisappearAnimation(host);
462                 auto pipeline = host->GetContextRefPtr();
463                 CHECK_NULL_VOID(pipeline);
464                 pipeline->RequestFrame();
465             },
466             TaskExecutor::TaskType::UI, tipDelayTime_, "ArkUISliderSetBubbleDisappearAnimation");
467     } else {
468         SetBubbleDisappearAnimation(host);
469     }
470     tipFlag_->Set(flag);
471 }
472 
BuildParagraph()473 void SliderTipModifier::BuildParagraph()
474 {
475     auto pipeline = PipelineBase::GetCurrentContext();
476     CHECK_NULL_VOID(pipeline);
477     auto fontStyle = std::make_unique<NG::FontStyle>();
478     CHECK_NULL_VOID(fontStyle);
479     fontStyle->UpdateTextColor(textColor_.ChangeAlpha(std::round(textColor_.GetAlpha() * opacityScale_->Get())));
480     auto fontScale = pipeline->GetFontScale();
481     if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) && LessNotEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
482         textFontSize_ = SUITABLEAGING_LEVEL_1_TEXT_FONT_SIZE;
483     } else if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
484         textFontSize_ = SUITABLEAGING_LEVEL_2_TEXT_FONT_SIZE;
485     }
486     fontStyle->UpdateFontSize(textFontSize_);
487     auto theme = pipeline->GetTheme<TextTheme>();
488     CHECK_NULL_VOID(theme);
489     TextStyle textStyle = CreateTextStyleUsingTheme(fontStyle, nullptr, theme);
490     auto content = content_->Get();
491     auto fontManager = pipeline->GetFontManager();
492     if (fontManager && fontManager->IsUseAppCustomFont()) {
493         textStyle.SetFontFamilies(Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont()));
494     }
495     CreateParagraphAndLayout(textStyle, content);
496 }
497 
CreateParagraphAndLayout(const TextStyle & textStyle,const std::string & content)498 void SliderTipModifier::CreateParagraphAndLayout(const TextStyle& textStyle, const std::string& content)
499 {
500     if (!CreateParagraph(textStyle, content)) {
501         return;
502     }
503     CHECK_NULL_VOID(paragraph_);
504     auto gridColumnType = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::BUBBLE_TYPE);
505     CHECK_NULL_VOID(gridColumnType);
506     auto parent = gridColumnType->GetParent();
507     if (parent) {
508         parent->BuildColumnWidth();
509     }
510 
511     auto pipeLine = PipelineBase::GetCurrentContextSafely();
512     CHECK_NULL_VOID(pipeLine);
513     auto fontScale = pipeLine->GetFontScale();
514     auto width = static_cast<float>(TEXT_MAX.ConvertToPx());
515     if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) ||
516         (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE))) {
517         width = static_cast<float>(TEXT_AGING_MAX.ConvertToPx());
518     }
519     paragraph_->Layout(width);
520 }
521 
CreateParagraph(const TextStyle & textStyle,std::string content)522 bool SliderTipModifier::CreateParagraph(const TextStyle& textStyle, std::string content)
523 {
524     ParagraphStyle paraStyle = { .direction = TextDirection::LTR,
525         .align = textStyle.GetTextAlign(),
526         .maxLines = MAX_LENGTH,
527         .fontLocale = Localization::GetInstance()->GetFontLocale(),
528         .wordBreak = WordBreak::BREAK_ALL,
529         .textOverflow = TextOverflow::ELLIPSIS };
530     paragraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
531     CHECK_NULL_RETURN(paragraph_, false);
532     paragraph_->PushStyle(textStyle);
533     StringUtils::TransformStrCase(content, static_cast<int32_t>(textStyle.GetTextCase()));
534     paragraph_->AddText(StringUtils::Str8ToStr16(content));
535     paragraph_->Build();
536     return true;
537 }
538 
GetBubbleVertex()539 std::pair<OffsetF, float> SliderTipModifier::GetBubbleVertex()
540 {
541     if (!getBubbleVertexFunc_) {
542         return std::pair<OffsetF, float>();
543     }
544     auto bubbleVertexInBlock = getBubbleVertexFunc_();
545     bubbleVertexInBlock.first += contentOffset_->Get();
546     return bubbleVertexInBlock;
547 }
548 
UpdateBubbleSize()549 void SliderTipModifier::UpdateBubbleSize()
550 {
551     auto pipeline = PipelineBase::GetCurrentContext();
552     CHECK_NULL_VOID(pipeline);
553     auto theme = pipeline->GetTheme<SliderTheme>();
554     CHECK_NULL_VOID(theme);
555 
556     float bubbleSizeHeight = static_cast<float>(BUBBLE_HORIZONTAL_WIDTH.ConvertToPx());
557     float bubbleSizeWidth = static_cast<float>(BUBBLE_HORIZONTAL_HEIGHT.ConvertToPx());
558     if (axis_ != Axis::HORIZONTAL) {
559         bubbleSizeHeight = static_cast<float>(BUBBLE_VERTICAL_WIDTH.ConvertToPx());
560         bubbleSizeWidth = static_cast<float>(BUBBLE_VERTICAL_HEIGHT.ConvertToPx());
561     }
562 
563     auto fontScale = pipeline->GetFontScale();
564     if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) && LessNotEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
565         bubbleSizeHeight = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_1_WIDTH.ConvertToPx());
566         bubbleSizeWidth = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_1_HEIGHT.ConvertToPx());
567         if (axis_ != Axis::HORIZONTAL) {
568             bubbleSizeHeight = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_1_WIDTH.ConvertToPx());
569             bubbleSizeWidth = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_1_HEIGHT.ConvertToPx());
570         }
571     } else if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
572         bubbleSizeHeight = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_2_WIDTH.ConvertToPx());
573         bubbleSizeWidth = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_2_HEIGHT.ConvertToPx());
574         if (axis_ != Axis::HORIZONTAL) {
575             bubbleSizeHeight = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_2_WIDTH.ConvertToPx());
576             bubbleSizeWidth = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_2_HEIGHT.ConvertToPx());
577         }
578     }
579     bubbleSize_ = SizeF(bubbleSizeHeight, bubbleSizeWidth);
580 }
581 
UpdateOverlayRect(const SizeF & frameSize)582 bool SliderTipModifier::UpdateOverlayRect(const SizeF& frameSize)
583 {
584     auto contentSize = contentSize_->Get();
585     auto pipeline = PipelineBase::GetCurrentContext();
586     CHECK_NULL_RETURN(pipeline, false);
587     auto theme = pipeline->GetTheme<SliderTheme>();
588     CHECK_NULL_RETURN(theme, false);
589     auto vertexPair = GetBubbleVertex();
590     auto vertex = vertexPair.first;
591     auto distance = static_cast<float>(theme->GetBubbleToCircleCenterDistance().ConvertToPx());
592     auto hotShadowWidth = sliderMode_ == SliderModel::SliderMode::OUTSET
593                               ? theme->GetOutsetHotBlockShadowWidth().ConvertToPx()
594                               : theme->GetInsetHotBlockShadowWidth().ConvertToPx();
595     auto circleSize = SizeF(blockSize_.Width() + hotShadowWidth / HALF, blockSize_.Height() + hotShadowWidth / HALF);
596     RectF rect;
597     if (axis_ == Axis::HORIZONTAL) {
598         auto maxWidth = std::max(circleSize.Height(), frameSize.Height());
599         if (sliderGlobalOffset_->Get().GetY() + vertex.GetY() < bubbleSize_.Height()) {
600             rect.SetOffset(OffsetF(-bubbleSize_.Width(), bubbleSize_.Height() + distance));
601         } else {
602             rect.SetOffset(OffsetF(-bubbleSize_.Width(), -bubbleSize_.Height() - distance));
603         }
604         rect.SetSize(
605             SizeF(contentSize.Width() + bubbleSize_.Width() / HALF, maxWidth + bubbleSize_.Height() + distance));
606     } else {
607         float bubbleCenterX = rect.GetOffset().GetX() + bubbleSize_.Width() * HALF;
608         float sliderOffsetX = sliderGlobalOffset_->Get().GetX() - bubbleCenterX;
609         auto maxWidth = std::max(circleSize.Width(), frameSize.Width());
610         if (sliderGlobalOffset_->Get().GetX() + vertex.GetX() < bubbleSize_.Width()) {
611             rect.SetOffset(OffsetF(AceApplicationInfo::GetInstance().IsRightToLeft()
612                 ? (sliderOffsetX - bubbleSize_.Width() - distance)
613                 : (bubbleSize_.Width() + distance), -bubbleSize_.Height()));
614         } else {
615             rect.SetOffset(OffsetF(AceApplicationInfo::GetInstance().IsRightToLeft()
616                 ? (sliderOffsetX + bubbleSize_.Width() + distance)
617                 : (-bubbleSize_.Width() - distance), -bubbleSize_.Height()));
618         }
619         rect.SetSize(
620             SizeF(maxWidth + bubbleSize_.Width() + distance, contentSize.Height() + bubbleSize_.Height() / HALF));
621     }
622     auto origin = GetBoundsRect();
623     if (origin.IsValid() && rect.IsValid()) {
624         rect = rect.CombineRectT(origin);
625     }
626     if (rect != origin) {
627         SetBoundsRect(rect);
628         return true;
629     }
630     return false;
631 }
632 } // namespace OHOS::Ace::NG
633