use egui::Sense; use crate::eguictx::EguiCtx; use crate::ntree::{NTree, NTreeNode}; use crate::solar_system::body::{BodyId, OrbitalBody}; use crate::solar_system::{SolarSystem, SystemId}; #[derive(Default, Clone)] pub struct BodiesWindowState { last_system: Option, system_heirarchy: NTree, selected_body: Option } #[derive(Default, Clone)] pub struct BodiesWindowAction { pub focus_body: Option } impl BodiesWindowState { fn build_system_heirarchy_rec( bodies: &[OrbitalBody], node: &mut NTreeNode) { for body in bodies { let orbit = body.get_orbit(); match orbit { Some(orbit) => { if orbit.parent() != *node.value() { continue; } }, None => { continue; } } let mut subnode = NTreeNode::new(body.id()); BodiesWindowState::build_system_heirarchy_rec(bodies, &mut subnode); node.insert_node(subnode); } } fn rebuild_system_heirarchy( &mut self, star_system: &SolarSystem) { let mut root_node = NTreeNode::::new(0); let bodies = star_system.bodies(); BodiesWindowState::build_system_heirarchy_rec(bodies, &mut root_node); self.system_heirarchy.set_root(root_node); } pub fn render( &mut self, current_system: &SolarSystem, eguictx: &EguiCtx) -> BodiesWindowAction { match self.last_system { Some(last_system) => { if last_system != current_system.id() { self.rebuild_system_heirarchy(current_system); } }, None => { self.rebuild_system_heirarchy(current_system); } } self.last_system = Some(current_system.id()); let mut action = BodiesWindowAction::default(); egui::Window::new("Bodies") .resizable(true) .show(eguictx.context(), |ui| { ui.horizontal(|ui| { self.paint_bodies_list(current_system, ui); self.paint_body_info_panel(&mut action, current_system, ui); }); }); action } fn paint_bodies_node_rec( &self, star_system: &SolarSystem, node: &NTreeNode, ui: &mut egui::Ui) -> Option { let body = star_system.body(*node.value()); let children = node.children(); let selected = self.selected_body.is_some_and(|v| { v == *node.value() }); let mut new_selected = None; if children.is_empty() { if ui.selectable_label(selected, body.name()).clicked() { new_selected = Some(*node.value()); } }else{ egui::collapsing_header::CollapsingState::load_with_default_open( ui.ctx(), ui.make_persistent_id(format!("bodies_window_body_{}", body.id())), true) .show_header(ui, |ui| { if ui.selectable_label(selected, body.name()).clicked() { new_selected = Some(*node.value()); } }) .body(|ui| { for child in children { let child_selected = self.paint_bodies_node_rec(star_system, child, ui); if child_selected.is_some() { new_selected = child_selected; } } }); }; new_selected } fn paint_bodies_list( &mut self, star_system: &SolarSystem, ui: &mut egui::Ui) -> Option { let resp = egui::ScrollArea::vertical() .auto_shrink(true) .min_scrolled_height(200.0) .show(ui, |ui| { ui.vertical(|ui| { let root = self.system_heirarchy.root(); let new_sel = self.paint_bodies_node_rec(star_system, root.as_ref().unwrap(), ui); if new_sel.is_some() { self.selected_body = new_sel; } }).response }); Some(resp.inner) } fn paint_body_info_panel( &mut self, action: &mut BodiesWindowAction, star_system: &SolarSystem, ui: &mut egui::Ui) { let selected_body = match self.selected_body { Some(id) => { star_system.body(id) }, None => { return; } }; ui.separator(); egui::Frame::canvas(ui.style()) .show(ui, |ui| { ui.set_width(200.0); ui.vertical_centered(|ui| { ui.label( egui::RichText::new(selected_body.name()) .heading()); }); ui.horizontal(|ui| { let focus_resp = ui.button("Focus"); if focus_resp.clicked() { action.focus_body = Some(selected_body.id()); } }); }); } }