diff --git a/crates/bevy_ecs/src/core/filter.rs b/crates/bevy_ecs/src/core/filter.rs index 65e01f4d58762..3ed6b5197ef39 100644 --- a/crates/bevy_ecs/src/core/filter.rs +++ b/crates/bevy_ecs/src/core/filter.rs @@ -29,6 +29,8 @@ impl EntityFilter for AnyEntityFilter { pub struct Or(pub T); +pub struct Not(pub T); + /// Query transformer that retrieves components of type `T` that have been mutated since the start of the frame. /// Added components do not count as mutated. pub struct Mutated(NonNull, PhantomData); @@ -270,3 +272,23 @@ impl_query_filter_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M); impl_query_filter_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); impl_query_filter_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); impl_query_filter_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); + +impl QueryFilter for Not { + type EntityFilter = Not; + + fn access() -> QueryAccess { + T::access() + } + + fn get_entity_filter(archetype: &Archetype) -> Option { + T::get_entity_filter(archetype).map(Not) + } +} + +impl EntityFilter for Not { + const DANGLING: Self = Not(T::DANGLING); + + unsafe fn matches_entity(&self, offset: usize) -> bool { + !self.0.matches_entity(offset) + } +} diff --git a/crates/bevy_ecs/src/core/mod.rs b/crates/bevy_ecs/src/core/mod.rs index 512bb10e48819..7013edf6d3088 100644 --- a/crates/bevy_ecs/src/core/mod.rs +++ b/crates/bevy_ecs/src/core/mod.rs @@ -50,7 +50,7 @@ pub use bundle::{Bundle, DynamicBundle, MissingComponent}; pub use entities::{Entity, EntityReserver, Location, NoSuchEntity}; pub use entity_builder::{BuiltEntity, EntityBuilder}; pub use entity_map::*; -pub use filter::{Added, Changed, EntityFilter, Mutated, Or, QueryFilter, With, Without}; +pub use filter::{Added, Changed, EntityFilter, Mutated, Not, Or, QueryFilter, With, Without}; pub use query::{Batch, BatchedIter, Flags, Mut, QueryIter, ReadOnlyFetch, WorldQuery}; pub use world::{ArchetypesGeneration, Component, ComponentError, SpawnBatchIter, World}; pub use world_builder::*; diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 70be39c666110..d0910feaa3c5d 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -16,7 +16,7 @@ pub mod prelude { resource::{ChangedRes, FromResources, Local, Res, ResMut, Resource, Resources}, schedule::{Schedule, State, StateStage, SystemStage}, system::{Commands, IntoSystem, Query, System}, - Added, Bundle, Changed, Component, Entity, Flags, In, IntoChainSystem, Mut, Mutated, Or, - QuerySet, Ref, RefMut, With, Without, World, + Added, Bundle, Changed, Component, Entity, Flags, In, IntoChainSystem, Mut, Mutated, Not, + Or, QuerySet, Ref, RefMut, With, Without, World, }; } diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index 43bb7c839c0cb..4bfbeedd66204 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -4,37 +4,31 @@ use crate::{ }; use bevy_math::{Rect, Size}; -pub fn from_rect( - scale_factor: f64, - rect: Rect, -) -> stretch::geometry::Rect { +pub fn from_rect(rect: Rect) -> stretch::geometry::Rect { stretch::geometry::Rect { - start: from_val(scale_factor, rect.left), - end: from_val(scale_factor, rect.right), + start: rect.left.into(), + end: rect.right.into(), // NOTE: top and bottom are intentionally flipped. stretch has a flipped y-axis - top: from_val(scale_factor, rect.bottom), - bottom: from_val(scale_factor, rect.top), + top: rect.bottom.into(), + bottom: rect.top.into(), } } -pub fn from_f32_size(scale_factor: f64, size: Size) -> stretch::geometry::Size { +pub fn from_f32_size(size: Size) -> stretch::geometry::Size { stretch::geometry::Size { - width: (scale_factor * size.width as f64) as f32, - height: (scale_factor * size.height as f64) as f32, + width: size.width, + height: size.height, } } -pub fn from_val_size( - scale_factor: f64, - size: Size, -) -> stretch::geometry::Size { +pub fn from_val_size(size: Size) -> stretch::geometry::Size { stretch::geometry::Size { - width: from_val(scale_factor, size.width), - height: from_val(scale_factor, size.height), + width: size.width.into(), + height: size.height.into(), } } -pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { +pub fn from_style(value: &Style) -> stretch::style::Style { stretch::style::Style { overflow: stretch::style::Overflow::Visible, display: value.display.into(), @@ -46,16 +40,16 @@ pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { align_self: value.align_self.into(), align_content: value.align_content.into(), justify_content: value.justify_content.into(), - position: from_rect(scale_factor, value.position), - margin: from_rect(scale_factor, value.margin), - padding: from_rect(scale_factor, value.padding), - border: from_rect(scale_factor, value.border), + position: from_rect(value.position), + margin: from_rect(value.margin), + padding: from_rect(value.padding), + border: from_rect(value.border), flex_grow: value.flex_grow, flex_shrink: value.flex_shrink, - flex_basis: from_val(scale_factor, value.flex_basis), - size: from_val_size(scale_factor, value.size), - min_size: from_val_size(scale_factor, value.min_size), - max_size: from_val_size(scale_factor, value.max_size), + flex_basis: value.flex_basis.into(), + size: from_val_size(value.size), + min_size: from_val_size(value.min_size), + max_size: from_val_size(value.max_size), aspect_ratio: match value.aspect_ratio { Some(value) => stretch::number::Number::Defined(value), None => stretch::number::Number::Undefined, @@ -63,12 +57,14 @@ pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { } } -pub fn from_val(scale_factor: f64, val: Val) -> stretch::style::Dimension { - match val { - Val::Auto => stretch::style::Dimension::Auto, - Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0), - Val::Px(value) => stretch::style::Dimension::Points((scale_factor * value as f64) as f32), - Val::Undefined => stretch::style::Dimension::Undefined, +impl From for stretch::style::Dimension { + fn from(val: Val) -> Self { + match val { + Val::Auto => stretch::style::Dimension::Auto, + Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0), + Val::Px(value) => stretch::style::Dimension::Points(value), + Val::Undefined => stretch::style::Dimension::Undefined, + } } } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index b32675534eb78..c2c66fcf06bd7 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -1,21 +1,29 @@ mod convert; -use crate::{Node, Style}; +use crate::{Node, Style, ZIndex}; + use bevy_app::EventReader; -use bevy_ecs::{Changed, Entity, Flags, Query, QueryFilter, Res, ResMut, With, Without}; -use bevy_log::warn; +use bevy_ecs::{Added, Changed, Entity, Mutated, Not, Or, Query, QuerySet, Res, ResMut, With}; +use bevy_log::{trace, warn}; + use bevy_math::Vec2; + use bevy_text::CalculatedSize; -use bevy_transform::prelude::{Children, Parent, Transform}; +use bevy_transform::{ + components::GlobalTransform, + prelude::{Children, Parent, Transform}, +}; use bevy_utils::HashMap; -use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows}; -use std::fmt; +use bevy_window::{Window, WindowId, WindowResized, Windows}; +use std::{collections::hash_map::Entry, fmt}; use stretch::{number::Number, Stretch}; pub struct FlexSurface { entity_to_stretch: HashMap, - window_nodes: HashMap, + window_nodes: WindowNodes, stretch: Stretch, + stacking_contexts: HashMap, + root_stacking_context: StackingContext, } impl fmt::Debug for FlexSurface { @@ -33,260 +41,844 @@ impl Default for FlexSurface { entity_to_stretch: Default::default(), window_nodes: Default::default(), stretch: Stretch::new(), + stacking_contexts: Default::default(), + root_stacking_context: Default::default(), } } } -impl FlexSurface { - pub fn upsert_node(&mut self, entity: Entity, style: &Style, scale_factor: f64) { - let mut added = false; - let stretch = &mut self.stretch; - let stretch_style = convert::from_style(scale_factor, style); - let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| { - added = true; - stretch.new_node(stretch_style, Vec::new()).unwrap() - }); - - if !added { - self.stretch - .set_style(*stretch_node, stretch_style) - .unwrap(); +#[derive(Debug, Default)] +struct WindowNodes { + map: HashMap, + dirty: bool, +} + +#[derive(Debug, Default)] +struct StackingContext { + // The root stacking context does not have a root entity + root_entity: Option, + context: Vec<(Entity, i16)>, + updated: bool, +} + +#[derive(Default, Debug)] +pub struct NodeWindowId(pub WindowId); + +// SAFE: as long as MeasureFunc is Send + Sync. https://github.com/vislyhq/stretch/issues/69 +unsafe impl Send for FlexSurface {} +unsafe impl Sync for FlexSurface {} + +#[allow(clippy::too_many_arguments)] +pub fn layout_system( + mut flex_surface: ResMut, + changed_style_query: Query<(Entity, &Style, Option<&CalculatedSize>), Changed