use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Button {
Primary,
Secondary,
Middle,
Extra1,
Extra2,
}
impl Button {
pub fn egui(self) -> egui::PointerButton {
match self {
Button::Primary => egui::PointerButton::Primary,
Button::Secondary => egui::PointerButton::Secondary,
Button::Middle => egui::PointerButton::Middle,
Button::Extra1 => egui::PointerButton::Extra1,
Button::Extra2 => egui::PointerButton::Extra2,
}
}
fn index(self) -> usize {
self as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum WheelUnit {
Point,
Line,
Page,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Modifiers {
#[serde(default)]
pub ctrl: bool,
#[serde(default)]
pub shift: bool,
#[serde(default)]
pub alt: bool,
#[serde(default)]
pub command: bool,
}
impl Modifiers {
pub fn egui(self) -> egui::Modifiers {
egui::Modifiers {
alt: self.alt,
ctrl: self.ctrl || self.command,
shift: self.shift,
mac_cmd: self.command,
command: self.ctrl || self.command,
}
}
}
#[derive(Debug, Clone, Serialize, schemars::JsonSchema)]
pub struct PointerState {
pub pos: Option<[f32; 2]>,
pub buttons: Vec<Button>,
pub modifiers: Modifiers,
}
#[derive(Debug, Clone, Default)]
pub struct Pointer {
pub pos: Option<egui::Pos2>,
pub buttons: [bool; 5],
pub modifiers: Modifiers,
}
const ALL_BUTTONS: [Button; 5] = [Button::Primary, Button::Secondary, Button::Middle, Button::Extra1, Button::Extra2];
impl Pointer {
pub fn state(&self) -> PointerState {
PointerState {
pos: self.pos.map(|p| [p.x, p.y]),
buttons: ALL_BUTTONS.iter().copied().filter(|b| self.buttons[b.index()]).collect(),
modifiers: self.modifiers,
}
}
pub fn moved(&mut self, x: f32, y: f32, out: &mut Vec<egui::Event>) {
let pos = egui::pos2(x, y);
self.pos = Some(pos);
out.push(egui::Event::PointerMoved(pos));
}
pub fn button(&mut self, button: Button, pressed: bool, out: &mut Vec<egui::Event>) -> Result<(), String> {
let pos = self.pos.ok_or("the pointer has no position yet: move it first")?;
self.buttons[button.index()] = pressed;
out.push(egui::Event::PointerButton { pos, button: button.egui(), pressed, modifiers: self.modifiers.egui() });
Ok(())
}
pub fn gone(&mut self, out: &mut Vec<egui::Event>) {
self.pos = None;
self.buttons = [false; 5];
out.push(egui::Event::PointerGone);
}
pub fn wheel(&mut self, dx: f32, dy: f32, unit: WheelUnit, out: &mut Vec<egui::Event>) {
let unit = match unit {
WheelUnit::Point => egui::MouseWheelUnit::Point,
WheelUnit::Line => egui::MouseWheelUnit::Line,
WheelUnit::Page => egui::MouseWheelUnit::Page,
};
out.push(egui::Event::MouseWheel {
unit,
delta: egui::vec2(dx, dy),
phase: egui::TouchPhase::Move,
modifiers: self.modifiers.egui(),
});
}
pub fn set_modifiers(&mut self, m: Modifiers) {
self.modifiers = m;
}
pub fn key(&mut self, name: &str, pressed: bool, repeat: bool, out: &mut Vec<egui::Event>) -> Result<(), String> {
let key = egui::Key::from_name(name).ok_or_else(|| format!("unknown key `{name}` (egui key names: A..Z, 0..9, Enter, Escape, Tab, Space, Backspace, Delete, ArrowLeft/Right/Up/Down, Home, End, PageUp/Down, F1..F12, Minus, Plus, …)"))?;
out.push(egui::Event::Key { key, physical_key: None, pressed, repeat, modifiers: self.modifiers.egui() });
Ok(())
}
pub fn text(&mut self, text: &str, out: &mut Vec<egui::Event>) {
if !text.is_empty() {
out.push(egui::Event::Text(text.to_string()));
}
}
}