You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.5 KiB
Rust
164 lines
4.5 KiB
Rust
use crate::prelude::*;
|
|
|
|
pub(crate) struct EditorPlugin;
|
|
|
|
impl Plugin for EditorPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_state::<EditorState>()
|
|
.add_systems(Startup, init_editor)
|
|
.add_systems(
|
|
Update,
|
|
toggle_editor_state.run_if(input_just_pressed(KeyCode::F3)),
|
|
)
|
|
.add_systems(
|
|
OnTransition {
|
|
from: EditorState::Open,
|
|
to: EditorState::Closed,
|
|
},
|
|
toggle_editor_window,
|
|
)
|
|
.add_systems(
|
|
OnTransition {
|
|
from: EditorState::Closed,
|
|
to: EditorState::Open,
|
|
},
|
|
toggle_editor_window,
|
|
)
|
|
.add_systems(
|
|
Update,
|
|
handle_window_close.run_if(on_event::<WindowCloseRequested>()),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Tracking the open/closed state of the editor
|
|
#[derive(States, Debug, Clone, PartialEq, Eq, Hash, Default, Component)]
|
|
enum EditorState {
|
|
/// The editor is closed => the editor window is disabled
|
|
#[default]
|
|
Closed,
|
|
/// The editor is open => the editor window is visible
|
|
Open,
|
|
}
|
|
|
|
impl std::ops::Not for &EditorState {
|
|
type Output = EditorState;
|
|
|
|
fn not(self) -> Self::Output {
|
|
match self {
|
|
EditorState::Open => EditorState::Closed,
|
|
EditorState::Closed => EditorState::Open,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::convert::From<&EditorState> for bool {
|
|
fn from(value: &EditorState) -> bool {
|
|
match value {
|
|
EditorState::Open => true,
|
|
EditorState::Closed => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Tag component for editor entities
|
|
#[derive(Component)]
|
|
struct EditorTag;
|
|
|
|
/// At startup initialize some editor components
|
|
fn init_editor(mut commands: Commands) {
|
|
// Editor window
|
|
let editor_window = commands
|
|
.spawn((
|
|
EditorTag,
|
|
Window {
|
|
visible: false,
|
|
title: "Editor".into(),
|
|
..default()
|
|
},
|
|
))
|
|
.id();
|
|
|
|
// Editor camera
|
|
let editor_camera = commands
|
|
.spawn((
|
|
EditorTag,
|
|
Camera3dBundle {
|
|
camera: Camera {
|
|
target: RenderTarget::Window(WindowRef::Entity(editor_window)),
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
))
|
|
.id();
|
|
|
|
// Editor UI elements
|
|
commands
|
|
.spawn((
|
|
EditorTag,
|
|
TargetCamera(editor_camera),
|
|
NodeBundle { ..default() },
|
|
))
|
|
.with_children(|parent| {
|
|
parent.spawn((
|
|
EditorTag,
|
|
TextBundle::from_section(
|
|
"Welcome to the editor",
|
|
TextStyle {
|
|
color: Color::WHITE,
|
|
..default()
|
|
},
|
|
),
|
|
));
|
|
});
|
|
}
|
|
|
|
fn toggle_editor_state(
|
|
curr_state: Res<State<EditorState>>,
|
|
mut next_state: ResMut<NextState<EditorState>>,
|
|
keys: Res<ButtonInput<KeyCode>>,
|
|
mut catch: Local<bool>,
|
|
) {
|
|
if keys.pressed(KeyCode::F3) && !*catch {
|
|
*catch = true;
|
|
match curr_state.get() {
|
|
EditorState::Open => next_state.set(EditorState::Closed),
|
|
EditorState::Closed => next_state.set(EditorState::Open),
|
|
}
|
|
} else {
|
|
*catch = false;
|
|
}
|
|
}
|
|
|
|
fn toggle_editor_window(
|
|
state: Res<State<EditorState>>,
|
|
mut windows: Query<&mut Window, With<EditorTag>>,
|
|
mut cameras: Query<&mut Camera, With<EditorTag>>,
|
|
) {
|
|
let curr = state.get().into();
|
|
cameras.iter_mut().for_each(|mut camera| {
|
|
camera.is_active = curr;
|
|
});
|
|
windows.iter_mut().for_each(|mut window| {
|
|
window.visible = curr;
|
|
})
|
|
}
|
|
|
|
/// Handles window close requests which are only weird because of the editor
|
|
/// When the editor window closes, just make it invisible and change the editor state to "Closed".
|
|
fn handle_window_close(
|
|
mut events: EventReader<WindowCloseRequested>,
|
|
editor_windows: Query<Entity, With<EditorTag>>,
|
|
mut editor_state: ResMut<NextState<EditorState>>,
|
|
) {
|
|
events
|
|
.read()
|
|
// Filter events down to jus those affecting the editor window
|
|
.filter_map(|WindowCloseRequested { window }| editor_windows.get(*window).ok())
|
|
// For each related close event, send out a "Close the editor" state transition
|
|
.for_each(|_| {
|
|
editor_state.set(EditorState::Closed);
|
|
});
|
|
}
|