paiagram/interface/tabs/
vehicle_overview.rs

1use crate::interface::{AppTab, UiCommand};
2use crate::vehicles::*;
3use bevy::prelude::*;
4use bevy_egui::egui;
5use egui_deferred_table::{
6    Action, AxisParameters, CellIndex, DeferredTable, DeferredTableDataSource,
7    DeferredTableRenderer, TableDimensions,
8};
9
10struct VehicleOverviewRow {
11    vehicle: Entity,
12    name: String,
13    entry_count: usize,
14    service_count: usize,
15}
16
17struct VehicleOverviewDataSource {
18    rows: Vec<VehicleOverviewRow>,
19}
20
21impl VehicleOverviewDataSource {
22    fn new(rows: Vec<VehicleOverviewRow>) -> Self {
23        Self { rows }
24    }
25
26    fn row(&self, index: usize) -> Option<&VehicleOverviewRow> {
27        self.rows.get(index)
28    }
29}
30
31impl DeferredTableDataSource for VehicleOverviewDataSource {
32    fn get_dimensions(&self) -> TableDimensions {
33        TableDimensions {
34            row_count: self.rows.len(),
35            column_count: 2,
36        }
37    }
38}
39
40struct VehicleOverviewRenderer;
41
42impl DeferredTableRenderer<VehicleOverviewDataSource> for VehicleOverviewRenderer {
43    fn render_cell(
44        &self,
45        ui: &mut bevy_egui::egui::Ui,
46        cell_index: CellIndex,
47        source: &VehicleOverviewDataSource,
48    ) {
49        let Some(row) = source.row(cell_index.row) else {
50            return;
51        };
52
53        match cell_index.column {
54            0 => {
55                ui.label(format!("{}", row.entry_count));
56            }
57            1 => {
58                ui.label(format!("{}", row.service_count));
59            }
60            _ => {}
61        }
62    }
63}
64
65pub fn show_vehicle_overview(
66    InMut(ui): InMut<egui::Ui>,
67    vehicles: Query<(Entity, &Name, &crate::vehicles::Schedule, &Children), With<Vehicle>>,
68    services: Query<&Service>,
69    mut msg_ui: MessageWriter<UiCommand>,
70    displayed_lines: Query<(Entity, &Name), With<crate::lines::DisplayedLine>>,
71) {
72    for line in displayed_lines.iter() {
73        let (entity, name) = line;
74        if ui.button(format!("{}", name)).clicked() {
75            msg_ui.write(UiCommand::OpenOrFocusVehicleTab(AppTab::LineTimetable(
76                entity,
77            )));
78        }
79    }
80
81    let rows: Vec<VehicleOverviewRow> = vehicles
82        .iter()
83        .map(|(entity, name, schedule, children)| VehicleOverviewRow {
84            vehicle: entity,
85            name: name.as_str().to_owned(),
86            entry_count: schedule.1.len(),
87            service_count: {
88                let mut count = 0;
89                for child in children.iter() {
90                    if let Ok(_service) = services.get(child) {
91                        count += 1;
92                    }
93                }
94                count
95            },
96        })
97        .collect();
98
99    if rows.is_empty() {
100        ui.label("No vehicles found.");
101        return;
102    }
103
104    let row_parameters: Vec<AxisParameters> = rows
105        .iter()
106        .map(|row| {
107            AxisParameters::default()
108                .name(row.name.clone())
109                .default_dimension(14.0)
110                .monospace(true)
111        })
112        .collect();
113
114    let mut data_source = VehicleOverviewDataSource::new(rows);
115
116    let column_parameters = vec![
117        AxisParameters::default()
118            .name("Entries")
119            .default_dimension(80.0)
120            .resizable(false)
121            .monospace(true),
122        AxisParameters::default()
123            .name("Services")
124            .default_dimension(80.0)
125            .resizable(false)
126            .monospace(true),
127    ];
128
129    let mut table = DeferredTable::new(ui.id().with("vehicle_overview"))
130        .default_cell_size(egui::vec2(160.0, 14.0))
131        .highlight_hovered_cell();
132
133    table = table.column_parameters(&column_parameters);
134
135    if !row_parameters.is_empty() {
136        table = table.row_parameters(&row_parameters);
137    }
138
139    let mut renderer = VehicleOverviewRenderer;
140    let (_response, actions) = table.show(ui, &mut data_source, &mut renderer);
141
142    for action in actions {
143        if let Action::CellClicked(cell_index) = action {
144            if let Some(row) = data_source.row(cell_index.row) {
145                msg_ui.write(UiCommand::OpenOrFocusVehicleTab(AppTab::Vehicle(
146                    row.vehicle,
147                )));
148            }
149        }
150    }
151}