UI fixes discovered during riding buses off-map

- speed limit dropdown crash
- link to bus route from bus stop panel, not some currently running bus
- show number of waiting people per stop in route panel and route dash
This commit is contained in:
Dustin Carlino 2020-07-27 08:19:14 -07:00
parent e79e186784
commit 2239059961
5 changed files with 81 additions and 52 deletions

View File

@ -596,29 +596,29 @@ pub fn can_edit_lane(mode: &GameplayMode, l: LaneID, app: &App) -> bool {
}
pub fn change_speed_limit(ctx: &mut EventCtx, default: Speed) -> Widget {
let mut choices = vec![
Choice::new("10 mph", Speed::miles_per_hour(10.0)),
Choice::new("15 mph", Speed::miles_per_hour(15.0)),
Choice::new("20 mph", Speed::miles_per_hour(20.0)),
Choice::new("25 mph", Speed::miles_per_hour(25.0)),
Choice::new("30 mph", Speed::miles_per_hour(30.0)),
Choice::new("35 mph", Speed::miles_per_hour(35.0)),
Choice::new("40 mph", Speed::miles_per_hour(40.0)),
Choice::new("45 mph", Speed::miles_per_hour(45.0)),
Choice::new("50 mph", Speed::miles_per_hour(50.0)),
Choice::new("55 mph", Speed::miles_per_hour(55.0)),
Choice::new("60 mph", Speed::miles_per_hour(60.0)),
Choice::new("65 mph", Speed::miles_per_hour(65.0)),
Choice::new("70 mph", Speed::miles_per_hour(70.0)),
// Don't need anything higher. Though now I kind of miss 3am drives on TX-71...
];
if !choices.iter().any(|c| c.data == default) {
choices.push(Choice::new(default.to_string(), default));
}
Widget::row(vec![
"Change speed limit:".draw_text(ctx).centered_vert(),
Widget::dropdown(
ctx,
"speed limit",
default,
vec![
Choice::new("10 mph", Speed::miles_per_hour(10.0)),
Choice::new("15 mph", Speed::miles_per_hour(15.0)),
Choice::new("20 mph", Speed::miles_per_hour(20.0)),
Choice::new("25 mph", Speed::miles_per_hour(25.0)),
Choice::new("30 mph", Speed::miles_per_hour(30.0)),
Choice::new("35 mph", Speed::miles_per_hour(35.0)),
Choice::new("40 mph", Speed::miles_per_hour(40.0)),
Choice::new("45 mph", Speed::miles_per_hour(45.0)),
Choice::new("50 mph", Speed::miles_per_hour(50.0)),
Choice::new("55 mph", Speed::miles_per_hour(55.0)),
Choice::new("60 mph", Speed::miles_per_hour(60.0)),
Choice::new("65 mph", Speed::miles_per_hour(65.0)),
Choice::new("70 mph", Speed::miles_per_hour(70.0)),
// Don't need anything higher. Though now I kind of miss 3am drives on TX-71...
],
),
Widget::dropdown(ctx, "speed limit", default, choices),
])
}

View File

