1use bevy::color::palettes::css::DARK_GREY;
26use bevy::color::palettes::tailwind::SLATE_300;
27use bevy::input_focus::AutoFocus;
28use bevy::input_focus::{
29 tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin},
30 InputFocus,
31};
32use bevy::prelude::*;
33use bevy::text::{EditableText, TextCursorStyle};
34
35fn main() {
36 App::new()
37 .add_plugins(DefaultPlugins)
38 .add_plugins(TabNavigationPlugin)
39 .add_systems(Startup, setup)
40 .add_systems(Update, text_submission)
41 .run();
42}
43
44#[derive(Component)]
45struct TextOutput;
46
47fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
48 commands.spawn(Camera2d);
49
50 let root = commands
51 .spawn(Node {
52 align_items: AlignItems::Center,
53 flex_direction: FlexDirection::Column,
54 padding: px(20).all(),
55 row_gap: px(16),
56 margin: auto().all(),
57 ..default()
58 })
59 .id();
60
61 let text_instructions = commands
62 .spawn((
63 Text::new("Enter to submit text\nTab to switch inputs"),
64 TextFont {
65 font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
66 font_size: FontSize::Px(25.0),
67 ..default()
68 },
69 ))
70 .id();
71
72 let text_input_left = build_input_text(&mut commands, true, 24.0);
73 let text_input_right = build_input_text(&mut commands, false, 24.0);
74
75 let input_container = commands
76 .spawn((
77 Node {
78 column_gap: px(16),
79 ..default()
80 },
81 AutoFocus,
82 TabGroup::new(0),
83 ))
84 .id();
85
86 let text_output = commands
88 .spawn((
89 Node {
90 width: px(400),
91 border: px(2).all(),
92 padding: px(8).all(),
93 ..Default::default()
94 },
95 BorderColor::from(Color::from(SLATE_300)),
96 Text::new(""),
97 TextOutput,
98 TextLayout {
99 linebreak: LineBreak::WordOrCharacter,
100 ..default()
101 },
102 TextFont {
103 font_size: FontSize::Px(24.0),
104 ..default()
105 },
106 ))
107 .id();
108
109 commands
110 .entity(input_container)
111 .add_children(&[text_input_left, text_input_right]);
112
113 commands
114 .entity(root)
115 .add_children(&[text_instructions, input_container, text_output]);
116}
117
118fn build_input_text(commands: &mut Commands, is_left: bool, font_size: f32) -> Entity {
119 commands
120 .spawn((
121 Node {
122 border: px(2).all(),
123 ..Default::default()
124 },
125 BorderColor::from(Color::from(SLATE_300)),
126 Name::new(if is_left { "Left" } else { "Right" }),
127 EditableText {
128 visible_width: Some(10.),
129 allow_newlines: false,
130 ..Default::default()
131 },
132 TextLayout::no_wrap(),
133 TextFont {
134 font_size: FontSize::Px(font_size),
135 ..default()
136 },
137 TextCursorStyle::default(),
138 TabIndex(if is_left { 0 } else { 1 }),
139 BackgroundColor(DARK_GREY.into()),
140 ))
141 .id()
142}
143
144fn text_submission(
146 input_focus: Res<InputFocus>,
147 keyboard_input: Res<ButtonInput<KeyCode>>,
148 mut text_input: Query<(&mut EditableText, &Name)>,
149 mut text_output: Single<&mut Text, With<TextOutput>>,
150) {
151 if keyboard_input.just_pressed(KeyCode::Enter)
152 && let Some(focused_entity) = input_focus.get()
153 && let Ok((mut text_input, name)) = text_input.get_mut(focused_entity)
154 {
155 text_output.0 = format!("{:}: {:}", name, text_input.value());
156
157 text_input.clear();
158 }
159}