Skip to content

Commit bd69b4e

Browse files
committed
Add basic functionality to operation state timeline
1 parent b3656a2 commit bd69b4e

9 files changed

Lines changed: 609 additions & 241 deletions

File tree

gui/src/backend.rs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -166,36 +166,7 @@ pub trait ReplayableBackendVariant: BackendVariant {
166166
}
167167

168168
fn skip_to_next_flightmode(&mut self, _reverse: bool) {
169-
//let fm: Option<FlightMode> = self.data_store().current_enum_value(Metric::FlightMode, self.end());
170-
171-
//let Some(end) = self.end() else {
172-
// return;
173-
//};
174-
175-
//let i = self.all_vehicle_states().partition_point(|(t, _)| *t <= end);
176-
177-
//let next_flightmode = if reverse {
178-
// self.all_vehicle_states()[..i]
179-
// .iter()
180-
// .rev()
181-
// .filter(|(_t, vs)| vs.mode.is_some() && vs.mode != fm)
182-
// .map(|(t, _)| t)
183-
// .next()
184-
//} else {
185-
// self.all_vehicle_states()[i..]
186-
// .iter()
187-
// .filter(|(_t, vs)| vs.mode.is_some() && vs.mode != fm)
188-
// .map(|(t, _)| t)
189-
// .next()
190-
//};
191-
192-
//if let Some(inst) = next_flightmode {
193-
// let playing = self.playing();
194-
// *self.playback_state_mut() = Some(PlaybackState::Paused(*inst));
195-
// if playing {
196-
// self.playpause();
197-
// }
198-
//}
169+
println!("Skipping FlightMode currently not supported!");
199170
}
200171

201172
fn playback_ui(&mut self, ui: &mut egui::Ui) {

gui/src/frontend.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
use crate::{
22
frontend::{metric_monitor::MetricMonitor, popup_manager::PopupManager},
33
settings::AppSettings,
4-
widgets::{map::MapState, plot::SharedPlotState},
4+
widgets::{
5+
map::MapState,
6+
plot::SharedPlotState,
7+
time_line::{HyacinthAnomalousState, HyacinthNominalState},
8+
},
59
};
610

711
pub mod metric_monitor;
812
pub mod popup_manager;
913
//TODO Hans: Probably should not be here
1014
pub mod constraints;
1115

16+
struct HyacinthState {
17+
nominal: HyacinthNominalState,
18+
anomalous: Option<HyacinthAnomalousState>,
19+
}
20+
21+
impl Default for HyacinthState {
22+
fn default() -> Self {
23+
Self {
24+
nominal: HyacinthNominalState::IdleActive,
25+
anomalous: None,
26+
}
27+
}
28+
}
29+
1230
pub struct Frontend {
1331
popup_manager: PopupManager,
1432
metric_monitor: MetricMonitor,
1533
map: MapState,
1634
shared_plot: SharedPlotState,
35+
hyacinth_state: HyacinthState,
1736
}
1837

1938
impl Frontend {
@@ -24,6 +43,7 @@ impl Frontend {
2443
metric_monitor: Default::default(),
2544
map: MapState::new(ctx, mapbox_token),
2645
shared_plot: SharedPlotState::new(),
46+
hyacinth_state: Default::default(),
2747
};
2848
}
2949

@@ -58,4 +78,20 @@ impl Frontend {
5878
pub fn shared_plot_mut(&mut self) -> &mut SharedPlotState {
5979
return &mut self.shared_plot;
6080
}
81+
82+
pub fn hyacinth_nominal_state(&self) -> HyacinthNominalState {
83+
return self.hyacinth_state.nominal;
84+
}
85+
86+
pub fn hyacinth_anomolous_state(&self) -> Option<HyacinthAnomalousState> {
87+
return self.hyacinth_state.anomalous;
88+
}
89+
90+
pub fn set_hyacinth_nominal_state(&mut self, state: HyacinthNominalState) {
91+
return self.hyacinth_state.nominal = state;
92+
}
93+
94+
pub fn set_hyacinth_anomalous_state(&mut self, state: Option<HyacinthAnomalousState>) {
95+
return self.hyacinth_state.anomalous = state;
96+
}
6197
}

gui/src/frontend/popup_manager.rs

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,31 @@ impl TriggerBuilder<()> {
169169
popups: Default::default(),
170170
};
171171
}
172+
173+
pub fn add_all<Contents: PopupContentList>(
174+
self,
175+
popups: Contents,
176+
position: Pos2,
177+
) -> TriggerBuilder<Contents::AsPopupList> {
178+
return TriggerBuilder {
179+
id: self.id,
180+
bounding_box: self.bounding_box,
181+
popups: popups.position(position),
182+
};
183+
}
172184
}
173185

174186
impl<L: PopupList> TriggerBuilder<L> {
175-
pub fn add<K, F>(self, position: Pos2, add_contents: F) -> TriggerBuilder<(PrimedPopup<K, F>, L)>
187+
pub fn add<C /*, K, F*/>(self, position: Pos2, contents: C) -> TriggerBuilder<(PositionedPopup<C>, L)>
176188
where
177-
K: PopupKind + NotInPopupList<L>,
178-
F: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <K as PopupKind>::Response,
189+
//K: PopupKind + NotInPopupList<L>,
190+
//F: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <K as PopupKind>::Response,
191+
C: PopupContents, //<Kind = K, Contents = F>,
179192
{
180193
return TriggerBuilder {
181194
id: self.id,
182195
bounding_box: self.bounding_box,
183-
popups: self.popups.add(PrimedPopup::new(position, add_contents)),
196+
popups: self.popups.add(PositionedPopup::new(position, contents)),
184197
};
185198
}
186199

@@ -200,29 +213,81 @@ impl<L: PopupList> TriggerBuilder<L> {
200213
}
201214
}
202215

203-
pub struct PrimedPopup<K, F>
216+
pub trait PopupContentList: Sized + Clone {
217+
type AsPopupList: PopupList;
218+
fn add<C: PopupContents>(self, contents: C) -> (Self, C) {
219+
return (self, contents);
220+
}
221+
222+
fn position(self, position: Pos2) -> Self::AsPopupList;
223+
}
224+
impl PopupContentList for () {
225+
type AsPopupList = ();
226+
fn position(self, _position: Pos2) -> Self::AsPopupList {}
227+
}
228+
impl<H, T> PopupContentList for (H, T)
229+
where
230+
H: PopupContents,
231+
T: PopupContentList,
232+
{
233+
type AsPopupList = (PositionedPopup<H>, T::AsPopupList);
234+
fn position(self, position: Pos2) -> Self::AsPopupList {
235+
return (PositionedPopup::new(position, self.0), self.1.position(position));
236+
}
237+
}
238+
239+
pub trait PopupContents: Clone {
240+
type Kind: PopupKind;
241+
type Contents: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <Self::Kind as PopupKind>::Response;
242+
fn contents(self) -> Self::Contents;
243+
}
244+
245+
impl<K, F> PopupContents for PopupContentData<K, F>
246+
where
247+
K: PopupKind,
248+
F: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <K as PopupKind>::Response + Clone,
249+
{
250+
type Kind = K;
251+
type Contents = F;
252+
253+
fn contents(self) -> Self::Contents {
254+
return self.add_contents;
255+
}
256+
}
257+
258+
#[derive(Clone)]
259+
pub struct PopupContentData<K, F>
204260
where
205261
K: PopupKind,
206262
F: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <K as PopupKind>::Response,
207263
{
208264
popup_kind: PhantomData<K>,
209-
position: Pos2,
210265
add_contents: F,
211266
}
212-
impl<K, F> PrimedPopup<K, F>
267+
268+
impl<K, F> PopupContentData<K, F>
213269
where
214270
K: PopupKind,
215271
F: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <K as PopupKind>::Response,
216272
{
217-
pub fn new(position: Pos2, add_contents: F) -> Self {
273+
pub fn new(add_contents: F) -> Self {
218274
Self {
219-
position,
220275
add_contents,
221276
popup_kind: PhantomData,
222277
}
223278
}
224279
}
225280

281+
pub struct PositionedPopup<Contents: PopupContents> {
282+
position: Pos2,
283+
contents: Contents,
284+
}
285+
impl<Contents: PopupContents> PositionedPopup<Contents> {
286+
pub fn new(position: Pos2, contents: Contents) -> Self {
287+
Self { position, contents }
288+
}
289+
}
290+
226291
pub trait PopupResponse: Sized {
227292
fn union(self, other: egui::Response) -> Self;
228293
}
@@ -252,23 +317,19 @@ pub trait DisplayablePopup {
252317
fn position(&self) -> &Pos2;
253318
fn show(self, ui: &mut Ui, frontend: &mut Frontend, backend: &mut Backend) -> <Self::Kind as PopupKind>::Response;
254319
}
255-
impl<K, F> DisplayablePopup for PrimedPopup<K, F>
256-
where
257-
K: PopupKind,
258-
F: FnOnce(&mut egui::Ui, &mut Frontend, &mut Backend) -> <K as PopupKind>::Response,
259-
{
260-
type Kind = K;
320+
impl<Contents: PopupContents> DisplayablePopup for PositionedPopup<Contents> {
321+
type Kind = Contents::Kind;
261322

262323
fn position(&self) -> &Pos2 {
263324
return &self.position;
264325
}
265326

266-
fn show(self, ui: &mut Ui, frontend: &mut Frontend, backend: &mut Backend) -> <K as PopupKind>::Response {
267-
return (self.add_contents)(ui, frontend, backend);
327+
fn show(self, ui: &mut Ui, frontend: &mut Frontend, backend: &mut Backend) -> <Self::Kind as PopupKind>::Response {
328+
return (self.contents.contents())(ui, frontend, backend);
268329
}
269330
}
270331

271-
pub trait PopupKind: Sized {
332+
pub trait PopupKind: Sized + Clone {
272333
type Response: PopupResponse;
273334
fn id(trigger_id: &egui::Id) -> egui::Id;
274335
fn close_condition() -> PopupCloseCondition;
@@ -281,7 +342,7 @@ pub trait PopupKind: Sized {
281342
P: DisplayablePopup<Kind = Self>;
282343
}
283344

284-
#[derive(Default)]
345+
#[derive(Default, Clone)]
285346
pub struct Tooltip {}
286347
impl PopupKind for Tooltip {
287348
type Response = egui::Response;
@@ -306,6 +367,7 @@ impl PopupKind for Tooltip {
306367
}
307368
}
308369

370+
#[derive(Clone)]
309371
pub struct ContextMenu {}
310372
impl PopupKind for ContextMenu {
311373
type Response = egui::Response;
@@ -329,6 +391,8 @@ impl PopupKind for ContextMenu {
329391
PopupManager::add_context_menu(trigger, ui, frontend, backend);
330392
}
331393
}
394+
395+
#[derive(Clone)]
332396
pub struct DropdownMenu {}
333397
impl PopupKind for DropdownMenu {
334398
type Response = egui::Response;
@@ -353,6 +417,7 @@ impl PopupKind for DropdownMenu {
353417
}
354418
}
355419

420+
#[derive(Clone)]
356421
pub struct ModalDialog {}
357422
impl PopupKind for ModalDialog {
358423
type Response = egui::InnerResponse<bool>;

gui/src/lib.rs

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ use crate::panels::metric_status_bar::MetricStatusBar;
2727
use crate::panels::*;
2828
use crate::settings::AppSettings;
2929
use crate::tabs::*;
30-
use crate::widgets::time_line::{
31-
COLOR_ABORT, COLOR_HOLD, COLOR_NOMINAL_IGNITION, COLOR_NOMINAL_IN_FLIGHT, COLOR_NOMINAL_ON_GROUND, Timeline,
32-
TimelineState,
33-
};
30+
use crate::widgets::time_line::{HyacinthAnomalousState, HyacinthNominalState, Timeline};
3431
use crate::windows::*;
3532

3633
/// Main state object of our GUI application
@@ -200,34 +197,14 @@ impl Sam {
200197

201198
// Header containing text indicators and flight mode buttons
202199
HeaderPanel::show(ctx, self.backend_mut(), enabled);
200+
203201
egui::TopBottomPanel::top("my_panel").show(ctx, |ui| {
204202
ui.add(Timeline::new(
205-
vec![
206-
TimelineState::new("Verification", COLOR_NOMINAL_ON_GROUND),
207-
TimelineState::new("IdlePassivated", COLOR_NOMINAL_ON_GROUND),
208-
TimelineState::new("N₂ Filling", COLOR_NOMINAL_ON_GROUND),
209-
TimelineState::new("IdleActive", COLOR_NOMINAL_ON_GROUND),
210-
TimelineState::new("HarwareArmed", COLOR_NOMINAL_ON_GROUND),
211-
TimelineState::new("N₂O Filling", COLOR_NOMINAL_ON_GROUND),
212-
TimelineState::new("SoftwareArmed", COLOR_NOMINAL_ON_GROUND),
213-
TimelineState::new("Ignition", COLOR_NOMINAL_IGNITION),
214-
TimelineState::new("BurnPhase", COLOR_NOMINAL_IN_FLIGHT),
215-
TimelineState::new("CoastPhase", COLOR_NOMINAL_IN_FLIGHT),
216-
TimelineState::new("DroguePhase", COLOR_NOMINAL_IN_FLIGHT),
217-
TimelineState::new("MainPhase", COLOR_NOMINAL_IN_FLIGHT),
218-
TimelineState::new("LandedActive", COLOR_NOMINAL_ON_GROUND),
219-
TimelineState::new("Passivation", COLOR_NOMINAL_ON_GROUND),
220-
TimelineState::new("LandedPassivated", COLOR_NOMINAL_ON_GROUND),
221-
],
222-
vec![
223-
TimelineState::new("Hold", COLOR_HOLD),
224-
TimelineState::new("Abort", COLOR_ABORT),
225-
],
226-
0,
203+
HyacinthNominalState::as_timeline(&self.frontend),
204+
HyacinthAnomalousState::as_timeline(&self.frontend),
227205
Rotation2::new(0f32), //f32::consts::PI / 2f32),
228206
&mut self.frontend,
229207
self.backends.last_mut().unwrap(),
230-
//self.backend_mut(),
231208
));
232209
});
233210

0 commit comments

Comments
 (0)