refactor menu text for all ItemSliders

This commit is contained in:
Dustin Carlino 2019-06-17 16:37:24 -07:00
parent 22db36c0f4
commit cdacaef1a6
10 changed files with 108 additions and 113 deletions

View File

@ -7,7 +7,6 @@ use map_model::BusStopID;
pub struct BusRouteExplorer {
slider: WarpingItemSlider<BusStopID>,
route_name: String,
}
impl BusRouteExplorer {
@ -24,18 +23,22 @@ impl BusRouteExplorer {
return None;
}
let stops: Vec<(Pt2D, BusStopID)> = route
let stops: Vec<(Pt2D, BusStopID, Text)> = route
.stops
.iter()
.map(|bs| {
let stop = map.get_bs(*bs);
(stop.sidewalk_pos.pt(map), stop.id)
(stop.sidewalk_pos.pt(map), stop.id, Text::new())
})
.collect();
Some(BusRouteExplorer {
route_name: route.name.clone(),
slider: WarpingItemSlider::new(stops, "Bus Route Explorer", "stop", ctx),
slider: WarpingItemSlider::new(
stops,
&format!("Bus Route Explorer for {}", route.name),
"stop",
ctx,
),
})
}
@ -52,14 +55,9 @@ impl BusRouteExplorer {
}
ctx.canvas.handle_event(ctx.input);
let (idx, stop_id) = self.slider.get();
let stop_id = *stop_id;
let mut txt = Text::prompt(&format!("Bus Route Explorer for {:?}", self.route_name));
txt.add_line(format!("Step {}/{}", idx + 1, self.slider.len()));
let (evmode, done_warping) = self.slider.event(ctx, Some(txt))?;
let (evmode, done_warping) = self.slider.event(ctx)?;
if done_warping {
ui.primary.current_selection = Some(ID::BusStop(stop_id));
ui.primary.current_selection = Some(ID::BusStop(*self.slider.get().1));
}
Some(evmode)
}

View File

