actually, with the previous fix, now we can get rid of all the transitions that ask for Animation when entering a new state!

This commit is contained in:
Dustin Carlino 2020-01-22 11:57:37 -08:00
parent 75281ed354
commit 2a194a9bea
13 changed files with 135 additions and 230 deletions

View File

@ -6,9 +6,8 @@ use crate::render::{dashed_lines, MIN_ZOOM_FOR_DETAIL};
use crate::ui::UI;
use abstutil::prettyprint_usize;
use ezgui::{
hotkey, Button, Color, Composite, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, Plot, RewriteColor, Series, Text,
VerticalAlignment,
hotkey, Button, Color, Composite, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment,
Key, Line, ManagedWidget, Outcome, Plot, RewriteColor, Series, Text, VerticalAlignment,
};
use geom::{Circle, Distance, Duration, Statistic, Time};
use map_model::{IntersectionID, RoadID};
@ -173,16 +172,13 @@ impl InfoPanel {
} else if action == "jump to object" {
return (
false,
Some(Transition::PushWithMode(
Warping::new(
ctx,
self.id.canonical_point(&ui.primary).unwrap(),
Some(10.0),
Some(self.id.clone()),
&mut ui.primary,
),
EventLoopMode::Animation,
)),
Some(Transition::Push(Warping::new(
ctx,
self.id.canonical_point(&ui.primary).unwrap(),
Some(10.0),
Some(self.id.clone()),
&mut ui.primary,
))),
);
} else {
ui.primary.current_selection = Some(self.id.clone());

View File

@ -5,9 +5,9 @@ use crate::render::{AgentColorScheme, MIN_ZOOM_FOR_DETAIL};
use crate::ui::UI;
use abstutil::clamp;
use ezgui::{
hotkey, Button, Choice, Color, Composite, DrawBoth, EventCtx, EventLoopMode, Filler, GeomBatch,
GfxCtx, HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, ScreenDims,
ScreenPt, Text, VerticalAlignment,
hotkey, Button, Choice, Color, Composite, DrawBoth, EventCtx, Filler, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, ScreenDims, ScreenPt,
Text, VerticalAlignment,
};
use geom::{Circle, Distance, Polygon, Pt2D, Ring};
@ -123,28 +123,22 @@ impl Minimap {
return Some(Transition::Push(shortcuts::ChoosingShortcut::new()));
}
x if x == "zoom out fully" => {
return Some(Transition::PushWithMode(
Warping::new(
ctx,
ui.primary.map.get_bounds().get_rectangle().center(),
Some(ctx.canvas.min_zoom()),
None,
&mut ui.primary,
),
EventLoopMode::Animation,
));
return Some(Transition::Push(Warping::new(
ctx,
ui.primary.map.get_bounds().get_rectangle().center(),
Some(ctx.canvas.min_zoom()),
None,
&mut ui.primary,
)));
}
x if x == "zoom in fully" => {
return Some(Transition::PushWithMode(
Warping::new(
ctx,
ctx.canvas.center_to_map_pt(),
Some(10.0),
None,
&mut ui.primary,
),
EventLoopMode::Animation,
));
return Some(Transition::Push(Warping::new(
ctx,
ctx.canvas.center_to_map_pt(),
Some(10.0),
None,
&mut ui.primary,
)));
}
x if x == "change overlay" => {
return Overlays::change_overlays(ctx);

View File

@ -2,7 +2,7 @@ use crate::common::Warping;
use crate::game::{State, Transition};
use crate::helpers::ID;
use crate::ui::UI;
use ezgui::{Autocomplete, EventCtx, EventLoopMode, GfxCtx, InputResult};
use ezgui::{Autocomplete, EventCtx, GfxCtx, InputResult};
use map_model::RoadID;
use std::collections::HashSet;
@ -79,16 +79,13 @@ impl State for CrossStreet {
// Just warp to somewhere on the first road
let road = map.get_r(self.first);
println!("Warping to {}", road.get_name());
Transition::ReplaceWithMode(
Warping::new(
ctx,
road.center_pts.dist_along(road.center_pts.length() / 2.0).0,
None,
Some(ID::Lane(road.all_lanes()[0])),
&mut ui.primary,
),
EventLoopMode::Animation,
)
Transition::Replace(Warping::new(
ctx,
road.center_pts.dist_along(road.center_pts.length() / 2.0).0,
None,
Some(ID::Lane(road.all_lanes()[0])),
&mut ui.primary,
))
}
InputResult::Done(name, ids) => {
println!(
@ -102,16 +99,13 @@ impl State for CrossStreet {
} else {
map.get_i(road.dst_i).polygon.center()
};
Transition::ReplaceWithMode(
Warping::new(
ctx,
pt,
None,
Some(ID::Lane(road.all_lanes()[0])),
&mut ui.primary,
),
EventLoopMode::Animation,
)
Transition::Replace(Warping::new(
ctx,
pt,
None,
Some(ID::Lane(road.all_lanes()[0])),
&mut ui.primary,
))
}
InputResult::StillActive => Transition::Keep,
}

View File

@ -6,9 +6,9 @@ use crate::managed::{ManagedGUIState, WrappedComposite, WrappedOutcome};
use crate::ui::UI;
use abstutil::{prettyprint_usize, Counter};
use ezgui::{
hotkey, Button, Color, Composite, DrawBoth, Drawable, EventCtx, EventLoopMode, GeomBatch,
GfxCtx, Histogram, HorizontalAlignment, JustDraw, Key, Line, ManagedWidget, Outcome, Plot,
RewriteColor, Series, Text, VerticalAlignment,
hotkey, Button, Color, Composite, DrawBoth, Drawable, EventCtx, GeomBatch, GfxCtx, Histogram,
HorizontalAlignment, JustDraw, Key, Line, ManagedWidget, Outcome, Plot, RewriteColor, Series,
Text, VerticalAlignment,
};
use geom::{Circle, Distance, Duration, PolyLine, Polygon, Pt2D, Statistic, Time};
use map_model::{BusRouteID, IntersectionID};
@ -122,16 +122,13 @@ impl Overlays {
"intersection demand" => {
let id = ID::Intersection(i);
ui.overlay = orig_overlay;
return Some(Transition::PushWithMode(
Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
Some(10.0),
Some(id.clone()),
&mut ui.primary,
),
EventLoopMode::Animation,
));
return Some(Transition::Push(Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
Some(10.0),
Some(id.clone()),
&mut ui.primary,
)));
}
"X" => {
ui.overlay = Overlays::Inactive;
@ -671,16 +668,13 @@ impl Overlays {
c = c.cb(
&format!("Stop {}", idx + 1),
Box::new(move |ctx, ui| {
Some(Transition::PushWithMode(
Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
Some(4.0),
Some(id.clone()),
&mut ui.primary,
),
EventLoopMode::Animation,
))
Some(Transition::Push(Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
Some(4.0),
Some(id.clone()),
&mut ui.primary,
)))
}),
);
}

