167 lines
4.4 KiB
Rust
167 lines
4.4 KiB
Rust
use std::sync::{Arc, Weak};
|
|
|
|
use crate::*;
|
|
|
|
pub trait ContentWrapper: ContentUpdate + Send + Sync {
|
|
fn refresh(&mut self) -> Result<()>;
|
|
fn next_tab(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()>;
|
|
fn previous_tab(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()>;
|
|
fn base(&self) -> &Arc<GuiSnippet>;
|
|
fn is_empty(&self) -> bool;
|
|
}
|
|
|
|
pub trait ContentUpdate {
|
|
fn update(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()>;
|
|
fn select(&self) -> Result<()>;
|
|
}
|
|
|
|
pub struct Content<T: Send + Sync> {
|
|
pub reference: Weak<CharacterWindow>,
|
|
base: Arc<GuiSnippet>,
|
|
data: Vec<T>,
|
|
|
|
on_enable: Box<dyn Fn() -> Result<Vec<T>> + Send + Sync + 'static>,
|
|
|
|
page: usize,
|
|
pages: usize,
|
|
}
|
|
|
|
impl<T: Send + Sync> Content<T> {
|
|
pub fn new<F>(
|
|
engine: &Arc<Engine>,
|
|
reference: Weak<CharacterWindow>,
|
|
on_enable: F,
|
|
) -> Result<Self>
|
|
where
|
|
F: Fn() -> Result<Vec<T>> + Send + Sync + 'static,
|
|
{
|
|
let base = GuiSnippet::from_str(
|
|
engine.gui_handler(),
|
|
include_str!("../resources/content.xml"),
|
|
)?;
|
|
|
|
let left: Arc<Button> = base.element("left")?;
|
|
left.set_text("<")?;
|
|
left.set_info_icon(&engine.controller_icon(ControllerButton::LeftTrigger)?)?;
|
|
let right: Arc<Button> = base.element("right")?;
|
|
right.set_text(">")?;
|
|
right.set_info_icon(&engine.controller_icon(ControllerButton::RightTrigger)?)?;
|
|
|
|
Ok(Self {
|
|
reference,
|
|
base,
|
|
data: Vec::new(),
|
|
|
|
on_enable: Box::new(on_enable),
|
|
|
|
page: 0,
|
|
pages: 1,
|
|
})
|
|
}
|
|
|
|
fn clear_grid(grid: &Arc<Grid>) -> Result<()> {
|
|
let (rows, columns) = grid.dimensions();
|
|
|
|
for x in 0..columns {
|
|
for y in 0..rows {
|
|
grid.detach(x, y)?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn set_tab(&self, label: &Arc<Label>) -> Result<()> {
|
|
label.set_text(format!("{} / {}", self.page + 1, self.pages))
|
|
}
|
|
|
|
pub fn update_base<F>(&mut self, engine: &Arc<Engine>, setup: F) -> Result<()>
|
|
where
|
|
Self: ContentWrapper,
|
|
F: Fn(&Arc<Button>, &T, usize) -> Result<()>,
|
|
{
|
|
self.refresh()?;
|
|
|
|
let grid: Arc<Grid> = self.base.element("content")?;
|
|
let label: Arc<Label> = self.base.element("tab_info")?;
|
|
|
|
Self::clear_grid(&grid)?;
|
|
self.set_tab(&label)?;
|
|
|
|
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(
|
|
engine.gui_handler(),
|
|
include_str!("../resources/content_button.xml"),
|
|
)?;
|
|
|
|
let button: Arc<Button> = snippet.element("button")?;
|
|
setup(&button, t, index)?;
|
|
grid.attach(button, x, y, 1, 1)?;
|
|
}
|
|
None => break 'outer,
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn select(&self) -> Result<()> {
|
|
let grid: Arc<Grid> = self.base.element("content")?;
|
|
|
|
if let Some(child) = grid.child_at(0, 0)? {
|
|
child.gridable().unwrap().selectable().unwrap().select()?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<T: Send + Sync> ContentWrapper for Content<T>
|
|
where
|
|
Content<T>: ContentUpdate,
|
|
{
|
|
fn refresh(&mut self) -> Result<()> {
|
|
self.data = (self.on_enable)()?;
|
|
|
|
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(())
|
|
}
|
|
|
|
fn next_tab(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
|
|
if self.page < (self.pages - 1) {
|
|
self.page += 1;
|
|
self.update(engine, hero)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn previous_tab(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
|
|
if self.page > 0 {
|
|
self.page -= 1;
|
|
self.update(engine, hero)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn base(&self) -> &Arc<GuiSnippet> {
|
|
&self.base
|
|
}
|
|
|
|
fn is_empty(&self) -> bool {
|
|
self.data.is_empty()
|
|
}
|
|
}
|