livesplit_core/component/delta/
mod.rs1use super::key_value;
6use crate::{
7 analysis::{delta, state_helper},
8 comparison,
9 platform::prelude::*,
10 settings::{Color, Field, Gradient, SemanticColor, SettingsDescription, Value},
11 timing::{
12 formatter::{Accuracy, Delta, TimeFormatter},
13 Snapshot,
14 },
15 GeneralLayoutSettings,
16};
17use alloc::borrow::Cow;
18use core::fmt::Write;
19use serde::{Deserialize, Serialize};
20
21#[cfg(test)]
22mod tests;
23
24#[derive(Default, Clone)]
27pub struct Component {
28 settings: Settings,
29}
30
31#[derive(Clone, Serialize, Deserialize)]
33#[serde(default)]
34pub struct Settings {
35 pub background: Gradient,
37 pub comparison_override: Option<String>,
40 pub display_two_rows: bool,
43 pub label_color: Option<Color>,
46 pub drop_decimals: bool,
49 pub accuracy: Accuracy,
51}
52
53impl Default for Settings {
54 fn default() -> Self {
55 Self {
56 background: key_value::DEFAULT_GRADIENT,
57 comparison_override: None,
58 display_two_rows: false,
59 label_color: None,
60 drop_decimals: true,
61 accuracy: Accuracy::Tenths,
62 }
63 }
64}
65
66impl Component {
67 pub fn new() -> Self {
69 Default::default()
70 }
71
72 pub const fn with_settings(settings: Settings) -> Self {
74 Self { settings }
75 }
76
77 pub const fn settings(&self) -> &Settings {
79 &self.settings
80 }
81
82 pub fn settings_mut(&mut self) -> &mut Settings {
84 &mut self.settings
85 }
86
87 pub fn name(&self) -> Cow<'static, str> {
89 if let Some(comparison) = &self.settings.comparison_override {
90 format!("Delta ({comparison})").into()
91 } else {
92 "Delta".into()
93 }
94 }
95
96 pub fn update_state(
99 &self,
100 state: &mut key_value::State,
101 timer: &Snapshot<'_>,
102 layout_settings: &GeneralLayoutSettings,
103 ) {
104 let comparison = comparison::resolve(&self.settings.comparison_override, timer);
105 let text = comparison.unwrap_or_else(|| timer.current_comparison());
106 let comparison = comparison::or_current(comparison, timer);
107
108 let (delta, use_live_delta) = delta::calculate(timer, comparison);
109
110 let mut index = timer.current_split_index();
111 if !use_live_delta {
112 index = index.and_then(|i| i.checked_sub(1));
113 }
114
115 let semantic_color = if let Some(index) = index {
116 state_helper::split_color(
117 timer,
118 delta,
119 index,
120 true,
121 false,
122 comparison,
123 timer.current_timing_method(),
124 )
125 } else {
126 SemanticColor::Default
127 };
128
129 let value_color = Some(semantic_color.visualize(layout_settings));
130
131 state.background = self.settings.background;
132 state.key_color = self.settings.label_color;
133 state.value_color = value_color;
134
135 state.key.clear();
136 state.key.push_str(text);
137
138 state.value.clear();
139 let _ = write!(
140 state.value,
141 "{}",
142 Delta::custom(self.settings.drop_decimals, self.settings.accuracy).format(delta),
143 );
144
145 state.key_abbreviations.clear();
146 if let Some(abbreviation) = comparison::try_shorten(text) {
147 state.key_abbreviations.push(abbreviation.into());
148 }
149
150 state.display_two_rows = self.settings.display_two_rows;
151 state.updates_frequently = use_live_delta;
152 }
153
154 pub fn state(
157 &self,
158 timer: &Snapshot<'_>,
159 layout_settings: &GeneralLayoutSettings,
160 ) -> key_value::State {
161 let mut state = Default::default();
162 self.update_state(&mut state, timer, layout_settings);
163 state
164 }
165
166 pub fn settings_description(&self) -> SettingsDescription {
169 SettingsDescription::with_fields(vec![
170 Field::new("Background".into(), self.settings.background.into()),
171 Field::new(
172 "Comparison".into(),
173 self.settings.comparison_override.clone().into(),
174 ),
175 Field::new(
176 "Display 2 Rows".into(),
177 self.settings.display_two_rows.into(),
178 ),
179 Field::new("Label Color".into(), self.settings.label_color.into()),
180 Field::new("Drop Decimals".into(), self.settings.drop_decimals.into()),
181 Field::new("Accuracy".into(), self.settings.accuracy.into()),
182 ])
183 }
184
185 pub fn set_value(&mut self, index: usize, value: Value) {
193 match index {
194 0 => self.settings.background = value.into(),
195 1 => self.settings.comparison_override = value.into(),
196 2 => self.settings.display_two_rows = value.into(),
197 3 => self.settings.label_color = value.into(),
198 4 => self.settings.drop_decimals = value.into(),
199 5 => self.settings.accuracy = value.into(),
200 _ => panic!("Unsupported Setting Index"),
201 }
202 }
203}