paiagram/interface/side_panel/
interval_stats.rs

1use bevy::ecs::{
2    change_detection::DetectChanges,
3    entity::Entity,
4    hierarchy::ChildOf,
5    name::Name,
6    query::With,
7    system::{In, InMut, Local, Query, Res},
8    world::Ref,
9};
10use egui::Ui;
11
12use crate::{
13    interface::tabs::PageCache,
14    intervals::{Graph, Interval, IntervalCache, Station},
15    vehicles::entries::TimetableEntry,
16};
17
18pub fn show_interval_stats(
19    (InMut(ui), In((s1, s2))): (InMut<Ui>, In<(Entity, Entity)>),
20    mut interval_string: Local<String>,
21    station_name: Query<&Name, With<Station>>,
22    intervals: Query<(Ref<IntervalCache>, &Interval)>,
23    graph: Res<Graph>,
24    get_entry_parent: Query<&ChildOf, With<TimetableEntry>>,
25    mut panel_buffer: Local<PageCache<Entity, Vec<Entity>>>,
26) {
27    // Display basic statistics and edit functions
28    interval_string.clear();
29    interval_string.push_str(station_name.get(s1).map_or("Unknown", Name::as_str));
30    interval_string.push_str(" ⇆ ");
31    interval_string.push_str(station_name.get(s2).map_or("Unknown", Name::as_str));
32    ui.heading(interval_string.as_str());
33    let Some(&edge) = graph.edge_weight(s1, s2) else {
34        ui.label("Interval not found.");
35        return;
36    };
37    let Ok((cache, info)) = intervals.get(edge) else {
38        ui.label("Interval not found");
39        return;
40    };
41    // only reconstruct when the cache changed
42    let update_vehicle_buffer = |mut buffer: &mut Vec<Entity>| {
43        buffer.clear();
44        cache.passing_vehicles(&mut buffer, |e| get_entry_parent.get(e).ok());
45        buffer.sort_unstable();
46        buffer.dedup();
47    };
48    let passing_vehicles_buffer = panel_buffer.get_mut_or_insert_with(edge, || {
49        let mut new_buffer = Vec::new();
50        update_vehicle_buffer(&mut new_buffer);
51        new_buffer
52    });
53    if cache.is_changed() {
54        update_vehicle_buffer(passing_vehicles_buffer)
55    }
56    // TODO: move the strings into their separate buffers;
57    egui::Grid::new("interval_info_grid")
58        .num_columns(2)
59        .striped(true)
60        .show(ui, |ui| {
61            ui.label("Length:");
62            ui.monospace(info.length.to_string());
63            ui.end_row();
64            ui.label("Passing entries:");
65            ui.monospace(cache.passing_entries.len().to_string());
66            ui.end_row();
67            ui.label("Passing vehicles:");
68            ui.monospace(passing_vehicles_buffer.len().to_string());
69        });
70}