diff --git a/game/src/common/warp.rs b/game/src/common/warp.rs index babc3b409e..b7b08c05fd 100644 --- a/game/src/common/warp.rs +++ b/game/src/common/warp.rs @@ -41,18 +41,21 @@ impl State for Warping { Transition::Keep } else { if let Some(id) = self.id.clone() { - Transition::PopWithData(Box::new(move |state, ctx, app| { - // Other states pretty much don't use info panels. - if let Some(ref mut s) = state.downcast_mut::() { - let mut actions = s.contextual_actions(); - s.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::from_id(app, id), - &mut actions, - ); - } - })) + Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + // Other states pretty much don't use info panels. + if let Some(ref mut s) = state.downcast_mut::() { + let mut actions = s.contextual_actions(); + s.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::from_id(app, id), + &mut actions, + ); + } + })), + ]) } else { Transition::Pop } @@ -178,18 +181,21 @@ fn warp_to_id(ctx: &mut EventCtx, app: &mut App, line: &str) -> Option { let r = BusRouteID(idx); app.primary.map.maybe_get_br(r)?; - return Some(Transition::PopWithData(Box::new(move |state, ctx, app| { - // Other states pretty much don't use info panels. - if let Some(ref mut s) = state.downcast_mut::() { - let mut actions = s.contextual_actions(); - s.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::BusRoute(r), - &mut actions, - ); - } - }))); + return Some(Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + // Other states pretty much don't use info panels. + if let Some(ref mut s) = state.downcast_mut::() { + let mut actions = s.contextual_actions(); + s.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::BusRoute(r), + &mut actions, + ); + } + })), + ])); } 'l' => ID::Lane(LaneID(idx)), 'i' => ID::Intersection(IntersectionID(idx)), @@ -199,18 +205,21 @@ fn warp_to_id(ctx: &mut EventCtx, app: &mut App, line: &str) -> Option { let id = PersonID(idx); app.primary.sim.lookup_person(id)?; - return Some(Transition::PopWithData(Box::new(move |state, ctx, app| { - // Other states pretty much don't use info panels. - if let Some(ref mut s) = state.downcast_mut::() { - let mut actions = s.contextual_actions(); - s.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::PersonTrips(id, BTreeMap::new()), - &mut actions, - ); - } - }))); + return Some(Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + // Other states pretty much don't use info panels. + if let Some(ref mut s) = state.downcast_mut::() { + let mut actions = s.contextual_actions(); + s.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::PersonTrips(id, BTreeMap::new()), + &mut actions, + ); + } + })), + ])); } 'c' => { // This one gets more complicated. :) @@ -220,18 +229,21 @@ fn warp_to_id(ctx: &mut EventCtx, app: &mut App, line: &str) -> Option { let trip = TripID(idx); let person = app.primary.sim.trip_to_person(trip); - return Some(Transition::PopWithData(Box::new(move |state, ctx, app| { - // Other states pretty much don't use info panels. - if let Some(ref mut s) = state.downcast_mut::() { - let mut actions = s.contextual_actions(); - s.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::PersonTrips(person, OpenTrip::single(trip)), - &mut actions, - ); - } - }))); + return Some(Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + // Other states pretty much don't use info panels. + if let Some(ref mut s) = state.downcast_mut::() { + let mut actions = s.contextual_actions(); + s.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::PersonTrips(person, OpenTrip::single(trip)), + &mut actions, + ); + } + })), + ])); } _ => { return None; diff --git a/game/src/debug/mod.rs b/game/src/debug/mod.rs index e41497f945..b8bc8cb3f1 100644 --- a/game/src/debug/mod.rs +++ b/game/src/debug/mod.rs @@ -410,11 +410,14 @@ fn search_osm(filter: String, ctx: &mut EventCtx, app: &mut App) -> Transition { draw: batch.upload(ctx), }; - Transition::PopWithData(Box::new(|state, ctx, _| { - let mut mode = state.downcast_mut::().unwrap(); - mode.search_results = Some(results); - mode.reset_info(ctx); - })) + Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(|state, ctx, _| { + let mut mode = state.downcast_mut::().unwrap(); + mode.search_results = Some(results); + mode.reset_info(ctx); + })), + ]) } struct SearchResults { @@ -496,7 +499,7 @@ impl ContextualActions for Actions { close_info: &mut bool, ) -> Transition { match (id, action.as_ref()) { - (id, "hide this") => Transition::KeepWithData(Box::new(|state, ctx, app| { + (id, "hide this") => Transition::ModifyState(Box::new(|state, ctx, app| { let mode = state.downcast_mut::().unwrap(); println!("Hiding {:?}", id); app.primary.current_selection = None; diff --git a/game/src/devtools/story.rs b/game/src/devtools/story.rs index 77433e45b8..3662c4b933 100644 --- a/game/src/devtools/story.rs +++ b/game/src/devtools/story.rs @@ -184,13 +184,17 @@ impl State for StoryMapEditor { ctx, "Name this story map", Box::new(|name, _, _| { - Transition::PopWithData(Box::new(move |state, ctx, app| { - let editor = state.downcast_mut::().unwrap(); - editor.story.name = name; - editor.story.save(app); - editor.dirty = false; - editor.redo_panel(ctx); - })) + Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let editor = + state.downcast_mut::().unwrap(); + editor.story.name = name; + editor.story.save(app); + editor.dirty = false; + editor.redo_panel(ctx); + })), + ]) }), )); } else { @@ -225,12 +229,15 @@ impl State for StoryMapEditor { self.panel.rect_of("load"), choices, Box::new(|story, _, _| { - Transition::PopWithData(Box::new(move |state, ctx, _| { - let editor = state.downcast_mut::().unwrap(); - editor.story = story; - editor.dirty = false; - editor.redo_panel(ctx); - })) + Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, _| { + let editor = state.downcast_mut::().unwrap(); + editor.story = story; + editor.dirty = false; + editor.redo_panel(ctx); + })), + ]) }), )); } diff --git a/game/src/edit/traffic_signals/edits.rs b/game/src/edit/traffic_signals/edits.rs index 9877311f30..4fd945fc4d 100644 --- a/game/src/edit/traffic_signals/edits.rs +++ b/game/src/edit/traffic_signals/edits.rs @@ -74,12 +74,15 @@ impl State for ChangeDuration { PhaseType::Adaptive(dt) }; let idx = self.idx; - return Transition::PopWithData(Box::new(move |state, ctx, app| { - let editor = state.downcast_mut::().unwrap(); - editor.add_new_edit(ctx, app, idx, |ts| { - ts.stages[idx].phase_type = new_type.clone(); - }); - })); + return Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let editor = state.downcast_mut::().unwrap(); + editor.add_new_edit(ctx, app, idx, |ts| { + ts.stages[idx].phase_type = new_type.clone(); + }); + })), + ]); } _ => unreachable!(), }, @@ -145,23 +148,29 @@ pub fn edit_entire_signal( &mut Timer::throwaway(), )), Box::new(move |new_signal, _, _| { - Transition::PopWithData(Box::new(move |state, ctx, app| { + Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let editor = state.downcast_mut::().unwrap(); + editor.add_new_edit(ctx, app, 0, |ts| { + *ts = new_signal.clone(); + }); + })), + ]) + }), + )), + x if x == all_walk => Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let mut new_signal = app.primary.map.get_traffic_signal(i).clone(); + if new_signal.convert_to_ped_scramble() { let editor = state.downcast_mut::().unwrap(); editor.add_new_edit(ctx, app, 0, |ts| { *ts = new_signal.clone(); }); - })) - }), - )), - x if x == all_walk => Transition::PopWithData(Box::new(move |state, ctx, app| { - let mut new_signal = app.primary.map.get_traffic_signal(i).clone(); - if new_signal.convert_to_ped_scramble() { - let editor = state.downcast_mut::().unwrap(); - editor.add_new_edit(ctx, app, 0, |ts| { - *ts = new_signal.clone(); - }); - } - })), + } + })), + ]), x if x == stop_sign => { original.apply(app); @@ -195,19 +204,22 @@ pub fn edit_entire_signal( Transition::Multi(vec![Transition::Pop, Transition::Pop]) } } - x if x == reset => Transition::PopWithData(Box::new(move |state, ctx, app| { - let editor = state.downcast_mut::().unwrap(); - let new_signal = ControlTrafficSignal::get_possible_policies( - &app.primary.map, - i, - &mut Timer::throwaway(), - ) - .remove(0) - .1; - editor.add_new_edit(ctx, app, 0, |ts| { - *ts = new_signal.clone(); - }); - })), + x if x == reset => Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let editor = state.downcast_mut::().unwrap(); + let new_signal = ControlTrafficSignal::get_possible_policies( + &app.primary.map, + i, + &mut Timer::throwaway(), + ) + .remove(0) + .1; + editor.add_new_edit(ctx, app, 0, |ts| { + *ts = new_signal.clone(); + }); + })), + ]), _ => unreachable!(), }), ) diff --git a/game/src/game.rs b/game/src/game.rs index 89cacb8c37..20dc9a0fe3 100644 --- a/game/src/game.rs +++ b/game/src/game.rs @@ -96,8 +96,7 @@ impl Game { } true } - Transition::PopWithData(cb) => { - self.states.pop().unwrap().on_destroy(ctx, &mut self.app); + Transition::ModifyState(cb) => { cb(self.states.last_mut().unwrap(), ctx, &mut self.app); true } @@ -108,10 +107,6 @@ impl Game { self.states.extend(new_states); true } - Transition::KeepWithData(cb) => { - cb(self.states.last_mut().unwrap(), ctx, &mut self.app); - true - } Transition::Push(state) => { self.states.push(state); true @@ -276,9 +271,9 @@ pub enum Transition { KeepWithMouseover, Pop, // If a state needs to pass data back to the parent, use this. Sadly, runtime type casting. - // TODO Collapse some of these cases too - PopWithData(Box, &mut EventCtx, &mut App)>), - KeepWithData(Box, &mut EventCtx, &mut App)>), + ModifyState(Box, &mut EventCtx, &mut App)>), + // TODO This is like Replace + ModifyState, then returning a few Push's from the callback. Not + // sure how to express it in terms of the others without complicating ModifyState everywhere. ReplaceWithData( Box, &mut EventCtx, &mut App) -> Vec>>, ), diff --git a/game/src/sandbox/dashboards/misc.rs b/game/src/sandbox/dashboards/misc.rs index a46e15c784..acdf11110e 100644 --- a/game/src/sandbox/dashboards/misc.rs +++ b/game/src/sandbox/dashboards/misc.rs @@ -177,16 +177,19 @@ impl State for TransitRoutes { } }; - Transition::PopWithData(Box::new(move |state, ctx, app| { - let sandbox = state.downcast_mut::().unwrap(); - let mut actions = sandbox.contextual_actions(); - sandbox.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::BusRoute(route), - &mut actions, - ) - })) + Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let sandbox = state.downcast_mut::().unwrap(); + let mut actions = sandbox.contextual_actions(); + sandbox.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::BusRoute(route), + &mut actions, + ) + })), + ]) } fn draw_baselayer(&self) -> DrawBaselayer { diff --git a/game/src/sandbox/dashboards/parking_overhead.rs b/game/src/sandbox/dashboards/parking_overhead.rs index 21fc2397d7..57d5db6366 100644 --- a/game/src/sandbox/dashboards/parking_overhead.rs +++ b/game/src/sandbox/dashboards/parking_overhead.rs @@ -109,16 +109,19 @@ impl State for ParkingOverhead { if let Ok(idx) = x.parse::() { let trip = TripID(idx); let person = app.primary.sim.trip_to_person(trip); - return Transition::PopWithData(Box::new(move |state, ctx, app| { - let sandbox = state.downcast_mut::().unwrap(); - let mut actions = sandbox.contextual_actions(); - sandbox.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::PersonTrips(person, OpenTrip::single(trip)), - &mut actions, - ); - })); + return Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let sandbox = state.downcast_mut::().unwrap(); + let mut actions = sandbox.contextual_actions(); + sandbox.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::PersonTrips(person, OpenTrip::single(trip)), + &mut actions, + ); + })), + ]); } return DashTab::ParkingOverhead.transition(ctx, app, x); } diff --git a/game/src/sandbox/dashboards/trip_table.rs b/game/src/sandbox/dashboards/trip_table.rs index b8db0a981d..968e0beb12 100644 --- a/game/src/sandbox/dashboards/trip_table.rs +++ b/game/src/sandbox/dashboards/trip_table.rs @@ -121,16 +121,19 @@ impl State for TripTable { if let Ok(idx) = x.parse::() { let trip = TripID(idx); let person = app.primary.sim.trip_to_person(trip); - return Transition::PopWithData(Box::new(move |state, ctx, app| { - let sandbox = state.downcast_mut::().unwrap(); - let mut actions = sandbox.contextual_actions(); - sandbox.controls.common.as_mut().unwrap().launch_info_panel( - ctx, - app, - Tab::PersonTrips(person, OpenTrip::single(trip)), - &mut actions, - ); - })); + return Transition::Multi(vec![ + Transition::Pop, + Transition::ModifyState(Box::new(move |state, ctx, app| { + let sandbox = state.downcast_mut::().unwrap(); + let mut actions = sandbox.contextual_actions(); + sandbox.controls.common.as_mut().unwrap().launch_info_panel( + ctx, + app, + Tab::PersonTrips(person, OpenTrip::single(trip)), + &mut actions, + ); + })), + ]); } return DashTab::TripTable.transition(ctx, app, x); } diff --git a/game/src/sandbox/mod.rs b/game/src/sandbox/mod.rs index 75ec1e40b4..b792bde543 100644 --- a/game/src/sandbox/mod.rs +++ b/game/src/sandbox/mod.rs @@ -468,7 +468,7 @@ impl ContextualActions for Actions { } (_, "follow (run the simulation)") => { *close_panel = false; - Transition::KeepWithData(Box::new(|state, ctx, app| { + Transition::ModifyState(Box::new(|state, ctx, app| { let mode = state.downcast_mut::().unwrap(); let speed = mode.controls.speed.as_mut().unwrap(); assert!(speed.is_paused()); @@ -477,7 +477,7 @@ impl ContextualActions for Actions { } (_, "unfollow (pause the simulation)") => { *close_panel = false; - Transition::KeepWithData(Box::new(|state, ctx, app| { + Transition::ModifyState(Box::new(|state, ctx, app| { let mode = state.downcast_mut::().unwrap(); let speed = mode.controls.speed.as_mut().unwrap(); assert!(!speed.is_paused());