use crate::event::{Event as InputEvent, KeyEvent, MouseEvent, MouseEventKind, MouseButton};
use crate::ui::WidgetId;
use std::collections::VecDeque;
#[derive(Debug, Clone, PartialEq)]
pub enum UIEvent {
Input(InputEvent),
Widget(WidgetEvent),
App(AppEvent),
}
#[derive(Debug, Clone, PartialEq)]
pub enum WidgetEvent {
FocusGained(WidgetId),
FocusLost(WidgetId),
MouseEnter(WidgetId),
MouseLeave(WidgetId),
Click(WidgetId, u16, u16),
ValueChanged(WidgetId, WidgetValue),
Custom(WidgetId, String, WidgetValue),
}
#[derive(Debug, Clone, PartialEq)]
pub enum AppEvent {
Quit,
Redraw,
Timer(String, f32),
ThemeChanged(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum WidgetValue {
None,
Bool(bool),
Int(i32),
Float(f32),
String(String),
Point(u16, u16),
}
impl From<InputEvent> for UIEvent {
fn from(event: InputEvent) -> Self {
UIEvent::Input(event)
}
}
impl From<WidgetEvent> for UIEvent {
fn from(event: WidgetEvent) -> Self {
UIEvent::Widget(event)
}
}
impl From<AppEvent> for UIEvent {
fn from(event: AppEvent) -> Self {
UIEvent::App(event)
}
}
pub trait EventHandler {
fn handle_event(&mut self, event: &UIEvent) -> bool;
}
#[derive(Default)]
pub struct EventDispatcher {
focused_widget: Option<WidgetId>,
hovered_widget: Option<WidgetId>,
event_queue: VecDeque<UIEvent>,
}
impl EventDispatcher {
pub fn new() -> Self {
Default::default()
}
pub fn set_focus(&mut self, widget_id: Option<WidgetId>) {
if self.focused_widget != widget_id {
if let Some(old_id) = self.focused_widget {
self.emit_event(WidgetEvent::FocusLost(old_id).into());
}
self.focused_widget = widget_id;
if let Some(new_id) = widget_id {
self.emit_event(WidgetEvent::FocusGained(new_id).into());
}
}
}
pub fn focused_widget(&self) -> Option<WidgetId> {
self.focused_widget
}
pub fn set_hover(&mut self, widget_id: Option<WidgetId>) {
if self.hovered_widget != widget_id {
if let Some(old_id) = self.hovered_widget {
self.emit_event(WidgetEvent::MouseLeave(old_id).into());
}
self.hovered_widget = widget_id;
if let Some(new_id) = widget_id {
self.emit_event(WidgetEvent::MouseEnter(new_id).into());
}
}
}
pub fn hovered_widget(&self) -> Option<WidgetId> {
self.hovered_widget
}
pub fn emit_event(&mut self, event: UIEvent) {
self.event_queue.push_back(event);
}
pub fn process_input(&mut self, input_event: InputEvent) {
match &input_event {
InputEvent::Mouse(mouse_event) => {
self.process_mouse_event(mouse_event);
}
InputEvent::Key(key_event) => {
self.process_key_event(key_event);
}
}
self.emit_event(UIEvent::Input(input_event));
}
fn process_mouse_event(&mut self, mouse_event: &MouseEvent) {
match mouse_event.kind {
MouseEventKind::Down(MouseButton::Left) => {
if let Some(widget_id) = self.hovered_widget {
self.emit_event(WidgetEvent::Click(widget_id, mouse_event.column, mouse_event.row).into());
}
}
MouseEventKind::Moved => {
}
_ => {}
}
}
fn process_key_event(&mut self, _key_event: &KeyEvent) {
}
pub fn next_event(&mut self) -> Option<UIEvent> {
self.event_queue.pop_front()
}
pub fn drain_events(&mut self) -> Vec<UIEvent> {
self.event_queue.drain(..).collect()
}
pub fn has_events(&self) -> bool {
!self.event_queue.is_empty()
}
pub fn clear_events(&mut self) {
self.event_queue.clear();
}
}
pub type ClickCallback = Box<dyn FnMut(&mut dyn std::any::Any) + Send>;
pub type ValueChangedCallback = Box<dyn FnMut(&mut dyn std::any::Any, WidgetValue) + Send>;
pub type GenericCallback = Box<dyn FnMut(&mut dyn std::any::Any, &UIEvent) + Send>;
#[macro_export]
macro_rules! ui_event_handler {
($widget:expr, $event:pat => $body:expr) => {
|event: &UIEvent| {
match event {
$event => {
$body;
true
}
_ => false
}
}
};
}