diff --git a/src/focus_navigation.rs b/src/focus_navigation.rs new file mode 100644 index 0000000..f3a5990 --- /dev/null +++ b/src/focus_navigation.rs @@ -0,0 +1,242 @@ +use crate::main_menu::InteractionColors; +use bevy::{ + input::gamepad::GamepadButton, + input_focus::{ + InputFocus, InputFocusSystems, InputFocusVisible, + directional_navigation::DirectionalNavigationPlugin, tab_navigation::TabNavigationPlugin, + }, + math::{CompassOctant, Dir2}, + prelude::*, + text::EditableText, + ui::{InteractionDisabled, auto_directional_navigation::AutoDirectionalNavigator}, + ui_widgets::{Activate, Button, RadioGroup}, +}; + +/// Orders initial focus selection before directional movement in `PreUpdate`. +#[derive(SystemSet, Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub(crate) enum NavigationSystems { + /// Selects the active menu layer's first focusable item when navigation starts without focus. + Initialize, + /// Applies arrow-key and D-pad movement after focus initialization. + Navigate, +} + +/// Prevents the input that initializes focus from also moving it directionally. +#[derive(Resource, Default)] +pub(crate) struct NavigationInputState { + /// Set by the initializer and consumed by the directional-navigation system in the same frame. + pub(crate) focus_initialized: bool, +} + +/// Installs Bevy focus, tab, and directional navigation for the application's UI. +pub struct FocusNavigationPlugin; + +impl Plugin for FocusNavigationPlugin { + fn build(&self, app: &mut App) { + app.add_plugins((TabNavigationPlugin, DirectionalNavigationPlugin)) + .insert_resource(InputFocusVisible(true)) + .init_resource::() + .configure_sets( + PreUpdate, + (NavigationSystems::Initialize, NavigationSystems::Navigate) + .chain() + .after(InputFocusSystems::Dispatch), + ) + .add_systems( + PreUpdate, + navigate_directionally.in_set(NavigationSystems::Navigate), + ) + .add_systems(Update, style_focus_outlines) + .add_observer(show_focus_after_activation); + } +} + +pub(crate) fn navigate_directionally( + keyboard: Res>, + gamepads: Query<&Gamepad>, + mut navigator: AutoDirectionalNavigator, + editable_texts: Query<(), With>, + radio_groups: Query<(), With>, + focusable_buttons: Query<(), (With