Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple single line text field #69

Draft
wants to merge 96 commits into
base: main
Choose a base branch
from
Draft

Conversation

rewin123
Copy link
Contributor

@rewin123 rewin123 commented Oct 6, 2024

ezgif-3-439f7a0e30
ezgif-3-4375ce2186
ezgif-5-37c39e79e5

Motivation

Currently,
we don't have any widget that allows editing text or component values. So I decided to create a simple version of such a field.

Proposal

I created two components

LineTextField

  • Single-line text editing
  • Cursor positioning and text selection
  • Clipboard operations (copy, cut, paste, select all | Ctrl-C,X,V,A)
  • Support for text longer than field width
  • Customizable allowed characters

NumericField

  • Supports multiple numeric types (u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64)
  • Text-based input for precise value entry
  • Mouse drag functionality for quick value adjustments
  • Configurable min/max value constraints
  • Customizable drag step (drag step can be less then 1 val per logical pixel)

And three crates

bevy_focus

This crate contains input focus managment

bevy_text_field

This crate contains text field logic. Builded on top of bevy_focus.

bevy_numeric_field

This crate builded on top of bevy_text_field and contains logic for NumericField

Usage

// LineTextField
commands.spawn((
    NodeBundle { /* ... */ },
    LineTextField::new("Initial text"),
)).observ(|trigger: Trigger<TextChanged>| {
  let text  = trigger.event().0; //Do whatever with text
});

// Update text
let mut text_field = LineTextField::default();
text_field.set_text("bla bla bla");

// NumericField
commands.spawn((
    NodeBundle { /* ... */ },
    NumericField::<f32>::new(0.0),
)).observe(|trigger: Trigger<NewValue<f32>>| {
    let new_value = trigger.event().0;
    // Handle value change
});

// Update number
// We must use trigger because its contains complex logic for updating
commands.trigger_targets(SetValue(0.0), translation_x);

Testing

I created three examples for manual testing:

  1. single_line_text_field.rs - contains three size different single line text fields
  2. many_fields - contains all supported numeric fields
  3. transform.rs - contains mvp for changing transform with new numeric fields
  4. NumericField uses LineTextField in this work

The following features are not planned for this PR

  • Multi-line editing
  • Precise cursor positioning by clicking on the text field with the mouse

Followed work

  • Move to i-cant-belive-this-is-not-bsn crate
  • Move to Required components
  • Create new SerializedField component, which allow to use LineTextField for any strut that support serialize/deserialize
  • Create design for split huge LineTextField to nice sub components, which will allow to huge customization of this text field
  • Unhardcode key bindings for copy/paste/cut
  • Change cursor from byte position into char number position for more safety for non-english text
  • Found a way to avoid invisible text nodes and text splitting

@viridia
Copy link

viridia commented Oct 6, 2024

Rather than have specific types for int and float, I would prefer a way to have a validator.

I had at one point started to build a text input field for quill and bevy_reactor, but this got put on hold due to the cosmic-text rework. However, my plan was to architect this just like form fields are done on the web: when the user types a key, the input field emits an "on_change" event, which bubbles up the hierarchy. The listener can inspect the text and decide if it's valid, if not it takes steps such as canceling the edit or showing an error message or whatever.

This lets you do things like have validation rules for email addresses, phone numbers, passwords, and so on.

As far as dragging goes, I would rather that be something that the third-party widget library adds on top of the basic text widget, by installing the appropriate observers. I don't think it should be built-in.

In the web world, there are many, many different widget toolkits competing against each other, and I think this is healthy. I want to see different third-party widget libraries in the Bevy ecosystem, and I think that these libraries need to have the freedom to customize their interaction behavior. Bevy should handle the gnarly stuff like calculating selection rectangles for BiDi text and handling non-English input methods, and provide a platform for experimentation into different kinds of interaction and presentation.

@rewin123
Copy link
Contributor Author

rewin123 commented Oct 6, 2024

Yes, the approach with validators is indeed a good one. I'm actually planning to experiment with it, limiting myself to three options: text without validation, text with float, and text with int. I'm considering using two traits: SerializableValue and DraggableValue, within which I'll separate the logic for int and float on top of the text field.

