Skip to content

Commit

Permalink
Allow value to be set
Browse files Browse the repository at this point in the history
  • Loading branch information
rparrett committed Feb 22, 2024
1 parent cb76e4c commit 81e657b
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 33 deletions.
115 changes: 115 additions & 0 deletions examples/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//! An example showing a very basic implementation.
use bevy::prelude::*;
use bevy_simple_text_input::{TextInput, TextInputBundle, TextInputPlugin};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(TextInputPlugin)
.add_systems(Startup, setup)
.add_systems(Update, (button_system, button_style_system))
.run();
}

#[derive(Component)]
struct IncValueButton;

fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());

let text_style = TextStyle {
font_size: 40.,
color: Color::rgb(0.9, 0.9, 0.9),
..default()
};

commands
.spawn(NodeBundle {
style: Style {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
column_gap: Val::Px(10.),
..default()
},
..default()
})
.with_children(|parent| {
parent.spawn((
NodeBundle {
style: Style {
width: Val::Px(200.0),
border: UiRect::all(Val::Px(5.0)),
padding: UiRect::all(Val::Px(5.0)),
..default()
},
border_color: BorderColor(Color::BLACK),
background_color: Color::RED.into(),
..default()
},
TextInputBundle::with_starting_text(text_style.clone(), "1".to_string()),
));

parent
.spawn((
ButtonBundle {
style: Style {
width: Val::Px(200.0),
border: UiRect::all(Val::Px(5.0)),
padding: UiRect::all(Val::Px(5.0)),
..default()
},
border_color: BorderColor(Color::BLACK),
background_color: Color::RED.into(),
..default()
},
IncValueButton,
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section("+", text_style.clone()));
});
});
}

fn button_system(
interaction_query: Query<&Interaction, (Changed<Interaction>, With<IncValueButton>)>,
mut text_input_query: Query<&mut TextInput>,
) {
for interaction in &interaction_query {
if !matches!(interaction, Interaction::Pressed) {
continue;
}

let mut text_input = text_input_query.single_mut();

let current_value = text_input.get_value().parse::<i32>().unwrap_or(0);

text_input.set_value(format!("{}", current_value + 1));
}
}

