1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Types related to transparent colors.

#[doc(hidden)]
pub use palette_derive::WithAlpha;

use crate::{num::Zero, stimulus::Stimulus};

pub use self::alpha::*;

#[doc(no_inline)]
pub use crate::blend::PreAlpha; // Cross-link for visibility.

#[allow(clippy::module_inception)]
mod alpha;

/// A trait for color types that can have or be given transparency (alpha channel).
///
/// `WithAlpha` is an interface for adding, removing and setting the alpha
/// channel of a color type. The color type itself doesn't need to store the
/// transparency value as it can be transformed into or wrapped in a type that
/// has a representation of transparency. This would typically be done by
/// wrapping it in an [`Alpha`] instance.
///
/// # Deriving
/// The trait is trivial enough to be automatically derived. If the color type
/// has a field for transparency (an alpha channel), it has to be marked with
/// `#[palette(alpha)]` to be taken into account.
///
/// Derived without an internal alpha channel:
///
/// ```
/// use palette::WithAlpha;
///
/// #[derive(WithAlpha)]
/// struct CustomColor {
///     redness: f32,
///     glow: f32,
///     glitter: f32,
/// }
///
/// let color = CustomColor {
///     redness: 0.8,
///     glow: 2.5,
///     glitter: 1000.0
/// };
/// let transparent = color.with_alpha(0.3);
///
/// assert_eq!(transparent.alpha, 0.3);
/// ```
///
/// Derived with an internal alpha channel:
///
/// ```
/// use palette::WithAlpha;
///
/// #[derive(WithAlpha)]
/// struct CustomColor {
///     redness: f32,
///     glow: f32,
///     glitter: f32,
///
///     #[palette(alpha)]
///     alpha: u8,
/// }
///
/// let color = CustomColor {
///     redness: 0.8,
///     glow: 2.5,
///     glitter: 1000.0,
///     alpha: 255
/// };
/// let transparent = color.with_alpha(10);
///
/// assert_eq!(transparent.alpha, 10);
/// ```
pub trait WithAlpha<A>: Sized {
    /// The opaque color type, without any transparency.
    ///
    /// This is typically `Self`.
    type Color;

    /// The color type with transparency applied.
    ///
    /// This is typically `Alpha<Self::Color, A>`.
    type WithAlpha: WithAlpha<A, Color = Self::Color, WithAlpha = Self::WithAlpha>;

    /// Transforms the color into a transparent color with the provided
    /// alpha value. If `Self` already has a transparency, it is
    /// overwritten.
    ///
    /// ```
    /// use palette::{Srgb, WithAlpha};
    ///
    /// let color = Srgb::new(255u8, 0, 255);
    ///
    /// // This results in an `Alpha<Srgb<u8>, f32>`
    /// let transparent = color.with_alpha(0.3f32);
    /// assert_eq!(transparent.alpha, 0.3);
    ///
    /// // This changes the transparency to 0.8
    /// let transparent = transparent.with_alpha(0.8f32);
    /// assert_eq!(transparent.alpha, 0.8);
    /// ```
    #[must_use]
    fn with_alpha(self, alpha: A) -> Self::WithAlpha;

    /// Removes the transparency from the color. If `Self::Color` has
    /// an internal transparency field, that field will be set to
    /// `A::max_intensity()` to make it opaque.
    ///
    /// ```
    /// use palette::{Srgba, Srgb, WithAlpha};
    ///
    /// let transparent = Srgba::new(255u8, 0, 255, 10);
    ///
    /// // This unwraps the color information from the `Alpha` wrapper
    /// let color = transparent.without_alpha();
    /// assert_eq!(transparent.color, color);
    /// ```
    #[must_use]
    fn without_alpha(self) -> Self::Color;

    /// Splits the color into separate color and transparency values.
    ///
    /// A color without any transparency field will return
    /// `A::max_intensity()` instead. If `Self::Color` has an internal
    /// transparency field, that field will be set to
    /// `A::max_intensity()` to make it opaque.
    ///
    /// ```
    /// use palette::{Srgba, Srgb, WithAlpha};
    ///
    /// let transparent = Srgba::new(255u8, 0, 255, 10);
    ///
    /// // This unwraps both the color and alpha from the `Alpha` wrapper
    /// let (color, alpha) = transparent.split();
    /// assert_eq!(transparent.color, color);
    /// assert_eq!(transparent.alpha, alpha);
    /// ```
    #[must_use]
    fn split(self) -> (Self::Color, A);

    /// Transforms the color into a fully opaque color with a transparency
    /// field. If `Self` already has a transparency, it is overwritten.
    ///
    /// ```
    /// use palette::{Srgb, Srgba, WithAlpha};
    ///
    /// let color = Srgb::new(255u8, 0, 255);
    ///
    /// let opaque: Srgba<u8> = color.opaque();
    /// assert_eq!(opaque.alpha, 255);
    /// ```
    #[must_use]
    #[inline]
    fn opaque(self) -> Self::WithAlpha
    where
        A: Stimulus,
    {
        self.with_alpha(A::max_intensity())
    }

    /// Transforms the color into a fully transparent color. If `Self`
    /// already has a transparency, it is overwritten.
    ///
    /// ```
    /// use palette::{Srgb, Srgba, WithAlpha};
    ///
    /// let color = Srgb::new(255u8, 0, 255);
    ///
    /// let transparent: Srgba<u8> = color.transparent();
    /// assert_eq!(transparent.alpha, 0);
    /// ```
    #[must_use]
    #[inline]
    fn transparent(self) -> Self::WithAlpha
    where
        A: Zero,
    {
        self.with_alpha(A::zero())
    }
}