View File

@ -2,7 +2,7 @@ use crate::common::Warping;
use crate::game::{State, Transition, WizardState};
use crate::ui::UI;
use abstutil::{Cloneable, Timer};
use ezgui::{Choice, EventCtx, EventLoopMode, Key, Wizard};
use ezgui::{Choice, EventCtx, Key, Wizard};
use geom::{LonLat, Pt2D};
use serde_derive::{Deserialize, Serialize};
@ -73,15 +73,12 @@ fn choose_shortcut(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<
wizard.abort();
Some(Transition::Pop)
} else {
Some(Transition::ReplaceWithMode(
Warping::new(
ctx,
Pt2D::forcibly_from_gps(s.center, &ui.primary.map.get_gps_bounds()),
Some(s.cam_zoom),
None,
&mut ui.primary,
),
EventLoopMode::Animation,
))
Some(Transition::Replace(Warping::new(
ctx,
Pt2D::forcibly_from_gps(s.center, &ui.primary.map.get_gps_bounds()),
Some(s.cam_zoom),
None,
&mut ui.primary,
)))
}
}

View File

@ -1,7 +1,7 @@
use crate::game::{State, Transition, WizardState};
use crate::helpers::ID;
use crate::ui::{PerMapUI, UI};
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Warper, Wizard};
use ezgui::{EventCtx, GfxCtx, Warper, Wizard};
use geom::Pt2D;
use map_model::{AreaID, BuildingID, IntersectionID, LaneID, RoadID};
use sim::{PedestrianID, TripID};
@ -20,10 +20,13 @@ fn warp_to(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transiti
let mut wizard = wiz.wrap(ctx);
let to = wizard.input_string("Warp to what?")?;
if let Some((id, pt, cam_zoom)) = warp_point(&to, &ui.primary) {
return Some(Transition::ReplaceWithMode(
Warping::new(ctx, pt, Some(cam_zoom), id, &mut ui.primary),
EventLoopMode::Animation,
));
return Some(Transition::Replace(Warping::new(
ctx,
pt,
Some(cam_zoom),
id,
&mut ui.primary,
)));
}
wizard.acknowledge("Bad warp ID", || vec![format!("{} isn't a valid ID", to)])?;
Some(Transition::Pop)

View File

@ -17,8 +17,7 @@ use crate::sandbox::{GameplayMode, SandboxMode};
use crate::ui::{PerMapUI, ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
hotkey, lctrl, Choice, Color, EventCtx, EventLoopMode, GfxCtx, Key, Line, ModalMenu, Text,
WrappedWizard,
hotkey, lctrl, Choice, Color, EventCtx, GfxCtx, Key, Line, ModalMenu, Text, WrappedWizard,
};
use map_model::{ControlStopSign, ControlTrafficSignal, EditCmd, LaneID, MapEdits};
use sim::Sim;
@ -198,16 +197,13 @@ impl State for EditMode {
EditCmd::UncloseIntersection(id, _) => ID::Intersection(id),
};
apply_map_edits(&mut ui.primary, &ui.cs, ctx, edits);
return Transition::PushWithMode(
Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
None,
Some(id),
&mut ui.primary,
),
EventLoopMode::Animation,
);
return Transition::Push(Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
None,
Some(id),
&mut ui.primary,
));
}
if let Some(t) = self.common.event(ctx, ui) {

View File

@ -705,10 +705,9 @@ fn make_previewer(i: IntersectionID, phase: usize, suspended_sim: Sim) -> Box<dy
}
_ => unreachable!(),
};
Some(Transition::ReplaceWithMode(
Box::new(PreviewTrafficSignal::new(ctx, ui)),
EventLoopMode::Animation,
))
Some(Transition::Replace(Box::new(PreviewTrafficSignal::new(
ctx, ui,
))))
}))
}

