Implement tab change via button

This commit is contained in:
hodasemi 2024-08-30 08:00:18 +02:00
parent cdd0959c4c
commit a629bc666b
6 changed files with 60 additions and 38 deletions

View file

@ -54,6 +54,7 @@ sdl2 = { version = "0.37.0" }
syn = { version = "2.0.67", features = ["extra-traits", "full"] } syn = { version = "2.0.67", features = ["extra-traits", "full"] }
quote = "1.0.35" quote = "1.0.35"
proc-macro2 = "1.0.86" proc-macro2 = "1.0.86"
downcast-rs = "1.2.1"
utilities = { git = "https://gavania.de/hodasemi/utilities.git" } utilities = { git = "https://gavania.de/hodasemi/utilities.git" }
vulkan-rs = { git = "https://gavania.de/hodasemi/vulkan_lib.git" } vulkan-rs = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }

View file

@ -7,6 +7,7 @@ edition = "2021"
anyhow = { workspace = true } anyhow = { workspace = true }
paste = { workspace = true } paste = { workspace = true }
destructure_traitobject = { workspace = true } destructure_traitobject = { workspace = true }
downcast-rs = { workspace = true }
engine = { path = "../engine" } engine = { path = "../engine" }
rpg_components = { path = "../rpg_components" } rpg_components = { path = "../rpg_components" }

View file

