use alloc::{string::String, vec::Vec};
use scenix_math::{Vec2, Vec3, Vec4};
use crate::Color;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InspectorId(pub u64);
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum InspectorValue {
Bool(bool),
Integer(i64),
Unsigned(u64),
Number(f64),
Text(String),
Vec2(Vec2),
Vec3(Vec3),
Vec4(Vec4),
Color(Color),
Bytes(u64),
}
impl From<bool> for InspectorValue {
fn from(value: bool) -> Self {
Self::Bool(value)
}
}
impl From<f32> for InspectorValue {
fn from(value: f32) -> Self {
Self::Number(value as f64)
}
}
impl From<f64> for InspectorValue {
fn from(value: f64) -> Self {
Self::Number(value)
}
}
impl From<u64> for InspectorValue {
fn from(value: u64) -> Self {
Self::Unsigned(value)
}
}
impl From<usize> for InspectorValue {
fn from(value: usize) -> Self {
Self::Unsigned(value as u64)
}
}
impl From<Vec2> for InspectorValue {
fn from(value: Vec2) -> Self {
Self::Vec2(value)
}
}
impl From<Vec3> for InspectorValue {
fn from(value: Vec3) -> Self {
Self::Vec3(value)
}
}
impl From<Vec4> for InspectorValue {
fn from(value: Vec4) -> Self {
Self::Vec4(value)
}
}
impl From<Color> for InspectorValue {
fn from(value: Color) -> Self {
Self::Color(value)
}
}
impl From<String> for InspectorValue {
fn from(value: String) -> Self {
Self::Text(value)
}
}
impl From<&str> for InspectorValue {
fn from(value: &str) -> Self {
Self::Text(value.into())
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InspectorField {
pub name: String,
pub value: InspectorValue,
}
impl InspectorField {
pub fn new(name: impl Into<String>, value: impl Into<InspectorValue>) -> Self {
Self {
name: name.into(),
value: value.into(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InspectorItem {
pub id: InspectorId,
pub label: String,
pub kind: String,
pub fields: Vec<InspectorField>,
pub children: Vec<InspectorItem>,
}
impl InspectorItem {
pub fn new(id: InspectorId, label: impl Into<String>, kind: impl Into<String>) -> Self {
Self {
id,
label: label.into(),
kind: kind.into(),
fields: Vec::new(),
children: Vec::new(),
}
}
pub fn field(mut self, name: impl Into<String>, value: impl Into<InspectorValue>) -> Self {
self.fields.push(InspectorField::new(name, value));
self
}
pub fn child(mut self, child: InspectorItem) -> Self {
self.children.push(child);
self
}
}
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InspectorSnapshot {
pub roots: Vec<InspectorItem>,
}
impl InspectorSnapshot {
pub const fn new() -> Self {
Self { roots: Vec::new() }
}
pub fn clear(&mut self) {
self.roots.clear();
}
pub fn push(&mut self, item: InspectorItem) {
self.roots.push(item);
}
}
pub trait Inspectable {
fn inspect(&self, snapshot: &mut InspectorSnapshot);
fn inspector_snapshot(&self) -> InspectorSnapshot {
let mut snapshot = InspectorSnapshot::new();
self.inspect(&mut snapshot);
snapshot
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inspector_tree_builders_preserve_typed_values() {
let item = InspectorItem::new(InspectorId(1), "Camera", "perspective")
.field("fov", 60.0_f32)
.child(InspectorItem::new(InspectorId(2), "Transform", "transform"));
assert_eq!(item.children.len(), 1);
assert_eq!(item.fields[0].value, InspectorValue::Number(60.0));
}
}