livesplit_core/component/
previous_segment.rs1use super::key_value;
10use crate::{
11 analysis, comparison,
12 platform::prelude::*,
13 settings::{Color, Field, Gradient, SemanticColor, SettingsDescription, Value},
14 timing::{
15 formatter::{Accuracy, Delta, SegmentTime, TimeFormatter},
16 Snapshot,
17 },
18 GeneralLayoutSettings, TimerPhase,
19};
20use alloc::borrow::Cow;
21use core::fmt::Write as FmtWrite;
22use serde::{Deserialize, Serialize};
23
24#[derive(Default, Clone)]
31pub struct Component {
32 settings: Settings,
33}
34
35#[derive(Clone, Serialize, Deserialize)]
37#[serde(default)]
38pub struct Settings {
39 pub background: Gradient,
41 pub comparison_override: Option<String>,
44 pub display_two_rows: bool,
47 pub label_color: Option<Color>,
50 pub drop_decimals: bool,
53 pub accuracy: Accuracy,
55 pub show_possible_time_save: bool,
58}
59
60impl Default for Settings {
61 fn default() -> Self {
62 Self {
63 background: key_value::DEFAULT_GRADIENT,
64 comparison_override: None,
65 display_two_rows: false,
66 label_color: None,
67 drop_decimals: true,
68 accuracy: Accuracy::Tenths,
69 show_possible_time_save: false,
70 }
71 }
72}
73
74impl Component {
75 pub fn new() -> Self {
77 Default::default()
78 }
79
80 pub const fn with_settings(settings: Settings) -> Self {
82 Self { settings }
83 }
84
85 pub const fn settings(&self) -> &Settings {
87 &self.settings
88 }
89
90 pub fn settings_mut(&mut self) -> &mut Settings {
92 &mut self.settings
93 }
94
95 pub fn name(&self) -> Cow<'static, str> {
97 self.text(
98 false,
99 self.settings
100 .comparison_override
101 .as_ref()
102 .map(String::as_ref),
103 )
104 }
105
106 fn text(&self, live: bool, comparison: Option<&str>) -> Cow<'static, str> {
107 let text = if live {
108 "Live Segment"
109 } else {
110 "Previous Segment"
111 };
112 let mut text = Cow::from(text);
113 if let Some(comparison) = comparison {
114 write!(text.to_mut(), " ({})", comparison::shorten(comparison)).unwrap();
115 }
116 text
117 }
118
119 pub fn update_state(
122 &self,
123 state: &mut key_value::State,
124 timer: &Snapshot<'_>,
125 layout_settings: &GeneralLayoutSettings,
126 ) {
127 let mut time_change = None;
128 let mut previous_possible = None;
129 let resolved_comparison = comparison::resolve(&self.settings.comparison_override, timer);
130 let comparison = comparison::or_current(resolved_comparison, timer);
131 let live_segment =
132 analysis::check_live_delta(timer, false, comparison, timer.current_timing_method());
133
134 let phase = timer.current_phase();
135 let method = timer.current_timing_method();
136 let semantic_color = if phase != TimerPhase::NotRunning {
137 let split_index = timer.current_split_index().unwrap();
138 if live_segment.is_some() {
139 time_change = analysis::live_segment_delta(timer, split_index, comparison, method);
140 if self.settings.show_possible_time_save {
141 previous_possible = analysis::possible_time_save::calculate(
142 timer,
143 split_index,
144 comparison,
145 false,
146 )
147 .0;
148 }
149 } else if let Some(prev_split_index) = split_index.checked_sub(1) {
150 time_change =
151 analysis::previous_segment_delta(timer, prev_split_index, comparison, method);
152 if self.settings.show_possible_time_save {
153 previous_possible = analysis::possible_time_save::calculate(
154 timer,
155 prev_split_index,
156 comparison,
157 false,
158 )
159 .0;
160 }
161 };
162
163 if let Some(time_change) = time_change {
164 if live_segment.is_some() {
165 analysis::split_color(
166 timer,
167 time_change.into(),
168 split_index,
169 false,
170 false,
171 comparison,
172 method,
173 )
174 } else if let Some(prev_split_index) = split_index.checked_sub(1) {
175 analysis::split_color(
176 timer,
177 time_change.into(),
178 prev_split_index,
179 false,
180 true,
181 comparison,
182 method,
183 )
184 } else {
185 SemanticColor::Default
186 }
187 } else if let Some(prev_split_index) = split_index.checked_sub(1) {
188 analysis::split_color(
189 timer,
190 None,
191 prev_split_index,
192 true,
193 true,
194 comparison,
195 method,
196 )
197 } else {
198 SemanticColor::Default
199 }
200 } else {
201 SemanticColor::Default
202 };
203
204 let value_color = Some(semantic_color.visualize(layout_settings));
205
206 let text = self.text(live_segment.is_some(), resolved_comparison);
207
208 state.background = self.settings.background;
209 state.key_color = self.settings.label_color;
210 state.value_color = value_color;
211 state.semantic_color = semantic_color;
212
213 state.key.clear();
214 state.key.push_str(&text); state.value.clear();
217 let _ = write!(
218 state.value,
219 "{}",
220 Delta::custom(self.settings.drop_decimals, self.settings.accuracy).format(time_change),
221 );
222
223 if self.settings.show_possible_time_save {
224 let _ = write!(
225 state.value,
226 " / {}",
227 SegmentTime::with_accuracy(self.settings.accuracy).format(previous_possible),
228 );
229 }
230
231 state.key_abbreviations.clear();
232 if live_segment.is_some() {
233 state.key_abbreviations.push("Live Segment".into());
234 state.key_abbreviations.push("Live Seg.".into());
235 } else {
236 state.key_abbreviations.push("Previous Segment".into());
237 state.key_abbreviations.push("Prev. Segment".into());
238 state.key_abbreviations.push("Prev. Seg.".into());
239 }
240
241 state.display_two_rows = self.settings.display_two_rows;
242 state.updates_frequently = live_segment.is_some() && phase.is_running();
243 }
244
245 pub fn state(
248 &self,
249 timer: &Snapshot<'_>,
250 layout_settings: &GeneralLayoutSettings,
251 ) -> key_value::State {
252 let mut state = Default::default();
253 self.update_state(&mut state, timer, layout_settings);
254 state
255 }
256
257 pub fn settings_description(&self) -> SettingsDescription {
260 SettingsDescription::with_fields(vec![
261 Field::new("Background".into(), self.settings.background.into()),
262 Field::new(
263 "Comparison".into(),
264 self.settings.comparison_override.clone().into(),
265 ),
266 Field::new(
267 "Display 2 Rows".into(),
268 self.settings.display_two_rows.into(),
269 ),
270 Field::new("Label Color".into(), self.settings.label_color.into()),
271 Field::new("Drop Decimals".into(), self.settings.drop_decimals.into()),
272 Field::new("Accuracy".into(), self.settings.accuracy.into()),
273 Field::new(
274 "Show Possible Time Save".into(),
275 self.settings.show_possible_time_save.into(),
276 ),
277 ])
278 }
279
280 pub fn set_value(&mut self, index: usize, value: Value) {
288 match index {
289 0 => self.settings.background = value.into(),
290 1 => self.settings.comparison_override = value.into(),
291 2 => self.settings.display_two_rows = value.into(),
292 3 => self.settings.label_color = value.into(),
293 4 => self.settings.drop_decimals = value.into(),
294 5 => self.settings.accuracy = value.into(),
295 6 => self.settings.show_possible_time_save = value.into(),
296 _ => panic!("Unsupported Setting Index"),
297 }
298 }
299}