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
10namespace slint {
11
12namespace private_api {
13
14using 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.
19class LinearGradientBrush
20{
21public:
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
47private:
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
65class RadialGradientBrush
66{
67public:
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
86private:
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.
105class Brush
106{
107public:
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
156private:
157 using Tag = cbindgen_private::types::Brush::Tag;
158 using Inner = cbindgen_private::types::Brush;
159 Inner data;
160};
161
162Color 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
183inline 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
207inline 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
231inline 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
257inline 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

source code of slint/api/cpp/include/slint_brush.h