@ -22,19 +22,10 @@ pub fn stop(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusStopID)
let all_arrivals = &sim.get_analytics().bus_arrivals;
for r in app.primary.map.get_routes_serving_stop(id) {
let buses = app.primary.sim.status_of_buses(r.id, &app.primary.map);
if buses.is_empty() {
rows.push(format!("Route {}: no buses running", r.short_name).draw_text(ctx));
} else {
rows.push(Btn::text_fg(format!("Route {}", r.short_name)).build(
ctx,
&r.full_name,
None,
));
details
.hyperlinks
.insert(r.full_name.clone(), Tab::BusStatus(buses[0].0));
}
rows.push(Btn::text_fg(format!("Route {}", r.short_name)).build(ctx, &r.full_name, None));
details
.hyperlinks
.insert(r.full_name.clone(), Tab::BusRoute(r.id));
let arrivals: Vec<(Time, CarID)> = all_arrivals
.iter()
@ -201,6 +192,7 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
let mut boardings: Counter<BusStopID> = Counter::new();
let mut alightings: Counter<BusStopID> = Counter::new();
let mut waiting: Counter<BusStopID> = Counter::new();
for bs in &route.stops {
if let Some(list) = app.primary.sim.get_analytics().passengers_boarding.get(bs) {
for (_, r, _) in list {
@ -216,15 +208,22 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
}
}
}
for (_, r, _, _) in app.primary.sim.get_people_waiting_at_stop(*bs) {
if *r == id {
waiting.inc(*bs);
}
}
}
rows.push(
Text::from_all(vec![
Line("Total"),
Line(format!(
": {} boardings, {} alightings",
": {} boardings, {} alightings, {} currently waiting",
prettyprint_usize(boardings.sum()),
prettyprint_usize(alightings.sum())
prettyprint_usize(alightings.sum()),
prettyprint_usize(waiting.sum())
))
.secondary(),
])
@ -257,9 +256,10 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
Text::from_all(vec![
Line(&bs.name),
Line(format!(
": {} boardings, {} alightings",
": {} boardings, {} alightings, {} currently waiting",
prettyprint_usize(boardings.get(bs.id)),
prettyprint_usize(alightings.get(bs.id))
prettyprint_usize(alightings.get(bs.id)),
prettyprint_usize(waiting.get(bs.id))
))
.secondary(),
])

View File

@ -70,7 +70,7 @@ pub struct TransitRoutes {
impl TransitRoutes {
pub fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State> {
// Count total boardings/alightings per route
// Count totals per route
let mut boardings = Counter::new();
for list in app.primary.sim.get_analytics().passengers_boarding.values() {
for (_, r, _) in list {
@ -89,13 +89,20 @@ impl TransitRoutes {
alightings.inc(*r);
}
}
let mut waiting = Counter::new();
for bs in app.primary.map.all_bus_stops().keys() {
for (_, r, _, _) in app.primary.sim.get_people_waiting_at_stop(*bs) {
waiting.inc(*r);
}
}
// Sort descending by count, but ascending by name. Hence the funny negation.
let mut routes: Vec<(isize, isize, String, BusRouteID)> = Vec::new();
let mut routes: Vec<(isize, isize, isize, String, BusRouteID)> = Vec::new();
for r in app.primary.map.all_bus_routes() {
routes.push((
-1 * (boardings.get(r.id) as isize),
-1 * (alightings.get(r.id) as isize),
-1 * (waiting.get(r.id) as isize),
r.full_name.clone(),
r.id,
));
@ -111,7 +118,7 @@ impl TransitRoutes {
ctx,
routes
.iter()
.map(|(_, _, r, id)| (r.clone(), *id))
.map(|(_, _, _, r, id)| (r.clone(), *id))
.collect(),
)
.named("search"),
@ -121,13 +128,14 @@ impl TransitRoutes {
Widget::col(
routes
.into_iter()
.map(|(boardings, alightings, name, id)| {
.map(|(boardings, alightings, waiting, name, id)| {
Widget::row(vec![
Btn::text_fg(name).build(ctx, id.to_string(), None),
format!(
"{} boardings, {} alightings",
"{} boardings, {} alightings, {} currently waiting",
prettyprint_usize(-boardings as usize),
prettyprint_usize(-alightings as usize)
prettyprint_usize(-alightings as usize),
prettyprint_usize(-waiting as usize)
)
.draw_text(ctx),
])

View File

@ -13,8 +13,8 @@ use derivative::Derivative;
use geom::{Distance, Duration, PolyLine, Pt2D, Speed, Time};
use instant::Instant;
use map_model::{
BuildingID, BusRoute, BusRouteID, IntersectionID, Lane, LaneID, Map, ParkingLotID, Path,
PathConstraints, PathRequest, Position, RoadID, Traversable,
BuildingID, BusRoute, BusRouteID, BusStopID, IntersectionID, Lane, LaneID, Map, ParkingLotID,
Path, PathConstraints, PathRequest, Position, RoadID, Traversable,
};
use rand_xorshift::XorShiftRng;
use serde::{Deserialize, Serialize};
@ -118,7 +118,7 @@ impl Sim {
opts.dont_block_the_box,
opts.break_turn_conflict_cycles,
),
transit: TransitSimState::new(),
transit: TransitSimState::new(map),
trips: TripManager::new(opts.pathfinding_upfront),
pandemic: if let Some(rng) = opts.enable_pandemic_model {
Some(PandemicModel::new(rng))
@ -854,6 +854,7 @@ impl Sim {
}
// Queries of all sorts
// TODO Many of these just delegate to an inner piece. This is unorganized and hard to maintain.
impl Sim {
pub fn time(&self) -> Time {
self.time
@ -1178,6 +1179,13 @@ impl Sim {
self.driving.target_lane_penalty(lane.id)
}
}
pub fn get_people_waiting_at_stop(
&self,
at: BusStopID,
) -> &Vec<(PedestrianID, BusRouteID, Option<BusStopID>, Time)> {
self.transit.get_people_waiting_at_stop(at)
}
}
// Invasive debugging

View File

@ -67,11 +67,17 @@ pub struct TransitSimState {
}
impl TransitSimState {
pub fn new() -> TransitSimState {
pub fn new(map: &Map) -> TransitSimState {
// Keep this filled out always so get_passengers can return &Vec without a hassle
let mut peds_waiting = BTreeMap::new();
for bs in map.all_bus_stops().keys() {
peds_waiting.insert(*bs, Vec::new());
}
TransitSimState {
buses: BTreeMap::new(),
routes: BTreeMap::new(),
peds_waiting: BTreeMap::new(),
peds_waiting,
events: Vec::new(),
}
}
@ -207,7 +213,7 @@ impl TransitSimState {
// Board new passengers.
let mut still_waiting = Vec::new();
for (ped, route, maybe_stop2, started_waiting) in
self.peds_waiting.remove(&stop1).unwrap_or_else(Vec::new)
self.peds_waiting.remove(&stop1).unwrap()
{
if bus.route == route {
let (trip, person) = trips.ped_boarded_bus(
@ -347,8 +353,8 @@ impl TransitSimState {
}
self.peds_waiting
.entry(stop1)
.or_insert_with(Vec::new)
.get_mut(&stop1)
.unwrap()
.push((ped, route_id, maybe_stop2, now));
None
}
@ -407,4 +413,11 @@ impl TransitSimState {
}
(buses, trains)
}
pub fn get_people_waiting_at_stop(
&self,
at: BusStopID,
) -> &Vec<(PedestrianID, BusRouteID, Option<BusStopID>, Time)> {
&self.peds_waiting[&at]
}
}