use bevy::{prelude::*, ui_widgets::observe};
use jackdaw_feathers::{
button::{self, ButtonProps, ButtonVariant},
separator, tokens,
};
use super::{
brp_client::GetNavmeshInput,
build::BuildNavmesh,
save_load::{LoadNavmesh, SaveNavmesh},
visualization::NavmeshVizConfig,
};
use crate::{EditorEntity, selection::Selection};
pub(super) fn plugin(app: &mut App) {
app.add_systems(
Update,
(toggle_toolbar_visibility, update_navmesh_viz_highlights)
.run_if(in_state(crate::AppState::Editor)),
);
app.add_observer(on_viz_toggle_added);
}
#[derive(Component)]
pub struct NavmeshToolbar;
#[derive(Component, Clone, Copy, PartialEq, Eq)]
enum NavmeshVizToggle {
Visual,
Obstacles,
DetailMesh,
PolygonMesh,
}
pub fn navmesh_toolbar() -> impl Bundle {
(
NavmeshToolbar,
EditorEntity,
Node {
flex_direction: FlexDirection::Row,
align_items: AlignItems::Center,
padding: UiRect::axes(px(tokens::SPACING_MD), px(tokens::SPACING_SM)),
column_gap: px(tokens::SPACING_SM),
width: percent(100),
height: px(32.0),
flex_shrink: 0.0,
display: Display::None,
..Default::default()
},
BackgroundColor(tokens::TOOLBAR_BG),
children![
(
Text::new("Navmesh"),
TextFont {
font_size: tokens::FONT_SM,
..Default::default()
},
TextColor(tokens::TEXT_SECONDARY),
),
(
button::button(
ButtonProps::new("Fetch Scene").with_variant(ButtonVariant::Primary),
),
observe(|_: On<Pointer<Click>>, mut commands: Commands| {
commands.trigger(GetNavmeshInput);
}),
),
(
button::button(ButtonProps::new("Build").with_variant(ButtonVariant::Default)),
observe(|_: On<Pointer<Click>>, mut commands: Commands| {
commands.trigger(BuildNavmesh);
}),
),
(
button::button(ButtonProps::new("Save").with_variant(ButtonVariant::Default)),
observe(|_: On<Pointer<Click>>, mut commands: Commands| {
commands.trigger(SaveNavmesh);
}),
),
(
button::button(ButtonProps::new("Load").with_variant(ButtonVariant::Default)),
observe(|_: On<Pointer<Click>>, mut commands: Commands| {
commands.trigger(LoadNavmesh);
}),
),
separator::separator(separator::SeparatorProps::vertical()),
viz_toggle_button("Visual", NavmeshVizToggle::Visual, true),
viz_toggle_button("Obstacles", NavmeshVizToggle::Obstacles, false),
viz_toggle_button("Detail", NavmeshVizToggle::DetailMesh, true),
viz_toggle_button("Poly", NavmeshVizToggle::PolygonMesh, false),
],
)
}
fn viz_toggle_button(
label: &str,
toggle: NavmeshVizToggle,
_initially_active: bool,
) -> impl Bundle {
(
toggle,
button::button(ButtonProps::new(label).with_variant(ButtonVariant::Default)),
observe(
move |_: On<Pointer<Click>>, mut config: ResMut<NavmeshVizConfig>| match toggle {
NavmeshVizToggle::Visual => config.show_visual = !config.show_visual,
NavmeshVizToggle::Obstacles => config.show_obstacles = !config.show_obstacles,
NavmeshVizToggle::DetailMesh => config.show_detail_mesh = !config.show_detail_mesh,
NavmeshVizToggle::PolygonMesh => {
config.show_polygon_mesh = !config.show_polygon_mesh
}
},
),
)
}
fn toggle_toolbar_visibility(
selection: Res<Selection>,
regions: Query<(), With<jackdaw_jsn::NavmeshRegion>>,
mut toolbar: Query<&mut Node, With<NavmeshToolbar>>,
) {
if !selection.is_changed() {
return;
}
let should_show = selection.primary().is_some_and(|e| regions.contains(e));
for mut node in &mut toolbar {
node.display = if should_show {
Display::Flex
} else {
Display::None
};
}
}
fn update_navmesh_viz_highlights(
viz_config: Res<NavmeshVizConfig>,
mut buttons: Query<(&NavmeshVizToggle, &mut BackgroundColor)>,
) {
if !viz_config.is_changed() {
return;
}
for (toggle, mut bg) in &mut buttons {
bg.0 = viz_toggle_bg(&viz_config, toggle);
}
}
fn on_viz_toggle_added(
trigger: On<Add, NavmeshVizToggle>,
viz_config: Res<NavmeshVizConfig>,
mut buttons: Query<(&NavmeshVizToggle, &mut BackgroundColor)>,
) {
if let Ok((toggle, mut bg)) = buttons.get_mut(trigger.event_target()) {
bg.0 = viz_toggle_bg(&viz_config, toggle);
}
}
fn viz_toggle_bg(config: &NavmeshVizConfig, toggle: &NavmeshVizToggle) -> Color {
let active = match toggle {
NavmeshVizToggle::Visual => config.show_visual,
NavmeshVizToggle::Obstacles => config.show_obstacles,
NavmeshVizToggle::DetailMesh => config.show_detail_mesh,
NavmeshVizToggle::PolygonMesh => config.show_polygon_mesh,
};
if active {
tokens::SELECTED_BG
} else {
tokens::TOOLBAR_BUTTON_BG
}
}