diff --git a/examples/ui/z_index.rs b/examples/ui/z_index.rs index 3a6674da2860d..5a3e64d28b8a3 100644 --- a/examples/ui/z_index.rs +++ b/examples/ui/z_index.rs @@ -1,5 +1,7 @@ //! Demonstrates how to use z-index -//! Shows two colored buttons with transparent text. +//! +//! It uses colored boxes with different z-index values to demonstrate how it can affect the order of +//! depth of nodes compared to their siblings, but also compared to the entire UI. use bevy::prelude::*; @@ -8,216 +10,123 @@ fn main() { .insert_resource(ClearColor(Color::BLACK)) .add_plugins(DefaultPlugins) .add_startup_system(setup) - .add_system(grab) - .add_system(update_z_index_text) - .add_system_to_stage(CoreStage::PreUpdate, grabbed_move) .run(); } #[derive(Component)] struct ZIndexText; -fn setup(mut commands: Commands, asset_server: Res) { +fn setup(mut commands: Commands) { commands.spawn_bundle(Camera2dBundle::default()); - let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf"); - - // prepare a stack node at the root that's above the stack container - spawn_stack_node( - &mut commands, - font_handle.clone(), - Color::DARK_GREEN, - Some(ZIndex::Global(1)), - UiRect { - left: Val::Px(20.0), - bottom: Val::Px(80.0), - ..default() - }, - ); - - // prepare a stack node at the root that's under the stack container - spawn_stack_node( - &mut commands, - font_handle.clone(), - Color::ORANGE, - Some(ZIndex::Global(-1)), - UiRect { - left: Val::Px(20.0), - bottom: Val::Px(20.0), - ..default() - }, - ); - - // prepare a stack of nodes that can be moved around inside their container. - let mut stacked_nodes = (0..9) - .map(|i| { - spawn_stack_node( - &mut commands, - font_handle.clone(), - Color::rgb(0.1 + i as f32 * 0.1, 0.0, 0.0), - Some(ZIndex::Local(-4 + i)), - UiRect { - left: Val::Px(10.0 + (i as f32 * 47.5)), - bottom: Val::Px(10.0 + (i as f32 * 22.5)), - ..default() - }, - ) - }) - .collect::>(); - - // add a node that has no z-index - stacked_nodes.push(spawn_stack_node( - &mut commands, - font_handle.clone(), - Color::PURPLE, - None, - UiRect { - left: Val::Px(10.0), - bottom: Val::Px(120.0), - ..default() - }, - )); - - // add a node with a global z-index - stacked_nodes.push(spawn_stack_node( - &mut commands, - font_handle, - Color::PINK, - Some(ZIndex::Global(2)), - UiRect { - left: Val::Px(10.0), - bottom: Val::Px(180.0), - ..default() - }, - )); - - // spawn the stack container + // spawn the container with default z-index. + // ommiting the z-index component is equivalent to inserting `ZIndex::Local(0)`. + // because this is a root UI node, it is also equivalent to inserting `ZIndex::Global(0)`. commands .spawn_bundle(NodeBundle { color: Color::GRAY.into(), style: Style { - size: Size::new(Val::Px(500.0), Val::Px(250.0)), - overflow: Overflow::Hidden, + size: Size::new(Val::Px(180.0), Val::Px(100.0)), margin: UiRect::all(Val::Auto), ..default() }, ..default() }) - .push_children(&stacked_nodes); -} - -fn spawn_stack_node( - commands: &mut Commands, - font_handle: Handle, - color: Color, - z_index: Option, - position: UiRect, -) -> Entity { - let text = commands - .spawn_bundle(TextBundle::from_section( - "", - TextStyle { - color: Color::WHITE, - font: font_handle, - font_size: 20.0, - }, - )) - .insert(ZIndexText) - .id(); - - let node = commands - .spawn_bundle(ButtonBundle { - color: color.into(), - style: Style { - position_type: PositionType::Absolute, - position, - size: Size::new(Val::Px(100.0), Val::Px(50.0)), - justify_content: JustifyContent::Center, - align_items: AlignItems::Center, + .with_children(|parent| { + // spawn a node with no z-index. + // this has the same result as using `ZIndex::Local(0)`. + // this uses the default depth ordering which is based on where this node is in the hierarchy. + parent.spawn_bundle(ButtonBundle { + color: Color::RED.into(), + style: Style { + position_type: PositionType::Absolute, + position: UiRect { + left: Val::Px(10.0), + bottom: Val::Px(40.0), + ..default() + }, + size: Size::new(Val::Px(100.0), Val::Px(50.0)), + ..default() + }, ..default() - }, - ..default() - }) - .insert(Grab) - .add_child(text) - .id(); - - if let Some(z_index) = z_index { - commands.entity(node).insert(z_index); - } - - node -} - -fn update_z_index_text( - mut text_query: Query<(&Parent, &mut Text), With>, - zindex_query: Query<&ZIndex>, -) { - for (parent, mut text) in &mut text_query { - let new_text = zindex_query - .get(parent.get()) - .map_or("No ZIndex".to_string(), |zindex| match zindex { - ZIndex::Local(value) => format!("Local({value})"), - ZIndex::Global(value) => format!("Global({value})"), }); - if text.sections[0].value != new_text { - text.sections[0].value = new_text; - } - } -} - -#[derive(Component, Copy, Clone, Debug)] -pub struct Grab; - -#[derive(Component, Copy, Clone, Debug)] -pub struct Grabbed { - pub cursor_position: Vec2, - pub cursor_offset: Vec2, -} - -fn grab( - mut commands: Commands, - query: Query<(Entity, &Interaction, Option<&Grabbed>), With>, - windows: Res, -) { - for (entity, interaction, grabbed) in query.iter() { - match interaction { - Interaction::Clicked => { - if grabbed.is_none() { - if let Some(cursor_position) = windows - .get_primary() - .and_then(|window| window.cursor_position()) - { - commands.entity(entity).insert(Grabbed { - cursor_position, - cursor_offset: Vec2::new(0.0, 0.0), - }); - } - } - } - _ => { - if grabbed.is_some() { - commands.entity(entity).remove::(); - } - } - }; - } -} - -fn grabbed_move(mut query: Query<(&mut Grabbed, &mut Style), With>, windows: Res) { - for (mut grabbed, mut style) in query.iter_mut() { - if let Some(cursor_position) = windows - .get_primary() - .and_then(|window| window.cursor_position()) - { - let offset = cursor_position - grabbed.cursor_position; - if grabbed.cursor_offset != offset { - style.position.left += offset.x - grabbed.cursor_offset.x; - style.position.bottom += offset.y - grabbed.cursor_offset.y; - - grabbed.cursor_offset = offset; - } - } - } + // spawn a node with a positive local z-index of 2. + // it will show above other nodes in the grey container. + parent + .spawn_bundle(ButtonBundle { + color: Color::BLUE.into(), + style: Style { + position_type: PositionType::Absolute, + position: UiRect { + left: Val::Px(45.0), + bottom: Val::Px(30.0), + ..default() + }, + size: Size::new(Val::Px(100.0), Val::Px(50.0)), + ..default() + }, + ..default() + }) + .insert(ZIndex::Local(2)); + + // spawn a node with a negative local z-index. + // it will show under all other nodes in the grey container. + parent + .spawn_bundle(ButtonBundle { + color: Color::GREEN.into(), + style: Style { + position_type: PositionType::Absolute, + position: UiRect { + left: Val::Px(70.0), + bottom: Val::Px(20.0), + ..default() + }, + size: Size::new(Val::Px(100.0), Val::Px(75.0)), + ..default() + }, + ..default() + }) + .insert(ZIndex::Local(-1)); + + // spawn a node with a positive global z-index of 1. + // it will show above all other nodes, because it's the highest global z-index in this example app. + // by default, boxes all share the global z-index of 0 that the grey container is implicitly added to. + parent + .spawn_bundle(ButtonBundle { + color: Color::PINK.into(), + style: Style { + position_type: PositionType::Absolute, + position: UiRect { + left: Val::Px(15.0), + bottom: Val::Px(-5.0), + ..default() + }, + size: Size::new(Val::Px(100.0), Val::Px(60.0)), + ..default() + }, + ..default() + }) + .insert(ZIndex::Global(1)); + + // spawn a node with a negative global z-index. + // this will show under all other nodes, including its parent, because -1 is the lowest global z-index + // in this example app. + parent + .spawn_bundle(ButtonBundle { + color: Color::YELLOW.into(), + style: Style { + position_type: PositionType::Absolute, + position: UiRect { + left: Val::Px(-10.0), + bottom: Val::Px(-10.0), + ..default() + }, + size: Size::new(Val::Px(100.0), Val::Px(50.0)), + ..default() + }, + ..default() + }) + .insert(ZIndex::Global(-1)); + }); }