mirror of
https://github.com/a-b-street/abstreet.git
synced 2025-01-07 06:57:25 +03:00
same for the bus timeline
This commit is contained in:
parent
52c394aaf2
commit
08a601c45a
@ -115,9 +115,8 @@ pub fn make_route_picker(routes: Vec<BusRouteID>) -> Box<dyn State> {
|
|||||||
Some(Transition::PopWithData(Box::new(move |state, ui, ctx| {
|
Some(Transition::PopWithData(Box::new(move |state, ui, ctx| {
|
||||||
state.downcast_mut::<SandboxMode>().unwrap().overlay = match choice {
|
state.downcast_mut::<SandboxMode>().unwrap().overlay = match choice {
|
||||||
x if x == show_route => Overlays::show_bus_route(id, ctx, ui),
|
x if x == show_route => Overlays::show_bus_route(id, ctx, ui),
|
||||||
// TODO These two
|
|
||||||
x if x == delays => Overlays::Inactive,
|
x if x == delays => Overlays::Inactive,
|
||||||
x if x == passengers => Overlays::Inactive,
|
x if x == passengers => Overlays::bus_passengers(id, ctx, ui),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
})))
|
})))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::common::{edit_map_panel, Warping};
|
use crate::common::edit_map_panel;
|
||||||
use crate::game::{msg, Transition, WizardState};
|
use crate::game::{msg, Transition, WizardState};
|
||||||
use crate::helpers::{rotating_color_total, ID};
|
use crate::helpers::rotating_color_total;
|
||||||
use crate::sandbox::gameplay::{
|
use crate::sandbox::gameplay::{
|
||||||
cmp_duration_shorter, manage_overlays, GameplayMode, GameplayState,
|
cmp_duration_shorter, manage_overlays, GameplayMode, GameplayState,
|
||||||
};
|
};
|
||||||
@ -8,10 +8,10 @@ use crate::sandbox::overlays::Overlays;
|
|||||||
use crate::sandbox::SandboxMode;
|
use crate::sandbox::SandboxMode;
|
||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use ezgui::{
|
use ezgui::{
|
||||||
hotkey, Button, Choice, Color, Composite, DrawBoth, EventCtx, EventLoopMode, GeomBatch,
|
hotkey, Choice, Color, Composite, EventCtx, Key, Line, ManagedWidget, ModalMenu, Plot, Series,
|
||||||
JustDraw, Key, Line, ManagedWidget, ModalMenu, Plot, Series, Text,
|
Text,
|
||||||
};
|
};
|
||||||
use geom::{Circle, Distance, Polygon, Pt2D, Statistic, Time};
|
use geom::{Statistic, Time};
|
||||||
use map_model::BusRouteID;
|
use map_model::BusRouteID;
|
||||||
|
|
||||||
pub struct OptimizeBus {
|
pub struct OptimizeBus {
|
||||||
@ -93,12 +93,12 @@ impl GameplayState for OptimizeBus {
|
|||||||
"hide bus passengers",
|
"hide bus passengers",
|
||||||
overlays,
|
overlays,
|
||||||
match overlays {
|
match overlays {
|
||||||
Overlays::BusPassengers(_) => true,
|
Overlays::BusPassengers(_, ref r, _) => *r == self.route,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
self.time != ui.primary.sim.time(),
|
false,
|
||||||
) {
|
) {
|
||||||
*overlays = Overlays::BusPassengers(bus_passengers(self.route, ui, ctx));
|
*overlays = Overlays::bus_passengers(self.route, ctx, ui);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Expensive
|
// TODO Expensive
|
||||||
@ -182,102 +182,6 @@ fn bus_route_panel(id: BusRouteID, stat: Statistic, ui: &UI) -> Text {
|
|||||||
txt
|
txt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bus_passengers(id: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> crate::managed::Composite {
|
|
||||||
let route = ui.primary.map.get_br(id);
|
|
||||||
let mut master_col = vec![ManagedWidget::draw_text(
|
|
||||||
ctx,
|
|
||||||
Text::prompt(&format!("Passengers for {}", route.name)),
|
|
||||||
)];
|
|
||||||
let mut col = Vec::new();
|
|
||||||
|
|
||||||
let mut delay_per_stop = ui
|
|
||||||
.primary
|
|
||||||
.sim
|
|
||||||
.get_analytics()
|
|
||||||
.bus_passenger_delays(ui.primary.sim.time(), id);
|
|
||||||
for idx in 0..route.stops.len() {
|
|
||||||
let mut row = vec![ManagedWidget::btn(Button::text_no_bg(
|
|
||||||
Text::from(Line(format!("Stop {}", idx + 1))),
|
|
||||||
Text::from(Line(format!("Stop {}", idx + 1)).fg(Color::ORANGE)),
|
|
||||||
None,
|
|
||||||
&format!("Stop {}", idx + 1),
|
|
||||||
ctx,
|
|
||||||
))];
|
|
||||||
if let Some(hgram) = delay_per_stop.remove(&route.stops[idx]) {
|
|
||||||
row.push(ManagedWidget::draw_text(
|
|
||||||
ctx,
|
|
||||||
Text::from(Line(format!(
|
|
||||||
": {} (avg {})",
|
|
||||||
hgram.count(),
|
|
||||||
hgram.select(Statistic::Mean)
|
|
||||||
))),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
row.push(ManagedWidget::draw_text(ctx, Text::from(Line(": nobody"))));
|
|
||||||
}
|
|
||||||
col.push(ManagedWidget::row(row));
|
|
||||||
}
|
|
||||||
|
|
||||||
let y_len = ctx.default_line_height() * (route.stops.len() as f64);
|
|
||||||
let mut batch = GeomBatch::new();
|
|
||||||
batch.push(
|
|
||||||
Color::CYAN,
|
|
||||||
Polygon::rounded_rectangle(
|
|
||||||
Distance::meters(15.0),
|
|
||||||
Distance::meters(y_len),
|
|
||||||
Distance::meters(4.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
for (_, stop_idx, percent_next_stop) in ui.primary.sim.status_of_buses(route.id) {
|
|
||||||
// TODO Line it up right in the middle of the line of text. This is probably a bit wrong.
|
|
||||||
let base_percent_y = if stop_idx == route.stops.len() - 1 {
|
|
||||||
0.0
|
|
||||||
} else {
|
|
||||||
(stop_idx as f64) / ((route.stops.len() - 1) as f64)
|
|
||||||
};
|
|
||||||
batch.push(
|
|
||||||
Color::BLUE,
|
|
||||||
Circle::new(
|
|
||||||
Pt2D::new(
|
|
||||||
7.5,
|
|
||||||
base_percent_y * y_len + percent_next_stop * ctx.default_line_height(),
|
|
||||||
),
|
|
||||||
Distance::meters(5.0),
|
|
||||||
)
|
|
||||||
.to_polygon(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let timeline = ManagedWidget::just_draw(JustDraw::wrap(DrawBoth::new(ctx, batch, Vec::new())));
|
|
||||||
|
|
||||||
master_col.push(ManagedWidget::row(vec![
|
|
||||||
timeline.margin(5),
|
|
||||||
ManagedWidget::col(col).margin(5),
|
|
||||||
]));
|
|
||||||
|
|
||||||
let mut c = crate::managed::Composite::new(
|
|
||||||
Composite::new(ManagedWidget::col(master_col).bg(Color::grey(0.4))).build(ctx),
|
|
||||||
);
|
|
||||||
for (idx, stop) in route.stops.iter().enumerate() {
|
|
||||||
let id = ID::BusStop(*stop);
|
|
||||||
c = c.cb(
|
|
||||||
&format!("Stop {}", idx + 1),
|
|
||||||
Box::new(move |ctx, ui| {
|
|
||||||
Some(Transition::PushWithMode(
|
|
||||||
Warping::new(
|
|
||||||
ctx,
|
|
||||||
id.canonical_point(&ui.primary).unwrap(),
|
|
||||||
Some(4.0),
|
|
||||||
Some(id.clone()),
|
|
||||||
&mut ui.primary,
|
|
||||||
),
|
|
||||||
EventLoopMode::Animation,
|
|
||||||
))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
c
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bus_delays(id: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> Composite {
|
fn bus_delays(id: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> Composite {
|
||||||
let route = ui.primary.map.get_br(id);
|
let route = ui.primary.map.get_br(id);
|
||||||
let mut delays_per_stop = ui
|
let mut delays_per_stop = ui
|
||||||
|
@ -7,11 +7,11 @@ use crate::sandbox::SandboxMode;
|
|||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use abstutil::{prettyprint_usize, Counter};
|
use abstutil::{prettyprint_usize, Counter};
|
||||||
use ezgui::{
|
use ezgui::{
|
||||||
hotkey, Button, Color, Composite, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
|
hotkey, Button, Color, Composite, DrawBoth, Drawable, EventCtx, EventLoopMode, GeomBatch,
|
||||||
Histogram, HorizontalAlignment, Key, Line, ManagedWidget, RewriteColor, Text,
|
GfxCtx, Histogram, HorizontalAlignment, JustDraw, Key, Line, ManagedWidget, RewriteColor, Text,
|
||||||
VerticalAlignment,
|
VerticalAlignment,
|
||||||
};
|
};
|
||||||
use geom::{Distance, Duration, PolyLine, Time};
|
use geom::{Circle, Distance, Duration, PolyLine, Polygon, Pt2D, Statistic, Time};
|
||||||
use map_model::{BusRouteID, IntersectionID};
|
use map_model::{BusRouteID, IntersectionID};
|
||||||
use sim::ParkingSpot;
|
use sim::ParkingSpot;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@ -28,7 +28,7 @@ pub enum Overlays {
|
|||||||
IntersectionDemand(Time, IntersectionID, Drawable, Composite),
|
IntersectionDemand(Time, IntersectionID, Drawable, Composite),
|
||||||
BusRoute(Time, BusRouteID, ShowBusRoute),
|
BusRoute(Time, BusRouteID, ShowBusRoute),
|
||||||
BusDelaysOverTime(Composite),
|
BusDelaysOverTime(Composite),
|
||||||
BusPassengers(crate::managed::Composite),
|
BusPassengers(Time, BusRouteID, crate::managed::Composite),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Overlays {
|
impl Overlays {
|
||||||
@ -69,7 +69,11 @@ impl Overlays {
|
|||||||
Overlays::Inactive | Overlays::BikeNetwork(_) | Overlays::BusNetwork(_) => {}
|
Overlays::Inactive | Overlays::BikeNetwork(_) | Overlays::BusNetwork(_) => {}
|
||||||
// TODO do the updates here
|
// TODO do the updates here
|
||||||
Overlays::BusDelaysOverTime(_) => {}
|
Overlays::BusDelaysOverTime(_) => {}
|
||||||
Overlays::BusPassengers(_) => {}
|
Overlays::BusPassengers(t, id, _) => {
|
||||||
|
if now != *t {
|
||||||
|
*self = Overlays::bus_passengers(*id, ctx, ui);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
@ -87,11 +91,16 @@ impl Overlays {
|
|||||||
*self = Overlays::Inactive;
|
*self = Overlays::Inactive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Overlays::BusPassengers(ref mut c) => match c.event(ctx, ui) {
|
Overlays::BusPassengers(_, _, ref mut c) => match c.event(ctx, ui) {
|
||||||
Some(Outcome::Transition(t)) => {
|
Some(Outcome::Transition(t)) => {
|
||||||
return Some(t);
|
return Some(t);
|
||||||
}
|
}
|
||||||
Some(Outcome::Clicked(_)) => unreachable!(),
|
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
||||||
|
"X" => {
|
||||||
|
*self = Overlays::Inactive;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
None => {}
|
None => {}
|
||||||
},
|
},
|
||||||
Overlays::IntersectionDemand(_, i, _, ref mut c) => match c.event(ctx) {
|
Overlays::IntersectionDemand(_, i, _, ref mut c) => match c.event(ctx) {
|
||||||
@ -145,7 +154,7 @@ impl Overlays {
|
|||||||
| Overlays::BusDelaysOverTime(ref composite) => {
|
| Overlays::BusDelaysOverTime(ref composite) => {
|
||||||
composite.draw(g);
|
composite.draw(g);
|
||||||
}
|
}
|
||||||
Overlays::BusPassengers(ref composite) => {
|
Overlays::BusPassengers(_, _, ref composite) => {
|
||||||
composite.draw(g);
|
composite.draw(g);
|
||||||
}
|
}
|
||||||
Overlays::IntersectionDemand(_, _, ref draw, ref legend) => {
|
Overlays::IntersectionDemand(_, _, ref draw, ref legend) => {
|
||||||
@ -566,4 +575,103 @@ impl Overlays {
|
|||||||
pub fn show_bus_route(id: BusRouteID, ctx: &mut EventCtx, ui: &UI) -> Overlays {
|
pub fn show_bus_route(id: BusRouteID, ctx: &mut EventCtx, ui: &UI) -> Overlays {
|
||||||
Overlays::BusRoute(ui.primary.sim.time(), id, ShowBusRoute::new(id, ctx, ui))
|
Overlays::BusRoute(ui.primary.sim.time(), id, ShowBusRoute::new(id, ctx, ui))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bus_passengers(id: BusRouteID, ctx: &mut EventCtx, ui: &UI) -> Overlays {
|
||||||
|
let route = ui.primary.map.get_br(id);
|
||||||
|
let mut master_col = vec![ManagedWidget::row(vec![
|
||||||
|
ManagedWidget::draw_text(ctx, Text::prompt(&format!("Passengers for {}", route.name))),
|
||||||
|
crate::managed::Composite::text_button(ctx, "X", None).align_right(),
|
||||||
|
])];
|
||||||
|
let mut col = Vec::new();
|
||||||
|
|
||||||
|
let mut delay_per_stop = ui
|
||||||
|
.primary
|
||||||
|
.sim
|
||||||
|
.get_analytics()
|
||||||
|
.bus_passenger_delays(ui.primary.sim.time(), id);
|
||||||
|
for idx in 0..route.stops.len() {
|
||||||
|
let mut row = vec![ManagedWidget::btn(Button::text_no_bg(
|
||||||
|
Text::from(Line(format!("Stop {}", idx + 1))),
|
||||||
|
Text::from(Line(format!("Stop {}", idx + 1)).fg(Color::ORANGE)),
|
||||||
|
None,
|
||||||
|
&format!("Stop {}", idx + 1),
|
||||||
|
ctx,
|
||||||
|
))];
|
||||||
|
if let Some(hgram) = delay_per_stop.remove(&route.stops[idx]) {
|
||||||
|
row.push(ManagedWidget::draw_text(
|
||||||
|
ctx,
|
||||||
|
Text::from(Line(format!(
|
||||||
|
": {} (avg {})",
|
||||||
|
hgram.count(),
|
||||||
|
hgram.select(Statistic::Mean)
|
||||||
|
))),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
row.push(ManagedWidget::draw_text(ctx, Text::from(Line(": nobody"))));
|
||||||
|
}
|
||||||
|
col.push(ManagedWidget::row(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
let y_len = ctx.default_line_height() * (route.stops.len() as f64);
|
||||||
|
let mut batch = GeomBatch::new();
|
||||||
|
batch.push(
|
||||||
|
Color::CYAN,
|
||||||
|
Polygon::rounded_rectangle(
|
||||||
|
Distance::meters(15.0),
|
||||||
|
Distance::meters(y_len),
|
||||||
|
Distance::meters(4.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
for (_, stop_idx, percent_next_stop) in ui.primary.sim.status_of_buses(route.id) {
|
||||||
|
// TODO Line it up right in the middle of the line of text. This is probably a bit wrong.
|
||||||
|
let base_percent_y = if stop_idx == route.stops.len() - 1 {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
(stop_idx as f64) / ((route.stops.len() - 1) as f64)
|
||||||
|
};
|
||||||
|
batch.push(
|
||||||
|
Color::BLUE,
|
||||||
|
Circle::new(
|
||||||
|
Pt2D::new(
|
||||||
|
7.5,
|
||||||
|
base_percent_y * y_len + percent_next_stop * ctx.default_line_height(),
|
||||||
|
),
|
||||||
|
Distance::meters(5.0),
|
||||||
|
)
|
||||||
|
.to_polygon(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let timeline =
|
||||||
|
ManagedWidget::just_draw(JustDraw::wrap(DrawBoth::new(ctx, batch, Vec::new())));
|
||||||
|
|
||||||
|
master_col.push(ManagedWidget::row(vec![
|
||||||
|
timeline.margin(5),
|
||||||
|
ManagedWidget::col(col).margin(5),
|
||||||
|
]));
|
||||||
|
|
||||||
|
let mut c = crate::managed::Composite::new(
|
||||||
|
Composite::new(ManagedWidget::col(master_col).bg(Color::grey(0.4)))
|
||||||
|
.aligned(HorizontalAlignment::Right, VerticalAlignment::Center)
|
||||||
|
.build(ctx),
|
||||||
|
);
|
||||||
|
for (idx, stop) in route.stops.iter().enumerate() {
|
||||||
|
let id = ID::BusStop(*stop);
|
||||||
|
c = c.cb(
|
||||||
|
&format!("Stop {}", idx + 1),
|
||||||
|
Box::new(move |ctx, ui| {
|
||||||
|
Some(Transition::PushWithMode(
|
||||||
|
Warping::new(
|
||||||
|
ctx,
|
||||||
|
id.canonical_point(&ui.primary).unwrap(),
|
||||||
|
Some(4.0),
|
||||||
|
Some(id.clone()),
|
||||||
|
&mut ui.primary,
|
||||||
|
),
|
||||||
|
EventLoopMode::Animation,
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Overlays::BusPassengers(ui.primary.sim.time(), id, c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user