mirror of
https://github.com/a-b-street/abstreet.git
synced 2025-01-05 13:05:06 +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| {
|
||||
state.downcast_mut::<SandboxMode>().unwrap().overlay = match choice {
|
||||
x if x == show_route => Overlays::show_bus_route(id, ctx, ui),
|
||||
// TODO These two
|
||||
x if x == delays => Overlays::Inactive,
|
||||
x if x == passengers => Overlays::Inactive,
|
||||
x if x == passengers => Overlays::bus_passengers(id, ctx, ui),
|
||||
_ => 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::helpers::{rotating_color_total, ID};
|
||||
use crate::helpers::rotating_color_total;
|
||||
use crate::sandbox::gameplay::{
|
||||
cmp_duration_shorter, manage_overlays, GameplayMode, GameplayState,
|
||||
};
|
||||
@ -8,10 +8,10 @@ use crate::sandbox::overlays::Overlays;
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{
|
||||
hotkey, Button, Choice, Color, Composite, DrawBoth, EventCtx, EventLoopMode, GeomBatch,
|
||||
JustDraw, Key, Line, ManagedWidget, ModalMenu, Plot, Series, Text,
|
||||
hotkey, Choice, Color, Composite, EventCtx, Key, Line, ManagedWidget, ModalMenu, Plot, Series,
|
||||
Text,
|
||||
};
|
||||
use geom::{Circle, Distance, Polygon, Pt2D, Statistic, Time};
|
||||
use geom::{Statistic, Time};
|
||||
use map_model::BusRouteID;
|
||||
|
||||
pub struct OptimizeBus {
|
||||
@ -93,12 +93,12 @@ impl GameplayState for OptimizeBus {
|
||||
"hide bus passengers",
|
||||
overlays,
|
||||
match overlays {
|
||||
Overlays::BusPassengers(_) => true,
|
||||
Overlays::BusPassengers(_, ref r, _) => *r == self.route,
|
||||
_ => 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
|
||||
@ -182,102 +182,6 @@ fn bus_route_panel(id: BusRouteID, stat: Statistic, ui: &UI) -> Text {
|
||||
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 {
|
||||
let route = ui.primary.map.get_br(id);
|
||||
let mut delays_per_stop = ui
|
||||
|
@ -7,11 +7,11 @@ use crate::sandbox::SandboxMode;
|
||||
use crate::ui::UI;
|
||||
use abstutil::{prettyprint_usize, Counter};
|
||||
use ezgui::{
|
||||
hotkey, Button, Color, Composite, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
|
||||
Histogram, HorizontalAlignment, Key, Line, ManagedWidget, RewriteColor, Text,
|
||||
hotkey, Button, Color, Composite, DrawBoth, Drawable, EventCtx, EventLoopMode, GeomBatch,
|
||||
GfxCtx, Histogram, HorizontalAlignment, JustDraw, Key, Line, ManagedWidget, RewriteColor, Text,
|
||||
VerticalAlignment,
|
||||
};
|
||||
use geom::{Distance, Duration, PolyLine, Time};
|
||||
use geom::{Circle, Distance, Duration, PolyLine, Polygon, Pt2D, Statistic, Time};
|
||||
use map_model::{BusRouteID, IntersectionID};
|
||||
use sim::ParkingSpot;
|
||||
use std::collections::HashSet;
|
||||
@ -28,7 +28,7 @@ pub enum Overlays {
|
||||
IntersectionDemand(Time, IntersectionID, Drawable, Composite),
|
||||
BusRoute(Time, BusRouteID, ShowBusRoute),
|
||||
BusDelaysOverTime(Composite),
|
||||
BusPassengers(crate::managed::Composite),
|
||||
BusPassengers(Time, BusRouteID, crate::managed::Composite),
|
||||
}
|
||||
|
||||
impl Overlays {
|
||||
@ -69,7 +69,11 @@ impl Overlays {
|
||||
Overlays::Inactive | Overlays::BikeNetwork(_) | Overlays::BusNetwork(_) => {}
|
||||
// TODO do the updates here
|
||||
Overlays::BusDelaysOverTime(_) => {}
|
||||
Overlays::BusPassengers(_) => {}
|
||||
Overlays::BusPassengers(t, id, _) => {
|
||||
if now != *t {
|
||||
*self = Overlays::bus_passengers(*id, ctx, ui);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self {
|
||||
@ -87,11 +91,16 @@ impl Overlays {
|
||||
*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)) => {
|
||||
return Some(t);
|
||||
}
|
||||
Some(Outcome::Clicked(_)) => unreachable!(),
|
||||
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
||||
"X" => {
|
||||
*self = Overlays::Inactive;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => {}
|
||||
},
|
||||
Overlays::IntersectionDemand(_, i, _, ref mut c) => match c.event(ctx) {
|
||||
@ -145,7 +154,7 @@ impl Overlays {
|
||||
| Overlays::BusDelaysOverTime(ref composite) => {
|
||||
composite.draw(g);
|
||||
}
|
||||
Overlays::BusPassengers(ref composite) => {
|
||||
Overlays::BusPassengers(_, _, ref composite) => {
|
||||
composite.draw(g);
|
||||
}
|
||||
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 {
|
||||
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