use crate::VDom;
use crate::key::{Key, KeyWithModifiers};
use crate::render_tree::RenderNode;
use crossterm::event::{KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};
use std::cell::RefCell;
use std::rc::Rc;
pub fn handle_key_event(vdom: &VDom, key_event: KeyEvent) {
if let Some(key) = Key::from_key_code(key_event.code) {
let render_tree = vdom.get_render_tree();
if key == Key::Tab {
render_tree.focus_next();
return;
}
if key == Key::BackTab {
render_tree.focus_prev();
return;
}
if key == Key::Esc {
if render_tree.get_focused_node().is_some() {
render_tree.set_focused_node(None);
return;
}
}
if key == Key::Enter
&& let Some(focused) = render_tree.get_focused_node()
{
focused.borrow().handle_click();
return;
}
if let Some(key_with_modifiers) = KeyWithModifiers::from_key_event(key_event) {
if let Some(root) = &render_tree.root {
broadcast_global_key_with_modifiers(root, key_with_modifiers);
broadcast_global_key(root, key);
}
if let Some(focused) = render_tree.get_focused_node() {
let mut handled = false;
if focused.borrow().scrollable && focused.borrow().focused {
handled = handle_scroll_key(&focused, key);
}
if !handled {
focused
.borrow()
.handle_key_with_modifiers(key_with_modifiers);
if !key_event.modifiers.contains(KeyModifiers::CONTROL)
&& !key_event.modifiers.contains(KeyModifiers::ALT)
&& !key_event.modifiers.contains(KeyModifiers::META)
{
focused.borrow().handle_key(key);
}
}
} else {
if let Some(root) = &render_tree.root {
broadcast_key_with_modifiers(root, key_with_modifiers);
if !key_event.modifiers.contains(KeyModifiers::CONTROL)
&& !key_event.modifiers.contains(KeyModifiers::ALT)
&& !key_event.modifiers.contains(KeyModifiers::META)
{
broadcast_key(root, key);
}
}
}
} else {
if let Some(root) = &render_tree.root {
broadcast_global_key(root, key);
}
if let Some(focused) = render_tree.get_focused_node() {
focused.borrow().handle_key(key);
} else {
if let Some(root) = &render_tree.root {
broadcast_key(root, key);
}
}
}
}
}
pub fn broadcast_key(node: &Rc<RefCell<RenderNode>>, key: Key) {
let node_ref = node.borrow();
node_ref.handle_key(key);
for child in &node_ref.children {
broadcast_key(child, key);
}
}
pub fn broadcast_global_key(node: &Rc<RefCell<RenderNode>>, key: Key) {
let node_ref = node.borrow();
node_ref.handle_global_key(key);
let children = node_ref.children.clone();
drop(node_ref); for child in &children {
broadcast_global_key(child, key);
}
}
pub fn broadcast_key_with_modifiers(
node: &Rc<RefCell<RenderNode>>,
key_with_modifiers: KeyWithModifiers,
) {
let node_ref = node.borrow();
node_ref.handle_key_with_modifiers(key_with_modifiers);
for child in &node_ref.children {
broadcast_key_with_modifiers(child, key_with_modifiers);
}
}
pub fn broadcast_global_key_with_modifiers(
node: &Rc<RefCell<RenderNode>>,
key_with_modifiers: KeyWithModifiers,
) {
let node_ref = node.borrow();
node_ref.handle_global_key_with_modifiers(key_with_modifiers);
let children = node_ref.children.clone();
drop(node_ref); for child in &children {
broadcast_global_key_with_modifiers(child, key_with_modifiers);
}
}
pub fn handle_mouse_event(vdom: &VDom, mouse_event: MouseEvent) {
let render_tree = vdom.get_render_tree();
match mouse_event.kind {
MouseEventKind::Down(_) => {
if let Some(node) = render_tree.find_node_at(mouse_event.column, mouse_event.row) {
{
let node_ref = node.borrow();
if node_ref.focusable {
drop(node_ref); render_tree.set_focused_node(Some(node.clone()));
}
}
node.borrow().handle_click();
}
}
MouseEventKind::ScrollUp => {
if let Some(node) = render_tree.find_node_at(mouse_event.column, mouse_event.row) {
if let Some(scrollable_node) = find_scrollable_ancestor(&node) {
let mut node_ref = scrollable_node.borrow_mut();
if node_ref.update_scroll(-3) {
node_ref.mark_dirty();
}
}
}
}
MouseEventKind::ScrollDown => {
if let Some(node) = render_tree.find_node_at(mouse_event.column, mouse_event.row) {
if let Some(scrollable_node) = find_scrollable_ancestor(&node) {
let mut node_ref = scrollable_node.borrow_mut();
if node_ref.update_scroll(3) {
node_ref.mark_dirty();
}
}
}
}
_ => {}
}
}
fn find_scrollable_ancestor(node: &Rc<RefCell<RenderNode>>) -> Option<Rc<RefCell<RenderNode>>> {
if node.borrow().scrollable {
return Some(node.clone());
}
let parent_weak = node.borrow().parent.clone();
if let Some(parent_weak) = parent_weak
&& let Some(parent) = parent_weak.upgrade()
{
return find_scrollable_ancestor(&parent);
}
None
}
fn handle_scroll_key(node: &Rc<RefCell<RenderNode>>, key: Key) -> bool {
let mut node_ref = node.borrow_mut();
if !node_ref.scrollable {
return false;
}
match key {
Key::Up => {
if node_ref.update_scroll(-1) {
node_ref.mark_dirty();
return true;
}
}
Key::Down => {
if node_ref.update_scroll(1) {
node_ref.mark_dirty();
return true;
}
}
Key::PageUp => {
let scroll_amount = (node_ref.height / 2).max(1) as i16;
if node_ref.update_scroll(-scroll_amount) {
node_ref.mark_dirty();
return true;
}
}
Key::PageDown => {
let scroll_amount = (node_ref.height / 2).max(1) as i16;
if node_ref.update_scroll(scroll_amount) {
node_ref.mark_dirty();
return true;
}
}
Key::Home => {
node_ref.set_scroll_y(0);
node_ref.mark_dirty();
return true;
}
Key::End => {
let max_y = node_ref.get_max_scroll_y();
node_ref.set_scroll_y(max_y);
node_ref.mark_dirty();
return true;
}
_ => {}
}
false
}