mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 02:33:54 +03:00
Slightly simplify some plumbing of variables through nested closures, by
remembering that FnOnce exists
This commit is contained in:
parent
5ef48a5d1c
commit
81dae1e39c
@ -15,14 +15,15 @@ pub struct CityPicker {
|
|||||||
// In untranslated screen-space
|
// In untranslated screen-space
|
||||||
regions: Vec<(String, Color, Polygon)>,
|
regions: Vec<(String, Color, Polygon)>,
|
||||||
selected: Option<usize>,
|
selected: Option<usize>,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App) -> Transition>,
|
// Wrapped in an Option just to make calling from event() work.
|
||||||
|
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut App) -> Transition>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CityPicker {
|
impl CityPicker {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: &mut EventCtx,
|
ctx: &mut EventCtx,
|
||||||
app: &mut App,
|
app: &mut App,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App) -> Transition>,
|
on_load: Box<dyn FnOnce(&mut EventCtx, &mut App) -> Transition>,
|
||||||
) -> Box<dyn State> {
|
) -> Box<dyn State> {
|
||||||
app.primary.current_selection = None;
|
app.primary.current_selection = None;
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ impl CityPicker {
|
|||||||
Box::new(CityPicker {
|
Box::new(CityPicker {
|
||||||
regions,
|
regions,
|
||||||
selected: None,
|
selected: None,
|
||||||
on_load,
|
on_load: Some(on_load),
|
||||||
panel: Panel::new(
|
panel: Panel::new(
|
||||||
Widget::col(vec![
|
Widget::col(vec![
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
@ -111,13 +112,11 @@ impl State for CityPicker {
|
|||||||
return Transition::Pop;
|
return Transition::Pop;
|
||||||
}
|
}
|
||||||
name => {
|
name => {
|
||||||
let on_load =
|
|
||||||
std::mem::replace(&mut self.on_load, Box::new(|_, _| Transition::Keep));
|
|
||||||
return Transition::Replace(MapLoader::new(
|
return Transition::Replace(MapLoader::new(
|
||||||
ctx,
|
ctx,
|
||||||
app,
|
app,
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
on_load,
|
self.on_load.take().unwrap(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -152,9 +151,12 @@ impl State for CityPicker {
|
|||||||
.per_obj
|
.per_obj
|
||||||
.left_click(ctx, format!("switch to {}", nice_map_name(name)))
|
.left_click(ctx, format!("switch to {}", nice_map_name(name)))
|
||||||
{
|
{
|
||||||
let on_load =
|
return Transition::Replace(MapLoader::new(
|
||||||
std::mem::replace(&mut self.on_load, Box::new(|_, _| Transition::Keep));
|
ctx,
|
||||||
return Transition::Replace(MapLoader::new(ctx, app, name.to_string(), on_load));
|
app,
|
||||||
|
name.to_string(),
|
||||||
|
self.on_load.take().unwrap(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,7 +743,7 @@ impl ScreenshotTest {
|
|||||||
todo_maps.pop().unwrap().to_string(),
|
todo_maps.pop().unwrap().to_string(),
|
||||||
Box::new(move |_, _| {
|
Box::new(move |_, _| {
|
||||||
Transition::Replace(Box::new(ScreenshotTest {
|
Transition::Replace(Box::new(ScreenshotTest {
|
||||||
todo_maps: todo_maps.clone(),
|
todo_maps,
|
||||||
screenshot_done: false,
|
screenshot_done: false,
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
|
@ -101,7 +101,6 @@ impl EditMode {
|
|||||||
app.primary.sim.handle_live_edits(&app.primary.map);
|
app.primary.sim.handle_live_edits(&app.primary.map);
|
||||||
Transition::Pop
|
Transition::Pop
|
||||||
} else {
|
} else {
|
||||||
let resume_time = old_sim.time();
|
|
||||||
Transition::Multi(vec![
|
Transition::Multi(vec![
|
||||||
Transition::Pop,
|
Transition::Pop,
|
||||||
Transition::Replace(SandboxMode::async_new(
|
Transition::Replace(SandboxMode::async_new(
|
||||||
@ -112,7 +111,7 @@ impl EditMode {
|
|||||||
vec![Transition::Push(TimeWarpScreen::new(
|
vec![Transition::Push(TimeWarpScreen::new(
|
||||||
ctx,
|
ctx,
|
||||||
app,
|
app,
|
||||||
resume_time,
|
old_sim.time(),
|
||||||
None,
|
None,
|
||||||
))]
|
))]
|
||||||
}),
|
}),
|
||||||
|
@ -22,10 +22,12 @@ impl MapLoader {
|
|||||||
ctx: &mut EventCtx,
|
ctx: &mut EventCtx,
|
||||||
app: &App,
|
app: &App,
|
||||||
name: String,
|
name: String,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App) -> Transition>,
|
on_load: Box<dyn FnOnce(&mut EventCtx, &mut App) -> Transition>,
|
||||||
) -> Box<dyn State> {
|
) -> Box<dyn State> {
|
||||||
if app.primary.map.get_name() == &name {
|
if app.primary.map.get_name() == &name {
|
||||||
return Box::new(MapAlreadyLoaded { on_load });
|
return Box::new(MapAlreadyLoaded {
|
||||||
|
on_load: Some(on_load),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO If we want to load montlake on the web, just pull from bundled data.
|
// TODO If we want to load montlake on the web, just pull from bundled data.
|
||||||
@ -66,11 +68,11 @@ impl MapLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct MapAlreadyLoaded {
|
struct MapAlreadyLoaded {
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App) -> Transition>,
|
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut App) -> Transition>>,
|
||||||
}
|
}
|
||||||
impl State for MapAlreadyLoaded {
|
impl State for MapAlreadyLoaded {
|
||||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||||
(self.on_load)(ctx, app)
|
(self.on_load.take().unwrap())(ctx, app)
|
||||||
}
|
}
|
||||||
fn draw(&self, _: &mut GfxCtx, _: &App) {}
|
fn draw(&self, _: &mut GfxCtx, _: &App) {}
|
||||||
}
|
}
|
||||||
@ -81,16 +83,21 @@ mod native_loader {
|
|||||||
|
|
||||||
pub struct FileLoader<T> {
|
pub struct FileLoader<T> {
|
||||||
path: String,
|
path: String,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App, Option<T>) -> Transition>,
|
// Wrapped in an Option just to make calling from event() work. Technically this is unsafe
|
||||||
|
// if a caller fails to pop the FileLoader state in their transitions!
|
||||||
|
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut App, Option<T>) -> Transition>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static + DeserializeOwned> FileLoader<T> {
|
impl<T: 'static + DeserializeOwned> FileLoader<T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_: &mut EventCtx,
|
_: &mut EventCtx,
|
||||||
path: String,
|
path: String,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App, Option<T>) -> Transition>,
|
on_load: Box<dyn FnOnce(&mut EventCtx, &mut App, Option<T>) -> Transition>,
|
||||||
) -> Box<dyn State> {
|
) -> Box<dyn State> {
|
||||||
Box::new(FileLoader { path, on_load })
|
Box::new(FileLoader {
|
||||||
|
path,
|
||||||
|
on_load: Some(on_load),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +105,7 @@ mod native_loader {
|
|||||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||||
ctx.loading_screen(format!("load {}", self.path), |ctx, timer| {
|
ctx.loading_screen(format!("load {}", self.path), |ctx, timer| {
|
||||||
// Assumes a binary file
|
// Assumes a binary file
|
||||||
(self.on_load)(
|
(self.on_load.take().unwrap())(
|
||||||
ctx,
|
ctx,
|
||||||
app,
|
app,
|
||||||
abstutil::maybe_read_binary(self.path.clone(), timer).ok(),
|
abstutil::maybe_read_binary(self.path.clone(), timer).ok(),
|
||||||
@ -130,7 +137,7 @@ mod wasm_loader {
|
|||||||
// compatible with winit's event loop.
|
// compatible with winit's event loop.
|
||||||
pub struct FileLoader<T> {
|
pub struct FileLoader<T> {
|
||||||
response: oneshot::Receiver<Vec<u8>>,
|
response: oneshot::Receiver<Vec<u8>>,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App, Option<T>) -> Transition>,
|
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut App, Option<T>) -> Transition>>,
|
||||||
panel: Panel,
|
panel: Panel,
|
||||||
started: Instant,
|
started: Instant,
|
||||||
url: String,
|
url: String,
|
||||||
@ -140,7 +147,7 @@ mod wasm_loader {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: &mut EventCtx,
|
ctx: &mut EventCtx,
|
||||||
path: String,
|
path: String,
|
||||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App, Option<T>) -> Transition>,
|
on_load: Box<dyn FnOnce(&mut EventCtx, &mut App, Option<T>) -> Transition>,
|
||||||
) -> Box<dyn State> {
|
) -> Box<dyn State> {
|
||||||
let url = if cfg!(feature = "wasm_s3") {
|
let url = if cfg!(feature = "wasm_s3") {
|
||||||
format!(
|
format!(
|
||||||
@ -177,7 +184,7 @@ mod wasm_loader {
|
|||||||
|
|
||||||
Box::new(FileLoader {
|
Box::new(FileLoader {
|
||||||
response: rx,
|
response: rx,
|
||||||
on_load,
|
on_load: Some(on_load),
|
||||||
panel: ctx.make_loading_screen(Text::from(Line(format!("Loading {}...", url)))),
|
panel: ctx.make_loading_screen(Text::from(Line(format!("Loading {}...", url)))),
|
||||||
started: Instant::now(),
|
started: Instant::now(),
|
||||||
url,
|
url,
|
||||||
@ -194,7 +201,7 @@ mod wasm_loader {
|
|||||||
|
|
||||||
// TODO Plumb failures
|
// TODO Plumb failures
|
||||||
let obj: T = abstutil::from_binary(&resp).unwrap();
|
let obj: T = abstutil::from_binary(&resp).unwrap();
|
||||||
return (self.on_load)(ctx, app, Some(obj));
|
return (self.on_load.take().unwrap())(ctx, app, Some(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.panel = ctx.make_loading_screen(Text::from_multiline(vec![
|
self.panel = ctx.make_loading_screen(Text::from_multiline(vec![
|
||||||
|
@ -417,10 +417,7 @@ impl State for Proposals {
|
|||||||
Box::new(move |ctx, app| {
|
Box::new(move |ctx, app| {
|
||||||
// Apply edits before setting up the sandbox, for simplicity
|
// Apply edits before setting up the sandbox, for simplicity
|
||||||
let maybe_err = ctx.loading_screen("apply edits", |ctx, mut timer| {
|
let maybe_err = ctx.loading_screen("apply edits", |ctx, mut timer| {
|
||||||
match PermanentMapEdits::from_permanent(
|
match PermanentMapEdits::from_permanent(edits, &app.primary.map) {
|
||||||
edits.clone(),
|
|
||||||
&app.primary.map,
|
|
||||||
) {
|
|
||||||
Ok(edits) => {
|
Ok(edits) => {
|
||||||
apply_map_edits(ctx, app, edits);
|
apply_map_edits(ctx, app, edits);
|
||||||
app.primary
|
app.primary
|
||||||
|
@ -65,7 +65,7 @@ impl GameplayState for PlayScenario {
|
|||||||
)) {
|
)) {
|
||||||
GameplayMode::PlayScenario(
|
GameplayMode::PlayScenario(
|
||||||
app.primary.map.get_name().clone(),
|
app.primary.map.get_name().clone(),
|
||||||
scenario.clone(),
|
scenario,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -618,15 +618,12 @@ impl State for SandboxLoader {
|
|||||||
ctx,
|
ctx,
|
||||||
abstutil::path_prebaked_results(app.primary.map.get_name(), &scenario_name),
|
abstutil::path_prebaked_results(app.primary.map.get_name(), &scenario_name),
|
||||||
Box::new(move |_, _, prebaked| {
|
Box::new(move |_, _, prebaked| {
|
||||||
let scenario_name = scenario_name.clone();
|
|
||||||
Transition::Multi(vec![
|
Transition::Multi(vec![
|
||||||
Transition::Pop,
|
Transition::Pop,
|
||||||
Transition::ModifyState(Box::new(move |state, _, _| {
|
Transition::ModifyState(Box::new(move |state, _, _| {
|
||||||
let loader = state.downcast_mut::<SandboxLoader>().unwrap();
|
let loader = state.downcast_mut::<SandboxLoader>().unwrap();
|
||||||
loader.stage = Some(LoadStage::GotPrebaked(
|
loader.stage =
|
||||||
scenario_name.clone(),
|
Some(LoadStage::GotPrebaked(scenario_name, prebaked));
|
||||||
prebaked,
|
|
||||||
));
|
|
||||||
})),
|
})),
|
||||||
])
|
])
|
||||||
}),
|
}),
|
||||||
|
Loading…
Reference in New Issue
Block a user