Blacksite/crates/editor/src/viewport/gizmos.rs
Rbanh 2fa64106c8
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
Polish inspector add component workflow
2026-06-06 03:08:28 -04:00

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;
}