refactor Warper to an ezgui widget, to use it in fix_map_geom

This commit is contained in:
Dustin Carlino 2019-06-14 12:36:41 -07:00
parent b2874193ec
commit 8c055312b4
9 changed files with 109 additions and 86 deletions

View File

@ -52,6 +52,9 @@ TODO:
## Map borders
## Buildings
home / commerical / mixed-use, etc. number of households and employees from psrc.
## Generalizing to other cities

View File

@ -11,7 +11,7 @@ use ezgui::{
hotkey, Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, MultiKey,
ScreenPt, Slider, Text, VerticalAlignment,
};
use geom::{Duration, Line, Pt2D};
use geom::Duration;
use std::collections::BTreeSet;
use std::time::Instant;
@ -189,53 +189,6 @@ impl CommonState {
}
}
const ANIMATION_TIME_S: f64 = 0.5;
// TODO Should factor in zoom too
const MIN_ANIMATION_SPEED: f64 = 200.0;
pub struct Warper {
started: Instant,
line: Option<Line>,
id: ID,
}
impl Warper {
pub fn new(ctx: &EventCtx, pt: Pt2D, id: ID) -> Warper {
Warper {
started: Instant::now(),
line: Line::maybe_new(ctx.canvas.center_to_map_pt(), pt),
id,
}
}
pub fn event(&self, ctx: &mut EventCtx, ui: &mut UI) -> Option<EventLoopMode> {
let line = self.line.as_ref()?;
// Weird to do stuff for any event?
if ctx.input.nonblocking_is_update_event() {
ctx.input.use_update_event();
}
let speed = line.length().inner_meters() / ANIMATION_TIME_S;
let total_time = if speed >= MIN_ANIMATION_SPEED {
ANIMATION_TIME_S
} else {
line.length().inner_meters() / MIN_ANIMATION_SPEED
};
let percent = elapsed_seconds(self.started) / total_time;
if percent >= 1.0 || ctx.input.nonblocking_is_keypress_event() {
ctx.canvas.center_on_map_pt(line.pt2());
ui.primary.current_selection = Some(self.id);
None
} else {
ctx.canvas
.center_on_map_pt(line.dist_along(line.length() * percent));
Some(EventLoopMode::Animation)
}
}
}
const ADJUST_SPEED: f64 = 0.1;
// TODO hardcoded cap for now...
const SPEED_CAP: f64 = 10.0 * 60.0;

View File

@ -1,14 +1,13 @@
use crate::common::Warper;
use crate::helpers::ID;
use crate::ui::UI;
use ezgui::{Autocomplete, EventCtx, EventLoopMode, GfxCtx, InputResult};
use ezgui::{Autocomplete, EventCtx, EventLoopMode, GfxCtx, InputResult, Warper};
use map_model::RoadID;
use std::collections::HashSet;
pub enum Navigator {
FirstStreet(Autocomplete<RoadID>),
CrossStreet(RoadID, Autocomplete<RoadID>),
Warping(Warper),
Warping(Warper, ID),
}
impl Navigator {
@ -64,11 +63,13 @@ impl Navigator {
// Just warp to somewhere on the first road
let road = map.get_r(*first_id);
println!("Warping to {}", road.get_name());
*self = Navigator::Warping(Warper::new(
ctx,
road.center_pts.dist_along(road.center_pts.length() / 2.0).0,
*self = Navigator::Warping(
Warper::new(
ctx,
road.center_pts.dist_along(road.center_pts.length() / 2.0).0,
),
ID::Lane(road.all_lanes()[0]),
));
);
Some(EventLoopMode::Animation)
}
InputResult::Done(name, ids) => {
@ -83,12 +84,18 @@ impl Navigator {
} else {
map.get_i(road.dst_i).polygon.center()
};
*self = Navigator::Warping(Warper::new(ctx, pt, ID::Lane(road.all_lanes()[0])));
*self = Navigator::Warping(Warper::new(ctx, pt), ID::Lane(road.all_lanes()[0]));
Some(EventLoopMode::Animation)
}
InputResult::StillActive => Some(EventLoopMode::InputOnly),
},
Navigator::Warping(ref warper) => warper.event(ctx, ui),
Navigator::Warping(ref warper, id) => {
let result = warper.event(ctx);
if result.is_none() {
ui.primary.current_selection = Some(*id);
}
result
}
}
}
@ -98,7 +105,7 @@ impl Navigator {
| Navigator::CrossStreet(_, ref autocomplete) => {
autocomplete.draw(g);
}
Navigator::Warping(_) => {}
Navigator::Warping(_, _) => {}
}
}
}

