From 8ed2d596ff2788dff5269be3045135b23b1e70fa Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Tue, 31 Mar 2020 14:21:03 -0700 Subject: [PATCH] basic accordians for trips --- game/src/info/building.rs | 3 +- game/src/info/mod.rs | 14 ++++--- game/src/info/person.rs | 81 ++++++++++++++++++++++++++++++--------- game/src/info/trip.rs | 28 ++++++++++++-- 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/game/src/info/building.rs b/game/src/info/building.rs index 28cfae5ec0..8e8dee61a4 100644 --- a/game/src/info/building.rs +++ b/game/src/info/building.rs @@ -6,6 +6,7 @@ use ezgui::{Btn, Color, EventCtx, Line, Text, TextExt, Widget}; use geom::{Angle, Circle, Time}; use map_model::{BuildingID, LaneID, Traversable, SIDEWALK_THICKNESS}; use sim::{DrawPedestrianInput, PedestrianID, PersonID, TripMode, TripResult}; +use std::collections::BTreeSet; pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID) -> Vec { let mut rows = header(ctx, app, details, id, Tab::BldgInfo(id)); @@ -104,7 +105,7 @@ pub fn people(ctx: &mut EventCtx, app: &App, details: &mut Details, id: Building let label = format!("Person #{}", p.0); details .hyperlinks - .insert(label.clone(), Tab::PersonTrips(p)); + .insert(label.clone(), Tab::PersonTrips(p, BTreeSet::new())); rows.push(Widget::col(vec![ Btn::text_bg1(label).build_def(ctx, None), if let Some((t, mode)) = next_trip { diff --git a/game/src/info/mod.rs b/game/src/info/mod.rs index bbcfd76e52..3c45a253b0 100644 --- a/game/src/info/mod.rs +++ b/game/src/info/mod.rs @@ -19,8 +19,10 @@ use ezgui::{ }; use geom::{Circle, Distance, Duration, Time}; use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID}; -use sim::{AgentID, Analytics, CarID, PedestrianID, PersonID, PersonState, TripMode, VehicleType}; -use std::collections::{BTreeMap, HashMap}; +use sim::{ + AgentID, Analytics, CarID, PedestrianID, PersonID, PersonState, TripID, TripMode, VehicleType, +}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; pub struct InfoPanel { tab: Tab, @@ -40,7 +42,7 @@ pub struct InfoPanel { #[derive(Clone, PartialEq)] pub enum Tab { PersonStatus(PersonID), - PersonTrips(PersonID), + PersonTrips(PersonID, BTreeSet), PersonBio(PersonID), BusStatus(CarID), @@ -100,7 +102,7 @@ impl Tab { // TODO Temporary hack until object actions go away. fn to_id(self, app: &App) -> Option { match self { - Tab::PersonStatus(p) | Tab::PersonTrips(p) | Tab::PersonBio(p) => { + Tab::PersonStatus(p) | Tab::PersonTrips(p, _) | Tab::PersonBio(p) => { match app.primary.sim.get_person(p).state { PersonState::Inside(b) => Some(ID::Building(b)), PersonState::Trip(t) => app @@ -177,7 +179,9 @@ impl InfoPanel { let (mut col, main_tab) = match tab { Tab::PersonStatus(p) => (person::status(ctx, app, &mut details, p), true), - Tab::PersonTrips(p) => (person::trips(ctx, app, &mut details, p), false), + Tab::PersonTrips(p, ref open) => { + (person::trips(ctx, app, &mut details, p, open), false) + } Tab::PersonBio(p) => (person::bio(ctx, app, &mut details, p), false), Tab::BusStatus(c) => (bus::bus_status(ctx, app, &mut details, c), true), Tab::BusDelays(c) => (bus::bus_delays(ctx, app, &mut details, c), true), diff --git a/game/src/info/person.rs b/game/src/info/person.rs index e057ef5f16..52cfc4bc54 100644 --- a/game/src/info/person.rs +++ b/game/src/info/person.rs @@ -3,7 +3,10 @@ use crate::info::{building, header_btns, make_table, make_tabs, trip, Details, T use crate::render::Renderable; use ezgui::{Btn, Color, EventCtx, Line, TextExt, Widget}; use map_model::Map; -use sim::{AgentID, CarID, PedestrianID, Person, PersonID, PersonState, TripResult, VehicleType}; +use sim::{ + AgentID, CarID, PedestrianID, Person, PersonID, PersonState, TripID, TripResult, VehicleType, +}; +use std::collections::BTreeSet; pub fn status(ctx: &mut EventCtx, app: &App, details: &mut Details, id: PersonID) -> Vec { let mut rows = header(ctx, app, details, id, Tab::PersonStatus(id)); @@ -43,15 +46,29 @@ pub fn status(ctx: &mut EventCtx, app: &App, details: &mut Details, id: PersonID } } - rows.push(trip::details(ctx, app, t, details)); + let mut open_trips = BTreeSet::new(); + open_trips.insert(t); + rows.push(trip::details(ctx, app, t, details, id, open_trips)); } } rows } -pub fn trips(ctx: &mut EventCtx, app: &App, details: &mut Details, id: PersonID) -> Vec { - let mut rows = header(ctx, app, details, id, Tab::PersonTrips(id)); +pub fn trips( + ctx: &mut EventCtx, + app: &App, + details: &mut Details, + id: PersonID, + open_trips: &BTreeSet, +) -> Vec { + let mut rows = header( + ctx, + app, + details, + id, + Tab::PersonTrips(id, open_trips.clone()), + ); let map = &app.primary.map; let sim = &app.primary.sim; @@ -79,7 +96,26 @@ pub fn trips(ctx: &mut EventCtx, app: &App, details: &mut Details, id: PersonID) } TripResult::TripDoesntExist => unreachable!(), } - rows.push(trip::details(ctx, app, *t, details)); + if open_trips.contains(t) { + rows.push(trip::details(ctx, app, *t, details, id, open_trips.clone())); + } else { + // TODO Style wrong. Button should be the entire row. + rows.push( + Widget::row(vec![ + format!("Trip #{}", t.0).draw_text(ctx), + Btn::text_fg("▼") + .build(ctx, format!("show Trip #{}", t.0), None) + .align_right(), + ]) + .outline(2.0, Color::WHITE), + ); + let mut new_trips = open_trips.clone(); + new_trips.insert(*t); + details.hyperlinks.insert( + format!("show Trip #{}", t.0), + Tab::PersonTrips(id, new_trips), + ); + } } if wheres_waldo { rows.push(current_status(ctx, person, map)); @@ -182,23 +218,26 @@ pub fn parked_car(ctx: &EventCtx, app: &App, details: &mut Details, id: CarID) - fn header(ctx: &EventCtx, app: &App, details: &mut Details, id: PersonID, tab: Tab) -> Vec { let mut rows = vec![]; - let descr = match app.primary.sim.get_person(id).state { + let (current_trip, descr) = match app.primary.sim.get_person(id).state { PersonState::Inside(b) => { building::draw_occupants(details, app, b, Some(id)); - "inside" + (None, "inside") } - PersonState::Trip(t) => match app.primary.sim.trip_to_agent(t).ok() { - Some(AgentID::Pedestrian(_)) => "on foot", - Some(AgentID::Car(c)) => match c.1 { - VehicleType::Car => "in a car", - VehicleType::Bike => "on a bike", - VehicleType::Bus => unreachable!(), + PersonState::Trip(t) => ( + Some(t), + match app.primary.sim.trip_to_agent(t).ok() { + Some(AgentID::Pedestrian(_)) => "on foot", + Some(AgentID::Car(c)) => match c.1 { + VehicleType::Car => "in a car", + VehicleType::Bike => "on a bike", + VehicleType::Bus => unreachable!(), + }, + // TODO Really should clean up the TripModeChange issue + None => "...", }, - // TODO Really should clean up the TripModeChange issue - None => "...", - }, - PersonState::OffMap => "off map", - PersonState::Limbo => "in limbo", + ), + PersonState::OffMap => (None, "off map"), + PersonState::Limbo => (None, "in limbo"), }; rows.push(Widget::row(vec![ @@ -208,13 +247,17 @@ fn header(ctx: &EventCtx, app: &App, details: &mut Details, id: PersonID, tab: T header_btns(ctx), ])); + let mut open_trips = BTreeSet::new(); + if let Some(t) = current_trip { + open_trips.insert(t); + } rows.push(make_tabs( ctx, &mut details.hyperlinks, tab, vec![ ("Status", Tab::PersonStatus(id)), - ("Trips", Tab::PersonTrips(id)), + ("Trips", Tab::PersonTrips(id, open_trips)), ("Bio", Tab::PersonBio(id)), ], )); diff --git a/game/src/info/trip.rs b/game/src/info/trip.rs index 2a2dae3dfb..2b1ea6f47b 100644 --- a/game/src/info/trip.rs +++ b/game/src/info/trip.rs @@ -1,16 +1,24 @@ use crate::app::App; use crate::colors; use crate::helpers::ID; -use crate::info::{make_table, Details}; +use crate::info::{make_table, Details, Tab}; use crate::render::dashed_lines; use ezgui::{ Btn, Color, EventCtx, GeomBatch, Line, Plot, PlotOptions, RewriteColor, Series, Text, Widget, }; use geom::{Angle, Distance, Duration, Polygon, Pt2D, Time}; use map_model::{Map, Path, PathStep}; -use sim::{TripEndpoint, TripID, TripPhaseType, TripResult}; +use sim::{PersonID, TripEndpoint, TripID, TripPhaseType, TripResult}; +use std::collections::BTreeSet; -pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Details) -> Widget { +pub fn details( + ctx: &mut EventCtx, + app: &App, + trip: TripID, + details: &mut Details, + person: PersonID, + mut open_trips: BTreeSet, +) -> Widget { let map = &app.primary.map; let sim = &app.primary.sim; let phases = sim.get_analytics().get_trip_phases(trip, map); @@ -24,7 +32,19 @@ pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Detail TripResult::TripDone => ("finished", None), TripResult::TripDoesntExist => unreachable!(), }; - let mut col = vec![Line(format!("Trip #{} ({})", trip.0, trip_status)).draw(ctx)]; + let mut col = vec![Widget::row(vec![ + Line(format!("Trip #{} ({})", trip.0, trip_status)).draw(ctx), + Btn::text_fg("▲") + .build(ctx, format!("hide Trip #{}", trip.0), None) + .align_right(), + ]) + .outline(2.0, Color::WHITE)]; + + open_trips.remove(&trip); + details.hyperlinks.insert( + format!("hide Trip #{}", trip.0), + Tab::PersonTrips(person, open_trips), + ); let mut kv = vec![ ("Departure", start_time.ampm_tostring()),