bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.44k stars 3.6k forks source link

A flex column nested inside a flex row results in unexpected layout calculation #4237

Open Earthmark opened 2 years ago

Earthmark commented 2 years ago

Bevy version

0.6.1

Operating system & version

Windows 11

What you did

I compiled and ran this code (when a valid font)

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup_ui)
        .run();
}

fn setup_ui(mut c: Commands, assets: Res<AssetServer>) {
    c.spawn_bundle(UiCameraBundle::default());

    let style = TextStyle {
        font: assets.load("Karla-VariableFont_wght.ttf"),
        font_size: 50.0,
        ..Default::default()
    };

    let label = |s: &'static str| TextBundle {
        text: Text::with_section(s, style.clone(), Default::default()),
        ..Default::default()
    };

    fn row() -> NodeBundle {
        NodeBundle {
            style: Style {
                flex_direction: FlexDirection::Row,
                ..Default::default()
            },
            color: Color::NONE.into(),
            ..Default::default()
        }
    }

    fn column() -> NodeBundle {
        NodeBundle {
            style: Style {
                flex_direction: FlexDirection::Column,
                ..Default::default()
            },
            color: Color::NONE.into(),
            ..Default::default()
        }
    };

    c.spawn_bundle(row()).with_children(|c| {
        c.spawn_bundle(label("-"));

        c.spawn_bundle(column()).with_children(|c| {
            c.spawn_bundle(label("/"));
            c.spawn_bundle(label("\\"));
        });

        c.spawn_bundle(label("|"));
    });
}

What you expected to happen

I expected a vertically reversed version of this html

<html>

<head>
  <style>
    .row {
      display: flex;
      flex-direction: row;
    }

    .col {
      display: flex;
      flex-direction: column;
    }
  </style>
</head>

<body>
  <div class="row">
    <div>-</div>
    <div class="col">
      <div>/</div>
      <div>\</div>
    </div>
    <div>|</div>
  </div>
</body>

</html>

which looks like this image

What actually happened

This is what bevy renders image

The row flex was ignored, and the column goes off the screen. Elements after the column are also missing.

Additional information

If I remove the children of the column, but keep the column itself there the row works fine. It looks like the column having content seems to break the row calculation. image

mockersf commented 2 years ago

Do you reproduce that issue with ImageBundle nodes with a specified size instead of the TextBundle?

Earthmark commented 2 years ago

I added an example using ImageBundle, however I'm not quite sure how to specify the exact size, I think Node has that but I'm uncertain.

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup_ui)
        .run();
}

fn setup_ui(mut c: Commands, assets: Res<AssetServer>) {
    c.spawn_bundle(UiCameraBundle::default());

    let image = |s: &'static str| ImageBundle {
        image: assets.load(s).into(),
        node: Node {
            size: Vec2::new(10.0, 10.0),
            ..Default::default()
        },
        ..Default::default()
    };

    fn row() -> NodeBundle {
        NodeBundle {
            style: Style {
                flex_direction: FlexDirection::Row,
                ..Default::default()
            },
            color: Color::NONE.into(),
            ..Default::default()
        }
    }

    fn column() -> NodeBundle {
        NodeBundle {
            style: Style {
                flex_direction: FlexDirection::Column,
                ..Default::default()
            },
            color: Color::NONE.into(),
            ..Default::default()
        }
    }

    c.spawn_bundle(row()).with_children(|c| {
        c.spawn_bundle(image("icons/outline_north_east_black_24dp.png"));

        c.spawn_bundle(column()).with_children(|c| {
            c.spawn_bundle(image("icons/outline_north_west_black_24dp.png"));
            c.spawn_bundle(image("icons/outline_south_east_black_24dp.png"));
        });

        c.spawn_bundle(image("icons/outline_south_west_black_24dp.png"));
    });
}

This does result in a different behavior though, it appears the row is now invisible. image

I tried this with all of the children directly under the row,


    c.spawn_bundle(row()).with_children(|c| {
        c.spawn_bundle(image("icons/outline_north_east_black_24dp.png"));
        c.spawn_bundle(image("icons/outline_north_west_black_24dp.png"));
        c.spawn_bundle(image("icons/outline_south_east_black_24dp.png"));
        c.spawn_bundle(image("icons/outline_south_west_black_24dp.png"));

        c.spawn_bundle(column()).with_children(|c| {});

    });

and this result was squished, but did render all 4. image

EDIT: The icons I used were the diagonal arrow icons from https://fonts.google.com/icons

Earthmark commented 2 years ago

It appears this happens specifically when the inner text element has a height of Auto or Unknown.

Weibye commented 2 years ago

I suspect the answer is yes, but are you able to reproduce the issue using current main?