Newer
Older
use bevy::{
ecs::{event::ManualEventReader, system::CommandQueue},
prelude::*,
utils::{HashMap, HashSet},
calculate_nodes::{calculate_layout, calculate_nodes},
children::KChildren,
clone_component::{clone_state, clone_system, EntityCloneSystems, PreviousWidget},
cursor::PointerEvents,
event_dispatcher::EventDispatcher,
focus_tree::FocusTree,
input::query_world,
layout::{LayoutCache, Rect},
layout_dispatcher::LayoutEventDispatcher,
node::{DirtyNode, WrappedIndex},
prelude::KayakWidgetContext,
styles::{
ComputedStyles, Corner, Edge, KCursorIcon, KPositionType, KStyle, LayoutType,
RenderCommand, StyleProp, Units,
Focusable, KayakUIPlugin, WindowSize, render::MAX_OPACITY_LAYERS,
};
/// A tag component representing when a widget has been mounted(added to the tree).
#[derive(Component, Reflect, Default)]
#[reflect(Component)]
pub struct Mounted;
const UPDATE_DEPTH: u32 = 0;
type WidgetSystems = HashMap<
String,
(
Box<dyn System<In = (KayakWidgetContext, Entity, Entity), Out = bool>>,
Box<dyn System<In = (KayakWidgetContext, Entity), Out = bool>>,
///
/// Kayak Context
///
/// This bevy resource keeps track of all of the necessary UI state. This includes the widgets, tree, input, layout, and other important data.
/// The Context provides some connivent helper functions for creating and using widgets, state, and context.
///
/// Usage:
/// ```rust
/// use bevy::prelude::*;
/// use kayak_ui::prelude::{widgets::*, *};
///
/// // Bevy setup function
/// fn setup(mut commands: Commands) {
/// let mut widget_context = Context::new();
/// let app_entity = commands.spawn(KayakAppBundle {
/// ..Default::default()
/// }).id();
/// // Stores the kayak app widget in the widget context's tree.
/// widget_context.add_widget(None, app_entity);
/// commands.spawn((widget_context, EventDispatcher::default()));
/// }
///
/// fn main() {
/// App::new()
/// .add_plugins(DefaultPlugins)
/// .add_plugin(ContextPlugin)
/// .add_plugin(KayakWidgets)
/// .add_startup_system(setup);
/// }
/// ```
#[derive(Component)]
pub struct KayakRootContext {
pub tree: Arc<RwLock<Tree>>,
pub(crate) layout_cache: Arc<RwLock<LayoutCache>>,
pub(crate) focus_tree: Arc<RwLock<FocusTree>>,
pub(crate) current_z: f32,
pub(crate) context_entities: ContextEntities,
pub(crate) current_cursor: CursorIcon,
pub(crate) clone_systems: Arc<RwLock<EntityCloneSystems>>,
pub(crate) cloned_widget_entities: Arc<RwLock<HashMap<Entity, Entity>>>,
pub(crate) widget_state: WidgetState,
pub(crate) order_tree: Arc<RwLock<Tree>>,
pub(crate) index: Arc<RwLock<HashMap<Entity, usize>>>,
/// Unique id's store entity id's related to a key rather than the child tree.
/// This lets users get a unique entity. The first Entity is the parent widget.
/// The 2nd hashmap is a list of keys and their entities.
pub(crate) unique_ids: Arc<RwLock<HashMap<Entity, HashMap<String, Entity>>>>,
/// Maps keyed entities to spawn parents. We can't use the tree in this case.
pub(crate) unique_ids_parents: Arc<RwLock<HashMap<Entity, Entity>>>,
pub(crate) uninitilized_systems: HashSet<String>,
impl Default for KayakRootContext {
fn default() -> Self {
Self::new(Entity::from_raw(0))
}
}
impl KayakRootContext {
/// Creates a new widget context.
pub fn new(camera_entity: Entity) -> Self {
Self {
tree: Arc::new(RwLock::new(Tree::default())),
layout_cache: Arc::new(RwLock::new(LayoutCache::default())),
focus_tree: Default::default(),
systems: HashMap::default(),
current_z: 0.0,
context_entities: ContextEntities::new(),
current_cursor: CursorIcon::Default,
clone_systems: Default::default(),
cloned_widget_entities: Default::default(),
widget_state: Default::default(),
index: Default::default(),
order_tree: Default::default(),
unique_ids: Default::default(),
unique_ids_parents: Default::default(),
uninitilized_systems: Default::default(),
/// Adds a kayak plugin and runs the build function on the context.
pub fn add_plugin(&mut self, plugin: impl KayakUIPlugin) {
plugin.build(self)
}
/// Retreives the current entity that has focus or None if nothing is focused.
pub fn get_current_focus(&self) -> Option<Entity> {
if let Ok(tree) = self.focus_tree.try_read() {
return tree.current().and_then(|a| Some(a.0));
}
None
}
/// Get's the layout for th given widget index.
pub(crate) fn get_layout(&self, id: &WrappedIndex) -> Option<Rect> {
if let Ok(cache) = self.layout_cache.try_read() {
cache.rect.get(id).cloned()
} else {
None
}
}
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
/// tree changes.
pub fn add_widget_system<Params, Params2>(
update: impl IntoSystem<(KayakWidgetContext, Entity, Entity), bool, Params>,
render: impl IntoSystem<(KayakWidgetContext, Entity), bool, Params2>,
let type_name = type_name.into();
let update_system = Box::new(IntoSystem::into_system(update));
let render_system = Box::new(IntoSystem::into_system(render));
self.systems
.insert(type_name.clone(), (update_system, render_system));
self.uninitilized_systems.insert(type_name);
/// Let's the widget context know what data types are used for a given widget.
/// This is useful as it allows Kayak to keep track of previous values for diffing.
/// When the default update widget system is called it checks the props and state of
/// the current widget with it's values from the previous frame.
/// This allows Kayak to diff data. Alternatively a custom widget update system can
/// be used and listen for events, resources, or any other bevy ECS data.
Props: Component + Clone + PartialEq,
State: Component + Clone + PartialEq,
>(
&mut self,
) {
if let Ok(mut clone_systems) = self.clone_systems.try_write() {
clone_systems
.0
.push((clone_system::<Props>, clone_state::<State>));
}
/// Adds a widget to the tree.
/// Widgets are created using entities and components.
/// Once created their id's need to be added to the widget tree
/// so that the correct ordering is preserved for updates and rendering.
pub fn add_widget(&mut self, parent: Option<Entity>, entity: Entity) {
if let Ok(mut tree) = self.tree.write() {
tree.add(WrappedIndex(entity), parent.map(WrappedIndex));
if let Ok(mut cache) = self.layout_cache.try_write() {
cache.add(WrappedIndex(entity));
}
}
}
/// Creates a new context using the context entity for the given type_id + parent id.
/// Context can be considered state that changes across multiple components.
/// Alternatively you can use bevy's resources.
pub fn set_context_entity<T: Default + 'static>(
&self,
parent_id: Option<Entity>,
context_entity: Entity,
) {
if let Some(parent_id) = parent_id {
self.context_entities
.add_context_entity::<T>(parent_id, context_entity);
}
}
/// Returns a new/existing widget entity.
/// Because a re-render can potentially spawn new entities it's advised to use this
/// to avoid creating a new entity.
///
/// Usage:
/// fn setup() {
/// let mut widget_context = WidgetContext::new();
/// // Root tree node, no parent node.
/// let root_entity = widget_context.spawn_widget(&mut commands, None);
/// commands.entity(root_entity).insert(KayakAppBundle::default());
/// widget_context.add_widget(None, root_entity);
/// }
pub fn spawn_widget(
&self,
commands: &mut Commands,
key: Option<&'static str>,
parent_id: Option<Entity>,
) -> Entity {
let mut entity = None;
if let Some(parent_entity) = parent_id {
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
if let Some(key) = key.map(|key| key.to_string()) {
if let Ok(unique_ids) = self.unique_ids.try_read() {
if let Some(key_hashmap) = unique_ids.get(&parent_entity) {
entity = key_hashmap.get(&key).cloned();
if let Some(child) = entity {
if let Some(mut entity_commands) = commands.get_entity(child) {
entity_commands.despawn();
}
entity =
Some(commands.get_or_spawn(child).set_parent(parent_entity).id());
log::trace!(
"Reusing keyed widget entity {:?} with parent: {:?}!",
child.index(),
parent_id.unwrap().index()
);
}
} else {
log::trace!("couldn't find key entity on parent!");
}
} else {
panic!("Couldn't get unique id lock!");
}
} else {
let children = self.get_children_ordered(parent_entity);
// We need to increment the index count even if we are using the unique id key.
let index = self.get_and_add_index(parent_entity);
let child = children.get(index).cloned();
if let Some(child) = child {
log::trace!(
"Reusing widget entity {:?} with parent: {:?}!",
child.index(),
parent_id.unwrap().index()
);
if let Some(mut entity_commands) = commands.get_entity(child) {
entity_commands.despawn();
}
entity = Some(commands.get_or_spawn(child).id());
}
// If we have no entity spawn it!
if entity.is_none() {
entity = Some(commands.spawn_empty().id());
log::trace!(
"Spawning new widget with entity {:?}!",
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Note: The root widget cannot have a key for now..
if let Some(parent_entity) = parent_id {
commands.entity(entity.unwrap()).set_parent(parent_entity);
if let Some(key) = key.map(|key| key.to_string()) {
if let Ok(mut unique_ids) = self.unique_ids.try_write() {
if let Some(key_hashmap) = unique_ids.get_mut(&parent_entity) {
key_hashmap.insert(key, entity.unwrap());
if let Ok(mut unique_ids_parents) = self.unique_ids_parents.try_write()
{
unique_ids_parents.insert(entity.unwrap(), parent_entity);
}
} else {
let mut key_hashmap = HashMap::new();
key_hashmap.insert(key, entity.unwrap());
unique_ids.insert(parent_entity, key_hashmap);
if let Ok(mut unique_ids_parents) = self.unique_ids_parents.try_write()
{
unique_ids_parents.insert(entity.unwrap(), parent_entity);
}
}
}
} else {
// We need to add it to the ordered tree
if let Ok(mut tree) = self.order_tree.try_write() {
tree.add(WrappedIndex(entity.unwrap()), parent_id.map(WrappedIndex))
}
}
}
}
entity.unwrap()
}
fn get_children_ordered(&self, entity: Entity) -> Vec<Entity> {
let mut children = vec![];
if let Ok(tree) = self.order_tree.read() {
let iterator = tree.child_iter(WrappedIndex(entity));
children = iterator.map(|index| index.0).collect::<Vec<_>>();
}
children
fn get_and_add_index(&self, parent: Entity) -> usize {
if let Ok(mut hash_map) = self.index.try_write() {
if hash_map.contains_key(&parent) {
let index = hash_map.get_mut(&parent).unwrap();
let current_index = *index;
*index += 1;
return current_index;
} else {
hash_map.insert(parent, 1);
return 0;
}
}
0
}
/// Generates a flat list of widget render commands sorted by tree order.
/// There is no need to call this unless you are implementing your own custom renderer.
pub fn build_render_primitives(
&self,
nodes: &Query<&crate::node::Node>,
widget_names: &Query<&WidgetName>,
) -> Vec<RenderPrimitive> {
let node_tree = self.tree.try_read();
if node_tree.is_err() {
return vec![];
}
let node_tree = node_tree.unwrap();
if node_tree.root_node.is_none() {
return vec![];
}
let (render_primitives, _, _) = if let Ok(mut layout_cache) = self.layout_cache.try_write() {
recurse_node_tree_to_build_primitives(
&node_tree,
&mut layout_cache,
nodes,
widget_names,
node_tree.root_node.unwrap(),
0.0,
0,
0
(vec![], 0.0, 0)
};
// render_primitives.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
// render_primitives.iter().enumerate().for_each(|(index, p)| {
// log::info!("Name: {:?}, Z: {:?}", p.to_string(), p.get_layout().z_index);
// });
// dbg!(&render_primitives
// .iter()
// .map(|a| (a.1.to_string(), a.0))
// .collect::<Vec<_>>());
render_primitives.into_iter().collect()
fn recurse_node_tree_to_build_primitives(
node_tree: &Tree,
layout_cache: &mut LayoutCache,
widget_names: &Query<&WidgetName>,
mut current_opacity_layer: u32,
mut total_opacity_layers: u32,
) -> (Vec<RenderPrimitive>, f32, u32) {
let mut opacity = None;
// Skip rendering completely transparent objects.
if node.opacity < 0.001 {
return (render_primitives, current_global_z, total_opacity_layers);
}
current_global_z += UI_Z_STEP + if node.z <= 0.0 { 0.0 } else { node.z };
let mut render_primitive = node.primitive.clone();
// Set opacity layer on render primitive
render_primitive.set_opacity_layer(current_opacity_layer);
// let mut new_z_index = main_z_index;
let new_z = current_global_z; // - parent_global_z;
let layout = if let Some(layout) = layout_cache.rect.get_mut(¤t_node) {
log::trace!(
"z_index is {} and node.z is {} for: {}-{}",
node.z,
widget_names.get(current_node.0).unwrap().0,
current_node.0.index(),
);
// new_z_index += if node.z <= 0.0 { 0.0 } else { node.z };
render_primitive.set_layout(*layout);
*layout
} else {
log::warn!(
"No layout for node: {}-{}",
widget_names.get(current_node.0).unwrap().0,
);
Rect::default()
};
match &render_primitive {
RenderPrimitive::Text {
content, layout, ..
} => {
"Text node: {}-{} is equal to: {}, {:?}",
widget_names.get(current_node.0).unwrap().0,
layout,
);
}
RenderPrimitive::Clip { layout, .. } => {
log::trace!(
"Clip node: {}-{} is equal to: {:?}",
widget_names.get(current_node.0).unwrap().0,
current_node.0.index(),
layout,
);
}
RenderPrimitive::Empty => {
log::trace!(
widget_names.get(current_node.0).unwrap().0,
);
}
_ => {}
}
if let RenderPrimitive::Clip { layout, .. } = &mut render_primitive {
if let RenderPrimitive::Clip {
layout: prev_layout,
..
} = &prev_clip
{
let y1 = layout.posy + layout.height;
let y2 = prev_layout.posy + prev_layout.height;
layout.height = y1.min(y2) - layout.posy;
if prev_layout.posy > layout.posy {
layout.posy = prev_layout.posy;
}
}
}
// Only spawn an opacity layer if we have an opacity greater than zero or less than one.
if node.opacity < 1.0 {
// If we've hit max opacity layer capacity skip rendering.
if total_opacity_layers + 1 >= MAX_OPACITY_LAYERS {
return (vec![], current_global_z, total_opacity_layers);
}
// Add in an opacity layer
total_opacity_layers += 1;
let opacity_layer = RenderPrimitive::OpacityLayer {
index: total_opacity_layers,
z: render_primitive.get_layout().z_index,
};
opacity = Some((
node.opacity,
total_opacity_layers,
));
current_opacity_layer = total_opacity_layers;
render_primitives.push(opacity_layer);
}
let _indent = " ".repeat(depth);
if !matches!(render_primitive, RenderPrimitive::Empty) {
// println!("{} [{}, current_global_z: {}, z: {}, x: {}, y: {}, width: {}, height: {}]", _indent, render_primitive.to_string(), current_global_z, layout.z_index, layout.posx, layout.posy, layout.width, layout.height);
render_primitives.push(render_primitive.clone());
}
let new_prev_clip = if matches!(render_primitive, RenderPrimitive::Clip { .. }) {
render_primitive.clone()
} else {
prev_clip
};
prev_clip = new_prev_clip.clone();
if node_tree.children.contains_key(¤t_node) {
let current_parent_global_z = current_global_z;
// let mut z = 1.0f32;
let mut children_primitives = Vec::new();
let children = node_tree.children.get(¤t_node).unwrap();
// let children_count = children.len();
// let original_opacity_layers = opacity_layers;
// let new_z = main_z_index + if node.z < 0.0 { 0.0 } else { node.z } + (z / children_count as f32);
let (mut children_p, _new_global_z, new_total_opacity_layers) = recurse_node_tree_to_build_primitives(
node_tree,
layout_cache,
nodes,
widget_names,
*child,
current_opacity_layer,
total_opacity_layers
total_opacity_layers = new_total_opacity_layers;
// current_global_z = new_global_z;
// z += 1.0;
if children_p.len() > 0 {
// Between each child node we need to reset the clip.
if matches!(prev_clip, RenderPrimitive::Clip { .. }) {
match prev_clip {
RenderPrimitive::Clip {
mut layout,
opacity_layer,
} => {
current_global_z += (UI_Z_STEP * 2.0) * children_p.len() as f32;
layout.z_index = current_global_z;
// println!("{} [previous_clip, z: {}, x: {}, y: {}, width: {}, height: {}", _indent, layout.z_index, layout.posx, layout.posy, layout.width, layout.height);
children_p.push(RenderPrimitive::Clip {
layout,
opacity_layer,
});
if let Ok(_node) = nodes.get(child.0) {
let zz = 0.0; //if node.z < 0.0 { z } else { z + node.z };
children_primitives.push((zz, children_p));
}
// opacity_layers = original_opacity_layers;
// children_primitives.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
for cp in children_primitives.drain(..) {
render_primitives.extend(cp.1);
}
} else {
log::trace!(
"No children for node: {}-{}",
widget_names.get(current_node.0).unwrap().0,
log::error!(
"No render node: {}-{} > {}-{}",
node_tree
.get_parent(current_node)
.map(|v| v.0.index() as i32)
.unwrap_or(-1),
widget_names
.get(
node_tree
.get_parent(current_node)
.map(|v| v.0)
.unwrap_or(Entity::from_raw(0))
)
.map(|v| v.0.clone())
.unwrap_or_else(|_| "None".into()),
widget_names
.get(current_node.0)
.map(|v| v.0.clone())
.unwrap_or_else(|_| "None".into()),
// When an opacity layer has been added all of its children are drawn to the same render target.
// After we need to draw the render target for that opacity layer to the screen.
if let Some((opacity, opacity_layer)) = opacity {
let root_node_layout = layout_cache.rect.get(&node_tree.root_node.unwrap()).unwrap();
current_global_z += UI_Z_STEP * 2.0;
let primitive = RenderPrimitive::DrawOpacityLayer {
opacity,
index: opacity_layer,
z: current_global_z,
layout: *root_node_layout,
};
render_primitives.push(primitive);
}
// dbg!(&render_primitives);
(render_primitives, current_global_z, total_opacity_layers)
/// Updates the widgets
pub fn update_widgets_sys(world: &mut World) {
let mut context_data = Vec::new();
query_world::<Query<(Entity, &mut KayakRootContext)>, _, _>(
|mut query| {
for (entity, mut kayak_root_context) in query.iter_mut() {
context_data.push((entity, std::mem::take(&mut *kayak_root_context)));
for (entity, mut context) in context_data.drain(..) {
for system_id in context.uninitilized_systems.drain() {
if let Some(system) = context.systems.get_mut(&system_id) {
system.0.initialize(world);
system.1.initialize(world);
let tree_iterator = if let Ok(tree) = context.tree.read() {
tree.down_iter().collect::<Vec<_>>()
} else {
panic!("Failed to acquire read lock.");
};
// let change_tick = world.increment_change_tick();
let old_focus = if let Ok(mut focus_tree) = context.focus_tree.try_write() {
let current = focus_tree.current();
focus_tree.clear();
if let Ok(tree) = context.tree.read() {
if let Some(root_node) = tree.root_node {
focus_tree.add(root_node, &tree);
}
}
current
None
};
let mut new_ticks = HashMap::new();
// dbg!("Updating widgets!");
update_widgets(
world,
&context.tree,
&context.layout_cache,
&mut context.systems,
tree_iterator,
&context.context_entities,
&context.focus_tree,
&context.clone_systems,
&context.cloned_widget_entities,
&context.widget_state,
&mut new_ticks,
&context.order_tree,
&context.index,
&context.unique_ids,
&context.unique_ids_parents,
);
if let Some(old_focus) = old_focus {
if let Ok(mut focus_tree) = context.focus_tree.try_write() {
if focus_tree.contains(old_focus) {
focus_tree.focus(old_focus);
}
}
// dbg!("Finished updating widgets!");
let tick = world.read_change_tick();
for (key, system) in context.systems.iter_mut() {
if let Some(new_tick) = new_ticks.get(key) {
system.0.set_last_change_tick(*new_tick);
system.1.set_last_change_tick(*new_tick);
} else {
system.0.set_last_change_tick(tick);
system.1.set_last_change_tick(tick);
}
// system.apply_buffers(world);
}
// Clear out indices
if let Ok(mut indices) = context.index.try_write() {
// for (entity, value) in indices.iter_mut() {
// if tree.root_node.unwrap().0.id() != entity.id() {
// *value = 0;
// }
// }
indices.clear();
}
world.entity_mut(entity).insert(context);
world: &mut World,
tree: &Arc<RwLock<Tree>>,
layout_cache: &Arc<RwLock<LayoutCache>>,
systems: &mut WidgetSystems,
widgets: Vec<WrappedIndex>,
context_entities: &ContextEntities,
focus_tree: &Arc<RwLock<FocusTree>>,
clone_systems: &Arc<RwLock<EntityCloneSystems>>,
cloned_widget_entities: &Arc<RwLock<HashMap<Entity, Entity>>>,
widget_state: &WidgetState,
order_tree: &Arc<RwLock<Tree>>,
index: &Arc<RwLock<HashMap<Entity, usize>>>,
unique_ids: &Arc<RwLock<HashMap<Entity, HashMap<String, Entity>>>>,
unique_ids_parents: &Arc<RwLock<HashMap<Entity, Entity>>>,
// 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(
tree.clone(),
context_entities.clone(),
layout_cache.clone(),
order_tree.clone(),
index.clone(),
unique_ids.clone(),
unique_ids_parents.clone(),
widget_context.copy_from_point(tree, *entity);
let children_before = widget_context.get_children(entity.0);
// let widget_name = widget_type.0.clone();
let (widget_context, should_update_children) = update_widget(
systems,
tree,
world,
*entity,
widget_type.0.clone(),
widget_context,
children_before,
clone_systems,
cloned_widget_entities,
widget_state,
order_tree,
unique_ids,
unique_ids_parents,
);
if should_update_children {
if let Ok(mut tree) = tree.write() {
let diff = tree.diff_children(&widget_context, *entity, UPDATE_DEPTH);
for (_index, child, _parent, changes) in diff.changes.iter() {
if changes
.iter()
.any(|change| matches!(change, Change::Inserted))
{
if let Ok(mut cache) = layout_cache.try_write() {
cache.add(*child);
}
}
if changes
.iter()
.any(|change| matches!(change, Change::Deleted))
{
// tree.dump();
// dbg!(&diff);
// }
tree.merge(&widget_context, *entity, diff, UPDATE_DEPTH);
// if _had_removal {
// tree.dump();
// }
for child in widget_context.child_iter(*entity) {
if let Some(mut entity_commands) = world.get_entity_mut(child.0) {
entity_commands.insert(DirtyNode);
}
}
let children = if let Ok(tree) = tree.read() {
tree.child_iter(*entity).collect::<Vec<_>>()
} else {
vec![]
};
world,
tree,
layout_cache,
systems,
children,
context_entities,
focus_tree,
clone_systems,
cloned_widget_entities,
widget_state,
} 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) {
if entity_ref.contains::<Focusable>() {
if let Ok(tree) = tree.try_read() {
if let Ok(mut focus_tree) = focus_tree.try_write() {
focus_tree.add(*entity, &tree);
}
}
}
}
}
}
fn update_widget(
systems: &mut WidgetSystems,
tree: &Arc<RwLock<Tree>>,
world: &mut World,
entity: WrappedIndex,
widget_type: String,
widget_context: KayakWidgetContext,
clone_systems: &Arc<RwLock<EntityCloneSystems>>,
cloned_widget_entities: &Arc<RwLock<HashMap<Entity, Entity>>>,
widget_state: &WidgetState,
order_tree: &Arc<RwLock<Tree>>,
unique_ids: &Arc<RwLock<HashMap<Entity, HashMap<String, Entity>>>>,
unique_ids_parents: &Arc<RwLock<HashMap<Entity, Entity>>>,
// Check if we should update this widget
let should_rerender = {
let old_props_entity =
if let Ok(mut cloned_widget_entities) = cloned_widget_entities.try_write() {
let old_parent_entity = if let Ok(tree) = tree.try_read() {
if let Some(parent_entity) = tree.get_parent(entity) {
cloned_widget_entities.get(&parent_entity.0).copied()
} else {
None
}
if let Some(entity) = cloned_widget_entities.get(&entity.0).copied() {
if let Some(possible_entity) = world.get_entity(entity) {
let target = possible_entity.id();
cloned_widget_entities.insert(entity, target);
target
} else {
let target = world.spawn_empty().insert(PreviousWidget).id();
if let Some(parent_id) = old_parent_entity {
world.entity_mut(parent_id).add_child(target);
}
cloned_widget_entities.insert(entity, target);
target
}
} else {
let target = world.spawn_empty().insert(PreviousWidget).id();
if let Some(parent_id) = old_parent_entity {
world.entity_mut(parent_id).add_child(target);
}
cloned_widget_entities.insert(entity.0, target);
target
}
} else {
panic!("Couldn't get write lock!")
};
let widget_update_system = &mut systems
.get_mut(&widget_type)
.expect(&format!(
"Wasn't able to find render/update systems for widget: {}!",
widget_type
))
.0;
let old_tick = widget_update_system.get_last_change_tick();
let should_rerender =
widget_update_system.run((widget_context.clone(), entity.0, old_props_entity), world);
let new_tick = widget_update_system.get_last_change_tick();
new_ticks.insert(widget_type.clone(), new_tick);
widget_update_system.set_last_change_tick(old_tick);
widget_update_system.apply_buffers(world);