mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-20 21:01:33 +03:00
use info panel for finished trips
This commit is contained in:
parent
b6d7acd385
commit
d5653e42ab
@ -98,14 +98,16 @@ impl InfoPanel {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let trip_details =
|
let trip_details = if let Some(trip) = match id {
|
||||||
if let Some(trip) = id.agent_id().and_then(|a| ui.primary.sim.agent_to_trip(a)) {
|
ID::Trip(t) => Some(t),
|
||||||
let (rows, unzoomed, zoomed) = trip_details(trip, ctx, ui);
|
_ => id.agent_id().and_then(|a| ui.primary.sim.agent_to_trip(a)),
|
||||||
col.push(rows);
|
} {
|
||||||
Some((unzoomed, zoomed))
|
let (rows, unzoomed, zoomed) = trip_details(trip, ctx, ui);
|
||||||
} else {
|
col.push(rows);
|
||||||
None
|
Some((unzoomed, zoomed))
|
||||||
};
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Follow the agent. When the sim is paused, this lets the player naturally pan away,
|
// Follow the agent. When the sim is paused, this lets the player naturally pan away,
|
||||||
// because the InfoPanel isn't being updated.
|
// because the InfoPanel isn't being updated.
|
||||||
@ -374,6 +376,8 @@ fn info_for(id: ID, ui: &UI) -> Text {
|
|||||||
let a = map.get_a(id);
|
let a = map.get_a(id);
|
||||||
styled_kv(&mut txt, &a.osm_tags);
|
styled_kv(&mut txt, &a.osm_tags);
|
||||||
}
|
}
|
||||||
|
// No info here, trip_details will be used
|
||||||
|
ID::Trip(_) => {}
|
||||||
};
|
};
|
||||||
txt
|
txt
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,12 @@ mod minimap;
|
|||||||
mod navigate;
|
mod navigate;
|
||||||
mod panels;
|
mod panels;
|
||||||
mod shortcuts;
|
mod shortcuts;
|
||||||
mod trip_explorer;
|
|
||||||
mod turn_cycler;
|
mod turn_cycler;
|
||||||
mod warp;
|
mod warp;
|
||||||
|
|
||||||
pub use self::colors::{ColorLegend, Colorer, ColorerBuilder};
|
pub use self::colors::{ColorLegend, Colorer, ColorerBuilder};
|
||||||
pub use self::minimap::Minimap;
|
pub use self::minimap::Minimap;
|
||||||
pub use self::panels::{edit_map_panel, tool_panel};
|
pub use self::panels::{edit_map_panel, tool_panel};
|
||||||
pub use self::trip_explorer::TripExplorer;
|
|
||||||
pub use self::warp::Warping;
|
pub use self::warp::Warping;
|
||||||
use crate::game::Transition;
|
use crate::game::Transition;
|
||||||
use crate::helpers::{list_names, ID};
|
use crate::helpers::{list_names, ID};
|
||||||
@ -182,6 +180,9 @@ impl CommonState {
|
|||||||
.collect();
|
.collect();
|
||||||
list_names(&mut osd, |l| l.fg(name_color), routes);
|
list_names(&mut osd, |l| l.fg(name_color), routes);
|
||||||
}
|
}
|
||||||
|
ID::Trip(t) => {
|
||||||
|
osd.append(Line(t.to_string()).fg(id_color));
|
||||||
|
}
|
||||||
ID::ExtraShape(es) => {
|
ID::ExtraShape(es) => {
|
||||||
// Only selectable in dev mode anyway
|
// Only selectable in dev mode anyway
|
||||||
osd.append(Line(es.to_string()).fg(id_color));
|
osd.append(Line(es.to_string()).fg(id_color));
|
||||||
@ -238,4 +239,10 @@ impl CommonState {
|
|||||||
.suppress_traffic_signal_details(&ui.primary.map);
|
.suppress_traffic_signal_details(&ui.primary.map);
|
||||||
opts
|
opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meant to be used for launching from other states
|
||||||
|
pub fn launch_info_panel(&mut self, id: ID, ctx: &mut EventCtx, ui: &mut UI) {
|
||||||
|
self.info_panel = Some(info::InfoPanel::new(id, ctx, ui, Vec::new()));
|
||||||
|
ui.per_obj.info_panel_open = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
use crate::common::ColorLegend;
|
|
||||||
use crate::game::{State, Transition};
|
|
||||||
use crate::helpers::rotating_color_map;
|
|
||||||
use crate::render::MIN_ZOOM_FOR_DETAIL;
|
|
||||||
use crate::ui::UI;
|
|
||||||
use ezgui::{hotkey, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, ModalMenu, Text};
|
|
||||||
use geom::{Circle, Distance};
|
|
||||||
use sim::{TripEnd, TripID, TripStart};
|
|
||||||
|
|
||||||
pub struct TripExplorer {
|
|
||||||
menu: ModalMenu,
|
|
||||||
unzoomed: Drawable,
|
|
||||||
zoomed: Drawable,
|
|
||||||
legend: ColorLegend,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TripExplorer {
|
|
||||||
pub fn new(trip: TripID, ctx: &mut EventCtx, ui: &UI) -> TripExplorer {
|
|
||||||
let map = &ui.primary.map;
|
|
||||||
let phases = ui.primary.sim.get_analytics().get_trip_phases(trip, map);
|
|
||||||
// TODO Hack because ColorLegend only takes &str
|
|
||||||
let mut rows = Vec::new();
|
|
||||||
for (idx, p) in phases.iter().enumerate() {
|
|
||||||
rows.push((
|
|
||||||
p.describe(ui.primary.sim.time()),
|
|
||||||
rotating_color_map(idx + 1),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let mut unzoomed = GeomBatch::new();
|
|
||||||
let mut zoomed = GeomBatch::new();
|
|
||||||
for (p, (_, color)) in phases.iter().zip(rows.iter()) {
|
|
||||||
if let Some((dist, ref path)) = p.path {
|
|
||||||
if let Some(t) = path.trace(map, dist, None) {
|
|
||||||
unzoomed.push(*color, t.make_polygons(Distance::meters(10.0)));
|
|
||||||
zoomed.push(*color, t.make_polygons(Distance::meters(1.0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle endpoints
|
|
||||||
let (trip_start, trip_end) = ui.primary.sim.trip_endpoints(trip);
|
|
||||||
let start_color = rotating_color_map(0);
|
|
||||||
match trip_start {
|
|
||||||
TripStart::Bldg(b) => {
|
|
||||||
let bldg = map.get_b(b);
|
|
||||||
rows.insert(0, (format!("start at {}", bldg.get_name(map)), start_color));
|
|
||||||
unzoomed.push(start_color, bldg.polygon.clone());
|
|
||||||
zoomed.push(start_color, bldg.polygon.clone());
|
|
||||||
}
|
|
||||||
TripStart::Border(i) => {
|
|
||||||
let i = map.get_i(i);
|
|
||||||
rows.insert(0, (format!("enter map via {}", i.id), start_color));
|
|
||||||
unzoomed.push(start_color, i.polygon.clone());
|
|
||||||
zoomed.push(start_color, i.polygon.clone());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Is the trip ongoing?
|
|
||||||
if let Some(pt) = ui.primary.sim.get_canonical_pt_per_trip(trip, map).ok() {
|
|
||||||
let color = rotating_color_map(rows.len());
|
|
||||||
unzoomed.push(color, Circle::new(pt, Distance::meters(10.0)).to_polygon());
|
|
||||||
zoomed.push(
|
|
||||||
color.alpha(0.7),
|
|
||||||
Circle::new(pt, Distance::meters(5.0)).to_polygon(),
|
|
||||||
);
|
|
||||||
rows.push((format!("currently here"), color));
|
|
||||||
}
|
|
||||||
|
|
||||||
let end_color = rotating_color_map(rows.len());
|
|
||||||
match trip_end {
|
|
||||||
TripEnd::Bldg(b) => {
|
|
||||||
let bldg = map.get_b(b);
|
|
||||||
rows.push((format!("end at {}", bldg.get_name(map)), end_color));
|
|
||||||
unzoomed.push(end_color, bldg.polygon.clone());
|
|
||||||
zoomed.push(end_color, bldg.polygon.clone());
|
|
||||||
}
|
|
||||||
TripEnd::Border(i) => {
|
|
||||||
let i = map.get_i(i);
|
|
||||||
rows.push((format!("leave map via {}", i.id), end_color));
|
|
||||||
unzoomed.push(end_color, i.polygon.clone());
|
|
||||||
zoomed.push(end_color, i.polygon.clone());
|
|
||||||
}
|
|
||||||
// TODO TripExplorer is pretty useless for buses; maybe ShowBusRoute or something
|
|
||||||
// instead
|
|
||||||
TripEnd::ServeBusRoute(br) => {
|
|
||||||
rows.push((
|
|
||||||
format!("serve route {} forever", map.get_br(br).name),
|
|
||||||
end_color,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let legend = ColorLegend::new(
|
|
||||||
ctx,
|
|
||||||
Text::from(Line(&trip.to_string())),
|
|
||||||
rows.iter()
|
|
||||||
.map(|(label, color)| (label.as_str(), *color))
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
TripExplorer {
|
|
||||||
menu: ModalMenu::new(trip.to_string(), vec![(hotkey(Key::Escape), "quit")], ctx),
|
|
||||||
legend,
|
|
||||||
unzoomed: unzoomed.upload(ctx),
|
|
||||||
zoomed: zoomed.upload(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State for TripExplorer {
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
|
|
||||||
if ctx.redo_mouseover() {
|
|
||||||
ui.recalculate_current_selection(ctx);
|
|
||||||
}
|
|
||||||
ctx.canvas_movement();
|
|
||||||
|
|
||||||
self.menu.event(ctx);
|
|
||||||
if self.menu.action("quit") {
|
|
||||||
return Transition::Pop;
|
|
||||||
}
|
|
||||||
|
|
||||||
Transition::Keep
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&self, g: &mut GfxCtx, _: &UI) {
|
|
||||||
if g.canvas.cam_zoom < MIN_ZOOM_FOR_DETAIL {
|
|
||||||
g.redraw(&self.unzoomed);
|
|
||||||
} else {
|
|
||||||
g.redraw(&self.zoomed);
|
|
||||||
}
|
|
||||||
self.legend.draw(g);
|
|
||||||
self.menu.draw(g);
|
|
||||||
}
|
|
||||||
}
|
|
@ -55,9 +55,6 @@ impl ObjectDebugger {
|
|||||||
|
|
||||||
fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
|
fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
|
||||||
match id {
|
match id {
|
||||||
ID::Road(id) => {
|
|
||||||
println!("{}", abstutil::to_json(map.get_r(id)));
|
|
||||||
}
|
|
||||||
ID::Lane(id) => {
|
ID::Lane(id) => {
|
||||||
let l = map.get_l(id);
|
let l = map.get_l(id);
|
||||||
println!("{}", abstutil::to_json(l));
|
println!("{}", abstutil::to_json(l));
|
||||||
@ -155,5 +152,6 @@ fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
|
|||||||
ID::Area(id) => {
|
ID::Area(id) => {
|
||||||
println!("{}", abstutil::to_json(map.get_a(id)));
|
println!("{}", abstutil::to_json(map.get_a(id)));
|
||||||
}
|
}
|
||||||
|
ID::Road(_) | ID::Trip(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ use ezgui::{Color, Line, Text, TextSpan};
|
|||||||
use geom::Pt2D;
|
use geom::Pt2D;
|
||||||
use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, RoadID, TurnID};
|
use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, RoadID, TurnID};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use sim::{AgentID, CarID, PedestrianID};
|
use sim::{AgentID, CarID, PedestrianID, TripID};
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
// Aside from Road, everything here can actually be selected.
|
// Aside from Road and Trip, everything here can actually be selected.
|
||||||
#[derive(Clone, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
|
#[derive(Clone, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
|
||||||
pub enum ID {
|
pub enum ID {
|
||||||
Road(RoadID),
|
Road(RoadID),
|
||||||
@ -23,6 +23,7 @@ pub enum ID {
|
|||||||
ExtraShape(ExtraShapeID),
|
ExtraShape(ExtraShapeID),
|
||||||
BusStop(BusStopID),
|
BusStop(BusStopID),
|
||||||
Area(AreaID),
|
Area(AreaID),
|
||||||
|
Trip(TripID),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl abstutil::Cloneable for ID {}
|
impl abstutil::Cloneable for ID {}
|
||||||
@ -70,6 +71,7 @@ impl ID {
|
|||||||
.maybe_get_bs(id)
|
.maybe_get_bs(id)
|
||||||
.map(|bs| bs.sidewalk_pos.pt(&primary.map)),
|
.map(|bs| bs.sidewalk_pos.pt(&primary.map)),
|
||||||
ID::Area(id) => primary.map.maybe_get_a(id).map(|a| a.polygon.center()),
|
ID::Area(id) => primary.map.maybe_get_a(id).map(|a| a.polygon.center()),
|
||||||
|
ID::Trip(id) => primary.sim.get_canonical_pt_per_trip(id, &primary.map).ok(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::common::TripExplorer;
|
|
||||||
use crate::game::{State, Transition};
|
use crate::game::{State, Transition};
|
||||||
|
use crate::helpers::ID;
|
||||||
use crate::managed::{Callback, Composite, ManagedGUIState};
|
use crate::managed::{Callback, Composite, ManagedGUIState};
|
||||||
use crate::sandbox::bus_explorer;
|
|
||||||
use crate::sandbox::gameplay::{cmp_count_fewer, cmp_count_more, cmp_duration_shorter};
|
use crate::sandbox::gameplay::{cmp_count_fewer, cmp_count_more, cmp_duration_shorter};
|
||||||
|
use crate::sandbox::{bus_explorer, SandboxMode};
|
||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use abstutil::prettyprint_usize;
|
use abstutil::prettyprint_usize;
|
||||||
use abstutil::Counter;
|
use abstutil::Counter;
|
||||||
@ -262,8 +262,14 @@ fn pick_finished_trips(
|
|||||||
let trip = *id;
|
let trip = *id;
|
||||||
cbs.push((
|
cbs.push((
|
||||||
label,
|
label,
|
||||||
Box::new(move |ctx, ui| {
|
Box::new(move |_, _| {
|
||||||
Some(Transition::Push(Box::new(TripExplorer::new(trip, ctx, ui))))
|
Some(Transition::PopWithData(Box::new(move |state, ui, ctx| {
|
||||||
|
state
|
||||||
|
.downcast_mut::<SandboxMode>()
|
||||||
|
.unwrap()
|
||||||
|
.common
|
||||||
|
.launch_info_panel(ID::Trip(trip), ctx, ui);
|
||||||
|
})))
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ pub struct SandboxMode {
|
|||||||
agent_meter: AgentMeter,
|
agent_meter: AgentMeter,
|
||||||
overlay: Overlays,
|
overlay: Overlays,
|
||||||
gameplay: gameplay::GameplayRunner,
|
gameplay: gameplay::GameplayRunner,
|
||||||
common: CommonState,
|
pub common: CommonState,
|
||||||
tool_panel: crate::managed::Composite,
|
tool_panel: crate::managed::Composite,
|
||||||
minimap: Option<Minimap>,
|
minimap: Option<Minimap>,
|
||||||
}
|
}
|
||||||
|
@ -323,9 +323,12 @@ impl UI {
|
|||||||
ID::Building(id) => buildings.push(draw_map.get_b(id)),
|
ID::Building(id) => buildings.push(draw_map.get_b(id)),
|
||||||
ID::ExtraShape(id) => extra_shapes.push(draw_map.get_es(id)),
|
ID::ExtraShape(id) => extra_shapes.push(draw_map.get_es(id)),
|
||||||
|
|
||||||
ID::BusStop(_) | ID::Turn(_) | ID::Car(_) | ID::Pedestrian(_) | ID::PedCrowd(_) => {
|
ID::BusStop(_)
|
||||||
panic!("{:?} shouldn't be in the quadtree", id)
|
| ID::Turn(_)
|
||||||
}
|
| ID::Car(_)
|
||||||
|
| ID::Pedestrian(_)
|
||||||
|
| ID::PedCrowd(_)
|
||||||
|
| ID::Trip(_) => panic!("{:?} shouldn't be in the quadtree", id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user