Correctly handle UI hierarchy without a camera (#12816)
# 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)
This commit is contained in:
parent
e9be54b0ea
commit
16ff354f1c
@ -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 {
|
||||
@ -43,6 +49,12 @@ impl LayoutContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LayoutContext {
|
||||
fn default() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum LayoutError {
|
||||
#[error("Invalid hierarchy")]
|
||||
@ -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();
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user