1use geom::{Duration, Time};
2use map_model::{EditCmd, TransitRouteID};
3use widgetry::{
4 EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, Spinner, State, TextExt,
5 VerticalAlignment, Widget,
6};
7
8use crate::app::App;
9use crate::app::Transition;
10use crate::edit::apply_map_edits;
11
12pub struct RouteEditor {
13 panel: Panel,
14 route: TransitRouteID,
15}
16
17impl RouteEditor {
18 pub fn new_state(ctx: &mut EventCtx, app: &mut App, id: TransitRouteID) -> Box<dyn State<App>> {
19 app.primary.current_selection = None;
20
21 let route = app.primary.map.get_tr(id);
22 Box::new(RouteEditor {
23 panel: Panel::new_builder(Widget::col(vec![
24 Widget::row(vec![
25 Line("Route editor").small_heading().into_widget(ctx),
26 ctx.style().btn_close_widget(ctx),
27 ]),
28 Line(&route.long_name).into_widget(ctx),
29 Widget::row(vec![
31 "Frequency".text_widget(ctx),
32 Spinner::widget(
33 ctx,
34 "freq_mins",
35 (Duration::minutes(1), Duration::hours(2)),
36 Duration::hours(1),
37 Duration::minutes(1),
38 ),
39 ]),
40 ctx.style()
41 .btn_solid_primary
42 .text("Apply")
43 .hotkey(Key::Enter)
44 .build_def(ctx),
45 ]))
46 .aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
47 .build(ctx),
48 route: id,
49 })
50 }
51}
52
53impl State<App> for RouteEditor {
54 fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
55 ctx.canvas_movement();
56
57 if let Outcome::Clicked(x) = self.panel.event(ctx) {
58 match x.as_ref() {
59 "close" => {
60 return Transition::Pop;
61 }
62 "Apply" => {
63 let freq = self.panel.spinner("freq_mins");
64 let mut now = Time::START_OF_DAY;
65 let mut hourly_times = Vec::new();
66 while now <= Time::START_OF_DAY + Duration::hours(24) {
67 hourly_times.push(now);
68 now += freq;
69 }
70
71 let mut edits = app.primary.map.get_edits().clone();
72 edits.commands.push(EditCmd::ChangeRouteSchedule {
73 id: self.route,
74 old: app.primary.map.get_tr(self.route).spawn_times.clone(),
75 new: hourly_times,
76 });
77 apply_map_edits(ctx, app, edits);
78
79 return Transition::Pop;
80 }
81 _ => unreachable!(),
82 }
83 }
84
85 Transition::Keep
86 }
87
88 fn draw(&self, g: &mut GfxCtx, _: &App) {
89 self.panel.draw(g);
90 }
91}