paiagram/interface/tabs/diagram/
edit_line.rs

1use bevy::{
2    ecs::{
3        entity::Entity,
4        name::Name,
5        query::With,
6        system::{In, InMut, Local, Query},
7    },
8    log::info,
9};
10use egui::{Color32, Popup, Pos2, ScrollArea, Sense, Stroke, Ui, UiBuilder, Vec2};
11
12use crate::intervals::Station;
13
14pub fn edit_line(
15    (InMut(ui), In(displayed_line_entity)): (InMut<Ui>, In<Entity>),
16    stations: Query<(Entity, &Name), With<Station>>,
17    mut displayed_lines: Query<&mut super::DisplayedLine>,
18) {
19    let mut insertion: Option<(usize, Entity)> = None;
20    let mut deletion: Option<usize> = None;
21    let Ok(mut displayed_line) = displayed_lines.get_mut(displayed_line_entity) else {
22        ui.label("Error: Displayed line not found.");
23        return;
24    };
25    ui.spacing_mut().item_spacing.y = 0.0;
26    let label_height = 20.0;
27    let addition_button_height = 30.0;
28    let addition_button_offset = 40.0;
29    ui.painter().line_segment(
30        [
31            Pos2 {
32                x: ui.max_rect().left() + addition_button_offset,
33                y: ui.min_rect().bottom(),
34            },
35            Pos2 {
36                x: ui.max_rect().left() + addition_button_offset,
37                y: ui.min_rect().bottom()
38                    + (label_height + addition_button_height)
39                        * (displayed_line.stations.len() + 1) as f32,
40            },
41        ],
42        ui.visuals().widgets.hovered.bg_stroke,
43    );
44
45    let mut add_station_between = |ui: &mut Ui, index: usize| {
46        let (rect, resp) = ui.allocate_exact_size(
47            Vec2 {
48                x: ui.available_width(),
49                y: addition_button_height,
50            },
51            Sense::click(),
52        );
53        let stroke = if resp.interact_pointer_pos().is_some() {
54            ui.visuals().widgets.hovered.fg_stroke
55        } else if resp.hovered() {
56            ui.visuals().widgets.hovered.bg_stroke
57        } else {
58            Stroke::NONE
59        };
60        let fill = if resp.hovered() || resp.interact_pointer_pos().is_some() {
61            ui.visuals().window_fill
62        } else {
63            Color32::TRANSPARENT
64        };
65        ui.painter()
66            .line_segment([rect.left_center(), rect.right_center()], stroke);
67        ui.painter().circle(
68            rect.left_center()
69                + Vec2 {
70                    x: addition_button_offset,
71                    y: 0.0,
72                },
73            6.0,
74            fill,
75            stroke,
76        );
77        Popup::menu(&resp).show(|ui| {
78            // TODO: improve station selection UI
79            ScrollArea::vertical().show(ui, |ui| {
80                for (entity, name) in stations.iter() {
81                    if ui.button(name.as_str()).clicked() {
82                        insertion = Some((index, entity));
83                    }
84                }
85            });
86        });
87    };
88
89    let station_names = displayed_line
90        .stations
91        .iter()
92        .copied()
93        .map(|(e, _)| stations.get(e).map_or("<Unknown>", |(_, n)| n.as_str()));
94    add_station_between(ui, 0);
95    for (i, name) in station_names.enumerate() {
96        let (rect, resp) = ui.allocate_exact_size(
97            Vec2 {
98                x: ui.available_width(),
99                y: label_height,
100            },
101            Sense::click(),
102        );
103        ui.scope_builder(UiBuilder::new().max_rect(rect).sense(resp.sense), |ui| {
104            ui.horizontal_centered(|ui| {
105                ui.add_space(addition_button_offset + 8.0 + 10.0);
106                ui.label(name)
107            });
108        });
109        ui.painter().circle(
110            rect.left_center()
111                + Vec2 {
112                    x: addition_button_offset,
113                    y: 0.0,
114                },
115            8.0,
116            ui.visuals().widgets.hovered.bg_fill,
117            ui.visuals().widgets.hovered.bg_stroke,
118        );
119        add_station_between(ui, i + 1);
120    }
121    if let Some((index, entity)) = insertion {
122        info!("Inserting station at index {index}");
123        // TODO: fix the 10.0 thingy
124        displayed_line.stations.insert(index, (entity, 10.0));
125    }
126}