game/layer/
transit.rs

1use map_gui::tools::ColorDiscrete;
2use map_model::{PathConstraints, PathStep};
3use widgetry::mapspace::ToggleZoomed;
4use widgetry::{EventCtx, GfxCtx, Outcome, Panel, Toggle, Widget};
5
6use crate::app::App;
7use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
8
9pub struct TransitNetwork {
10    panel: Panel,
11    draw: ToggleZoomed,
12}
13
14impl Layer for TransitNetwork {
15    fn name(&self) -> Option<&'static str> {
16        Some("transit network")
17    }
18    fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Option<LayerOutcome> {
19        match self.panel.event(ctx) {
20            Outcome::Clicked(x) => match x.as_ref() {
21                "close" => {
22                    return Some(LayerOutcome::Close);
23                }
24                _ => unreachable!(),
25            },
26            Outcome::Changed(_) => {
27                *self = TransitNetwork::new(
28                    ctx,
29                    app,
30                    self.panel.is_checked("show all routes"),
31                    self.panel.is_checked("show buses"),
32                    self.panel.is_checked("show trains"),
33                );
34            }
35            _ => {}
36        }
37        None
38    }
39    fn draw(&self, g: &mut GfxCtx, _: &App) {
40        self.panel.draw(g);
41        self.draw.draw(g);
42    }
43    fn draw_minimap(&self, g: &mut GfxCtx) {
44        g.redraw(&self.draw.unzoomed);
45    }
46}
47
48impl TransitNetwork {
49    pub fn new(
50        ctx: &mut EventCtx,
51        app: &App,
52        show_all_routes: bool,
53        show_buses: bool,
54        show_trains: bool,
55    ) -> TransitNetwork {
56        let map = &app.primary.map;
57        // TODO Same color for both?
58        let mut categories = vec![
59            ("bus lanes / rails", app.cs.bus_layer),
60            ("transit stops", app.cs.bus_layer),
61        ];
62        if show_all_routes {
63            categories.push(("routes", app.cs.bus_layer));
64        }
65        let mut colorer = ColorDiscrete::new(app, categories);
66        for l in map.all_lanes() {
67            if l.is_bus() && show_buses {
68                colorer.add_l(l.id, "bus lanes / rails");
69            }
70            if l.is_light_rail() && show_trains {
71                colorer.add_l(l.id, "bus lanes / rails");
72            }
73        }
74        for ts in map.all_transit_stops().values() {
75            if !ts.is_train_stop && show_buses {
76                colorer.add_ts(ts.id, "transit stops");
77            }
78            if ts.is_train_stop && show_trains {
79                colorer.add_ts(ts.id, "transit stops");
80            }
81        }
82        if show_all_routes {
83            for tr in map.all_transit_routes() {
84                if !show_buses && tr.route_type == PathConstraints::Bus {
85                    continue;
86                }
87                if !show_trains && tr.route_type == PathConstraints::Train {
88                    continue;
89                }
90                for path in tr.all_paths(map).unwrap() {
91                    for step in path.get_steps() {
92                        if let PathStep::Lane(l) = step {
93                            colorer.add_l(*l, "routes");
94                        }
95                    }
96                }
97            }
98        }
99        let (draw, legend) = colorer.build(ctx);
100
101        let panel = Panel::new_builder(Widget::col(vec![
102            header(ctx, "Transit network"),
103            Toggle::switch(ctx, "show all routes", None, show_all_routes),
104            Toggle::switch(ctx, "show buses", None, show_buses),
105            Toggle::switch(ctx, "show trains", None, show_trains),
106            legend,
107        ]))
108        .aligned_pair(PANEL_PLACEMENT)
109        .build(ctx);
110
111        TransitNetwork { panel, draw }
112    }
113}