Skip to main content

color_output/color/
impl.rs

1use crate::*;
2
3impl ColorDisplay for Color {
4    fn get_str(&self, display_type: DisplayType) -> String {
5        let str: &str = match display_type {
6            DisplayType::Text => match self {
7                Color::Red => RED,
8                Color::Green => GREEN,
9                Color::Blue => BLUE,
10                Color::Yellow => YELLOW,
11                Color::Black => BLACK,
12                Color::White => WHITE,
13                Color::Default => DEFAULT,
14                Color::Magenta => MAGENTA,
15                Color::Cyan => CYAN,
16            },
17            DisplayType::Background => match self {
18                Color::Red => BG_RED,
19                Color::Green => BG_GREEN,
20                Color::Blue => BG_BLUE,
21                Color::Yellow => BG_YELLOW,
22                Color::Black => BG_BLACK,
23                Color::White => BG_WHITE,
24                Color::Default => DEFAULT,
25                Color::Magenta => BG_MAGENTA,
26                Color::Cyan => BG_CYAN,
27            },
28        };
29        str.to_string()
30    }
31}
32
33impl Display for Color {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        write!(f, "{}", self.get_str(DisplayType::Text))
36    }
37}
38
39impl Display for ColorType {
40    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41        write!(f, "{}", self.get_str(DisplayType::Text))
42    }
43}
44
45impl ColorDisplay for ColorType {
46    fn get_str(&self, display_type: DisplayType) -> String {
47        match self {
48            ColorType::Color256(fg) => match display_type {
49                DisplayType::Text => color256_fg_color(*fg),
50                DisplayType::Background => color256_bg_color(*fg),
51            },
52            ColorType::Rgb(r, g, b) => match display_type {
53                DisplayType::Text => rgb_fg_color(*r, *g, *b),
54                DisplayType::Background => rgb_bg_color(*r, *g, *b),
55            },
56            ColorType::Use(color) => color.get_str(display_type),
57        }
58    }
59}
60
61impl Default for ColorType {
62    fn default() -> Self {
63        ColorType::Use(Color::Default)
64    }
65}
66
67impl ColorContrast {
68    /// Calculates the relative luminance of a color.
69    ///
70    /// # Arguments
71    ///
72    /// - `u8` - Red component (0-255)
73    /// - `u8` - Green component (0-255)
74    /// - `u8` - Blue component (0-255)
75    ///
76    /// # Returns
77    ///
78    /// - `f64` - Relative luminance value (0.0-1.0)
79    pub fn calculate_luminance(r: u8, g: u8, b: u8) -> f64 {
80        let r_norm: f64 = r as f64 / 255.0;
81        let g_norm: f64 = g as f64 / 255.0;
82        let b_norm: f64 = b as f64 / 255.0;
83        let r_linear: f64 = if r_norm <= 0.03928 {
84            r_norm / 12.92
85        } else {
86            ((r_norm + 0.055) / 1.055).powf(2.4)
87        };
88        let g_linear: f64 = if g_norm <= 0.03928 {
89            g_norm / 12.92
90        } else {
91            ((g_norm + 0.055) / 1.055).powf(2.4)
92        };
93        let b_linear: f64 = if b_norm <= 0.03928 {
94            b_norm / 12.92
95        } else {
96            ((b_norm + 0.055) / 1.055).powf(2.4)
97        };
98        0.2126 * r_linear + 0.7152 * g_linear + 0.0722 * b_linear
99    }
100
101    /// Calculates the contrast ratio between two colors.
102    ///
103    /// # Arguments
104    ///
105    /// - `(u8, u8, u8)` - First color RGB values
106    /// - `(u8, u8, u8)` - Second color RGB values
107    ///
108    /// # Returns
109    ///
110    /// - `f64` - Contrast ratio (1.0-21.0)
111    pub fn calculate_contrast_ratio(color1: (u8, u8, u8), color2: (u8, u8, u8)) -> f64 {
112        let lum1: f64 = Self::calculate_luminance(color1.0, color1.1, color1.2);
113        let lum2: f64 = Self::calculate_luminance(color2.0, color2.1, color2.2);
114        let lighter: f64 = lum1.max(lum2);
115        let darker: f64 = lum1.min(lum2);
116        (lighter + 0.05) / (darker + 0.05)
117    }
118
119    /// Extracts RGB values from ColorType.
120    ///
121    /// # Arguments
122    ///
123    /// - `&ColorType` - Color to extract RGB from
124    ///
125    /// # Returns
126    ///
127    /// - `(u8, u8, u8)` - RGB values
128    pub fn extract_rgb_from_color_type(color: &ColorType) -> (u8, u8, u8) {
129        match color {
130            ColorType::Rgb(r, g, b) => (*r, *g, *b),
131            ColorType::Color256(hex) => {
132                let r: u8 = ((hex >> 16) & 0xFF) as u8;
133                let g: u8 = ((hex >> 8) & 0xFF) as u8;
134                let b: u8 = (hex & 0xFF) as u8;
135                (r, g, b)
136            }
137            ColorType::Use(color) => {
138                use super::r#enum::Color;
139                match color {
140                    Color::Default => (128, 128, 128),
141                    Color::Black => (0, 0, 0),
142                    Color::Red => (255, 0, 0),
143                    Color::Green => (0, 255, 0),
144                    Color::Yellow => (255, 255, 0),
145                    Color::Blue => (0, 0, 255),
146                    Color::Magenta => (255, 0, 255),
147                    Color::Cyan => (0, 255, 255),
148                    Color::White => (255, 255, 255),
149                }
150            }
151        }
152    }
153
154    /// Checks if two colors have sufficient contrast for readability.
155    ///
156    /// # Arguments
157    ///
158    /// - `&ColorType` - Text color
159    /// - `&ColorType` - Background color
160    ///
161    /// # Returns
162    ///
163    /// - `bool` - Whether contrast is sufficient (ratio >= 4.5)
164    pub fn has_sufficient_contrast(text_color: &ColorType, bg_color: &ColorType) -> bool {
165        let text_rgb: (u8, u8, u8) = Self::extract_rgb_from_color_type(text_color);
166        let bg_rgb: (u8, u8, u8) = Self::extract_rgb_from_color_type(bg_color);
167        let ratio: f64 = Self::calculate_contrast_ratio(text_rgb, bg_rgb);
168        ratio >= 4.5
169    }
170
171    /// Automatically adjusts text color to ensure sufficient contrast with background.
172    ///
173    /// # Arguments
174    ///
175    /// - `&ColorType` - Original text color
176    /// - `&ColorType` - Background color
177    ///
178    /// # Returns
179    ///
180    /// - `ColorType` - Adjusted text color with sufficient contrast
181    pub fn ensure_sufficient_contrast(text_color: &ColorType, bg_color: &ColorType) -> ColorType {
182        if Self::has_sufficient_contrast(text_color, bg_color) {
183            return *text_color;
184        }
185        let text_rgb: (u8, u8, u8) = Self::extract_rgb_from_color_type(text_color);
186        let bg_rgb: (u8, u8, u8) = Self::extract_rgb_from_color_type(bg_color);
187        let bg_luminance: f64 = Self::calculate_luminance(bg_rgb.0, bg_rgb.1, bg_rgb.2);
188        if bg_luminance > 0.5 {
189            Self::darken_color_for_contrast(text_rgb, bg_rgb)
190        } else {
191            Self::lighten_color_for_contrast(text_rgb, bg_rgb)
192        }
193    }
194
195    /// Darkens a color while preserving its hue for better contrast against light backgrounds.
196    ///
197    /// # Arguments
198    ///
199    /// - `(u8, u8, u8)` - Original text color RGB
200    /// - `(u8, u8, u8)` - Background color RGB
201    ///
202    /// # Returns
203    ///
204    /// - `ColorType` - Darkened color with sufficient contrast
205    pub fn darken_color_for_contrast(text_rgb: (u8, u8, u8), bg_rgb: (u8, u8, u8)) -> ColorType {
206        let (r, g, b): (u8, u8, u8) = text_rgb;
207        let max_component: u8 = r.max(g).max(b);
208        if max_component == 0 {
209            return ColorType::Rgb(0, 0, 0);
210        }
211        let scale_factor: f64 = 0.3;
212        let new_r: u8 = ((r as f64 * scale_factor) as u8).min(80);
213        let new_g: u8 = ((g as f64 * scale_factor) as u8).min(80);
214        let new_b: u8 = ((b as f64 * scale_factor) as u8).min(80);
215        let result_color: ColorType = ColorType::Rgb(new_r, new_g, new_b);
216        if Self::calculate_contrast_ratio((new_r, new_g, new_b), bg_rgb) >= 4.5 {
217            result_color
218        } else {
219            ColorType::Rgb(0, 0, 0)
220        }
221    }
222
223    /// Lightens a color while preserving its hue for better contrast against dark backgrounds.
224    ///
225    /// # Arguments
226    ///
227    /// - `(u8, u8, u8)` - Original text color RGB
228    /// - `(u8, u8, u8)` - Background color RGB
229    ///
230    /// # Returns
231    ///
232    /// - `ColorType` - Lightened color with sufficient contrast
233    pub fn lighten_color_for_contrast(text_rgb: (u8, u8, u8), bg_rgb: (u8, u8, u8)) -> ColorType {
234        let (r, g, b): (u8, u8, u8) = text_rgb;
235        let scale_factor: f64 = 2.5;
236        let new_r: u8 = ((r as f64 * scale_factor) as u8).max(200);
237        let new_g: u8 = ((g as f64 * scale_factor) as u8).max(200);
238        let new_b: u8 = ((b as f64 * scale_factor) as u8).max(200);
239        let result_color: ColorType = ColorType::Rgb(new_r, new_g, new_b);
240        if Self::calculate_contrast_ratio((new_r, new_g, new_b), bg_rgb) >= 4.5 {
241            result_color
242        } else {
243            ColorType::Rgb(255, 255, 255)
244        }
245    }
246}
247
248/// Default implementation for ColorOutput with empty configuration.
249impl<'a> Default for ColorOutput<'a> {
250    #[inline(always)]
251    fn default() -> Self {
252        ColorOutput {
253            text: "",
254            color: ColorType::default(),
255            bg_color: ColorType::default(),
256            bold: false,
257            endl: false,
258        }
259    }
260}
261
262impl<'a> ColorOutput<'a> {
263    /// Executes the output operation with current configuration.
264    ///
265    /// # Returns
266    ///
267    /// - `()` - No return value
268    #[inline(always)]
269    pub fn output(self) {
270        output(self);
271    }
272}
273
274/// Implementation of ColorOutputBuilder methods.
275impl<'a> Default for ColorOutputBuilder<'a> {
276    #[inline(always)]
277    fn default() -> Self {
278        Self::new()
279    }
280}
281
282impl<'a> ColorOutputBuilder<'a> {
283    /// Creates a new ColorOutputBuilder instance.
284    ///
285    /// # Returns
286    ///
287    /// - `ColorOutputBuilder<'a>` - The new builder instance.
288    #[inline(always)]
289    pub fn new() -> Self {
290        Self {
291            output: ColorOutput::default(),
292        }
293    }
294
295    /// Creates a new ColorOutputBuilder from existing ColorOutput.
296    ///
297    /// # Arguments
298    ///
299    /// - `ColorOutput` - The output configuration to initialize from
300    ///
301    /// # Returns
302    ///
303    /// - `ColorOutputBuilder` - The new builder instance
304    #[inline(always)]
305    pub fn new_from(output: ColorOutput<'a>) -> Self {
306        Self { output }
307    }
308
309    /// Sets the output text.
310    ///
311    /// # Arguments
312    ///
313    /// - `&str` - The text content to display
314    ///
315    /// # Returns
316    ///
317    /// - `&mut Self` - The builder for method chaining
318    #[inline(always)]
319    pub fn text(&mut self, text: &'a str) -> &mut Self {
320        self.output.text = text;
321        self
322    }
323
324    /// Sets the text color.
325    ///
326    /// # Arguments
327    ///
328    /// - `ColorType` - The color to apply to text
329    ///
330    /// # Returns
331    ///
332    /// - `&mut Self` - The builder for method chaining
333    #[inline(always)]
334    pub fn color(&mut self, color: ColorType) -> &mut Self {
335        self.output.color = color;
336        self
337    }
338
339    /// Sets the background color.
340    ///
341    /// # Arguments
342    ///
343    /// - `ColorType` - The background color type.
344    ///
345    /// # Returns
346    ///
347    /// - `&mut Self` - The builder for chaining.
348    #[inline(always)]
349    pub fn bg_color(&mut self, bg_color: ColorType) -> &mut Self {
350        self.output.bg_color = bg_color;
351        self
352    }
353
354    /// Sets bold text style.
355    ///
356    /// # Arguments
357    ///
358    /// - `bool` - Whether to use bold style.
359    ///
360    /// # Returns
361    ///
362    /// - `&mut Self` - The builder for chaining.
363    #[inline(always)]
364    pub fn bold(&mut self, bold: bool) -> &mut Self {
365        self.output.bold = bold;
366        self
367    }
368
369    /// Sets whether to add newline at end.
370    ///
371    /// # Arguments
372    ///
373    /// - `bool` - Whether to add newline.
374    ///
375    /// # Returns
376    ///
377    /// - `&mut Self` - The builder for chaining.
378    #[inline(always)]
379    pub fn endl(&mut self, endl: bool) -> &mut Self {
380        self.output.endl = endl;
381        self
382    }
383
384    /// Builds the final ColorOutput.
385    ///
386    /// # Returns
387    ///
388    /// - `ColorOutput<'a>` - The constructed output.
389    #[inline(always)]
390    pub fn build(&'_ self) -> ColorOutput<'_> {
391        self.output
392    }
393
394    /// ColorOutputs the current state.
395    ///
396    /// # Returns
397    ///
398    /// - `()` - No return value.
399    #[inline(always)]
400    pub fn output(&self) {
401        output(self.output);
402    }
403}
404
405impl<'a> Default for ColorOutputList<'a> {
406    /// Provides a default implementation for ColorOutputList.
407    ///
408    /// # Returns
409    ///
410    /// - `ColorOutputList` - New instance containing a single default ColorOutput
411    #[inline(always)]
412    fn default() -> Self {
413        ColorOutputList(vec![ColorOutput::<'a>::default()])
414    }
415}
416
417impl<'a> Deref for ColorOutputList<'a> {
418    type Target = Vec<ColorOutput<'a>>;
419
420    /// Dereferences ColorOutputList to its internal Vec of ColorOutputs.
421    ///
422    /// # Returns
423    ///
424    /// - `&Vec<ColorOutput>` - Reference to the internal vector of outputs
425    #[inline(always)]
426    fn deref(&self) -> &Self::Target {
427        &self.0
428    }
429}
430
431impl<'a> IntoIterator for &'a ColorOutputList<'a> {
432    type Item = &'a ColorOutput<'a>;
433    type IntoIter = Iter<'a, ColorOutput<'a>>;
434
435    /// Returns an iterator over the elements of the internal Vec.
436    ///
437    /// # Returns
438    ///
439    /// - `Iter<ColorOutput>` - Iterator over references to ColorOutput elements
440    #[inline(always)]
441    fn into_iter(self) -> Self::IntoIter {
442        self.0.iter()
443    }
444}
445
446impl<'a> ColorOutputList<'a> {
447    /// Provides an iterator over the elements in the internal `Vec<ColorOutput<'a>>`.
448    ///
449    /// # Returns
450    /// - `Iter<'_, ColorOutput<'a>>`: An iterator over references to `ColorOutput` elements.
451    #[inline(always)]
452    pub fn iter(&self) -> std::slice::Iter<'_, ColorOutput<'a>> {
453        self.0.iter()
454    }
455
456    /// ColorOutputs the content of each `ColorOutput` in the list.
457    ///
458    /// This method clones the `ColorOutputList` and iterates through its elements, calling the `output` method on each cloned `ColorOutput`.
459    ///
460    /// # Returns
461    /// - `()` : Nothing is returned.
462    pub fn output(self) {
463        output_list(&self.to_vec());
464    }
465}
466
467impl<'a> Default for ColorOutputListBuilder<'a> {
468    #[inline(always)]
469    fn default() -> Self {
470        Self::new()
471    }
472}
473
474impl<'a> ColorOutputListBuilder<'a> {
475    /// Creates a new empty ColorOutputListBuilder.
476    ///
477    /// # Returns
478    ///
479    /// - `ColorOutputListBuilder` - New instance with empty output list
480    #[inline(always)]
481    pub fn new() -> Self {
482        Self {
483            output_list: vec![],
484        }
485    }
486
487    /// Creates a new ColorOutputListBuilder from existing outputs.
488    ///
489    /// # Arguments
490    ///
491    /// - `Vec<ColorOutput>` - Collection of outputs to initialize with
492    ///
493    /// # Returns
494    ///
495    /// - `ColorOutputListBuilder` - New instance containing the specified outputs
496    #[inline(always)]
497    pub fn new_from(output_list: Vec<ColorOutput<'a>>) -> Self {
498        Self { output_list }
499    }
500
501    /// Adds an output to the list.
502    ///
503    /// # Arguments
504    ///
505    /// - `ColorOutput` - The output configuration to add
506    ///
507    /// # Returns
508    ///
509    /// - `&mut Self` - The builder for method chaining
510    #[inline(always)]
511    pub fn add(&mut self, output: ColorOutput<'a>) -> &mut Self {
512        self.output_list.push(output);
513        self
514    }
515
516    /// Removes an output item from the list at the specified index.
517    ///
518    /// # Parameters
519    /// - `&mut self`: A mutable reference to the current instance of `ColorOutputListBuilder`.
520    /// - `idx`: The index of the output item to be removed.
521    ///
522    /// # Returns
523    /// - `&mut Self`: A mutable reference to the current instance, allowing for method chaining.
524    ///
525    /// If the index is out of bounds, the list remains unchanged.
526    pub fn remove(&mut self, idx: usize) -> &mut Self {
527        if idx >= self.output_list.len() {
528            return self;
529        }
530        self.output_list.remove(idx);
531        self
532    }
533
534    /// Clears all output items from the output list.
535    ///
536    /// # Parameters
537    /// - `&mut self`: A mutable reference to the current instance of `ColorOutputListBuilder`.
538    #[inline(always)]
539    pub fn clear(&mut self) {
540        self.output_list.clear();
541    }
542
543    /// Runs all output items in the list, executing their output logic.
544    ///
545    /// # Parameters
546    /// - `&mut self`: A mutable reference to the current instance of `ColorOutputListBuilder`.
547    ///
548    /// # Returns
549    /// - `&mut Self`: A mutable reference to the current instance, allowing for method chaining.
550    ///
551    /// The method clones the current output list, clears the original list, and executes
552    /// the output for each cloned item.
553    pub fn run(&mut self) -> &mut Self {
554        let outputs: Vec<ColorOutput<'_>> = self.output_list.to_vec();
555        self.clear();
556        output_list(&outputs);
557        self
558    }
559
560    /// Queries the output item at the specified index.
561    ///
562    /// # Parameters
563    /// - `&self`: An immutable reference to the current instance of `ColorOutputListBuilder`.
564    /// - `idx`: The index of the output item to query.
565    ///
566    /// # Returns
567    /// - `ColorOutput`: The output item at the specified index, or a default output if the index is out of bounds.
568    pub fn query_idx(&'_ self, idx: usize) -> ColorOutput<'_> {
569        if idx >= self.output_list.len() {
570            return ColorOutput::default();
571        }
572        self.output_list[idx]
573    }
574
575    /// Runs the output item at the specified index.
576    ///
577    /// # Parameters
578    /// - `&mut self`: A mutable reference to the current instance of `ColorOutputListBuilder`.
579    /// - `idx`: The index of the output item to run.
580    ///
581    /// # Returns
582    /// - `&mut Self`: A mutable reference to the current instance, allowing for method chaining.
583    ///
584    /// If the index is out of bounds, the list remains unchanged.
585    pub fn run_idx(&mut self, idx: usize) -> &mut Self {
586        if idx >= self.output_list.len() {
587            return self;
588        }
589        let output: ColorOutput<'_> = self.query_idx(idx);
590        output.output();
591        self
592    }
593}