use super::*;
impl EditorHook {
pub(super) fn entry_index_of(&self, ty: &str) -> Option<usize> {
self.entries.iter().position(|e| entry_type(e) == Some(ty))
}
pub(super) fn entry_args(&self, idx: usize) -> serde_json::Map<String, serde_json::Value> {
self.entries[idx]
.get("args")
.and_then(|v| v.as_object())
.cloned()
.unwrap_or_default()
}
pub(super) fn lighting_present(&self) -> Vec<bool> {
lighting::SECTIONS
.iter()
.map(|s| self.entry_index_of(s.ty).is_some())
.collect()
}
pub(super) fn lighting_fields(&self) -> Vec<Option<FormField>> {
let mut out = Vec::with_capacity(lighting::binding_count());
for s in lighting::SECTIONS {
match self.entry_index_of(s.ty) {
Some(idx) => {
let args = self.entry_args(idx);
let fields = lighting::section_fields(s, Some(&args));
for (path, _) in s.fields {
out.push(fields.iter().find(|f| &f.key == path).cloned());
}
}
None => out.extend(std::iter::repeat_with(|| None).take(s.fields.len())),
}
}
out
}
pub(super) fn lighting_data(&self) -> LightingData {
LightingData {
rows: lighting::rows(&self.lighting_present()),
fields: self.lighting_fields(),
}
}
pub(super) fn make_lighting_view<'a>(
&'a self,
d: &'a LightingData,
mouse: [f32; 2],
) -> LightingView<'a> {
LightingView {
rows: &d.rows,
fields: &d.fields,
focus: self
.lighting_focus
.filter(|_| self.panel_order.last() == Some(&PanelKey::Lighting)),
status: self.lighting_status.as_deref(),
dirty: self.lighting_touched,
mouse,
}
}
pub(super) fn seed_lighting(&mut self, world: &mut World) {
self.lighting_touched = false;
for (b, field) in self.lighting_fields().iter().enumerate() {
if let Some(f) = field
&& f.kind.has_text_input()
{
widget::seed_field(world, lighting_panel::input(b), &f.initial);
}
}
}
pub(super) fn apply_lighting_action(&mut self, action: LightingAction, world: &mut World) {
match action {
LightingAction::Focus(b) => self.lighting_focus = Some(b),
LightingAction::Toggle(b) => self.toggle_lighting_bool(b),
LightingAction::Add(s) => self.add_lighting_section(s, world),
LightingAction::Apply => self.apply_lighting(world),
LightingAction::Consume => self.lighting_focus = None,
}
}
pub(super) fn apply_lighting(&mut self, world: &mut World) {
self.lighting_status = None;
let mut staged = Vec::new();
for (si, s) in lighting::SECTIONS.iter().enumerate() {
let Some(idx) = self.entry_index_of(s.ty) else {
continue;
};
let existing = self.entry_args(idx);
let fields = lighting::section_fields(s, Some(&existing));
let base = lighting::section_base(si);
let texts: Vec<String> = fields
.iter()
.map(|f| {
let j = s.fields.iter().position(|(p, _)| *p == f.key).unwrap_or(0);
if f.kind.has_text_input() {
widget::field_text(world, lighting_panel::input(base + j))
} else {
String::new()
}
})
.collect();
let args = form::assemble(s.ty, Some(&existing), &fields, &texts);
let name = self.entries.get(idx).and_then(entry_name).unwrap_or(s.ty);
if let Err(e) = form::validate(s.ty, name, &args) {
self.lighting_status = Some(short_status(&format!("{}: {e}", s.title)));
return;
}
staged.push((idx, args));
}
for (idx, args) in staged {
if let Some(obj) = self.entries.get_mut(idx).and_then(|e| e.as_object_mut()) {
obj.insert("args".to_string(), serde_json::Value::Object(args));
}
}
self.mark_changed();
self.seed_lighting(world);
}
pub(super) fn toggle_lighting_bool(&mut self, b: usize) {
let (si, path, _) = lighting::binding(b);
let s = &lighting::SECTIONS[si];
let Some(idx) = self.entry_index_of(s.ty) else {
return;
};
let existing = self.entry_args(idx);
let mut fields = lighting::section_fields(s, Some(&existing));
if let Some(f) = fields.iter_mut().find(|f| f.key == path) {
f.boolval = !f.boolval;
}
let merged = form::working_args(s.ty, Some(&existing));
let texts: Vec<String> = fields
.iter()
.map(|f| form::current_text(&merged, &f.key))
.collect();
let args = form::assemble(s.ty, Some(&existing), &fields, &texts);
let name = self.entries.get(idx).and_then(entry_name).unwrap_or(s.ty);
if let Err(e) = form::validate(s.ty, name, &args) {
self.lighting_status = Some(short_status(&format!("{}: {e}", s.title)));
return;
}
if let Some(obj) = self.entries.get_mut(idx).and_then(|e| e.as_object_mut()) {
obj.insert("args".to_string(), serde_json::Value::Object(args));
}
self.mark_changed();
}
pub(super) fn add_lighting_section(&mut self, si: usize, world: &mut World) {
let Some(s) = lighting::SECTIONS.get(si) else {
return;
};
if self.entry_index_of(s.ty).is_some() {
return;
}
let name = self.unique_name(s.ty);
self.entries.push(serde_json::json!({
"name": name, "type": s.ty, "args": {},
}));
self.mark_changed();
self.seed_lighting(world);
}
}