Commit Graph

36 Commits

Author SHA1 Message Date
ickshonpe 736d2b0a9e multiline_text_input example pop up justify menu (#24584)
# Objective

Add a way to change the justification for the text input in the
multiline_text_input example.

## Solution

Add a pop up menu that lets you set justify.
2026-06-11 03:36:18 +00:00
ickshonpe e52d2c5c53 Justify the inputs in the multiple_text_inputs example (#24583)
# Objective

Make the `multiple_text_inputs` example a bit more useful by giving each
text input a different justification, which should help with debugging
cursor behaviour.

## Solution

Add an input for each `Justify` variant along with a column on the left
labelling the justification it is using.

## Showcase

<img width="1798" height="750" alt="inputs-justified"
src="https://github.com/user-attachments/assets/324c1cd4-b6a1-4c0f-ad1a-38cd28867704"
/>
2026-06-10 17:57:58 +00:00
Jay f7f50d1a75 Fix IME text input wrapping (#23932) (#24421)
The IME support example configures its editable text field as a
single visible input, but the text layout still used default soft
wrapping. When the cursor moved through long text, wrapped visual lines
could appear as disconnected text segments.

Set the example input to use `TextLayout::no_wrap()`, matching the
other single-line text input examples while still allowing explicit
newlines.

Fixes https://github.com/bevyengine/bevy/issues/23932.

```sh
cargo check --example ime_support --features system_font_discovery
```
2026-06-06 18:29:22 +00:00
ickshonpe 457b91808a More consistant Font asset resolution and change detection (#24362)
# Objective

- When `FontSource` resolution fails because an asset isn't yet loaded,
it doesn't attempt to reresolve the `FontSource` again the next frame.
- When a `Font` asset is removed, its font data is not unloaded from
Parley's font database
- The results from font lookups can be inconsistant when using `Handle`s
to identify a font.

Fixes #24356

## Solution

* In `load_font_assets_into_font_collection`, register each font twice,
once with an internal asset-specific alias for handle lookups and once
using its embedded family name.
* Use `set_changed` on `TextFont` to trigger chain detection, instead of
the `needs_rerender` flag on `TextBlock`. Schedule
`load_font_assets_into_collection` to run before
`detect_text_needs_rerender`, otherwise this would delay updates for a
frame.
* Store the changed family ids and asset paths, and set any `TextFont`s
that refer to them as changed.
* Don't update the measure funcs in `update_editable_text_content_size`
on font asset changes. Instead rely on the narrower `TextFont` change
detection, which is sufficient now because
`load_font_assets_into_font_collection` marks affected `TextFont`
components as changed when newly loaded font assets can affect font
resolution.
* Removed the mutable deref of `EditableText` at the start of
`update_editable_text_styles`. The editor is only mutable accessed if
updates to the styles need to be made.
* On unloading a font rebuild the whole font database, minus the
unloaded fonts, remap any generic families and relayout all text.
* Keep a copy of the registered generic families in `FontCx`, so they
can be remapped after unloading a font.

## Testing

```rust
use bevy::{
    feathers::{controls::FeathersNumberInput, FeathersPlugins},
    prelude::*,
};

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, FeathersPlugins))
        .add_systems(Startup, setup)
        .add_systems(Update, spawn_number_input)
        .run();
}

fn setup(mut commands: Commands) {
    // ui camera
    commands.spawn(Camera2d);
}

fn spawn_number_input(mut commands: Commands, mut is_spawned: Local<bool>) {
    if *is_spawned {
        return;
    }
    *is_spawned = true;
    commands.spawn_scene(bsn! {
        Node {
            margin: UiRect::all(auto())
        }
        Outline
        Children [
        :FeathersNumberInput Node { width: px(200) }
        ]
    });
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-06-04 04:55:04 +00:00
ickshonpe dbfa384182 Only select all on input focus with SelectAllOnFocus (#24278)
# Objective

Only select all on focus with `SelectAllOnFocus`. 
It should be possible to have single line inputs without automatic
select all on focus.

## Solution

Remove the automatic select all on focus for single line inputs from
`on_focus_select_all`.
2026-05-22 10:40:46 +00:00
ickshonpe a382a230a2 multiple_text_input example layout fixes (#24294)
# Objective

These are meant to be single line inputs, but:

<img width="1552" height="954" alt="image"
src="https://github.com/user-attachments/assets/5e7ab2c7-9bb2-46cd-9a42-bca36b933837"
/>

A mess!

## Solution

1. Add `TextLayout::no_wrap()` to each input and their outputs.
2. Add an intermediate node wrapping each output node applying clipping
to hide the overflow.

<img width="1608" height="489" alt="fixed-inputs"
src="https://github.com/user-attachments/assets/22dc436c-e677-4b1f-a569-d3a9c9effc1c"
/>

## Testing

```
cargo run --example multiple_text_inputs  --features="system_clipboard"
```
2026-05-21 10:16:40 +00:00
ickshonpe 7500b6c5aa text_input example clean up (#24297)
# Objective

Clean up the `text_input` example a bit.

## Solution

- Removed some unneeded style constraints.
- Disable newlines, disable wrapping, and set a responsive width for the
inputs.
- Submit on Enter, not Ctrl + Enter.
- Center the example using an auto margin.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-05-21 10:16:23 +00:00
ickshonpe 7af4723083 ime_support example clean up (#24296)
# Objective

Little bit of clean up for the `ime_support` example.

## Solution

* Use `row_gap` on the parent for spacing instead of setting individual
margins on the children.
* Give the text input node a fixed height and allow newlines.

## Testing

```
cargo run --example ime_support --features="system_font_discovery"
```
2026-05-21 10:13:03 +00:00
ickshonpe 10db67e459 multiple_text_inputs example: Navigate to next input on submission (#24295)
# Objective

In the `multiple_text_inputs` example, the input focus should move to
the next text input after the user submits the input's contents.

## Solution

- In `submit_text`, after submission, use the `TabNavigation` system
param to find the next input, and set it as the `InputFocus`.
- Submit on just `Enter`. The `Ctrl` + `Enter` chord should be reserved
for inputs that allow new lines.
2026-05-21 09:26:17 +00:00
ickshonpe bf9a118c46 text input selection radius (#24307)
# Objective

Allow rounded corners for text input selection regions.

Fixes #23952

## Solution

* Added a `selection_radius` field to `TextCursorStyle`, defaults to
`0.`.
* In `extract_text_cursor` set a corner radius for each selection rect,
after clamping for short and inner corners.

---

Left rounded inner corners for a follow up, as they are significantly
more complicated to implement.

## Testing

Added an option to set the selection radius to the
`multiline_text_input` example:

```
cargo run --example multiline_text_input --features="system_clipboard"
```

<img width="400" alt="image"
src="https://github.com/user-attachments/assets/a10bb552-ac03-4e06-a287-53c57e5c2f45"
/>

## Showcase

<img width="400" alt="rounded"
src="https://github.com/user-attachments/assets/79d59c66-7fb0-4ad4-8a17-308c755c1f23"
/>
<img width="400" alt="r2"
src="https://github.com/user-attachments/assets/a3dfd8a6-f85f-4534-ba61-4a8c74e9793d"
/>
<img width="400" alt="r3"
src="https://github.com/user-attachments/assets/78e4d863-198e-4ee0-ad33-22e7cde7016a"
/>
2026-05-21 08:24:38 +00:00
Lennard d2481ccf60 Add OpenType font variations (#24088)
# Objective
Bevy currently supports OpenType `FontFeatures`, but it doesn't support
`FontVariations`, although `parley` has support for them.

Font features are mainly on/off values to vary the font (`u32`), while
font variations are a continuous range of values that can be set to vary
the font (`f32`).

I personally need it for setting `FILL` on the material design icon
font.

## Solution
I implemented `FontVariations` as a separate struct from `FontFeatures`
for now and copied it's api.

However, since both are so similar it's worth considering to merge them
into something like a `FontVariables` with a builder that has
`set_feature` and `set_variation` methods.

## Testing
Added a new example demonstrating how to set the font weight using
`FontVariations` instead of `FontWeight`.

(Setting font weight using `FontFeatures` does not work, although the
documentation suggests it should. I'm not sure if this depends on the
variable font used or whether this is an error in the documentation.)

## Showcase

<img width="946" height="541" alt="Screenshot 2026-05-02 225528"
src="https://github.com/user-attachments/assets/9067191b-8517-4fec-9283-45e57180658a"
/>

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2026-05-08 13:29:06 +00:00
ickshonpe 211b9ab63f EditableText scrolling and cursor fixes (#24032)
# Objective

Fix some scrolling jitters and bugs.
* The cursor can be scrolled out of view.
* Horizontal scrolling is jittery with a cursor taller then the line
height.
* Vertical scrolling jitters.
* Scrolling and cursor state should only update on changes to the editor
state and input focus (this is needed so scroll bars will work with a
text input).

Fixes #23931

## Solution

* Use the full cursor width when calculating the horizontal scroll
offset.
* Base vertical offsets on the bounds of the current visual line, not
the cursor.
* Update scrolling on `InputFocus` changes.
* `TextLayoutInfo` always holds the cursor geometry (if there is a
cursor), made the field a `(bool, Rect)` tuple, the bool is true if the
cursor should be rendered.
* Lots of clamping, logic behind it mostly trial and error tbh. 

This should fix the major scrolling bugs, scrolling should feel
consistant and intuitive now.
Left look-ahead scrolling
https://github.com/bevyengine/bevy/issues/23933 left for a follow up,
after this is merged.

## Testing

```
cargo run --example multiple_text_inputs
cargo run --example multiline_text_input
cargo run --example ime_support --features="system_font_discovery"
```

With `ime_support` and `multiline_text_input`, you probably want to set
`TextLayout::new_with_no_wrap()` on the inputs to fully appreciate the
changes.
2026-05-03 23:55:52 +00:00
ickshonpe b00ff93c87 Remove new_with_ prefix from the TextLayout constuctor functions (#24049)
# Objective

Remove the `new_with_` prefixes from the `TextLayout` constuctor
functions. Generally, the "new" part is redundant and "with" is used by
fluent APIs.

## Solution

Just delete the prefixes, shorten the names (all on `TextLayout`).
* `new_with_justify` -> `justify`
* `new_with_linebreak` -> `linebreak`
* `new_with_no_wrap` -> `no_wrap`
2026-05-01 21:08:18 +00:00
ickshonpe 68c4223091 multi-click support (#24023)
# Objective

Implement minimal multi-click support.
Add double click to select word and triple click to select all support
to text input widgets.

Fixes #23874

## Solution

New `MULTI_CLICK_DURATION` constant that sets the max time between
clicks for them to count as consecutive.

Added a field `count` to `Click`. 1 is a single click, 2 is a double
click, 3 is a triple click and so on. It's a `u8` and saturates at 255
if you click that many times.

Current multi-click state is stored in a field `clicking` on
`PointerButtonState`.
The `clicking` state is cleared after `MULTI_CLICK_DURATION` without
another click.

New `SelectWordAtPoint` `TextEdit`.

New observer system `on_pointer_click` in `bevy_ui_widgets::text_input`.
This queues `SelectWordAtPoint` for 2 clicks and `SelectAll` for 3 or
more. `Click` events are dispatched on release, so they happen after
`Press`. The `Press` for a double click might move the cursor but that
doesn't affect the `SelectWordAtPoint` edit that is dispatched.

#

The implementation is deliberately minimal, I just added here what was
needed for the text input. Left for followups:
- Tracking the initial click position and returning the displacement
with `Click`.
- Spatial tolerance (clicks are only multi-clicks if the pointer hasn't
moved too far).
- Configurable multi-click duration.

We could add a separate `MultiClick` event instead. It seems to me
things would be more complicated with both `Click` and `MultiClick`
observer systems though.

## Testing

Text inputs now support double click to select a word and triple click
to select all:

```
cargo run --example multiline_text_input
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Talin <viridia@gmail.com>
2026-04-29 15:59:37 +00:00
Alice Cecile 90b41543e2 Improve default colors for text_input widgets (#23960)
# Objective

- Text input is one of the headline feature in Bevy 0.19.
- Our defaults are currently very ugly, and shown across our user-facing
text examples.
- Good default matter for user perception of quality, and to make quick
prototyping easier.
- Additionally, the layout in the text_input example is erratic in a way
that looks poorly made.

Fixes #23955.

## Solution

1. Clean up the default colors for text input by picking boring,
uncontroversial tailwind colors.
2. Change the css::YELLOW borders in our text input examples to
something neutral that looks nice with our background.
3. Fix up the layout for the `text_input` example so it's both simpler
and looks much better.

## Testing

`cargo run --example text_input`

## Showcase

Before:

<img width="873" height="773" alt="image"
src="https://github.com/user-attachments/assets/bcc70bf6-e6b1-4bf4-b671-7924ac24e984"
/>

After:

<img width="757" height="274" alt="image"
src="https://github.com/user-attachments/assets/e1a3e325-b3a7-4a9b-831e-6886e6a818fc"
/>
2026-04-24 05:21:39 +00:00
ickshonpe 41f170c0a3 Basic clipboard support (#19106)
# Objective

Add a platform-agnostic interface for interacting with the clipboard.

## Solution

New crate `bevy_clipboard` with a `ClipboardPlugin` that adds a
`Clipboard` resource. The clipboard is accessed using the methods
`fetch_text`, `fetch_image`, `set_text` and `set_image` on the
`Clipboard` resource. `fetch_text` returns a `ClipboardRead` with a
`poll_result` method that's used to get the actual value once it's
ready.

The `windows` and `unix` implementations both use the `arboard` crate.
On windows the `Clipboard` resource is a unit struct and a new arboard
clipboard instance is created and dropped for each clipboard access. On
unix targets the `Clipboard` resource holds a clipboard instance it
reuses each time. On both targets the `fetch_*` and `set_*` methods work
instantly.

On `wasm32` `Clipboard` is a unit struct. The `fetch_text` and
`set_text` functions spawn async tasks. The task spawned by `fetch_text`
updates the shared arc mutex option once the future is evaluated to get
the clipboard text. There is no image support on `wasm32`.

Everything seems to work but it feels like the design is a bit clumsy
and not very idiomatic. I don't tend to do much asynchronous
programming, maybe a reviewer can suggest an improved construction.

I also added an alternative `fetch_text_async` function for async access
that returns a `Result<String, ClipboardError>` future.

### Notes
* Doesn't support android targets yet. 
* The wasm32 implementation doesn't support images. It's much more
complicated and probably best to left to a follow up.

## Testing

The PR includes a basic example `clipboard` that can be used for
testing.
The image display will only work if the image is already in the
clipboard before the example starts.

---------

Co-authored-by: Gilles Henaux <ghx_github_priv@fastmail.com>
Co-authored-by: Andrew Zhurov <zhurov.andrew@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-04-23 21:18:07 +00:00
Alice Cecile 61042b10f0 IME support for text input (#23841)
# Objective

IME support during text input is extremely important for non-Latin
languages: notably the CJK family (Chinese, Japanese, Korean). It would
be very nice to support it in our initial release!

Fixes #23795.

## Solution

1. Peek at the `input/text_input` example that @mockersf made and I
forgot about.
2. Steal its strategy and wire up the IME events to Bevy's proper text
input widgets.
3. Delete the now-obsolete example.
4. Add underlines to tentative characters (exposed by parley :D) so then
users can distinguish what they're typing from what they have typed.
5. Rename `editable_text` to the nicer `text_input`.
6. Create a dedicated example for `ime_support`, which uses system
fonts.
7. Add an `error_once!` to fix a footgun I tripped on when using system
fonts...

Per @mockersf's complaints, I've opted not to ship any new fonts in this
PR: the system fonts actually worked great!

## Testing

I've setup IME support on Windows, and added a small font with Japanese
support to the `editable_text` example.

It works quite well! We can even submit the values!

Known issues:

- when entering Japanese characters, the console is spammed with "ICU4X
data error: No segmentation model found for language: ja". I have no
idea where this is coming from: I think a system dependency is causing
this, and it's bubbled up by `parley`? IDK. Doesn't happen with Latin
characters, and it renders fine so...
-~~tab selecting the IME suggestion causes the selected text entry box
to change. I wasn't sure how we want to fix that, so Ieft it for now.~~
EDIT: fixed!

## Showcase

<img width="470" height="233" alt="image"
src="https://github.com/user-attachments/assets/8f8721b3-6746-46d5-8a20-40de634f52e5"
/>

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-04-21 04:47:51 +00:00
ickshonpe 8b8a432ab4 EditableText change detection using parley::Generation (#23785)
# Objective

Improved change detection for `EditableText`.

Fixes #23793

## Solution

* Remove the `text_edited` field from `EditableText` that was used for
manual change detection.
* Use the `PlainEditor`'s `Generation` to track changes.
* New component `EditableTextGeneration`. Newtypes `parley::Generation`.
Stores the generation from the last `TextLayoutInfo` update.
* If `EditableText::editor`'s and `EditableTextGeneration`'s generation
values aren't equal, reupdate `TextLayoutInfo`.
* Added support for `TextLayout::justify`.
* Split up `editable_text_system` into two systems
`update_editable_text_styles` and `update_editable_text_layout`. The
text input's style values need to be updated before layout, so the
measure func returns the correct size for the text layout.
* New `EditableText` `testbed_ui` scene.
* Added two numeric inputs to `multiline_text_input` that allow you to
set the height of the multiline input and its fontsize.
* Update selection rects on all changes, not just when a text input is
focused.

## Testing

```
cargo run --example multiline_text_input
```

The cursor appears to be missing for the numeric inputs in the example
but it isn't. The cursor gets clipped because it's at the end of the
right aligned input value text. If you press left it comes into view.
Cursor and scrolling behaviour needs some adjustments but that's out of
the scope of this PR.
2026-04-19 18:38:47 +00:00
ickshonpe 5eed63e924 Per character filter for TextEdits (#23704)
# Objective

Add an option to reject `TextEdit`s based on a per character filter.

## Solution

* New component: `EditableTextFilter`. Can be used to set a per
character filter for an `EditableText` entity.
* `TextEdit::insert` and `TextEdit::Paste` edits are ignored unless all
their characters pass the filter.

The filter does not apply to characters already within the
`EditableText`'s text buffer

Initially I thought it would be better to implement the filter at the
widget level, then a key press that results in a rejected edit could be
propagated, but the clipboard isn't available to the keyboard observer
function so paste edits would still need to be filtered when the input
buffer is applied.

I made a branch adding a `TextEditRejected` entity event as an
alternative (that would also notify when an edit failed due to the
`max_characters` limit being exceeded), but left it out of this PR to
keep this one focused on just the filtering.

## Testing

New example:  
```
cargo run --example editable_text_filter
```
2026-04-12 20:45:30 +00:00
ickshonpe b83d130bd7 EditableText::new method to set initial text (#23702)
# Objective

It should be simple to set an initial value for `EditableText`'s text
buffer.

Otherwise I can see users struggling with this and using some ghastly
construction like a run once system in `Update` to set initial text.

## Solution

New `EditableText::new` method. The value of the text buffer is set
immediately and a `TextEdit::TextEnd(false)` edit is queued to move the
cursor to the end of the text.


## Testing

Added some initial text to the multiple text example:

```
cargo run --example multiple_text_inputs
```
2026-04-12 20:43:22 +00:00
ickshonpe 1aa3396863 Text editing selection box rendering fix (#23679)
# Objective

`EditableText`'s selection rects are currently drawn on top of the text.
Instead they should be drawn below with an option to draw the selected
text in an alternative color.

## Solution

* New field on `selected_text_color: Option<Color>` on
`TextCursorStyle`.
* In `extract_text_sections`, if `selected_text_color` is `Some` and the
glyph is inside a selection rect, use `selected_text_color` to draw the
glyph.
* The z offset for text selection rects is changed so the selection
rects are drawn behind the glyphs.

## Testing

```
cargo run --example multiline_text_input
```

---------

Co-authored-by: Daniel Skates <zeophlite@gmail.com>
2026-04-06 23:40:31 +00:00
ickshonpe 28f99e9618 Minimal editable text scrolling implementation (#23646)
# Objective

Add basic support for scrolling text horizontally and vertically to
EditableText.

## Solution

* New component `TextScroll`. Wraps a Vec2 offset that can be used to
set the scroll position.
* Clip overflowing editable text content automatically.
* New system `scroll_editable_text` sets `TextScroll` to keep the cursor
within view inside the `EditableText`'s content box.
* New `allow_newline` flag on `EditableText`. Allows insertion of
newlines with the enter key.
* `editable_text_system` previously ignored `TextLayout::linebreak`. Now
it's possible to change the line break settings.
* Scrolling only happens after a `TextEdit` is applied.

The implementation here is extremely simple but it has some flaws:
* Depending on the width of the node sometimes the cursor can get
clipped.
* `allow_newlines: false` doesn't block pasting in a section of text
with a newline
* No support for scroll margins yet.
* Drag-to-scroll seems to work, but I'm not super confident in it and it
may need some changes.

Went back and forth over whether `ScrollPosition` should be used instead
of a dedicated component, I think it's probably simpler with
`TextScroll` but not certain. Clipping doesn't use `Node`'s overflow API
and is handled automatically during extraction, always targeting the
content box.

## Testing

```
cargo run --example multiline_text_input
```
2026-04-05 10:24:03 +00:00
François Mockers fb2d3c29bd fix editable_text example after new text plugins added to DefaultPlugins (#23664)
# Objective

- Example `editable_text` crashes because of duplicated plugins

## Solution

- Remove the duplicated plugins

## Testing

- `cargo run -example editable_text`
2026-04-05 01:27:21 +00:00
Luke Yoo 09ef09eaa5 UiWidgetsPlugins and InputDispatchPlugin are now in DefaultPlugins (#23346)
# Objective

-
[Overview](https://hackmd.io/@UrWywBGGTV6bLjORZhuuPw/BJNPlNCu-g#Overview)
- `UiWidgetsPlugins` is part of `DefaultPlugins`
- Prerequisite for [Remove `Interaction` from
`examples/*`](https://github.com/bevyengine/bevy/pull/23285)

## Solution

- `UIWidgetsPlugins` adds `InputDispatchPlugin`.
- `UIWidgetsPlugins` and `InputDispatchPlugin` are removed from
`FeathersPlugins`.
- `UIWidgetsPlugins` slips into `DefaultPlugins`.

## Testing

Following examples are relevant:
- examples/ui/widgets/feathers.rs
- examples/games/game_menu.rs

## Also

[Migration
Guide](https://github.com/micttyoid/bevy/blob/ui-widgets-to-default-2/_release-content/migration-guides/ui_widgets_plugins_and_input_dispatch_plugin_are_now_default.md)
- Also: e7bab9fb83

[TODO after merge](#issuecomment-4057934697)

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-04-02 18:46:41 +00:00
ickshonpe 7dcc2244a9 New multiple_text_inputs example. (#23579)
# Objective

Add another text input example

## Solution

Grid layout with three rows of input, immediate updated copy of its
text, and submitted text.
2026-03-31 16:14:14 +00:00
ickshonpe 4bbd37d4b0 editable_text example cleanup (#23580)
# Objective

A few minor changes for the `editable_text` example.

## Solution

* Use `px` and `Val2::px` helpers.
* No need to clone the `SplitString` from `EditableText::value`.
2026-03-30 21:20:02 +00:00
ickshonpe f62d53dbca Bordered and padded content (#23510)
# Objective

Allow borders and padding on text and images.

Fixes #17300, #14498, #14789, #11557, #6879

## Solution

Remove filter for border values on content sized nodes.
Apply content offsets to content in rendering and picking.

## Testing

```
cargo run --example testbed_ui -- boxedcontent
```

```
cargo run --example image_node
```

```
cargo run --example editable_text
```

```
cargo run --example text_background_colors
```

## Showcase

<img width="1924" height="1127" alt="Screenshot 2026-03-25 113700"
src="https://github.com/user-attachments/assets/68be286b-ca0e-46c7-9295-973df77412e9"
/>

<img width="223" height="223" alt="birdd"
src="https://github.com/user-attachments/assets/e9f6e393-7ee9-498b-85d0-318abd702448"
/>
2026-03-25 17:13:34 +00:00
ickshonpe c235fc1ef4 EditableText max characters limit (#23496)
# Objective

Add a max characters limit to `EditableText`

## Solution

- New field `max_characters: Option<usize>` on `EditableText`.
- Queued `TextEdit`s that would cause the text to exceed
`max_characters` (if some) are ignored.

## Testing

```
cargo run --example editable_text
```

The right input's max character limit is set to 7.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-24 21:32:43 +00:00
ickshonpe baa6a1498d EditableText: intrinsic height (#23494)
# Objective

Add support to set a text input’s height based on a given number of
visible lines.

## Solution

- Added a `visible_lines: Option<f32>` field to `EditableText`. 
- New system `update_editable_text_content_size` that runs in
`UiSystems::Content.

If `visible_lines` is `Some`, `UiSystems::Content` sets a `ContentSize`
that determines the node's height as `line_height * visible_lines`,
using the resolved font line height.

## Testing

Updated the example:
```
cargo run --example editable_text
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-03-24 19:39:25 +00:00
Daniel Skates 2de8711a40 Minimal unstyled Text Input with Parley (#23282)
# Objective

- Minimal unstyled Text Input, using Parley,
https://github.com/bevyengine/bevy/issues/23014

## Solution

- Initial work based off of @alice-i-cecile
[parley-text-input](https://github.com/bevyengine/bevy/compare/main...alice-i-cecile:bevy:parley-text-input)
and @ickshonpe 's
[text-editing](https://github.com/bevyengine/bevy/compare/main...ickshonpe:bevy:text-editing)
and
[parley-input](https://github.com/bevyengine/bevy/compare/main...ickshonpe:bevy:parley-input)
branches
- `EditableText` component wraps a `parley::PlainEditor`
- Edits to the text are made via a queue of `TextEdit` items
- We use the `PlainEditor` for layout, and render from there

Relevant schedules are:
- `PreUpdate`, `bevy_ui_widgets::process_text_inputs`
- `PostUpdate`, `bevy_text::apply_text_edits`
- `PostUpdate`, `bevy_ui::editable_text_system`

And in `render_app`:
- `ExtractSchedule`, `bevy_ui_render::extract_text_editable`
- `ExtractSchedule`, `bevy_ui_render::extract_text_cursor`

## Testing

- `cargo run --example editable_text`

---

## Showcase

![text-input-wip4](https://github.com/user-attachments/assets/8f19c539-c076-4374-b4fc-5df18c07b3e8)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-03-21 21:22:42 +00:00
gregcsokas 71cfd3ec01 Support letter spacing in bevy_text (#23380)
# Objective

- Implements the `LetterSpacing` feature from issue #8781, the
`LineHeight` is already implemented.

## Solution

Connects Bevy's text pipeline to `parley`'s built-in letter spacing
support,
mirroring the approach used for `LineHeight`.
`Rem` and percentage-based sizing are not yet implemented.

## Testing

- Added a `letter_spacing` example that visually validates the feature.
- Fixed AABB-related tests for `text2d`.
- Reviewers can run: `cargo run --example letter_spacing`
- Works like `LineHeight`, but currently only supports `Px()`.
- Note: letter spacing is currently a required field —
  open to making it optional if that's preferred.

## Showcase

`cargo run --example letter_spacing`


Or here is a video about it:


[Kooha-2026-03-16-10-14-23.webm](https://github.com/user-attachments/assets/3d778bd0-c8bc-43d3-b61b-14ae23c3b906)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2026-03-18 01:53:20 +00:00
Gonçalo Rica Pais da Silva f255b8e57a Upgrade glam, hexasphere, rand & uuid to latest versions (#22928)
# Objective

- `glam`, `hexasphere` & `rand` have released their latest versions,
update Bevy to support them.

## Solution

- The above have been updated to their compatible versions. `rand_distr`
updated as well to match `rand` v0.10 support.
- `rand_chacha` is soft deprecated and no longer used by `rand`, so its
usage has been changed to `chacha20` to match `rand` dep tree.
- `uuid` is in the process of updating to `getrandom` v0.4, which `rand`
v0.10 supports. This PR remains in draft until a new `uuid` release hits
crates.io.
- `RngCore` is now `Rng`, and `Rng` is now `RngExt`, so this required
updating across many files.
- `choose_multiple` method is deprecated, changed to `sample`.

## Testing

- Chase all compiler errors, since this should not regress any already
existing behaviour.
- This must pass CI without regressions.

## Additional Notes

`getrandom` v0.4 doesn't add anything new for Web WASM support, so the
same `wasm_js` feature is used.
2026-02-19 22:17:25 +00:00
ickshonpe 48ec375a3a bevy_text parley migration (#22879)
# Objective

Migrate `bevy_text` from Cosmic Text to Parley.

Closes #21940. Fixes #21767, fixes #21768. Part of #21676.

## Solution

I came down with the flu yesterday when I was about halfway done. I
managed to work through it and drag this to a sort of finished state
anyway but there's probably some weird decisions because I haven't been
entirely coherent.

Most of the significant changes are to the pipeline module. There is
also a new `parley_context` module.
`FontAtlasKey` has a bunch of new fields, I can't remember why there's
both an `id` and a `index` now.

## Testing

Weird bug in `testbed_2d`:

<img width="893" height="168" alt="symbols"
src="https://github.com/user-attachments/assets/29288e16-9c3a-4aee-9ec5-638179b0bac0"
/>

Most other things seem to work the same as main, ymmv.

## Showcase

`testbed_2d`'s text scene on main with Cosmic Text:

<img width="1924" height="1127" alt="main-text2d-layout"
src="https://github.com/user-attachments/assets/55d0c7b7-7517-4a50-b76f-2a24e7cdc28f"
/>

`testbed_2d`'s text scene on this PR with Parley:

<img width="1924" height="1127" alt="testbed-2d-text"
src="https://github.com/user-attachments/assets/c87265fa-6e5f-4c03-aa5e-730f09f83ca3"
/>

`testbed_ui`'s text scene on main with Cosmic Text:

<img width="1924" height="1127" alt="testbed-ui-main"
src="https://github.com/user-attachments/assets/ce764891-3ca6-4c63-83af-8fe285a4a229"
/>

`testbed_ui`'s text scene on this PR with Parley:

<img width="1924" height="1127" alt="testbed_ui_parley"
src="https://github.com/user-attachments/assets/45bcbfe7-1ce4-44f7-bad7-7fa8f46c66ce"
/>

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2026-02-11 05:52:47 +00:00
WaterWhisperer d1dc09ae19 Use the shorthand functions to construct Vals and UiRects in examples (#22765)
# Objective

- Fixes #22753 

## Solution

- Replace `Val::Px` and `Val::Auto` with `px()` and `auto()` in examples

## Testing

- None
2026-02-02 23:27:19 +00:00
ickshonpe 6ca4769128 Minimal responsive FontSize support (#22614)
# Objective

Add responsive font sizes supporting rem and viewport units to
`bevy_text` with minimal changes to the APIs and systems.

## Solution

Introduce a new `FontSize` enum:

```rust
pub enum FontSize {
    /// Font Size in logical pixels.
    Px(f32),
    /// Font size as a percentage of the viewport width.
    Vw(f32),
    /// Font size as a percentage of the viewport height.
    Vh(f32),
    /// Font size as a percentage of the smaller of the viewport width and height.
    VMin(f32),
    /// Font size as a percentage of the larger of the viewport width and height.
    VMax(f32),
    /// Font Size relative to the value of the `RemSize` resource.
    Rem(f32),
}
```

This replaces the `f32` value of `TextFont`'s `font_size` field.

The viewport variants work the same way as their respective `Val`
counterparts.

`Rem` values are multiplied by the value of the `RemSize` resource
(which newtypes an `f32`).

`FontSize` provides an `eval` method that takes a logical viewport size
and rem base size and returns an `f32` logical font size. The resolved
logical font size is then written into the `Attributes` passed to Cosmic
Text by `TextPipeline::update_buffer`.

Any text implementation using `bevy_text` must now provide viewport and
rem base values when calling `TextPipeline::update_buffer` or
`create_measure`.

`Text2d` uses the size of the primary window to resolve viewport values
(or `Vec2::splat(1000)` if no primary window is found). This is a
deliberate compromise, a single `Text2d` can be rendered to multiple
viewports using `RenderLayers`, so it's difficult to find a rule for
which viewport size should be chosen.

### Change detection 

`ComputedTextBlock` has two new fields: `uses_viewport_sizes` and
`uses_rem_sizes`, which are set to true in `TextPipeline::update_buffer`
iff any text section in the block uses viewport or rem font sizes,
respectively.

The `ComputedTextBlock::needs_rerender` method has been modified to take
take two bool parameters:
```rust
    pub fn needs_rerender(
        &self,
        is_viewport_size_changed: bool,
        is_rem_size_changed: bool,
    ) -> bool {
        self.needs_rerender
            || (is_viewport_size_changed && self.uses_viewport_sizes)
            || (is_rem_size_changed && self.uses_rem_sizes)
    }
 ```
This ensures that text reupdates will also be scheduled if one of the text section's uses a viewport font size and the local viewport size changed, or if one of the text section's uses a rem font size and the rem size changed.

#### Limitations

There are some limitations because we don't have any sort of font style inheritance yet:

* "rem" units aren't proper rem units, and just based on the value of a resource. 
* "em" units are resolved based on inherited font size, so can't be implemented without inheritance support.

#### Notes

* This PR is quite small and not very technical. Reviewers don't need to be especially familiar with `bevy_text`. Most of the changes are to the examples.

* We could consider using `Val` instead of `FontSize`, then we could use `Val`'s constructor functions which would be much nicer, but some variants might not have sensible interpretations in both UI and Text2d contexts. Also we'd have to make `Val` accessible to `bevy_text`.

## Testing

The changes to the text systems are relatively trivial and easy to understand.  I already added a minor change to the `text` example to use `Vh` font size for the "hello bevy" text in the bottom right corner. If you change the size of the window, you should see the text change size in response. The text initially flickers before it updates because of some unrelated asset/image changes that mean that font textures aren't ready until the frame after the text update that changes the font size.

Most of the example migrations were automated using regular expressions, and there are bound to be mistakes in those changes. It's infeasible to check every single example thoroughly, but it's early enough in the release cycle that I don't think we should be too worried if a few bugs slip in.

---------

Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
2026-02-02 22:52:33 +00:00
WaterWhisperer 727a350fc6 Sort the UI examples into sub-dirs (#22727)
# Objective

- Fixes #22644

## Solution

- Create new subdirectories for categorization, and update the paths in
`Cargo.toml` and `README`.

## Testing

- `cargo check --example *`
2026-02-01 18:14:10 +00:00