chromatic/spaces/hsv_alpha.rs
1//! HSV colour with transparency representation.
2
3use num_traits::Float;
4use std::fmt::{Display, Formatter, Result as FmtResult};
5
6use crate::{
7 error::{Result, normalize_hue, validate_unit_component},
8 impl_transparent_colour, impl_transparent_convert, impl_transparent_display,
9 spaces::{Grey, GreyAlpha, Hsl, HslAlpha, Hsv, Lab, LabAlpha, Rgb, RgbAlpha, Srgb, SrgbAlpha, Xyz, XyzAlpha},
10 traits::{Colour, Convert},
11};
12
13/// HSV with alpha channel.
14#[derive(Debug, Clone, Copy)]
15pub struct HsvAlpha<T: Float + Send + Sync> {
16 /// Base colour
17 colour: Hsv<T>,
18 /// Alpha component in range [0, 1].
19 alpha: T,
20}
21
22impl<T: Float + Send + Sync> HsvAlpha<T> {
23 /// Create a new `HsvAlpha` instance.
24 ///
25 /// # Arguments
26 ///
27 /// * `hue` - The hue in degrees, will be normalized to [0, 360)
28 /// * `saturation` - The saturation, must be in range [0, 1]
29 /// * `value` - The value (brightness), must be in range [0, 1]
30 /// * `alpha` - The alpha (transparency) component, must be in range [0, 1]
31 ///
32 /// # Errors
33 ///
34 /// Returns an error if saturation, value, or alpha are outside [0, 1],
35 /// or if hue normalization fails.
36 pub fn new(hue: T, saturation: T, value: T, alpha: T) -> Result<Self> {
37 validate_unit_component(alpha, "alpha")?;
38
39 Ok(Self {
40 colour: Hsv::new(hue, saturation, value)?,
41 alpha,
42 })
43 }
44
45 /// Create a new `HsvAlpha` instance from a `Hsv` colour and an alpha component.
46 ///
47 /// # Arguments
48 ///
49 /// * `colour` - The base HSV colour
50 /// * `alpha` - The alpha (transparency) component, must be in range [0, 1]
51 ///
52 /// # Errors
53 ///
54 /// Returns an error if the alpha component is outside the range [0, 1].
55 fn new_colour_with_alpha(colour: Hsv<T>, alpha: T) -> Result<Self> {
56 validate_unit_component(alpha, "alpha")?;
57
58 Ok(Self { colour, alpha })
59 }
60
61 /// Get the base `colour`.
62 const fn colour(&self) -> &Hsv<T> {
63 &self.colour
64 }
65
66 /// Get the `hue` component in degrees [0, 360).
67 pub const fn hue(&self) -> T {
68 self.colour.hue()
69 }
70
71 /// Get the `saturation` component.
72 pub const fn saturation(&self) -> T {
73 self.colour.saturation()
74 }
75
76 /// Get the `value` component.
77 pub const fn value(&self) -> T {
78 self.colour.value()
79 }
80
81 /// Get the `alpha` component.
82 pub const fn alpha(&self) -> T {
83 self.alpha
84 }
85
86 /// Set the `hue` component.
87 ///
88 /// # Arguments
89 ///
90 /// * `hue` - The new hue in degrees, will be normalized to [0, 360)
91 ///
92 /// # Errors
93 ///
94 /// Returns an error if hue normalization fails.
95 pub fn set_hue(&mut self, hue: T) -> Result<()> {
96 self.colour.set_hue(hue)
97 }
98
99 /// Set the `saturation` component.
100 ///
101 /// # Arguments
102 ///
103 /// * `saturation` - The new saturation, must be in range [0, 1]
104 ///
105 /// # Errors
106 ///
107 /// Returns an error if the value is outside the range [0, 1].
108 pub fn set_saturation(&mut self, saturation: T) -> Result<()> {
109 self.colour.set_saturation(saturation)
110 }
111
112 /// Set the `value` component.
113 ///
114 /// # Arguments
115 ///
116 /// * `value` - The new value (brightness), must be in range [0, 1]
117 ///
118 /// # Errors
119 ///
120 /// Returns an error if the value is outside the range [0, 1].
121 pub fn set_value(&mut self, value: T) -> Result<()> {
122 self.colour.set_value(value)
123 }
124
125 /// Set the `alpha` component.
126 ///
127 /// # Arguments
128 ///
129 /// * `alpha` - The new alpha value, must be in range [0, 1]
130 ///
131 /// # Errors
132 ///
133 /// Returns an error if the value is outside the range [0, 1].
134 pub fn set_alpha(&mut self, alpha: T) -> Result<()> {
135 validate_unit_component(alpha, "alpha")?;
136 self.alpha = alpha;
137 Ok(())
138 }
139
140 /// Set all components at once with validation.
141 ///
142 /// # Arguments
143 ///
144 /// * `hue` - The hue in degrees, will be normalized to [0, 360)
145 /// * `saturation` - The saturation, must be in range [0, 1]
146 /// * `value` - The value (brightness), must be in range [0, 1]
147 /// * `alpha` - The alpha component, must be in range [0, 1]
148 ///
149 /// # Errors
150 ///
151 /// Returns an error if any component validation fails.
152 pub fn set_components(&mut self, hue: T, saturation: T, value: T, alpha: T) -> Result<()> {
153 let normalized_hue = normalize_hue(hue)?;
154 validate_unit_component(saturation, "saturation")?;
155 validate_unit_component(value, "value")?;
156 validate_unit_component(alpha, "alpha")?;
157
158 // If all validations pass, update all components
159 self.colour = Hsv::new(normalized_hue, saturation, value)?;
160 self.alpha = alpha;
161 Ok(())
162 }
163}
164
165impl_transparent_colour!(HsvAlpha<T>, Hsv<T>, 3);
166impl_transparent_convert!(HsvAlpha<T>, Hsv<T>);
167impl_transparent_display!(HsvAlpha<T>);