From bdfc64560c182c1797f983878e032ce0a32d0d29 Mon Sep 17 00:00:00 2001 From: StarToaster <startoaster23@gmail.com> Date: Fri, 28 Oct 2022 10:11:12 -0400 Subject: [PATCH] Improve text calculations. Improved bevy_scene example. --- examples/bevy_scene.rs | 13 +++--- src/calculate_nodes.rs | 94 ++++++++++++++++++++++++------------------ src/context.rs | 28 ++++++++++--- src/layout.rs | 2 +- src/widgets/window.rs | 5 ++- 5 files changed, 91 insertions(+), 51 deletions(-) diff --git a/examples/bevy_scene.rs b/examples/bevy_scene.rs index 7804645..68a6568 100644 --- a/examples/bevy_scene.rs +++ b/examples/bevy_scene.rs @@ -79,17 +79,20 @@ fn move_active_tile(mut tile: Query<(&mut Transform, &ActiveTile)>) { /// A system that moves the ghost tile to the cursor's position fn move_ghost_tile( + event_context: Res<EventDispatcher>, mut tile: Query<&mut Transform, With<GhostTile>>, mut cursor_moved: EventReader<CursorMoved>, camera_transform: Query<&GlobalTransform, With<WorldCamera>>, windows: Res<Windows>, ) { for _ in cursor_moved.iter() { - let world_pos = cursor_to_world(&windows, &camera_transform.single()); - let tile_pos = world_to_tile(world_pos); - let mut ghost = tile.single_mut(); - ghost.translation.x = tile_pos.x; - ghost.translation.y = tile_pos.y; + if !event_context.contains_cursor() { + let world_pos = cursor_to_world(&windows, &camera_transform.single()); + let tile_pos = world_to_tile(world_pos); + let mut ghost = tile.single_mut(); + ghost.translation.x = tile_pos.x; + ghost.translation.y = tile_pos.y; + } } } diff --git a/src/calculate_nodes.rs b/src/calculate_nodes.rs index 593c86e..a053978 100644 --- a/src/calculate_nodes.rs +++ b/src/calculate_nodes.rs @@ -3,6 +3,7 @@ use bevy::{ utils::HashMap, }; use kayak_font::KayakFont; +use morphorm::Hierarchy; use crate::{ layout::{DataCache, Rect}, @@ -21,7 +22,6 @@ pub fn calculate_nodes( query: Query<Entity, With<DirtyNode>>, all_styles_query: Query<&KStyle>, node_query: Query<(Entity, &Node)>, - nodes_no_entity_query: Query<&'static Node>, ) { let mut new_nodes = HashMap::<Entity, (Node, bool)>::default(); // This is the maximum recursion depth for this method. @@ -95,6 +95,7 @@ pub fn calculate_nodes( &context, &fonts, &font_mapping, + &query, // &node_query, dirty_entity, &mut styles, @@ -139,18 +140,30 @@ pub fn calculate_nodes( log::trace!("{:?} needs layout!", entity.id()); } } + } +} - { - let context = context.as_mut(); - if let Ok(tree) = context.tree.try_read() { - // tree.dump(); - let node_tree = &*tree; - if let Ok(mut cache) = context.layout_cache.try_write() { - let mut data_cache = DataCache { - cache: &mut cache, - query: &nodes_no_entity_query, - }; - morphorm::layout(&mut data_cache, node_tree, &nodes_no_entity_query); +pub fn calculate_layout( + mut commands: Commands, + mut context: ResMut<KayakRootContext>, + nodes_no_entity_query: Query<&'static Node>, +) { + let context = context.as_mut(); + if let Ok(tree) = context.tree.try_read() { + // tree.dump(); + let node_tree = &*tree; + if let Ok(mut cache) = context.layout_cache.try_write() { + let mut data_cache = DataCache { + cache: &mut cache, + query: &nodes_no_entity_query, + }; + morphorm::layout(&mut data_cache, node_tree, &nodes_no_entity_query); + + for (entity, change) in cache.geometry_changed.iter() { + if !change.is_empty() { + for child in tree.child_iter(*entity) { + commands.entity(child.0).insert(DirtyNode); + } } } } @@ -163,11 +176,12 @@ fn create_primitive( fonts: &Assets<KayakFont>, font_mapping: &FontMapping, // query: &Query<(Entity, &Node)>, + dirty: &Query<Entity, With<DirtyNode>>, id: WrappedIndex, styles: &mut KStyle, ) -> (RenderPrimitive, bool) { let mut render_primitive = RenderPrimitive::from(&styles.clone()); - let mut needs_layout = false; + let mut needs_layout = true; match &mut render_primitive { RenderPrimitive::Text { @@ -183,38 +197,40 @@ fn create_primitive( // self.bind(id, &asset); if let Ok(node_tree) = context.tree.try_read() { if let Some(parent_id) = node_tree.get_parent(id) { - if let Some(parent_layout) = context.get_layout(&parent_id) { - properties.max_size = (parent_layout.width, parent_layout.height); - - if properties.max_size.0 == 0.0 || properties.max_size.1 == 0.0 { - needs_layout = true; - } - - // --- Calculate Text Layout --- // - *text_layout = font.measure(&content, *properties); - let measurement = text_layout.size(); - - // --- Apply Layout --- // - if matches!(styles.width, StyleProp::Default) { - styles.width = StyleProp::Value(Units::Pixels(measurement.0)); + if !dirty.contains(parent_id.0) { + if let Some(parent_layout) = context.get_layout(&parent_id) { + properties.max_size = (parent_layout.width, parent_layout.height); + + if properties.max_size.0 == 0.0 || properties.max_size.1 == 0.0 { + needs_layout = true; + } else { + needs_layout = false; + } + + if context.get_geometry_changed(&parent_id) { + needs_layout = true; + } + + // --- Calculate Text Layout --- // + *text_layout = font.measure(&content, *properties); + let measurement = text_layout.size(); + + // --- Apply Layout --- // + if matches!(styles.width, StyleProp::Default) { + styles.width = StyleProp::Value(Units::Pixels(measurement.0)); + } + if matches!(styles.height, StyleProp::Default) { + styles.height = StyleProp::Value(Units::Pixels(measurement.1)); + } } - if matches!(styles.height, StyleProp::Default) { - styles.height = StyleProp::Value(Units::Pixels(measurement.1)); - } - } else { - needs_layout = true; } - } else { - needs_layout = true; } - } else { - needs_layout = true; } - } else { - needs_layout = true; } } - _ => {} + _ => { + needs_layout = false; + } } if needs_layout { diff --git a/src/context.rs b/src/context.rs index d3f3d37..4096dc8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -8,7 +8,7 @@ use bevy::{ use morphorm::Hierarchy; use crate::{ - calculate_nodes::calculate_nodes, + calculate_nodes::{calculate_layout, calculate_nodes}, children::KChildren, clone_component::{clone_state, clone_system, EntityCloneSystems, PreviousWidget}, context_entities::ContextEntities, @@ -111,6 +111,18 @@ impl KayakRootContext { } } + pub(crate) fn get_geometry_changed(&self, id: &WrappedIndex) -> bool { + if let Ok(cache) = self.layout_cache.try_read() { + if let Some(geometry_changed) = cache.geometry_changed.get(id) { + !geometry_changed.is_empty() + } else { + false + } + } else { + false + } + } + /// Adds a new set of systems for a widget type. /// Update systems are ran every frame and return true or false depending on if the widget has "changed". /// Render systems are ran only if the widget has changed and are meant to re-render children and handle @@ -709,12 +721,18 @@ impl Plugin for KayakContextPlugin { fn calculate_ui(world: &mut World) { // dbg!("Calculating nodes!"); - let mut system = IntoSystem::into_system(calculate_nodes); - system.initialize(world); + let mut node_system = IntoSystem::into_system(calculate_nodes); + node_system.initialize(world); + + let mut layout_system = IntoSystem::into_system(calculate_layout); + layout_system.initialize(world); for _ in 0..5 { - system.run((), world); - system.apply_buffers(world); + node_system.run((), world); + node_system.apply_buffers(world); + + layout_system.run((), world); + layout_system.apply_buffers(world); world.resource_scope::<KayakRootContext, _>(|world, mut context| { LayoutEventDispatcher::dispatch(&mut context, world); }); diff --git a/src/layout.rs b/src/layout.rs index c09176e..8f49ce5 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -67,7 +67,7 @@ pub(crate) struct LayoutCache { /// /// This should only contain entries for nodes that have _at least one_ flag set. /// If a node does not have any flags set, then they should be removed from the map. - geometry_changed: HashMap<WrappedIndex, GeometryChanged>, + pub(crate) geometry_changed: HashMap<WrappedIndex, GeometryChanged>, visible: HashMap<WrappedIndex, bool>, } diff --git a/src/widgets/window.rs b/src/widgets/window.rs index 5fa45fd..d51c0f5 100644 --- a/src/widgets/window.rs +++ b/src/widgets/window.rs @@ -179,7 +179,10 @@ pub fn window_render( } <ClipBundle styles={KStyle { - padding: StyleProp::Value(Edge::all(Units::Pixels(10.0))), + top: Units::Pixels(10.0).into(), + left: Units::Pixels(10.0).into(), + right: Units::Pixels(10.0).into(), + bottom: Units::Pixels(10.0).into(), ..Default::default() }} children={window_children.clone()} -- GitLab