The example works! yipee!

main
Elijah Voigt 3 months ago
parent ca3db16a48
commit cd9daa38c5

2
Cargo.lock generated

@ -2226,7 +2226,9 @@ dependencies = [
"bevy",
"bevy_rapier3d",
"chrono",
"itertools 0.13.0",
"lipsum",
"rand",
"serde",
"thiserror 2.0.12",
"walkdir",

@ -19,7 +19,9 @@ features = ["wayland", "dynamic_linking"]
[dev-dependencies]
lipsum = "*"
rand = "*"
itertools = "*"
[build-dependencies]
chrono = "*"
walkdir = "*"
chrono = "*"

@ -1,11 +1,20 @@
#![feature(iter_intersperse)]
//! This example illustrates scrolling in Bevy UI.
use bevy::picking::{
hover::HoverMap,
pointer::{PointerId, PointerMap},
};
use games::*;
use lipsum::*;
use rand::*;
fn main() {
let mut app = App::new();
app.add_plugins(BaseGamePlugin::default())
.add_systems(Startup, (setup_list, setup_nav_tree));
.add_systems(Startup, (setup_list, setup_nav_tree))
.add_systems(Update, (hide_menu, control_menu.run_if(on_event::<Pointer<Over>>.or(on_event::<Pointer<Out>>))));
app.run();
}
@ -36,12 +45,14 @@ fn setup_nav_tree(mut commands: Commands) {
// Nav Tree
commands
.spawn((
Text::new("+"),
Node {
position_type: PositionType::Absolute,
right: Val::Px(0.0),
top: Val::Percent(50.0),
align_self: AlignSelf::Start,
justify_self: JustifySelf::End,
min_width: Val::Px(25.0),
min_height: Val::Px(25.0),
align_content: AlignContent::Center,
justify_content: JustifyContent::Center,
..default()
},
BackgroundColor(RED.into()),
@ -49,26 +60,107 @@ fn setup_nav_tree(mut commands: Commands) {
.with_children(|parent| {
parent
.spawn((
Name::new("Buttons"),
NavState::default(),
Node {
position_type: PositionType::Absolute,
right: Val::Px(25.0),
min_width: Val::Px(25.0),
min_height: Val::Px(25.0),
flex_direction: FlexDirection::Column,
right: Val::Percent(100.0),
width: Val::Auto,
..default()
},
Visibility::Hidden,
BackgroundColor(ORANGE.into()),
))
.with_children(|parent| {
(0..10).for_each(|_| {
let title: String = lipsum_title_with_rng(thread_rng())
.split_whitespace()
.take(2)
.intersperse(" ")
.collect();
parent.spawn((
Text::new(title),
Node {
width: Val::Auto,
margin: UiRect::all(Val::Px(5.0)),
..default()
},
BackgroundColor(ORANGE_RED.into()),
Button,
));
});
})
.with_children(|parent| {
parent.spawn((
Name::new("Preview"),
NavState::default(),
Text::new(lipsum_with_rng(thread_rng(), 50)),
Node {
position_type: PositionType::Absolute,
right: Val::Px(25.0),
min_width: Val::Px(25.0),
min_height: Val::Px(25.0),
right: Val::Percent(100.0),
..default()
},
BackgroundColor(YELLOW.into()),
Visibility::Hidden,
));
});
});
}
// When you pointer over the '+' make the entire menu visible
fn hide_menu(
mut nodes: Query<(Entity, &mut Visibility, &NavState), Changed<NavState>>,
) {
nodes.iter_mut().for_each(|(e, mut v, n)| {
*v = match n {
NavState::Open => Visibility::Inherited,
NavState::Closed => Visibility::Hidden,
};
});
}
// 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<Pointer<Over>>,
mut out_events: EventReader<Pointer<Out>>,
children: Query<&ChildOf>,
parents: Query<&Children>,
mut nav: Query<&mut NavState>,
hover_map: Res<HoverMap>,
) {
over_events.read().for_each(|over| {
let root = children.root_ancestor(over.target);
parents.iter_descendants(root).for_each(|child| {
if let Ok(mut n) = nav.get_mut(child) {
*n = NavState::Open;
}
});
});
// 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();
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) {
*n = NavState::Closed;
}
})
}
})
}

@ -309,11 +309,7 @@ impl Display for Fps {
}
}
fn track_fps(
time: Res<Time>,
mut fps: ResMut<Fps>,
mut history: Local<VecDeque<f32>>,
) {
fn track_fps(time: Res<Time>, mut fps: ResMut<Fps>, mut history: Local<VecDeque<f32>>) {
// Get the time to render the last frame
let d = time.delta_secs();
@ -338,9 +334,6 @@ impl Display for EntityCount {
}
}
fn track_entity_count(
query: Query<Entity>,
mut count: ResMut<EntityCount>,
) {
fn track_entity_count(query: Query<Entity>, mut count: ResMut<EntityCount>) {
count.0 = query.iter().len();
}

@ -42,11 +42,21 @@ pub fn scroll(trigger: Trigger<Pointer<Scroll>>, mut scrollers: Query<&mut Scrol
}
}
/// Track who your parent is for navigation in the UI
/// Think the file menu is a child of the "file" button
#[derive(Component, Debug)]
#[relationship(relationship_target = NavParent)]
pub(crate) struct NavChild(Entity);
#[relationship(relationship_target = NavChildren)]
pub struct NavParent(pub Entity);
/// Back-relationship for nav-parent
#[derive(Component, Debug)]
#[relationship_target(relationship = NavChild)]
pub(crate) struct NavParent(Vec<Entity>);
#[relationship_target(relationship = NavParent)]
pub struct NavChildren(Vec<Entity>);
/// Track if a navigation [sub]tree is open or closed
#[derive(Component, Debug, Default)]
pub enum NavState {
Open,
#[default]
Closed,
}

Loading…
Cancel
Save