use crate::prelude::*; use anyhow::Result; use ecs::World; use std::any::Any; use std::collections::HashMap; use std::{ ops::Deref, sync::{Arc, RwLock}, }; #[derive(Debug)] enum KeyboardMode { LowerCase, UpperCase, Specials, } pub struct Keyboard { text_field_gui: Arc, text_field: Arc, lower_case: Arc, upper_case: Arc, specials: Arc, mode: Arc>, decline_callback: Arc Result<()> + Send + Sync>>>>, accept_callback: Arc Result<()> + Send + Sync>>>>, elements: HashMap, } impl Keyboard { pub fn new(gui_handler: &mut GuiHandler) -> Result> { let text_field_gui: Arc = GuiBuilder::from_str(gui_handler, include_str!("text_field.xml"))?; let text_field: Arc = text_field_gui.element("field")?; let decline_callback: Arc< RwLock Result<()> + Send + Sync>>>, > = Arc::new(RwLock::new(None)); let accept_callback: Arc< RwLock Result<()> + Send + Sync>>>, > = Arc::new(RwLock::new(None)); let mode = Arc::new(RwLock::new(KeyboardMode::UpperCase)); let (lower_case, upper_case, specials) = Self::setup( gui_handler, text_field.clone(), &mode, decline_callback.clone(), accept_callback.clone(), )?; let mut elements = HashMap::new(); elements.insert( "text".to_string(), UiElement::TextField(Arc::downgrade(&text_field)), ); Ok(Arc::new(Keyboard { text_field_gui, text_field, lower_case, upper_case, specials, mode, decline_callback, accept_callback, elements, })) } fn setup( gui_handler: &mut GuiHandler, textfield: Arc, mode: &Arc>, decline_callback: Arc Result<()> + Send + Sync>>>>, accept_callback: Arc< RwLock Result<()> + Send + Sync>>>, >, ) -> Result<(Arc, Arc, Arc)> { let lower_case = GuiBuilder::from_str(gui_handler, include_str!("lower_case.xml"))?; let upper_case = GuiBuilder::from_str(gui_handler, include_str!("upper_case.xml"))?; let specials = GuiBuilder::from_str(gui_handler, include_str!("specials.xml"))?; // first row Self::set_text_callback(&lower_case, "q", textfield.clone())?; Self::set_text_callback(&lower_case, "w", textfield.clone())?; Self::set_text_callback(&lower_case, "e", textfield.clone())?; Self::set_text_callback(&lower_case, "r", textfield.clone())?; Self::set_text_callback(&lower_case, "t", textfield.clone())?; Self::set_text_callback(&lower_case, "y", textfield.clone())?; Self::set_text_callback(&lower_case, "u", textfield.clone())?; Self::set_text_callback(&lower_case, "i", textfield.clone())?; Self::set_text_callback(&lower_case, "o", textfield.clone())?; Self::set_text_callback(&lower_case, "p", textfield.clone())?; // second row Self::set_text_callback(&lower_case, "a", textfield.clone())?; Self::set_text_callback(&lower_case, "s", textfield.clone())?; Self::set_text_callback(&lower_case, "d", textfield.clone())?; Self::set_text_callback(&lower_case, "f", textfield.clone())?; Self::set_text_callback(&lower_case, "g", textfield.clone())?; Self::set_text_callback(&lower_case, "h", textfield.clone())?; Self::set_text_callback(&lower_case, "j", textfield.clone())?; Self::set_text_callback(&lower_case, "k", textfield.clone())?; Self::set_text_callback(&lower_case, "l", textfield.clone())?; // third row Self::set_text_callback(&lower_case, "z", textfield.clone())?; Self::set_text_callback(&lower_case, "x", textfield.clone())?; Self::set_text_callback(&lower_case, "c", textfield.clone())?; Self::set_text_callback(&lower_case, "v", textfield.clone())?; Self::set_text_callback(&lower_case, "b", textfield.clone())?; Self::set_text_callback(&lower_case, "n", textfield.clone())?; Self::set_text_callback(&lower_case, "m", textfield.clone())?; // first row Self::set_text_callback(&upper_case, "Q", textfield.clone())?; Self::set_text_callback(&upper_case, "W", textfield.clone())?; Self::set_text_callback(&upper_case, "E", textfield.clone())?; Self::set_text_callback(&upper_case, "R", textfield.clone())?; Self::set_text_callback(&upper_case, "T", textfield.clone())?; Self::set_text_callback(&upper_case, "Y", textfield.clone())?; Self::set_text_callback(&upper_case, "U", textfield.clone())?; Self::set_text_callback(&upper_case, "I", textfield.clone())?; Self::set_text_callback(&upper_case, "O", textfield.clone())?; Self::set_text_callback(&upper_case, "P", textfield.clone())?; // second row Self::set_text_callback(&upper_case, "A", textfield.clone())?; Self::set_text_callback(&upper_case, "S", textfield.clone())?; Self::set_text_callback(&upper_case, "D", textfield.clone())?; Self::set_text_callback(&upper_case, "F", textfield.clone())?; Self::set_text_callback(&upper_case, "G", textfield.clone())?; Self::set_text_callback(&upper_case, "H", textfield.clone())?; Self::set_text_callback(&upper_case, "J", textfield.clone())?; Self::set_text_callback(&upper_case, "K", textfield.clone())?; Self::set_text_callback(&upper_case, "L", textfield.clone())?; // third row Self::set_text_callback(&upper_case, "Z", textfield.clone())?; Self::set_text_callback(&upper_case, "X", textfield.clone())?; Self::set_text_callback(&upper_case, "C", textfield.clone())?; Self::set_text_callback(&upper_case, "V", textfield.clone())?; Self::set_text_callback(&upper_case, "B", textfield.clone())?; Self::set_text_callback(&upper_case, "N", textfield.clone())?; Self::set_text_callback(&upper_case, "M", textfield.clone())?; // first row Self::set_text_callback(&specials, "1", textfield.clone())?; Self::set_text_callback(&specials, "2", textfield.clone())?; Self::set_text_callback(&specials, "3", textfield.clone())?; Self::set_text_callback(&specials, "4", textfield.clone())?; Self::set_text_callback(&specials, "5", textfield.clone())?; Self::set_text_callback(&specials, "6", textfield.clone())?; Self::set_text_callback(&specials, "7", textfield.clone())?; Self::set_text_callback(&specials, "8", textfield.clone())?; Self::set_text_callback(&specials, "9", textfield.clone())?; Self::set_text_callback(&specials, "0", textfield.clone())?; // second row Self::set_text_callback(&specials, "!", textfield.clone())?; Self::set_text_callback(&specials, "^", textfield.clone())?; Self::set_text_callback(&specials, "\\", textfield.clone())?; Self::set_text_callback(&specials, "*", textfield.clone())?; Self::set_text_callback(&specials, "%", textfield.clone())?; Self::set_text_callback(&specials, "~", textfield.clone())?; Self::set_text_callback(&specials, "/", textfield.clone())?; Self::set_text_callback(&specials, "(", textfield.clone())?; Self::set_text_callback(&specials, ")", textfield.clone())?; Self::set_text_callback(&specials, "=", textfield.clone())?; // third row Self::set_text_callback(&specials, "#", textfield.clone())?; Self::set_text_callback(&specials, "+", textfield.clone())?; Self::set_text_callback(&specials, "{", textfield.clone())?; Self::set_text_callback(&specials, "}", textfield.clone())?; Self::set_text_callback(&specials, ":", textfield.clone())?; Self::set_text_callback(&specials, ";", textfield.clone())?; Self::set_text_callback(&specials, "-", textfield.clone())?; Self::set_text_callback(&specials, ",", textfield.clone())?; Self::set_text_callback(&specials, ".", textfield.clone())?; Self::set_text_callback(&specials, "_", textfield.clone())?; let back = Box::new(move |world: &mut World| { if let Some(callback) = decline_callback.read().unwrap().as_ref() { (callback)(world)?; } Ok(()) }); let accept = { let weak_textfield = Arc::downgrade(&textfield); let weak_accept = Arc::downgrade(&accept_callback); Box::new(move |world: &mut World| { if let Some(textfield) = weak_textfield.upgrade() { if let Some(accept_callback) = weak_accept.upgrade() { if let Some(text) = textfield.text() { if let Some(callback) = accept_callback.read().unwrap().as_ref() { (callback)(world, &text)?; } } } } Ok(()) }) }; let switch_to_upper = { let mode = mode.clone(); let weak_lower = Arc::downgrade(&lower_case); let weak_upper = Arc::downgrade(&upper_case); Box::new(move |world: &mut World| { if let Some(lower) = weak_lower.upgrade() { if let Some(upper) = weak_upper.upgrade() { let mut mode = mode.write().unwrap(); if let KeyboardMode::LowerCase = mode.deref() { *mode = KeyboardMode::UpperCase; let gui_handler = world.resources.get_mut::(); lower.disable(gui_handler)?; upper.enable(gui_handler)?; } } } Ok(()) }) }; let switch_to_special = { let mode = mode.clone(); let weak_upper = Arc::downgrade(&upper_case); let weak_specials = Arc::downgrade(&specials); Box::new(move |world: &mut World| { if let Some(specials) = weak_specials.upgrade() { if let Some(upper) = weak_upper.upgrade() { let mut mode = mode.write().unwrap(); if let KeyboardMode::UpperCase = mode.deref() { *mode = KeyboardMode::Specials; let gui_handler = world.resources.get_mut::(); upper.disable(gui_handler)?; specials.enable(gui_handler)?; } } } Ok(()) }) }; let switch_to_lower = { let mode = mode.clone(); let weak_lower = Arc::downgrade(&lower_case); let weak_specials = Arc::downgrade(&specials); Box::new(move |world: &mut World| { if let Some(lower) = weak_lower.upgrade() { if let Some(specials) = weak_specials.upgrade() { let mut mode = mode.write().unwrap(); if let KeyboardMode::Specials = mode.deref() { *mode = KeyboardMode::LowerCase; let gui_handler = world.resources.get_mut::(); specials.disable(gui_handler)?; lower.enable(gui_handler)?; } } } Ok(()) }) }; let space_bar = { let weak_textfield = Arc::downgrade(&textfield); Box::new(move |world: &mut World| { if let Some(text_field) = weak_textfield.upgrade() { let gui_handler = world.resources.get_mut::(); text_field.add_letter(gui_handler, ' ')?; } Ok(()) }) }; lower_case.set_click_callbacks(vec![ ("back", back.clone()), ("enter", accept.clone()), ("switch", switch_to_upper), ("space_bar", space_bar.clone()), ])?; specials.set_click_callbacks(vec![ ("back", back.clone()), ("enter", accept.clone()), ("switch", switch_to_lower), ("space_bar", space_bar.clone()), ])?; upper_case.set_click_callbacks(vec![ ("back", back), ("enter", accept), ("switch", switch_to_special), ("space_bar", space_bar), ])?; Ok((lower_case, upper_case, specials)) } fn set_text_callback( builder: &Arc, letter: &str, textfield: Arc, ) -> Result<()> { let button_ref: Arc