You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.6 KiB
Rust
176 lines
5.6 KiB
Rust
#![feature(iter_intersperse)]
|
|
|
|
//! This example illustrates scrolling in Bevy UI.
|
|
|
|
use bevy::picking::hover::HoverMap;
|
|
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, setup_button))
|
|
.add_systems(
|
|
Update,
|
|
(
|
|
hide_menu,
|
|
control_menu.run_if(on_event::<Pointer<Over>>.or(on_event::<Pointer<Out>>)),
|
|
),
|
|
);
|
|
app.run();
|
|
}
|
|
|
|
fn setup_list(mut commands: Commands) {
|
|
// Scrolling list
|
|
commands
|
|
.spawn((Node {
|
|
flex_direction: FlexDirection::Column,
|
|
// If height is not set, we need both align_self: Stetch and overflow: scroll()
|
|
height: Val::Percent(50.0),
|
|
// align_self: AlignSelf::Stretch,
|
|
overflow: Overflow::scroll(),
|
|
..default()
|
|
},))
|
|
.with_children(|parent| {
|
|
parent.spawn(Text("This srolls".into()));
|
|
// List items
|
|
(0..250).for_each(|i| {
|
|
parent.spawn(Text(format!("Item {i}")));
|
|
});
|
|
})
|
|
.observe(scroll);
|
|
}
|
|
|
|
fn setup_button(mut commands: Commands) {
|
|
// Spawn a random button at the center of the screen for testing
|
|
commands.spawn((
|
|
Node {
|
|
align_self: AlignSelf::Center,
|
|
justify_self: JustifySelf::Center,
|
|
..default()
|
|
},
|
|
Button,
|
|
children![Text("Hello World".into()),],
|
|
));
|
|
}
|
|
|
|
fn setup_nav_tree(mut commands: Commands) {
|
|
// Nav Tree
|
|
commands
|
|
.spawn((
|
|
Node {
|
|
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()
|
|
},
|
|
Button,
|
|
children![Text::new("+Menu"),],
|
|
))
|
|
.with_children(|parent| {
|
|
parent
|
|
.spawn((
|
|
Name::new("Buttons"),
|
|
NavState::default(),
|
|
Node {
|
|
position_type: PositionType::Absolute,
|
|
flex_direction: FlexDirection::Column,
|
|
right: Val::Percent(100.0),
|
|
width: Val::Auto,
|
|
..default()
|
|
},
|
|
))
|
|
.with_children(|parent| {
|
|
(0..10).for_each(|_| {
|
|
let title: String = lipsum_title_with_rng(thread_rng())
|
|
.split_whitespace()
|
|
.take(2)
|
|
.intersperse(" ")
|
|
.collect();
|
|
parent.spawn((
|
|
children![Text::new(title),],
|
|
Node {
|
|
width: Val::Auto,
|
|
..default()
|
|
},
|
|
Button,
|
|
));
|
|
});
|
|
})
|
|
.with_children(|parent| {
|
|
parent.spawn((
|
|
Name::new("Preview"),
|
|
NavState::default(),
|
|
children![Text::new(lipsum_with_rng(thread_rng(), 50)),],
|
|
Node {
|
|
position_type: PositionType::Absolute,
|
|
right: Val::Percent(100.0),
|
|
width: Val::Percent(100.0),
|
|
max_height: Val::Percent(100.0),
|
|
..default()
|
|
},
|
|
));
|
|
});
|
|
});
|
|
}
|
|
|
|
// When you pointer over the '+' make the entire menu visible
|
|
fn hide_menu(mut nodes: Query<(&mut Visibility, &NavState), Changed<NavState>>) {
|
|
nodes.iter_mut().for_each(|(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;
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|