paiagram/interface/tabs/diagram/
edit_line.rs1use 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 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 displayed_line.stations.insert(index, (entity, 10.0));
125 }
126}