From aa20709b30f5338d93187601846717ceaba4cc79 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 10 Jun 2025 20:15:52 +0300 Subject: [PATCH] feat(demo): replace egui combobox with bevy UI dropdown --- crates/bevy_dice_demo/Cargo.toml | 3 +- crates/bevy_dice_demo/src/main.rs | 39 ++--- crates/bevy_dice_demo/src/ui.rs | 238 +++++++++++++++++++++++++++--- 3 files changed, 232 insertions(+), 48 deletions(-) diff --git a/crates/bevy_dice_demo/Cargo.toml b/crates/bevy_dice_demo/Cargo.toml index 64270bf..2253eb8 100644 --- a/crates/bevy_dice_demo/Cargo.toml +++ b/crates/bevy_dice_demo/Cargo.toml @@ -9,6 +9,7 @@ debug = [ "bevy_dice/debug", "bevy/bevy_ui_debug", "avian3d/debug-plugin", + "dep:bevy_egui", "dep:bevy-inspector-egui", ] wasm = [ @@ -41,7 +42,7 @@ bevy_embedded_assets = { version = "0.13", default-features = false } bevy_egui = { version = "0.34", default-features = false, features = [ "render", "default_fonts", -] } +], optional = true } bevy-inspector-egui = { version = "0.31", optional = true } console_error_panic_hook = { version = "0.1", optional = true } web-time = { version = "1", optional = true } diff --git a/crates/bevy_dice_demo/src/main.rs b/crates/bevy_dice_demo/src/main.rs index 33f32c6..8a1a23b 100644 --- a/crates/bevy_dice_demo/src/main.rs +++ b/crates/bevy_dice_demo/src/main.rs @@ -11,7 +11,8 @@ use std::collections::HashMap; use avian3d::prelude::*; use bevy::{asset::LoadState, prelude::*}; use bevy_dice::{DicePlugin, DicePluginConfig, Die, DieResult, DieVariant, ThrowDie}; -use bevy_egui::{EguiContextPass, EguiContexts, EguiPlugin, egui}; +#[cfg(feature = "debug")] +use bevy_egui::EguiPlugin; use bevy_embedded_assets::EmbeddedAssetPlugin; #[cfg(feature = "debug")] use bevy_inspector_egui::quick::WorldInspectorPlugin; @@ -47,11 +48,11 @@ fn main() { PhysicsDebugPlugin::default(), )); + #[cfg(feature = "debug")] app.add_plugins(( EguiPlugin { enable_multipass_for_primary_context: true, }, - #[cfg(feature = "debug")] WorldInspectorPlugin::default(), )); @@ -70,12 +71,12 @@ fn main() { .add_systems(Update, wait_for_assets_to_load) .add_systems(OnEnter(ExampleState::Running), setup); - app.init_resource::() - .add_systems(EguiContextPass, ui); + app.init_resource::(); app.add_systems(Update, rotate_light); - app.add_observer(throw_die) + app.add_observer(variant_selected) + .add_observer(throw_die) .add_observer(despawn_dice) .add_observer(show_die_result); @@ -167,12 +168,12 @@ struct ExampleAssets { } #[derive(Resource)] -struct UIState { +struct State { selected_variant: DieVariant, die_id: u32, } -impl Default for UIState { +impl Default for State { fn default() -> Self { Self { selected_variant: DieVariant::D6, @@ -181,35 +182,23 @@ impl Default for UIState { } } -fn ui(mut contexts: EguiContexts, mut r_ui_state: ResMut) { - egui::Window::new("Demo").show(contexts.ctx_mut(), |ui| { - egui::ComboBox::from_label("") - .selected_text(format!("{:?}", r_ui_state.selected_variant)) - .show_ui(ui, |ui| { - for variant in DieVariant::VALUES { - ui.selectable_value( - &mut r_ui_state.selected_variant, - variant, - format!("{:?}", variant), - ); - } - }); - }); +fn variant_selected(trigger: Trigger, mut r_state: ResMut) { + r_state.selected_variant = trigger.0; } fn throw_die( _trigger: Trigger, mut commands: Commands, - mut r_ui_state: ResMut, + mut r_state: ResMut, ) { commands.trigger(ThrowDie { - id: r_ui_state.die_id, - variant: r_ui_state.selected_variant, + id: r_state.die_id, + variant: r_state.selected_variant, angular_velocity: None, position: Some(Vec3::new(0.0, 4.0, 0.0)), rotation: None, }); - r_ui_state.die_id += 1; + r_state.die_id += 1; } fn despawn_dice( diff --git a/crates/bevy_dice_demo/src/ui.rs b/crates/bevy_dice_demo/src/ui.rs index 0fb9212..02bf8e0 100644 --- a/crates/bevy_dice_demo/src/ui.rs +++ b/crates/bevy_dice_demo/src/ui.rs @@ -5,19 +5,32 @@ */ use bevy::{color::palettes::tailwind::*, prelude::*}; +use bevy_dice::DieVariant; const THROW_COLOR: Srgba = LIME_400; const DESPAWN_COLOR: Srgba = RED_400; +const VARIANT_COLOR: Srgba = AMBER_400; pub struct UIPlugin; impl Plugin for UIPlugin { fn build(&self, app: &mut App) { - app.add_systems(Startup, setup) - .add_systems(Update, button_interaction); + app.add_systems(Startup, setup).add_systems( + Update, + ( + button_interaction, + variant_dropdown_interaction, + variant_button_interaction, + ), + ); - app.add_event::() + app.add_event::() + .add_event::() + .add_event::() .add_event::(); + + app.add_observer(toggle_variant_buttons) + .add_observer(set_selected_variant_text); } } @@ -68,25 +81,6 @@ fn button(function: ButtonFunction, text: impl Into, color: Srgba) -> im ) } -fn setup(mut commands: Commands) { - commands.spawn(( - Node { - width: Val::Percent(100.0), - height: Val::Percent(100.0), - flex_direction: FlexDirection::Row, - align_items: AlignItems::FlexEnd, - justify_content: JustifyContent::SpaceEvenly, - padding: UiRect::all(Val::Px(8.0)), - overflow: Overflow::scroll_y(), - ..Default::default() - }, - children![ - button(ButtonFunction::Throw, "Throw", THROW_COLOR), - button(ButtonFunction::Despawn, "Despawn Dice", DESPAWN_COLOR), - ], - )); -} - fn button_interaction( mut commands: Commands, q_interaction: Query< @@ -117,3 +111,203 @@ fn button_interaction( } } } + +#[derive(Component)] +struct VariantDropdown; + +#[derive(Component)] +struct SelectedVariantText; + +#[derive(Event)] +struct ToggleVariantButtons; + +#[derive(Component)] +struct VariantButton(DieVariant); + +#[derive(Event)] +pub struct VariantSelected(pub DieVariant); + +fn variant_button(variant: VariantButton, text: impl Into) -> impl Bundle { + ( + variant, + Button, + Node { + width: Val::Px(120.0), + height: Val::Px(40.0), + border: UiRect::all(Val::Px(2.0)), + flex_direction: FlexDirection::Column, + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + margin: UiRect::bottom(Val::Px(4.0)), + ..Default::default() + }, + BackgroundColor(Color::from(VARIANT_COLOR)), + BorderColor(Color::from(VARIANT_COLOR.darker(0.3))), + BorderRadius::all(Val::Px(10.0)), + BoxShadow::new( + Color::BLACK.with_alpha(0.8), + Val::Px(4.0), + Val::Px(4.0), + Val::DEFAULT, + Val::DEFAULT, + ), + Visibility::Hidden, + children![( + Text::new(text), + TextFont { + font_size: 18.0, + ..Default::default() + }, + TextColor(Color::BLACK), + ),], + ) +} + +fn variant_dropdown_interaction( + mut commands: Commands, + q_interaction: Query< + (&Interaction, &mut BackgroundColor), + (Changed, With), + >, +) { + for (interaction, mut background) in q_interaction { + match *interaction { + Interaction::Pressed => { + commands.trigger(ToggleVariantButtons); + *background = VARIANT_COLOR.darker(0.3).into(); + } + Interaction::Hovered => { + *background = VARIANT_COLOR.darker(0.1).into(); + } + Interaction::None => { + *background = VARIANT_COLOR.into(); + } + } + } +} + +fn toggle_variant_buttons( + _trigger: Trigger, + mut q_variant_button_visibilities: Query<&mut Visibility, With>, +) { + for mut visibility in &mut q_variant_button_visibilities { + visibility.toggle_visible_hidden(); + } +} + +fn variant_button_interaction( + mut commands: Commands, + q_interaction: Query< + (&Interaction, &mut BackgroundColor, &VariantButton), + (Changed, With