From 1a0f8f0a3f07bac0773e32ee79d4fe1a794b82e8 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Mon, 21 Jul 2025 12:02:51 -0700 Subject: [PATCH] Partially implemented debug UI -- need to hide it now... --- examples/ui.rs | 29 +++++---- src/bin/trees/main.rs | 134 ++++++++++++++++++++++++++++++------------ src/ui.rs | 4 +- 3 files changed, 116 insertions(+), 51 deletions(-) diff --git a/examples/ui.rs b/examples/ui.rs index b2357a2..332b457 100644 --- a/examples/ui.rs +++ b/examples/ui.rs @@ -14,7 +14,13 @@ fn main() { let mut app = App::new(); app.add_plugins(BaseGamePlugin::default()) .add_systems(Startup, (setup_list, setup_nav_tree)) - .add_systems(Update, (hide_menu, control_menu.run_if(on_event::>.or(on_event::>)))); + .add_systems( + Update, + ( + hide_menu, + control_menu.run_if(on_event::>.or(on_event::>)), + ), + ); app.run(); } @@ -109,9 +115,7 @@ fn setup_nav_tree(mut commands: Commands) { } // When you pointer over the '+' make the entire menu visible -fn hide_menu( - mut nodes: Query<(Entity, &mut Visibility, &NavState), Changed>, -) { +fn hide_menu(mut nodes: Query<(Entity, &mut Visibility, &NavState), Changed>) { nodes.iter_mut().for_each(|(e, mut v, n)| { *v = match n { NavState::Open => Visibility::Inherited, @@ -140,21 +144,22 @@ fn control_menu( }); // Gives us the entiies covered by the HoverMap - let is_hovered: Vec<&Entity> = hover_map.iter().flat_map(|(_, submap)| { - let x: Vec<&Entity> = submap.iter().map(|(node, _)| { - node - }).collect(); + let is_hovered: Vec<&Entity> = hover_map + .iter() + .flat_map(|(_, submap)| { + let x: Vec<&Entity> = submap.iter().map(|(node, _)| node).collect(); x - }).collect(); + }) + .collect(); // For all pointer out events out_events.read().for_each(|out| { // If a relative of out.target is hovered, do nothing // Otherwise set to closed let root = children.root_ancestor(out.target); - let tree_still_hovered = parents.iter_descendants(root).any(|child| { - is_hovered.contains(&&child) - }); + let tree_still_hovered = parents + .iter_descendants(root) + .any(|child| is_hovered.contains(&&child)); if !tree_still_hovered { parents.iter_descendants(root).for_each(|child| { if let Ok(mut n) = nav.get_mut(child) { diff --git a/src/bin/trees/main.rs b/src/bin/trees/main.rs index cd17703..c396b93 100644 --- a/src/bin/trees/main.rs +++ b/src/bin/trees/main.rs @@ -4,7 +4,7 @@ mod mono; -use bevy::platform::hash::RandomState; +use bevy::{picking::hover::HoverMap, platform::hash::RandomState}; use games::*; use mono::*; use std::hash::BuildHasher; @@ -43,12 +43,13 @@ fn main() { .run_if(on_event::>), spawn_debug_buttons.run_if(on_event::>), dialog_engine.run_if(on_event::), - mouse_wheel_scroll.run_if(on_event::), auto_scroll.run_if(any_component_added::), dialog_box_visibility.run_if(state_changed::), monologue_asset_tooltip .run_if(on_event::>.or(on_event::>)), scale_window.run_if(on_event::), + hide_menu.run_if(any_component_changed::), + control_menu.run_if(on_event::>.or(on_event::>)), ), ) .add_observer(add_dialog_option) @@ -101,6 +102,7 @@ fn init_ui(mut commands: Commands) { ..default() }, )) + .observe(scroll) .observe(hover_dialog_box_over) .observe(hover_dialog_box_out); } @@ -115,46 +117,59 @@ struct MonologuesList; struct MonologuePreview; /// Panel for selecting which monologue tree to spawn -/// TODO: When monologue is loaded, add a button for it in this -/// TODO: When mouse over button, preview it in the "MonologuePreview" box fn init_debug_ui(mut commands: Commands) { - commands + let button = commands .spawn(( + Name::new("Monologue Assignment Menu"), + Text::new("+ Monologue"), Node { - max_height: Val::Percent(90.0), - align_self: AlignSelf::Center, + align_self: AlignSelf::Start, justify_self: JustifySelf::Start, + min_width: Val::Px(25.0), + min_height: Val::Px(25.0), ..default() }, - MonologuesContainer, - GlobalZIndex(i32::MAX - 1), - BackgroundColor(PINK.into()), + BackgroundColor(RED.into()), DebuggingState::On, + MonologuesContainer, )) - .with_children(|parent| { + .id(); + commands + .spawn(( + NavParent(button), + NavState::default(), + Name::new("Container"), + Node { + flex_direction: FlexDirection::Row, + top: Val::Px(25.0), + height: Val::Percent(90.0), + ..default() + }, + BackgroundColor(BLACK.into()), + )).with_children(|parent| { parent.spawn(( + Name::new("Buttons"), Node { - height: Val::Percent(100.0), flex_direction: FlexDirection::Column, - padding: UiRect::all(Val::Px(10.0)), + height: Val::Percent(100.0), overflow: Overflow::scroll_y(), ..default() }, - BackgroundColor(PINK.with_alpha(0.9).into()), + ScrollPosition::default(), + BackgroundColor(ORANGE.into()), MonologuesList, - )); + )).observe(scroll); + parent.spawn(( + Name::new("Preview"), + Text::new("This is placeholder text"), Node { - height: Val::Percent(100.0), - flex_direction: FlexDirection::Column, - padding: UiRect::all(Val::Px(10.0)), - overflow: Overflow::scroll_y(), ..default() }, - BackgroundColor(ORANGE.with_alpha(0.9).into()), + BackgroundColor(YELLOW.into()), MonologuePreview, )); - }); + }); } fn hover_dialog_box_over( @@ -186,22 +201,6 @@ fn position_camera(mut query: Query<&mut Transform, (With, With, - mut scroll_position: Query<&mut ScrollPosition>, -) { - events.read().for_each(|MouseWheel { unit, y, .. }| { - let offset_y = match unit { - MouseScrollUnit::Line => 10.0 * y, - MouseScrollUnit::Pixel => 1.0 * y, - }; - scroll_position - .iter_mut() - .for_each(|mut pos| pos.offset_y += offset_y); - }); -} - /// Automatically scrolls dialog when a new batch of options are added fn auto_scroll( added: Query>, @@ -757,3 +756,64 @@ fn drag_tree( } } } + +// When you pointer over the '+' make the entire menu visible +fn hide_menu(mut nodes: Query<(Entity, &mut Visibility, &NavState), Changed>) { + nodes.iter_mut().for_each(|(e, mut v, n)| { + *v = match n { + NavState::Open => Visibility::Inherited, + NavState::Closed => Visibility::Hidden, + }; + info!("Visiblity for {:?}: {:?}", e, v); + }); +} + +// When you pointer goes off of the '+' or any of it's children make the entire menu invisible +fn control_menu( + mut over_events: EventReader>, + mut out_events: EventReader>, + nav_children: Query<&NavParent>, + children: Query<&ChildOf>, + nav_parents: Query<&NavChildren>, + parents: Query<&Children>, + mut nav: Query<&mut NavState>, + hover_map: Res, +) { + over_events.read().for_each(|over| { + let root = nav_children.root_ancestor(over.target); + + nav_parents.iter_descendants(root).for_each(|child| { + if let Ok(mut n) = nav.get_mut(child) { + info!("Opening {:?} for {:?}", child, root); + *n = NavState::Open; + } + }); + }); + + // Gives us the enities covered by the HoverMap + let is_hovered: Vec<&Entity> = hover_map + .iter() + .flat_map(|(_, submap)| { + let x: Vec<&Entity> = submap.iter().map(|(node, _)| node).collect(); + x + }) + .collect(); + + // For all pointer out events + out_events.read().for_each(|out| { + // If a relative of out.target is hovered, do nothing + // Otherwise set to closed + let root = children.root_ancestor(out.target); + let tree_still_hovered = parents + .iter_descendants(root) + .any(|child| is_hovered.contains(&&child)); + if !tree_still_hovered { + parents.iter_descendants(root).for_each(|child| { + if let Ok(mut n) = nav.get_mut(child) { + info!("Closing {:?} for {:?}", child, root); + *n = NavState::Closed; + } + }) + } + }) +} diff --git a/src/ui.rs b/src/ui.rs index 42678a7..a29b827 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -25,7 +25,7 @@ pub fn sync_resource_to_ui( } /// Updates the scroll position of scrollable nodes in response to mouse input -pub fn scroll(trigger: Trigger>, mut scrollers: Query<&mut ScrollPosition>) { +pub fn scroll(trigger: Trigger>, mut scrollers: Query<(Entity, &mut ScrollPosition)>) { let Pointer { event: Scroll { unit, x, y, .. }, .. @@ -36,7 +36,7 @@ pub fn scroll(trigger: Trigger>, mut scrollers: Query<&mut Scrol MouseScrollUnit::Pixel => (x * 1., y * 1.), }; - if let Ok(mut pos) = scrollers.get_mut(trigger.target()) { + if let Ok((e, mut pos)) = scrollers.get_mut(trigger.target()) { pos.offset_x -= dx; pos.offset_y -= dy; }