traaains/ui/track/segment/signals_list/item/data/
max_speed_select.rs1use core::panic;
2
3use bevy::{
4 ecs::{
5 entity::Entity,
6 event::EntityEvent,
7 hierarchy::ChildOf,
8 observer::On,
9 query::With,
10 system::{Commands, Query},
11 },
12 feathers::controls::{FeathersCheckbox, FeathersSelect, OptionIndex, list_rows_from_strings},
13 log::tracing,
14 scene::{Scene, bsn, on},
15 ui_widgets::ValueChange,
16};
17use strum::IntoEnumIterator;
18
19use crate::{
20 sim::signal::{
21 Signals,
22 main::{MainSignalState, MaxSpeed},
23 },
24 ui::{
25 Target,
26 segment::signals_list::item::{
27 SignalListItem,
28 data::{MaxSpeedField, is_checkbox_checked, update_checkbox_visual},
29 find_root_with_target,
30 },
31 },
32};
33
34fn on_value_change(
35 e: On<ValueChange<Entity>>,
36 options: Query<&OptionIndex>,
37 target: Query<(Entity, &Target), With<SignalListItem>>,
38 children: Query<&ChildOf>,
39 max_speed_field: Query<&MaxSpeedField>,
40 mut signals: Query<&mut Signals>,
41) {
42 let Some((_, target_signal)) = find_root_with_target(e.event_target(), &target, &children)
43 else {
44 tracing::error!(
45 "Could not find parent UI entity with a target component pointing to a signal!"
46 );
47 return;
48 };
49
50 let Ok(option) = options.get(e.value) else {
51 return;
52 };
53
54 let new_speed = MaxSpeed::iter().nth(option.0).unwrap();
55
56 let Ok(max_speed_field) = max_speed_field.get(e.event_target()) else {
57 tracing::warn!("Max speed select doesn't have field set, add a MaxSpeedField component!");
58 return;
59 };
60
61 let Ok(mut signal) = signals.get_mut(target_signal) else {
62 return;
63 };
64
65 match &mut *signal {
66 Signals::Main(main_signal) => match &mut main_signal.state {
67 MainSignalState::Warning {
68 max_speed,
69 next_speed,
70 } => match max_speed_field {
71 MaxSpeedField::MaxSpeed => *max_speed = Some(new_speed),
72 MaxSpeedField::NextSpeed => *next_speed = Some(new_speed),
73 },
74 MainSignalState::Free { max_speed } => match max_speed_field {
75 MaxSpeedField::MaxSpeed => *max_speed = Some(new_speed),
76 _ => panic!("Invalid max speed field"),
77 },
78 _ => panic!("Invalid signal state"),
79 },
80 _ => panic!("Invalid signal"),
81 }
82}
83
84pub fn max_speed_select(curr: &MaxSpeed, field: MaxSpeedField) -> impl Scene {
85 let selected_signal = MaxSpeed::iter().enumerate().find_map(|(i, v)| {
86 if v == *curr {
87 return Some(i);
88 }
89
90 None
91 });
92
93 bsn! {
94 @FeathersSelect {
95 @options: list_rows_from_strings(MaxSpeed::iter().map(|s| u32::from(s).to_string()), selected_signal),
96 }
97 field
98 on(on_value_change)
99 }
100}
101
102fn on_value_change_toggle(
103 e: On<ValueChange<bool>>,
104 mut cmd: Commands,
105 target: Query<(Entity, &Target), With<SignalListItem>>,
106 children: Query<&ChildOf>,
107 max_speed_field: Query<&MaxSpeedField>,
108 mut signals: Query<&mut Signals>,
109) {
110 update_checkbox_visual(e.value, e.event_target(), &mut cmd);
111
112 let Some((_, target_signal)) = find_root_with_target(e.event_target(), &target, &children)
113 else {
114 tracing::error!(
115 "Could not find parent UI entity with a target component pointing to a signal!"
116 );
117 return;
118 };
119
120 let Ok(max_speed_field) = max_speed_field.get(e.event_target()) else {
121 tracing::warn!("Max speed toggle doesn't have field set, add a MaxSpeedField component!");
122 return;
123 };
124
125 let Ok(mut signal) = signals.get_mut(target_signal) else {
126 return;
127 };
128
129 match &mut *signal {
130 Signals::Main(main_signal) => match &mut main_signal.state {
131 MainSignalState::Warning {
132 max_speed,
133 next_speed,
134 } => match max_speed_field {
135 MaxSpeedField::MaxSpeed => {
136 *max_speed = if e.value {
137 Some(Default::default())
138 } else {
139 None
140 }
141 }
142 MaxSpeedField::NextSpeed => {
143 *next_speed = if e.value {
144 Some(Default::default())
145 } else {
146 None
147 }
148 }
149 },
150 MainSignalState::Free { max_speed } => match max_speed_field {
151 MaxSpeedField::MaxSpeed => {
152 *max_speed = if e.value {
153 Some(Default::default())
154 } else {
155 None
156 }
157 }
158 _ => panic!("Invalid max speed field"),
159 },
160 _ => panic!("Invalid signal state"),
161 },
162 _ => panic!("Invalid signal"),
163 }
164}
165
166pub fn max_speed_toggle(is_present: bool, field: MaxSpeedField) -> impl Scene {
167 bsn! {
168 @FeathersCheckbox
169 @is_checkbox_checked(is_present)
170 field
171 on(on_value_change_toggle)
172 }
173}