use bevy::prelude::*;
use bevy_ui_navigation::mark::{NavMarker, NavMarkerPropagationPlugin};
use bevy_ui_navigation::prelude::{
DefaultNavigationPlugins, FocusState, Focusable, Focused, MenuBuilder, MenuSetting,
NavRequestSystem,
};
macro_rules! column_type {
(enum $type_name:ident , $i_base:expr) => {
#[derive(Component, Clone, Debug)]
enum $type_name {
Top,
Middle,
Bottom,
}
impl $type_name {
fn i(&self) -> usize {
match *self {
$type_name::Top => $i_base + 0,
$type_name::Middle => $i_base + 1,
$type_name::Bottom => $i_base + 2,
}
}
}
};
}
column_type!(enum LeftColMenu, 0);
column_type!(enum CenterColMenu, 3);
column_type!(enum RightColMenu, 6);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(NavMarkerPropagationPlugin::<LeftColMenu>::new())
.add_plugin(NavMarkerPropagationPlugin::<CenterColMenu>::new())
.add_plugin(NavMarkerPropagationPlugin::<RightColMenu>::new())
.add_plugins(DefaultNavigationPlugins)
.add_startup_system(setup)
.add_system(button_system.after(NavRequestSystem))
.add_system(print_menus.after(NavRequestSystem))
.run();
}
fn print_menus(
left_menus: Query<&LeftColMenu, Added<Focused>>,
center_menus: Query<&CenterColMenu, Added<Focused>>,
right_menus: Query<&RightColMenu, Added<Focused>>,
) {
if let Ok(menu) = left_menus.get_single() {
println!("Entered Red column menu: {menu:?}");
}
if let Ok(menu) = center_menus.get_single() {
println!("Entered Green column menu: {menu:?}");
}
if let Ok(menu) = right_menus.get_single() {
println!("Entered Blue column menu: {menu:?}");
}
}
fn button_system(
mut interaction_query: Query<(&Focusable, &mut BackgroundColor), Changed<Focusable>>,
) {
for (focus, mut material) in interaction_query.iter_mut() {
let color = match focus.state() {
FocusState::Focused => Color::ORANGE,
FocusState::Active => Color::GOLD,
FocusState::Prioritized => Color::GRAY,
FocusState::Inert | FocusState::Blocked => Color::BLACK,
};
*material = color.into();
}
}
fn setup(mut commands: Commands) {
use FlexDirection::{Column, Row};
use Val::{Percent as Pct, Px};
commands.spawn(Camera2dBundle::default());
macro_rules! bndl {
($color:expr, {$($style:tt)*} ) => (
NodeBundle {
background_color: ($color as Color).into(),
style: Style {
$($style)*
align_items: AlignItems::Center,
justify_content: JustifyContent::SpaceEvenly,
..Default::default()
},
..Default::default()
}
)
}
let wrap = MenuSetting::new().wrapping();
let reachable_from = MenuBuilder::EntityParent;
let good_margin = UiRect::all(Val::Px(20.0));
let root = bndl!(Color::WHITE, {
size: Size::new(Pct(100.0), Pct(100.0)),
flex_direction: Row,
});
let keyboard = bndl!(Color::DARK_GRAY, {
size: Size::new(Px(50.0 * 3.2), Px(50.0 * 3.2)),
flex_direction: Column,
flex_wrap: FlexWrap::Wrap,
});
let billboard = bndl!(Color::BLACK, { flex_direction: Row, margin: good_margin, });
let column = |color| bndl!(color, { flex_direction: Column, margin: good_margin, });
let cell = bndl!(Color::rgba(1.0, 1.0, 1.0, 0.2), {
flex_direction: Row,
margin: good_margin,
padding: good_margin,
});
let button = bndl!(Color::BLACK, {
size: Size::new(Px(40.0), Px(40.0)),
margin: UiRect::all(Px(5.0)),
});
macro_rules! nine {
($k:expr) => {
[$k, $k, $k, $k, $k, $k, $k, $k, $k]
};
}
let bts: [Entity; 9] = nine![commands.spawn((button.clone(), Focusable::default())).id()];
macro_rules! spawn_cell {
($cmds: expr) => {{
$cmds.spawn(cell.clone()).with_children(|cmds| {
let focus = || Focusable::default();
cmds.spawn((button.clone(), focus()));
cmds.spawn((button.clone(), focus()));
cmds.spawn((button.clone(), focus()));
})
}};
}
let (red, green, blue) = (Color::RED, Color::GREEN, Color::BLUE);
commands.spawn(root).with_children(|cmds| {
cmds.spawn((
keyboard,
MenuSetting::new().wrapping().scope(),
MenuBuilder::Root, ))
.push_children(&bts);
cmds.spawn(billboard).with_children(|cmds| {
cmds.spawn(column(red)).with_children(|cmds| {
let menu = |row: LeftColMenu| (wrap, reachable_from(bts[row.i()]), NavMarker(row));
spawn_cell!(cmds).insert(menu(LeftColMenu::Top));
spawn_cell!(cmds).insert(menu(LeftColMenu::Middle));
spawn_cell!(cmds).insert(menu(LeftColMenu::Bottom));
});
cmds.spawn(column(green)).with_children(|cmds| {
let menu =
|row: CenterColMenu| (wrap, reachable_from(bts[row.i()]), NavMarker(row));
spawn_cell!(cmds).insert(menu(CenterColMenu::Top));
spawn_cell!(cmds).insert(menu(CenterColMenu::Middle));
spawn_cell!(cmds).insert(menu(CenterColMenu::Bottom));
});
cmds.spawn(column(blue)).with_children(|cmds| {
let menu = |row: RightColMenu| (wrap, reachable_from(bts[row.i()]), NavMarker(row));
spawn_cell!(cmds).insert(menu(RightColMenu::Top));
spawn_cell!(cmds).insert(menu(RightColMenu::Middle));
spawn_cell!(cmds).insert(menu(RightColMenu::Bottom));
});
});
});
}