egui_charts/ui/replay/
status.rs1use super::model::ReplayProgress;
7use crate::icons::icons;
8use crate::localization as l10n;
9use crate::styles::icons as icon_sizes;
10use crate::theme::ThemeExt;
11use egui::{Response, RichText, Sense, Ui, Vec2, Widget};
12
13#[derive(Clone, Debug, Default)]
15pub enum ReplayStatus {
16 #[default]
18 Inactive,
19 Playing {
21 symbol: String,
23 progress_pct: f32,
25 ticks_processed: u64,
27 speed: f32,
29 },
30 Paused {
32 symbol: String,
34 progress_pct: f32,
36 },
37 Finished {
39 symbol: String,
41 total_ticks: u64,
43 },
44}
45
46impl From<(&ReplayProgress, &str, f32)> for ReplayStatus {
47 fn from((progress, symbol, speed): (&ReplayProgress, &str, f32)) -> Self {
48 if progress.progress_pct >= 99.9 {
49 ReplayStatus::Finished {
50 symbol: symbol.to_string(),
51 total_ticks: progress.ticks_processed,
52 }
53 } else {
54 ReplayStatus::Playing {
55 symbol: symbol.to_string(),
56 progress_pct: progress.progress_pct,
57 ticks_processed: progress.ticks_processed,
58 speed,
59 }
60 }
61 }
62}
63
64pub struct ReplayStatusIndicator<'a> {
66 status: &'a ReplayStatus,
68 show_details: bool,
70}
71
72impl<'a> ReplayStatusIndicator<'a> {
73 pub fn new(status: &'a ReplayStatus) -> Self {
75 Self {
76 status,
77 show_details: false,
78 }
79 }
80
81 #[must_use]
83 pub fn with_details(mut self) -> Self {
84 self.show_details = true;
85 self
86 }
87}
88
89impl<'a> Widget for ReplayStatusIndicator<'a> {
90 fn ui(self, ui: &mut Ui) -> Response {
91 let theme = ui.active_theme();
92 let (muted, size) = (theme.ui.text_muted, theme.text.small);
93 match self.status {
94 ReplayStatus::Inactive => ui.allocate_response(Vec2::ZERO, Sense::hover()),
96 ReplayStatus::Playing {
97 symbol: _,
98 progress_pct,
99 ticks_processed,
100 speed,
101 } => {
102 ui.horizontal(|ui| {
103 ui.spacing_mut().item_spacing.x = theme.spacing.xs;
104
105 ui.add(icons::MEDIA_PLAY.as_image_tinted(
107 Vec2::splat(icon_sizes::STATUS_INDICATOR),
108 theme.ui.warning,
109 ));
110 ui.label(
111 RichText::new(l10n::text(ui.ctx(), "Replay"))
112 .color(theme.ui.warning)
113 .strong()
114 .size(size),
115 );
116
117 if self.show_details {
118 ui.label(
120 RichText::new(format!("{progress_pct:.1}%"))
121 .color(muted)
122 .size(size),
123 );
124
125 ui.label(
127 RichText::new(l10n::text(ui.ctx(), format!("{speed}x")))
128 .color(muted)
129 .size(size),
130 );
131
132 ui.label(
134 RichText::new(l10n::format_text(
135 ui.ctx(),
136 "{0}K ticks",
137 &[("0", format!("{}", ticks_processed / 1000))],
138 ))
139 .color(muted)
140 .size(size),
141 );
142 }
143 })
144 .response
145 }
146 ReplayStatus::Paused {
147 symbol: _,
148 progress_pct,
149 } => {
150 ui.horizontal(|ui| {
151 ui.spacing_mut().item_spacing.x = theme.spacing.xs;
152
153 ui.add(
155 icons::MEDIA_PAUSE
156 .as_image_tinted(Vec2::splat(icon_sizes::STATUS_INDICATOR), muted),
157 );
158 ui.label(
159 RichText::new(l10n::text(ui.ctx(), "Paused"))
160 .color(muted)
161 .size(size),
162 );
163
164 if self.show_details {
165 ui.label(
166 RichText::new(format!("{progress_pct:.1}%"))
167 .color(muted)
168 .size(size),
169 );
170 }
171 })
172 .response
173 }
174 ReplayStatus::Finished {
175 symbol: _,
176 total_ticks,
177 } => {
178 ui.horizontal(|ui| {
179 ui.spacing_mut().item_spacing.x = theme.spacing.xs;
180
181 ui.add(icons::SUCCESS.as_image_tinted(
183 Vec2::splat(icon_sizes::STATUS_INDICATOR),
184 theme.ui.success,
185 ));
186 ui.label(
187 RichText::new(l10n::text(ui.ctx(), "Complete"))
188 .color(theme.ui.success)
189 .size(size),
190 );
191
192 if self.show_details {
193 ui.label(
194 RichText::new(l10n::format_text(
195 ui.ctx(),
196 "{0}K ticks",
197 &[("0", format!("{}", total_ticks / 1000))],
198 ))
199 .color(muted)
200 .size(size),
201 );
202 }
203 })
204 .response
205 }
206 }
207 }
208}
209
210pub fn show_replay_status(ui: &mut Ui, status: &ReplayStatus) -> Response {
212 ReplayStatusIndicator::new(status).ui(ui)
213}
214
215pub fn show_replay_status_with_details(ui: &mut Ui, status: &ReplayStatus) -> Response {
217 ReplayStatusIndicator::new(status).with_details().ui(ui)
218}