From fb1b95426227ad5476e5d25b8e14bce85e13a8b2 Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Tue, 26 Aug 2025 12:24:20 -0500 Subject: [PATCH] Replace base-ui bundle with a spawning function --- src/main.rs | 9 ++- src/resources.rs | 11 +++- src/widgets/machines.rs | 140 ++++++++++++++++++++-------------------- src/widgets/mod.rs | 96 ++++++++++++++------------- 4 files changed, 137 insertions(+), 119 deletions(-) diff --git a/src/main.rs b/src/main.rs index cbb3b5d..66e2a7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use bevy::{prelude::*, window::WindowResolution}; use bevy_inspector_egui::{bevy_egui::EguiPlugin, quick::WorldInspectorPlugin}; -use crate::game::machines::RotatingMachine; +use crate::game::machines::{CuttingMachine, RotatingMachine}; mod assets; mod card; @@ -24,7 +24,12 @@ fn main() { .register_type::() .add_systems( Startup, - (setup, assets::load_assets, RotatingMachine::spawn_ui), + ( + setup, + assets::load_assets, + RotatingMachine::spawn_ui, + CuttingMachine::spawn_ui, + ), ) .add_observer(widgets::CloseButton::hover_start) .add_observer(widgets::CloseButton::hover_stop) diff --git a/src/resources.rs b/src/resources.rs index 4236d6e..db47d7c 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,11 +1,16 @@ //! Program constants & defaults -use bevy::{color::palettes::css::*, prelude::*}; +use bevy::{ + color::palettes::{css::*, tailwind::SLATE_100}, + prelude::*, +}; #[derive(Debug, Reflect, Resource)] #[reflect(Resource)] pub struct UiTheme { - // TODO: Panes + // Colors for the machine UI panes + // (and others, but we're not there yet) + pub pane_bg: Color, // Colors for the "Big Red Buttons" (the main actions of the machines) // normal @@ -33,6 +38,8 @@ pub struct UiTheme { impl FromWorld for UiTheme { fn from_world(world: &mut World) -> Self { Self { + pane_bg: SLATE_100.into(), + brb_bg: RED.into(), brb_border: DARK_RED.into(), brb_hover_bg: PINK.into(), diff --git a/src/widgets/machines.rs b/src/widgets/machines.rs index 013c7c5..a5b26f6 100644 --- a/src/widgets/machines.rs +++ b/src/widgets/machines.rs @@ -2,89 +2,87 @@ use bevy::{color::palettes::css::*, prelude::*, ui::Val::*}; use crate::{ game::machines::*, - widgets::{CloseButton, machine_ui_base, spawn_big_red_button}, + resources::UiTheme, + widgets::{machine_ui_base, spawn_big_red_button}, }; impl CuttingMachine { - pub fn spawn_ui(mut commands: Commands) { - commands - .spawn((machine_ui_base("Cutting Machine"),)) - .with_children(|commands| { - // Left panel. For fuel or machine stats or whatever. - commands.spawn(( - Node { - padding: UiRect::all(Px(10.0)), - ..default() - }, - BackgroundColor(GREEN.into()), - Pickable::default(), - children![(Text::new("Uses: "), TextColor(BLACK.into()),)], - )); + pub fn spawn_ui(mut commands: Commands, theme: Res) { + let base_entity = machine_ui_base(&mut commands, "Cutting Machine", &theme); + commands.entity(base_entity).with_children(|commands| { + // Left panel. For fuel or machine stats or whatever. + commands.spawn(( + Node { + padding: UiRect::all(Px(10.0)), + ..default() + }, + BackgroundColor(GREEN.into()), + Pickable::default(), + children![(Text::new("Uses: "), TextColor(BLACK.into()),)], + )); - // Center panel (placeholder for the Card view) - commands.spawn(( - Node::default(), - BackgroundColor(BLUE.into()), + // Center panel (placeholder for the Card view) + commands.spawn(( + Node::default(), + BackgroundColor(BLUE.into()), + Pickable::default(), + children![( + Text::new("Card cut view placeholder"), + TextColor(MAGENTA.into()), + TextShadow::default(), + ),], + )); + // Right panel for the "CUT" button + commands + .spawn(( + Node { + align_items: AlignItems::End, + ..Default::default() + }, + BackgroundColor(DARK_GRAY.into()), Pickable::default(), - children![( - Text::new("Card cut view placeholder"), - TextColor(MAGENTA.into()), - TextShadow::default(), - ),], - )); - // Right panel for the "CUT" button - commands - .spawn(( - Node { - align_items: AlignItems::End, - ..Default::default() - }, - BackgroundColor(DARK_GRAY.into()), - Pickable::default(), - )) - .with_children(|cmds| spawn_big_red_button(cmds, "CUT")); - }); + )) + .with_children(|cmds| spawn_big_red_button(cmds, "CUT")); + }); } } impl RotatingMachine { - pub fn spawn_ui(mut commands: Commands) { - commands - .spawn((machine_ui_base("Rotating Machine"),)) - .with_children(|commands| { - commands.spawn(CloseButton::bundle(commands.target_entity())); - commands.spawn(( + pub fn spawn_ui(mut commands: Commands, theme: Res) { + let base_entity = machine_ui_base(&mut commands, "Rotating Machine", &theme); + commands.entity(base_entity).with_children(|commands| { + commands.spawn(( + Node { + padding: UiRect::all(Px(10.0)), + ..Default::default() + }, + BackgroundColor(GREEN.into()), + Pickable::default(), + children![(Text::new("Uses: "), TextColor(BLACK.into()))], + )); + + // Center panel (placeholder for input-output rotation) + commands.spawn(( + Node::default(), + BackgroundColor(BLUE.into()), + Pickable::default(), + children![ + Text::new("Card rotation side-by-side placeholder"), + TextColor(MAGENTA.into()), + ], + )); + + // Right panel for the rotation controls + commands + .spawn(( Node { - padding: UiRect::all(Px(10.0)), + align_items: AlignItems::End, ..Default::default() }, - BackgroundColor(GREEN.into()), + BackgroundColor(DARK_GRAY.into()), Pickable::default(), - children![(Text::new("Uses: "), TextColor(BLACK.into()))], - )); - - // Center panel (placeholder for input-output rotation) - commands.spawn(( - Node::default(), - BackgroundColor(BLUE.into()), - Pickable::default(), - children![ - Text::new("Card rotation side-by-side placeholder"), - TextColor(MAGENTA.into()), - ], - )); - - // Right panel for the rotation controls - commands - .spawn(( - Node { - align_items: AlignItems::End, - ..Default::default() - }, - BackgroundColor(DARK_GRAY.into()), - Pickable::default(), - )) - .with_children(|cmds| spawn_big_red_button(cmds, "TURN")); - }); + )) + .with_children(|cmds| spawn_big_red_button(cmds, "TURN")); + }); } } diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index cafefd3..1e5efbd 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -2,58 +2,66 @@ pub mod machines; -use bevy::{ - color::palettes::{css::*, tailwind::*}, - prelude::*, - ui::Val::*, -}; +use bevy::{color::palettes::css::*, prelude::*, ui::Val::*}; use crate::resources::UiTheme; /// The base panel for the machines that manipulate the room cards. -fn machine_ui_base(header: impl Into) -> impl Bundle { - ( - Node { - // Position & size - position_type: PositionType::Relative, - width: Percent(60.0), - height: Percent(60.0), - top: Percent(20.0), - left: Percent(20.0), - - // 5x5 grid, padding & gutters, etc - aspect_ratio: Some(1.0), - display: Display::Grid, - padding: UiRect::all(Val::Px(10.0)), - grid_template_columns: vec![ - GridTrack::min_content(), - GridTrack::flex(1.0), - GridTrack::min_content(), - ], - grid_template_rows: vec![GridTrack::min_content(), GridTrack::flex(1.0)], - row_gap: Val::Px(5.0), - column_gap: Val::Px(5.0), - - ..default() - }, - BackgroundColor(SLATE_100.into()), - BorderRadius::all(Percent(2.0)), - children![( - // TODO: A real node with stuff in it (buttons, maybe?) +/// +/// This function is not a valid Bevy System because of how the Commands struct +/// is passed through. Users are meant to call this *from* a System to create a +/// base UI Node. That system then re-acquires an [`EntityCommands`] and adds +/// child nodes to fill out the panel. +fn machine_ui_base(commands: &mut Commands, header: impl Into, theme: &UiTheme) -> Entity { + let root_pane = commands + .spawn(( Node { - justify_content: JustifyContent::Center, - grid_column: GridPlacement::span(2), + // Position & size + position_type: PositionType::Relative, + width: Percent(60.0), + height: Percent(60.0), + top: Percent(20.0), + left: Percent(20.0), + + // 5x5 grid, padding & gutters, etc + aspect_ratio: Some(1.0), + display: Display::Grid, + padding: UiRect::all(Val::Px(10.0)), + grid_template_columns: vec![ + GridTrack::min_content(), + GridTrack::flex(1.0), + GridTrack::min_content(), + ], + grid_template_rows: vec![GridTrack::min_content(), GridTrack::flex(1.0)], + row_gap: Val::Px(5.0), + column_gap: Val::Px(5.0), + ..default() }, - BackgroundColor(RED.into()), - Pickable::default(), + BackgroundColor(theme.pane_bg), + BorderRadius::all(Percent(2.0)), children![( - Text::new(header), - TextColor(BLACK.into()), - // TODO: Text shadow, maybe. I couldn't make it look good. - )], - ),], - ) + // TODO: A real node with stuff in it (buttons, maybe?) + Node { + justify_content: JustifyContent::Center, + grid_column: GridPlacement::span(2), + ..default() + }, + BackgroundColor(RED.into()), + Pickable::default(), + children![( + Text::new(header), + TextColor(BLACK.into()), + // TODO: Text shadow, maybe. I couldn't make it look good. + )], + ),], + )) + .id(); + + commands.entity(root_pane).with_children(|cmds| { + cmds.spawn(CloseButton::bundle(root_pane)); + }); + root_pane } // TODO: Hook up action handling (callback? Observer? Some other weird component?)