mod abilities; mod character; mod content; mod inventory; mod page_content; mod traits; use anyhow::Result; use downcast_rs::{Downcast, impl_downcast}; use engine::prelude::*; use rpg_components::{ components::{ crafting_materials::CraftingMaterials, inventory::{Inventory, Storable}, }, items::ability_book::Ability, }; use std::{ any::Any, collections::HashMap, ops::{Deref, DerefMut}, sync::{ Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard, atomic::{AtomicUsize, Ordering::SeqCst}, }, }; use self::{abilities::AbilityPage, character::CharacterPage, inventory::InventoryPage}; trait Page: Any + Send + Sync + Downcast { fn enable(&mut self, world: &mut World) -> Result>; fn disable(&mut self, world: &mut World) -> Result<()>; fn select(&self, world: &mut World) -> Result<()>; fn next_tab(&mut self, world: &mut World) -> Result<()>; fn previous_tab(&mut self, world: &mut World) -> Result<()>; fn event(&mut self, world: &mut World, button: ControllerButton) -> Result; } impl_downcast!(Page); struct Tab<'a> { index: usize, tabs: RwLockReadGuard<'a, [Box; 3]>, } impl<'a> Deref for Tab<'a> { type Target = Box; fn deref(&self) -> &Self::Target { &self.tabs[self.index] } } struct TabMut<'a> { index: usize, tabs: RwLockWriteGuard<'a, [Box; 3]>, } impl<'a> TabMut<'a> { pub fn downcast_mut(&mut self) -> &mut T { self.tabs[self.index].downcast_mut().unwrap() } } impl<'a> Deref for TabMut<'a> { type Target = Box; fn deref(&self) -> &Self::Target { &self.tabs[self.index] } } impl<'a> DerefMut for TabMut<'a> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.tabs[self.index] } } pub struct Tabs<'a> { tabs: RwLockReadGuard<'a, [Box; 3]>, } #[allow(unused)] impl<'a> Tabs<'a> { pub fn character(&mut self) -> &CharacterPage { self.tabs[0].downcast_ref().unwrap() } pub fn inventory(&mut self) -> &InventoryPage { self.tabs[1].downcast_ref().unwrap() } pub fn abilities(&mut self) -> &AbilityPage { self.tabs[2].downcast_ref().unwrap() } } pub struct TabsMut<'a> { tabs: RwLockWriteGuard<'a, [Box; 3]>, } #[allow(unused)] impl<'a> TabsMut<'a> { pub fn character(&mut self) -> &mut CharacterPage { self.tabs[0].downcast_mut().unwrap() } pub fn inventory(&mut self) -> &mut InventoryPage { self.tabs[1].downcast_mut().unwrap() } pub fn abilities(&mut self) -> &mut AbilityPage { self.tabs[2].downcast_mut().unwrap() } } pub struct CharacterWindow { close: Box, menu_gui: Arc, tab_content_grid: Arc, tooltips: Mutex>>, tabs: RwLock<[Box; 3]>, tab: AtomicUsize, } impl CharacterWindow { pub fn new( world: &mut World, hero: Entity, name: &str, close: Box, ) -> Result> { let menu_gui = GuiBuilder::from_str(world, include_str!("../resources/menu.xml"))?; let content_grid = menu_gui.element("tab_content")?; let open_character_page: Arc