Skip to content

Commit eece4e0

Browse files
committed
wip: refactor GUI into separate crates
1 parent e92c3bc commit eece4e0

42 files changed

Lines changed: 1443 additions & 717 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sandpolis-client/Cargo.toml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,24 @@ sandpolis-instance = { path = "../sandpolis-instance", version = "0.0.1" }
1919
sandpolis-database = { path = "../sandpolis-database", version = "0.0.1" }
2020
sandpolis-macros = { path = "../sandpolis-macros", version = "0.0.1" }
2121
sandpolis-core = { path = "../sandpolis-core", version = "0.0.1" }
22+
sandpolis-network = { path = "../sandpolis-network", version = "0.0.1", optional = true }
23+
sandpolis-server = { path = "../sandpolis-server", version = "0.0.1", optional = true }
24+
sandpolis-user = { path = "../sandpolis-user", version = "0.0.1", optional = true }
2225
native_db = { workspace = true, optional = true }
2326
native_model = { workspace = true, optional = true }
2427

2528
# GUI dependencies
2629
bevy = { workspace = true, optional = true }
2730
bevy_svg = { workspace = true, optional = true, features = ["2d"] }
2831
bevy_rapier2d = { workspace = true, optional = true }
32+
bevy_egui = { workspace = true, optional = true }
33+
bevy_stl = { workspace = true, optional = true }
34+
egui-file-dialog = { workspace = true, optional = true }
35+
egui_console = { workspace = true, optional = true }
36+
egui_extras = { workspace = true, optional = true }
37+
inventory = { workspace = true }
38+
tracing = { workspace = true }
39+
rand = { workspace = true, optional = true }
2940

3041
# TUI dependencies
3142
ratatui = { workspace = true, optional = true }
@@ -35,7 +46,26 @@ tui-popup = { workspace = true, optional = true }
3546

