use crate::CurrentWidgetState;
use crate::widgets::{BindToID, IgnoreParentState, UIGenID, UIWidgetState};
use bevy::prelude::*;
pub struct StateService;
impl Plugin for StateService {
fn build(&self, app: &mut App) {
app.register_type::<Pickable>();
app.add_systems(PostUpdate, update_widget_states);
app.add_systems(
Update,
(
internal_state_check.run_if(resource_changed::<CurrentWidgetState>),
handle_tab_focus,
unfocus_disabled,
),
);
}
}
pub fn update_widget_states(
main_query: Query<(&UIGenID, &UIWidgetState), (Changed<UIWidgetState>, With<UIGenID>)>,
mut inner_query: Query<
(&BindToID, &mut UIWidgetState),
(Without<UIGenID>, Without<IgnoreParentState>),
>,
) {
for (id, state) in main_query.iter() {
for (bind_to, mut inner_state) in inner_query.iter_mut() {
if bind_to.0 != id.get() {
continue;
}
inner_state.hovered = state.hovered;
inner_state.focused = state.focused;
inner_state.readonly = state.readonly;
inner_state.disabled = state.disabled;
inner_state.checked = state.checked;
}
}
}
fn internal_state_check(
current_state_element: Res<CurrentWidgetState>,
mut query: Query<(&mut UIWidgetState, &UIGenID), With<UIGenID>>,
) {
for (mut state, gen_id) in query.iter_mut() {
if gen_id.get() == current_state_element.widget_id {
continue;
}
state.focused = false;
}
}
fn handle_tab_focus(
mut query: Query<(Entity, &mut UIWidgetState, &UIGenID)>,
keyboard: Res<ButtonInput<KeyCode>>,
mut current_state: ResMut<CurrentWidgetState>,
) {
if !keyboard.just_pressed(KeyCode::Tab) {
return;
}
let reverse = keyboard.pressed(KeyCode::ShiftLeft) || keyboard.pressed(KeyCode::ShiftRight);
let mut elems: Vec<_> = query
.iter_mut()
.filter(|(_, state, _)| !state.disabled)
.collect();
elems.sort_by_key(|(_, _, id)| id.get());
let len = elems.len();
if len == 0 {
return;
}
let mut focused_idx = None;
for (i, (_, state, _)) in elems.iter().enumerate() {
if state.focused {
focused_idx = Some(i);
break;
}
}
match focused_idx {
Some(i) => {
elems[i].1.focused = false;
let next = if reverse {
(i + len - 1) % len
} else {
(i + 1) % len
};
elems[next].1.focused = true;
current_state.widget_id = elems[next].2.get();
}
None => {
let next = if reverse { len - 1 } else { 0 };
elems[next].1.focused = true;
current_state.widget_id = elems[next].2.get();
}
}
}
fn unfocus_disabled(mut q: Query<&mut UIWidgetState, Changed<UIWidgetState>>) {
for mut s in &mut q {
if s.disabled && s.focused {
s.focused = false;
}
}
}