mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 22:18:33 +00:00
Add ControlNode for UI (#2908)
This PR adds a ControlNode which 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(s).
This commit is contained in:
parent
0887f41b58
commit
2974293682
3 changed files with 102 additions and 15 deletions
|
@ -2,7 +2,7 @@ use super::Node;
|
||||||
use crate::{
|
use crate::{
|
||||||
render::UI_PIPELINE_HANDLE,
|
render::UI_PIPELINE_HANDLE,
|
||||||
widget::{Button, Image},
|
widget::{Button, Image},
|
||||||
CalculatedSize, FocusPolicy, Interaction, Style,
|
CalculatedSize, ControlNode, FocusPolicy, Interaction, Style,
|
||||||
};
|
};
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use bevy_ecs::bundle::Bundle;
|
use bevy_ecs::bundle::Bundle;
|
||||||
|
@ -17,6 +17,15 @@ use bevy_sprite::{ColorMaterial, QUAD_HANDLE};
|
||||||
use bevy_text::Text;
|
use bevy_text::Text;
|
||||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
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)]
|
#[derive(Bundle, Clone, Debug)]
|
||||||
pub struct NodeBundle {
|
pub struct NodeBundle {
|
||||||
pub node: Node,
|
pub node: Node,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
mod convert;
|
mod convert;
|
||||||
|
|
||||||
use crate::{CalculatedSize, Node, Style};
|
use crate::{CalculatedSize, ControlNode, Node, Style};
|
||||||
use bevy_app::EventReader;
|
use bevy_app::EventReader;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
|
@ -111,17 +111,60 @@ 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());
|
let mut stretch_children = Vec::with_capacity(children.len());
|
||||||
for child in children.iter() {
|
fn inner(
|
||||||
if let Some(stretch_node) = self.entity_to_stretch.get(child) {
|
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 {
|
||||||
|
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);
|
stretch_children.push(*stretch_node);
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
"Unstyled child in a UI entity hierarchy. You are using an entity \
|
"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."
|
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();
|
let stretch_node = self.entity_to_stretch.get(&entity).unwrap();
|
||||||
|
@ -207,7 +250,10 @@ pub fn flex_node_system(
|
||||||
(Entity, &Style, &CalculatedSize),
|
(Entity, &Style, &CalculatedSize),
|
||||||
(With<Node>, Changed<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>)>,
|
mut node_transform_query: Query<(Entity, &mut Node, &mut Transform, Option<&Parent>)>,
|
||||||
) {
|
) {
|
||||||
// update window root nodes
|
// update window root nodes
|
||||||
|
@ -262,8 +308,28 @@ pub fn flex_node_system(
|
||||||
}
|
}
|
||||||
|
|
||||||
// update children
|
// update children
|
||||||
for (entity, children) in children_query.iter() {
|
for (entity, children) in changed_children_query.iter() {
|
||||||
flex_surface.update_children(entity, children);
|
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
|
// compute layouts
|
||||||
|
@ -284,7 +350,11 @@ pub fn flex_node_system(
|
||||||
position.x = to_logical(layout.location.x + layout.size.width / 2.0);
|
position.x = to_logical(layout.location.x + layout.size.width / 2.0);
|
||||||
position.y = to_logical(layout.location.y + layout.size.height / 2.0);
|
position.y = to_logical(layout.location.y + layout.size.height / 2.0);
|
||||||
if let Some(parent) = parent {
|
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.x -= to_logical(parent_layout.size.width / 2.0);
|
||||||
position.y -= to_logical(parent_layout.size.height / 2.0);
|
position.y -= to_logical(parent_layout.size.height / 2.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_math::{Rect, Size, Vec2};
|
||||||
use bevy_reflect::{Reflect, ReflectDeserialize};
|
use bevy_reflect::{Reflect, ReflectDeserialize};
|
||||||
use bevy_render::renderer::RenderResources;
|
use bevy_render::renderer::RenderResources;
|
||||||
|
@ -11,6 +11,14 @@ pub struct Node {
|
||||||
pub size: Vec2,
|
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)]
|
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
|
||||||
#[reflect_value(PartialEq, Serialize, Deserialize)]
|
#[reflect_value(PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Val {
|
pub enum Val {
|
||||||
|
|
Loading…
Add table
Reference in a new issue