traaains/ui/track/segment/signals_list/
item.rs1use bevy::{
2 ecs::{
3 change_detection::DetectChanges,
4 component::Component,
5 entity::Entity,
6 hierarchy::{ChildOf, Children},
7 observer::On,
8 query::With,
9 system::{Commands, Query},
10 world::Ref,
11 },
12 feathers::{
13 constants::icons,
14 containers::{flex_spacer, group, group_body, group_header},
15 controls::{ButtonVariant, FeathersToolButton},
16 display::{icon, label, label_small},
17 },
18 scene::{CommandsSceneExt, Scene, bsn, on},
19 ui_widgets::Activate,
20};
21
22use crate::{
23 sim::{
24 signal::{Signals, commands::RemoveSignal},
25 track::pos::TrackPos,
26 },
27 ui::{
28 Target,
29 segment::signals_list::item::{
30 data::{SignalData, signal_data, signal_data_main, signal_data_stop},
31 index_input::SignalIndexInput,
32 type_input::signal_type_input,
33 },
34 },
35};
36
37pub mod data;
38pub mod index_input;
39pub mod type_input;
40
41#[derive(Component, Clone, Default)]
51pub struct SignalListItem;
52
53pub fn signals_list_item(
54 idx: usize,
55 entity: Entity,
56 variant: &Signals,
57 track_pos: &TrackPos,
58) -> impl Scene {
59 bsn! {
60 @group()
61 SignalListItem
62 Target(entity)
63 Children [
64 @group_header() Children [
65 @label(format!("Segment #{}", idx + 1))
66 --
67 @flex_spacer()
68 --
69 @FeathersToolButton {
70 @variant: ButtonVariant::Plain,
71 }
72 Children [
73 @icon(icons::X)
74 ]
75 on(|e: On<Activate>, mut cmd: Commands, target: Query<(Entity, &Target), With<SignalListItem>>,
76 children: Query<&ChildOf>| {
77 let (signal_list_item, signal) = find_root_with_target(e.entity, &target, &children).unwrap();
78 cmd.queue(RemoveSignal::new(signal));
79 cmd.entity(signal_list_item).despawn();
80 })
81 ]
82 --
83 @group_body() Children [
84 @label_small("Track index")
85 --
86 @SignalIndexInput {
87 @value: {track_pos.idx}
88 }
89 Target(entity)
90 --
91 @label_small("Signal type")
92 --
93 @signal_type_input(variant.into())
94 --
95 @label_small("Signal data")
96 --
97 @signal_data(variant)
98 ]
99 ]
100 }
101}
102
103fn find_root_with_target(
105 curr_entity: Entity,
106 target: &Query<(Entity, &Target), With<SignalListItem>>,
107 children: &Query<&ChildOf>,
108) -> Option<(Entity, Entity)> {
109 if let Ok((te, t)) = target.get(curr_entity) {
110 return Some((te, t.0));
111 }
112
113 if let Ok(child) = children.get(curr_entity) {
114 return find_root_with_target(child.parent(), target, children);
115 }
116
117 None
118}
119
120fn find_signal_data(
121 curr_entity: Entity,
122 signal_data: &Query<Entity, With<SignalData>>,
123 children: &Query<&Children>,
124) -> Option<Entity> {
125 if let Ok(e) = signal_data.get(curr_entity) {
126 return Some(e);
127 }
128
129 if let Ok(curr_children) = children.get(curr_entity) {
131 for c in curr_children {
132 if let Some(e) = find_signal_data(*c, signal_data, children) {
133 return Some(e);
134 }
135 }
136 }
137
138 None
139}
140
141pub fn update_signal_list_items(
143 mut cmd: Commands,
144 signal_list_items: Query<(Entity, &Target), With<SignalListItem>>,
145 _signal_index_inputs: Query<Entity, With<SignalIndexInput>>,
146 signal_data: Query<Entity, With<SignalData>>,
147 signals: Query<(Ref<Signals>, Ref<TrackPos>)>,
148 children: Query<&Children>,
149) {
150 for (item_e, item_target) in signal_list_items {
151 match signals.get(item_target.0) {
152 Ok((signal_var, _signal_track_pos)) => {
153 if signal_var.is_changed()
154 && let Some(signal_data) = find_signal_data(item_e, &signal_data, &children)
155 {
156 cmd.entity(signal_data).despawn_children();
157 match &*signal_var {
158 Signals::Main(main_signal) => {
159 let sd_id = cmd.spawn_scene(signal_data_main(main_signal)).id();
160 cmd.entity(sd_id).insert(ChildOf(signal_data));
161 }
162 Signals::Stop => {
163 let sd_id = cmd.spawn_scene(signal_data_stop()).id();
164 cmd.entity(sd_id).insert(ChildOf(signal_data));
165 }
166 };
167 }
168 }
169 Err(_) => {
170 cmd.entity(item_e).despawn();
173 }
174 }
175 }
176}