Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store both the rounded and unrounded node size in Node #9923

Merged
merged 8 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
42 changes: 28 additions & 14 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
mod convert;
pub mod debug;

use crate::{ContentSize, Node, Style, UiScale};
use crate::{ContentSize, Node, SizeRounding, Style, UiScale};
use bevy_ecs::{
change_detection::DetectChanges,
entity::Entity,
event::EventReader,
query::{With, Without},
removal_detection::RemovedComponents,
system::{Query, Res, ResMut, Resource},
system::{ParamSet, Query, Res, ResMut, Resource},
world::Ref,
};
use bevy_hierarchy::{Children, Parent};
Expand Down Expand Up @@ -245,12 +245,14 @@ pub fn ui_layout_system(
mut ui_surface: ResMut<UiSurface>,
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
style_query: Query<(Entity, Ref<Style>), With<Node>>,
mut measure_query: Query<(Entity, &mut ContentSize)>,
children_query: Query<(Entity, Ref<Children>), With<Node>>,
just_children_query: Query<&Children>,
mut removed_children: RemovedComponents<Children>,
mut removed_content_sizes: RemovedComponents<ContentSize>,
mut node_transform_query: Query<(&mut Node, &mut Transform)>,
mut mutables_param_set: ParamSet<(
Query<(Entity, &mut ContentSize)>,
Query<(&mut Node, &mut Transform, Option<&ContentSize>)>,
)>,
mut removed_nodes: RemovedComponents<Node>,
) {
// assume one window for time being...
Expand Down Expand Up @@ -296,7 +298,7 @@ pub fn ui_layout_system(
ui_surface.try_remove_measure(entity);
}

for (entity, mut content_size) in &mut measure_query {
for (entity, mut content_size) in &mut mutables_param_set.p0() {
if let Some(measure_func) = content_size.measure_func.take() {
ui_surface.update_measure(entity, measure_func);
}
Expand Down Expand Up @@ -328,28 +330,40 @@ pub fn ui_layout_system(
fn update_uinode_geometry_recursive(
entity: Entity,
ui_surface: &UiSurface,
node_transform_query: &mut Query<(&mut Node, &mut Transform)>,
node_transform_query: &mut Query<(&mut Node, &mut Transform, Option<&ContentSize>)>,
children_query: &Query<&Children>,
inverse_target_scale_factor: f32,
parent_size: Vec2,
mut absolute_location: Vec2,
) {
if let Ok((mut node, mut transform)) = node_transform_query.get_mut(entity) {
if let Ok((mut node, mut transform, maybe_content_size)) =
node_transform_query.get_mut(entity)
{
let layout = ui_surface.get_layout(entity).unwrap();
let layout_size =
inverse_target_scale_factor * Vec2::new(layout.size.width, layout.size.height);
let layout_location =
inverse_target_scale_factor * Vec2::new(layout.location.x, layout.location.y);

absolute_location += layout_location;
let rounded_size = round_layout_coords(absolute_location + layout_size)
- round_layout_coords(absolute_location);

let size = match maybe_content_size
.map(|content_size| content_size.rounding)
.unwrap_or_default()
{
SizeRounding::Enabled => {
round_layout_coords(absolute_location + layout_size)
- round_layout_coords(absolute_location)
}
SizeRounding::Disabled => layout_size,
};

let rounded_location =
round_layout_coords(layout_location) + 0.5 * (rounded_size - parent_size);
round_layout_coords(layout_location) + 0.5 * (size - parent_size);

// only trigger change detection when the new values are different
if node.calculated_size != rounded_size {
node.calculated_size = rounded_size;
if node.calculated_size != size {
node.calculated_size = size;
}
if transform.translation.truncate() != rounded_location {
transform.translation = rounded_location.extend(0.);
Expand All @@ -362,7 +376,7 @@ pub fn ui_layout_system(
node_transform_query,
children_query,
inverse_target_scale_factor,
rounded_size,
size,
absolute_location,
);
}
Expand All @@ -374,7 +388,7 @@ pub fn ui_layout_system(
update_uinode_geometry_recursive(
entity,
&ui_surface,
&mut node_transform_query,
&mut mutables_param_set.p1(),
&just_children_query,
inverse_target_scale_factor as f32,
Vec2::ZERO,
Expand Down
25 changes: 25 additions & 0 deletions crates/bevy_ui/src/measurement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ impl std::fmt::Debug for ContentSize {
}
}

/// Determines if the size of a UI node should be rounded
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Reflect)]
pub enum SizeRounding {
/// The node's size should be rounded after layout recomputation
#[default]
Enabled,
/// The node's size should be not rounded after layout recomputation
Disabled,
}

/// A `Measure` is used to compute the size of a ui node
/// when the size of that node is based on its content.
pub trait Measure: Send + Sync + 'static {
Expand Down Expand Up @@ -52,6 +62,8 @@ pub struct ContentSize {
/// The `Measure` used to compute the intrinsic size
#[reflect(ignore)]
pub(crate) measure_func: Option<MeasureFunc>,
/// Determines if the size of the UI node with this `ContentSize` should be rounded after layout recomputation
pub(crate) rounding: SizeRounding,
}

impl ContentSize {
Expand All @@ -67,6 +79,19 @@ impl ContentSize {
self.measure_func = Some(MeasureFunc::Boxed(Box::new(measure_func)));
}

/// Set a `Measure` for the UI node entity with this component with size rounding disabled
pub fn set_unrounded(&mut self, measure: impl Measure) {
let measure_func = move |size: TaffySize<_>, available: TaffySize<_>| {
let size = measure.measure(size.width, size.height, available.width, available.height);
TaffySize {
width: size.x,
height: size.y,
}
};
self.measure_func = Some(MeasureFunc::Boxed(Box::new(measure_func)));
self.rounding = SizeRounding::Disabled;
}

/// Creates a `ContentSize` with a `Measure` that always returns given `size` argument, regardless of the UI layout's constraints.
pub fn fixed_size(size: Vec2) -> ContentSize {
let mut content_size = Self::default();
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ui/src/widget/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ fn create_text_measure(
match TextMeasureInfo::from_text(&text, fonts, scale_factor) {
Ok(measure) => {
if text.linebreak_behavior == BreakLineOn::NoWrap {
content_size.set(FixedMeasure { size: measure.max });
content_size.set_unrounded(FixedMeasure { size: measure.max });
} else {
content_size.set(TextMeasure { info: measure });
content_size.set_unrounded(TextMeasure { info: measure });
}

// Text measure func created successfully, so set `TextFlags` to schedule a recompute
Expand Down