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 "core/components_ng/render/drawing_prop_convertor.h"
20
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr Dimension BEZIER_HORIZON_OFFSET_FIRST = 1.3_vp;
24 constexpr Dimension BEZIER_HORIZON_OFFSET_SECOND = 3.2_vp;
25 constexpr Dimension BEZIER_HORIZON_OFFSET_THIRD = 6.6_vp;
26 constexpr Dimension BEZIER_HORIZON_OFFSET_FOURTH = 16.0_vp;
27 constexpr Dimension BEZIER_VERTICAL_OFFSET_FIRST = 0.1_vp;
28 constexpr Dimension BEZIER_VERTICAL_OFFSET_SECOND = 3.0_vp;
29 constexpr Dimension BEZIER_VERTICAL_OFFSET_THIRD = 8.0_vp;
30 constexpr Dimension ARROW_HEIGHT = 8.0_vp;
31 constexpr float HALF = 0.5f;
32 } // namespace
33
SliderTipModifier()34 SliderTipModifier::SliderTipModifier()
35 : tipFlag_(AceType::MakeRefPtr<PropertyBool>(false)),
36 contentOffset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
37 bubbleSize_(AceType::MakeRefPtr<PropertySizeF>(SizeF())),
38 bubbleOffset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
39 textOffset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF()))
40 {
41 AttachProperty(tipFlag_);
42 AttachProperty(contentOffset_);
43 AttachProperty(bubbleSize_);
44 AttachProperty(bubbleOffset_);
45 AttachProperty(textOffset_);
46 }
47
PaintTip(DrawingContext & context)48 void SliderTipModifier::PaintTip(DrawingContext& context)
49 {
50 auto textOffset = textOffset_->Get() + contentOffset_->Get();
51 PaintBubble(context);
52 CHECK_NULL_VOID(paragraph_);
53 paragraph_->Paint(context.canvas, textOffset.GetX(), textOffset.GetY());
54 }
55
PaintBezier(bool isLeft,Axis axis,RSPath & path,const OffsetF & arrowCenter,const OffsetF & arrowEdge)56 void PaintBezier(bool isLeft, Axis axis, RSPath& path, const OffsetF& arrowCenter, const OffsetF& arrowEdge)
57 {
58 if (isLeft) {
59 path.MoveTo(arrowCenter.GetX(), arrowCenter.GetY());
60 if (axis == Axis::HORIZONTAL) {
61 path.QuadTo(arrowCenter.GetX() - static_cast<float>(BEZIER_HORIZON_OFFSET_FIRST.ConvertToPx()),
62 arrowCenter.GetY() + static_cast<float>(BEZIER_VERTICAL_OFFSET_FIRST.ConvertToPx()),
63 arrowCenter.GetX() - static_cast<float>(BEZIER_HORIZON_OFFSET_SECOND.ConvertToPx()),
64 arrowCenter.GetY() - static_cast<float>(BEZIER_VERTICAL_OFFSET_SECOND.ConvertToPx()));
65 path.QuadTo(arrowCenter.GetX() - static_cast<float>(BEZIER_HORIZON_OFFSET_THIRD.ConvertToPx()),
66 arrowCenter.GetY() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()),
67 arrowCenter.GetX() - static_cast<float>(BEZIER_HORIZON_OFFSET_FOURTH.ConvertToPx()),
68 arrowCenter.GetY() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()));
69 } else {
70 path.QuadTo(arrowCenter.GetX() + static_cast<float>(BEZIER_VERTICAL_OFFSET_FIRST.ConvertToPx()),
71 arrowCenter.GetY() + static_cast<float>(BEZIER_HORIZON_OFFSET_FIRST.ConvertToPx()),
72 arrowCenter.GetX() - static_cast<float>(BEZIER_VERTICAL_OFFSET_SECOND.ConvertToPx()),
73 arrowCenter.GetY() + static_cast<float>(BEZIER_HORIZON_OFFSET_SECOND.ConvertToPx()));
74 path.QuadTo(arrowCenter.GetX() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()),
75 arrowCenter.GetY() + static_cast<float>(BEZIER_HORIZON_OFFSET_THIRD.ConvertToPx()),
76 arrowCenter.GetX() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()),
77 arrowCenter.GetY() + static_cast<float>(BEZIER_HORIZON_OFFSET_FOURTH.ConvertToPx()));
78 }
79 path.LineTo(arrowEdge.GetX(), arrowEdge.GetY());
80 } else {
81 path.MoveTo(arrowEdge.GetX(), arrowEdge.GetY());
82 if (axis == Axis::HORIZONTAL) {
83 path.LineTo(arrowCenter.GetX() + static_cast<float>(BEZIER_HORIZON_OFFSET_FOURTH.ConvertToPx()),
84 arrowCenter.GetY() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()));
85 path.QuadTo(arrowCenter.GetX() + static_cast<float>(BEZIER_HORIZON_OFFSET_THIRD.ConvertToPx()),
86 arrowCenter.GetY() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()),
87 arrowCenter.GetX() + static_cast<float>(BEZIER_HORIZON_OFFSET_SECOND.ConvertToPx()),
88 arrowCenter.GetY() - static_cast<float>(BEZIER_VERTICAL_OFFSET_SECOND.ConvertToPx()));
89 path.QuadTo(arrowCenter.GetX() + static_cast<float>(BEZIER_HORIZON_OFFSET_FIRST.ConvertToPx()),
90 arrowCenter.GetY() + static_cast<float>(BEZIER_VERTICAL_OFFSET_FIRST.ConvertToPx()), arrowCenter.GetX(),
91 arrowCenter.GetY());
92 } else {
93 path.LineTo(arrowCenter.GetX() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()),
94 arrowCenter.GetY() - static_cast<float>(BEZIER_HORIZON_OFFSET_FOURTH.ConvertToPx()));
95 path.QuadTo(arrowCenter.GetX() - static_cast<float>(BEZIER_VERTICAL_OFFSET_THIRD.ConvertToPx()),
96 arrowCenter.GetY() - static_cast<float>(BEZIER_HORIZON_OFFSET_THIRD.ConvertToPx()),
97 arrowCenter.GetX() - static_cast<float>(BEZIER_VERTICAL_OFFSET_SECOND.ConvertToPx()),
98 arrowCenter.GetY() - static_cast<float>(BEZIER_HORIZON_OFFSET_SECOND.ConvertToPx()));
99 path.QuadTo(arrowCenter.GetX() + static_cast<float>(BEZIER_VERTICAL_OFFSET_FIRST.ConvertToPx()),
100 arrowCenter.GetY() - static_cast<float>(BEZIER_HORIZON_OFFSET_FIRST.ConvertToPx()), arrowCenter.GetX(),
101 arrowCenter.GetY());
102 }
103 }
104 }
105
PaintBubble(DrawingContext & context)106 void SliderTipModifier::PaintBubble(DrawingContext& context)
107 {
108 auto contentOffset = contentOffset_->Get();
109 auto offset = bubbleOffset_->Get() + contentOffset;
110 auto bubbleSize = bubbleSize_->Get();
111 auto arrowHeight = static_cast<float>(ARROW_HEIGHT.ConvertToPx());
112 RSPath path;
113 OffsetF arrowCenter;
114 OffsetF clockwiseFirstPoint;
115 OffsetF clockwiseSecondPoint;
116 float circularRadius = 0.0f;
117 OffsetF clockwiseThirdPoint;
118 OffsetF clockwiseFourthPoint;
119 if (axis_ == Axis::HORIZONTAL) {
120 arrowCenter = { offset.GetX() + bubbleSize.Width() * HALF, offset.GetY() + bubbleSize.Height() };
121 float bottomLineLength = bubbleSize.Width() - (bubbleSize.Height() - arrowHeight);
122 clockwiseFirstPoint = { arrowCenter.GetX() - bottomLineLength * HALF, arrowCenter.GetY() - arrowHeight };
123 clockwiseSecondPoint = { clockwiseFirstPoint.GetX(), offset.GetY() };
124 circularRadius = (clockwiseFirstPoint.GetY() - clockwiseSecondPoint.GetY()) * HALF;
125 clockwiseThirdPoint = { clockwiseSecondPoint.GetX() + bottomLineLength, clockwiseSecondPoint.GetY() };
126 clockwiseFourthPoint = { clockwiseThirdPoint.GetX(), offset.GetY() + circularRadius * 2 };
127 } else {
128 arrowCenter = { offset.GetX() + bubbleSize.Width(), offset.GetY() + bubbleSize.Height() * HALF };
129 float bottomLineLength = bubbleSize.Height() - (bubbleSize.Width() - arrowHeight);
130 clockwiseFirstPoint = { arrowCenter.GetX() - arrowHeight, arrowCenter.GetY() + bottomLineLength * HALF };
131 clockwiseSecondPoint = { offset.GetX(), clockwiseFirstPoint.GetY() };
132 circularRadius = (clockwiseFirstPoint.GetX() - clockwiseSecondPoint.GetX()) * HALF;
133 clockwiseThirdPoint = { clockwiseSecondPoint.GetX(), clockwiseSecondPoint.GetY() - bottomLineLength };
134 clockwiseFourthPoint = { offset.GetX() + circularRadius * 2, clockwiseThirdPoint.GetY() };
135 }
136 path.MoveTo(arrowCenter.GetX(), arrowCenter.GetY());
137 PaintBezier(
138 true, axis_, path, arrowCenter, clockwiseFirstPoint);
139 path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION, clockwiseSecondPoint.GetX(),
140 clockwiseSecondPoint.GetY());
141 path.LineTo(clockwiseThirdPoint.GetX(), clockwiseThirdPoint.GetY());
142 path.ArcTo(circularRadius, circularRadius, 0.0f, RSPathDirection::CW_DIRECTION, clockwiseFourthPoint.GetX(),
143 clockwiseFourthPoint.GetY());
144 PaintBezier(
145 false, axis_, path, arrowCenter, clockwiseFourthPoint);
146 RSPen pen;
147 pen.SetColor(ToRSColor(tipColor_));
148 pen.SetAntiAlias(true);
149 RSBrush brush;
150 brush.SetColor(ToRSColor(tipColor_));
151 auto& canvas = context.canvas;
152 canvas.AttachPen(pen);
153 canvas.AttachBrush(brush);
154 canvas.DrawPath(path);
155 canvas.ClipPath(path, RSClipOp::INTERSECT);
156 }
157 } // namespace OHOS::Ace::NG
158