View File

@ -1,7 +1,6 @@
use crate::common::Warper;
use crate::helpers::ID;
use crate::ui::{PerMapUI, UI};
use ezgui::{EventCtx, EventLoopMode, GfxCtx, InputResult, TextBox};
use ezgui::{EventCtx, EventLoopMode, GfxCtx, InputResult, TextBox, Warper};
use geom::Pt2D;
use map_model::{raw_data, AreaID, BuildingID, IntersectionID, LaneID, RoadID};
use sim::{PedestrianID, TripID};
@ -9,7 +8,7 @@ use std::usize;
pub enum WarpState {
EnteringSearch(TextBox),
Warping(Warper),
Warping(Warper, ID),
}
impl WarpState {
@ -24,7 +23,7 @@ impl WarpState {
InputResult::Canceled => None,
InputResult::Done(to, _) => {
if let Some((id, pt)) = warp_point(to, &ui.primary) {
*self = WarpState::Warping(Warper::new(ctx, pt, id));
*self = WarpState::Warping(Warper::new(ctx, pt), id);
Some(EventLoopMode::Animation)
} else {
None
@ -32,7 +31,13 @@ impl WarpState {
}
InputResult::StillActive => Some(EventLoopMode::InputOnly),
},
WarpState::Warping(ref warper) => warper.event(ctx, ui),
WarpState::Warping(ref warper, id) => {
let result = warper.event(ctx);
if result.is_none() {
ui.primary.current_selection = Some(*id);
}
result
}
}
}

View File

@ -1,14 +1,14 @@
use crate::common::{CommonState, Warper};
use crate::common::CommonState;
use crate::helpers::ID;
use crate::ui::{ShowEverything, UI};
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text, Warper};
use geom::Pt2D;
use map_model::{BusStopID, LaneID};
pub struct BusRouteExplorer {
slider: ItemSlider<(BusStopID, LaneID, Pt2D)>,
route_name: String,
warper: Option<Warper>,
warper: Option<(Warper, ID)>,
}
impl BusRouteExplorer {
@ -36,7 +36,7 @@ impl BusRouteExplorer {
Some(BusRouteExplorer {
route_name: route.name.clone(),
warper: Some(Warper::new(ctx, stops[0].2, ID::Lane(stops[0].1))),
warper: Some((Warper::new(ctx, stops[0].2), ID::Lane(stops[0].1))),
slider: ItemSlider::new(
stops,
"Bus Route Explorer",
@ -51,10 +51,11 @@ impl BusRouteExplorer {
// TODO Refactor with sandbox route explorer
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<EventLoopMode> {
// Don't block while we're warping
let ev_mode = if let Some(ref warper) = self.warper {
if let Some(mode) = warper.event(ctx, ui) {
let ev_mode = if let Some((ref warper, id)) = self.warper {
if let Some(mode) = warper.event(ctx) {
mode
} else {
ui.primary.current_selection = Some(id);
self.warper = None;
EventLoopMode::InputOnly
}
@ -84,7 +85,7 @@ impl BusRouteExplorer {
}
let (_, (_, lane, pt)) = self.slider.get();
self.warper = Some(Warper::new(ctx, *pt, ID::Lane(*lane)));
self.warper = Some((Warper::new(ctx, *pt), ID::Lane(*lane)));
// We just created a new warper, so...
Some(EventLoopMode::Animation)
}

View File

@ -1,8 +1,8 @@
use crate::common::{CommonState, Warper};
use crate::common::CommonState;
use crate::helpers::ID;
use crate::render::DrawTurn;
use crate::ui::{ShowEverything, UI};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text, Warper};
use geom::{Distance, Polygon};
use map_model::{Traversable, LANE_THICKNESS};
use sim::AgentID;
@ -11,7 +11,7 @@ pub struct RouteExplorer {
slider: ItemSlider<Traversable>,
agent: AgentID,
entire_trace: Option<Polygon>,
warper: Option<Warper>,
warper: Option<(Warper, ID)>,
}
impl RouteExplorer {
@ -49,11 +49,13 @@ impl RouteExplorer {
.collect();
Some(RouteExplorer {
agent,
warper: Some(Warper::new(
ctx,
steps[0]
.dist_along(steps[0].length(&ui.primary.map) / 2.0, &ui.primary.map)
.0,
warper: Some((
Warper::new(
ctx,
steps[0]
.dist_along(steps[0].length(&ui.primary.map) / 2.0, &ui.primary.map)
.0,
),
match steps[0] {
Traversable::Lane(l) => ID::Lane(l),
Traversable::Turn(t) => ID::Turn(t),
@ -73,10 +75,11 @@ impl RouteExplorer {
// Done when None
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<EventLoopMode> {
// Don't block while we're warping
let ev_mode = if let Some(ref warper) = self.warper {
if let Some(mode) = warper.event(ctx, ui) {
let ev_mode = if let Some((ref warper, id)) = self.warper {
if let Some(mode) = warper.event(ctx) {
mode
} else {
ui.primary.current_selection = Some(id);
self.warper = None;
EventLoopMode::InputOnly
}
@ -106,10 +109,12 @@ impl RouteExplorer {
}
let (_, step) = self.slider.get();
self.warper = Some(Warper::new(
ctx,
step.dist_along(step.length(&ui.primary.map) / 2.0, &ui.primary.map)
.0,
self.warper = Some((
Warper::new(
ctx,
step.dist_along(step.length(&ui.primary.map) / 2.0, &ui.primary.map)
.0,
),
match step {
Traversable::Lane(l) => ID::Lane(*l),
Traversable::Turn(t) => ID::Turn(*t),

View File

@ -19,8 +19,8 @@ pub use crate::runner::{run, EventLoopMode, GUI};
pub use crate::screen_geom::ScreenPt;
pub use crate::text::{Text, HOTKEY_COLOR};
pub use crate::widgets::{
Autocomplete, ItemSlider, LogScroller, ModalMenu, ScrollingMenu, Slider, TextBox, Wizard,
WrappedWizard,
Autocomplete, ItemSlider, LogScroller, ModalMenu, ScrollingMenu, Slider, TextBox, Warper,
Wizard, WrappedWizard,
};
pub enum InputResult<T: Clone> {

View File

@ -6,6 +6,7 @@ mod screenshot;
mod scrolling_menu;
mod slider;
mod text_box;
mod warper;
mod wizard;
pub use self::autocomplete::Autocomplete;
@ -16,4 +17,5 @@ pub(crate) use self::screenshot::{screenshot_current, screenshot_everything};
pub use self::scrolling_menu::ScrollingMenu;
pub use self::slider::{ItemSlider, Slider};
pub use self::text_box::TextBox;
pub use self::warper::Warper;
pub use self::wizard::{Wizard, WrappedWizard};

View File

@ -0,0 +1,47 @@
use crate::{EventCtx, EventLoopMode};
use geom::{Line, Pt2D};
use std::time::Instant;
const ANIMATION_TIME_S: f64 = 0.5;
// TODO Should factor in zoom too
const MIN_ANIMATION_SPEED: f64 = 200.0;
pub struct Warper {
started: Instant,
line: Option<Line>,
}
impl Warper {
pub fn new(ctx: &EventCtx, pt: Pt2D) -> Warper {
Warper {
started: Instant::now(),
line: Line::maybe_new(ctx.canvas.center_to_map_pt(), pt),
}
}
pub fn event(&self, ctx: &mut EventCtx) -> Option<EventLoopMode> {
let line = self.line.as_ref()?;
// Weird to do stuff for any event?
if ctx.input.nonblocking_is_update_event() {
ctx.input.use_update_event();
}
let speed = line.length().inner_meters() / ANIMATION_TIME_S;
let total_time = if speed >= MIN_ANIMATION_SPEED {
ANIMATION_TIME_S
} else {
line.length().inner_meters() / MIN_ANIMATION_SPEED
};
let percent = abstutil::elapsed_seconds(self.started) / total_time;
if percent >= 1.0 || ctx.input.nonblocking_is_keypress_event() {
ctx.canvas.center_on_map_pt(line.pt2());
None
} else {
ctx.canvas
.center_on_map_pt(line.dist_along(line.length() * percent));
Some(EventLoopMode::Animation)
}
}
}