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

Text2d misalignment fix #14270

Closed
wants to merge 12 commits into from

Conversation

ickshonpe
Copy link
Contributor

@ickshonpe ickshonpe commented Jul 10, 2024

Objective

Fixes #14266

Solution

In update_text2d_layout after generating the layout translate all the glpyhs horizontally so that the left edge of the leftmost glyph is at 0.

Not sure if this the best method but it avoids the need for seperate fixes for ab_gyph and cosmic text.

Testing

This covers all the cases I think:

use bevy::color::palettes;
use bevy::math::vec2;
use bevy::prelude::*;
use bevy::sprite::Anchor;
use bevy::text::TextBounds;

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

fn example(
    commands: &mut Commands,
    dest: Vec3,
    justify: JustifyText,
) {
    let size = vec2(600., 200.);
    commands.spawn(SpriteBundle {
        sprite: Sprite {
            color: palettes::css::YELLOW.into(),
            custom_size: Some(10. * Vec2::ONE),
            anchor: Anchor::Center,
            ..Default::default()
        },
        transform: Transform::from_translation(dest),
        ..Default::default()
    });

    for a in [Anchor::TopLeft, Anchor::TopRight, Anchor::BottomRight, Anchor::BottomLeft] {
        commands.spawn(Text2dBundle {
            text: Text::from_section(
                format!("L R\n{:?}\n{:?}", a, justify),
                TextStyle {
                    font_size: 14.0,
                    ..default()
                },
            )
            .with_justify(justify),
            text_2d_bounds: TextBounds { width: Some(size.x), height: Some(size.y) },
            transform: Transform::from_translation(dest + Vec3::Z),
            text_anchor: a,
            ..default()
        });
    }
}

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

    for (i, j) in [JustifyText::Left, JustifyText::Right, JustifyText::Center, JustifyText::Justified].into_iter().enumerate() {
        example(&mut commands, (300. - 150. * i as f32) * Vec3::Y, j);
    }

    commands.spawn(SpriteBundle {
        sprite: Sprite {
            color: palettes::css::YELLOW.into(),
            custom_size: Some(10. * Vec2::ONE),
            anchor: Anchor::Center,
            ..Default::default()
        },
        ..Default::default()
    });
}

@ickshonpe ickshonpe added C-Bug An unexpected or incorrect behavior A-Text Rendering and layout for characters labels Jul 10, 2024
@rparrett rparrett requested a review from nicoburns July 14, 2024 15:14
@rparrett
Copy link
Contributor

@tigregalis would you mind taking a look if you get a chance?

@tigregalis
Copy link
Contributor

tigregalis commented Jul 15, 2024

cosmic-text is positioning the glyphs within the rectangle given by the bounds. For example, consider text that is centred, "a" with a content width 20, and a bounded width of 100, means it will be positioned at 40 (40-60).

I think the approach in this PR is good... with one caveat I think we should revisit later: it's the text content, not the text box, that is anchored.

When you "shrink to fit", the bounds are exclusively for wrapping behaviour, not for giving the Text2dBundle "size", which is the behaviour documented:

Currently this component is mainly useful for text wrapping only.

Should this always be the behaviour? There may be scenarios where we want the text box itself to be anchored, not the text content only, but we haven't got a way of representing that currently.

centre-justified text, in a text box, anchored bottom right, positioned at the centre of the window
---------------------------------------------------
| ------------------------                        |
| |     text content     |                        |
| |                      | <- the box             |
| |                      |                        |
| -----------------------x                        | <- the window
|                                                 |
|                                                 |
|                                                 |
|                                                 |
---------------------------------------------------

@ickshonpe
Copy link
Contributor Author

ickshonpe commented Jul 16, 2024

cosmic-text is positioning the glyphs within the rectangle given by the bounds. For example, consider text that is centred, "a" with a content width 20, and a bounded width of 100, means it will be positioned at 40 (40-60).

Yep, the reasons I went with this approach are entirely pragmatic, it works for both Bevy 14 with ab_glyph and main with cosmic-text, so the change can be included in a Bevy 14.1 release.

I think the approach in this PR is good... with one caveat I think we should revisit later: it's the text content, not the text box, that is anchored.

When you "shrink to fit", the bounds are exclusively for wrapping behaviour, not for giving the Text2dBundle "size", which is the behaviour documented:

Currently this component is mainly useful for text wrapping only.

Should this always be the behaviour? There may be scenarios where we want the text box itself to be anchored, not the text content only, but we haven't got a way of representing that currently.

centre-justified text, in a text box, anchored bottom right, positioned at the centre of the window
---------------------------------------------------
| ------------------------                        |
| |     text content     |                        |
| |                      | <- the box             |
| |                      |                        |
| -----------------------x                        | <- the window
|                                                 |
|                                                 |
|                                                 |
|                                                 |
---------------------------------------------------

Yeah agree with all of this. The text2d api is not intuitive at all. IIRC I made most of the changes that lead to the current design and my concerns were all about bugs and consistency. I don't remember thinking much about usability or more complex layout composition at all. The tricky thing to get right with a redesign is that most of the use cases for text2d are very trivial and any sort of layout support just gets in their way. Possibly we could have two distinct bundles (Text2dBundle and Text2dLayoutBundle?) or maybe some sort of enum discriminator component with Label and Layout variants.

@janhohenheim janhohenheim added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Jul 17, 2024
@alice-i-cecile
Copy link
Member

The tricky thing to get right with a redesign is that most of the use cases for text2d are very trivial and any sort of layout support just gets in their way. Possibly we could have two distinct bundles (Text2dBundle and Text2dLayoutBundle?) or maybe some sort of enum discriminator component with Label and Layout variants.

Seconding this: there's a few different use cases that got all mashed together. Billboarded text in 3D and text decals on e.g. walls are also related.

@nicoburns
Copy link
Contributor

and any sort of layout support just gets in their way

What counts as layout here? Line breaking? Presumably even trivial use cases would want the text to be shaped?

@ickshonpe
Copy link
Contributor Author

and any sort of layout support just gets in their way

What counts as layout here? Line breaking? Presumably even trivial use cases would want the text to be shaped?

Just think of floating score and damage numbers. Don't even need spaces, just got to be simple and efficient so that if everything in the game blows up and dies it can display ten thousand animated damage labels without any slowdown or hiccups.

@BenjaminBrienen BenjaminBrienen added D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 31, 2024
@ickshonpe
Copy link
Contributor Author

Closed in favour of #17365

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 C-Bug An unexpected or incorrect behavior D-Straightforward Simple bug fixes and API improvements, docs, test and examples 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.

JustifyText::Center doesn't place a text in the center of Text2dBounds
8 participants