• 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()394 void SliderTipModifier::SetBubbleDisplayAnimation()
395 {
396     auto weak = AceType::WeakClaim(this);
397     AnimationOption option = AnimationOption();
398     option.SetDuration(BUBBLE_DISPLAY_SIZE_CHANGE_TIMER);
399     option.SetCurve(Curves::FRICTION);
400     AnimationUtils::Animate(option, [weak]() {
401         auto self = weak.Upgrade();
402         CHECK_NULL_VOID(self);
403         self->sizeScale_->Set(BUBBLE_SIZE_MAX_SCALE);
404     });
405 
406     option.SetDuration(BUBBLE_DISPLAY_OPACITY_CHANGE_TIMER);
407     option.SetCurve(Curves::SHARP);
408     AnimationUtils::Animate(option, [weak]() {
409         auto self = weak.Upgrade();
410         CHECK_NULL_VOID(self);
411         self->opacityScale_->Set(BUBBLE_OPACITY_MAX_SCALE);
412     });
413 }
414 
SetBubbleDisappearAnimation()415 void SliderTipModifier::SetBubbleDisappearAnimation()
416 {
417     auto weak = AceType::WeakClaim(this);
418     AnimationOption option = AnimationOption();
419     option.SetDuration(BUBBLE_DISAPPEAR_SIZE_CHANGE_TIMER);
420     option.SetCurve(Curves::FRICTION);
421     AnimationUtils::Animate(option, [weak]() {
422         auto self = weak.Upgrade();
423         CHECK_NULL_VOID(self);
424         self->sizeScale_->Set(BUBBLE_SIZE_MIN_SCALE);
425     });
426 
427     option.SetDuration(BUBBLE_DISAPPEAR_OPACITY_CHANGE_TIMER);
428     option.SetCurve(Curves::SHARP);
429     AnimationUtils::Animate(option, [weak]() {
430         auto self = weak.Upgrade();
431         CHECK_NULL_VOID(self);
432         self->opacityScale_->Set(BUBBLE_OPACITY_MIN_SCALE);
433     });
434 }
435 
SetTipFlag(bool flag)436 void SliderTipModifier::SetTipFlag(bool flag)
437 {
438     CHECK_NULL_VOID(tipFlag_);
439     if (tipFlag_->Get() == flag) {
440         return;
441     }
442     taskId_++;
443     if (flag) {
444         SetBubbleDisplayAnimation();
445     } else if (tipDelayTime_ > 0) {
446         auto pipeline = PipelineBase::GetCurrentContext();
447         CHECK_NULL_VOID(pipeline);
448         auto taskExecutor = pipeline->GetTaskExecutor();
449         CHECK_NULL_VOID(taskExecutor);
450         taskExecutor->PostDelayedTask(
451             [weak = WeakClaim(this), taskId = taskId_]() {
452                 auto modifier = weak.Upgrade();
453                 CHECK_NULL_VOID(modifier);
454                 if (modifier->taskId_ != taskId) {
455                     return;
456                 }
457                 modifier->SetBubbleDisappearAnimation();
458                 auto pipeline = PipelineBase::GetCurrentContext();
459                 CHECK_NULL_VOID(pipeline);
460                 pipeline->RequestFrame();
461             },
462             TaskExecutor::TaskType::UI, tipDelayTime_, "ArkUISliderSetBubbleDisappearAnimation");
463     } else {
464         SetBubbleDisappearAnimation();
465     }
466     tipFlag_->Set(flag);
467 }
468 
BuildParagraph()469 void SliderTipModifier::BuildParagraph()
470 {
471     auto pipeline = PipelineBase::GetCurrentContext();
472     CHECK_NULL_VOID(pipeline);
473     auto fontStyle = std::make_unique<NG::FontStyle>();
474     CHECK_NULL_VOID(fontStyle);
475     fontStyle->UpdateTextColor(textColor_.ChangeAlpha(std::round(textColor_.GetAlpha() * opacityScale_->Get())));
476     auto fontScale = pipeline->GetFontScale();
477     if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) && LessNotEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
478         textFontSize_ = SUITABLEAGING_LEVEL_1_TEXT_FONT_SIZE;
479     } else if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
480         textFontSize_ = SUITABLEAGING_LEVEL_2_TEXT_FONT_SIZE;
481     }
482     fontStyle->UpdateFontSize(textFontSize_);
483     auto theme = pipeline->GetTheme<TextTheme>();
484     CHECK_NULL_VOID(theme);
485     TextStyle textStyle = CreateTextStyleUsingTheme(fontStyle, nullptr, theme);
486     auto content = content_->Get();
487     auto fontManager = pipeline->GetFontManager();
488     if (fontManager && fontManager->IsUseAppCustomFont()) {
489         textStyle.SetFontFamilies(Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont()));
490     }
491     CreateParagraphAndLayout(textStyle, content);
492 }
493 
CreateParagraphAndLayout(const TextStyle & textStyle,const std::string & content)494 void SliderTipModifier::CreateParagraphAndLayout(const TextStyle& textStyle, const std::string& content)
495 {
496     if (!CreateParagraph(textStyle, content)) {
497         return;
498     }
499     CHECK_NULL_VOID(paragraph_);
500     auto gridColumnType = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::BUBBLE_TYPE);
501     CHECK_NULL_VOID(gridColumnType);
502     auto parent = gridColumnType->GetParent();
503     if (parent) {
504         parent->BuildColumnWidth();
505     }
506 
507     auto pipeLine = PipelineBase::GetCurrentContextSafely();
508     CHECK_NULL_VOID(pipeLine);
509     auto fontScale = pipeLine->GetFontScale();
510     auto width = static_cast<float>(TEXT_MAX.ConvertToPx());
511     if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) ||
512         (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE))) {
513         width = static_cast<float>(TEXT_AGING_MAX.ConvertToPx());
514     }
515     paragraph_->Layout(width);
516 }
517 
CreateParagraph(const TextStyle & textStyle,std::string content)518 bool SliderTipModifier::CreateParagraph(const TextStyle& textStyle, std::string content)
519 {
520     ParagraphStyle paraStyle = { .direction = TextDirection::LTR,
521         .align = textStyle.GetTextAlign(),
522         .maxLines = MAX_LENGTH,
523         .fontLocale = Localization::GetInstance()->GetFontLocale(),
524         .wordBreak = WordBreak::BREAK_ALL,
525         .textOverflow = TextOverflow::ELLIPSIS };
526     paragraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
527     CHECK_NULL_RETURN(paragraph_, false);
528     paragraph_->PushStyle(textStyle);
529     StringUtils::TransformStrCase(content, static_cast<int32_t>(textStyle.GetTextCase()));
530     paragraph_->AddText(StringUtils::Str8ToStr16(content));
531     paragraph_->Build();
532     return true;
533 }
534 
GetBubbleVertex()535 std::pair<OffsetF, float> SliderTipModifier::GetBubbleVertex()
536 {
537     if (!getBubbleVertexFunc_) {
538         return std::pair<OffsetF, float>();
539     }
540     auto bubbleVertexInBlock = getBubbleVertexFunc_();
541     bubbleVertexInBlock.first += contentOffset_->Get();
542     return bubbleVertexInBlock;
543 }
544 
UpdateBubbleSize()545 void SliderTipModifier::UpdateBubbleSize()
546 {
547     auto pipeline = PipelineBase::GetCurrentContext();
548     CHECK_NULL_VOID(pipeline);
549     auto theme = pipeline->GetTheme<SliderTheme>();
550     CHECK_NULL_VOID(theme);
551 
552     float bubbleSizeHeight = static_cast<float>(BUBBLE_HORIZONTAL_WIDTH.ConvertToPx());
553     float bubbleSizeWidth = static_cast<float>(BUBBLE_HORIZONTAL_HEIGHT.ConvertToPx());
554     if (axis_ != Axis::HORIZONTAL) {
555         bubbleSizeHeight = static_cast<float>(BUBBLE_VERTICAL_WIDTH.ConvertToPx());
556         bubbleSizeWidth = static_cast<float>(BUBBLE_VERTICAL_HEIGHT.ConvertToPx());
557     }
558 
559     auto fontScale = pipeline->GetFontScale();
560     if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_1_SCALE) && LessNotEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
561         bubbleSizeHeight = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_1_WIDTH.ConvertToPx());
562         bubbleSizeWidth = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_1_HEIGHT.ConvertToPx());
563         if (axis_ != Axis::HORIZONTAL) {
564             bubbleSizeHeight = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_1_WIDTH.ConvertToPx());
565             bubbleSizeWidth = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_1_HEIGHT.ConvertToPx());
566         }
567     } else if (GreatOrEqual(fontScale, SUITABLEAGING_LEVEL_2_SCALE)) {
568         bubbleSizeHeight = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_2_WIDTH.ConvertToPx());
569         bubbleSizeWidth = static_cast<float>(BUBBLE_HORIZONTAL_SUITABLEAGING_LEVEL_2_HEIGHT.ConvertToPx());
570         if (axis_ != Axis::HORIZONTAL) {
571             bubbleSizeHeight = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_2_WIDTH.ConvertToPx());
572             bubbleSizeWidth = static_cast<float>(BUBBLE_VERTICAL_SUITABLEAGING_LEVEL_2_HEIGHT.ConvertToPx());
573         }
574     }
575     bubbleSize_ = SizeF(bubbleSizeHeight, bubbleSizeWidth);
576 }
577 
UpdateOverlayRect(const SizeF & frameSize)578 bool SliderTipModifier::UpdateOverlayRect(const SizeF& frameSize)
579 {
580     auto contentSize = contentSize_->Get();
581     auto pipeline = PipelineBase::GetCurrentContext();
582     CHECK_NULL_RETURN(pipeline, false);
583     auto theme = pipeline->GetTheme<SliderTheme>();
584     CHECK_NULL_RETURN(theme, false);
585     auto vertexPair = GetBubbleVertex();
586     auto vertex = vertexPair.first;
587     auto distance = static_cast<float>(theme->GetBubbleToCircleCenterDistance().ConvertToPx());
588     auto hotShadowWidth = sliderMode_ == SliderModel::SliderMode::OUTSET
589                               ? theme->GetOutsetHotBlockShadowWidth().ConvertToPx()
590                               : theme->GetInsetHotBlockShadowWidth().ConvertToPx();
591     auto circleSize = SizeF(blockSize_.Width() + hotShadowWidth / HALF, blockSize_.Height() + hotShadowWidth / HALF);
592     RectF rect;
593     if (axis_ == Axis::HORIZONTAL) {
594         auto maxWidth = std::max(circleSize.Height(), frameSize.Height());
595         if (sliderGlobalOffset_->Get().GetY() + vertex.GetY() < bubbleSize_.Height()) {
596             rect.SetOffset(OffsetF(-bubbleSize_.Width(), bubbleSize_.Height() + distance));
597         } else {
598             rect.SetOffset(OffsetF(-bubbleSize_.Width(), -bubbleSize_.Height() - distance));
599         }
600         rect.SetSize(
601             SizeF(contentSize.Width() + bubbleSize_.Width() / HALF, maxWidth + bubbleSize_.Height() + distance));
602     } else {
603         float bubbleCenterX = rect.GetOffset().GetX() + bubbleSize_.Width() * HALF;
604         float sliderOffsetX = sliderGlobalOffset_->Get().GetX() - bubbleCenterX;
605         auto maxWidth = std::max(circleSize.Width(), frameSize.Width());
606         if (sliderGlobalOffset_->Get().GetX() + vertex.GetX() < bubbleSize_.Width()) {
607             rect.SetOffset(OffsetF(AceApplicationInfo::GetInstance().IsRightToLeft()
608                 ? (sliderOffsetX - bubbleSize_.Width() - distance)
609                 : (bubbleSize_.Width() + distance), -bubbleSize_.Height()));
610         } else {
611             rect.SetOffset(OffsetF(AceApplicationInfo::GetInstance().IsRightToLeft()
612                 ? (sliderOffsetX + bubbleSize_.Width() + distance)
613                 : (-bubbleSize_.Width() - distance), -bubbleSize_.Height()));
614         }
615         rect.SetSize(
616             SizeF(maxWidth + bubbleSize_.Width() + distance, contentSize.Height() + bubbleSize_.Height() / HALF));
617     }
618     auto origin = GetBoundsRect();
619     if (origin.IsValid() && rect.IsValid()) {
620         rect = rect.CombineRectT(origin);
621     }
622     if (rect != origin) {
623         SetBoundsRect(rect);
624         return true;
625     }
626     return false;
627 }
628 } // namespace OHOS::Ace::NG
629