game/info/
parking_lot.rs

1use abstutil::prettyprint_usize;
2use map_model::ParkingLotID;
3use widgetry::{EventCtx, Line, LinePlot, PlotOptions, Series, TextExt, Widget};
4
5use crate::app::App;
6use crate::info::{header_btns, make_tabs, Details, Tab};
7
8pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: ParkingLotID) -> Widget {
9    Widget::custom_col(vec![
10        header(ctx, details, id, Tab::ParkingLot(id)),
11        info_body(ctx, app, id).tab_body(ctx),
12    ])
13}
14
15fn info_body(ctx: &mut EventCtx, app: &App, id: ParkingLotID) -> Widget {
16    let mut rows = vec![];
17    let pl = app.primary.map.get_pl(id);
18    let capacity = pl.capacity();
19
20    rows.push(
21        format!(
22            "{} / {} spots available",
23            prettyprint_usize(app.primary.sim.get_free_lot_spots(pl.id).len()),
24            prettyprint_usize(capacity)
25        )
26        .text_widget(ctx),
27    );
28
29    let mut series = vec![Series {
30        label: format!("After \"{}\"", app.primary.map.get_edits().edits_name),
31        color: app.cs.after_changes,
32        pts: app.primary.sim.get_analytics().parking_lot_availability(
33            app.primary.sim.time(),
34            pl.id,
35            capacity,
36        ),
37    }];
38    if app.has_prebaked().is_some() {
39        series.push(Series {
40            label: format!("Before \"{}\"", app.primary.map.get_edits().edits_name),
41            color: app.cs.before_changes.alpha(0.5),
42            pts: app.prebaked().parking_lot_availability(
43                app.primary.sim.get_end_of_day(),
44                pl.id,
45                capacity,
46            ),
47        });
48    }
49
50    let section = Widget::col(vec![
51        Line("Parking spots available")
52            .small_heading()
53            .into_widget(ctx),
54        LinePlot::new_widget(
55            ctx,
56            "parking availability",
57            series,
58            PlotOptions {
59                max_y: Some(capacity),
60                ..Default::default()
61            },
62            app.opts.units,
63        ),
64    ])
65    .padding(10)
66    .bg(app.cs.inner_panel_bg)
67    .outline(ctx.style().section_outline);
68    rows.push(section);
69
70    if app.opts.dev {
71        rows.push(
72            ctx.style()
73                .btn_outline
74                .text("Open OSM")
75                .build_widget(ctx, format!("open {}", pl.osm_id)),
76        );
77    }
78
79    Widget::col(rows)
80}
81
82fn header(ctx: &EventCtx, details: &mut Details, id: ParkingLotID, tab: Tab) -> Widget {
83    Widget::custom_col(vec![
84        Widget::row(vec![
85            Line(id.to_string()).small_heading().into_widget(ctx),
86            header_btns(ctx),
87        ]),
88        make_tabs(
89            ctx,
90            &mut details.hyperlinks,
91            tab,
92            vec![("Info", Tab::ParkingLot(id))],
93        ),
94    ])
95}