1use abstio::MapName;
2use widgetry::tools::PopupMsg;
3use widgetry::tools::{FileLoader, RawBytes};
4use widgetry::{EventCtx, GfxCtx, State, Transition};
5
6use crate::AppLike;
7
8pub struct MapLoader;
9
10impl MapLoader {
11 pub fn new_state<A: AppLike + 'static>(
12 ctx: &mut EventCtx,
13 app: &A,
14 name: MapName,
15 on_load: Box<dyn FnOnce(&mut EventCtx, &mut A) -> Transition<A>>,
16 ) -> Box<dyn State<A>> {
17 if app.map().get_name() == &name {
18 return Box::new(MapAlreadyLoaded {
19 on_load: Some(on_load),
20 });
21 }
22
23 MapLoader::force_reload(ctx, name, on_load)
24 }
25
26 pub fn force_reload<A: AppLike + 'static>(
28 ctx: &mut EventCtx,
29 name: MapName,
30 on_load: Box<dyn FnOnce(&mut EventCtx, &mut A) -> Transition<A>>,
31 ) -> Box<dyn State<A>> {
32 if let Some(extra_font) = match name.city.country.as_ref() {
34 "hk" | "jp" | "tw" => Some("NotoSerifCJKtc-Regular.otf"),
35 "il" => Some("NotoSansHebrew-Regular.ttf"),
36 "ir" | "ly" => Some("NotoSansArabic-Regular.ttf"),
37 "kr" => Some("NotoSansKR-Regular.ttf"),
38 _ => None,
39 } {
40 if !ctx.is_font_loaded(extra_font) {
41 return FileLoader::<A, RawBytes>::new_state(
42 ctx,
43 abstio::path(format!("system/extra_fonts/{}", extra_font)),
44 Box::new(move |ctx, app, _, bytes| match bytes {
45 Ok(bytes) => {
46 ctx.load_font(extra_font, bytes.0);
47 Transition::Replace(MapLoader::new_state(ctx, app, name, on_load))
48 }
49 Err(err) => Transition::Replace(PopupMsg::new_state(
50 ctx,
51 "Error",
52 vec![format!("Couldn't load {}", extra_font), err.to_string()],
53 )),
54 }),
55 );
56 }
57 }
58
59 FileLoader::<A, map_model::Map>::new_state(
60 ctx,
61 name.path(),
62 Box::new(move |ctx, app, timer, map| {
63 match map {
64 Ok(mut map) => {
65 map.map_loaded_directly(timer);
67
68 app.map_switched(ctx, map, timer);
69
70 (on_load)(ctx, app)
71 }
72 Err(err) => Transition::Replace(PopupMsg::new_state(
73 ctx,
74 "Error",
75 vec![
76 format!("Couldn't load {}", name.describe()),
77 err.to_string(),
78 ],
79 )),
80 }
81 }),
82 )
83 }
84}
85
86struct MapAlreadyLoaded<A: AppLike> {
87 on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut A) -> Transition<A>>>,
88}
89impl<A: AppLike + 'static> State<A> for MapAlreadyLoaded<A> {
90 fn event(&mut self, ctx: &mut EventCtx, app: &mut A) -> Transition<A> {
91 (self.on_load.take().unwrap())(ctx, app)
92 }
93 fn draw(&self, _: &mut GfxCtx, _: &A) {}
94}