use super::list_panel::{self, Row};
use super::registry::{self, PanelKey};
use super::widget::{self, point_in};
use crate::ecs::World;
use crate::ecs::asset_id::AssetId;
const BASE: u32 = registry::base(PanelKey::View);
#[cfg(test)]
pub(crate) const PANEL_BG: AssetId = list_panel::panel_bg(BASE);
#[cfg(test)]
pub(crate) fn row_bg(i: usize) -> AssetId {
list_panel::row_bg(BASE, i)
}
#[cfg(test)]
pub(crate) fn check_box(i: usize) -> AssetId {
list_panel::check_box(BASE, i)
}
pub(crate) fn count() -> usize {
registry::view_toggle_count()
}
const VIEW_W: f32 = 200.0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ViewAction {
Toggle(usize),
Consume,
}
pub(crate) fn default_origin() -> [f32; 2] {
let preview = super::preview::default_origin();
[8.0, preview[1] + list_panel::size(VIEW_W, 1)[1] + 8.0]
}
pub(crate) fn size() -> [f32; 2] {
list_panel::size(VIEW_W, count())
}
pub(crate) fn hit_test(mx: f32, my: f32, o: [f32; 2], s: [f32; 2]) -> Option<ViewAction> {
if let Some(i) = list_panel::hit_row(mx, my, o, s[0], count()) {
return Some(ViewAction::Toggle(i));
}
point_in(mx, my, widget::outer_rect(o, s)).then_some(ViewAction::Consume)
}
pub(crate) fn apply(world: &mut World, o: [f32; 2], s: [f32; 2], rows: &[Row], mouse: [f32; 2]) {
list_panel::apply(world, BASE, o, s, "View", rows, mouse);
}
pub(crate) fn hide_all(world: &mut World) {
widget::hide_all(world, &all_sprite_ids(), &all_label_ids(), &[]);
}
pub(crate) fn all_sprite_ids() -> Vec<AssetId> {
list_panel::all_sprite_ids(BASE, count(), true)
}
pub(crate) fn all_label_ids() -> Vec<AssetId> {
list_panel::all_label_ids(BASE, count(), false)
}
#[cfg(test)]
mod tests {
use super::list_panel::{row_label, title_label};
use super::*;
use crate::components::{Sprite, TextLabel};
fn injected_world() -> World {
let mut world = World::new();
for id in all_sprite_ids() {
world.add_component(Sprite {
asset_id: id,
..Default::default()
});
}
for id in all_label_ids() {
world.add_component(TextLabel {
asset_id: id,
..Default::default()
});
}
world
}
fn rows(states: &[(&str, bool)]) -> Vec<Row> {
states
.iter()
.map(|&(caption, on)| Row::checkbox(caption, on))
.collect()
}
#[test]
fn hit_test_resolves_a_row_or_swallows() {
let o = default_origin();
let s = size();
let r0 = list_panel::row_rect(o, VIEW_W, 0);
assert_eq!(
hit_test(r0[0] + 10.0, r0[1] + 10.0, o, s),
Some(ViewAction::Toggle(0))
);
let t = widget::title_rect(o, VIEW_W);
assert_eq!(
hit_test(t[0] + 5.0, t[1] + 5.0, o, s),
Some(ViewAction::Consume)
);
assert_eq!(hit_test(2000.0, 2000.0, o, s), None);
let wide = [VIEW_W + 120.0, s[1]];
let rw = list_panel::row_rect(o, wide[0], 0);
assert_eq!(
hit_test(rw[0] + 10.0, rw[1] + 10.0, o, wide),
Some(ViewAction::Toggle(0))
);
assert_eq!(
hit_test(o[0] + wide[0] - 4.0, rw[1] + 10.0, o, wide),
Some(ViewAction::Toggle(0)),
"the widened right side is still part of the row"
);
let tall = [VIEW_W, s[1] + 100.0];
assert_eq!(
hit_test(o[0] + 5.0, o[1] + s[1] + 40.0, o, tall),
Some(ViewAction::Consume),
"the padding below the last row is still part of the panel"
);
}
#[test]
fn count_tracks_the_registry() {
assert_eq!(count(), registry::view_toggle_count());
assert!(count() >= 3, "Assets / Preview / Templates are registered");
}
#[test]
fn apply_shows_heading_and_row_captions() {
let mut world = injected_world();
apply(
&mut world,
default_origin(),
size(),
&rows(&[("Assets", false), ("Preview", true), ("Templates", false)]),
[0.0, 0.0],
);
let title = world
.query::<TextLabel>()
.find(|l| l.asset_id == title_label(BASE))
.unwrap();
assert!(title.visible && title.content == "View");
let first = world
.query::<TextLabel>()
.find(|l| l.asset_id == row_label(BASE, 0))
.unwrap();
assert_eq!(first.content, "Assets");
}
#[test]
fn checkbox_tints_track_the_row_state() {
let mut world = injected_world();
let o = default_origin();
apply(
&mut world,
o,
size(),
&rows(&[("Assets", false)]),
[0.0, 0.0],
);
let off = world
.query::<Sprite>()
.find(|s| s.asset_id == check_box(0))
.cloned()
.unwrap()
.tint;
apply(
&mut world,
o,
size(),
&rows(&[("Assets", true)]),
[0.0, 0.0],
);
let on = world
.query::<Sprite>()
.find(|s| s.asset_id == check_box(0))
.unwrap()
.tint;
assert_ne!(off, on, "the checkbox tint flips with the panel state");
}
#[test]
fn hide_all_blanks_every_element() {
let mut world = injected_world();
apply(
&mut world,
default_origin(),
size(),
&rows(&[("Assets", true), ("Preview", true), ("Templates", true)]),
[0.0, 0.0],
);
hide_all(&mut world);
assert!(world.query::<Sprite>().all(|s| !s.visible));
assert!(world.query::<TextLabel>().all(|l| !l.visible));
}
}