use bevy::{ prelude::{Assets, Commands, Entity, In, Query, Res, With}, utils::HashMap, }; use kayak_font::{KayakFont, TextProperties}; use morphorm::Hierarchy; use crate::{ layout::{DataCache, Rect}, node::{DirtyNode, Node, NodeBuilder, WrappedIndex}, prelude::{KStyle, KayakRootContext, Tree}, render::font::FontMapping, styles::{ComputedStyles, RenderCommand, StyleProp, Units}, }; pub fn calculate_nodes( In(mut context): In<KayakRootContext>, mut commands: Commands, fonts: Res<Assets<KayakFont>>, font_mapping: Res<FontMapping>, query: Query<Entity, With<DirtyNode>>, all_styles_query: Query<&ComputedStyles>, node_query: Query<(Entity, &Node)>, // widget_names: Query<&WidgetName>, ) -> KayakRootContext { let mut new_nodes = HashMap::<Entity, (Node, bool)>::default(); context.current_z = 0.0; let initial_styles = KStyle::initial(); let default_styles = KStyle { opacity: StyleProp::Value(1.0), ..KStyle::new_default() }; if let Ok(tree) = context.tree.clone().try_read() { if tree.root_node.is_none() { return context; } let mut dirty_entities = query.iter().collect::<Vec<_>>(); dirty_entities.sort_unstable_by(|a, b| a.index().partial_cmp(&b.index()).unwrap()); for dirty_entity in dirty_entities { let dirty_entity = WrappedIndex(dirty_entity); if !tree.contains(dirty_entity) { continue; } let styles = all_styles_query.get(dirty_entity.0).map(|cs| &cs.0); let styles = styles.unwrap_or(&default_styles); // Get the parent styles. Will be one of the following: // 1. Already-resolved node styles (best) // 2. Unresolved widget prop styles // 3. Unresolved default styles let parent_styles = if let Some(parent_widget_id) = tree.parents.get(&dirty_entity) { if let Some(parent_node) = new_nodes.get(&parent_widget_id.0) { parent_node.0.resolved_styles.clone() } else if let Ok((_, parent_node)) = node_query.get(parent_widget_id.0) { parent_node.resolved_styles.clone() } else if let Ok(parent_styles) = all_styles_query.get(parent_widget_id.0) { parent_styles.0.clone() } else { default_styles.clone() } } else { default_styles.clone() }; // let parent_z = if let Some(parent_widget_id) = tree.parents.get(&dirty_entity) { // if let Some(parent_node) = new_nodes.get(&parent_widget_id.0) { // parent_node.0.z // } else if let Ok((_, parent_node)) = node_query.get(parent_widget_id.0) { // parent_node.z // } else { // if let Ok(parent_styles) = all_styles_query.get(parent_widget_id.0) { // parent_styles.z_index.resolve() as f32 // } else { // -1.0 // } // } // } else { // -1.0 // }; let raw_styles = styles.clone(); let mut styles = raw_styles.clone(); // Fill in all `initial` values for any unset property styles.apply(&initial_styles); // Fill in all `inherited` values for any `inherit` property styles.inherit(&parent_styles); // Lock opacity so the max opacity for a child is the opacity of the parent. // if let StyleProp::Value(opacity) = &mut styles.opacity { // if let StyleProp::Value(parent_opacity) = &parent_styles.opacity { // *opacity = opacity.min(*parent_opacity); // } // } else { // styles.opacity = parent_styles.opacity.clone(); // } // if let StyleProp::Value(opacity) = &mut styles.opacity { // if let StyleProp::Value(background_color) = &mut styles.background_color { // // Apply opacity to background_color // background_color.set_a(opacity.min(background_color.a())); // } else { // styles.background_color = Color::rgba(1.0, 1.0, 1.0, *opacity).into(); // } // if let StyleProp::Value(color) = &mut styles.color { // // Apply opacity to color // color.set_a(opacity.min(color.a())); // } else { // styles.color = Color::rgba(1.0, 1.0, 1.0, *opacity).into(); // } // if let StyleProp::Value(border_color) = &mut styles.border_color { // // Apply opacity to border_color // border_color.set_a(opacity.min(border_color.a())); // } else { // styles.border_color = Color::rgba(1.0, 1.0, 1.0, *opacity).into(); // } // } // let mut current_z = { // if parent_z > -1.0 { // parent_z + 1.0 // } else { // let z = context.current_z; // context.current_z += 1.0; // z // } // }; let current_z = if matches!(styles.z_index, StyleProp::Value(..)) { styles.z_index.resolve() as f32 } else { -1.0 }; let needs_layout = create_primitive( &mut commands, &context, &fonts, &font_mapping, &query, // &node_query, dirty_entity, &mut styles, node_query .get(dirty_entity.0) .map(|(_, node)| node.raw_styles.clone().unwrap_or_default()) .unwrap_or_default(), &all_styles_query, ); let children = tree .children .get(&dirty_entity) .cloned() .unwrap_or_default(); // If a parent updates the children need to as well. // for child in children.iter() { // commands.entity(child.0).insert(DirtyNode); // } let width = styles.width.resolve().value_or(0.0, 0.0); let height = styles.height.resolve().value_or(0.0, 0.0); let opacity = styles.opacity.resolve_or(1.0); let mut node: Node = NodeBuilder::empty() .with_id(dirty_entity) .with_styles(styles, Some(raw_styles)) .with_children(children) .with_opacity(opacity) .build(); if dirty_entity == tree.root_node.unwrap() { if let Ok(mut cache) = context.layout_cache.try_write() { cache.rect.insert( dirty_entity, Rect { posx: 0.0, posy: 0.0, width, height, z_index: None, }, ); } } node.old_z = node_query .get(dirty_entity.0) .map(|old_node| old_node.1.z) .unwrap_or(0.0); node.z = current_z; new_nodes.insert(dirty_entity.0, (node, needs_layout)); } for (entity, (node, needs_layout)) in new_nodes.drain() { if !needs_layout { commands.entity(entity).remove::<DirtyNode>(); } else { log::trace!("{:?} needs layout!", entity.index()); } commands.entity(entity).insert(node); } } context } pub fn calculate_layout( In(context): In<KayakRootContext>, mut commands: Commands, nodes_no_entity_query: Query<&'static Node>, ) -> KayakRootContext { 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) { // log::info!("Layout changed for: {:?}", child.0.id()); if let Some(mut entity_commands) = commands.get_entity(child.0) { entity_commands.insert(DirtyNode); } } } } } } context } fn create_primitive( commands: &mut Commands, context: &KayakRootContext, fonts: &Assets<KayakFont>, font_mapping: &FontMapping, // query: &Query<(Entity, &Node)>, dirty: &Query<Entity, With<DirtyNode>>, id: WrappedIndex, styles: &mut KStyle, _prev_styles: KStyle, all_styles_query: &Query<&ComputedStyles>, ) -> bool { let mut needs_layout = true; if let StyleProp::Value(render_command) = &mut styles.render_command { match render_command { RenderCommand::Text { alignment, content, word_wrap, text_layout, properties, .. } => { let font = styles .font .resolve_or_else(|| String::from(crate::DEFAULT_FONT)); // --- Bind to Font Asset --- // let font_handle = font_mapping.get_handle(font).unwrap(); if let Some(font) = fonts.get(&font_handle) { if let Ok(node_tree) = context.tree.try_read() { if let Some(parent_id) = find_not_empty_parent(&node_tree, all_styles_query, &id) { if let Some(parent_layout) = context.get_layout(&parent_id) { let border_x = if let Ok(style) = all_styles_query.get(parent_id.0) { let border = style.0.border.resolve(); border.left + border.right } else { 0.0 }; let border_y = if let Ok(style) = all_styles_query.get(parent_id.0) { let border = style.0.border.resolve(); border.top + border.bottom } else { 0.0 }; let font_size = styles.font_size.resolve_or(14.0); *properties = TextProperties { font_size, line_height: styles.line_height.resolve_or(font_size * 1.2), alignment: *alignment, ..*properties }; properties.max_size = ( parent_layout.width - border_x, parent_layout.height - border_y, ); // TODO: Fix this hack. if !*word_wrap { properties.max_size.0 = 100000.0; } needs_layout = false; if properties.max_size.0 == 0.0 || properties.max_size.1 == 0.0 { needs_layout = true; } if context.get_geometry_changed(&parent_id) { needs_layout = true; } if dirty.contains(parent_id.0) { needs_layout = true; } // --- Calculate Text Layout --- // *text_layout = font.measure(content, *properties); let measurement = text_layout.size(); log::trace!( "Text Node: {}, has a measurement of: {:?}, it's parent takes up: {:?}", &content, measurement, properties.max_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)); } } else { log::trace!("no layout for: {:?}", parent_id.0.index()); } } else { log::trace!("No parent found for: {:?}", id.0.index()); } } } } _ => { needs_layout = false; } } } if needs_layout { commands.entity(id.0).insert(DirtyNode); } // If we have data from the previous frame no need to do anything here! // if matches!(prev_styles.width, StyleProp::Value(..)) { // styles.width = prev_styles.width; // styles.height = prev_styles.height; // needs_layout = false; // } needs_layout } pub fn find_not_empty_parent( tree: &Tree, all_styles_query: &Query<&ComputedStyles>, node: &WrappedIndex, ) -> Option<WrappedIndex> { if let Some(parent) = tree.parent(*node) { if let Ok(styles) = all_styles_query.get(parent.0) { if matches!(styles.0.render_command.resolve(), RenderCommand::Empty) || matches!(styles.0.render_command.resolve(), RenderCommand::Layout) { find_not_empty_parent(tree, all_styles_query, &parent) } else { Some(parent) } } else { find_not_empty_parent(tree, all_styles_query, &parent) } } else { None } } // pub fn build_nodes_tree(context: &mut Context, tree: &Tree, node_query: &Query<(Entity, &Node)>) { // if tree.root_node.is_none() { // return; // } // let mut node_tree = Tree::default(); // node_tree.root_node = tree.root_node; // node_tree.children.insert( // tree.root_node.unwrap(), // get_valid_node_children(&tree, &node_query, tree.root_node.unwrap()), // ); // // let old_focus = self.focus_tree.current(); // // self.focus_tree.clear(); // // self.focus_tree.add(root_node_id, &self.tree); // for (node_id, node) in node_query.iter() { // let node_id = WrappedIndex(node_id); // if let Some(widget_styles) = node.raw_styles.as_ref() { // // Only add widgets who have renderable nodes. // // if widget_styles.render_command.resolve() != RenderCommand::Empty { // let valid_children = get_valid_node_children(&tree, &node_query, node_id); // node_tree.children.insert(node_id, valid_children); // let valid_parent = get_valid_parent(&tree, &node_query, node_id); // if let Some(valid_parent) = valid_parent { // node_tree.parents.insert(node_id, valid_parent); // } // // } // } // // let focusable = self.get_focusable(widget_id).unwrap_or_default(); // // if focusable { // // self.focus_tree.add(widget_id, &self.tree); // // } // } // // if let Some(old_focus) = old_focus { // // if self.focus_tree.contains(old_focus) { // // self.focus_tree.focus(old_focus); // // } // // } // // dbg!(&node_tree); // // context.node_tree = node_tree; // } // pub fn get_valid_node_children( // tree: &Tree, // query: &Query<(Entity, &Node)>, // node_id: WrappedIndex, // ) -> Vec<WrappedIndex> { // let mut children = Vec::new(); // if let Some(node_children) = tree.children.get(&node_id) { // for child_id in node_children { // if let Ok((_, _child_node)) = query.get(child_id.0) { // // if child_node.resolved_styles.render_command.resolve() != RenderCommand::Empty { // children.push(*child_id); // // } else { // // children.extend(get_valid_node_children(tree, query, *child_id)); // // } // } else { // // children.extend(get_valid_node_children(tree, query, *child_id)); // } // } // } // children // } // pub fn get_valid_parent( // tree: &Tree, // query: &Query<(Entity, &Node)>, // node_id: WrappedIndex, // ) -> Option<WrappedIndex> { // if let Some(parent_id) = tree.parents.get(&node_id) { // if let Ok((_, parent_node)) = query.get(parent_id.0) { // // if parent_node.resolved_styles.render_command.resolve() != RenderCommand::Empty { // return Some(*parent_id); // // } // } // // return get_valid_parent(tree, query, *parent_id); // } // None // }