pub(crate) mod cinematic;
mod draw;
mod geometry;
pub(crate) mod loading;
pub(crate) use draw::apply;
pub(crate) use geometry::{Layout, Mode, hit_test};
use super::registry::{self, PanelKey};
use super::widget;
use crate::ecs::asset_id::AssetId;
const BASE: u32 = registry::base(PanelKey::Worlds);
pub(crate) const PANEL_BG: AssetId = AssetId(BASE);
pub(crate) const TITLE_LABEL: AssetId = AssetId(BASE + 1);
pub(crate) const CLOSE_BG: AssetId = AssetId(BASE + 2);
pub(crate) const CLOSE_LABEL: AssetId = AssetId(BASE + 3);
pub(crate) const NEW_BG: AssetId = AssetId(BASE + 4);
pub(crate) const NEW_LABEL: AssetId = AssetId(BASE + 5);
pub(crate) const STATUS_LABEL: AssetId = AssetId(BASE + 6);
pub(crate) const LIST_HEADER: AssetId = AssetId(BASE + 7);
pub(crate) const LIST_TRACK: AssetId = AssetId(BASE + 8);
pub(crate) const LIST_THUMB: AssetId = AssetId(BASE + 9);
pub(crate) const DOT_BG: AssetId = AssetId(BASE + 0xA);
pub(crate) const DOT1: AssetId = AssetId(BASE + 0xB);
pub(crate) const DOT2: AssetId = AssetId(BASE + 0xC);
pub(crate) const DOT3: AssetId = AssetId(BASE + 0xD);
pub(crate) const MENU_BG: AssetId = AssetId(BASE + 0xE);
pub(crate) const MENU_OPEN_BG: AssetId = AssetId(BASE + 0xF);
pub(crate) const MENU_OPEN_LABEL: AssetId = AssetId(BASE + 0x10);
pub(crate) const MENU_DELETE_BG: AssetId = AssetId(BASE + 0x11);
pub(crate) const MENU_DELETE_LABEL: AssetId = AssetId(BASE + 0x12);
pub(crate) fn row_bg(i: usize) -> AssetId {
AssetId(BASE + 0x20 + i as u32)
}
pub(crate) fn row_label(i: usize) -> AssetId {
AssetId(BASE + 0x40 + i as u32)
}
pub(crate) const POOL: usize = 24;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct WorldRow {
pub name: String,
pub path: String,
pub open: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum WorldTarget {
Open(String),
Untitled,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum WorldsConfirm {
Delete(String),
Save(WorldTarget),
Discard(WorldTarget),
}
pub(crate) struct WorldsView<'a> {
pub rows: &'a [WorldRow],
pub scroll: usize,
pub layout: Layout,
pub selected: Option<usize>,
pub previewing: Option<usize>,
pub menu: Option<usize>,
pub status: Option<&'a str>,
pub mouse: [f32; 2],
}
impl WorldsView<'_> {
pub(crate) fn slot_of(&self, i: usize) -> Option<usize> {
let slot = i.checked_sub(self.scroll)?;
(slot < self.layout.rows() && i < self.rows.len()).then_some(slot)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WorldsAction {
New,
Select(usize),
Open(usize),
OpenMenu(usize),
Delete(usize),
CloseMenu,
Consume,
}
pub(crate) fn hide_all(world: &mut crate::ecs::World) {
widget::hide_all(world, &all_sprite_ids(), &all_label_ids(), &[]);
}
pub(crate) fn all_sprite_ids() -> Vec<AssetId> {
let mut ids = vec![PANEL_BG, CLOSE_BG, NEW_BG];
ids.extend((0..POOL).map(row_bg));
ids.extend([
LIST_TRACK,
LIST_THUMB,
DOT_BG,
DOT1,
DOT2,
DOT3,
MENU_BG,
MENU_OPEN_BG,
MENU_DELETE_BG,
]);
ids
}
pub(crate) fn all_label_ids() -> Vec<AssetId> {
let mut ids = vec![
TITLE_LABEL,
CLOSE_LABEL,
NEW_LABEL,
STATUS_LABEL,
LIST_HEADER,
];
ids.extend((0..POOL).map(row_label));
ids.extend([MENU_OPEN_LABEL, MENU_DELETE_LABEL]);
ids
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn id_lists_cover_every_slot_without_repeats() {
let mut all: Vec<AssetId> = all_sprite_ids()
.into_iter()
.chain(all_label_ids())
.collect();
let n = all.len();
all.sort_by_key(|id| id.0);
all.dedup();
assert_eq!(all.len(), n, "no duplicate reserved ids");
}
}