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
183
184
185
//! Configuration of a progress bar.
//!
//! This is used to configure the progress bar.

use bevy::prelude::*;

use super::{BarState, ColorScheme, Percentage};

/// Configuration of a progress bar.
#[derive(Component, Debug, Clone)]
#[allow(clippy::module_name_repetitions)]
pub struct ProgressBarConfig<T: Percentage + Component> {
    /// The color scheme to use for the progress bar.
    pub color_scheme: ColorScheme,
    /// The size of the progress bar.
    ///
    /// This is the size to draw the background for the bar, and the foreground bar will be drawn inside of this. At
    /// full, the foreground bar will be the same size as the background bar.
    pub size: Vec2,
    /// The relative position of the progress bar to the entity it will be attached to.
    ///
    /// This is relative to the [`Transform.translation`] of the entity.
    pub position_translation: Vec3,

    _marker: std::marker::PhantomData<T>,
}

impl<T: Percentage + Component> Default for ProgressBarConfig<T> {
    fn default() -> Self {
        Self {
            color_scheme: ColorScheme::default(),
            size: Vec2::new(100.0, 10.0),
            position_translation: Vec3::new(0.0, 0.0, 0.0),
            _marker: std::marker::PhantomData,
        }
    }
}

impl<T: Percentage + Component> ProgressBarConfig<T> {
    /// The shift of the background bar (in the z-axis) relative to the entity's translation.
    pub const BACKGROUND_BAR_SHIFT: f32 = 1.0;
    /// The shift of the foreground bar (in the z-axis) relative to the background bar.
    pub const FOREGROUND_BAR_SHIFT: f32 = 0.1;

    /// Create a new progress bar config with the given color scheme.
    #[must_use]
    pub fn new(color_scheme: ColorScheme) -> Self {
        Self {
            color_scheme,
            ..Default::default()
        }
    }

    /// Update the progress bar config with the given color scheme.
    #[must_use]
    pub const fn with_color_scheme(mut self, color_scheme: ColorScheme) -> Self {
        self.color_scheme = color_scheme;
        self
    }
    /// Update the progress bar's color scheme with the given background color.
    #[must_use]
    pub const fn with_background_color(mut self, color: Color) -> Self {
        self.color_scheme.background = color;
        self
    }
    /// Update the progress bar's color scheme with the given color for the given state.
    #[must_use]
    pub fn with_color(mut self, state: &BarState, color: Color) -> Self {
        self.color_scheme.set_color(state, color);
        self
    }
    /// Update the progress bar's color scheme with the given moderate cutoff.
    #[must_use]
    pub fn with_moderate_cutoff(mut self, cutoff: f32) -> Self {
        self.color_scheme.set_moderate_cutoff(cutoff);
        self
    }
    /// Update the progress bar's color scheme with the given critical cutoff.
    #[must_use]
    pub fn with_critical_cutoff(mut self, cutoff: f32) -> Self {
        self.color_scheme.set_critical_cutoff(cutoff);
        self
    }
    /// Update the progress bar to use a single color for all states.
    #[must_use]
    pub fn with_single_color(mut self, color: Color) -> Self {
        self.color_scheme.set_single_color(color);
        self
    }
    /// Update the progress bar's size.
    #[must_use]
    pub const fn with_size(mut self, size: Vec2) -> Self {
        self.size = size;
        self
    }
    /// Update the progress bar's relative position.
    #[must_use]
    pub const fn with_position_translation(mut self, position_translation: Vec3) -> Self {
        self.position_translation = position_translation;
        self
    }

    /// Set the size of the progress bar.
    pub fn set_size(&mut self, size: Vec2) {
        self.size = size;
    }
    /// Set the relative position of the progress bar.
    pub fn set_position_translation(&mut self, position_translation: Vec3) {
        self.position_translation = position_translation;
    }
    /// Set the color scheme of the progress bar.
    pub fn set_color_scheme(&mut self, color_scheme: ColorScheme) {
        self.color_scheme = color_scheme;
    }

    /// Get the background color.
    #[must_use]
    pub const fn background_color(&self) -> Color {
        self.color_scheme.background
    }
    /// Get the foreground color for the given T.
    #[must_use]
    pub fn color(&self, percentage: &T) -> Color {
        self.color_scheme.get_color(percentage)
    }
    /// Get the realized [`Transform`] for the progress bar background.
    ///
    /// This adjusts the translation of the background to be relative to the entity's translation.
    #[must_use]
    pub fn background_transform(&self, entity_transform: &Transform) -> Transform {
        let mut transform = *entity_transform;
        transform.translation += self.position_translation;
        // Center the bar on the entity's translation
        transform.translation.x += self.size.x / 2.0;
        // Draw the background bar behind the foreground bar
        transform.translation.z += Self::BACKGROUND_BAR_SHIFT;
        transform
    }
    /// Get the realized [`Transform`] for the progress bar foreground.
    ///
    /// This adjusts the translation of the foreground to be relative to the entity's translation. It also adjusts the
    /// translation of the foreground to be centered on the entity's translation.
    #[must_use]
    pub fn foreground_transform(&self, entity_transform: &Transform, percentage: &T) -> Transform {
        let mut transform = *entity_transform;
        // Adjust position to be relative to the entity's translation
        transform.translation += self.position_translation;
        // Center the bar on the entity's translation
        transform.translation.x += self.size.x * percentage.percentage() / 2.0;
        // Draw the foreground bar in front of the background bar
        transform.translation.z += Self::FOREGROUND_BAR_SHIFT + Self::BACKGROUND_BAR_SHIFT;
        transform
    }
    /// Get the mesh for the progress bar background.
    ///
    /// This is a [`Quad`] with the size of the progress bar.
    #[must_use]
    pub fn background_mesh(&self) -> Mesh {
        shape::Quad::new(self.size).into()
    }
    /// Get the mesh for the progress bar foreground.
    ///
    /// This is a [`Quad`] with the size of the progress bar foreground, which is the size of the progress
    /// bar background scaled by the percentage.
    #[must_use]
    pub fn foreground_mesh(&self, percentage: &T) -> Mesh {
        shape::Quad::new(Vec2::new(
            self.size.x * percentage.percentage(),
            self.size.y,
        ))
        .into()
    }
    /// Get the current [`BarState`] for the given percentage.
    #[must_use]
    pub fn get_state(&self, percentage: &T) -> BarState {
        self.color_scheme
            .cutoffs()
            .get_state(percentage.percentage())
    }
    /// Get the color for the given [`BarState`].
    #[must_use]
    pub const fn color_for_state(&self, state: &BarState) -> Color {
        self.color_scheme.bar.get_state(state)
    }
}