bevy_yoleck/
editor_window.rs

1use bevy::prelude::*;
2use bevy::window::PrimaryWindow;
3use bevy_egui::{EguiContext, PrimaryEguiContext, egui};
4
5use crate::YoleckEditorBottomPanelSections;
6use crate::YoleckEditorLeftPanelSections;
7use crate::YoleckEditorRightPanelSections;
8use crate::YoleckEditorTopPanelSections;
9use crate::editor_panels::EditorPanel;
10
11#[derive(Resource, Default)]
12pub struct YoleckEditorViewportRect {
13    pub rect: Option<egui::Rect>,
14}
15
16pub(crate) fn yoleck_editor_window(
17    world: &mut World,
18    mut egui_query: Local<Option<QueryState<&mut EguiContext, With<PrimaryEguiContext>>>>,
19) {
20    let egui_query = egui_query.get_or_insert_with(|| world.query_filtered());
21    let mut borrowed_egui = if let Ok(mut egui_context) = egui_query.single_mut(world) {
22        core::mem::take(egui_context.as_mut())
23    } else {
24        return;
25    };
26
27    let ctx = borrowed_egui.get_mut();
28
29    // The order of panels is important, because panels that go first will take height/width from
30    // adjacent panels. The top panel must go first because it's height is very small (so it won't
31    // be impacting the side panels much) and it needs all the width it can get. The bottom panel
32    // can go last because giving the side panels more height for displaying their lists is more
33    // important than giving extra width to the console.
34
35    let top = YoleckEditorTopPanelSections::show_panel(world, ctx)
36        .rect
37        .height();
38
39    let left = YoleckEditorLeftPanelSections::show_panel(world, ctx)
40        .rect
41        .width();
42
43    let right = YoleckEditorRightPanelSections::show_panel(world, ctx)
44        .rect
45        .width();
46
47    let bottom = YoleckEditorBottomPanelSections::show_panel(world, ctx)
48        .rect
49        .height();
50
51    let viewport_rect = egui::Rect::from_min_max(
52        egui::Pos2::new(left, top),
53        egui::Pos2::new(
54            ctx.input(|i| i.viewport_rect().width()) - right,
55            ctx.input(|i| i.viewport_rect().height()) - bottom,
56        ),
57    );
58
59    if let Some(mut editor_viewport) = world.get_resource_mut::<YoleckEditorViewportRect>() {
60        editor_viewport.rect = Some(viewport_rect);
61    }
62
63    if let Ok(window) = world
64        .query_filtered::<&bevy::window::Window, With<PrimaryWindow>>()
65        .single(world)
66    {
67        let scale = window.scale_factor();
68
69        let left_px = (left * scale) as u32;
70        let right_px = (right * scale) as u32;
71        let top_px = (top * scale) as u32;
72        let bottom_px = (bottom * scale) as u32;
73
74        let pos = UVec2::new(left_px, top_px);
75        let size = UVec2::new(window.physical_width(), window.physical_height())
76            .saturating_sub(pos)
77            .saturating_sub(UVec2::new(right_px, bottom_px));
78
79        if size.x > 0 && size.y > 0 {
80            let mut camera_query =
81                world.query_filtered::<&mut Camera, Without<PrimaryEguiContext>>();
82            for mut camera in camera_query.iter_mut(world) {
83                camera.viewport = Some(bevy::camera::Viewport {
84                    physical_position: pos,
85                    physical_size: size,
86                    ..default()
87                });
88            }
89        }
90    }
91
92    if let Ok(mut egui_context) = egui_query.single_mut(world) {
93        *egui_context = borrowed_egui;
94    }
95}