3647
[features]
3748
client = ["dep:passwords"]
38-
client-gui = ["client", "dep:bevy", "dep:bevy_svg", "dep:bevy_rapier2d"]
49+
client-gui = [
50+
"client",
51+
"dep:bevy",
52+
"dep:bevy_svg",
53+
"dep:bevy_rapier2d",
54+
"dep:bevy_egui",
55+
"dep:bevy_stl",
56+
"dep:egui-file-dialog",
57+
"dep:egui_console",
58+
"dep:egui_extras",
59+
"dep:rand",
60+
"dep:sandpolis-network",
61+
"dep:sandpolis-server",
62+
"dep:sandpolis-user",
63+
"sandpolis-core/client-gui",
64+
"sandpolis-instance/client-gui",
65+
"sandpolis-network/client-gui",
66+
"sandpolis-server/client-gui",
67+
"sandpolis-user/client",
68+
]
3969
client-tui = [
4070
"client",
4171
"dep:ratatui",
Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
1+
//! About screen with Easter egg activation.
2+
//!
3+
//! The about screen can be activated by triple-clicking on the layer indicator.
4+
15
use bevy::prelude::*;
26
use bevy_egui::{EguiContexts, egui};
37
use std::time::{Duration, Instant};
48

5-
/// Resource to track about screen state
9+
/// Resource to track about screen state.
610
#[derive(Resource, Default)]
711
pub struct AboutScreenState {
812
pub show: bool,
9-
/// Tracks clicks on the layer indicator for Easter egg
13+
/// Tracks clicks on the layer indicator for Easter egg.
1014
pub logo_click_count: u8,
1115
pub last_logo_click: Option<Instant>,
1216
}
1317

14-
/// Marker component for the 3D logo entity
18+
/// Marker component for the 3D logo entity.
1519
#[derive(Component)]
1620
pub struct AboutLogo;
1721

18-
/// Marker component for the about screen's 3D camera
22+
/// Marker component for the about screen's 3D camera.
1923
#[derive(Component)]
2024
pub struct AboutCamera;
2125

22-
/// Easter egg: Check if the click sequence has timed out
23-
/// Returns true if we should reset the counter
26+
/// Easter egg: Check if the click sequence has timed out.
27+
/// Returns true if we should reset the counter.
2428
fn should_reset_clicks(last_click: Option<Instant>) -> bool {
2529
if let Some(last) = last_click {
2630
last.elapsed() > Duration::from_secs(2)
@@ -29,8 +33,8 @@ fn should_reset_clicks(last_click: Option<Instant>) -> bool {
2933
}
3034
}
3135

32-
/// System to handle the Easter egg for opening about screen
33-
/// Easter egg: Triple-click on the layer indicator within 2 seconds
36+
/// System to handle the Easter egg for opening about screen.
37+
/// Easter egg: Triple-click on the layer indicator within 2 seconds.
3438
pub fn handle_about_easter_egg(mut about_state: ResMut<AboutScreenState>) {
3539
// Reset click counter if too much time has passed
3640
if should_reset_clicks(about_state.last_logo_click) {
@@ -39,7 +43,7 @@ pub fn handle_about_easter_egg(mut about_state: ResMut<AboutScreenState>) {
3943
}
4044
}
4145

42-
/// Call this from the layer indicator when it's clicked
46+
/// Call this from the layer indicator when it's clicked.
4347
pub fn register_logo_click(about_state: &mut AboutScreenState) {
4448
let now = Instant::now();
4549

@@ -58,12 +62,12 @@ pub fn register_logo_click(about_state: &mut AboutScreenState) {
5862
about_state.last_logo_click = None;
5963

6064
if about_state.show {
61-
info!("🥚 Easter egg activated! About screen opened.");
65+
info!("Easter egg activated! About screen opened.");
6266
}
6367
}
6468
}
6569

66-
/// System to spawn the 3D logo when about screen is shown
70+
/// System to spawn the 3D logo when about screen is shown.
6771
pub fn spawn_about_logo(
6872
mut commands: Commands,
6973
about_state: Res<AboutScreenState>,
@@ -131,7 +135,7 @@ pub fn spawn_about_logo(
131135
}
132136
}
133137

134-
/// System to rotate the logo slowly backwards
138+
/// System to rotate the logo slowly backwards.
135139
pub fn rotate_about_logo(time: Res<Time>, mut logo_query: Query<&mut Transform, With<AboutLogo>>) {
136140
for mut transform in logo_query.iter_mut() {
137141
// Rotate backwards (negative rotation around X axis) at a slow speed
@@ -140,7 +144,7 @@ pub fn rotate_about_logo(time: Res<Time>, mut logo_query: Query<&mut Transform,
140144
}
141145
}
142146

143-
/// System to render the about screen UI with egui
147+
/// System to render the about screen UI with egui.
144148
pub fn render_about_screen(
145149
mut contexts: EguiContexts,
146150
mut about_state: ResMut<AboutScreenState>,
@@ -172,7 +176,7 @@ pub fn render_about_screen(
172176
// Space for the 3D logo rendering at the top
173177
ui.add_space(320.0); // Height of the 3D viewport + padding
174178

175-
ui.heading("🏰 SANDPOLIS");
179+
ui.heading("SANDPOLIS");
176180
ui.add_space(8.0);
177181

178182
ui.label("Security & Systems Management Platform");
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{components::NodeEntity, edges::Edge};
1+
use crate::gui::{NodeEntity, edges::Edge};
22
use bevy::prelude::*;
33
use sandpolis_core::InstanceId;
44

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,61 @@
1+
//! Core GUI component definitions.
2+
//!
3+
//! This module contains the shared Bevy components and resources used
4+
//! throughout the GUI system.
5+
16
use bevy::prelude::*;
2-
use sandpolis_core::InstanceId;
7+
use sandpolis_core::{InstanceId, Layer};
38
use tokio::sync::mpsc;
49

5-
/// Marker component for the main world view camera
10+
/// Only one layer can be selected at a time.
11+
#[derive(Resource, Deref, DerefMut, Debug)]
12+
pub struct CurrentLayer(pub Layer);
13+
14+
impl Default for CurrentLayer {
15+
fn default() -> Self {
16+
Self(Layer::from("Network"))
17+
}
18+
}
19+
20+
/// Current zoom level for the camera.
21+
#[derive(Resource, Deref, DerefMut)]
22+
pub struct ZoomLevel(pub f32);
23+
24+
impl Default for ZoomLevel {
25+
fn default() -> Self {
26+
Self(1.0)
27+
}
28+
}
29+
30+
/// Marker component for the main world view camera.
631
#[derive(Component)]
732
pub struct WorldView;
833

9-
/// Component that marks an entity as representing an instance node
34+
/// Component that marks an entity as representing an instance node.
1035
#[derive(Component)]
1136
pub struct NodeEntity {
1237
pub instance_id: InstanceId,
1338
}
1439

15-
/// Minimap configuration
40+
/// Marker component for selected nodes.
41+
#[derive(Component)]
42+
pub struct Selected;
43+
44+
/// Component representing a minimap configuration.
1645
#[derive(Component)]
1746
pub struct Minimap {
1847
pub zoom_factor: f32, // How much smaller the minimap view is (e.g., 0.1 for 10x zoom out)
1948
}
2049

21-
/// Marker component for the minimap camera
50+
/// Marker component for the minimap camera.
2251
#[derive(Component)]
2352
pub struct MinimapCamera;
2453

25-
/// Marker component for layer indicator UI
54+
/// Marker component for layer indicator UI.
2655
#[derive(Component)]
2756
pub struct LayerIndicator;
2857

29-
/// Resource controlling minimap viewport settings
58+
/// Resource controlling minimap viewport settings.
3059
#[derive(Resource)]
3160
pub struct MinimapViewport {
3261
pub width: f32,
@@ -35,7 +64,7 @@ pub struct MinimapViewport {
3564
}
3665

3766
impl MinimapViewport {
38-
/// Create responsive minimap viewport based on window size
67+
/// Create responsive minimap viewport based on window size.
3968
pub fn from_window_size(window_width: f32, window_height: f32) -> Self {
4069
// For mobile screens (< 800px width), use smaller minimap
4170
let is_mobile = window_width < 800.0;
@@ -66,7 +95,7 @@ impl Default for MinimapViewport {
6695
}
6796
}
6897

69-
/// Resource for layer indicator state
98+
/// Resource for layer indicator state.
7099
#[derive(Resource)]
71100
pub struct LayerIndicatorState {
72101
pub show_timer: Timer, // Display for N seconds after layer change
@@ -80,7 +109,7 @@ impl Default for LayerIndicatorState {
80109
}
81110
}
82111

83-
/// Database update events from resident listeners
112+
/// Database update events from resident listeners.
84113
#[derive(Clone, Debug)]
85114
pub enum DatabaseUpdate {
86115
InstanceAdded(InstanceId),
@@ -96,23 +125,19 @@ pub enum DatabaseUpdate {
96125
TransferCompleted(InstanceId, InstanceId),
97126
}
98127

99-
/// Resource containing channel receiver for database updates
128+
/// Resource containing channel receiver for database updates.
100129
#[derive(Resource)]
101130
pub struct DatabaseUpdateChannel {
102131
pub receiver: mpsc::UnboundedReceiver<DatabaseUpdate>,
103132
}
104133

105-
/// Resource containing channel sender for database updates
134+
/// Resource containing channel sender for database updates.
106135
#[derive(Resource, Clone)]
107136
pub struct DatabaseUpdateSender {
108137
pub sender: mpsc::UnboundedSender<DatabaseUpdate>,
109138
}
110139

111-
/// Marker component for selected nodes
112-
#[derive(Component)]
113-
pub struct Selected;
114-
115-
/// Resource tracking all currently selected nodes
140+
/// Resource tracking all currently selected nodes.
116141
#[derive(Resource, Default)]
117142
pub struct SelectionSet {
118143
pub selected_nodes: Vec<InstanceId>,

0 commit comments

Comments
 (0)