mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
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:
parent
e79e186784
commit
2239059961
@ -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),
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
])
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user