1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial |
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 | }; |
161 | |
162 | Color Brush::color() const |
163 | { |
164 | Color result; |
165 | switch (data.tag) { |
166 | case Tag::SolidColor: |
167 | result.inner = data.solid_color._0; |
168 | break; |
169 | case Tag::LinearGradient: |
170 | if (data.linear_gradient._0.size() > 1) { |
171 | result.inner = data.linear_gradient._0[1].color; |
172 | } |
173 | break; |
174 | case Tag::RadialGradient: |
175 | if (data.radial_gradient._0.size() > 0) { |
176 | result.inner = data.radial_gradient._0[0].color; |
177 | } |
178 | break; |
179 | } |
180 | return result; |
181 | } |
182 | |
183 | inline Brush Brush::brighter(float factor) const |
184 | { |
185 | Brush result = *this; |
186 | switch (data.tag) { |
187 | case Tag::SolidColor: |
188 | cbindgen_private::types::slint_color_brighter(col: &data.solid_color._0, factor, |
189 | out: &result.data.solid_color._0); |
190 | break; |
191 | case Tag::LinearGradient: |
192 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
193 | cbindgen_private::types::slint_color_brighter(col: &data.linear_gradient._0[i].color, factor, |
194 | out: &result.data.linear_gradient._0[i].color); |
195 | } |
196 | break; |
197 | case Tag::RadialGradient: |
198 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
199 | cbindgen_private::types::slint_color_brighter(col: &data.radial_gradient._0[i].color, factor, |
200 | out: &result.data.radial_gradient._0[i].color); |
201 | } |
202 | break; |
203 | } |
204 | return result; |
205 | } |
206 | |
207 | inline Brush Brush::darker(float factor) const |
208 | { |
209 | Brush result = *this; |
210 | switch (data.tag) { |
211 | case Tag::SolidColor: |
212 | cbindgen_private::types::slint_color_darker(col: &data.solid_color._0, factor, |
213 | out: &result.data.solid_color._0); |
214 | break; |
215 | case Tag::LinearGradient: |
216 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
217 | cbindgen_private::types::slint_color_darker(col: &data.linear_gradient._0[i].color, factor, |
218 | out: &result.data.linear_gradient._0[i].color); |
219 | } |
220 | break; |
221 | case Tag::RadialGradient: |
222 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
223 | cbindgen_private::types::slint_color_darker(col: &data.radial_gradient._0[i].color, factor, |
224 | out: &result.data.radial_gradient._0[i].color); |
225 | } |
226 | break; |
227 | } |
228 | return result; |
229 | } |
230 | |
231 | inline Brush Brush::transparentize(float factor) const |
232 | { |
233 | Brush result = *this; |
234 | switch (data.tag) { |
235 | case Tag::SolidColor: |
236 | cbindgen_private::types::slint_color_transparentize(col: &data.solid_color._0, factor, |
237 | out: &result.data.solid_color._0); |
238 | break; |
239 | case Tag::LinearGradient: |
240 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
241 | cbindgen_private::types::slint_color_transparentize( |
242 | col: &data.linear_gradient._0[i].color, factor, |
243 | out: &result.data.linear_gradient._0[i].color); |
244 | } |
245 | break; |
246 | case Tag::RadialGradient: |
247 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
248 | cbindgen_private::types::slint_color_transparentize( |
249 | col: &data.radial_gradient._0[i].color, factor, |
250 | out: &result.data.radial_gradient._0[i].color); |
251 | } |
252 | break; |
253 | } |
254 | return result; |
255 | } |
256 | |
257 | inline Brush Brush::with_alpha(float alpha) const |
258 | { |
259 | Brush result = *this; |
260 | switch (data.tag) { |
261 | case Tag::SolidColor: |
262 | cbindgen_private::types::slint_color_with_alpha(col: &data.solid_color._0, alpha, |
263 | out: &result.data.solid_color._0); |
264 | break; |
265 | case Tag::LinearGradient: |
266 | for (std::size_t i = 1; i < data.linear_gradient._0.size(); ++i) { |
267 | cbindgen_private::types::slint_color_with_alpha( |
268 | col: &data.linear_gradient._0[i].color, alpha, |
269 | out: &result.data.linear_gradient._0[i].color); |
270 | } |
271 | break; |
272 | case Tag::RadialGradient: |
273 | for (std::size_t i = 0; i < data.linear_gradient._0.size(); ++i) { |
274 | cbindgen_private::types::slint_color_with_alpha( |
275 | col: &data.radial_gradient._0[i].color, alpha, |
276 | out: &result.data.radial_gradient._0[i].color); |
277 | } |
278 | break; |
279 | } |
280 | return result; |
281 | } |
282 | } |
283 | |