traaains/ui/track/segment/signals_list/item/
data.rs1use std::panic;
2
3use bevy::{
4 ecs::{
5 component::Component,
6 entity::Entity,
7 event::EntityEvent,
8 hierarchy::{ChildOf, Children},
9 observer::On,
10 query::With,
11 system::{Commands, Query},
12 },
13 feathers::{
14 controls::{FeathersCheckbox, FeathersSelect},
15 display::{label_dim, label_small},
16 },
17 log::tracing,
18 scene::{Scene, SceneList, bsn, on},
19 ui::{Checked, Display, FlexDirection, InteractionDisabled, Node, px},
20 ui_widgets::ValueChange,
21};
22
23use crate::{
24 sim::signal::{
25 Signals,
26 main::{MainSignal, MainSignalState, MainSignalStateDiscriminants, MaxSpeed},
27 },
28 ui::{
29 Target,
30 segment::signals_list::item::{
31 SignalListItem, data::max_speed_select::max_speed_toggle, find_root_with_target,
32 },
33 },
34};
35
36mod is_repeat;
37mod main_state_select;
38mod max_speed_select;
39
40#[derive(Clone, Copy, Component, Default)]
41enum MaxSpeedField {
42 #[default]
43 MaxSpeed,
44 NextSpeed,
45}
46
47#[derive(Component, Clone, Default)]
48pub struct SignalData;
49
50fn is_checkbox_checked(value: bool) -> Box<dyn Scene> {
51 if value {
52 Box::new(bsn! {Checked})
53 } else {
54 Box::new(bsn! {})
55 }
56}
57
58fn update_checkbox_visual(checked: bool, checkbox: Entity, cmd: &mut Commands) {
59 if checked {
60 cmd.entity(checkbox).insert(Checked);
61 } else {
62 cmd.entity(checkbox).remove::<Checked>();
63 }
64}
65
66fn on_value_change_summon(
67 e: On<ValueChange<bool>>,
68 mut cmd: Commands,
69 target: Query<(Entity, &Target), With<SignalListItem>>,
70 children: Query<&ChildOf>,
71 mut signals: Query<&mut Signals>,
72) {
73 update_checkbox_visual(e.value, e.event_target(), &mut cmd);
74
75 let Some((_, target_signal)) = find_root_with_target(e.event_target(), &target, &children)
76 else {
77 tracing::error!(
78 "Could not find parent UI entity with a target component pointing to a signal!"
79 );
80 return;
81 };
82
83 if let Ok(mut signal) = signals.get_mut(target_signal) {
84 match &mut *signal {
85 Signals::Main(main_signal) => match &mut main_signal.state {
86 MainSignalState::Stop { summon } => *summon = e.value,
87 _ => panic!("Unexpected signal type!"),
88 },
89 _ => panic!("Unexpected signal type!"),
90 }
91 }
92}
93
94fn is_summon_checkbox(is_summon: bool) -> impl Scene {
95 bsn! {
96 @FeathersCheckbox
97 @is_checkbox_checked(is_summon)
98 on(on_value_change_summon)
99 }
100}
101
102fn main_stop(is_summon: bool) -> impl SceneList {
103 bsn! {
104 @label_small("Summon?")
105 --
106 @is_summon_checkbox(is_summon)
107 }
108}
109
110fn max_speed_input(curr_max_speed: &Option<MaxSpeed>, field: MaxSpeedField) -> Box<dyn Scene> {
111 match curr_max_speed {
112 Some(max_speed) => Box::new(bsn! {
113 Node {
114 display: Display::Flex,
115 flex_direction: FlexDirection::Row
116 }
117 Children [
118 @max_speed_toggle(curr_max_speed.is_some(), field)
119 @max_speed_select::max_speed_select(max_speed, field)
120 ]
121 }),
122 None => Box::new(bsn! {
123 Node {
124 display: Display::Flex,
125 flex_direction: FlexDirection::Row
126 }
127 Children [
128 @max_speed_toggle(curr_max_speed.is_some(), field)
129 --
130 @FeathersSelect
131 InteractionDisabled
132 ]
133 }),
134 }
135}
136
137fn main_warning(max_speed: &Option<MaxSpeed>, next_speed: &Option<MaxSpeed>) -> impl SceneList {
138 bsn! {
139 @label_small("Max speed:")
140 --
141 @max_speed_input(max_speed, MaxSpeedField::MaxSpeed)
142 --
143 @label_small("Next speed:")
144 --
145 @max_speed_input(next_speed, MaxSpeedField::NextSpeed)
146 }
147}
148
149fn main_free(max_speed: &Option<MaxSpeed>) -> impl SceneList {
150 bsn! {
151 @label_small("Max speed:")
152 --
153 @max_speed_input(max_speed, MaxSpeedField::MaxSpeed)
154 }
155}
156
157fn main_data(main_signal: &MainSignal) -> Box<dyn SceneList> {
158 match &main_signal.state {
159 MainSignalState::Stop { summon } => Box::new(main_stop(*summon)),
160 MainSignalState::Warning {
161 max_speed,
162 next_speed,
163 } => Box::new(main_warning(max_speed, next_speed)),
164 MainSignalState::Free { max_speed } => Box::new(main_free(max_speed)),
165 }
166}
167
168pub fn signal_data_main(main_signal: &MainSignal) -> impl Scene {
171 let state_var = match &main_signal.state {
172 MainSignalState::Stop { summon: _ } => MainSignalStateDiscriminants::Stop,
173 MainSignalState::Warning {
174 max_speed: _,
175 next_speed: _,
176 } => MainSignalStateDiscriminants::Warning,
177 MainSignalState::Free { max_speed: _ } => MainSignalStateDiscriminants::Free,
178 };
179
180 bsn! {
181 Node {
182 display: Display::Flex,
183 flex_direction: FlexDirection::Column,
184 padding: px(4)
185 }
186 Children [
187 @label_small("Is a repeat signal?")
188 --
189 @is_repeat::is_repeat_checkbox(main_signal.is_repeat)
190 --
191 @label_small("State")
192 --
193 @main_state_select::main_state_select(state_var)
194 --
195 @label_small("Main signal data")
196 --
197 {main_data(main_signal)}
198 ]
199 }
200}
201
202pub fn signal_data_stop() -> impl Scene {
203 bsn! {
204 Node {
205 display: Display::Flex,
206 flex_direction: FlexDirection::Column,
207 padding: px(4)
208 }
209 Children [
210 @label_dim("No data")
211 ]
212 }
213}
214
215pub fn signal_data(signal_var: &Signals) -> impl Scene {
216 let signal_data_inner: Box<dyn Scene> = match signal_var {
217 Signals::Main(main_signal) => Box::new(signal_data_main(main_signal)),
218 Signals::Stop => Box::new(signal_data_stop()),
219 };
220
221 bsn! {
222 SignalData
223 Node {}
224 Children [@signal_data_inner]
225 }
226}