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::() .init_resource::() .add_systems( Update, ( handle_gizmo_hotkeys, sync_gizmo_viewport_rect, sync_gizmo_options, ) .chain(), ); } } fn handle_gizmo_hotkeys( keys: Res>, buttons: Res>, mut contexts: EguiContexts, ui_state: Res, display: Res, mut mode: ResMut, mut space: ResMut, ) -> 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, display: Res, mut options: ResMut, ) { 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, space: Res, mut options: ResMut, ) { 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; }