make parking availability layer toggle on/off street

This commit is contained in:
Dustin Carlino 2020-05-04 12:50:33 -07:00
parent ce12974434
commit fe739c92fa
2 changed files with 130 additions and 26 deletions

View File

@ -23,7 +23,13 @@ use map_model::{BusRouteID, IntersectionID};
pub enum Layers {
Inactive,
ParkingOccupancy(Time, Colorer),
ParkingOccupancy {
time: Time,
onstreet: bool,
offstreet: bool,
unzoomed: Drawable,
composite: Composite,
},
WorstDelay(Time, Colorer),
TrafficJams(Time, Colorer),
CumulativeThroughput(Time, Colorer),
@ -53,9 +59,14 @@ impl Layers {
pub fn update(ctx: &mut EventCtx, app: &mut App, minimap: &Composite) -> Option<Transition> {
let now = app.primary.sim.time();
match app.layer {
Layers::ParkingOccupancy(t, _) => {
if now != t {
app.layer = parking::new(ctx, app);
Layers::ParkingOccupancy {
time,
onstreet,
offstreet,
..
} => {
if now != time {
app.layer = parking::new(ctx, app, onstreet, offstreet);
}
}
Layers::WorstDelay(t, _) => {
@ -107,8 +118,7 @@ impl Layers {
};
match app.layer {
Layers::ParkingOccupancy(_, ref mut c)
| Layers::BusNetwork(ref mut c)
Layers::BusNetwork(ref mut c)
| Layers::Elevation(ref mut c, _)
| Layers::WorstDelay(_, ref mut c)
| Layers::TrafficJams(_, ref mut c)
@ -120,6 +130,37 @@ impl Layers {
app.layer = Layers::Inactive;
}
}
Layers::ParkingOccupancy {
ref mut composite,
onstreet,
offstreet,
..
} => {
composite.align_above(ctx, minimap);
match composite.event(ctx) {
Some(Outcome::Clicked(x)) => match x.as_ref() {
"close" => {
app.layer = Layers::Inactive;
}
_ => unreachable!(),
},
None => {
let new_onstreet = composite.is_checked("On-street spots");
let new_offstreet = composite.is_checked("Off-street spots");
if onstreet != new_onstreet || offstreet != new_offstreet {
app.layer = parking::new(ctx, app, new_onstreet, new_offstreet);
// Immediately fix the alignment. TODO Do this for all of them, in a
// more uniform way
if let Layers::ParkingOccupancy {
ref mut composite, ..
} = app.layer
{
composite.align_above(ctx, minimap);
}
}
}
}
}
Layers::BikeNetwork(ref mut c1, ref mut maybe_c2) => {
if let Some(ref mut c2) = maybe_c2 {
c2.legend.align_above(ctx, minimap);
@ -216,8 +257,7 @@ impl Layers {
pub fn draw(&self, g: &mut GfxCtx) {
match self {
Layers::Inactive => {}
Layers::ParkingOccupancy(_, ref c)
| Layers::BusNetwork(ref c)
Layers::BusNetwork(ref c)
| Layers::WorstDelay(_, ref c)
| Layers::TrafficJams(_, ref c)
| Layers::CumulativeThroughput(_, ref c)
@ -237,6 +277,16 @@ impl Layers {
g.redraw(draw);
}
}
Layers::ParkingOccupancy {
ref unzoomed,
ref composite,
..
} => {
composite.draw(g);
if g.canvas.cam_zoom < MIN_ZOOM_FOR_DETAIL {
g.redraw(unzoomed);
}
}
Layers::PopulationMap(_, _, ref draw, ref composite) => {
composite.draw(g);
if g.canvas.cam_zoom < MIN_ZOOM_FOR_DETAIL {
@ -264,8 +314,7 @@ impl Layers {
pub fn draw_minimap(&self, g: &mut GfxCtx) {
match self {
Layers::Inactive => {}
Layers::ParkingOccupancy(_, ref c)
| Layers::BusNetwork(ref c)
Layers::BusNetwork(ref c)
| Layers::WorstDelay(_, ref c)
| Layers::TrafficJams(_, ref c)
| Layers::CumulativeThroughput(_, ref c)
@ -273,6 +322,9 @@ impl Layers {
| Layers::Edits(ref c) => {
g.redraw(&c.unzoomed);
}
Layers::ParkingOccupancy { ref unzoomed, .. } => {
g.redraw(unzoomed);
}
Layers::BikeNetwork(ref c1, ref maybe_c2) => {
g.redraw(&c1.unzoomed);
if let Some(ref c2) = maybe_c2 {
@ -322,7 +374,7 @@ impl Layers {
}
if let Some(name) = match app.layer {
Layers::Inactive => Some("None"),
Layers::ParkingOccupancy(_, _) => Some("parking occupancy"),
Layers::ParkingOccupancy { .. } => Some("parking occupancy"),
Layers::WorstDelay(_, _) => Some("delay"),
Layers::TrafficJams(_, _) => Some("worst traffic jams"),
Layers::CumulativeThroughput(_, _) => Some("throughput"),
@ -364,7 +416,7 @@ impl Layers {
.maybe_cb(
"parking occupancy",
Box::new(|ctx, app| {
app.layer = parking::new(ctx, app);
app.layer = parking::new(ctx, app, true, true);
Some(Transition::Pop)
}),
)

View File

@ -1,13 +1,25 @@
use crate::app::App;
use crate::common::Colorer;
use crate::common::{ColorLegend, Colorer};
use crate::layer::Layers;
use abstutil::{prettyprint_usize, Counter};
use ezgui::EventCtx;
use ezgui::{
hotkey, Btn, Checkbox, Composite, EventCtx, HorizontalAlignment, Key, Line, Text, TextExt,
VerticalAlignment, Widget,
};
use sim::{ParkingSpot, VehicleType};
use std::collections::HashSet;
pub fn new(ctx: &mut EventCtx, app: &App) -> Layers {
let (filled_spots, avail_spots) = app.primary.sim.get_all_parking_spots();
pub fn new(ctx: &mut EventCtx, app: &App, onstreet: bool, offstreet: bool) -> Layers {
let (mut filled_spots, mut avail_spots) = app.primary.sim.get_all_parking_spots();
filled_spots.retain(|spot| match spot {
ParkingSpot::Onstreet(_, _) => onstreet,
ParkingSpot::Offstreet(_, _) => offstreet,
});
avail_spots.retain(|spot| match spot {
ParkingSpot::Onstreet(_, _) => onstreet,
ParkingSpot::Offstreet(_, _) => offstreet,
});
let mut total_ppl = 0;
let mut has_car = 0;
for p in app.primary.sim.get_all_people() {
@ -20,19 +32,53 @@ pub fn new(ctx: &mut EventCtx, app: &App) -> Layers {
}
}
let composite = Composite::new(
Widget::col(vec![
Widget::row(vec![
Widget::draw_svg(ctx, "../data/system/assets/tools/layers.svg").margin_right(10),
"Parking occupancy (per road)".draw_text(ctx),
Btn::plaintext("X")
.build(ctx, "close", hotkey(Key::Escape))
.align_right(),
]),
Text::from_multiline(vec![
Line(format!(
"{:.0}% of the population owns a car",
100.0 * (has_car as f64) / (total_ppl as f64)
)),
Line(format!(
"{} spots filled",
prettyprint_usize(filled_spots.len())
)),
Line(format!(
"{} spots available ",
prettyprint_usize(avail_spots.len())
)),
])
.draw(ctx),
Widget::row(vec![
Checkbox::text(ctx, "On-street spots", None, onstreet),
Checkbox::text(ctx, "Off-street spots", None, offstreet),
])
.evenly_spaced(),
ColorLegend::scale(
ctx,
app.cs.good_to_bad.to_vec(),
vec!["0%", "40%", "70%", "90%", "100%"],
),
])
.padding(5)
.bg(app.cs.panel_bg),
)
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
.build(ctx);
// TODO Some kind of Scale abstraction that maps intervals of some quantity (percent,
// duration) to these 4 colors
let mut colorer = Colorer::scaled(
ctx,
"Parking occupancy (per road)",
vec![
format!(
"{:.0}% of the population owns a car",
100.0 * (has_car as f64) / (total_ppl as f64)
),
format!("{} spots filled", prettyprint_usize(filled_spots.len())),
format!("{} spots available ", prettyprint_usize(avail_spots.len())),
],
"",
Vec::new(),
app.cs.good_to_bad.to_vec(),
vec!["0%", "40%", "70%", "90%", "100%"],
);
@ -80,5 +126,11 @@ pub fn new(ctx: &mut EventCtx, app: &App) -> Layers {
colorer.add_l(l, color, &app.primary.map);
}
Layers::ParkingOccupancy(app.primary.sim.time(), colorer.build_unzoomed(ctx, app))
Layers::ParkingOccupancy {
time: app.primary.sim.time(),
onstreet,
offstreet,
unzoomed: colorer.build_both(ctx, app).unzoomed,
composite,
}
}