#![warn(missing_docs)]
use crate::component::ComponentRc;
use crate::graphics::Point;
use crate::item_tree::ItemVisitorResult;
use crate::items::{ItemRc, ItemRef, ItemWeak};
use euclid::default::Vector2D;
use sixtyfps_corelib_macros::*;
use std::convert::TryFrom;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MouseEventType {
MousePressed,
MouseReleased,
MouseMoved,
MouseExit,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MouseEvent {
pub pos: Point,
pub what: MouseEventType,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum InputEventResult {
EventAccepted,
EventIgnored,
GrabMouse,
ObserveHover,
}
impl Default for InputEventResult {
fn default() -> Self {
Self::EventIgnored
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, MappedKeyCode)]
#[allow(missing_docs)]
pub enum KeyCode {
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
F17,
F18,
F19,
F20,
F21,
F22,
F23,
F24,
Snapshot,
Scroll,
Pause,
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
Back,
Return,
Space,
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
AbntC1,
AbntC2,
NumpadAdd,
Apostrophe,
Apps,
Asterisk,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
NumpadDecimal,
NumpadDivide,
Equals,
Grave,
Kana,
Kanji,
LAlt,
LBracket,
LControl,
LShift,
LWin,
Mail,
MediaSelect,
MediaStop,
Minus,
NumpadMultiply,
Mute,
MyComputer,
NavigateForward,
NavigateBackward,
NextTrack,
NoConvert,
NumpadComma,
NumpadEnter,
NumpadEquals,
OEM102,
Period,
PlayPause,
Plus,
Power,
PrevTrack,
RAlt,
RBracket,
RControl,
RShift,
RWin,
Semicolon,
Slash,
Sleep,
Stop,
NumpadSubtract,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
Copy,
Paste,
Cut,
}
impl TryFrom<char> for KeyCode {
type Error = ();
fn try_from(value: char) -> Result<Self, Self::Error> {
Ok(match value {
'a' => Self::A,
'b' => Self::B,
'c' => Self::C,
'd' => Self::D,
'e' => Self::E,
'f' => Self::F,
'g' => Self::G,
'h' => Self::H,
'i' => Self::I,
'j' => Self::J,
'k' => Self::K,
'l' => Self::L,
'm' => Self::M,
'n' => Self::N,
'o' => Self::O,
'p' => Self::P,
'q' => Self::Q,
'r' => Self::R,
's' => Self::S,
't' => Self::T,
'u' => Self::U,
'v' => Self::V,
'w' => Self::W,
'x' => Self::X,
'y' => Self::Y,
'z' => Self::Z,
'1' => Self::Key1,
'2' => Self::Key2,
'3' => Self::Key3,
'4' => Self::Key4,
'5' => Self::Key5,
'6' => Self::Key6,
'7' => Self::Key7,
'8' => Self::Key8,
'9' => Self::Key9,
_ => return Err(()),
})
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct KeyboardModifiers(u32);
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct KeyboardModifier(u32);
pub const NO_MODIFIER: KeyboardModifier = KeyboardModifier(0);
pub const SHIFT_MODIFIER: KeyboardModifier =
KeyboardModifier(winit::event::ModifiersState::SHIFT.bits());
pub const CONTROL_MODIFIER: KeyboardModifier =
KeyboardModifier(winit::event::ModifiersState::CTRL.bits());
pub const ALT_MODIFIER: KeyboardModifier =
KeyboardModifier(winit::event::ModifiersState::ALT.bits());
pub const LOGO_MODIFIER: KeyboardModifier =
KeyboardModifier(winit::event::ModifiersState::LOGO.bits());
pub const COPY_PASTE_MODIFIER: KeyboardModifier =
if cfg!(target_os = "macos") { LOGO_MODIFIER } else { CONTROL_MODIFIER };
impl KeyboardModifiers {
pub fn test(&self, modifier: KeyboardModifier) -> bool {
self.0 & modifier.0 != 0
}
pub fn test_exclusive(&self, modifier: KeyboardModifier) -> bool {
self.0 == modifier.0
}
pub fn shift(&self) -> bool {
self.test(SHIFT_MODIFIER)
}
pub fn control(&self) -> bool {
self.test(CONTROL_MODIFIER)
}
pub fn alt(&self) -> bool {
self.test(ALT_MODIFIER)
}
pub fn logo(&self) -> bool {
self.test(LOGO_MODIFIER)
}
}
impl Default for KeyboardModifiers {
fn default() -> Self {
Self(NO_MODIFIER.0)
}
}
impl From<winit::event::ModifiersState> for KeyboardModifiers {
fn from(state: winit::event::ModifiersState) -> Self {
Self(state.bits())
}
}
impl From<KeyboardModifier> for KeyboardModifiers {
fn from(modifier: KeyboardModifier) -> Self {
Self(modifier.0)
}
}
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub enum KeyEvent {
KeyPressed {
code: KeyCode,
modifiers: KeyboardModifiers,
},
KeyReleased {
code: KeyCode,
modifiers: KeyboardModifiers,
},
CharacterInput {
unicode_scalar: u32,
modifiers: KeyboardModifiers,
},
}
impl TryFrom<(&winit::event::KeyboardInput, KeyboardModifiers)> for KeyEvent {
type Error = ();
fn try_from(
input: (&winit::event::KeyboardInput, KeyboardModifiers),
) -> Result<Self, Self::Error> {
let key_code = match input.0.virtual_keycode {
Some(code) => code.into(),
None => return Err(()),
};
Ok(match input.0.state {
winit::event::ElementState::Pressed => {
KeyEvent::KeyPressed { code: key_code, modifiers: input.1 }
}
winit::event::ElementState::Released => {
KeyEvent::KeyReleased { code: key_code, modifiers: input.1 }
}
})
}
}
#[repr(C)]
pub enum KeyEventResult {
EventAccepted,
EventIgnored,
}
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub enum FocusEvent {
FocusIn,
FocusOut,
WindowReceivedFocus,
WindowLostFocus,
}
#[derive(Default)]
pub struct MouseInputState {
item_stack: Vec<ItemWeak>,
grabbed: bool,
}
pub fn process_mouse_input(
component: ComponentRc,
mouse_event: MouseEvent,
window: &crate::eventloop::ComponentWindow,
mouse_input_state: MouseInputState,
) -> MouseInputState {
'grab: loop {
if !mouse_input_state.grabbed || mouse_input_state.item_stack.is_empty() {
break 'grab;
};
let mut event = mouse_event.clone();
for it in mouse_input_state.item_stack.iter() {
let item = if let Some(item) = it.upgrade() { item } else { break 'grab };
let g = item.borrow().as_ref().geometry();
event.pos -= g.origin.to_vector();
}
let grabber = mouse_input_state.item_stack.last().unwrap().upgrade().unwrap();
return match grabber.borrow().as_ref().input_event(event, window, &grabber) {
InputEventResult::GrabMouse => mouse_input_state,
_ => Default::default(),
};
}
let mut pos = mouse_event.pos;
for it in mouse_input_state.item_stack.iter() {
let item = if let Some(item) = it.upgrade() { item } else { break };
let g = item.borrow().as_ref().geometry();
pos -= g.origin.to_vector();
item.borrow().as_ref().input_event(
MouseEvent { pos, what: MouseEventType::MouseExit },
window,
&item,
);
}
let mut result = MouseInputState::default();
type State = (Vector2D<f32>, Vec<ItemWeak>);
crate::item_tree::visit_items(
&component,
crate::item_tree::TraversalOrder::FrontToBack,
|comp_rc: &ComponentRc,
item: core::pin::Pin<ItemRef>,
item_index: usize,
(offset, mouse_grabber_stack): &State|
-> ItemVisitorResult<State> {
let item_rc = ItemRc::new(comp_rc.clone(), item_index);
let geom = item.as_ref().geometry();
let geom = geom.translate(*offset);
if geom.contains(mouse_event.pos) {
let mut event2 = mouse_event.clone();
event2.pos -= geom.origin.to_vector();
match item.as_ref().input_event(event2, window, &item_rc) {
InputEventResult::EventAccepted => {
result.item_stack = mouse_grabber_stack.clone();
result.item_stack.push(item_rc.downgrade());
result.grabbed = false;
return ItemVisitorResult::Abort;
}
InputEventResult::EventIgnored => (),
InputEventResult::GrabMouse => {
result.item_stack = mouse_grabber_stack.clone();
result.item_stack.push(item_rc.downgrade());
result.grabbed = true;
return ItemVisitorResult::Abort;
}
InputEventResult::ObserveHover => {
result.item_stack = mouse_grabber_stack.clone();
result.item_stack.push(item_rc.downgrade());
result.grabbed = false;
}
};
}
let mut mouse_grabber_stack = mouse_grabber_stack.clone();
mouse_grabber_stack.push(item_rc.downgrade());
ItemVisitorResult::Continue((geom.origin.to_vector(), mouse_grabber_stack))
},
(Vector2D::new(0., 0.), Vec::new()),
);
result
}