Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/bevy_ui/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::Node;
use crate::{
render::UI_PIPELINE_HANDLE,
widget::{Button, Image},
CalculatedSize, FocusPolicy, Interaction, Style,
CalculatedSize, ControlNode, FocusPolicy, Interaction, Style,
};
use bevy_asset::Handle;
use bevy_ecs::bundle::Bundle;
Expand All @@ -17,6 +17,15 @@ use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
use bevy_text::Text;
use bevy_transform::prelude::{GlobalTransform, Transform};

/// If you add this to an entity, it should be the *only* bundle on it from bevy_ui.
/// This bundle will mark the entity as transparent to the UI layout system, meaning the
/// children of this entity will be treated as the children of this entity s parent by the layout system.
pub struct ControlBundle {
pub control_node: ControlNode,
pub transform: Transform,
pub global_transform: GlobalTransform,
}

#[derive(Bundle, Clone, Debug)]
pub struct NodeBundle {
pub node: Node,
Expand Down
96 changes: 83 additions & 13 deletions crates/bevy_ui/src/flex/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod convert;

use crate::{CalculatedSize, Node, Style};
use crate::{CalculatedSize, ControlNode, Node, Style};
use bevy_app::EventReader;
use bevy_ecs::{
entity::Entity,
Expand Down Expand Up @@ -111,19 +111,62 @@ impl FlexSurface {
}
}

pub fn update_children(&mut self, entity: Entity, children: &Children) {
pub fn update_children(
&mut self,
entity: Entity,
children: &Children,
control_node_query: &mut Query<&mut ControlNode>,
unfiltered_children_query: &Query<&Children>,
) {
let mut stretch_children = Vec::with_capacity(children.len());
for child in children.iter() {
if let Some(stretch_node) = self.entity_to_stretch.get(child) {
stretch_children.push(*stretch_node);
fn inner(
true_parent: Entity,
child: Entity,
control_node_query: &mut Query<&mut ControlNode>,
unfiltered_children_query: &Query<&Children>,
do_on_real: &mut impl FnMut(Entity),
) {
if let Ok(mut control_node) = control_node_query.get_mut(child) {
control_node.true_parent = Some(true_parent);
for &child in unfiltered_children_query
.get(child)
.ok()
.into_iter()
.map(|c| &**c)
.flatten()
{
inner(
true_parent,
child,
control_node_query,
unfiltered_children_query,
do_on_real,
);
}
} else {
warn!(
"Unstyled child in a UI entity hierarchy. You are using an entity \
without UI components as a child of an entity with UI components, results may be unexpected."
);
do_on_real(child);
}
}

for &child in children.iter() {
inner(
entity,
child,
control_node_query,
unfiltered_children_query,
&mut |e| {
if let Some(stretch_node) = self.entity_to_stretch.get(&e) {
stretch_children.push(*stretch_node);
} else {
warn!(
"Unstyled child in a UI entity hierarchy. You are using an entity \
without UI components as a child of an entity with UI components, results may be unexpected."
);
}
},
);
}

let stretch_node = self.entity_to_stretch.get(&entity).unwrap();
self.stretch
.set_children(*stretch_node, stretch_children)
Expand Down Expand Up @@ -207,7 +250,10 @@ pub fn flex_node_system(
(Entity, &Style, &CalculatedSize),
(With<Node>, Changed<CalculatedSize>),
>,
children_query: Query<(Entity, &Children), (With<Node>, Changed<Children>)>,
changed_children_query: Query<(Entity, &Children), (With<Node>, Changed<Children>)>,
unfiltered_children_query: Query<&Children>,
mut control_node_query: Query<&mut ControlNode>,
changed_cnc_query: Query<Entity, (Changed<Children>, With<ControlNode>)>,
mut node_transform_query: Query<(Entity, &mut Node, &mut Transform, Option<&Parent>)>,
) {
// update window root nodes
Expand Down Expand Up @@ -262,8 +308,28 @@ pub fn flex_node_system(
}

// update children
for (entity, children) in children_query.iter() {
flex_surface.update_children(entity, children);
for (entity, children) in changed_children_query.iter() {
flex_surface.update_children(
entity,
children,
&mut control_node_query,
&unfiltered_children_query,
);
}

for entity in changed_cnc_query.iter() {
let true_parent = if let Some(e) = control_node_query.get_mut(entity).unwrap().true_parent {
e
} else {
continue;
};
let children = unfiltered_children_query.get(true_parent).unwrap();
flex_surface.update_children(
true_parent,
children,
&mut control_node_query,
&unfiltered_children_query,
);
}

// compute layouts
Expand All @@ -284,7 +350,11 @@ pub fn flex_node_system(
position.x = to_logical(layout.location.x + layout.size.width / 2.0);
position.y = to_logical(layout.location.y + layout.size.height / 2.0);
if let Some(parent) = parent {
if let Ok(parent_layout) = flex_surface.get_layout(parent.0) {
let parent = control_node_query
.get_mut(parent.0)
.map(|cn| cn.true_parent.unwrap())
.unwrap_or(parent.0);
if let Ok(parent_layout) = flex_surface.get_layout(parent) {
position.x -= to_logical(parent_layout.size.width / 2.0);
position.y -= to_logical(parent_layout.size.height / 2.0);
}
Expand Down
10 changes: 9 additions & 1 deletion crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_ecs::{prelude::*, reflect::ReflectComponent};
use bevy_math::{Rect, Size, Vec2};
use bevy_reflect::{Reflect, ReflectDeserialize};
use bevy_render::renderer::RenderResources;
Expand All @@ -11,6 +11,14 @@ pub struct Node {
pub size: Vec2,
}

/// If you add this to an entity, it should be the *only* component on it from bevy_ui.
/// This component marks an entity as "transparent" to the UI layout system, meaning the
/// children of this entity will be treated as the children of this entity s parent by the layout system.
#[derive(Clone, Default, Component)]
pub struct ControlNode {
pub(crate) true_parent: Option<Entity>,
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum Val {
Expand Down