@ -56,7 +56,7 @@ impl<A: Ability + 'static> AbilityPage<A> {
// abilities // abilities
let ability_mode = PageContent::new( let ability_mode = PageContent::new(
Content::new(&engine, reference.clone(), { Content::new::<_, Self>(&engine, reference.clone(), {
let engine = engine.clone(); let engine = engine.clone();
let hero = hero.clone(); let hero = hero.clone();
@ -100,7 +100,7 @@ impl<A: Ability + 'static> AbilityPage<A> {
// addons // addons
let addons_mode = PageContent::<A, _>::new( let addons_mode = PageContent::<A, _>::new(
Content::new(&engine, reference.clone(), { Content::new::<_, Self>(&engine, reference.clone(), {
let engine = engine.clone(); let engine = engine.clone();
let hero = hero.clone(); let hero = hero.clone();

View file

@ -32,13 +32,14 @@ pub struct Content<A: Ability + 'static, T: Send + Sync> {
} }
impl<A: Ability + 'static, T: Send + Sync> Content<A, T> { impl<A: Ability + 'static, T: Send + Sync> Content<A, T> {
pub fn new<F>( pub fn new<F, P>(
engine: &Arc<Engine>, engine: &Arc<Engine>,
reference: Weak<CharacterWindow>, reference: Weak<CharacterWindow>,
on_enable: F, on_enable: F,
) -> Result<Self> ) -> Result<Self>
where where
F: Fn() -> Result<Vec<T>> + Send + Sync + 'static, F: Fn() -> Result<Vec<T>> + Send + Sync + 'static,
P: Page,
{ {
let base = GuiSnippet::from_str( let base = GuiSnippet::from_str(
engine.gui_handler(), engine.gui_handler(),
@ -48,9 +49,38 @@ impl<A: Ability + 'static, T: Send + Sync> Content<A, T> {
let left: Arc<Button> = base.element("left")?; let left: Arc<Button> = base.element("left")?;
left.set_text("<")?; left.set_text("<")?;
left.set_info_icon(&engine.controller_icon(ControllerButton::LeftTrigger)?)?; left.set_info_icon(&engine.controller_icon(ControllerButton::LeftTrigger)?)?;
left.set_callback({
let reference = reference.clone();
move || {
if let Some(window) = reference.upgrade() {
let mut tab = window.tab_mut();
let page = tab.downcast_mut::<P>();
page.previous_tab()?;
}
Ok(())
}
});
let right: Arc<Button> = base.element("right")?; let right: Arc<Button> = base.element("right")?;
right.set_text(">")?; right.set_text(">")?;
right.set_info_icon(&engine.controller_icon(ControllerButton::RightTrigger)?)?; right.set_info_icon(&engine.controller_icon(ControllerButton::RightTrigger)?)?;
right.set_callback({
let reference = reference.clone();
move || {
if let Some(window) = reference.upgrade() {
let mut tab = window.tab_mut();
let page = tab.downcast_mut::<P>();
page.next_tab()?;
}
Ok(())
}
});
Ok(Self { Ok(Self {
reference, reference,

View file

@ -58,7 +58,7 @@ impl<A: Ability + 'static> InventoryPage<A> {
// items // items
let item_mode = PageContent::<A, _>::new( let item_mode = PageContent::<A, _>::new(
Content::new(engine, reference.clone(), { Content::new::<_, Self>(engine, reference.clone(), {
let engine = engine.clone(); let engine = engine.clone();
let hero = hero.clone(); let hero = hero.clone();
@ -107,7 +107,7 @@ impl<A: Ability + 'static> InventoryPage<A> {
// jewels // jewels
let jewel_mode = PageContent::<A, _>::new( let jewel_mode = PageContent::<A, _>::new(
Content::new(engine, reference.clone(), { Content::new::<_, Self>(engine, reference.clone(), {
let engine = engine.clone(); let engine = engine.clone();
let hero = hero.clone(); let hero = hero.clone();
@ -153,7 +153,7 @@ impl<A: Ability + 'static> InventoryPage<A> {
// maps // maps
let map_mode = PageContent::<A, _>::new( let map_mode = PageContent::<A, _>::new(
Content::new(engine, reference.clone(), { Content::new::<_, Self>(engine, reference.clone(), {
let engine = engine.clone(); let engine = engine.clone();
let hero: Entity = hero.clone(); let hero: Entity = hero.clone();

View file

@ -6,6 +6,7 @@ mod page_content;
mod traits; mod traits;
use anyhow::Result; use anyhow::Result;
use downcast_rs::{impl_downcast, Downcast};
use engine::prelude::*; use engine::prelude::*;
use rpg_components::{ use rpg_components::{
components::{ components::{
@ -18,7 +19,6 @@ use rpg_components::{
use std::{ use std::{
any::Any, any::Any,
collections::HashMap, collections::HashMap,
mem::transmute,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
sync::{ sync::{
atomic::{AtomicUsize, Ordering::SeqCst}, atomic::{AtomicUsize, Ordering::SeqCst},
@ -28,7 +28,7 @@ use std::{
use self::{abilities::AbilityPage, character::CharacterPage, inventory::InventoryPage}; use self::{abilities::AbilityPage, character::CharacterPage, inventory::InventoryPage};
trait Page: Any + Send + Sync { trait Page: Any + Send + Sync + Downcast {
fn enable(&mut self) -> Result<Arc<Grid>>; fn enable(&mut self) -> Result<Arc<Grid>>;
fn disable(&mut self) -> Result<()>; fn disable(&mut self) -> Result<()>;
fn select(&self) -> Result<()>; fn select(&self) -> Result<()>;
@ -37,6 +37,8 @@ trait Page: Any + Send + Sync {
fn event(&mut self, button: ControllerButton) -> Result<bool>; fn event(&mut self, button: ControllerButton) -> Result<bool>;
} }
impl_downcast!(Page);
struct Tab<'a> { struct Tab<'a> {
index: usize, index: usize,
tabs: RwLockReadGuard<'a, [Box<dyn Page>; 3]>, tabs: RwLockReadGuard<'a, [Box<dyn Page>; 3]>,
@ -55,6 +57,12 @@ struct TabMut<'a> {
tabs: RwLockWriteGuard<'a, [Box<dyn Page>; 3]>, tabs: RwLockWriteGuard<'a, [Box<dyn Page>; 3]>,
} }
impl<'a> TabMut<'a> {
pub fn downcast_mut<T: Page>(&mut self) -> &mut T {
self.tabs[self.index].downcast_mut().unwrap()
}
}
impl<'a> Deref for TabMut<'a> { impl<'a> Deref for TabMut<'a> {
type Target = Box<dyn Page>; type Target = Box<dyn Page>;
@ -75,25 +83,16 @@ pub struct Tabs<'a> {
#[allow(unused)] #[allow(unused)]
impl<'a> Tabs<'a> { impl<'a> Tabs<'a> {
pub fn character(&mut self) -> &'a CharacterPage { pub fn character(&mut self) -> &CharacterPage {
Self::downcast_unchecked(&self.tabs[0]) self.tabs[0].downcast_ref().unwrap()
} }
pub fn inventory<A: Ability + 'static>(&mut self) -> &'a InventoryPage<A> { pub fn inventory<A: Ability + 'static>(&mut self) -> &InventoryPage<A> {
Self::downcast_unchecked(&self.tabs[1]) self.tabs[1].downcast_ref().unwrap()
} }
pub fn abilities<A: Ability + 'static>(&mut self) -> &'a AbilityPage<A> { pub fn abilities<A: Ability + 'static>(&mut self) -> &AbilityPage<A> {
Self::downcast_unchecked(&self.tabs[2]) self.tabs[2].downcast_ref().unwrap()
}
fn downcast_unchecked<T: Page>(boxed_ref: &Box<dyn Page>) -> &'a T {
unsafe {
let ptr_to_ptr: *const *const T =
transmute(destructure_traitobject::data(boxed_ref as *const _));
&**ptr_to_ptr
}
} }
} }
@ -103,25 +102,16 @@ pub struct TabsMut<'a> {
#[allow(unused)] #[allow(unused)]
impl<'a> TabsMut<'a> { impl<'a> TabsMut<'a> {
pub fn character(&mut self) -> &'a mut CharacterPage { pub fn character(&mut self) -> &mut CharacterPage {
Self::downcast_mut_unchecked(&mut self.tabs[0]) self.tabs[0].downcast_mut().unwrap()
} }
pub fn inventory<A: Ability + 'static>(&mut self) -> &'a mut InventoryPage<A> { pub fn inventory<A: Ability + 'static>(&mut self) -> &mut InventoryPage<A> {
Self::downcast_mut_unchecked(&mut self.tabs[1]) self.tabs[1].downcast_mut().unwrap()
} }
pub fn abilities<A: Ability + 'static>(&mut self) -> &'a mut AbilityPage<A> { pub fn abilities<A: Ability + 'static>(&mut self) -> &mut AbilityPage<A> {
Self::downcast_mut_unchecked(&mut self.tabs[2]) self.tabs[2].downcast_mut().unwrap()
}
fn downcast_mut_unchecked<T: Page>(boxed_ref: &mut Box<dyn Page>) -> &'a mut T {
unsafe {
let ptr_to_ptr: *mut *mut T =
transmute(destructure_traitobject::data(boxed_ref as *mut _));
&mut **ptr_to_ptr
}
} }
} }