paiagram/interface/tabs/
displayed_lines.rs

1use bevy::ecs::{
2    entity::Entity,
3    name::Name,
4    query::With,
5    system::{InMut, Local, Populated, Query},
6};
7use egui::{Frame, Response, RichText, ScrollArea, Sense, Ui, UiBuilder, Vec2};
8
9const PANEL_DEFAULT_SIZE: f32 = 20.0;
10
11use crate::{
12    interface::tabs::{PageCache, Tab},
13    intervals::{Station, StationCache},
14    lines::DisplayedLine,
15};
16
17#[derive(PartialEq, Debug, Clone, Copy)]
18pub struct DisplayedLinesTab;
19
20impl Tab for DisplayedLinesTab {
21    const NAME: &'static str = "Available Lines";
22    fn main_display(&mut self, world: &mut bevy::ecs::world::World, ui: &mut Ui) {
23        if let Err(e) = world.run_system_cached_with(show_displayed_lines, ui) {
24            bevy::log::error!("UI Error while displaying displayed lines page: {}", e)
25        }
26    }
27    fn scroll_bars(&self) -> [bool; 2] {
28        [false; 2]
29    }
30}
31
32fn full_width_button(ui: &mut Ui, text: &str) -> Response {
33    let (rect, resp) = ui.allocate_exact_size(
34        Vec2 {
35            x: ui.available_width(),
36            y: 15.0,
37        },
38        Sense::click(),
39    );
40    let res = ui.scope_builder(UiBuilder::new().sense(resp.sense).max_rect(rect), |ui| {
41        let response = ui.response();
42        let visuals = ui.style().interact(&response);
43        let mut stroke = visuals.bg_stroke;
44        stroke.width = 1.5;
45        Frame::canvas(ui.style())
46            .fill(visuals.bg_fill.gamma_multiply(0.2))
47            .stroke(stroke)
48            .show(ui, |ui| {
49                ui.set_min_size(ui.available_size());
50                ui.add(egui::Label::new(text).truncate())
51            })
52    });
53    res.response
54}
55
56fn show_displayed_lines(
57    InMut(ui): InMut<Ui>,
58    displayed_lines: Query<(Entity, &mut DisplayedLine, &Name)>,
59    station_names: Query<(Entity, &Name, &StationCache), With<Station>>,
60    mut selected_line: Local<Option<Entity>>,
61    mut selected_station_cache: Local<PageCache<Entity, Option<Entity>>>,
62) {
63    egui::SidePanel::left("left_panel")
64        .resizable(true)
65        .min_width(PANEL_DEFAULT_SIZE)
66        .show_inside(ui, |ui| {
67            if full_width_button(ui, "Overview").clicked() {
68                *selected_line = None;
69            }
70            for (line_entity, _, name) in displayed_lines.iter() {
71                if full_width_button(ui, name.as_str()).clicked() {
72                    *selected_line = Some(line_entity);
73                }
74            }
75        });
76    if let Some(line_entity) = *selected_line {
77        let selected_station = selected_station_cache.get_mut_or_insert_with(line_entity, || None);
78        if let Ok((_, displayed_line, _)) = displayed_lines.get(line_entity) {
79            show_line(ui, displayed_line, selected_station, |e| {
80                station_names.get(e).ok()
81            });
82        }
83    } else {
84        show_overview(ui);
85    }
86}
87
88pub fn show_overview(ui: &mut Ui) {
89    ui.heading("Overview");
90}
91
92pub fn show_line<'a, F>(
93    ui: &mut Ui,
94    line: &DisplayedLine,
95    selected_station: &mut Option<Entity>,
96    get_station_info: F,
97) where
98    F: Fn(Entity) -> Option<(Entity, &'a Name, &'a StationCache)> + Copy + 'a,
99{
100    egui::SidePanel::left("inner_left_panel")
101        .resizable(true)
102        .min_width(PANEL_DEFAULT_SIZE)
103        .show_inside(ui, |ui| {
104            ScrollArea::vertical().show(ui, |ui| {
105                for (station_entity, station_name, _) in line
106                    .stations
107                    .iter()
108                    .filter_map(|(e, _)| get_station_info(*e))
109                {
110                    if full_width_button(ui, station_name.as_str()).clicked() {
111                        *selected_station = Some(station_entity);
112                    }
113                }
114            })
115        });
116    let Some(station_entity) = selected_station else {
117        return;
118    };
119    let Some((_, station_name, station_cache)) = get_station_info(*station_entity) else {
120        *selected_station = None;
121        return;
122    };
123    ui.heading(station_name.as_str());
124}