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 | |
6 | #include "slint_color_internal.h" |
7 | #include "slint_properties.h" |
8 | |
9 | #include <stdint.h> |
10 | |
11 | namespace slint { |
12 | |
13 | namespace private_api { |
14 | class LinearGradientBrush; |
15 | } |
16 | |
17 | class Color; |
18 | |
19 | /// RgbaColor stores the red, green, blue and alpha components of a color |
20 | /// with the precision of the template parameter T. For example if T is float, |
21 | /// the values are normalized between 0 and 1. If T is uint8_t, they values range |
22 | /// is 0 to 255. |
23 | template<typename T> |
24 | struct RgbaColor |
25 | { |
26 | /// The alpha component. |
27 | T alpha; |
28 | /// The red component. |
29 | T red; |
30 | /// The green component. |
31 | T green; |
32 | /// The blue component. |
33 | T blue; |
34 | |
35 | /// Creates a new RgbaColor instance from a given color. This template function is |
36 | /// specialized and thus implemented for T == uint8_t and T == float. |
37 | RgbaColor(const Color &col); |
38 | }; |
39 | |
40 | /// Color represents a color in the Slint run-time, represented using 8-bit channels for |
41 | /// red, green, blue and the alpha (opacity). |
42 | class Color |
43 | { |
44 | public: |
45 | /// Default constructs a new color that is entirely transparent. |
46 | Color() { inner.red = inner.green = inner.blue = inner.alpha = 0; } |
47 | /// Constructs a new color from the given RgbaColor<uint8_t> \a col. |
48 | Color(const RgbaColor<uint8_t> &col) |
49 | { |
50 | inner.red = col.red; |
51 | inner.green = col.green; |
52 | inner.blue = col.blue; |
53 | inner.alpha = col.alpha; |
54 | } |
55 | /// Constructs a new color from the given RgbaColor<float> \a col. |
56 | Color(const RgbaColor<float> &col) |
57 | { |
58 | inner.red = uint8_t(col.red * 255); |
59 | inner.green = uint8_t(col.green * 255); |
60 | inner.blue = uint8_t(col.blue * 255); |
61 | inner.alpha = uint8_t(col.alpha * 255); |
62 | } |
63 | |
64 | /// Construct a color from an integer encoded as `0xAARRGGBB` |
65 | [[nodiscard]] static Color from_argb_encoded(uint32_t argb_encoded) |
66 | { |
67 | Color col; |
68 | col.inner.red = (argb_encoded >> 16) & 0xff; |
69 | col.inner.green = (argb_encoded >> 8) & 0xff; |
70 | col.inner.blue = argb_encoded & 0xff; |
71 | col.inner.alpha = (argb_encoded >> 24) & 0xff; |
72 | return col; |
73 | } |
74 | |
75 | /// Returns `(alpha, red, green, blue)` encoded as uint32_t. |
76 | uint32_t as_argb_encoded() const |
77 | { |
78 | return (uint32_t(inner.red) << 16) | (uint32_t(inner.green) << 8) | uint32_t(inner.blue) |
79 | | (uint32_t(inner.alpha) << 24); |
80 | } |
81 | |
82 | /// Construct a color from the alpha, red, green and blue color channel parameters. |
83 | [[nodiscard]] static Color from_argb_uint8(uint8_t alpha, uint8_t red, uint8_t green, |
84 | uint8_t blue) |
85 | { |
86 | Color col; |
87 | col.inner.alpha = alpha; |
88 | col.inner.red = red; |
89 | col.inner.green = green; |
90 | col.inner.blue = blue; |
91 | return col; |
92 | } |
93 | |
94 | /// Construct a color from the red, green and blue color channel parameters. The alpha |
95 | /// channel will have the value 255. |
96 | [[nodiscard]] static Color from_rgb_uint8(uint8_t red, uint8_t green, uint8_t blue) |
97 | { |
98 | return from_argb_uint8(alpha: 255, red, green, blue); |
99 | } |
100 | |
101 | /// Construct a color from the alpha, red, green and blue color channel parameters. |
102 | [[nodiscard]] static Color from_argb_float(float alpha, float red, float green, float blue) |
103 | { |
104 | Color col; |
105 | col.inner.alpha = uint8_t(alpha * 255); |
106 | col.inner.red = uint8_t(red * 255); |
107 | col.inner.green = uint8_t(green * 255); |
108 | col.inner.blue = uint8_t(blue * 255); |
109 | return col; |
110 | } |
111 | |
112 | /// Construct a color from the red, green and blue color channel parameters. The alpha |
113 | /// channel will have the value 255. |
114 | [[nodiscard]] static Color from_rgb_float(float red, float green, float blue) |
115 | { |
116 | return Color::from_argb_float(alpha: 1.0, red, green, blue); |
117 | } |
118 | |
119 | /// Converts this color to an RgbaColor struct for easy destructuring. |
120 | inline RgbaColor<uint8_t> to_argb_uint() const; |
121 | |
122 | /// Converts this color to an RgbaColor struct for easy destructuring. |
123 | inline RgbaColor<float> to_argb_float() const; |
124 | |
125 | /// Returns the red channel of the color as u8 in the range 0..255. |
126 | uint8_t red() const { return inner.red; } |
127 | |
128 | /// Returns the green channel of the color as u8 in the range 0..255. |
129 | uint8_t green() const { return inner.green; } |
130 | |
131 | /// Returns the blue channel of the color as u8 in the range 0..255. |
132 | uint8_t blue() const { return inner.blue; } |
133 | |
134 | /// Returns the alpha channel of the color as u8 in the range 0..255. |
135 | uint8_t alpha() const { return inner.alpha; } |
136 | |
137 | /// Returns a new version of this color that has the brightness increased |
138 | /// by the specified factor. This is done by converting the color to the HSV |
139 | /// color space and multiplying the brightness (value) with (1 + factor). |
140 | /// The result is converted back to RGB and the alpha channel is unchanged. |
141 | /// So for example `brighter(0.2)` will increase the brightness by 20%, and |
142 | /// calling `brighter(-0.5)` will return a color that's 50% darker. |
143 | [[nodiscard]] inline Color brighter(float factor) const; |
144 | /// Returns a new version of this color that has the brightness decreased |
145 | /// by the specified factor. This is done by converting the color to the HSV |
146 | /// color space and dividing the brightness (value) by (1 + factor). The |
147 | /// result is converted back to RGB and the alpha channel is unchanged. |
148 | /// So for example `darker(0.3)` will decrease the brightness by 30%. |
149 | [[nodiscard]] inline Color darker(float factor) const; |
150 | |
151 | /// Returns a new version of this color with the opacity decreased by \a factor. |
152 | /// |
153 | /// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`. |
154 | [[nodiscard]] inline Color transparentize(float factor) const; |
155 | |
156 | /// Returns a new color that is a mix of \a this and \a other, with a proportion |
157 | /// factor given by \a factor (which will be clamped to be between `0.0` and `1.0`). |
158 | [[nodiscard]] inline Color mix(const Color &other, float factor) const; |
159 | |
160 | /// Returns a new version of this color with the opacity set to \a alpha. |
161 | [[nodiscard]] inline Color with_alpha(float alpha) const; |
162 | |
163 | /// Returns true if \a lhs has the same values for the individual color channels as \a rhs; |
164 | /// false otherwise. |
165 | friend bool operator==(const Color &lhs, const Color &rhs) = default; |
166 | |
167 | /// Writes the \a color to the specified \a stream and returns a reference to the |
168 | /// stream. |
169 | friend std::ostream &operator<<(std::ostream &stream, const Color &color) |
170 | { |
171 | // Cast to uint32_t to avoid the components being interpreted as char. |
172 | return stream << "argb(" << uint32_t(color.inner.alpha) << ", " << uint32_t(color.inner.red) |
173 | << ", " << uint32_t(color.inner.green) << ", " << uint32_t(color.inner.blue) |
174 | << ")" ; |
175 | } |
176 | |
177 | #if !defined(DOXYGEN) |
178 | // FIXME: we need this to create GradientStop |
179 | operator const cbindgen_private::types::Color &() const |
180 | { |
181 | return inner; |
182 | } |
183 | #endif |
184 | |
185 | private: |
186 | cbindgen_private::types::Color inner; |
187 | friend class private_api::LinearGradientBrush; |
188 | friend class Brush; |
189 | }; |
190 | |
191 | inline Color Color::brighter(float factor) const |
192 | { |
193 | Color result; |
194 | cbindgen_private::types::slint_color_brighter(col: &inner, factor, out: &result.inner); |
195 | return result; |
196 | } |
197 | |
198 | inline Color Color::darker(float factor) const |
199 | { |
200 | Color result; |
201 | cbindgen_private::types::slint_color_darker(col: &inner, factor, out: &result.inner); |
202 | return result; |
203 | } |
204 | |
205 | inline Color Color::transparentize(float factor) const |
206 | { |
207 | Color result; |
208 | cbindgen_private::types::slint_color_transparentize(col: &inner, factor, out: &result.inner); |
209 | return result; |
210 | } |
211 | |
212 | inline Color Color::mix(const Color &other, float factor) const |
213 | { |
214 | Color result; |
215 | cbindgen_private::types::slint_color_mix(col1: &inner, col2: &other.inner, factor, out: &result.inner); |
216 | return result; |
217 | } |
218 | |
219 | inline Color Color::with_alpha(float alpha) const |
220 | { |
221 | Color result; |
222 | cbindgen_private::types::slint_color_with_alpha(col: &inner, alpha, out: &result.inner); |
223 | return result; |
224 | } |
225 | |
226 | /// Constructs a new RgbaColor<uint8_t> from the color \a color. |
227 | template<> |
228 | inline RgbaColor<uint8_t>::RgbaColor(const Color &color) |
229 | { |
230 | red = color.red(); |
231 | green = color.green(); |
232 | blue = color.blue(); |
233 | alpha = color.alpha(); |
234 | } |
235 | |
236 | /// Constructs a new RgbaColor<float> from the color \a color. |
237 | template<> |
238 | inline RgbaColor<float>::RgbaColor(const Color &color) |
239 | { |
240 | red = float(color.red()) / 255.f; |
241 | green = float(color.green()) / 255.f; |
242 | blue = float(color.blue()) / 255.f; |
243 | alpha = float(color.alpha()) / 255.f; |
244 | } |
245 | |
246 | RgbaColor<uint8_t> Color::to_argb_uint() const |
247 | { |
248 | return RgbaColor<uint8_t>(*this); |
249 | } |
250 | |
251 | RgbaColor<float> Color::to_argb_float() const |
252 | { |
253 | return RgbaColor<float>(*this); |
254 | } |
255 | |
256 | namespace private_api { |
257 | |
258 | template<> |
259 | inline void |
260 | Property<Color>::set_animated_value(const Color &new_value, |
261 | const cbindgen_private::PropertyAnimation &animation_data) const |
262 | { |
263 | cbindgen_private::slint_property_set_animated_value_color(handle: &inner, from: value, to: new_value, |
264 | animation_data: &animation_data); |
265 | } |
266 | |
267 | } // namespace private_api |
268 | |
269 | } // namespace slint |
270 | |