mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 16:02:23 +03:00
refactor Warper to an ezgui widget, to use it in fix_map_geom
This commit is contained in:
parent
b2874193ec
commit
8c055312b4
@ -52,6 +52,9 @@ TODO:
|
||||
## Map borders
|
||||
|
||||
|
||||
## Buildings
|
||||
|
||||
home / commerical / mixed-use, etc. number of households and employees from psrc.
|
||||
|
||||
## Generalizing to other cities
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(_, _) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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> {
|
||||
|
@ -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};
|
||||
|
47
ezgui/src/widgets/warper.rs
Normal file
47
ezgui/src/widgets/warper.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user