Skip to content

Commit

Permalink
Correctly handle UI hierarchy without a camera (#12816)
Browse files Browse the repository at this point in the history
# Objective
Add support so bevy_ui can correctly handle an UI hierarchy without a
camera present.

- Fixes #12184

## Solution

As there was no default behavior for what should happen when a camera is
not present in a UI hierarchy, the solution
was based in defining that default behavior and improving the overall
handling of this "exception".


## Changelog

- Create default values to be used in upsert_node
- Add flag to control warnings about no camera present
- Create unit test no_camera_ui (to test if ui handles no camera
present)
  • Loading branch information
salvadorcarvalhinho authored Apr 22, 2024
1 parent e9be54b commit 16ff354
Showing 1 changed file with 75 additions and 0 deletions.
75 changes: 75 additions & 0 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ pub struct LayoutContext {
}

impl LayoutContext {
pub const DEFAULT: Self = Self {
scale_factor: 1.0,
physical_size: Vec2::ZERO,
min_size: 0.0,
max_size: 0.0,
};
/// create new a [`LayoutContext`] from the window's physical size and scale factor
fn new(scale_factor: f32, physical_size: Vec2) -> Self {
Self {
Expand All @@ -43,6 +49,12 @@ impl LayoutContext {
}
}

impl Default for LayoutContext {
fn default() -> Self {
Self::DEFAULT
}
}

#[derive(Debug, Error)]
pub enum LayoutError {
#[error("Invalid hierarchy")]
Expand Down Expand Up @@ -156,6 +168,8 @@ pub fn ui_layout_system(
);
ui_surface.upsert_node(entity, &style, &layout_context);
}
} else {
ui_surface.upsert_node(entity, &Style::default(), &LayoutContext::default());
}
}
scale_factor_events.clear();
Expand Down Expand Up @@ -1000,4 +1014,65 @@ mod tests {
}
}
}

#[test]
fn no_camera_ui() {
let mut world = World::new();
world.init_resource::<UiScale>();
world.init_resource::<UiSurface>();
world.init_resource::<Events<WindowScaleFactorChanged>>();
world.init_resource::<Events<WindowResized>>();
// Required for the camera system
world.init_resource::<Events<WindowCreated>>();
world.init_resource::<Events<AssetEvent<Image>>>();
world.init_resource::<Assets<Image>>();
world.init_resource::<ManualTextureViews>();

// spawn a dummy primary window and camera
world.spawn((
Window {
resolution: WindowResolution::new(WINDOW_WIDTH, WINDOW_HEIGHT),
..default()
},
PrimaryWindow,
));

let mut ui_schedule = Schedule::default();
ui_schedule.add_systems(
(
// UI is driven by calculated camera target info, so we need to run the camera system first
bevy_render::camera::camera_system::<OrthographicProjection>,
update_target_camera_system,
apply_deferred,
ui_layout_system,
)
.chain(),
);

let ui_root = world
.spawn(NodeBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
..default()
},
..default()
})
.id();

let ui_child = world
.spawn(NodeBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
..default()
},
..default()
})
.id();

world.entity_mut(ui_root).add_child(ui_child);

ui_schedule.run(&mut world);
}
}

0 comments on commit 16ff354

Please sign in to comment.