Skip to content

Resolve EditableText's scrolling per edit in bevy_text#24634

Open
ickshonpe wants to merge 26 commits into
bevyengine:mainfrom
ickshonpe:editable-text-scroll
Open

Resolve EditableText's scrolling per edit in bevy_text#24634
ickshonpe wants to merge 26 commits into
bevyengine:mainfrom
ickshonpe:editable-text-scroll

Conversation

@ickshonpe

@ickshonpe ickshonpe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Objective

  • Scrolling for `EditableText' is resolved per frame with different cases handled over a couple of systems. This makes it hard to reason about and test and puts the responsibility on widget authors to handle scrolling resolution which can get quite complicated when you have to consider different wrapping, justification, linebreak, and text direction settings.

  • Drag scrolling is framerate dependent, should be independent.

  • Scrolling and cursor behaviour is inconsistant, depending on layout settings.

Solution

New module bevy_text::scroll. Includes a write up of the basic scrolling rules and a new struct TextViewport along with methods and helper functions and tests.

TextViewport represents the region of the editable text layout visible to the user. EditableText has a new viewport: TextViewport field.

The TextScroll component is removed (replaced by TextViewport).

There are three new TextEdits:

  • ScrollTo(Vec2)
  • ScrollBy(Vec2)
  • ScrollByLines(f32)
    Having scrolling controlled through TextEdits makes EditableText's much easier to test. You can just apply a sequence of TextEdits to an EditableText, no need to setup a full text pipeline.

A new system sync_editable_text_viewports updates each TextViewport's size when an EditableText node's size is changed by ui_layout_system.

Drag scrolling is no longer event based and framerate independent. A new system text_input_autoscroll_system scrolls the viewport each frame when the input is being dragged with the point outside the viewport's bounds.


Initially this also included a larger number of changes that split up EditableText into multiple components and moved more functionality into bevy_text, but it was too much for one PR, so I split off just the scrolling work, which is the most important part.

There are still some problems with RTL and non-left justified text, fixing at least some of those will need changes in Parley: #24587.

Testing

There a bunch of new tests included in bevy_text::scroll, bevy_text::text_edit and bevy_ui_widgets::text_input.

Also testbed_ui's EditableText scene has been updated:

cargo run --example testbed_ui -- EditableText

ickshonpe added 23 commits June 12, 2026 11:35
Added viewport and margin params to `TextEdit::apply`
@github-actions

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-24634

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@ickshonpe ickshonpe added C-Bug An unexpected or incorrect behavior A-UI Graphical user interfaces, styles, layouts, and widgets M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide D-Complex Quite challenging from either a design or technical perspective. Ask for help! A-Text Rendering and layout for characters S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 15, 2026
@ickshonpe ickshonpe added the M-Deliberate-Rendering-Change An intentional change to how tests and examples are rendered label Jun 15, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in UI Jun 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

It looks like your PR is a breaking change, but you didn't provide a migration guide.

Please review the instructions for writing migration guides, then expand or revise the content in the migration guides directory to reflect your changes.

@ickshonpe ickshonpe added the C-Testing A change that impacts how we test Bevy or how users test their apps label Jun 15, 2026
@alice-i-cecile alice-i-cecile added this to the 0.20 milestone Jun 15, 2026
@alice-i-cecile alice-i-cecile added the C-Code-Quality A section of code that is hard to understand or change label Jun 15, 2026
@alice-i-cecile alice-i-cecile self-requested a review June 15, 2026 20:55
TextEdit::Backspace => {
driver.backdelete();
reveal_cursor(driver, viewport, cursor_margin);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do a single if generation change then reveal_cursor at the end of the system?

@ickshonpe ickshonpe Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not every editor change that updates the generation requires reveal_cursor afterwards. I thought about having a method needs_reveal_cursor on TextEdit but it felt less clear and explicit then calling it per match branch.

Also some edits that don't update the generation may still require reveal_cursor. Down when the cursor is on the last line, for instance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option I considered was adding a wrapper type containing the driver, viewport, and any options. Then we could reimplement the PlainDriver API over it but with the functions automatically updating the viewport as needed. Didn't want to make the PR any larger though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Text Rendering and layout for characters A-UI Graphical user interfaces, styles, layouts, and widgets C-Bug An unexpected or incorrect behavior C-Code-Quality A section of code that is hard to understand or change C-Testing A change that impacts how we test Bevy or how users test their apps D-Complex Quite challenging from either a design or technical perspective. Ask for help! M-Deliberate-Rendering-Change An intentional change to how tests and examples are rendered M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

3 participants