117 lines
3.2 KiB
Rust
117 lines
3.2 KiB
Rust
use bevy::math::Rect;
|
|
use bevy::prelude::*;
|
|
use bevy_egui::EguiContexts;
|
|
use transform_gizmo_bevy::prelude::{GizmoMode, GizmoOptions, GizmoOrientation};
|
|
|
|
use crate::ui::{viewport_keyboard_shortcuts_active, UiState};
|
|
use crate::viewport::ViewportDisplayMode;
|
|
|
|
#[derive(Resource, Default, Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum EditorGizmoMode {
|
|
#[default]
|
|
Translate,
|
|
Rotate,
|
|
Scale,
|
|
}
|
|
|
|
#[derive(Resource, Default, Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum EditorGizmoSpace {
|
|
#[default]
|
|
World,
|
|
Local,
|
|
}
|
|
|
|
pub struct EditorGizmoPlugin;
|
|
|
|
impl Plugin for EditorGizmoPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_resource::<EditorGizmoMode>()
|
|
.init_resource::<EditorGizmoSpace>()
|
|
.add_systems(
|
|
Update,
|
|
(
|
|
handle_gizmo_hotkeys,
|
|
sync_gizmo_viewport_rect,
|
|
sync_gizmo_options,
|
|
)
|
|
.chain(),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn handle_gizmo_hotkeys(
|
|
keys: Res<ButtonInput<KeyCode>>,
|
|
buttons: Res<ButtonInput<MouseButton>>,
|
|
mut contexts: EguiContexts,
|
|
ui_state: Res<UiState>,
|
|
display: Res<ViewportDisplayMode>,
|
|
mut mode: ResMut<EditorGizmoMode>,
|
|
mut space: ResMut<EditorGizmoSpace>,
|
|
) -> Result {
|
|
if display.clean_game_view {
|
|
return Ok(());
|
|
}
|
|
let ctx = contexts.ctx_mut()?;
|
|
if !viewport_keyboard_shortcuts_active(&ui_state, ctx, &buttons) {
|
|
return Ok(());
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyW) {
|
|
*mode = EditorGizmoMode::Translate;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyE) {
|
|
*mode = EditorGizmoMode::Rotate;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyR) {
|
|
*mode = EditorGizmoMode::Scale;
|
|
}
|
|
if keys.just_pressed(KeyCode::KeyX) {
|
|
*space = match *space {
|
|
EditorGizmoSpace::World => EditorGizmoSpace::Local,
|
|
EditorGizmoSpace::Local => EditorGizmoSpace::World,
|
|
};
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Maps the viewport egui panel to gizmo cursor space (required for render-to-texture).
|
|
fn sync_gizmo_viewport_rect(
|
|
ui_state: Res<UiState>,
|
|
display: Res<ViewportDisplayMode>,
|
|
mut options: ResMut<GizmoOptions>,
|
|
) {
|
|
if display.clean_game_view {
|
|
options.viewport_rect = None;
|
|
return;
|
|
}
|
|
let panel = ui_state.viewport_rect;
|
|
options.viewport_rect = if panel.width() > 1.0 && panel.height() > 1.0 {
|
|
Some(Rect {
|
|
min: Vec2::new(panel.min.x, panel.min.y),
|
|
max: Vec2::new(panel.max.x, panel.max.y),
|
|
})
|
|
} else {
|
|
None
|
|
};
|
|
}
|
|
|
|
fn sync_gizmo_options(
|
|
mode: Res<EditorGizmoMode>,
|
|
space: Res<EditorGizmoSpace>,
|
|
mut options: ResMut<GizmoOptions>,
|
|
) {
|
|
if !mode.is_changed() && !space.is_changed() {
|
|
return;
|
|
}
|
|
|
|
options.gizmo_modes = match *mode {
|
|
EditorGizmoMode::Translate => GizmoMode::all_translate(),
|
|
EditorGizmoMode::Rotate => GizmoMode::all_rotate(),
|
|
EditorGizmoMode::Scale => GizmoMode::all_scale(),
|
|
};
|
|
options.gizmo_orientation = match *space {
|
|
EditorGizmoSpace::World => GizmoOrientation::Global,
|
|
EditorGizmoSpace::Local => GizmoOrientation::Local,
|
|
};
|
|
options.mode_override = None;
|
|
}
|