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

Fix regression in TextEdit::singleline layout #5640

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

IaVashik
Copy link

This PR reverts a change introduced in PR #3660 that caused a regression with TextEdit::singleline. The original PR attempted to fix an issue with the cursor in TextEdit inside ScrollArea, but it did so by adding unnecessary size allocation to TextEdit, which breaks the layout when TextEdit::singleline is used outside of ScrollArea.

Image

The regression introduced by #3660 is more severe, as it completely breaks the layout of applications using TextEdit::singleline, as shown in the following issues:

Furthermore, I was unable to reproduce the original bug from PR #3660 in the current version of egui using the following code:

impl eframe::App for MyEguiApp {
    fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
        ctx.set_debug_on_hover(true);
        egui::CentralPanel::default().show(ctx, |ui| {
            ScrollArea::vertical().max_height(100.0).show(ui, |ui| {
                ui.add(TextEdit::multiline(&mut self.text).hint_text("Enter text here..."))
            });
        });
    }
}

This code attempts to recreate the layout shown in the video from PR #3660, using a ScrollArea with limited height and a TextEdit inside. However, the cursor hiding issue was not reproducible.
Video_2025-01-26_17-54-24

Therefore, I believe the code added in PR #3660 is no longer necessary and only creates more problems.

Copy link
Owner

@emilk emilk left a comment

Choose a reason for hiding this comment

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

Thanks!

@emilk emilk mentioned this pull request Jan 21, 2025
Copy link

Preview available at https://egui-pr-preview.github.io/pr/5640-master
Note that it might take a couple seconds for the update to show up after the preview_build workflow has completed.

@emilk
Copy link
Owner

emilk commented Jan 27, 2025

There are some clippy failures that need fixing

@IaVashik
Copy link
Author

Done. There's still a warning left at crates/egui/src/context.rs:2469:13, but it's outside the scope of this PR, so I didn't touch it.

@emilk emilk added bug Something is broken egui labels Jan 27, 2025
@emilk
Copy link
Owner

emilk commented Jan 27, 2025

@juancampa you may wanna have a look at this too

@juancampa
Copy link
Contributor

The only thing I'm seeing that could be a regression is the frame delay that appears in the video (bottom border disappears for one frame) but I'll test locally to double check

@juancampa
Copy link
Contributor

juancampa commented Jan 27, 2025

Ok so the border disappearing is because of the TextArea is animating the scroll, which is expected. However, I can still repro the original issue when scroll animation is disabled (using .animated(false))

Screenshot.2025-01-27.at.14.13.01.mp4

Since .horizontal comes with its own scrolling behavior a better fix is to wrap the original code in if !clip_text. It seems to fix all the issues:

Screenshot 2025-01-27 at 14 33 23

This is what I used:

            if !clip_text {
                // Allocate additional space if edits were made this frame that changed the size. This is important so that,
                // if there's a ScrollArea, it can properly scroll to the cursor.
                let extra_size = galley.size() - rect.size();
                if extra_size.x > 0.0 || extra_size.y > 0.0 {
                    ui.allocate_rect(
                        Rect::from_min_size(outer_rect.max, extra_size),
                        Sense::hover(),
                    );
                }
            }

@IaVashik
Copy link
Author

So, the root cause of the original issue is .animated(false), that makes sense now. Yeah, using if !clip_text would definitely work as a workaround for the bug we're talking about.
Ngl, after looking at egui's code, I'm still not sure how animated actually affects the ScrollArea and existing pipeline, so I can't really tell if this behavior is a bug in ScrollArea or TextEdit itself.

@IaVashik
Copy link
Author

Anyway, we need to decide what to do here. If you're both sure that the root cause of the original issue is a flaw in TextEdit, then I can use @juancampa's code in the next commit, if he doesn't object.

@juancampa
Copy link
Contributor

The original issue was a bug in TextArea because it was painting outside of its allocated space (for one frame), so there was no way for ScrollArea to scroll to it.

When scroll animation is enabled, it works fine, because ScrollArea continues to scroll to the target for a few frames, and at that point TextArea is allocating the correct amount of space.

@IaVashik
Copy link
Author

Okay, that makes sense. I tried to figure out where the calculation goes wrong, but egui is just too complex and complicated for me. My only suspicion is galley.size() in show_content, but I couldn't understand how galley and layouter are obtained, so I'll leave this to the smarter contributors of this wonderful project :<

The solution from @juancampa does work, but to me, it feels more like a workaround. I'll revert to their code and add an if statement for !clip_text. At the very least, it's the quickest way to fix the bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is broken egui
Projects
None yet
3 participants