summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-05-12 19:01:27 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-05-12 19:01:27 -0400
commita0a3b3974cab754c10a1517d82762b99482970ce (patch)
tree8aeb0ca1e007bacecc8e12a263bd5aa321b8f69a /src/ui
parent7f63ec5c10eb7e8dd4edaabd1a6a437328911d39 (diff)
downloadsystemic4x-main.tar.gz
systemic4x-main.tar.bz2
systemic4x-main.zip
update packages to latest versionsHEADmain
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/bodies_window.rs114
-rw-r--r--src/ui/fleet_window.rs190
-rw-r--r--src/ui/topbar.rs9
3 files changed, 179 insertions, 134 deletions
diff --git a/src/ui/bodies_window.rs b/src/ui/bodies_window.rs
index 21a2060..7e24948 100644
--- a/src/ui/bodies_window.rs
+++ b/src/ui/bodies_window.rs
@@ -1,6 +1,3 @@
-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};
@@ -11,8 +8,6 @@ use crate::timeman::TimeMan;
pub struct BodiesWindowState
{
pub open: bool,
- last_system: Option<SystemId>,
- system_heirarchy: NTree<SystemId>,
selected_body: Option<BodyId>
}
@@ -24,64 +19,19 @@ pub struct BodiesWindowAction
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(
+ pub fn paint(
&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)
+ ui: &mut egui::Ui,
+ current_system: &SolarSystem)
-> 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();
let mut bodies_window_open = self.open;
egui::Window::new("Bodies")
.open(&mut &mut bodies_window_open)
.resizable(true)
- .show(eguictx.context(), |ui| {
+ .show(ui.ctx(), |ui| {
ui.horizontal(|ui| {
self.paint_bodies_list(current_system, ui);
@@ -142,8 +92,8 @@ impl BodiesWindowState
.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);
+ let root = star_system.heirarchy();
+ let new_sel = self.paint_bodies_node_rec(star_system, root, ui);
if new_sel.is_some() {
self.selected_body = new_sel;
}
@@ -176,26 +126,40 @@ impl BodiesWindowState
});
ui.vertical(|ui| {
- ui.vertical_centered(|ui| {
- ui.label("Physical Properties");
- });
- ui.label(format!("Mass: {:.4E} kg", selected_body.mass()));
- ui.label(format!("Radius: {} km", selected_body.radius()));
-
- if let Some(orbit) = selected_body.get_orbit() {
- ui.vertical_centered(|ui| {
- ui.label("Orbital Properties");
+ ui.style_mut().interaction.selectable_labels = false;
+ egui_extras::TableBuilder::new(ui)
+ .column(egui_extras::Column::auto())
+ .column(egui_extras::Column::remainder())
+ .body(|mut body| {
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Mass"); });
+ row.col(|col| { col.label(format!("{:.4E}", selected_body.mass())); });
});
- ui.label(format!("Orbiting {}",
- star_system.body(orbit.parent()).name()
- ));
- ui.label(format!("Period: {}",
- TimeMan::format_duration(orbit.period(selected_body))
- ));
- ui.label(format!("Semi-major Axis: {:.4E} km",
- orbit.sma()
- ));
- }
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Radius"); });
+ row.col(|col| { col.label(format!("{:.4E}", selected_body.radius())); });
+ });
+
+ if let Some(orbit) = selected_body.get_orbit() {
+ let parent = star_system.body(orbit.parent());
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Orbiting"); });
+ row.col(|col| { col.label(parent.name()); });
+ });
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Period"); });
+ row.col(|col| {
+ col.label(format!("{}",
+ TimeMan::format_duration(orbit.period(selected_body))
+ ));
+ });
+ });
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Semi-major Axis"); });
+ row.col(|col| { col.label(format!("{:.4E} km", orbit.sma())); });
+ });
+ }
+ });
});
});
diff --git a/src/ui/fleet_window.rs b/src/ui/fleet_window.rs
index eb8ccde..55e3d59 100644
--- a/src/ui/fleet_window.rs
+++ b/src/ui/fleet_window.rs
@@ -1,17 +1,22 @@
-use std::cell::RefCell;
-
use crate::GameState;
-use crate::eguictx::EguiCtx;
-use crate::fleet::{Fleet, FleetsManager};
+use crate::fleet::{Fleet, FleetId, FleetsManager};
+use crate::solar_system::orbit::StaticOrbiter;
use crate::solar_system::{Kilometers, SolarSystem, SystemId};
use crate::solar_system::body::BodyId;
+#[derive(Default, Clone, PartialEq)]
+enum FleetMenuPanelSel {
+ #[default]
+ Info,
+ Schedule
+}
#[derive(Default, Clone)]
pub struct FleetWindowState
{
pub open: bool,
- pub selected_system: Option<SystemId>,
+ pub selected_fleet: Option<FleetId>,
+ pub menu_panel: FleetMenuPanelSel,
pub new_fleet_window: Option<NewFleetWindowState>
}
@@ -33,7 +38,7 @@ pub struct NewFleetWindowState
pub fleet_sma: Kilometers
}
-#[derive(Default, Clone)]
+#[derive(Clone)]
pub struct NewFleet
{
pub system: SystemId,
@@ -46,8 +51,9 @@ impl FleetWindowState
{
pub fn paint(
&mut self,
+ ui: &mut egui::Ui,
game_state: &GameState,
- eguictx: &EguiCtx,
+ focused_system: &Option<SystemId>,
focused_body: &Option<BodyId>)
-> FleetWindowAction
{
@@ -59,22 +65,30 @@ impl FleetWindowState
let mut mgr_open = self.open;
egui::Window::new("Fleet Manager")
.open(&mut mgr_open)
- .show(eguictx.context(), |ui| {
+ .show(ui.ctx(), |ui| {
- ui.horizontal(|ui| {
- self.paint_systems_list(
- &mut action,
- ui,
- fleets_manager,
- star_systems,
- focused_body
- );
+ ui.vertical(|ui| {
+ ui.horizontal(|ui| {
+ self.paint_fleet_list(fleets_manager, ui);
+ self.paint_fleet_menu(star_systems, fleets_manager, ui);
+ });
+
+ if focused_system.is_some() {
+ if ui.button("New Fleet").clicked() {
+ if self.new_fleet_window.is_none() {
+ self.new_fleet_window = Some(NewFleetWindowState::new(
+ focused_system.unwrap(),
+ focused_body.unwrap_or(0)
+ ));
+ }
+ }
+ }
});
});
match &mut self.new_fleet_window {
Some(new_fleet_window) => {
- action.new_fleet = new_fleet_window.paint(game_state, eguictx);
+ action.new_fleet = new_fleet_window.paint(ui, game_state);
if action.new_fleet.is_some() || !new_fleet_window.open {
self.new_fleet_window = None;
}
@@ -86,53 +100,106 @@ impl FleetWindowState
action
}
- fn paint_systems_list(
+ fn paint_fleet_menu(
&mut self,
- action: &mut FleetWindowAction,
- ui: &mut egui::Ui,
- fleets_manager: &FleetsManager,
star_systems: &[SolarSystem],
- focused_body: &Option<BodyId>)
- -> egui::InnerResponse<()>
+ fleets_man: &FleetsManager,
+ ui: &mut egui::Ui)
{
- ui.vertical(|ui| {
- for system in star_systems {
- self.paint_fleet_list(fleets_manager, &system, ui);
+ let fleet = match self.selected_fleet {
+ Some(id) => { fleets_man.entry(id) },
+ None => { return; }
+ };
+ let fleet = match fleet {
+ Some(entry) => entry,
+ None => {
+ self.selected_fleet = None;
+ return;
}
+ };
- if self.selected_system.is_none() { return; }
- if ui.button("New Fleet").clicked() {
- if self.new_fleet_window.is_none() {
- self.new_fleet_window = Some(NewFleetWindowState::new(
- self.selected_system.unwrap(),
- focused_body.unwrap_or(0)
- ));
+ ui.separator();
+ ui.vertical(|ui| {
+ ui.horizontal(|ui| {
+ if ui.button("Info").clicked() {
+ self.menu_panel = FleetMenuPanelSel::Info;
}
+ if ui.button("Schedule").clicked() {
+ self.menu_panel = FleetMenuPanelSel::Schedule;
+ }
+ });
+ self.paint_fleet_menu_info(star_systems, fleets_man, fleet, ui);
+ });
+ }
+
+ fn paint_fleet_menu_info(
+ &mut self,
+ star_systems: &[SolarSystem],
+ fleets_man: &FleetsManager,
+ fleet: &Fleet,
+ ui: &mut egui::Ui)
+ {
+ if self.menu_panel != FleetMenuPanelSel::Info {
+ return;
+ }
+ egui::Frame::canvas(ui.style()).show(ui, |ui| {
+ ui.set_min_width(200.0);
+ ui.style_mut().interaction.selectable_labels = false;
+
+ if let Some(orbit) = fleet.orbit() {
+ let star_system = &star_systems[orbit.system()];
+ let parent = star_system.body(orbit.parent());
+
+ ui.push_id("orbital_info_table", |ui| {
+ egui_extras::TableBuilder::new(ui)
+ .column(egui_extras::Column::auto())
+ .column(egui_extras::Column::remainder())
+ .body(|mut body| {
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("System"); });
+ row.col(|col| { col.label(star_system.name()); });
+ });
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Orbiting"); });
+ row.col(|col| { col.label(parent.name()); });
+ });
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Radius"); });
+ row.col(|col| { col.label(format!("{:.1}", orbit.sma())); });
+ });
+ });
+ });
+
+ ui.separator();
}
- })
+
+ let heading = fleet.heading();
+ egui_extras::TableBuilder::new(ui)
+ .column(egui_extras::Column::auto())
+ .column(egui_extras::Column::remainder())
+ .body(|mut body| {
+ body.row(16.0, |mut row| {
+ row.col(|col| { col.label("Heading"); });
+ row.col(|col| {
+ col.label(format!("{:?} by {:?}",
+ cgmath::Deg::<f32>::from(heading.x),
+ cgmath::Deg::<f32>::from(heading.y)
+ ));
+ });
+ });
+ });
+ });
}
fn paint_fleet_list(
&mut self,
- fleets_manager: &FleetsManager,
- star_system: &SolarSystem,
+ fleets_man: &FleetsManager,
ui: &mut egui::Ui)
{
- let fleet_ids = star_system.fleets(fleets_manager);
- egui::collapsing_header::CollapsingState::load_with_default_open(
- ui.ctx(),
- ui.make_persistent_id(format!("fleet_window_star_{}", star_system.id())),
- true
- )
- .show_header(ui, |ui| {
- let selected = self.selected_system.is_some_and(|id| { id == star_system.id() });
- if ui.selectable_label(selected, star_system.name()).clicked() {
- self.selected_system = if !selected { Some(star_system.id()) } else { None };
- }
- })
- .body(|ui| {
+ let fleet_ids = fleets_man.all();
+ ui.vertical(|ui| {
for id in fleet_ids {
- if let Some(fleet) = fleets_manager.entry(id) {
+ if let Some(fleet) = fleets_man.entry(id) {
self.paint_fleet_entry(fleet, ui);
}
}
@@ -144,7 +211,10 @@ impl FleetWindowState
fleet: &Fleet,
ui: &mut egui::Ui)
{
- ui.label(fleet.name());
+ let selected = self.selected_fleet.is_some_and(|id| { id == fleet.id() });
+ if ui.selectable_label(selected, fleet.name()).clicked() {
+ self.selected_fleet = if selected { None } else { Some(fleet.id()) };
+ }
}
} // FleetWindowAction
@@ -164,8 +234,8 @@ impl NewFleetWindowState
pub fn paint(
&mut self,
- game_state: &GameState,
- eguictx: &EguiCtx)
+ ui: &mut egui::Ui,
+ game_state: &GameState,)
-> Option<NewFleet>
{
let solar_system = &game_state.solar_systems()[self.parent_system];
@@ -174,7 +244,7 @@ impl NewFleetWindowState
match egui::Window::new("New Fleet")
.collapsible(false)
.open(&mut self.open)
- .show(eguictx.context(), |ui| {
+ .show(ui.ctx(), |ui| {
ui.vertical(|ui| {
ui.horizontal(|ui| {
ui.label("Name: ");
@@ -205,4 +275,16 @@ impl NewFleetWindowState
None => None
}
}
+} // impl FleetWindowState
+
+impl Default for NewFleet
+{
+ fn default() -> Self {
+ Self {
+ system: Default::default(),
+ orbiting: Default::default(),
+ name: "New Fleet".to_string(),
+ sma: Default::default()
+ }
+ }
}
diff --git a/src/ui/topbar.rs b/src/ui/topbar.rs
index ba26d7c..511c67e 100644
--- a/src/ui/topbar.rs
+++ b/src/ui/topbar.rs
@@ -22,7 +22,7 @@ impl TopBarState
{
pub fn paint(
&mut self,
- eguictx: &EguiCtx,
+ ui: &mut egui::Ui,
game_state: &GameState,
bodies_window_state: &BodiesWindowState,
fleets_window_state: &FleetWindowState)
@@ -33,8 +33,8 @@ impl TopBarState
let solar_systems = game_state.solar_systems();
let timeman = game_state.timeman();
- egui::TopBottomPanel::top("topbar").show(
- eguictx.context(),
+ egui::Panel::top("topbar").show_inside(
+ ui,
|ui| {
ui.horizontal(|ui| {
@@ -62,7 +62,7 @@ impl TopBarState
});
});
- self.paint_tick_buttons(&mut action, timeman, ui);
+ self.paint_tick_buttons(&mut action, ui);
});
ui.vertical_centered_justified(|ui| {
@@ -95,7 +95,6 @@ impl TopBarState
pub fn paint_tick_buttons(
&mut self,
action: &mut TopBarAction,
- timeman: &TimeMan,
ui: &mut egui::Ui)
{
let button_seconds = [