1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 |
3 | |
4 | #pragma once |
5 | #include <string_view> |
6 | #include "slint_color.h" |
7 | #include "slint_brush_internal.h" |
8 | #include "slint_string.h" |
9 | |
10 | namespace slint { |
11 | |
12 | namespace private_api { |
13 | |
14 | using cbindgen_private::types::GradientStop; |
15 | |
16 | /// \private |
17 | /// LinearGradientBrush represents a gradient for a brush that is a linear sequence of color stops, |
18 | /// that are aligned at a specific angle. |
19 | class LinearGradientBrush |
20 | { |
21 | public: |
22 | /// Constructs an empty linear gradient with no color stops. |
23 | LinearGradientBrush() = default; |
24 | /// Constructs a new linear gradient with the specified \a angle. The color stops will be |
25 | /// constructed from the stops array pointed to be \a firstStop, with the length \a stopCount. |
26 | LinearGradientBrush(float angle, const GradientStop *firstStop, int stopCount) |
27 | : inner(make_linear_gradient(angle, firstStop, stopCount)) |
28 | { |
29 | } |
30 | |
31 | /// Returns the linear gradient's angle in degrees. |
32 | float angle() const |
33 | { |
34 | // The gradient's first stop is a fake stop to store the angle |
35 | return inner[0].position; |
36 | } |
37 | |
38 | /// Returns the number of gradient stops. |
39 | int stopCount() const { return int(inner.size()) - 1; } |
40 | |
41 | /// Returns a pointer to the first gradient stop; undefined if the gradient has not stops. |
42 | const GradientStop *stopsBegin() const { return inner.begin() + 1; } |
43 | /// Returns a pointer past the last gradient stop. The returned pointer cannot be dereferenced, |
44 | /// it can only be used for comparison. |
45 | const GradientStop *stopsEnd() const { return inner.end(); } |
46 | |
47 | private: |
48 | cbindgen_private::types::LinearGradientBrush inner; |
49 | |
50 | friend class slint::Brush; |
51 | |
52 | static SharedVector<private_api::GradientStop> |
53 | make_linear_gradient(float angle, const GradientStop *firstStop, int stopCount) |
54 | { |
55 | SharedVector<private_api::GradientStop> gradient; |
56 | gradient.push_back(value: { .color: Color::from_argb_encoded(argb_encoded: 0).inner, .position: angle }); |
57 | for (int i = 0; i < stopCount; ++i, ++firstStop) |
58 | gradient.push_back(value: *firstStop); |
59 | return gradient; |
60 | } |
61 | }; |
62 | |
63 | /// \private |
64 | /// RadialGradientBrush represents a circular gradient centered in the middle |
65 | class RadialGradientBrush |
66 | { |
67 | public: |
68 | /// Constructs an empty linear gradient with no color stops. |
69 | RadialGradientBrush() = default; |
70 | /// Constructs a new circular radial gradient . The color stops will be |
71 | /// constructed from the stops array pointed to be \a firstStop, with the length \a stopCount. |
72 | RadialGradientBrush(const GradientStop *firstStop, int stopCount) |
73 | : inner(make_circle_gradient(firstStop, stopCount)) |
74 | { |
75 | } |
76 | |
77 | /// Returns the number of gradient stops. |
78 | int stopCount() const { return int(inner.size()); } |
79 | |
80 | /// Returns a pointer to the first gradient stop; undefined if the gradient has not stops. |
81 | const GradientStop *stopsBegin() const { return inner.begin(); } |
82 | /// Returns a pointer past the last gradient stop. The returned pointer cannot be dereferenced, |
83 | /// it can only be used for comparison. |
84 | const GradientStop *stopsEnd() const { return inner.end(); } |
85 | |
86 | private: |
87 | cbindgen_private::types::RadialGradientBrush inner; |
88 | |
89 | friend class slint::Brush; |
90 | |
91 | static SharedVector<private_api::GradientStop> |
92 | make_circle_gradient(const GradientStop *firstStop, int stopCount) |
93 | { |
94 | SharedVector<private_api::GradientStop> gradient; |
95 | for (int i = 0; i < stopCount; ++i, ++firstStop) |
96 | gradient.push_back(value: *firstStop); |
97 | return gradient; |
98 | } |
99 | }; |
100 | |
101 | } |
102 | |
103 | /// Brush is used to declare how to fill or outline shapes, such as rectangles, paths or text. A |
104 | /// brush is either a solid color or a linear gradient. |
105 | class Brush |
106 | { |
107 | public: |
108 | /// Constructs a new brush that is a transparent color. |
109 | Brush() : Brush(Color {}) { } |
110 | /// Constructs a new brush that is of color \a color. |
111 | Brush(const Color &color) : data(Inner::SolidColor(0: color.inner)) { } |
112 | /// \private |
113 | /// Constructs a new brush that is the gradient \a gradient. |
114 | Brush(const private_api::LinearGradientBrush &gradient) |
115 | : data(Inner::LinearGradient(0: gradient.inner)) |
116 | { |
117 | } |
118 | |
119 | /// \private |
120 | /// Constructs a new brush that is the gradient \a gradient. |
121 | Brush(const private_api::RadialGradientBrush &gradient) |
122 | : data(Inner::RadialGradient(0: gradient.inner)) |
123 | { |
124 | } |
125 | |
126 | /// Returns the color of the brush. If the brush is a gradient, this function returns the color |
127 | /// of the first stop. |
128 | inline Color color() const; |
129 | |
130 | /// Returns a new version of this brush that has the brightness increased |
131 | /// by the specified factor. This is done by calling Color::brighter on |
132 | /// all the colors of this brush. |
133 | [[nodiscard]] inline Brush brighter(float factor) const; |
134 | /// Returns a new version of this color that has the brightness decreased |
135 | /// by the specified factor. This is done by calling Color::darker on |
136 | /// all the colors of this brush. |
137 | [[nodiscard]] inline Brush darker(float factor) const; |
138 | |
139 | /// Returns a new version of this brush with the opacity decreased by \a factor. |
140 | /// |
141 | /// This is done by calling Color::transparentize on all the colors of this brush. |
142 | [[nodiscard]] inline Brush transparentize(float factor) const; |
143 | |
144 | /// Returns a new version of this brush with the related color's opacities |
145 | /// set to \a alpha. |
146 | [[nodiscard]] inline Brush with_alpha(float alpha) const; |
147 | |
148 | /// Returns true if \a a is equal to \a b. If \a a holds a color, then \a b must also hold a |
149 | /// color that is identical to \a a's color. If it holds a gradient, then the gradients must be |
150 | /// identical. Returns false if the brushes differ in what they hold or their respective color |
151 | /// or gradient are not equal. |
152 | friend bool operator==(const Brush &a, const Brush &b) { return a.data == b.data; } |
153 | /// Returns false if \a is not equal to \a b; true otherwise. |
154 | friend bool operator!=(const Brush &a, const Brush &b) { return a.data != b.data; } |
155 | |
156 | private: |
157 | using Tag = cbindgen_private::types::Brush::Tag; |
158 | using Inner = cbindgen_private::types::Brush; |
159 | Inner data; |
160 | friend struct private_api::Property<Brush>; |
161 | }; |
162 | |
163 | Color Brush::color() const |
164 | { |
165 | Color result; |
166 | switch (data.tag) { |
167 | case Tag::SolidColor: |
168 | result.inner = data.solid_color._0; |
169 | break; |
170 | case Tag::LinearGradient: |
171 | if (data.linear_gradient._0.size() > 1) { |
172 | result.inner = data.linear_gradient._0[1].color; |
173 | } |
174 | break; |
175 | case Tag::RadialGradient: |
176 | if (data.radial_gradient._0.size() > 0) { |
177 | result.inner = data.radial_gradient._0[0].color; |
178 | } |
179 | break; |
180 | } |
181 | return result; |
182 | } |
183 | |
184 | inline Brush Brush::brighter(float factor) const |
185 | { |
186 | Brush result = *this; |
187 | switch (data.tag) { |
188 | case Tag::SolidColor: |
189 | cbindgen_private::types::slint_color_brighter(col: &data.solid_color._0, factor, |
190 | out: &result.data.solid_color._0); |
191 | break; |
192 | case Tag::LinearGradient: |
193 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
194 | cbindgen_private::types::slint_color_brighter(col: &data.linear_gradient._0[i].color, factor, |
195 | out: &result.data.linear_gradient._0[i].color); |
196 | } |
197 | break; |
198 | case Tag::RadialGradient: |
199 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
200 | cbindgen_private::types::slint_color_brighter(col: &data.radial_gradient._0[i].color, factor, |
201 | out: &result.data.radial_gradient._0[i].color); |
202 | } |
203 | break; |
204 | } |
205 | return result; |
206 | } |
207 | |
208 | inline Brush Brush::darker(float factor) const |
209 | { |
210 | Brush result = *this; |
211 | switch (data.tag) { |
212 | case Tag::SolidColor: |
213 | cbindgen_private::types::slint_color_darker(col: &data.solid_color._0, factor, |
214 | out: &result.data.solid_color._0); |
215 | break; |
216 | case Tag::LinearGradient: |
217 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
218 | cbindgen_private::types::slint_color_darker(col: &data.linear_gradient._0[i].color, factor, |
219 | out: &result.data.linear_gradient._0[i].color); |
220 | } |
221 | break; |
222 | case Tag::RadialGradient: |
223 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
224 | cbindgen_private::types::slint_color_darker(col: &data.radial_gradient._0[i].color, factor, |
225 | out: &result.data.radial_gradient._0[i].color); |
226 | } |
227 | break; |
228 | } |
229 | return result; |
230 | } |
231 | |
232 | inline Brush Brush::transparentize(float factor) const |
233 | { |
234 | Brush result = *this; |
235 | switch (data.tag) { |
236 | case Tag::SolidColor: |
237 | cbindgen_private::types::slint_color_transparentize(col: &data.solid_color._0, factor, |
238 | out: &result.data.solid_color._0); |
239 | break; |
240 | case Tag::LinearGradient: |
241 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
242 | cbindgen_private::types::slint_color_transparentize( |
243 | col: &data.linear_gradient._0[i].color, factor, |
244 | out: &result.data.linear_gradient._0[i].color); |
245 | } |
246 | break; |
247 | case Tag::RadialGradient: |
248 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
249 | cbindgen_private::types::slint_color_transparentize( |
250 | col: &data.radial_gradient._0[i].color, factor, |
251 | out: &result.data.radial_gradient._0[i].color); |
252 | } |
253 | break; |
254 | } |
255 | return result; |
256 | } |
257 | |
258 | inline Brush Brush::with_alpha(float alpha) const |
259 | { |
260 | Brush result = *this; |
261 | switch (data.tag) { |
262 | case Tag::SolidColor: |
263 | cbindgen_private::types::slint_color_with_alpha(col: &data.solid_color._0, alpha, |
264 | out: &result.data.solid_color._0); |
265 | break; |
266 | case Tag::LinearGradient: |
267 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
268 | cbindgen_private::types::slint_color_with_alpha( |
269 | col: &data.linear_gradient._0[i].color, alpha, |
270 | out: &result.data.linear_gradient._0[i].color); |
271 | } |
272 | break; |
273 | case Tag::RadialGradient: |
274 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
275 | cbindgen_private::types::slint_color_with_alpha( |
276 | col: &data.radial_gradient._0[i].color, alpha, |
277 | out: &result.data.radial_gradient._0[i].color); |
278 | } |
279 | break; |
280 | } |
281 | return result; |
282 | } |
283 | |
284 | namespace private_api { |
285 | |
286 | template<> |
287 | inline void Property<slint::Brush>::set_animated_value( |
288 | const slint::Brush &new_value, |
289 | const cbindgen_private::PropertyAnimation &animation_data) const |
290 | { |
291 | cbindgen_private::slint_property_set_animated_value_brush(&inner, &value, &new_value, |
292 | &animation_data); |
293 | } |
294 | |
295 | } // namespace private_api |
296 | |
297 | } // namespace slint |
298 | |