diff --git a/examples/render_target.rs b/examples/render_target.rs index 32ffe6814625e1c25e7ff59269edc67903db15d6..52760fc168b68ca270b51aba49ec48fa1381cea6 100644 --- a/examples/render_target.rs +++ b/examples/render_target.rs @@ -16,6 +16,9 @@ use kayak_ui::{ #[derive(Component)] struct MainPassCube; +#[derive(Component)] +struct MainUI; + fn startup( mut commands: Commands, mut font_mapping: ResMut<FontMapping>, @@ -145,7 +148,7 @@ fn startup( /> </KayakAppBundle> } - commands.spawn(UICameraBundle::new(widget_context)); + commands.spawn((UICameraBundle::new(widget_context), MainUI)); } /// Rotates the outer cube (main pass) @@ -156,6 +159,18 @@ fn cube_rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<Ma } } +fn depsawn_ui( + mut commands: Commands, + keyboard_input: Res<Input<KeyCode>>, + ui_query: Query<(Entity, &KayakRootContext), With<MainUI>>, +) { + if keyboard_input.pressed(KeyCode::Escape) { + if let Ok((entity, _)) = ui_query.get_single() { + commands.entity(entity).despawn_descendants(); + } + } +} + fn main() { App::new() .add_plugins(DefaultPlugins) @@ -163,5 +178,6 @@ fn main() { .add_plugin(KayakWidgets) .add_startup_system(startup) .add_system(cube_rotator_system) + .add_system(depsawn_ui) .run() } diff --git a/src/context.rs b/src/context.rs index 14ab8ef6becadea52ee04d06e228783203108a62..fd60e63f5cd6f908656a80fced5665d1405f10b0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -579,6 +579,16 @@ fn update_widgets( index: &Arc<RwLock<HashMap<Entity, usize>>>, ) { for entity in widgets.iter() { + // A small hack to add parents to widgets + let mut command_queue = CommandQueue::default(); + { + let mut commands = Commands::new(&mut command_queue, &world); + if let Some(mut entity_commands) = commands.get_entity(entity.0) { + entity_commands.set_parent(camera_entity); + } + } + command_queue.apply(world); + if let Some(entity_ref) = world.get_entity(entity.0) { if let Some(widget_type) = entity_ref.get::<WidgetName>() { let widget_context = KayakWidgetContext::new( @@ -703,6 +713,31 @@ fn update_widgets( ); // } } + } else { + // In this case the entity we are trying to process no longer exists. + // The approach taken here removes said entities from the tree. + let mut despawn_list = Vec::default(); + if let Ok(mut tree) = tree.write() { + for child in tree.down_iter_at(*entity, true) { + despawn_list.push(child.0); + if let Ok(mut order_tree) = order_tree.try_write() { + // had_removal = true; + log::trace!( + "Removing entity! {:?} inside of: {:?}", + child.0.index(), + entity.0.index() + ); + order_tree.remove(child); + } + } + + for entity in despawn_list.drain(..) { + tree.remove(WrappedIndex(entity)); + if let Some(entity_mut) = world.get_entity_mut(entity) { + entity_mut.despawn(); + } + } + } } if let Some(entity_ref) = world.get_entity(entity.0) { diff --git a/src/event_dispatcher.rs b/src/event_dispatcher.rs index 064c71cddc792c7b270ec0dfa6df644a4ff26c6c..12dad3b514f622f44c5c0841ebfc1c2053517ea4 100644 --- a/src/event_dispatcher.rs +++ b/src/event_dispatcher.rs @@ -385,36 +385,37 @@ impl EventDispatcher { let (current, depth) = stack.pop().unwrap(); let mut enter_children = true; - if world.entity(current.0).contains::<OnEvent>() { - for input_event in input_events { - // --- Process Event --- // - if matches!(input_event.category(), InputEventCategory::Mouse) { - // A widget's PointerEvents style will determine how it and its children are processed - let pointer_events = Self::resolve_pointer_events(current, world); - - match pointer_events { - PointerEvents::All | PointerEvents::SelfOnly => { - let events = self.process_pointer_events( - input_event, - (current, depth), - &mut states, - world, - context, - false, - ); - event_stream.extend(events); - - if matches!(pointer_events, PointerEvents::SelfOnly) { - enter_children = false; + if let Some(entity_ref) = world.get_entity(current.0) { + if entity_ref.contains::<OnEvent>() { + for input_event in input_events { + // --- Process Event --- // + if matches!(input_event.category(), InputEventCategory::Mouse) { + // A widget's PointerEvents style will determine how it and its children are processed + let pointer_events = Self::resolve_pointer_events(current, world); + + match pointer_events { + PointerEvents::All | PointerEvents::SelfOnly => { + let events = self.process_pointer_events( + input_event, + (current, depth), + &mut states, + world, + context, + false, + ); + event_stream.extend(events); + + if matches!(pointer_events, PointerEvents::SelfOnly) { + enter_children = false; + } } + PointerEvents::None => enter_children = false, + PointerEvents::ChildrenOnly => {} } - PointerEvents::None => enter_children = false, - PointerEvents::ChildrenOnly => {} } } } } - // --- Push Children to Stack --- // if enter_children { if let Some(children) = node_tree.children.get(¤t) { diff --git a/src/tree.rs b/src/tree.rs index a3b9468c1e9f7f907827a6c598fa1ede565c98c3..0c91b5eb1b3dc0f35c61ab5bdcce786f5437396c 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -77,6 +77,7 @@ impl Tree { children } else { // Is root node + self.root_node = None; Vec::default() } }