@ -30,7 +30,9 @@ impl PolygonDebugger {
pts_without_last.pop();
return Some(PolygonDebugger {
slider: ItemSlider::new(
pts.iter().map(|pt| Item::Point(*pt)).collect(),
pts.iter()
.map(|pt| (Item::Point(*pt), Text::new()))
.collect(),
"Polygon Debugger",
"point",
vec![(hotkey(Key::Escape), "quit")],
@ -50,7 +52,7 @@ impl PolygonDebugger {
&mut Timer::new("calculate corners"),
)
.into_iter()
.map(Item::Polygon)
.map(|poly| (Item::Polygon(poly), Text::new()))
.collect(),
"Polygon Debugger",
"corner",
@ -71,7 +73,7 @@ impl PolygonDebugger {
.lane_center_pts
.points()
.iter()
.map(|pt| Item::Point(*pt))
.map(|pt| (Item::Point(*pt), Text::new()))
.collect(),
"Polygon Debugger",
"point",
@ -89,7 +91,7 @@ impl PolygonDebugger {
.polygon
.triangles()
.into_iter()
.map(Item::Triangle)
.map(|tri| (Item::Triangle(tri), Text::new()))
.collect(),
"Polygon Debugger",
"triangle",
@ -112,7 +114,9 @@ impl PolygonDebugger {
};
return Some(PolygonDebugger {
slider: ItemSlider::new(
pts.iter().map(|pt| Item::Point(*pt)).collect(),
pts.iter()
.map(|pt| (Item::Point(*pt), Text::new()))
.collect(),
"Polygon Debugger",
"point",
vec![(hotkey(Key::Escape), "quit")],
@ -129,7 +133,7 @@ impl PolygonDebugger {
.polygon
.triangles()
.into_iter()
.map(Item::Triangle)
.map(|tri| (Item::Triangle(tri), Text::new()))
.collect(),
"Polygon Debugger",
"triangle",
@ -147,10 +151,7 @@ impl PolygonDebugger {
// True when done
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
let (idx, _) = self.slider.get();
let mut txt = Text::prompt("Polygon Debugger");
txt.add_line(format!("Item {}/{}", idx + 1, self.slider.len()));
self.slider.event(ctx, Some(txt));
self.slider.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.slider.action("quit") {

View File

@ -2,7 +2,6 @@ use crate::common::CommonState;
use crate::helpers::ID;
use crate::mission::trips::{clip_trips, Trip, TripEndpt};
use crate::ui::{ShowEverything, UI};
use abstutil::prettyprint_usize;
use ezgui::{hotkey, Color, EventCtx, GfxCtx, ItemSlider, Key, Text};
use geom::{Circle, Distance, Line, Speed};
use map_model::BuildingID;
@ -18,7 +17,29 @@ impl TripsVisualizer {
pub fn new(ctx: &mut EventCtx, ui: &UI) -> TripsVisualizer {
let (trips, bldgs) = ctx.loading_screen("load trip data", |_, mut timer| {
// TODO We'll break if there are no matching trips
clip_trips(ui, &mut timer)
let (trips, bldgs) = clip_trips(ui, &mut timer);
(
trips
.into_iter()
.map(|trip| {
let mut txt = Text::new();
txt.add_line(format!("Leave at {}", trip.depart_at));
txt.add_line(format!(
"Purpose: {:?} -> {:?}",
trip.purpose.0, trip.purpose.1
));
txt.add_line(format!("Mode: {:?}", trip.mode));
txt.add_line(format!("Trip time: {}", trip.trip_time));
txt.add_line(format!("Trip distance: {}", trip.trip_dist));
txt.add_line(format!(
"Average speed {}",
Speed::from_dist_time(trip.trip_dist, trip.trip_time)
));
(trip, txt)
})
.collect(),
bldgs,
)
});
TripsVisualizer {
slider: ItemSlider::new(
@ -34,27 +55,7 @@ impl TripsVisualizer {
// Returns true if the we're done
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
let (idx, trip) = self.slider.get();
let mut txt = Text::prompt("Trips Visualizer");
txt.add_line(format!(
"Trip {}/{}",
prettyprint_usize(idx + 1),
prettyprint_usize(self.slider.len())
));
txt.add_line(format!("Leave at {}", trip.depart_at));
txt.add_line(format!(
"Purpose: {:?} -> {:?}",
trip.purpose.0, trip.purpose.1
));
txt.add_line(format!("Mode: {:?}", trip.mode));
txt.add_line(format!("Trip time: {}", trip.trip_time));
txt.add_line(format!("Trip distance: {}", trip.trip_dist));
txt.add_line(format!(
"Average speed {}",
Speed::from_dist_time(trip.trip_dist, trip.trip_time)
));
self.slider.event(ctx, Some(txt));
self.slider.event(ctx);
ctx.canvas.handle_event(ctx.input);
if ctx.redo_mouseover() {

View File

@ -8,7 +8,6 @@ use sim::AgentID;
pub struct RouteExplorer {
slider: WarpingItemSlider<Traversable>,
agent: AgentID,
entire_trace: Option<Polygon>,
}
@ -40,7 +39,7 @@ impl RouteExplorer {
.trace(&ui.primary.map, Distance::ZERO, None)
.map(|pl| pl.make_polygons(LANE_THICKNESS));
let steps: Vec<(Pt2D, Traversable)> = path
let steps: Vec<(Pt2D, Traversable, Text)> = path
.get_steps()
.iter()
.map(|step| {
@ -49,12 +48,17 @@ impl RouteExplorer {
t.dist_along(t.length(&ui.primary.map) / 2.0, &ui.primary.map)
.0,
t,
Text::from_line(format!("{:?}", t)),
)
})
.collect();
Some(RouteExplorer {
agent,
slider: WarpingItemSlider::new(steps, "Route Explorer", "step", ctx),
slider: WarpingItemSlider::new(
steps,
&format!("Route Explorer for {}", agent),
"step",
ctx,
),
entire_trace,
})
}
@ -72,15 +76,9 @@ impl RouteExplorer {
}
ctx.canvas.handle_event(ctx.input);
let (idx, step) = self.slider.get();
let step = *step;
let mut txt = Text::prompt(&format!("Route Explorer for {:?}", self.agent));
txt.add_line(format!("Step {}/{}", idx + 1, self.slider.len()));
txt.add_line(format!("{:?}", step));
// We don't really care about setting current_selection to the current step; drawing covers
// it up anyway.
self.slider.event(ctx, Some(txt)).map(|(evmode, _)| evmode)
self.slider.event(ctx).map(|(evmode, _)| evmode)
}
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -58,7 +58,7 @@ impl Scoreboard {
}
}
Scoreboard::BrowseTrips(ref trips, ref mut wizard) => {
if let Some(_) = pick_trip(trips, &mut wizard.wrap(ctx)) {
if pick_trip(trips, &mut wizard.wrap(ctx)).is_some() {
// TODO show trip departure, where it started and ended
*self = Scoreboard::new(ctx, ui);
} else if wizard.aborted() {

View File

@ -10,7 +10,7 @@ pub enum TimeTravel {
Active(ItemSlider<StateAtTime>),
Inactive {
should_record: bool,
moments: Vec<StateAtTime>,
moments: Vec<(StateAtTime, Text)>,
},
}
@ -75,7 +75,7 @@ impl TimeTravel {
let sim = &ui.primary.sim;
let now = sim.time();
if let Some(ref state) = moments.last() {
if let Some((ref state, _)) = moments.last() {
// Already have this
if now == state.time {
return;
@ -101,7 +101,8 @@ impl TimeTravel {
state.peds_per_traversable.insert(draw.on, draw.id);
state.peds.insert(draw.id, draw);
}
moments.push(state);
let label = Text::from_line(state.time.to_string());
moments.push((state, label));
}
TimeTravel::Active(_) => unreachable!(),
}
@ -112,11 +113,7 @@ impl TimeTravel {
match self {
TimeTravel::Inactive { .. } => unreachable!(),
TimeTravel::Active(ref mut slider) => {
let (idx, state) = slider.get();
let mut txt = Text::prompt("Time Traveler");
txt.add_line(format!("{}", state.time));
txt.add_line(format!("{}/{}", idx + 1, slider.len()));
slider.event(ctx, Some(txt));
slider.event(ctx);
ctx.canvas.handle_event(ctx.input);
if slider.action("quit") {

View File

@ -140,6 +140,10 @@ impl Text {
self.lines.len()
}
pub fn extend(&mut self, other: &Text) {
self.lines.extend(other.lines.clone())
}
pub(crate) fn is_empty(&self) -> bool {
self.lines.is_empty()
}

View File

@ -171,9 +171,10 @@ impl Slider {
}
pub struct ItemSlider<T> {
items: Vec<T>,
items: Vec<(T, Text)>,
slider: Slider,
menu: ModalMenu,
menu_title: String,
prev: String,
next: String,
@ -183,7 +184,7 @@ pub struct ItemSlider<T> {
impl<T> ItemSlider<T> {
pub fn new(
items: Vec<T>,
items: Vec<(T, Text)>,
menu_title: &str,
noun: &str,
other_choices: Vec<(Option<MultiKey>, &str)>,
@ -207,6 +208,7 @@ impl<T> ItemSlider<T> {
items,
slider: Slider::new(None),
menu: ModalMenu::new(menu_title, choices, ctx),
menu_title: menu_title.to_string(),
prev,
next,
@ -216,10 +218,19 @@ impl<T> ItemSlider<T> {
}
// Returns true if the value changed.
pub fn event(&mut self, ctx: &mut EventCtx, menu_prompt: Option<Text>) -> bool {
let current = self.slider.get_value(self.items.len());
self.menu.handle_event(ctx, menu_prompt);
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
let current = {
let idx = self.slider.get_value(self.items.len());
let mut txt = Text::prompt(&self.menu_title);
txt.add_line(format!(
"{}/{}",
abstutil::prettyprint_usize(idx + 1),
abstutil::prettyprint_usize(self.items.len())
));
txt.extend(&self.items[idx].1);
self.menu.handle_event(ctx, Some(txt));
idx
};
if current != self.items.len() - 1 && self.menu.action(&self.next) {
self.slider.set_value(ctx, current + 1, self.items.len());
@ -243,11 +254,7 @@ impl<T> ItemSlider<T> {
pub fn get(&self) -> (usize, &T) {
let idx = self.slider.get_value(self.items.len());
(idx, &self.items[idx])
}
pub fn len(&self) -> usize {
self.items.len()
(idx, &self.items[idx].0)
}
pub fn action(&mut self, name: &str) -> bool {
@ -255,7 +262,7 @@ impl<T> ItemSlider<T> {
}
// TODO Consume self
pub fn consume_all_items(&mut self) -> Vec<T> {
pub fn consume_all_items(&mut self) -> Vec<(T, Text)> {
std::mem::replace(&mut self.items, Vec::new())
}
}
@ -268,7 +275,7 @@ pub struct WarpingItemSlider<T> {
impl<T> WarpingItemSlider<T> {
// Note other_choices is hardcoded to quitting.
pub fn new(
items: Vec<(Pt2D, T)>,
items: Vec<(Pt2D, T, Text)>,
menu_title: &str,
noun: &str,
ctx: &mut EventCtx,
@ -276,7 +283,10 @@ impl<T> WarpingItemSlider<T> {
WarpingItemSlider {
warper: Some(Warper::new(ctx, items[0].0)),
slider: ItemSlider::new(
items,
items
.into_iter()
.map(|(pt, obj, label)| ((pt, obj), label))
.collect(),
menu_title,
noun,
vec![(hotkey(Key::Escape), "quit")],
@ -286,11 +296,7 @@ impl<T> WarpingItemSlider<T> {
}
// Done when None. If the bool is true, done warping.
pub fn event(
&mut self,
ctx: &mut EventCtx,
menu_prompt: Option<Text>,
) -> Option<(EventLoopMode, bool)> {
pub fn event(&mut self, ctx: &mut EventCtx) -> Option<(EventLoopMode, bool)> {
// Don't block while we're warping
let (ev_mode, done_warping) = if let Some(ref warper) = self.warper {
if let Some(mode) = warper.event(ctx) {
@ -303,7 +309,7 @@ impl<T> WarpingItemSlider<T> {
(EventLoopMode::InputOnly, false)
};
let changed = self.slider.event(ctx, menu_prompt);
let changed = self.slider.event(ctx);
if self.slider.action("quit") {
return None;
@ -325,8 +331,4 @@ impl<T> WarpingItemSlider<T> {
let (idx, (_, data)) = self.slider.get();
(idx, data)
}
pub fn len(&self) -> usize {
self.slider.len()
}
}

View File

@ -168,7 +168,7 @@ impl GUI for UI {
}
};
let pt = Pt2D::from_gps(gps_pt, &self.raw.gps_bounds)?;
Some((pt, h.clone()))
Some((pt, h.clone(), Text::from_line(describe(h))))
})
.collect(),
"Hints Browser",
@ -244,13 +244,7 @@ impl GUI for UI {
}
State::BrowsingHints(ref mut slider) => {
ctx.canvas.handle_event(ctx.input);
let mut txt = Text::prompt("Hints Browser");
{
let (idx, hint) = slider.get();
txt.add_line(format!("Hint {}/{}", idx + 1, slider.len()));
txt.add_line(describe(hint));
}
if let Some((evmode, _)) = slider.event(ctx, Some(txt)) {
if let Some((evmode, _)) = slider.event(ctx) {
evmode
} else {
self.state = State::main(ctx);

View File

@ -60,11 +60,15 @@ impl SidewalkPathfinder {
// Connect each adjacent stop along a route, again with a "free" cost.
for route in map.get_all_bus_routes() {
for (stop1, stop2) in route
.stops
.iter()
.zip(route.stops.iter().skip(1))
.chain(std::iter::once((route.stops.last().unwrap(), &route.stops[0])))
for (stop1, stop2) in
route
.stops
.iter()
.zip(route.stops.iter().skip(1))
.chain(std::iter::once((
route.stops.last().unwrap(),
&route.stops[0],
)))
{
input_graph.add_edge(
nodes.get(Node::RideBus(*stop1)),
@ -76,14 +80,13 @@ impl SidewalkPathfinder {
}
}
input_graph.freeze();
println!(
"{} nodes, {} edges",
abstutil::prettyprint_usize(input_graph.get_num_nodes()),
abstutil::prettyprint_usize(input_graph.get_num_edges())
);
let graph = fast_paths::prepare(&input_graph);
SidewalkPathfinder { graph, nodes, connections }
SidewalkPathfinder {
graph,
nodes,
connections,
}
}
pub fn pathfind(&self, req: &PathRequest, map: &Map) -> Option<Path> {
@ -176,11 +179,8 @@ impl SidewalkPathfinder {
)?;
for pair in self.nodes.translate(&raw_path).windows(2) {
match (pair[0], pair[1]) {
(Node::RideBus(stop1), Node::RideBus(stop2)) => {
return Some((stop1, stop2, self.connections[&(stop1, stop2)]));
}
_ => {}
if let (Node::RideBus(stop1), Node::RideBus(stop2)) = (pair[0], pair[1]) {
return Some((stop1, stop2, self.connections[&(stop1, stop2)]));
}
}
None