Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ui/text/text_input.rs
30635 views
1
//! Demonstrates a simple, unstyled [`EditableText`] widget.
2
//!
3
//! [`EditableText`] is a basic primitive for text input in Bevy UI.
4
//! In most cases, this should be combined with other entities to create a compound widget
5
//! that includes e.g. a background, border, and text label.
6
//!
7
//! Note that while Bevy does offer clipboard support, access to the system clipboard is gated
8
//! behind an off-by-default feature (`system_clipboard` on `bevy_clipboard`).
9
//! When this is disabled, clipboard operations (copy, cut, paste) will operate on a simple in-memory buffer
10
//! that is not shared with the operating system.
11
//! This means that, unless you enable this feature,
12
//! you will not be able to copy text from your application and paste it into another application, or vice versa.
13
//!
14
//! Most applications that use text input will want to enable system clipboard support to meet user expectations for copy/paste behavior.
15
//! It is off by default to avoid forcing clipboard permissions on applications that do not need it but wish to use Bevy's UI solution for other widgets,
16
//! and to avoid including the `arboard` dependency on platforms where it is not supported or where clipboard access is not desired.
17
//! While desktop platforms generally support clipboard access without special permissions, some platforms (notably web and mobile)
18
//! may require additional permissions or user gestures to allow clipboard access;
19
//! this approach allows developers to opt in to full clipboard support only when they genuinely need it.
20
//!
21
//! To test this example using the system feature, run `cargo run --example text_input --features="system_clipboard"`.
22
//! To enable this feature in your own project, add the `system_clipboard` feature to your list of enabled features for `bevy` in your `Cargo.toml`.
23
//!
24
//! See the module documentation for [`editable_text`](bevy::ui_widgets::editable_text) for more details.
25
use bevy::color::palettes::css::DARK_GREY;
26
use bevy::color::palettes::tailwind::SLATE_300;
27
use bevy::input_focus::AutoFocus;
28
use bevy::input_focus::{
29
tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin},
30
InputFocus,
31
};
32
use bevy::prelude::*;
33
use bevy::text::{EditableText, TextCursorStyle};
34
35
fn 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)]
45
struct TextOutput;
46
47
fn 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
// Set up a text output to see the result of our text input
87
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
118
fn 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
144
// Submit the text when Ctrl+Enter is pressed
145
fn 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
}
160
161