summaryrefslogtreecommitdiffstats
path: root/src/ui/bodies_window.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/bodies_window.rs')
-rw-r--r--src/ui/bodies_window.rs180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/ui/bodies_window.rs b/src/ui/bodies_window.rs
new file mode 100644
index 0000000..6300f5f
--- /dev/null
+++ b/src/ui/bodies_window.rs
@@ -0,0 +1,180 @@
+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<SystemId>,
+ system_heirarchy: NTree<SystemId>,
+ selected_body: Option<BodyId>
+}
+
+#[derive(Default, Clone)]
+pub struct BodiesWindowAction
+{
+ pub focus_body: Option<BodyId>
+}
+
+impl BodiesWindowState
+{
+ fn build_system_heirarchy_rec(
+ bodies: &[OrbitalBody],
+ node: &mut NTreeNode<BodyId>)
+ {
+ 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::<BodyId>::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<BodyId>,
+ ui: &mut egui::Ui)
+ -> Option<BodyId>
+ {
+ 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<egui::Response>
+ {
+ 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());
+ }
+ });
+ });
+ }
+}