use crate::core::rect::{Position, Size};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq)]
pub enum Event {
Key(KeyEvent),
Mouse(MouseEvent),
TextInput(String),
Resize(Size),
FocusGained,
FocusLost,
CloseRequested,
Tick,
FileDrop(Vec<String>),
FileHover(Vec<String>),
FileHoverCancelled,
DragDrop(DragDropEvent),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyEvent {
pub code: KeyCode,
pub modifiers: KeyModifiers,
pub kind: KeyEventKind,
}
impl KeyEvent {
pub fn new(code: KeyCode, modifiers: KeyModifiers) -> Self {
Self {
code,
modifiers,
kind: KeyEventKind::Press,
}
}
pub fn is_ctrl(&self, code: KeyCode) -> bool {
self.code == code && self.modifiers.contains(KeyModifiers::CONTROL)
}
pub fn is_key(&self, code: KeyCode) -> bool {
self.code == code && self.modifiers.is_empty()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum KeyEventKind {
Press,
Release,
Repeat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum KeyCode {
Char(char),
F(u8),
Backspace,
Enter,
Tab,
BackTab,
Esc,
Left,
Right,
Up,
Down,
Home,
End,
PageUp,
PageDown,
Insert,
Delete,
Null,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct KeyModifiers(u8);
impl KeyModifiers {
pub const NONE: Self = Self(0);
pub const SHIFT: Self = Self(1 << 0);
pub const CONTROL: Self = Self(1 << 1);
pub const ALT: Self = Self(1 << 2);
pub const SUPER: Self = Self(1 << 3);
pub const fn empty() -> Self {
Self(0)
}
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
pub const fn is_empty(self) -> bool {
self.0 == 0
}
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
}
impl std::ops::BitOr for KeyModifiers {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for KeyModifiers {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MouseEvent {
pub kind: MouseEventKind,
pub position: Position,
pub modifiers: KeyModifiers,
}
impl MouseEvent {
pub fn is_click(&self) -> bool {
matches!(self.kind, MouseEventKind::Click(_))
}
pub fn is_drag(&self) -> bool {
matches!(self.kind, MouseEventKind::Drag(_))
}
pub fn is_scroll(&self) -> bool {
matches!(self.kind, MouseEventKind::Scroll { .. })
}
pub fn clicked_in(&self, area: crate::core::rect::Rect) -> bool {
self.is_click() && area.contains(self.position)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MouseEventKind {
Click(MouseButton),
Release(MouseButton),
Drag(MouseButton),
Move,
Scroll { delta_x: f32, delta_y: f32 },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MouseButton {
Left,
Right,
Middle,
}
#[derive(Debug, Default)]
pub struct HitMap {
entries: Vec<HitEntry>,
}
#[derive(Debug)]
struct HitEntry {
agent_id: String,
bounds: crate::core::rect::Rect,
z_order: u32,
}
impl HitMap {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn register(
&mut self,
agent_id: impl Into<String>,
bounds: crate::core::rect::Rect,
z_order: u32,
) {
self.entries.push(HitEntry {
agent_id: agent_id.into(),
bounds,
z_order,
});
}
pub fn hit_test(&self, pos: Position) -> Option<&str> {
self.entries
.iter()
.filter(|e| e.bounds.contains(pos))
.max_by_key(|e| e.z_order)
.map(|e| e.agent_id.as_str())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct DragDropEvent {
pub kind: DragDropKind,
pub position: Position,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DragDropKind {
DragStart {
source_id: String,
payload: DragPayload,
},
DragOver {
target_id: String,
},
DragLeave {
target_id: String,
},
Drop {
source_id: String,
target_id: String,
payload: DragPayload,
},
DragCancel,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DragPayload {
Text(String),
Index(usize),
Path(Vec<String>),
Json(serde_json::Value),
}