View File

@ -38,30 +38,17 @@ impl GUI for Game {
fn event(&mut self, ctx: &mut EventCtx) -> EventLoopMode {
self.ui.per_obj.reset();
// First rewrite the transitions to explicitly have EventLoopMode, to avoid duplicated
// code.
let transition = match self.states.last_mut().unwrap().event(ctx, &mut self.ui) {
Transition::Keep => Transition::KeepWithMode(EventLoopMode::InputOnly),
Transition::Pop => Transition::PopWithMode(EventLoopMode::InputOnly),
Transition::Push(state) => Transition::PushWithMode(state, EventLoopMode::InputOnly),
Transition::Replace(state) => {
Transition::ReplaceWithMode(state, EventLoopMode::InputOnly)
}
Transition::PopThenReplace(state) => {
Transition::PopThenReplaceWithMode(state, EventLoopMode::InputOnly)
}
x => x,
};
let transition = self.states.last_mut().unwrap().event(ctx, &mut self.ui);
let (ev_mode, new_state) = match transition {
Transition::Keep => (EventLoopMode::InputOnly, false),
Transition::KeepWithMode(evmode) => (evmode, false),
Transition::PopWithMode(evmode) => {
Transition::Pop => {
self.states.pop().unwrap().on_destroy(ctx, &mut self.ui);
if self.states.is_empty() {
self.before_quit(ctx.canvas);
std::process::exit(0);
}
(evmode, true)
(EventLoopMode::InputOnly, true)
}
Transition::PopWithData(cb) => {
self.states.pop().unwrap().on_destroy(ctx, &mut self.ui);
@ -73,25 +60,25 @@ impl GUI for Game {
self.states.pop().unwrap().on_destroy(ctx, &mut self.ui);
(EventLoopMode::InputOnly, true)
}
Transition::PushWithMode(state, evmode) => {
Transition::Push(state) => {
self.states
.last_mut()
.unwrap()
.on_suspend(ctx, &mut self.ui);
self.states.push(state);
(evmode, true)
(EventLoopMode::InputOnly, true)
}
Transition::ReplaceWithMode(state, evmode) => {
Transition::Replace(state) => {
self.states.pop().unwrap().on_destroy(ctx, &mut self.ui);
self.states.push(state);
(evmode, true)
(EventLoopMode::InputOnly, true)
}
Transition::PopThenReplaceWithMode(state, evmode) => {
Transition::PopThenReplace(state) => {
self.states.pop().unwrap().on_destroy(ctx, &mut self.ui);
assert!(!self.states.is_empty());
self.states.pop().unwrap().on_destroy(ctx, &mut self.ui);
self.states.push(state);
(evmode, true)
(EventLoopMode::InputOnly, true)
}
Transition::Clear(state) => {
while !self.states.is_empty() {
@ -113,7 +100,6 @@ impl GUI for Game {
self.states.push(s2);
return EventLoopMode::InputOnly;
}
_ => unreachable!(),
};
self.ui.per_obj.assert_chosen_used();
if new_state {
@ -198,8 +184,8 @@ pub trait State: downcast_rs::Downcast {
downcast_rs::impl_downcast!(State);
pub enum Transition {
// These variants imply EventLoopMode::InputOnly.
Keep,
KeepWithMode(EventLoopMode),
Pop,
PopTwice,
// If a state needs to pass data back to the parent, use this. Sadly, runtime type casting.
@ -210,13 +196,6 @@ pub enum Transition {
Clear(Box<dyn State>),
ApplyObjectAction(String),
PushTwice(Box<dyn State>, Box<dyn State>),
// These don't.
KeepWithMode(EventLoopMode),
PopWithMode(EventLoopMode),
PushWithMode(Box<dyn State>, EventLoopMode),
ReplaceWithMode(Box<dyn State>, EventLoopMode),
PopThenReplaceWithMode(Box<dyn State>, EventLoopMode),
}
pub struct WizardState {

View File

@ -7,8 +7,8 @@ use crate::sandbox::{GameplayMode, SandboxMode};
use crate::ui::UI;
use abstutil::{prettyprint_usize, Counter, MultiMap, WeightedUsizeChoice};
use ezgui::{
hotkey, Choice, Color, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, Line,
ModalMenu, Text, Wizard, WrappedWizard,
hotkey, Choice, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, ModalMenu, Text,
Wizard, WrappedWizard,
};
use geom::{Distance, Duration, PolyLine, Time};
use map_model::{BuildingID, IntersectionID, Map, Neighborhood};
@ -474,16 +474,13 @@ fn make_trip_picker(
.collect()
})?
.1;
Some(Transition::ReplaceWithMode(
Warping::new(
ctx,
warp_to.canonical_point(&ui.primary).unwrap(),
None,
Some(warp_to),
&mut ui.primary,
),
EventLoopMode::Animation,
))
Some(Transition::Replace(Warping::new(
ctx,
warp_to.canonical_point(&ui.primary).unwrap(),
None,
Some(warp_to),
&mut ui.primary,
)))
}))
}

View File

@ -131,24 +131,16 @@ pub fn main_menu(ctx: &mut EventCtx, ui: &UI) -> Box<dyn State> {
)
.cb(
"Tutorial",
Box::new(|ctx, ui| {
Some(Transition::PushWithMode(
TutorialMode::new(ctx, ui),
EventLoopMode::Animation,
))
}),
Box::new(|ctx, ui| Some(Transition::Push(TutorialMode::new(ctx, ui)))),
)
.cb(
"Sandbox mode",
Box::new(|ctx, ui| {
Some(Transition::PushWithMode(
Box::new(SandboxMode::new(
ctx,
ui,
GameplayMode::PlayScenario("random".to_string()),
)),
EventLoopMode::Animation,
))
Some(Transition::Push(Box::new(SandboxMode::new(
ctx,
ui,
GameplayMode::PlayScenario("random".to_string()),
))))
}),
)
.cb(

View File

@ -183,13 +183,10 @@ impl SpeedControls {
.cb(
"step forwards 1 hour",
Box::new(|_, ui| {
Some(Transition::PushWithMode(
Box::new(TimeWarpScreen {
target: ui.primary.sim.time() + Duration::hours(1),
started: Instant::now(),
}),
EventLoopMode::Animation,
))
Some(Transition::Push(Box::new(TimeWarpScreen {
target: ui.primary.sim.time() + Duration::hours(1),
started: Instant::now(),
})))
}),
)
}
@ -316,13 +313,10 @@ fn jump_to_time(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Tra
ui.primary.sim.time(),
Time::END_OF_DAY,
)?;
Some(Transition::ReplaceWithMode(
Box::new(TimeWarpScreen {
target,
started: Instant::now(),
}),
EventLoopMode::Animation,
))
Some(Transition::Replace(Box::new(TimeWarpScreen {
target,
started: Instant::now(),
})))
}
// Display a nicer screen for jumping forwards in time, allowing cancellation.

View File

@ -55,16 +55,13 @@ impl State for TutorialMode {
if let Stage::Msg { ref warp_pt, .. } = self.state.stage() {
if let Some(id) = warp_pt {
self.warped = true;
return Transition::PushWithMode(
Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
Some(4.0),
Some(id.clone()),
&mut ui.primary,
),
EventLoopMode::Animation,
);
return Transition::Push(Warping::new(
ctx,
id.canonical_point(&ui.primary).unwrap(),
Some(4.0),
Some(id.clone()),
&mut ui.primary,
));
}
}
}
@ -78,17 +75,11 @@ impl State for TutorialMode {
}
"<" => {
self.state.current -= 1;
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
">" => {
self.state.current += 1;
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
_ => unreachable!(),
},
@ -104,10 +95,7 @@ impl State for TutorialMode {
ui.primary.clear_sim();
return Transition::Pop;
} else {
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
}
_ => unreachable!(),
@ -135,10 +123,7 @@ impl State for TutorialMode {
}
Some(WrappedOutcome::Clicked(x)) => match x {
x if x == "reset to midnight" => {
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
_ => unreachable!(),
},
@ -166,10 +151,7 @@ impl State for TutorialMode {
&& ui.per_obj.left_click(ctx, "put out the... fire?")
{
self.state.next();
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
} else if interact == "Go hit 3 different lanes on one road" {
if let Some(ID::Lane(l)) = ui.primary.current_selection {
@ -177,10 +159,7 @@ impl State for TutorialMode {
self.hit_roads.insert(l);
if self.hit_roads.len() == 3 {
self.state.next();
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
} else {
return Transition::Push(msg(
"You hit the road",
@ -195,10 +174,7 @@ impl State for TutorialMode {
} else if interact == "Wait until 5pm" {
if ui.primary.sim.time() >= Time::START_OF_DAY + Duration::hours(17) {
self.state.next();
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
} else if interact == "Escort the first northbound car to their home" {
if ui.primary.current_selection == Some(ID::Building(BuildingID(2322)))
@ -207,10 +183,7 @@ impl State for TutorialMode {
match ui.primary.sim.trip_to_agent(TripID(24)) {
TripResult::TripDone => {
self.state.next();
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
_ => {
return Transition::Push(msg(
@ -250,10 +223,7 @@ impl State for TutorialMode {
));
}
self.state.next();
return Transition::ReplaceWithMode(
self.state.make_state(ctx, ui),
EventLoopMode::Animation,
);
return Transition::Replace(self.state.make_state(ctx, ui));
}
}
}