use glam::{Vec2, Vec3, Vec4};
use anyhow::{anyhow, Result};
#[cfg(feature = "egui")]
use crate::ui::*;
use crate::*;
#[cfg(feature = "egui")]
const COLUMNS: [&str; 4] = ["X", "Y", "Z", "W"];
#[cfg(feature = "egui")]
const COLOR_COLUMNS: [&str; 4] = ["R", "G", "B", "A"];
#[cfg(feature = "egui")]
pub(crate) fn f32_table_ui(
ui: &mut egui::Ui,
columns: &[&str],
rows: usize,
values: &mut [f32],
range: Option<(f32, f32)>,
) -> bool {
use egui_extras::{Column, TableBuilder};
let node_style = NodeStyle::get(ui);
let mut changed = false;
let height = 20.0 * node_style.zoom;
let width = 40.0 * node_style.zoom;
ui.set_min_height(height * (rows + 1) as f32);
ui.vertical(|ui| {
TableBuilder::new(ui)
.columns(Column::exact(width), columns.len())
.vscroll(false)
.header(height, |mut header| {
for col in columns {
header.col(|ui| {
ui.heading(*col);
});
}
})
.body(|body| {
body.rows(height, rows, |mut row| {
let row_index = row.index();
for col in 0..columns.len() {
row.col(|ui| {
let val = &mut values[col * rows + row_index];
let drag = if let Some((min, max)) = range {
egui::DragValue::new(val).speed(0.1).range(min..=max)
} else {
egui::DragValue::new(val).speed(0.1)
};
if ui.add(drag).changed() {
changed = true;
}
});
}
});
});
});
changed
}
#[cfg(feature = "egui")]
pub(crate) fn vector_ui(ui: &mut egui::Ui, values: &mut [f32]) -> bool {
let len = values.len();
f32_table_ui(ui, &COLUMNS[0..len], 1, values, None)
}
#[cfg(feature = "egui")]
pub(crate) fn color_ui(ui: &mut egui::Ui, values: &mut [f32]) -> bool {
let len = values.len();
f32_table_ui(ui, &COLOR_COLUMNS[0..len], 1, values, Some((0., 1.)))
}
#[cfg(feature = "egui")]
pub(crate) fn matrix_ui(ui: &mut egui::Ui, dim: usize, values: &mut [f32]) -> bool {
f32_table_ui(ui, &COLUMNS[0..dim], dim, values, None)
}
impl ValueType for Vec2 {
fn clone_value(&self) -> Box<dyn ValueType> {
Box::new(self.clone())
}
fn to_value(&self) -> Value {
Value::Vec2(*self)
}
fn set_value(&mut self, value: Value) -> Result<()> {
match value {
Value::I32(v) => {
*self = (v as f32, 0.).into();
Ok(())
}
Value::U32(v) => {
*self = (v as f32, 0.).into();
Ok(())
}
Value::F32(v) => {
*self = (v, 0.).into();
Ok(())
}
Value::Vec2(v) => {
*self = v;
Ok(())
}
Value::Vec3(v) => {
*self = (v.x, v.y).into();
Ok(())
}
Value::Vec4(v) => {
*self = (v.x, v.y).into();
Ok(())
}
_ => Err(anyhow!("Expected a Vec2 got: {value:?}")),
}
}
fn data_type(&self) -> DataType {
DataType::Vec2
}
#[cfg(feature = "egui")]
fn ui(&mut self, ui: &mut egui::Ui) -> bool {
vector_ui(ui, self.as_mut())
}
}
impl ValueType for Vec3 {
fn clone_value(&self) -> Box<dyn ValueType> {
Box::new(self.clone())
}
fn to_value(&self) -> Value {
Value::Vec3(*self)
}
fn set_value(&mut self, value: Value) -> Result<()> {
match value {
Value::I32(v) => {
*self = (v as f32, 0., 0.).into();
Ok(())
}
Value::U32(v) => {
*self = (v as f32, 0., 0.).into();
Ok(())
}
Value::F32(v) => {
*self = (v, 0., 0.).into();
Ok(())
}
Value::Vec2(v) => {
*self = (v, 0.).into();
Ok(())
}
Value::Vec3(v) => {
*self = v;
Ok(())
}
Value::Vec4(v) => {
*self = (v.x, v.y, v.z).into();
Ok(())
}
_ => Err(anyhow!("Expected a Vec3 got: {value:?}")),
}
}
fn data_type(&self) -> DataType {
DataType::Vec3
}
#[cfg(feature = "egui")]
fn ui(&mut self, ui: &mut egui::Ui) -> bool {
vector_ui(ui, self.as_mut())
}
}
impl ValueType for Vec4 {
fn clone_value(&self) -> Box<dyn ValueType> {
Box::new(self.clone())
}
fn to_value(&self) -> Value {
Value::Vec4(*self)
}
fn set_value(&mut self, value: Value) -> Result<()> {
match value {
Value::I32(v) => {
*self = (v as f32, 0., 0., 1.).into();
Ok(())
}
Value::U32(v) => {
*self = (v as f32, 0., 0., 1.).into();
Ok(())
}
Value::F32(v) => {
*self = (v, 0., 0., 1.).into();
Ok(())
}
Value::Vec2(v) => {
*self = (v, 0., 1.).into();
Ok(())
}
Value::Vec3(v) => {
*self = (v, 1.).into();
Ok(())
}
Value::Vec4(v) => {
*self = v;
Ok(())
}
_ => Err(anyhow!("Expected a Vec4 got: {value:?}")),
}
}
fn data_type(&self) -> DataType {
DataType::Vec4
}
#[cfg(feature = "egui")]
fn ui(&mut self, ui: &mut egui::Ui) -> bool {
vector_ui(ui, self.as_mut())
}
}
#[derive(Clone, Copy, Debug, Default, serde::Serialize, serde::Deserialize)]
pub enum DynamicSize {
#[default]
D1,
D2,
D3,
D4,
}
impl DynamicSize {
pub const fn len(&self) -> usize {
match self {
Self::D1 => 1,
Self::D2 => 2,
Self::D3 => 3,
Self::D4 => 4,
}
}
}
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct DynamicVector {
data: Vec4,
size: DynamicSize,
}
impl ValueType for DynamicVector {
fn clone_value(&self) -> Box<dyn ValueType> {
Box::new(self.clone())
}
fn to_value(&self) -> Value {
match self.size {
DynamicSize::D1 => Value::F32(self.data.x),
DynamicSize::D2 => Value::Vec2(Vec2::from_slice(self.data.as_ref())),
DynamicSize::D3 => Value::Vec3(Vec3::from_slice(self.data.as_ref())),
DynamicSize::D4 => Value::Vec4(self.data),
}
}
fn set_value(&mut self, value: Value) -> Result<()> {
match value {
Value::I32(v) => {
*self = Self {
data: (v as f32, 0., 0., 1.).into(),
size: DynamicSize::D1,
};
Ok(())
}
Value::U32(v) => {
*self = Self {
data: (v as f32, 0., 0., 1.).into(),
size: DynamicSize::D1,
};
Ok(())
}
Value::F32(v) => {
*self = Self {
data: (v, 0., 0., 1.).into(),
size: DynamicSize::D1,
};
Ok(())
}
Value::Vec2(v) => {
*self = Self {
data: (v, 0., 1.).into(),
size: DynamicSize::D2,
};
Ok(())
}
Value::Vec3(v) => {
*self = Self {
data: (v, 1.).into(),
size: DynamicSize::D3,
};
Ok(())
}
Value::Vec4(v) => {
*self = Self {
data: v,
size: DynamicSize::D4,
};
Ok(())
}
_ => Err(anyhow!("Expected a Dynamic Vector got: {value:?}")),
}
}
fn compile(&self) -> Result<CompiledValue> {
self.to_value().compile()
}
fn data_type(&self) -> DataType {
DataType::DynamicVector
}
fn is_dynamic(&self) -> bool {
true
}
#[cfg(feature = "egui")]
fn ui(&mut self, ui: &mut egui::Ui) -> bool {
let len = self.size.len();
vector_ui(ui, &mut self.data.as_mut()[0..len])
}
}
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct Dynamic(DynamicVector);
impl ValueType for Dynamic {
fn clone_value(&self) -> Box<dyn ValueType> {
Box::new(self.clone())
}
fn to_value(&self) -> Value {
self.0.to_value()
}
fn set_value(&mut self, value: Value) -> Result<()> {
self.0.set_value(value)
}
fn compile(&self) -> Result<CompiledValue> {
self.to_value().compile()
}
fn data_type(&self) -> DataType {
DataType::Dynamic
}
fn is_dynamic(&self) -> bool {
true
}
#[cfg(feature = "egui")]
fn ui(&mut self, ui: &mut egui::Ui) -> bool {
self.0.ui(ui)
}
}