rpg_base/character_window/src/content.rs

219 lines
5.9 KiB
Rust
Raw Normal View History

2025-02-28 07:43:35 +00:00
use std::{
marker::PhantomData,
sync::{Arc, Weak},
};
use crate::*;
pub trait ContentWrapper: ContentUpdate + Send + Sync {
2025-03-05 08:45:39 +00:00
fn refresh(&mut self, world: &mut World) -> Result<()>;
fn next_tab(&mut self, world: &mut World, hero: Entity) -> Result<()>;
fn previous_tab(&mut self, world: &mut World, hero: Entity) -> Result<()>;
2025-02-28 07:43:35 +00:00
fn base(&self) -> &Arc<GuiSnippet>;
fn is_empty(&self) -> bool;
}
pub trait ContentUpdate {
2025-03-05 08:45:39 +00:00
fn update(&mut self, world: &mut World, hero: Entity) -> Result<()>;
fn select(&self, world: &mut World) -> Result<()>;
2025-02-28 07:43:35 +00:00
}
pub struct Content<A: Ability + 'static, T: Send + Sync> {
pub reference: Weak<CharacterWindow>,
base: Arc<GuiSnippet>,
data: Vec<T>,
2025-03-05 08:45:39 +00:00
on_enable: Box<dyn Fn(&mut World) -> Result<Vec<T>> + Send + Sync + 'static>,
2025-02-28 07:43:35 +00:00
page: usize,
pages: usize,
ability_marker: PhantomData<A>,
}
impl<A: Ability + 'static, T: Send + Sync> Content<A, T> {
pub fn new<F, P>(
2025-03-05 08:45:39 +00:00
world: &mut World,
2025-02-28 07:43:35 +00:00
reference: Weak<CharacterWindow>,
on_enable: F,
) -> Result<Self>
where
2025-03-05 08:45:39 +00:00
F: Fn(&mut World) -> Result<Vec<T>> + Send + Sync + 'static,
2025-02-28 07:43:35 +00:00
P: Page,
{
2025-03-05 08:45:39 +00:00
let base = GuiSnippet::from_str(world, include_str!("../resources/content.xml"))?;
2025-04-05 10:16:34 +00:00
let (gui_handler, engine_settings, context): (
&mut GuiHandler,
&mut EngineSettings,
&mut Context,
) = world.resources.get_mut()?;
2025-02-28 07:43:35 +00:00
let left: Arc<Button> = base.element("left")?;
2025-03-05 08:45:39 +00:00
left.set_text(gui_handler, "<")?;
left.set_info_icon(
gui_handler,
&engine_settings.controller_icon(context, ControllerButton::LeftTrigger)?,
)?;
2025-02-28 07:43:35 +00:00
left.set_callback({
let reference = reference.clone();
2025-03-05 08:45:39 +00:00
move |world| {
2025-02-28 07:43:35 +00:00
if let Some(window) = reference.upgrade() {
let mut tab = window.tab_mut();
let page = tab.downcast_mut::<P>();
2025-03-05 08:45:39 +00:00
page.previous_tab(world)?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
});
let right: Arc<Button> = base.element("right")?;
2025-03-05 08:45:39 +00:00
right.set_text(gui_handler, ">")?;
right.set_info_icon(
gui_handler,
&engine_settings.controller_icon(context, ControllerButton::RightTrigger)?,
)?;
2025-02-28 07:43:35 +00:00
right.set_callback({
let reference = reference.clone();
2025-03-05 08:45:39 +00:00
move |world| {
2025-02-28 07:43:35 +00:00
if let Some(window) = reference.upgrade() {
let mut tab = window.tab_mut();
let page = tab.downcast_mut::<P>();
2025-03-05 08:45:39 +00:00
page.next_tab(world)?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
});
Ok(Self {
reference,
base,
data: Vec::new(),
on_enable: Box::new(on_enable),
page: 0,
pages: 1,
ability_marker: PhantomData,
})
}
2025-03-05 08:45:39 +00:00
fn clear_grid(world: &mut World, grid: &Arc<Grid>) -> Result<()> {
2025-02-28 07:43:35 +00:00
let (rows, columns) = grid.dimensions();
for x in 0..columns {
for y in 0..rows {
2025-03-05 08:45:39 +00:00
grid.detach(world, x, y)?;
2025-02-28 07:43:35 +00:00
}
}
Ok(())
}
2025-03-05 08:45:39 +00:00
fn set_tab(&self, gui_handler: &mut GuiHandler, label: &Arc<Label>) -> Result<()> {
label.set_text(gui_handler, format!("{} / {}", self.page + 1, self.pages))
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
pub fn update_base<F>(&mut self, world: &mut World, setup: F) -> Result<()>
2025-02-28 07:43:35 +00:00
where
Self: ContentWrapper,
2025-03-05 08:45:39 +00:00
F: Fn(&mut World, &Arc<Button>, &T, usize) -> Result<()>,
2025-02-28 07:43:35 +00:00
{
2025-03-05 08:45:39 +00:00
self.refresh(world)?;
2025-02-28 07:43:35 +00:00
let grid: Arc<Grid> = self.base.element("content")?;
let label: Arc<Label> = self.base.element("tab_info")?;
2025-03-05 08:45:39 +00:00
Self::clear_grid(world, &grid)?;
2025-04-05 11:45:08 +00:00
self.set_tab(world.resources.get_mut()?, &label)?;
2025-02-28 07:43:35 +00:00
let (rows, columns) = grid.dimensions();
'outer: for y in 0..rows {
for x in 0..columns {
let index = (self.page * columns * rows) + y * columns + x;
match self.data.get(index) {
Some(t) => {
let snippet = GuiSnippet::from_str(
2025-03-05 08:45:39 +00:00
world,
2025-02-28 07:43:35 +00:00
include_str!("../resources/content_button.xml"),
)?;
let button: Arc<Button> = snippet.element("button")?;
2025-03-05 08:45:39 +00:00
setup(world, &button, t, index)?;
grid.attach(world, button, x, y, 1, 1)?;
2025-02-28 07:43:35 +00:00
}
None => break 'outer,
}
}
}
Ok(())
}
2025-03-05 08:45:39 +00:00
pub fn select(&self, gui_handler: &mut GuiHandler) -> Result<()> {
2025-02-28 07:43:35 +00:00
let grid: Arc<Grid> = self.base.element("content")?;
if let Some(child) = grid.child_at(0, 0)? {
2025-03-05 08:45:39 +00:00
child
.gridable()
.unwrap()
.selectable()
.unwrap()
.select(gui_handler)?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
}
impl<A: Ability + 'static, T: Send + Sync> ContentWrapper for Content<A, T>
where
Content<A, T>: ContentUpdate,
{
2025-03-05 08:45:39 +00:00
fn refresh(&mut self, world: &mut World) -> Result<()> {
self.data = (self.on_enable)(world)?;
2025-02-28 07:43:35 +00:00
let grid: Arc<Grid> = self.base.element("content")?;
let (rows, columns) = grid.dimensions();
self.pages = 1.max((self.data.len() as f32 / (rows * columns) as f32).ceil() as usize);
Ok(())
}
2025-03-05 08:45:39 +00:00
fn next_tab(&mut self, world: &mut World, hero: Entity) -> Result<()> {
2025-02-28 07:43:35 +00:00
if self.page < (self.pages - 1) {
self.page += 1;
2025-03-05 08:45:39 +00:00
self.update(world, hero)?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
2025-03-05 08:45:39 +00:00
fn previous_tab(&mut self, world: &mut World, hero: Entity) -> Result<()> {
2025-02-28 07:43:35 +00:00
if self.page > 0 {
self.page -= 1;
2025-03-05 08:45:39 +00:00
self.update(world, hero)?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
fn base(&self) -> &Arc<GuiSnippet> {
&self.base
}
fn is_empty(&self) -> bool {
self.data.is_empty()
}
}