bones_bevy_renderer/
ui.rs

1use super::*;
2use bevy_egui::EguiContext;
3
4/// Startup system to load egui fonts and textures.
5pub fn setup_egui(world: &mut World) {
6    world.resource_scope(|world: &mut World, mut game: Mut<BonesGame>| {
7        let ctx = {
8            let mut egui_query = world.query_filtered::<&mut EguiContext, With<Window>>();
9            let mut egui_ctx = egui_query.get_single_mut(world).unwrap();
10            egui_ctx.get_mut().clone()
11        };
12
13        // Insert the egui context as a shared resource
14        game.insert_shared_resource(bones::EguiCtx(ctx.clone()));
15
16        if let Some(bones_assets) = &game.asset_server() {
17            update_egui_fonts(&ctx, bones_assets);
18
19            // Insert the bones egui textures
20            ctx.data_mut(|map| {
21                map.insert_temp(
22                    bevy_egui::egui::Id::null(),
23                    game.shared_resource_cell::<bones::EguiTextures>().unwrap(),
24                );
25            });
26        }
27    });
28}
29
30/// Applies the modifications setup in the [`bones::EguiInputHook`] resource.
31pub fn egui_input_hook(
32    mut egui_query: Query<&mut bevy_egui::EguiInput, With<Window>>,
33    mut game: ResMut<BonesGame>,
34) {
35    if let Some(hook) = game.shared_resource_cell::<bones::EguiInputHook>() {
36        let hook = hook.borrow().unwrap();
37        let mut egui_input = egui_query.get_single_mut().unwrap();
38        (hook.0)(&mut game, &mut egui_input);
39    }
40}
41
42/// Syncs the [`bones::EguiSettings`] with the [`bevy_egui::EguiSettings`].
43pub fn sync_egui_settings(
44    game: Res<BonesGame>,
45    mut bevy_egui_settings: ResMut<bevy_egui::EguiSettings>,
46) {
47    for session_name in &game.sorted_session_keys {
48        let session = game.sessions.get(*session_name).unwrap();
49        let world = &session.world;
50
51        if let Some(settings) = world.get_resource::<bones::EguiSettings>() {
52            bevy_egui_settings.scale_factor = settings.scale;
53        }
54    }
55}
56
57/// Updates the egui fonts based on [`bones::Font`]s in the [`bones::AssetServer`].
58pub fn update_egui_fonts(ctx: &bevy_egui::egui::Context, bones_assets: &bones::AssetServer) {
59    use bevy_egui::egui;
60    let mut fonts = egui::FontDefinitions::default();
61
62    for entry in bones_assets.store.assets.iter() {
63        let asset = entry.value();
64        if let Ok(font) = asset.try_cast_ref::<bones::Font>() {
65            let previous = fonts
66                .font_data
67                .insert(font.family_name.to_string(), font.data.clone());
68            if previous.is_some() {
69                warn!(
70                    name=%font.family_name,
71                    "Found two fonts with the same family name, using \
72                    only the latest one"
73                );
74            }
75            fonts
76                .families
77                .entry(egui::FontFamily::Name(font.family_name.clone()))
78                .or_default()
79                .push(font.family_name.to_string());
80        }
81    }
82
83    ctx.set_fonts(fonts);
84}
85
86/// The system for displaying the default egui loading screen.
87pub fn default_load_progress(asset_server: &bones::AssetServer, ctx: &bevy_egui::egui::Context) {
88    use bevy_egui::egui;
89    let errored = asset_server.load_progress.errored();
90
91    egui::CentralPanel::default().show(ctx, |ui| {
92        let height = ui.available_height();
93        let ctx = ui.ctx().clone();
94
95        let space_size = 0.03;
96        let spinner_size = 0.07;
97        let text_size = 0.034;
98        ui.vertical_centered(|ui| {
99            ui.add_space(height * 0.3);
100
101            if errored > 0 {
102                ui.label(
103                    egui::RichText::new("⚠")
104                        .color(egui::Color32::RED)
105                        .size(height * spinner_size),
106                );
107                ui.add_space(height * space_size);
108                ui.label(
109                    egui::RichText::new(format!(
110                        "Error loading {errored} asset{}.",
111                        if errored > 1 { "s" } else { "" }
112                    ))
113                    .color(egui::Color32::RED)
114                    .size(height * text_size * 0.75),
115                );
116            } else {
117                ui.add(egui::Spinner::new().size(height * spinner_size));
118                ui.add_space(height * space_size);
119                ui.label(egui::RichText::new("Loading").size(height * text_size));
120            }
121        });
122
123        ctx.data_mut(|d| {
124            d.insert_temp(ui.id(), (spinner_size, space_size, text_size));
125        })
126    });
127}