1use bevy::{
4 color::palettes::css::{NAVY, WHITE},
5 feathers::{
6 controls::{VirtualKeyPressed, VirtualKeyboard},
7 dark_theme::create_dark_theme,
8 theme::UiTheme,
9 FeathersPlugins,
10 },
11 input_focus::{
12 tab_navigation::{TabGroup, TabIndex},
13 AutoFocus, InputFocus,
14 },
15 prelude::*,
16 text::{EditableText, TextCursorStyle, TextEdit},
17 ui_widgets::TextInput,
18};
19
20fn main() {
21 App::new()
22 .add_plugins((DefaultPlugins, FeathersPlugins))
23 .insert_resource(UiTheme(create_dark_theme()))
24 .add_systems(Startup, scene.spawn())
25 .run();
26}
27
28fn on_virtual_key_pressed(
29 virtual_key_pressed: On<VirtualKeyPressed<&'static str>>,
30 mut query: Query<(Entity, &mut EditableText)>,
31 mut input_focus: ResMut<InputFocus>,
32) {
33 println!("Virtual keyboard key pressed: {}", virtual_key_pressed.key);
34 let Ok((entity_id, mut text)) = query.single_mut() else {
35 return;
36 };
37 text.queue_edit(match virtual_key_pressed.key {
38 "space" => TextEdit::Insert(" ".into()),
39 "enter" => TextEdit::Insert("\n".into()),
40 "backspace" => TextEdit::Backspace,
41 "left" => TextEdit::Left(false),
42 "right" => TextEdit::Right(false),
43 "up" => TextEdit::Up(false),
44 "down" => TextEdit::Down(false),
45 "home" => TextEdit::LineStart(false),
46 "end" => TextEdit::LineEnd(false),
47 key if key.len() == 1 => TextEdit::Insert(key.into()),
48 _ => return,
49 });
50 input_focus.set(entity_id, bevy::input_focus::FocusCause::Navigated);
51}
52
53fn scene() -> impl SceneList {
54 bsn_list! {
55 Camera2d
56 --
57 @text_input()
58 --
59 @keyboard()
60 }
61}
62
63fn keyboard() -> impl Scene {
64 let keys = [
65 vec!["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", ","],
66 vec!["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
67 vec!["A", "S", "D", "F", "G", "H", "J", "K", "L", "'"],
68 vec!["Z", "X", "C", "V", "B", "N", "M", "-", "/"],
69 vec!["space", "enter", "backspace"],
70 vec!["left", "right", "up", "down", "home", "end"],
71 ];
72
73 bsn! {
74 Node {
75 width: percent(100),
76 bottom: px(0),
77 flex_direction: FlexDirection::Column,
78 position_type: PositionType::Absolute,
79 align_items: AlignItems::Center,
80 justify_content: JustifyContent::End,
81 }
82 Children [
83 Node {
84 flex_direction: FlexDirection::Column,
85 border: px(5),
86 row_gap: px(5),
87 padding: px(5),
88 align_items: AlignItems::Center,
89 margin: px(25),
90 border_radius: BorderRadius::all(px(10)),
91 }
92 BackgroundColor(NAVY)
93 BorderColor::all(Color::WHITE)
94 Children [
95 Text("virtual keyboard")
96 --
97 @VirtualKeyboard::<&str> { @keys: keys }
98 on(on_virtual_key_pressed)
99 ]
100 ]
101 }
102}
103
104fn text_input() -> impl Scene {
105 bsn! {
106 Node {
107 width: percent(100),
108 padding: px(25),
109 position_type: PositionType::Absolute,
110 align_items: AlignItems::Center,
111 justify_content: JustifyContent::Center,
112 }
113 TabGroup
114 Children [
115 Node {
116 width: percent(80),
117 border: px(5),
118 padding: px(5),
119 flex_grow: 0.0,
120 border_radius: BorderRadius::all(px(10)),
121 }
122 BorderColor::from(WHITE)
123 TextInput
124 EditableText {
125 visible_lines: { Some(5.) }
126 allow_newlines: true,
127 }
128 TextLayout::no_wrap()
129 TextCursorStyle {
130 color: WHITE
131 }
132 TextFont {
133 font_size: FontSize::Px(25.),
134 }
135 TabIndex(0)
136 AutoFocus
137 ]
138 }
139}