use crate::kurbo::{Rect, Shape, Size, Vec2};
use druid_shell::{Clipboard, KeyEvent, TimerToken};
use crate::mouse::MouseEvent;
use crate::{Command, Target, WidgetId};
#[derive(Debug, Clone)]
pub enum Event {
WindowConnected,
WindowSize(Size),
MouseDown(MouseEvent),
MouseUp(MouseEvent),
MouseMove(MouseEvent),
Wheel(MouseEvent),
KeyDown(KeyEvent),
KeyUp(KeyEvent),
Paste(Clipboard),
Zoom(f64),
Timer(TimerToken),
Command(Command),
Internal(InternalEvent),
}
#[derive(Debug, Clone)]
pub enum InternalEvent {
MouseLeave,
TargetedCommand(Target, Command),
RouteTimer(TimerToken, WidgetId),
}
#[derive(Debug, Clone)]
pub enum LifeCycle {
WidgetAdded,
Size(Size),
AnimFrame(u64),
HotChanged(bool),
FocusChanged(bool),
Internal(InternalLifeCycle),
}
#[derive(Debug, Clone)]
pub enum InternalLifeCycle {
RouteWidgetAdded,
RouteFocusChanged {
old: Option<WidgetId>,
new: Option<WidgetId>,
},
#[cfg(test)]
DebugRequestState {
widget: WidgetId,
state_cell: StateCell,
},
#[cfg(test)]
DebugInspectState(StateCheckFn),
}
impl Event {
pub fn transform_scroll(&self, offset: Vec2, viewport: Rect, force: bool) -> Option<Event> {
match self {
Event::MouseDown(mouse_event) => {
if force || viewport.winding(mouse_event.pos) != 0 {
let mut mouse_event = mouse_event.clone();
mouse_event.pos += offset;
Some(Event::MouseDown(mouse_event))
} else {
None
}
}
Event::MouseUp(mouse_event) => {
if force || viewport.winding(mouse_event.pos) != 0 {
let mut mouse_event = mouse_event.clone();
mouse_event.pos += offset;
Some(Event::MouseUp(mouse_event))
} else {
None
}
}
Event::MouseMove(mouse_event) => {
if force || viewport.winding(mouse_event.pos) != 0 {
let mut mouse_event = mouse_event.clone();
mouse_event.pos += offset;
Some(Event::MouseMove(mouse_event))
} else {
None
}
}
Event::Wheel(mouse_event) => {
if force || viewport.winding(mouse_event.pos) != 0 {
let mut mouse_event = mouse_event.clone();
mouse_event.pos += offset;
Some(Event::Wheel(mouse_event))
} else {
None
}
}
_ => Some(self.clone()),
}
}
}
#[cfg(test)]
pub(crate) use state_cell::{StateCell, StateCheckFn};
#[cfg(test)]
mod state_cell {
use crate::core::WidgetState;
use crate::WidgetId;
use std::{cell::RefCell, rc::Rc};
#[derive(Clone, Default)]
pub struct StateCell(Rc<RefCell<Option<WidgetState>>>);
#[derive(Clone)]
pub struct StateCheckFn(Rc<dyn Fn(&WidgetState)>);
struct WidgetDrop(bool, WidgetId);
impl Drop for WidgetDrop {
fn drop(&mut self) {
if self.0 {
eprintln!("panic in {:?}", self.1);
}
}
}
impl StateCell {
pub(crate) fn set(&self, state: WidgetState) {
assert!(
self.0.borrow_mut().replace(state).is_none(),
"StateCell already set"
)
}
#[allow(dead_code)]
pub(crate) fn take(&self) -> Option<WidgetState> {
self.0.borrow_mut().take()
}
}
impl StateCheckFn {
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn new(f: impl Fn(&WidgetState) + 'static) -> Self {
StateCheckFn(Rc::new(f))
}
pub(crate) fn call(&self, state: &WidgetState) {
let mut panic_reporter = WidgetDrop(true, state.id);
(self.0)(&state);
panic_reporter.0 = false;
}
}
impl std::fmt::Debug for StateCell {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let inner = if self.0.borrow().is_some() {
"Some"
} else {
"None"
};
write!(f, "StateCell({})", inner)
}
}
impl std::fmt::Debug for StateCheckFn {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "StateCheckFn")
}
}
}