use crate::{EguiContext, EguiInput, EguiOutput, EguiSettings, EguiShapes, WindowSize};
use bevy::{
app::Events,
core::Time,
ecs::{Res, ResMut},
input::{
keyboard::KeyCode,
mouse::{MouseButton, MouseScrollUnit, MouseWheel},
Input,
},
log,
window::{CursorMoved, ReceivedCharacter, Windows},
};
use bevy_winit::WinitWindows;
#[allow(clippy::too_many_arguments)]
pub fn process_input(
mut egui_context: ResMut<EguiContext>,
mut egui_input: ResMut<EguiInput>,
#[cfg(feature = "manage_clipboard")] egui_clipboard: Res<crate::EguiClipboard>,
ev_cursor: Res<Events<CursorMoved>>,
ev_mouse_wheel: Res<Events<MouseWheel>>,
ev_received_character: Res<Events<ReceivedCharacter>>,
mouse_button_input: Res<Input<MouseButton>>,
keyboard_input: Res<Input<KeyCode>>,
mut window_size: ResMut<WindowSize>,
windows: ResMut<Windows>,
egui_settings: ResMut<EguiSettings>,
time: Res<Time>,
) {
if let Some(window) = windows.get_primary() {
*window_size = WindowSize::new(
window.physical_width() as f32,
window.physical_height() as f32,
window.scale_factor() as f32,
);
}
if let Some(cursor_moved) = egui_context.cursor.latest(&ev_cursor) {
if cursor_moved.id.is_primary() {
let scale_factor = egui_settings.scale_factor as f32;
let mut mouse_position: (f32, f32) = (cursor_moved.position / scale_factor).into();
mouse_position.1 = window_size.height() / scale_factor - mouse_position.1;
egui_context.mouse_position = mouse_position;
egui_input.raw_input.mouse_pos = Some(egui::pos2(mouse_position.0, mouse_position.1));
}
}
egui_input.raw_input.mouse_down = mouse_button_input.pressed(MouseButton::Left);
egui_input.raw_input.screen_rect = Some(egui::Rect::from_min_max(
egui::pos2(0.0, 0.0),
egui::pos2(
window_size.physical_width
/ window_size.scale_factor
/ egui_settings.scale_factor as f32,
window_size.physical_height
/ window_size.scale_factor
/ egui_settings.scale_factor as f32,
),
));
egui_input.raw_input.pixels_per_point =
Some(window_size.scale_factor * egui_settings.scale_factor as f32);
for event in egui_context.mouse_wheel.iter(&ev_mouse_wheel) {
let mut delta = egui::vec2(event.x, event.y);
if let MouseScrollUnit::Line = event.unit {
delta *= 24.0;
}
egui_input.raw_input.scroll_delta += delta;
}
let shift = keyboard_input.pressed(KeyCode::LShift) || keyboard_input.pressed(KeyCode::RShift);
let ctrl =
keyboard_input.pressed(KeyCode::LControl) || keyboard_input.pressed(KeyCode::RControl);
let alt = keyboard_input.pressed(KeyCode::LAlt) || keyboard_input.pressed(KeyCode::RAlt);
let win = keyboard_input.pressed(KeyCode::LWin) || keyboard_input.pressed(KeyCode::RWin);
let mac_cmd = if cfg!(target_os = "macos") {
win
} else {
false
};
let command = if cfg!(target_os = "macos") { win } else { ctrl };
let modifiers = egui::Modifiers {
alt,
ctrl,
shift,
mac_cmd,
command,
};
if !ctrl && !win {
for event in egui_context.received_character.iter(&ev_received_character) {
if event.id.is_primary() && !event.char.is_control() {
egui_input
.raw_input
.events
.push(egui::Event::Text(event.char.to_string()));
}
}
}
for pressed_key in keyboard_input.get_just_pressed() {
if let Some(key) = bevy_to_egui_key(*pressed_key) {
egui_input.raw_input.events.push(egui::Event::Key {
key,
pressed: true,
modifiers,
})
}
}
for pressed_key in keyboard_input.get_just_released() {
if let Some(key) = bevy_to_egui_key(*pressed_key) {
egui_input.raw_input.events.push(egui::Event::Key {
key,
pressed: false,
modifiers,
})
}
}
#[cfg(feature = "manage_clipboard")]
{
if command && keyboard_input.just_pressed(KeyCode::C) {
egui_input.raw_input.events.push(egui::Event::Copy);
}
if command && keyboard_input.just_pressed(KeyCode::X) {
egui_input.raw_input.events.push(egui::Event::Cut);
}
if command && keyboard_input.just_pressed(KeyCode::V) {
if let Some(contents) = egui_clipboard.get_contents() {
egui_input
.raw_input
.events
.push(egui::Event::Text(contents))
}
}
};
egui_input.raw_input.predicted_dt = time.delta_seconds();
egui_input.raw_input.modifiers = modifiers;
}
pub fn begin_frame(mut egui_context: ResMut<EguiContext>, mut egui_input: ResMut<EguiInput>) {
let raw_input = egui_input.raw_input.take();
egui_context.ctx.begin_frame(raw_input);
}
pub fn process_output(
egui_context: Res<EguiContext>,
mut egui_output: ResMut<EguiOutput>,
mut egui_shapes: ResMut<EguiShapes>,
#[cfg(feature = "manage_clipboard")] mut egui_clipboard: ResMut<crate::EguiClipboard>,
windows: Res<Windows>,
winit_windows: Res<WinitWindows>,
) {
let (output, shapes) = egui_context.ctx.end_frame();
egui_shapes.shapes = shapes;
egui_output.output = output.clone();
#[cfg(feature = "manage_clipboard")]
if !output.copied_text.is_empty() {
egui_clipboard.set_contents(&output.copied_text);
}
if let Some(window) = windows.get_primary() {
if let Some(winit_window) = winit_windows.get_window(window.id()) {
winit_window.set_cursor_icon(egui_to_winit_cursor_icon(output.cursor_icon));
} else {
log::error!("No winit window found for the primary window");
}
} else {
log::warn!("No primary window detected");
}
#[cfg(feature = "open_url")]
if let Some(url) = output.open_url {
if let Err(err) = webbrowser::open(&url) {
log::error!("Failed to open '{}': {:?}", url, err);
}
}
}
fn egui_to_winit_cursor_icon(cursor_icon: egui::CursorIcon) -> winit::window::CursorIcon {
match cursor_icon {
egui::CursorIcon::Default => winit::window::CursorIcon::Default,
egui::CursorIcon::PointingHand => winit::window::CursorIcon::Hand,
egui::CursorIcon::ResizeHorizontal => winit::window::CursorIcon::EwResize,
egui::CursorIcon::ResizeNeSw => winit::window::CursorIcon::NeswResize,
egui::CursorIcon::ResizeNwSe => winit::window::CursorIcon::NwseResize,
egui::CursorIcon::ResizeVertical => winit::window::CursorIcon::NsResize,
egui::CursorIcon::Text => winit::window::CursorIcon::Text,
egui::CursorIcon::Grab => winit::window::CursorIcon::Grab,
egui::CursorIcon::Grabbing => winit::window::CursorIcon::Grabbing,
}
}
fn bevy_to_egui_key(key_code: KeyCode) -> Option<egui::Key> {
let key = match key_code {
KeyCode::Down => egui::Key::ArrowDown,
KeyCode::Left => egui::Key::ArrowLeft,
KeyCode::Right => egui::Key::ArrowRight,
KeyCode::Up => egui::Key::ArrowUp,
KeyCode::Escape => egui::Key::Escape,
KeyCode::Tab => egui::Key::Tab,
KeyCode::Back => egui::Key::Backspace,
KeyCode::Return => egui::Key::Enter,
KeyCode::Space => egui::Key::Space,
KeyCode::Insert => egui::Key::Insert,
KeyCode::Delete => egui::Key::Delete,
KeyCode::Home => egui::Key::Home,
KeyCode::End => egui::Key::End,
KeyCode::PageUp => egui::Key::PageUp,
KeyCode::PageDown => egui::Key::PageDown,
KeyCode::Numpad0 | KeyCode::Key0 => egui::Key::Num0,
KeyCode::Numpad1 | KeyCode::Key1 => egui::Key::Num1,
KeyCode::Numpad2 | KeyCode::Key2 => egui::Key::Num2,
KeyCode::Numpad3 | KeyCode::Key3 => egui::Key::Num3,
KeyCode::Numpad4 | KeyCode::Key4 => egui::Key::Num4,
KeyCode::Numpad5 | KeyCode::Key5 => egui::Key::Num5,
KeyCode::Numpad6 | KeyCode::Key6 => egui::Key::Num6,
KeyCode::Numpad7 | KeyCode::Key7 => egui::Key::Num7,
KeyCode::Numpad8 | KeyCode::Key8 => egui::Key::Num8,
KeyCode::Numpad9 | KeyCode::Key9 => egui::Key::Num9,
KeyCode::A => egui::Key::A,
KeyCode::B => egui::Key::B,
KeyCode::C => egui::Key::C,
KeyCode::D => egui::Key::D,
KeyCode::E => egui::Key::E,
KeyCode::F => egui::Key::F,
KeyCode::G => egui::Key::G,
KeyCode::H => egui::Key::H,
KeyCode::I => egui::Key::I,
KeyCode::J => egui::Key::J,
KeyCode::K => egui::Key::K,
KeyCode::L => egui::Key::L,
KeyCode::M => egui::Key::M,
KeyCode::N => egui::Key::N,
KeyCode::O => egui::Key::O,
KeyCode::P => egui::Key::P,
KeyCode::Q => egui::Key::Q,
KeyCode::R => egui::Key::R,
KeyCode::S => egui::Key::S,
KeyCode::T => egui::Key::T,
KeyCode::U => egui::Key::U,
KeyCode::V => egui::Key::V,
KeyCode::W => egui::Key::W,
KeyCode::X => egui::Key::X,
KeyCode::Y => egui::Key::Y,
KeyCode::Z => egui::Key::Z,
_ => return None,
};
Some(key)
}