mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 08:24:15 +03:00
continuing with some of the harder info tabs. got everything moved over!
This commit is contained in:
parent
fff8c8ae9d
commit
49870c0f9f
@ -1,270 +0,0 @@
|
||||
use crate::app::App;
|
||||
use crate::colors;
|
||||
use crate::helpers::ID;
|
||||
use crate::info::trip::trip_details;
|
||||
use crate::info::{make_browser, make_table, make_tabs, person, InfoTab, TripDetails};
|
||||
use crate::render::Renderable;
|
||||
use ezgui::{Color, EventCtx, GeomBatch, Line, Text, Widget};
|
||||
use sim::{AgentID, CarID, PedestrianID, PersonID, VehicleType};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Tab {
|
||||
Person(PersonID),
|
||||
// The crowd could change as we go; just freeze the list.
|
||||
Crowd(Vec<PedestrianID>, usize),
|
||||
}
|
||||
impl std::cmp::PartialEq for Tab {
|
||||
fn eq(&self, other: &Tab) -> bool {
|
||||
match (self, other) {
|
||||
// Only one possibility per ID
|
||||
(Tab::Person(_), Tab::Person(_)) => true,
|
||||
(Tab::Crowd(_, _), Tab::Crowd(_, _)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn car_info(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
id: CarID,
|
||||
tab: InfoTab,
|
||||
header_btns: Widget,
|
||||
action_btns: Vec<Widget>,
|
||||
batch: &mut GeomBatch,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
warpers: &mut HashMap<String, ID>,
|
||||
) -> (Vec<Widget>, Option<TripDetails>) {
|
||||
let mut rows = vec![];
|
||||
|
||||
let label = match id.1 {
|
||||
VehicleType::Car => "Car",
|
||||
VehicleType::Bike => "Bike",
|
||||
VehicleType::Bus => "Bus",
|
||||
};
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("{} #{}", label, id.0))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns,
|
||||
]));
|
||||
|
||||
rows.push(make_tabs(ctx, hyperlinks, ID::Car(id), tab.clone(), {
|
||||
let mut tabs = vec![("Info", InfoTab::Nil)];
|
||||
if let Some(p) = app
|
||||
.primary
|
||||
.sim
|
||||
.agent_to_trip(AgentID::Car(id))
|
||||
.map(|t| app.primary.sim.trip_to_person(t))
|
||||
{
|
||||
tabs.push(("Trips", InfoTab::Agent(Tab::Person(p))));
|
||||
}
|
||||
tabs
|
||||
}));
|
||||
|
||||
let mut details: Option<TripDetails> = None;
|
||||
|
||||
match tab {
|
||||
InfoTab::Nil => {
|
||||
rows.extend(action_btns);
|
||||
|
||||
let (kv, extra) = app.primary.sim.car_properties(id, &app.primary.map);
|
||||
rows.extend(make_table(ctx, kv));
|
||||
if !extra.is_empty() {
|
||||
let mut txt = Text::from(Line(""));
|
||||
for line in extra {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
rows.push(txt.draw(ctx));
|
||||
}
|
||||
|
||||
let trip = if id.1 == VehicleType::Bus {
|
||||
None
|
||||
} else {
|
||||
app.primary.sim.agent_to_trip(AgentID::Car(id))
|
||||
};
|
||||
details = trip.map(|t| {
|
||||
let (more, details) = trip_details(
|
||||
ctx,
|
||||
app,
|
||||
t,
|
||||
app.primary.sim.progress_along_path(AgentID::Car(id)),
|
||||
warpers,
|
||||
);
|
||||
rows.push(more);
|
||||
details
|
||||
});
|
||||
}
|
||||
InfoTab::Agent(Tab::Person(p)) => {
|
||||
// TODO Reorganize this
|
||||
rows.extend(person::info(
|
||||
ctx,
|
||||
app,
|
||||
p,
|
||||
InfoTab::Nil,
|
||||
None,
|
||||
Vec::new(),
|
||||
hyperlinks,
|
||||
warpers,
|
||||
));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
if let Some(b) = app.primary.sim.get_owner_of_car(id) {
|
||||
// TODO Mention this, with a warp tool
|
||||
batch.push(
|
||||
app.cs
|
||||
.get_def("something associated with something else", Color::PURPLE),
|
||||
app.primary.draw_map.get_b(b).get_outline(&app.primary.map),
|
||||
);
|
||||
}
|
||||
|
||||
(rows, details)
|
||||
}
|
||||
|
||||
pub fn ped_info(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
id: PedestrianID,
|
||||
tab: InfoTab,
|
||||
header_btns: Widget,
|
||||
action_btns: Vec<Widget>,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
warpers: &mut HashMap<String, ID>,
|
||||
) -> (Vec<Widget>, Option<TripDetails>) {
|
||||
let mut rows = vec![];
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Pedestrian #{}", id.0))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns,
|
||||
]));
|
||||
|
||||
let trip = app
|
||||
.primary
|
||||
.sim
|
||||
.agent_to_trip(AgentID::Pedestrian(id))
|
||||
.unwrap();
|
||||
|
||||
rows.push(make_tabs(
|
||||
ctx,
|
||||
hyperlinks,
|
||||
ID::Pedestrian(id),
|
||||
tab.clone(),
|
||||
vec![
|
||||
("Info", InfoTab::Nil),
|
||||
(
|
||||
"Trips",
|
||||
InfoTab::Agent(Tab::Person(app.primary.sim.trip_to_person(trip))),
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
let mut details: Option<TripDetails> = None;
|
||||
|
||||
match tab {
|
||||
InfoTab::Nil => {
|
||||
rows.extend(action_btns);
|
||||
|
||||
let (kv, extra) = app.primary.sim.ped_properties(id, &app.primary.map);
|
||||
rows.extend(make_table(ctx, kv));
|
||||
if !extra.is_empty() {
|
||||
let mut txt = Text::from(Line(""));
|
||||
for line in extra {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
rows.push(txt.draw(ctx));
|
||||
}
|
||||
|
||||
let (more, trip_details) = trip_details(
|
||||
ctx,
|
||||
app,
|
||||
app.primary
|
||||
.sim
|
||||
.agent_to_trip(AgentID::Pedestrian(id))
|
||||
.unwrap(),
|
||||
app.primary.sim.progress_along_path(AgentID::Pedestrian(id)),
|
||||
warpers,
|
||||
);
|
||||
rows.push(more);
|
||||
details = Some(trip_details);
|
||||
}
|
||||
InfoTab::Agent(Tab::Person(p)) => {
|
||||
// TODO Reorganize this
|
||||
rows.extend(person::info(
|
||||
ctx,
|
||||
app,
|
||||
p,
|
||||
InfoTab::Nil,
|
||||
None,
|
||||
Vec::new(),
|
||||
hyperlinks,
|
||||
warpers,
|
||||
));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
(rows, details)
|
||||
}
|
||||
|
||||
pub fn crowd_info(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
members: Vec<PedestrianID>,
|
||||
mut tab: InfoTab,
|
||||
header_btns: Widget,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
warpers: &mut HashMap<String, ID>,
|
||||
) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line("Pedestrian crowd").small_heading().draw(ctx),
|
||||
header_btns,
|
||||
]));
|
||||
|
||||
if tab == InfoTab::Nil {
|
||||
tab = InfoTab::Agent(Tab::Crowd(members, 0));
|
||||
}
|
||||
|
||||
match tab {
|
||||
InfoTab::Agent(Tab::Crowd(peds, idx)) => {
|
||||
let mut inner = vec![make_browser(
|
||||
ctx,
|
||||
hyperlinks,
|
||||
"Pedestrian",
|
||||
peds.len(),
|
||||
idx,
|
||||
|n| {
|
||||
(
|
||||
ID::PedCrowd(peds.clone()),
|
||||
InfoTab::Agent(Tab::Crowd(peds.clone(), n)),
|
||||
)
|
||||
},
|
||||
)];
|
||||
// If we click a tab for a pedestrian, we lose the crowd. Woops?
|
||||
inner.extend(
|
||||
ped_info(
|
||||
ctx,
|
||||
app,
|
||||
peds[idx],
|
||||
InfoTab::Nil,
|
||||
// No header buttons
|
||||
Widget::nothing(),
|
||||
Vec::new(),
|
||||
hyperlinks,
|
||||
warpers,
|
||||
)
|
||||
.0,
|
||||
);
|
||||
rows.push(Widget::col(inner).bg(colors::INNER_PANEL_BG));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
@ -1,143 +1,182 @@
|
||||
use crate::app::App;
|
||||
use crate::helpers::ID;
|
||||
use crate::info::{make_table, make_tabs, person, InfoTab};
|
||||
use ezgui::{EventCtx, GeomBatch, Line, Text, TextExt, Widget};
|
||||
use crate::info::{header_btns, make_table, make_tabs, Details, Tab};
|
||||
use ezgui::{Btn, EventCtx, Line, Text, TextExt, Widget};
|
||||
use geom::Time;
|
||||
use map_model::BuildingID;
|
||||
use sim::TripEndpoint;
|
||||
use std::collections::HashMap;
|
||||
use sim::{TripEndpoint, TripMode, TripResult};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Tab {
|
||||
// If we're live updating, the people inside could change! Re-calculate constantly.
|
||||
People,
|
||||
Debug,
|
||||
pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, app, details, id, Tab::BldgInfo(id));
|
||||
let b = app.primary.map.get_b(id);
|
||||
|
||||
let mut kv = Vec::new();
|
||||
|
||||
kv.push(("Address", b.just_address(&app.primary.map)));
|
||||
if let Some(name) = b.just_name() {
|
||||
kv.push(("Name", name.to_string()));
|
||||
}
|
||||
|
||||
if let Some(ref p) = b.parking {
|
||||
kv.push(("Parking", format!("{} spots via {}", p.num_stalls, p.name)));
|
||||
} else {
|
||||
kv.push(("Parking", "None".to_string()));
|
||||
}
|
||||
|
||||
rows.extend(make_table(ctx, kv));
|
||||
|
||||
let mut txt = Text::new();
|
||||
|
||||
if !b.amenities.is_empty() {
|
||||
txt.add(Line(""));
|
||||
if b.amenities.len() > 1 {
|
||||
txt.add(Line(format!("{} amenities:", b.amenities.len())));
|
||||
}
|
||||
for (name, amenity) in &b.amenities {
|
||||
txt.add(Line(format!("- {} (a {})", name, amenity)));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Rethink this
|
||||
let trip_lines = app
|
||||
.primary
|
||||
.sim
|
||||
.count_trips(TripEndpoint::Bldg(id))
|
||||
.describe();
|
||||
if !trip_lines.is_empty() {
|
||||
txt.add(Line(""));
|
||||
for line in trip_lines {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
}
|
||||
|
||||
let cars = app.primary.sim.get_parked_cars_by_owner(id);
|
||||
if !cars.is_empty() {
|
||||
txt.add(Line(""));
|
||||
txt.add(Line(format!(
|
||||
"{} parked cars owned by this building",
|
||||
cars.len()
|
||||
)));
|
||||
// TODO Jump to it or see status
|
||||
for p in cars {
|
||||
txt.add(Line(format!("- {}", p.vehicle.id)));
|
||||
}
|
||||
}
|
||||
|
||||
if !txt.is_empty() {
|
||||
rows.push(txt.draw(ctx))
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
pub fn info(
|
||||
ctx: &mut EventCtx,
|
||||
pub fn debug(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, app, details, id, Tab::BldgDebug(id));
|
||||
let b = app.primary.map.get_b(id);
|
||||
|
||||
rows.extend(make_table(
|
||||
ctx,
|
||||
vec![(
|
||||
"Dist along sidewalk",
|
||||
b.front_path.sidewalk.dist_along().to_string(),
|
||||
)],
|
||||
));
|
||||
rows.push("Raw OpenStreetMap data".draw_text(ctx));
|
||||
rows.extend(make_table(ctx, b.osm_tags.clone().into_iter().collect()));
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
pub fn people(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, app, details, id, Tab::BldgPeople(id));
|
||||
// TODO Sort/group better
|
||||
// Show minimal info: ID, next departure time, type of that trip
|
||||
for p in app.primary.sim.bldg_to_people(id) {
|
||||
let person = app.primary.sim.get_person(p);
|
||||
|
||||
let mut next_trip: Option<(Time, TripMode)> = None;
|
||||
for t in &person.trips {
|
||||
match app.primary.sim.trip_to_agent(*t) {
|
||||
TripResult::TripNotStarted => {
|
||||
let (start_time, _, _, mode) = app.primary.sim.trip_info(*t);
|
||||
next_trip = Some((start_time, mode));
|
||||
break;
|
||||
}
|
||||
TripResult::Ok(_) | TripResult::ModeChange => {
|
||||
// TODO What to do here? This is meant for building callers right now
|
||||
break;
|
||||
}
|
||||
TripResult::TripDone => {}
|
||||
TripResult::TripDoesntExist => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let label = format!("Person #{}", p.0);
|
||||
details
|
||||
.hyperlinks
|
||||
.insert(label.clone(), Tab::PersonStatus(p));
|
||||
rows.push(Widget::col(vec![
|
||||
Btn::text_bg1(label).build_def(ctx, None),
|
||||
if let Some((t, mode)) = next_trip {
|
||||
format!("Leaving in {} to {}", t - app.primary.sim.time(), mode).draw_text(ctx)
|
||||
} else {
|
||||
"Staying inside".draw_text(ctx)
|
||||
},
|
||||
]));
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
fn header(
|
||||
ctx: &EventCtx,
|
||||
app: &App,
|
||||
details: &mut Details,
|
||||
id: BuildingID,
|
||||
tab: InfoTab,
|
||||
header_btns: Widget,
|
||||
action_btns: Vec<Widget>,
|
||||
batch: &mut GeomBatch,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
tab: Tab,
|
||||
) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
let b = app.primary.map.get_b(id);
|
||||
let ppl = app.primary.sim.bldg_to_people(id);
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Building #{}", id.0))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns,
|
||||
header_btns(ctx),
|
||||
]));
|
||||
|
||||
rows.push(make_tabs(ctx, hyperlinks, ID::Building(id), tab.clone(), {
|
||||
let mut tabs = vec![("Info", InfoTab::Nil), ("Debug", InfoTab::Bldg(Tab::Debug))];
|
||||
if !ppl.is_empty() {
|
||||
tabs.push(("People", InfoTab::Bldg(Tab::People)));
|
||||
}
|
||||
tabs
|
||||
}));
|
||||
|
||||
match tab {
|
||||
InfoTab::Nil => {
|
||||
rows.extend(action_btns);
|
||||
|
||||
let mut kv = Vec::new();
|
||||
|
||||
kv.push(("Address", b.just_address(&app.primary.map)));
|
||||
if let Some(name) = b.just_name() {
|
||||
kv.push(("Name", name.to_string()));
|
||||
}
|
||||
|
||||
if let Some(ref p) = b.parking {
|
||||
kv.push(("Parking", format!("{} spots via {}", p.num_stalls, p.name)));
|
||||
} else {
|
||||
kv.push(("Parking", "None".to_string()));
|
||||
}
|
||||
|
||||
rows.extend(make_table(ctx, kv));
|
||||
|
||||
let mut txt = Text::new();
|
||||
|
||||
if !b.amenities.is_empty() {
|
||||
txt.add(Line(""));
|
||||
if b.amenities.len() > 1 {
|
||||
txt.add(Line(format!("{} amenities:", b.amenities.len())));
|
||||
}
|
||||
for (name, amenity) in &b.amenities {
|
||||
txt.add(Line(format!("- {} (a {})", name, amenity)));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Rethink this
|
||||
let trip_lines = app
|
||||
.primary
|
||||
.sim
|
||||
.count_trips(TripEndpoint::Bldg(id))
|
||||
.describe();
|
||||
if !trip_lines.is_empty() {
|
||||
txt.add(Line(""));
|
||||
for line in trip_lines {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
}
|
||||
|
||||
let cars = app.primary.sim.get_parked_cars_by_owner(id);
|
||||
if !cars.is_empty() {
|
||||
txt.add(Line(""));
|
||||
txt.add(Line(format!(
|
||||
"{} parked cars owned by this building",
|
||||
cars.len()
|
||||
)));
|
||||
// TODO Jump to it or see status
|
||||
for p in cars {
|
||||
txt.add(Line(format!("- {}", p.vehicle.id)));
|
||||
}
|
||||
}
|
||||
|
||||
if !txt.is_empty() {
|
||||
rows.push(txt.draw(ctx))
|
||||
}
|
||||
}
|
||||
InfoTab::Bldg(Tab::Debug) => {
|
||||
rows.extend(make_table(
|
||||
ctx,
|
||||
vec![(
|
||||
"Dist along sidewalk",
|
||||
b.front_path.sidewalk.dist_along().to_string(),
|
||||
)],
|
||||
));
|
||||
rows.push("Raw OpenStreetMap data".draw_text(ctx));
|
||||
rows.extend(make_table(ctx, b.osm_tags.clone().into_iter().collect()));
|
||||
}
|
||||
InfoTab::Bldg(Tab::People) => {
|
||||
// TODO Sort/group better
|
||||
// Show minimal info: ID, next departure time, type of that trip
|
||||
for person in ppl {
|
||||
rows.push(person::summary(ctx, app, person, hyperlinks));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
rows.push(make_tabs(
|
||||
ctx,
|
||||
&mut details.hyperlinks,
|
||||
tab,
|
||||
vec![
|
||||
("Info", Tab::BldgInfo(id)),
|
||||
("Debug", Tab::BldgDebug(id)),
|
||||
("People", Tab::BldgPeople(id)),
|
||||
],
|
||||
));
|
||||
|
||||
// TODO On every tab?
|
||||
for p in app.primary.sim.get_parked_cars_by_owner(id) {
|
||||
batch.push(
|
||||
let shape = app
|
||||
.primary
|
||||
.draw_map
|
||||
.get_obj(
|
||||
ID::Car(p.vehicle.id),
|
||||
app,
|
||||
&mut app.primary.draw_map.agents.borrow_mut(),
|
||||
ctx.prerender,
|
||||
)
|
||||
.unwrap()
|
||||
.get_outline(&app.primary.map);
|
||||
details.unzoomed.push(
|
||||
app.cs.get("something associated with something else"),
|
||||
app.primary
|
||||
.draw_map
|
||||
.get_obj(
|
||||
ID::Car(p.vehicle.id),
|
||||
app,
|
||||
&mut app.primary.draw_map.agents.borrow_mut(),
|
||||
ctx.prerender,
|
||||
)
|
||||
.unwrap()
|
||||
.get_outline(&app.primary.map),
|
||||
shape.clone(),
|
||||
);
|
||||
details.zoomed.push(
|
||||
app.cs.get("something associated with something else"),
|
||||
shape,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
use crate::app::App;
|
||||
use crate::info::{header_btns, make_table, Details};
|
||||
use ezgui::{EventCtx, Line, Text, Widget};
|
||||
use geom::Time;
|
||||
use map_model::BusStopID;
|
||||
use sim::CarID;
|
||||
|
||||
pub fn info(
|
||||
ctx: &EventCtx,
|
||||
app: &App,
|
||||
id: BusStopID,
|
||||
header_btns: Widget,
|
||||
action_btns: Vec<Widget>,
|
||||
) -> Vec<Widget> {
|
||||
// TODO Needs much more work
|
||||
pub fn stop(ctx: &EventCtx, app: &App, details: &mut Details, id: BusStopID) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
let sim = &app.primary.sim;
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line("Bus stop").small_heading().draw(ctx),
|
||||
header_btns,
|
||||
header_btns(ctx),
|
||||
]));
|
||||
rows.extend(action_btns);
|
||||
|
||||
let mut txt = Text::new();
|
||||
txt.add(Line(format!(
|
||||
@ -53,3 +48,25 @@ pub fn info(
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
// TODO Likewise
|
||||
pub fn bus(ctx: &EventCtx, app: &App, details: &mut Details, id: CarID) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Bus #{}", id.0)).small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
]));
|
||||
|
||||
let (kv, extra) = app.primary.sim.car_properties(id, &app.primary.map);
|
||||
rows.extend(make_table(ctx, kv));
|
||||
if !extra.is_empty() {
|
||||
let mut txt = Text::from(Line(""));
|
||||
for line in extra {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
rows.push(txt.draw(ctx));
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
//mod building;
|
||||
//mod bus;
|
||||
mod building;
|
||||
mod bus;
|
||||
mod debug;
|
||||
mod intersection;
|
||||
mod lane;
|
||||
//mod person;
|
||||
mod person;
|
||||
mod trip;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::colors;
|
||||
@ -200,20 +201,16 @@ impl InfoPanel {
|
||||
}*/
|
||||
|
||||
let col = match tab {
|
||||
/*Tab::PersonStatus(p) => person::status(ctx, app, &mut details, p),
|
||||
Tab::PersonStatus(p) => person::status(ctx, app, &mut details, p),
|
||||
Tab::PersonTrips(p) => person::trips(ctx, app, &mut details, p),
|
||||
Tab::PersonBio(p) => person::bio(ctx, app, &mut details, p),
|
||||
|
||||
Tab::Bus(c) => bus::bus(ctx, app, &mut details, c),
|
||||
Tab::BusStop(bs) => bus::stop(ctx, app, &mut details, bs),
|
||||
|
||||
Tab::ParkedCar(c) => person::parked_car(ctx, app, &mut details, c),
|
||||
|
||||
Tab::BldgInfo(b) => building::info(ctx, app, &mut details, b),
|
||||
Tab::BldgDebug(b) => building::debug(ctx, app, &mut details, b),
|
||||
Tab::BldgPeople(b) => building::people(ctx, app, &mut details, b),
|
||||
|
||||
Tab::Crowd(members) => person::crowd(ctx, app, &mut details, members),*/
|
||||
Tab::Crowd(ref members) => person::crowd(ctx, app, &mut details, members),
|
||||
Tab::Area(a) => debug::area(ctx, app, &mut details, a),
|
||||
Tab::ExtraShape(es) => debug::extra_shape(ctx, app, &mut details, es),
|
||||
Tab::IntersectionInfo(i) => intersection::info(ctx, app, &mut details, i),
|
||||
@ -222,7 +219,6 @@ impl InfoPanel {
|
||||
Tab::LaneInfo(l) => lane::info(ctx, app, &mut details, l),
|
||||
Tab::LaneDebug(l) => lane::debug(ctx, app, &mut details, l),
|
||||
Tab::LaneTraffic(l) => lane::traffic(ctx, app, &mut details, l),
|
||||
_ => panic!("TODO"),
|
||||
};
|
||||
|
||||
/*
|
||||
@ -430,35 +426,6 @@ fn make_tabs(
|
||||
Widget::row(row).bg(Color::WHITE)
|
||||
}
|
||||
|
||||
fn make_browser<F: Fn(usize) -> Tab>(
|
||||
ctx: &EventCtx,
|
||||
hyperlinks: &mut HashMap<String, Tab>,
|
||||
noun: &str,
|
||||
total: usize,
|
||||
idx: usize,
|
||||
make_link: F,
|
||||
) -> Widget {
|
||||
// TODO Keys are weird! But left/right for speed
|
||||
Widget::row(vec![
|
||||
if idx != 0 {
|
||||
hyperlinks.insert("previous".to_string(), make_link(idx - 1));
|
||||
Btn::text_fg("<").build(ctx, "previous", hotkey(Key::UpArrow))
|
||||
} else {
|
||||
Btn::text_fg("<").inactive(ctx)
|
||||
}
|
||||
.margin(5),
|
||||
format!("{} {}/{}", noun, idx + 1, total).draw_text(ctx),
|
||||
if idx != total - 1 {
|
||||
hyperlinks.insert("next".to_string(), make_link(idx + 1));
|
||||
Btn::text_fg(">").build(ctx, "next", hotkey(Key::DownArrow))
|
||||
} else {
|
||||
Btn::text_fg(">").inactive(ctx)
|
||||
}
|
||||
.margin(5),
|
||||
])
|
||||
.centered()
|
||||
}
|
||||
|
||||
fn header_btns(ctx: &EventCtx) -> Widget {
|
||||
Widget::row(vec![
|
||||
Btn::svg_def("../data/system/assets/tools/location.svg")
|
||||
|
@ -1,113 +1,223 @@
|
||||
use crate::app::App;
|
||||
use crate::colors;
|
||||
use crate::helpers::ID;
|
||||
use crate::info::trip::trip_details;
|
||||
use crate::info::{make_table, make_tabs, InfoTab};
|
||||
use ezgui::{Btn, EventCtx, Line, TextExt, Widget};
|
||||
use geom::Time;
|
||||
use crate::info::{header_btns, make_table, make_tabs, Details, Tab, Text};
|
||||
use crate::render::Renderable;
|
||||
use ezgui::{Btn, Color, EventCtx, Line, TextExt, Widget};
|
||||
use map_model::Map;
|
||||
use sim::{Person, PersonID, PersonState, TripMode, TripResult};
|
||||
use std::collections::HashMap;
|
||||
use sim::{AgentID, CarID, PedestrianID, Person, PersonID, PersonState, TripResult};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Tab {
|
||||
Bio,
|
||||
pub fn status(ctx: &mut EventCtx, app: &App, details: &mut Details, id: PersonID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, app, details, id, Tab::PersonStatus(id));
|
||||
|
||||
let map = &app.primary.map;
|
||||
let sim = &app.primary.sim;
|
||||
let person = sim.get_person(id);
|
||||
|
||||
match sim.get_person(id).state {
|
||||
PersonState::Inside(b) => {
|
||||
// TODO hyperlink
|
||||
rows.push(
|
||||
format!("Currently inside {}", map.get_b(b).just_address(map)).draw_text(ctx),
|
||||
);
|
||||
}
|
||||
PersonState::OffMap => {
|
||||
rows.push("Currently outside the map boundaries".draw_text(ctx));
|
||||
}
|
||||
PersonState::Limbo => {
|
||||
rows.push(
|
||||
"Currently in limbo -- they broke out of the Matrix! Woops. (A bug occurred)"
|
||||
.draw_text(ctx),
|
||||
);
|
||||
}
|
||||
PersonState::Trip(t) => {
|
||||
if let Some(a) = sim.trip_to_agent(t).ok() {
|
||||
rows.push(Widget::col(vec![
|
||||
Line(format!("Trip #{}", t.0)).small_heading().draw(ctx),
|
||||
trip_details(ctx, app, t, sim.progress_along_path(a), details),
|
||||
]));
|
||||
|
||||
let (kv, extra) = match a {
|
||||
AgentID::Car(c) => sim.car_properties(c, map),
|
||||
AgentID::Pedestrian(p) => sim.ped_properties(p, map),
|
||||
};
|
||||
rows.extend(make_table(ctx, kv));
|
||||
if !extra.is_empty() {
|
||||
let mut txt = Text::from(Line(""));
|
||||
for line in extra {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
rows.push(txt.draw(ctx));
|
||||
}
|
||||
|
||||
if let AgentID::Car(c) = a {
|
||||
if let Some(b) = app.primary.sim.get_owner_of_car(c) {
|
||||
// TODO Mention this, with a warp tool
|
||||
details.unzoomed.push(
|
||||
app.cs
|
||||
.get_def("something associated with something else", Color::PURPLE),
|
||||
app.primary.draw_map.get_b(b).get_outline(&app.primary.map),
|
||||
);
|
||||
details.zoomed.push(
|
||||
app.cs.get("something associated with something else"),
|
||||
app.primary.draw_map.get_b(b).get_outline(&app.primary.map),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO Temporary mode change, what's going on?
|
||||
rows.push(Widget::col(vec![
|
||||
Line(format!("Trip #{}", t.0)).small_heading().draw(ctx),
|
||||
trip_details(ctx, app, t, None, details),
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
pub fn info(
|
||||
ctx: &mut EventCtx,
|
||||
pub fn trips(ctx: &mut EventCtx, app: &App, details: &mut Details, id: PersonID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, app, details, id, Tab::PersonTrips(id));
|
||||
|
||||
let map = &app.primary.map;
|
||||
let sim = &app.primary.sim;
|
||||
let person = sim.get_person(id);
|
||||
|
||||
// I'm sorry for bad variable names
|
||||
let mut wheres_waldo = true;
|
||||
// TODO Classify trips as not started, ongoing, done. Don't mention current status as much?
|
||||
for t in &person.trips {
|
||||
match sim.trip_to_agent(*t) {
|
||||
TripResult::TripNotStarted => {
|
||||
if wheres_waldo {
|
||||
wheres_waldo = false;
|
||||
rows.push(current_status(ctx, person, map));
|
||||
}
|
||||
}
|
||||
TripResult::Ok(_) | TripResult::ModeChange => {
|
||||
// ongoing
|
||||
assert!(wheres_waldo);
|
||||
wheres_waldo = false;
|
||||
}
|
||||
TripResult::TripDone => {
|
||||
assert!(wheres_waldo);
|
||||
}
|
||||
TripResult::TripDoesntExist => unreachable!(),
|
||||
}
|
||||
rows.push(
|
||||
Widget::col(vec![
|
||||
Line(format!("Trip #{}", t.0)).small_heading().draw(ctx),
|
||||
trip_details(ctx, app, *t, None, details),
|
||||
])
|
||||
.bg(colors::SECTION_BG)
|
||||
.margin(10),
|
||||
);
|
||||
}
|
||||
if wheres_waldo {
|
||||
rows.push(current_status(ctx, person, map));
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
pub fn bio(ctx: &EventCtx, app: &App, details: &mut Details, id: PersonID) -> Vec<Widget> {
|
||||
let mut rows = header(ctx, app, details, id, Tab::PersonBio(id));
|
||||
|
||||
// TODO A little picture
|
||||
rows.extend(make_table(
|
||||
ctx,
|
||||
vec![
|
||||
("Name", "Somebody".to_string()),
|
||||
("Age", "42".to_string()),
|
||||
("Occupation", "classified".to_string()),
|
||||
],
|
||||
));
|
||||
// TODO Mad libs!
|
||||
// - Keeps a collection of ___ at all times
|
||||
// - Origin story: accidentally fell into a vat of cheese curds
|
||||
// - Superpower: Makes unnervingly realistic squirrel noises
|
||||
// - Rides a fixie
|
||||
// - Has 17 pinky toe piercings (surprising, considering they're the state champ at
|
||||
// barefoot marathons)
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
pub fn crowd(
|
||||
ctx: &EventCtx,
|
||||
app: &App,
|
||||
id: PersonID,
|
||||
tab: InfoTab,
|
||||
// If None, then the panel is embedded
|
||||
header_btns: Option<Widget>,
|
||||
action_btns: Vec<Widget>,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
warpers: &mut HashMap<String, ID>,
|
||||
details: &mut Details,
|
||||
members: &Vec<PedestrianID>,
|
||||
) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
// Header
|
||||
if let Some(btns) = header_btns {
|
||||
rows.push(Widget::row(vec![
|
||||
Line("Pedestrian crowd").small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
]));
|
||||
|
||||
for (idx, id) in members.into_iter().enumerate() {
|
||||
let person = app
|
||||
.primary
|
||||
.sim
|
||||
.agent_to_person(AgentID::Pedestrian(*id))
|
||||
.unwrap();
|
||||
// TODO What other info is useful to summarize?
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Person #{}", id.0)).small_heading().draw(ctx),
|
||||
btns,
|
||||
format!("{})", idx + 1).draw_text(ctx),
|
||||
Btn::text_fg(format!("Person #{}", person.0)).build_def(ctx, None),
|
||||
]));
|
||||
} else {
|
||||
rows.push(Line(format!("Person #{}", id.0)).small_heading().draw(ctx));
|
||||
details
|
||||
.hyperlinks
|
||||
.insert(format!("Person #{}", person.0), Tab::PersonStatus(person));
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
pub fn parked_car(ctx: &EventCtx, app: &App, details: &mut Details, id: CarID) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Parked car #{}", id.0))
|
||||
.small_heading()
|
||||
.draw(ctx),
|
||||
header_btns(ctx),
|
||||
]));
|
||||
|
||||
let (kv, extra) = app.primary.sim.car_properties(id, &app.primary.map);
|
||||
rows.extend(make_table(ctx, kv));
|
||||
if !extra.is_empty() {
|
||||
let mut txt = Text::from(Line(""));
|
||||
for line in extra {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
rows.push(txt.draw(ctx));
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
fn header(ctx: &EventCtx, app: &App, details: &mut Details, id: PersonID, tab: Tab) -> Vec<Widget> {
|
||||
let mut rows = vec![];
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Person #{}", id.0)).small_heading().draw(ctx),
|
||||
header_btns(ctx),
|
||||
]));
|
||||
|
||||
rows.push(make_tabs(
|
||||
ctx,
|
||||
hyperlinks,
|
||||
ID::Person(id),
|
||||
tab.clone(),
|
||||
vec![("Trips", InfoTab::Nil), ("Bio", InfoTab::Person(Tab::Bio))],
|
||||
&mut details.hyperlinks,
|
||||
tab,
|
||||
vec![
|
||||
("Status", Tab::PersonStatus(id)),
|
||||
("Trips", Tab::PersonTrips(id)),
|
||||
("Bio", Tab::PersonBio(id)),
|
||||
],
|
||||
));
|
||||
|
||||
match tab {
|
||||
InfoTab::Nil => {
|
||||
// TODO None of these right now
|
||||
rows.extend(action_btns);
|
||||
|
||||
let map = &app.primary.map;
|
||||
let sim = &app.primary.sim;
|
||||
let person = sim.get_person(id);
|
||||
|
||||
// I'm sorry for bad variable names
|
||||
let mut wheres_waldo = true;
|
||||
for t in &person.trips {
|
||||
match sim.trip_to_agent(*t) {
|
||||
TripResult::TripNotStarted => {
|
||||
if wheres_waldo {
|
||||
wheres_waldo = false;
|
||||
rows.push(current_status(ctx, person, map));
|
||||
}
|
||||
}
|
||||
TripResult::Ok(_) | TripResult::ModeChange => {
|
||||
// ongoing
|
||||
assert!(wheres_waldo);
|
||||
wheres_waldo = false;
|
||||
}
|
||||
TripResult::TripDone => {
|
||||
assert!(wheres_waldo);
|
||||
}
|
||||
TripResult::TripDoesntExist => unreachable!(),
|
||||
}
|
||||
rows.push(
|
||||
Widget::col(vec![
|
||||
Line(format!("Trip #{}", t.0)).small_heading().draw(ctx),
|
||||
trip_details(ctx, app, *t, None, warpers).0,
|
||||
])
|
||||
.bg(colors::SECTION_BG)
|
||||
.margin(10),
|
||||
);
|
||||
}
|
||||
if wheres_waldo {
|
||||
rows.push(current_status(ctx, person, map));
|
||||
}
|
||||
}
|
||||
InfoTab::Person(Tab::Bio) => {
|
||||
// TODO A little picture
|
||||
rows.extend(make_table(
|
||||
ctx,
|
||||
vec![
|
||||
("Name", "Somebody".to_string()),
|
||||
("Age", "42".to_string()),
|
||||
("Occupation", "classified".to_string()),
|
||||
],
|
||||
));
|
||||
// TODO Mad libs!
|
||||
// - Keeps a collection of ___ at all times
|
||||
// - Origin story: accidentally fell into a vat of cheese curds
|
||||
// - Superpower: Makes unnervingly realistic squirrel noises
|
||||
// - Rides a fixie
|
||||
// - Has 17 pinky toe piercings (surprising, considering they're the state champ at
|
||||
// barefoot marathons)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
@ -124,40 +234,3 @@ fn current_status(ctx: &EventCtx, person: &Person, map: &Map) -> Widget {
|
||||
.draw_text(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn summary(
|
||||
ctx: &EventCtx,
|
||||
app: &App,
|
||||
id: PersonID,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
) -> Widget {
|
||||
let person = app.primary.sim.get_person(id);
|
||||
|
||||
let mut next_trip: Option<(Time, TripMode)> = None;
|
||||
for t in &person.trips {
|
||||
match app.primary.sim.trip_to_agent(*t) {
|
||||
TripResult::TripNotStarted => {
|
||||
let (start_time, _, _, mode) = app.primary.sim.trip_info(*t);
|
||||
next_trip = Some((start_time, mode));
|
||||
break;
|
||||
}
|
||||
TripResult::Ok(_) | TripResult::ModeChange => {
|
||||
// TODO What to do here? This is meant for building callers right now
|
||||
break;
|
||||
}
|
||||
TripResult::TripDone => {}
|
||||
TripResult::TripDoesntExist => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let label = format!("Person #{}", id.0);
|
||||
hyperlinks.insert(label.clone(), (ID::Person(id), InfoTab::Nil));
|
||||
Widget::col(vec![
|
||||
Btn::text_bg1(label).build_def(ctx, None),
|
||||
if let Some((t, mode)) = next_trip {
|
||||
format!("Leaving in {} to {}", t - app.primary.sim.time(), mode).draw_text(ctx)
|
||||
} else {
|
||||
"Staying inside".draw_text(ctx)
|
||||
},
|
||||
])
|
||||
}
|
||||
|
@ -1,97 +1,26 @@
|
||||
use crate::app::App;
|
||||
use crate::colors;
|
||||
use crate::helpers::ID;
|
||||
use crate::info::{make_table, make_tabs, person, InfoTab, TripDetails};
|
||||
use crate::info::{make_table, Details};
|
||||
use crate::render::dashed_lines;
|
||||
use ezgui::{
|
||||
hotkey, Btn, Color, EventCtx, GeomBatch, Key, Line, Plot, PlotOptions, RewriteColor, Series,
|
||||
Text, Widget,
|
||||
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::{PersonID, TripEndpoint, TripID, TripPhaseType};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Tab {
|
||||
Person(PersonID),
|
||||
}
|
||||
|
||||
pub fn inactive_info(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
id: TripID,
|
||||
tab: InfoTab,
|
||||
action_btns: Vec<Widget>,
|
||||
hyperlinks: &mut HashMap<String, (ID, InfoTab)>,
|
||||
warpers: &mut HashMap<String, ID>,
|
||||
) -> (Vec<Widget>, Option<TripDetails>) {
|
||||
let mut rows = vec![];
|
||||
|
||||
rows.push(Widget::row(vec![
|
||||
Line(format!("Trip #{}", id.0)).small_heading().draw(ctx),
|
||||
Btn::text_fg("X")
|
||||
.build(ctx, "close info", hotkey(Key::Escape))
|
||||
.align_right(),
|
||||
]));
|
||||
|
||||
rows.push(make_tabs(
|
||||
ctx,
|
||||
hyperlinks,
|
||||
ID::Trip(id),
|
||||
tab.clone(),
|
||||
vec![
|
||||
("Info", InfoTab::Nil),
|
||||
(
|
||||
"Trips",
|
||||
InfoTab::Trip(Tab::Person(app.primary.sim.trip_to_person(id))),
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
let mut details: Option<TripDetails> = None;
|
||||
|
||||
match tab {
|
||||
InfoTab::Nil => {
|
||||
rows.extend(action_btns);
|
||||
|
||||
let (more, trip_details) = trip_details(ctx, app, id, None, warpers);
|
||||
rows.push(more);
|
||||
details = Some(trip_details);
|
||||
}
|
||||
InfoTab::Trip(Tab::Person(p)) => {
|
||||
// TODO Hyperlink?
|
||||
rows.extend(person::info(
|
||||
ctx,
|
||||
app,
|
||||
p,
|
||||
InfoTab::Nil,
|
||||
None,
|
||||
Vec::new(),
|
||||
hyperlinks,
|
||||
warpers,
|
||||
));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
(rows, details)
|
||||
}
|
||||
use sim::{TripEndpoint, TripID, TripPhaseType};
|
||||
|
||||
pub fn trip_details(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
trip: TripID,
|
||||
progress_along_path: Option<f64>,
|
||||
warpers: &mut HashMap<String, ID>,
|
||||
) -> (Widget, TripDetails) {
|
||||
details: &mut Details,
|
||||
) -> Widget {
|
||||
let map = &app.primary.map;
|
||||
let phases = app.primary.sim.get_analytics().get_trip_phases(trip, map);
|
||||
let (start_time, trip_start, trip_end, trip_mode) = app.primary.sim.trip_info(trip);
|
||||
|
||||
let mut unzoomed = GeomBatch::new();
|
||||
let mut zoomed = GeomBatch::new();
|
||||
|
||||
if phases.is_empty() {
|
||||
// The trip hasn't started
|
||||
let kv = vec![
|
||||
@ -103,27 +32,22 @@ pub fn trip_details(
|
||||
("From", endpoint(&trip_start, map).2),
|
||||
("To", endpoint(&trip_end, map).2),
|
||||
];
|
||||
return (
|
||||
Widget::col(make_table(ctx, kv)),
|
||||
TripDetails {
|
||||
id: trip,
|
||||
unzoomed: unzoomed.upload(ctx),
|
||||
zoomed: zoomed.upload(ctx),
|
||||
},
|
||||
);
|
||||
return Widget::col(make_table(ctx, kv));
|
||||
}
|
||||
|
||||
let start_btn = {
|
||||
let (id, center, name) = endpoint(&trip_start, map);
|
||||
warpers.insert(format!("jump to start of Trip #{}", trip.0), id);
|
||||
unzoomed.add_svg(
|
||||
details
|
||||
.warpers
|
||||
.insert(format!("jump to start of Trip #{}", trip.0), id);
|
||||
details.unzoomed.add_svg(
|
||||
ctx.prerender,
|
||||
"../data/system/assets/timeline/start_pos.svg",
|
||||
center,
|
||||
1.0,
|
||||
Angle::ZERO,
|
||||
);
|
||||
zoomed.add_svg(
|
||||
details.zoomed.add_svg(
|
||||
ctx.prerender,
|
||||
"../data/system/assets/timeline/start_pos.svg",
|
||||
center,
|
||||
@ -145,15 +69,17 @@ pub fn trip_details(
|
||||
|
||||
let goal_btn = {
|
||||
let (id, center, name) = endpoint(&trip_end, map);
|
||||
warpers.insert(format!("jump to goal of Trip #{}", trip.0), id);
|
||||
unzoomed.add_svg(
|
||||
details
|
||||
.warpers
|
||||
.insert(format!("jump to goal of Trip #{}", trip.0), id);
|
||||
details.unzoomed.add_svg(
|
||||
ctx.prerender,
|
||||
"../data/system/assets/timeline/goal_pos.svg",
|
||||
center,
|
||||
1.0,
|
||||
Angle::ZERO,
|
||||
);
|
||||
zoomed.add_svg(
|
||||
details.zoomed.add_svg(
|
||||
ctx.prerender,
|
||||
"../data/system/assets/timeline/goal_pos.svg",
|
||||
center,
|
||||
@ -281,8 +207,10 @@ pub fn trip_details(
|
||||
}
|
||||
|
||||
if let Some(trace) = path.trace(map, dist, None) {
|
||||
unzoomed.push(color, trace.make_polygons(Distance::meters(10.0)));
|
||||
zoomed.extend(
|
||||
details
|
||||
.unzoomed
|
||||
.push(color, trace.make_polygons(Distance::meters(10.0)));
|
||||
details.zoomed.extend(
|
||||
color,
|
||||
dashed_lines(
|
||||
&trace,
|
||||
@ -309,14 +237,7 @@ pub fn trip_details(
|
||||
col.extend(make_table(ctx, kv));
|
||||
col.extend(elevation);
|
||||
|
||||
(
|
||||
Widget::col(col),
|
||||
TripDetails {
|
||||
id: trip,
|
||||
unzoomed: unzoomed.upload(ctx),
|
||||
zoomed: zoomed.upload(ctx),
|
||||
},
|
||||
)
|
||||
Widget::col(col)
|
||||
}
|
||||
|
||||
fn make_elevation(ctx: &EventCtx, color: Color, walking: bool, path: &Path, map: &Map) -> Widget {
|
||||
|
Loading…
Reference in New Issue
Block a user