However, I'm not quite clear on the second part of the comment. I'm curious about how the multitude of existing UI libraries relates to the editor prototype. The goals of this repository state that we're not using third-party UIs, only bevy_ui. My intention is to create a widget for the editor prototype that could be used right now, rather than waiting for Bevy to improve its UI capabilities. (In any case, there will be several iterations of improvements for both text fields and reactivity in general, but I would like to avoid overengineering the solution before we have even completed the first step of the editor prototype.)

@rewin123 rewin123 changed the title Single line text field Simple single line text field Oct 6, 2024
@viridia
Copy link

viridia commented Oct 6, 2024

I'm assuming that the editable text field is going to be used for something besides editors.

Lots of games need text input:

  • name your character
  • name this saved game
  • type your username and password to log in to the network.

A simple single-line text editing widget would be very useful for all of these. But it should be flexible enough to work with games that have their own distinct visual style.

Alternatively, instead of providing a text-edit widget, we could provide an API (exposing the cosmic-edit methods) to let people build their own edit widgets.

@rewin123
Copy link
Contributor Author

rewin123 commented Oct 6, 2024

It's true that a text field builder would be very useful. But such a constructor should be in bevy_ui crate. This is outside the scope of the current repository

@alice-i-cecile
Copy link
Member

Yep, I'm fine with a very simple design to start.

@n1ght-hunter
Copy link
Contributor

one other thing i think would be really useful to add is ctrl + a for full text select

@JeanMertz
Copy link

JeanMertz commented Nov 8, 2024

edit: Sorry, GitHub had pushed many recent comments into "see 53 more lines", which, I assumed, would only be commits, but it also hides relevant discussions. Please ignore my comment if this has been discussed earlier.

I love the work being done here.

I do want to point out that a +4300 lines PR for "simple single line text field" seems excessive. Looking at the code, I see (f.e.) bevy_incomplete_bsn as a new crate.

Would it make more sense to split those up into separate PRs, to unblock less controversial (or less complex) code that fits well as a single (utility) crate?

@rewin123
Copy link
Contributor Author

rewin123 commented Nov 8, 2024

edit: Sorry, GitHub had pushed many recent comments into "see 53 more lines", which, I assumed, would only be commits, but it also hides relevant discussions. Please ignore my comment if this has been discussed earlier.

I love the work being done here.

I do want to point out that a +4300 lines PR for "simple single line text field" seems excessive. Looking at the code, I see (f.e.) bevy_incomplete_bsn as a new crate.

Would it make more sense to split those up into separate PRs, to unblock less controversial (or less complex) code that fits well as a single (utility) crate?

The bevy_incomplete_bsn will be cut from this PR when it is ready. In this case, I'm using it to stress test a text field. Unfortunately, the stresstesting found two bugs that need to be fixed. Unfortunately in 1.5 weeks I never got to sit down to fix them due to increased work load. I hope to be able to do it next week and prepare two PRs - this one and the “component inspector” pane.

@rewin123
Copy link
Contributor Author

I deeply apologize for disappearing. Preparation for my PhD defense consumed all my free time last month. On the other hand, I successfully defended my PhD last week, so starting today I'm returning to finish this PR. (If it's still relevant).

@BUGO07
Copy link
Contributor

BUGO07 commented Dec 11, 2024

Congrats, and about the project - it is relevant, I really like at the point it is rn, and I'm sure it will be better. You will have some work to do though, theres been a lot of changes with the editor

@rewin123
Copy link
Contributor Author

Finally found a bug and everything works almost as intended. It remains only to understand why sometimes at startup the text field is not filled with the value of the component and I will prepare a PR for review

image

@alice-i-cecile
Copy link
Member

FYI, we've merged InputFocus upstream. Could you use that here to avoid duplication and help us find problems with it?

@rewin123
Copy link
Contributor Author

FYI, we've merged InputFocus upstream. Could you use that here to avoid duplication and help us find problems with it?

Awesome. I will try to use it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Widgets Various primitive UI widgets C-Feature Make something new possible S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants