Skip to main content

bevy_feathers/controls/
virtual_keyboard.rs

1use bevy_ecs::prelude::*;
2use bevy_input_focus::tab_navigation::TabGroup;
3use bevy_ui::Node;
4use bevy_ui::Val;
5use bevy_ui::{widget::Text, FlexDirection};
6use bevy_ui_widgets::{observe, Activate};
7
8use crate::controls::{button, ButtonProps};
9
10/// Fired whenever a virtual key is pressed.
11#[derive(EntityEvent)]
12pub struct VirtualKeyPressed<T> {
13    /// The virtual keyboard entity
14    pub entity: Entity,
15    /// The pressed virtual key
16    pub key: T,
17}
18
19/// Function to spawn a virtual keyboard
20///
21/// # Emitted events
22/// * [`crate::controls::VirtualKeyPressed<T>`] when a virtual key on the keyboard is un-pressed.
23///
24///  These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
25pub fn virtual_keyboard<T>(
26    keys: impl Iterator<Item = Vec<T>> + Send + Sync + 'static,
27) -> impl Bundle
28where
29    T: AsRef<str> + Clone + Send + Sync + 'static,
30{
31    (
32        Node {
33            flex_direction: FlexDirection::Column,
34            row_gap: Val::Px(4.),
35            ..Default::default()
36        },
37        TabGroup::new(0),
38        Children::spawn(SpawnIter(keys.map(move |row| {
39            (
40                Node {
41                    flex_direction: FlexDirection::Row,
42                    column_gap: Val::Px(4.),
43                    ..Default::default()
44                },
45                Children::spawn(SpawnIter(row.into_iter().map(move |key| {
46                    (
47                        button(ButtonProps::default(), (), Spawn(Text::new(key.as_ref()))),
48                        observe(
49                            move |activate: On<Activate>,
50                                  mut commands: Commands,
51                                  query: Query<&ChildOf>|
52                                  -> Result {
53                                let virtual_keyboard =
54                                    query.get(query.get(activate.entity)?.parent())?.parent();
55                                commands.trigger(VirtualKeyPressed {
56                                    entity: virtual_keyboard,
57                                    key: key.clone(),
58                                });
59                                Ok(())
60                            },
61                        ),
62                    )
63                }))),
64            )
65        }))),
66    )
67}