use crate::{construct::*, prelude::*};
use bevy::prelude::*;
use std::borrow::Cow;
#[derive(Debug, Component, Reflect)]
pub struct Confirm {
pub yes: bool,
}
impl OptionPrompt for Confirm {
fn name(&self, index: usize) -> &str {
match index {
0 => "No",
1 => "Yes",
_ => panic!("No such option for Confirm."),
}
}
fn state(&self) -> usize {
if self.yes { 1 } else { 0 }
}
}
unsafe impl Submitter for Confirm {
type Out = bool;
}
pub(crate) fn plugin(app: &mut App) {
app.add_systems(Update, confirm_controller.in_set(AskySet::Controller));
}
impl Construct for Confirm {
type Props = Cow<'static, str>;
fn construct(
context: &mut ConstructContext,
props: Self::Props,
) -> Result<Self, ConstructError> {
let mut commands = context.world.commands();
commands
.entity(context.id)
.insert(Focusable::default())
.insert(Prompt(props.clone()));
context.world.flush();
Ok(Confirm { yes: false })
}
}
fn confirm_controller(
mut query: Query<(Entity, &mut Confirm)>,
input: Res<ButtonInput<KeyCode>>,
mut commands: Commands,
focus: FocusParam,
) {
for (id, mut confirm) in query.iter_mut() {
if !focus.is_focused(id) {
continue;
}
if input.any_just_pressed([
KeyCode::KeyY,
KeyCode::ArrowRight,
KeyCode::ArrowLeft,
KeyCode::KeyH,
KeyCode::KeyL,
KeyCode::KeyN,
KeyCode::Enter,
KeyCode::Escape,
]) {
if input.any_just_pressed([KeyCode::KeyY, KeyCode::KeyL, KeyCode::ArrowRight]) {
confirm.yes = true;
}
if input.any_just_pressed([KeyCode::KeyN, KeyCode::KeyH, KeyCode::ArrowLeft]) {
confirm.yes = false;
}
if input.just_pressed(KeyCode::Enter) {
commands.trigger(Submit::<bool>::new(id, Ok(confirm.yes)));
}
if input.just_pressed(KeyCode::Escape) {
commands.trigger(Submit::<bool>::new(id, Err(Error::Cancel)));
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use bevy::ecs::system::RunSystemOnce;
use bevy::input::keyboard::KeyCode;
#[derive(Resource)]
struct KeyToPress(KeyCode);
fn press_key_system(key: Res<KeyToPress>, mut input: ResMut<ButtonInput<KeyCode>>) {
input.press(key.0);
}
fn clear_keys_system(mut input: ResMut<ButtonInput<KeyCode>>) {
*input = ButtonInput::default();
}
#[test]
fn test_confirm_key_presses() {
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.add_plugins(AskyPlugin)
.add_message::<bevy::input::keyboard::KeyboardInput>()
.init_resource::<ButtonInput<KeyCode>>()
.init_resource::<bevy::input_focus::InputFocus>();
let entity = app
.world_mut()
.spawn((
Confirm { yes: false },
Focusable::default(),
Prompt(Cow::Borrowed("Do you confirm?")),
))
.id();
app.update();
fn simulate_key_press(app: &mut App, key: KeyCode) {
app.world_mut().insert_resource(KeyToPress(key));
app.world_mut().run_system_once(press_key_system).unwrap();
app.update();
app.world_mut().run_system_once(clear_keys_system).unwrap();
app.update();
}
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(!confirm.yes);
simulate_key_press(&mut app, KeyCode::KeyY);
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(confirm.yes);
simulate_key_press(&mut app, KeyCode::KeyN);
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(!confirm.yes);
simulate_key_press(&mut app, KeyCode::KeyL);
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(confirm.yes);
simulate_key_press(&mut app, KeyCode::KeyH);
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(!confirm.yes);
simulate_key_press(&mut app, KeyCode::ArrowRight);
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(confirm.yes);
simulate_key_press(&mut app, KeyCode::ArrowLeft);
let confirm = app.world().get::<Confirm>(entity).unwrap();
assert!(!confirm.yes);
simulate_key_press(&mut app, KeyCode::KeyY);
let confirm_before = app.world().get::<Confirm>(entity).unwrap();
assert!(confirm_before.yes);
simulate_key_press(&mut app, KeyCode::Enter);
let confirm_after = app.world().get::<Confirm>(entity).unwrap();
assert!(confirm_after.yes);
simulate_key_press(&mut app, KeyCode::Escape);
let confirm_after_escape = app.world().get::<Confirm>(entity).unwrap();
assert!(confirm_after_escape.yes);
}
}