livesplit_core/component/
pb_chance.rs

1//! Provides the PB Chance Component and relevant types for using it. The PB
2//! Chance Component is a component that shows how likely it is to beat the
3//! Personal Best. If there is no active attempt it shows the general chance of
4//! beating the Personal Best. During an attempt it actively changes based on
5//! how well the attempt is going.
6
7use super::key_value;
8use crate::{
9    analysis::pb_chance,
10    platform::prelude::*,
11    settings::{Color, Field, Gradient, SettingsDescription, Value},
12    timing::Snapshot,
13};
14use core::fmt::Write;
15use serde::{Deserialize, Serialize};
16
17/// The PB Chance Component is a component that shows how likely it is to beat
18/// the Personal Best. If there is no active attempt it shows the general chance
19/// of beating the Personal Best. During an attempt it actively changes based on
20/// how well the attempt is going.
21#[derive(Default, Clone)]
22pub struct Component {
23    settings: Settings,
24}
25
26/// The Settings for this component.
27#[derive(Clone, Serialize, Deserialize)]
28#[serde(default)]
29pub struct Settings {
30    /// The background shown behind the component.
31    pub background: Gradient,
32    /// Specifies whether to display the name of the component and its value in
33    /// two separate rows.
34    pub display_two_rows: bool,
35    /// The color of the label. If `None` is specified, the color is taken from
36    /// the layout.
37    pub label_color: Option<Color>,
38    /// The color of the value. If `None` is specified, the color is taken from
39    /// the layout.
40    pub value_color: Option<Color>,
41}
42
43impl Default for Settings {
44    fn default() -> Self {
45        Self {
46            background: key_value::DEFAULT_GRADIENT,
47            display_two_rows: false,
48            label_color: None,
49            value_color: None,
50        }
51    }
52}
53
54impl Component {
55    /// Creates a new Possible Time Save Component.
56    pub fn new() -> Self {
57        Default::default()
58    }
59
60    /// Creates a new Possible Time Save Component with the given settings.
61    pub const fn with_settings(settings: Settings) -> Self {
62        Self { settings }
63    }
64
65    /// Accesses the settings of the component.
66    pub const fn settings(&self) -> &Settings {
67        &self.settings
68    }
69
70    /// Grants mutable access to the settings of the component.
71    pub fn settings_mut(&mut self) -> &mut Settings {
72        &mut self.settings
73    }
74
75    /// Accesses the name of the component.
76    pub const fn name(&self) -> &'static str {
77        "PB Chance"
78    }
79
80    /// Updates the component's state based on the timer provided.
81    pub fn update_state(&self, state: &mut key_value::State, timer: &Snapshot<'_>) {
82        let (chance, is_live) = pb_chance::for_timer(timer);
83
84        state.background = self.settings.background;
85        state.key_color = self.settings.label_color;
86        state.value_color = self.settings.value_color;
87        state.semantic_color = Default::default();
88
89        state.key.clear();
90        state.key.push_str(self.name());
91
92        state.value.clear();
93        let _ = write!(state.value, "{:.1}%", 100.0 * chance);
94
95        state.key_abbreviations.clear();
96        state.display_two_rows = self.settings.display_two_rows;
97        state.updates_frequently = is_live;
98    }
99
100    /// Calculates the component's state based on the timer provided.
101    pub fn state(&self, timer: &Snapshot<'_>) -> key_value::State {
102        let mut state = Default::default();
103        self.update_state(&mut state, timer);
104        state
105    }
106
107    /// Accesses a generic description of the settings available for this
108    /// component and their current values.
109    pub fn settings_description(&self) -> SettingsDescription {
110        SettingsDescription::with_fields(vec![
111            Field::new("Background".into(), self.settings.background.into()),
112            Field::new(
113                "Display 2 Rows".into(),
114                self.settings.display_two_rows.into(),
115            ),
116            Field::new("Label Color".into(), self.settings.label_color.into()),
117            Field::new("Value Color".into(), self.settings.value_color.into()),
118        ])
119    }
120
121    /// Sets a setting's value by its index to the given value.
122    ///
123    /// # Panics
124    ///
125    /// This panics if the type of the value to be set is not compatible with
126    /// the type of the setting's value. A panic can also occur if the index of
127    /// the setting provided is out of bounds.
128    pub fn set_value(&mut self, index: usize, value: Value) {
129        match index {
130            0 => self.settings.background = value.into(),
131            1 => self.settings.display_two_rows = value.into(),
132            2 => self.settings.label_color = value.into(),
133            3 => self.settings.value_color = value.into(),
134            _ => panic!("Unsupported Setting Index"),
135        }
136    }
137}