#![warn(clippy::all)]
#![allow(clippy::single_match)]
pub use egui;
use crate::*;
use egui::*;
#[cfg(not(feature = "clipboard"))]
use super::clipboard::{
ClipboardContext, ClipboardProvider,
};
pub struct EguiInputState {
pub pointer_pos: Pos2,
pub clipboard: Option<ClipboardContext>,
pub input: RawInput,
pub modifiers: Modifiers,
}
impl EguiInputState {
pub fn new(input: RawInput) -> Self {
EguiInputState {
pointer_pos: Pos2::new(0f32, 0f32),
clipboard: init_clipboard(),
input,
modifiers: Modifiers::default(),
}
}
}
pub fn handle_event(event: glfw::WindowEvent, state: &mut EguiInputState) {
use glfw::WindowEvent::*;
match event {
FramebufferSize(width, height) => {
state.input.screen_rect = Some(epaint::emath::Rect::from_min_size(
Pos2::new(0f32, 0f32),
egui::vec2(width as f32, height as f32) / state.input.pixels_per_point.unwrap(),
))
}
MouseButton (mouse_btn, glfw::Action::Press, _) => state.input.events.push(egui::Event::PointerButton {
pos: state.pointer_pos,
button: match mouse_btn {
glfw::MouseButtonLeft => egui::PointerButton::Primary,
glfw::MouseButtonRight => egui::PointerButton::Secondary,
glfw::MouseButtonMiddle => egui::PointerButton::Middle,
_ => unreachable!(),
},
pressed: true,
modifiers: state.modifiers,
}),
MouseButton (mouse_btn, glfw::Action::Release, _) => state.input.events.push(egui::Event::PointerButton {
pos: state.pointer_pos,
button: match mouse_btn {
glfw::MouseButtonLeft => egui::PointerButton::Primary,
glfw::MouseButtonRight => egui::PointerButton::Secondary,
glfw::MouseButtonMiddle => egui::PointerButton::Middle,
_ => unreachable!(),
},
pressed: false,
modifiers: state.modifiers,
}),
CursorPos(x, y) => {
state.pointer_pos = pos2(
x as f32 / state.input.pixels_per_point.unwrap(),
y as f32 / state.input.pixels_per_point.unwrap(),
);
state
.input
.events
.push(egui::Event::PointerMoved(state.pointer_pos))
}
Key(keycode, _scancode, glfw::Action::Release, keymod) => {
use glfw::Modifiers as Mod;
if let Some(key) = translate_virtual_key_code(keycode) {
state.modifiers = Modifiers {
alt: (keymod & Mod::Alt == Mod::Alt),
ctrl: (keymod & Mod::Control == Mod::Control),
shift: (keymod & Mod::Shift == Mod::Shift),
command: (keymod & Mod::Control == Mod::Control),
..Default::default()
};
state.input.events.push(Event::Key {
key,
pressed: false,
modifiers: state.modifiers,
});
}
}
Key(keycode, _scancode, glfw::Action::Press | glfw::Action::Repeat, keymod) => {
use glfw::Modifiers as Mod;
if let Some(key) = translate_virtual_key_code(keycode) {
state.modifiers = Modifiers {
alt: (keymod & Mod::Alt == Mod::Alt),
ctrl: (keymod & Mod::Control == Mod::Control),
shift: (keymod & Mod::Shift == Mod::Shift),
command: (keymod & Mod::Control == Mod::Control),
..Default::default()
};
if state.modifiers.command && key == egui::Key::X {
state.input.events.push(egui::Event::Cut);
} else if state.modifiers.command && key == egui::Key::C {
state.input.events.push(egui::Event::Copy);
} else if state.modifiers.command && key == egui::Key::V {
if let Some(clipboard_ctx) = state.clipboard.as_mut() {
state.input.events.push(egui::Event::Text(clipboard_ctx.get_contents().unwrap_or("".to_string())));
}
} else {
state.input.events.push(Event::Key {
key,
pressed: true,
modifiers: state.modifiers,
});
}
}
}
Char(c) => {
state.input.events.push(Event::Text(c.to_string()));
}
Scroll (x, y) => {
state.input.scroll_delta = vec2(x as f32, y as f32);
}
_ => {}
}
}
pub fn translate_virtual_key_code(key: glfw::Key) -> Option<egui::Key> {
Some(match key {
glfw::Key::Left => egui::Key::ArrowLeft,
glfw::Key::Up => egui::Key::ArrowUp,
glfw::Key::Right => egui::Key::ArrowRight,
glfw::Key::Down => egui::Key::ArrowDown,
glfw::Key::Escape => egui::Key::Escape,
glfw::Key::Tab => egui::Key::Tab,
glfw::Key::Backspace => egui::Key::Backspace,
glfw::Key::Space => egui::Key::Space,
glfw::Key::Enter => egui::Key::Enter,
glfw::Key::Insert => egui::Key::Insert,
glfw::Key::Home => egui::Key::Home,
glfw::Key::Delete => egui::Key::Delete,
glfw::Key::End => egui::Key::End,
glfw::Key::PageDown => egui::Key::PageDown,
glfw::Key::PageUp => egui::Key::PageUp,
glfw::Key::A => egui::Key::A,
glfw::Key::B => egui::Key::B,
glfw::Key::C => egui::Key::C,
glfw::Key::D => egui::Key::D,
glfw::Key::E => egui::Key::E,
glfw::Key::F => egui::Key::F,
glfw::Key::G => egui::Key::G,
glfw::Key::H => egui::Key::H,
glfw::Key::I => egui::Key::I,
glfw::Key::J => egui::Key::J,
glfw::Key::K => egui::Key::K,
glfw::Key::L => egui::Key::L,
glfw::Key::M => egui::Key::M,
glfw::Key::N => egui::Key::N,
glfw::Key::O => egui::Key::O,
glfw::Key::P => egui::Key::P,
glfw::Key::Q => egui::Key::Q,
glfw::Key::R => egui::Key::R,
glfw::Key::S => egui::Key::S,
glfw::Key::T => egui::Key::T,
glfw::Key::U => egui::Key::U,
glfw::Key::V => egui::Key::V,
glfw::Key::W => egui::Key::W,
glfw::Key::X => egui::Key::X,
glfw::Key::Y => egui::Key::Y,
glfw::Key::Z => egui::Key::Z,
_ => {
return None;
}
})
}
pub fn translate_cursor(cursor_icon: egui::CursorIcon) -> glfw::StandardCursor {
match cursor_icon {
CursorIcon::Default => glfw::StandardCursor::Arrow,
CursorIcon::PointingHand => glfw::StandardCursor::Hand,
CursorIcon::ResizeHorizontal => glfw::StandardCursor::HResize,
CursorIcon::ResizeVertical => glfw::StandardCursor::VResize,
CursorIcon::ResizeNeSw => glfw::StandardCursor::HResize,
CursorIcon::ResizeNwSe => glfw::StandardCursor::VResize,
CursorIcon::Text => glfw::StandardCursor::IBeam,
CursorIcon::Crosshair => glfw::StandardCursor::Crosshair,
CursorIcon::NotAllowed | CursorIcon::NoDrop => glfw::StandardCursor::Arrow,
CursorIcon::Wait => glfw::StandardCursor::Arrow,
CursorIcon::Grab | CursorIcon::Grabbing => glfw::StandardCursor::Hand,
_ => glfw::StandardCursor::Arrow,
}
}
pub fn init_clipboard() -> Option<ClipboardContext> {
match ClipboardContext::new() {
Ok(clipboard) => Some(clipboard),
Err(err) => {
eprintln!("Failed to initialize clipboard: {}", err);
None
}
}
}
pub fn copy_to_clipboard(egui_state: &mut EguiInputState, copy_text: String) {
if let Some(clipboard) = egui_state.clipboard.as_mut() {
let result = clipboard.set_contents(copy_text);
if result.is_err() {
dbg!("Unable to set clipboard content.");
}
}
}