fn button_style_system(
mut interaction_query: Query<
(&Interaction, &mut BackgroundColor, &mut BorderColor),
(Changed<Interaction>, With<Button>),
>,
) {
for (interaction, mut color, mut border_color) in &mut interaction_query {
match *interaction {
Interaction::Pressed => {
//*color = PRESSED_BUTTON.into();
border_color.0 = Color::RED;
}
Interaction::Hovered => {
//*color = HOVERED_BUTTON.into();
border_color.0 = Color::WHITE;
}
Interaction::None => {
//*color = NORMAL_BUTTON.into();
border_color.0 = Color::BLACK;
}
}
}
}
100 changes: 67 additions & 33 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl Plugin for TextInputPlugin {
(
create,
keyboard,
update_value.after(keyboard),
blink_cursor,
show_hide_cursor,
update_style,
Expand Down Expand Up @@ -76,7 +77,10 @@ impl TextInputBundle {
pub fn with_starting_text(text_style: TextStyle, starting_text: String) -> Self {
Self {
text_style: TextInputTextStyle(text_style),
text_input: TextInput(starting_text),
text_input: TextInput {
value: starting_text,
..default()
},
..default()
}
}
Expand Down Expand Up @@ -109,7 +113,20 @@ impl Default for TextInputCursorTimer {

/// A component containing the current value of the text input.
#[derive(Component, Default, Reflect)]
pub struct TextInput(pub String);
pub struct TextInput {
cursor_position: usize,
value: String,
}
impl TextInput {
pub fn get_value(&self) -> &str {
&self.value
}

pub fn set_value(&mut self, value: String) {
self.cursor_position = value.len();
self.value = value;
}
}

#[derive(Component, Reflect)]
struct TextInputInner;
Expand Down Expand Up @@ -146,7 +163,6 @@ fn keyboard(
&mut TextInput,
&mut TextInputCursorTimer,
)>,
mut inner_text: InnerText,
mut submit_writer: EventWriter<TextInputSubmitEvent>,
) {
if events.is_empty() {
Expand All @@ -158,10 +174,6 @@ fn keyboard(
continue;
}

let Some(mut text) = inner_text.get_mut(input_entity) else {
continue;
};

let mut submitted_value = None;

for event in events.read() {
Expand All @@ -171,68 +183,90 @@ fn keyboard(

match event.key_code {
KeyCode::ArrowLeft => {
if let Some(behind) = text.sections[0].value.pop() {
text.sections[2].value.insert(0, behind);
if text_input.cursor_position > 0 {
text_input.cursor_position -= 1;

cursor_timer.should_reset = true;
continue;
}
}
KeyCode::ArrowRight => {
if !text.sections[2].value.is_empty() {
let ahead = text.sections[2].value.remove(0);
text.sections[0].value.push(ahead);
if text_input.cursor_position < text_input.value.len() {
text_input.cursor_position += 1;

cursor_timer.should_reset = true;
continue;
}
}
KeyCode::Backspace => {
text.sections[0].value.pop();
cursor_timer.should_reset = true;
continue;
if text_input.cursor_position > 0 {
let pos = text_input.cursor_position - 1;
text_input.value.remove(pos);
text_input.cursor_position -= 1;

cursor_timer.should_reset = true;
continue;
}
}
KeyCode::Delete => {
text.sections[2].value = text.sections[2].value.chars().skip(1).collect();
cursor_timer.should_reset = true;
continue;
if text_input.cursor_position < text_input.value.len() {
let pos = text_input.cursor_position;
text_input.value.remove(pos);
cursor_timer.should_reset = true;
continue;
}
}
KeyCode::Enter => {
submitted_value = Some(format!(
"{}{}",
text.sections[0].value, text.sections[2].value
));
submitted_value = Some(std::mem::take(&mut text_input.value));
text_input.cursor_position = 0;

text.sections[0].value.clear();
text.sections[2].value.clear();
continue;
}
KeyCode::Space => {
text.sections[0].value.push(' ');
let pos = text_input.cursor_position;
text_input.value.insert(pos, ' ');
text_input.cursor_position += 1;

cursor_timer.should_reset = true;
continue;
}
_ => {}
}

if let Key::Character(ref s) = event.logical_key {
text.sections[0].value.push_str(s.as_str());
let pos = text_input.cursor_position;

text_input.value.insert_str(pos, s);
text_input.cursor_position += 1;

cursor_timer.should_reset = true;
}
}

let value = format!("{}{}", text.sections[0].value, text.sections[2].value);
if !value.eq(&text_input.bypass_change_detection().0) {
text_input.0 = value;
}

if let Some(value) = submitted_value {
submit_writer.send(TextInputSubmitEvent {
entity: input_entity,
value,
});
}
}
}

fn update_value(
input_query: Query<(Entity, &TextInput), Changed<TextInput>>,
mut inner_text: InnerText,
) {
for (entity, text_input) in &input_query {
let Some(mut text) = inner_text.get_mut(entity) else {
continue;
};

let (before, after) = text_input.value.split_at(text_input.cursor_position);
text.sections[0].value = before.to_string();
text.sections[2].value = after.to_string();

// If the cursor is between two characters, use the zero-width cursor.
if text.sections[2].value.is_empty() {
if text_input.cursor_position >= text_input.value.len() {
text.sections[1].value = "}".to_string();
} else {
text.sections[1].value = "|".to_string();
Expand All @@ -253,7 +287,7 @@ fn create(
sections: vec![
// Pre-cursor
TextSection {
value: text_input.0.clone(),
value: text_input.value.clone(),
style: style.0.clone(),
},
// cursor
Expand Down

0 comments on commit 81e657b

Please sign in to comment.