diff --git a/book/src/chapter_2.md b/book/src/chapter_2.md index 8782e06df3518eee37931e0320fe9e849f563d83..3abec0b72c2e25894df3cbf52ce4b4f8b0cfb0d1 100644 --- a/book/src/chapter_2.md +++ b/book/src/chapter_2.md @@ -8,7 +8,8 @@ Kayak UI builds out UI using a tree structure. A widget can be defined as any ob ### Widgets are entities Kayak UI uses Bevy ECS. Each widget is considered an entity with a collection of data. Typically an widget and it's entity can contain whatever data desired, but some common components are: - Mount - A component tag used to know that a widget was spawned and added to the tree. -- KStyle - Used to describe how a widget looks. Kayak uses this component to dictate UI rendering. +- KStyle - Used to pass in styles from outside of a widget. +- ComputedStyles - The actual styles of a widget. Styles define the look and layout of the widget. Kayak uses this component to dictate UI rendering. - KChildren - A collection of entities that are added to the tree in a deferred way. These entities are coming from higher up the hierarchy. - OnEvent - A mini/micro bevy system that lets you respond to UI input events. - OnChange - A mini/micro system which allows changes to state based on value changes to state. @@ -23,6 +24,7 @@ It's advised to have bundles that correspond to a group of components on a widge pub struct BackgroundBundle { pub background: Background, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub on_event: OnEvent, pub widget_name: WidgetName, diff --git a/book/src/chapter_3.md b/book/src/chapter_3.md index 256b25e6f0143cbd5a2727e284674e05054ed77c..4ee11e239e98d0a3e2347ce3c6c2335624eaf51c 100644 --- a/book/src/chapter_3.md +++ b/book/src/chapter_3.md @@ -27,6 +27,7 @@ impl Widget for MyButtonProps { } pub struct MyButtonBundle { pub props: MyButtonProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, // This allows us to hook into on click events! pub on_event: OnEvent, @@ -39,6 +40,7 @@ impl Default for MyButtonBundle { Self { props: MyButtonProps::default(), styles: KStyle::default(), + computed_styles: ComputedStyles::default(), children: KChildren::default(), on_event: OnEvent::default(), // Kayak uses this component to find out more information about your widget. @@ -76,6 +78,7 @@ pub fn my_button_render( rsx! { <BackgroundBundle + styles={background_styles} // We pass the children to the background bundle! children={children.clone()} /> diff --git a/examples/bevy_scene.rs b/examples/bevy_scene.rs index 096ee9f9f901cbb67fa6ec05682308352a500a5c..7e77f0c4c351792f1a5ad48c5f45d79733faf50b 100644 --- a/examples/bevy_scene.rs +++ b/examples/bevy_scene.rs @@ -225,10 +225,10 @@ fn startup( }} > <TextWidgetBundle + styles={text_styles.clone()} text={TextProps { size: 13.0, content: "You can check if the cursor is over the UI or on a focusable widget using the BevyContext resource.".to_string(), - user_styles: text_styles.clone(), ..Default::default() }} /> @@ -241,13 +241,13 @@ fn startup( styles={button_styles} /> <TextWidgetBundle + styles={KStyle { + top: Units::Pixels(10.0).into(), + ..text_styles + }} text={TextProps { size: 11.0, content: "Go ahead and click the button! The tile won't move.".to_string(), - user_styles: KStyle { - top: Units::Pixels(10.0).into(), - ..text_styles - }, ..Default::default() }} /> diff --git a/examples/conditional_widget.rs b/examples/conditional_widget.rs index 6c652ac76a6dabbbd7a2c6c4f0de094dd7602de0..42476e4df8a16797810c83e7f029a3857c493473 100644 --- a/examples/conditional_widget.rs +++ b/examples/conditional_widget.rs @@ -39,13 +39,13 @@ fn my_widget_render( rsx! { <ElementBundle> <KButtonBundle + styles={KStyle { + left: Units::Stretch(1.0).into(), + right: Units::Stretch(1.0).into(), + ..Default::default() + }} button={KButton { text: "Show Window".into(), - user_styles: KStyle { - left: Units::Stretch(1.0).into(), - right: Units::Stretch(1.0).into(), - ..Default::default() - } }} on_event={OnEvent::new( move |In((event_dispatcher_context, _, mut event, _entity)): In<(EventDispatcherContext, WidgetState, Event, Entity)>, diff --git a/examples/context.rs b/examples/context.rs index aa3696f59c8a94ccbcd584620bfba509ce0e9688..9523f64fdebaa7fed2e38f6e4388c16bb05c9de3 100644 --- a/examples/context.rs +++ b/examples/context.rs @@ -256,14 +256,14 @@ fn update_theme_demo( rsx! { <ElementBundle> <TextWidgetBundle + styles={KStyle { + height: StyleProp::Value(Units::Pixels(28.0)), + ..Default::default() + }} text={TextProps { content: select_lbl, size: 14.0, line_height: Some(28.0), - user_styles: KStyle { - height: StyleProp::Value(Units::Pixels(28.0)), - ..Default::default() - }, ..Default::default() }} /> @@ -278,10 +278,10 @@ fn update_theme_demo( }} > <TextWidgetBundle + styles={text_styles} text={TextProps { content: "Lorem ipsum dolor...".into(), size: 12.0, - user_styles: text_styles, ..Default::default() }} /> diff --git a/examples/main_menu.rs b/examples/main_menu.rs index 467dc38ede2ef83a8c22635cd8627f436d084d9c..c59c2d4042eb0314001d83166cf3ba450ff62402 100644 --- a/examples/main_menu.rs +++ b/examples/main_menu.rs @@ -91,16 +91,15 @@ fn menu_button_render( on_event={on_event} > <TextWidgetBundle + styles={KStyle { + top: Units::Stretch(1.0).into(), + bottom: Units::Stretch(1.0).into(), + ..Default::default() + }} text={TextProps { alignment: Alignment::Middle, content: button_text, size: 28.0, - user_styles: KStyle { - // top: Units::Stretch(1.0).into(), - top: Units::Pixels(-16.0).into(), - height: Units::Pixels(40.0).into(), - ..Default::default() - }, ..Default::default() }} /> diff --git a/examples/quads.rs b/examples/quads.rs index e0afabedbe25817f52a5b68a6e396174380d72f9..9bd772229ff1035c9851805798c2cee402a306c9 100644 --- a/examples/quads.rs +++ b/examples/quads.rs @@ -14,19 +14,26 @@ pub struct MyQuad { fn my_quad_update( In((_widget_context, entity)): In<(KayakWidgetContext, Entity)>, - mut query: Query<(&MyQuad, &mut KStyle, &mut OnEvent)>, + mut query: Query<(&MyQuad, &KStyle, &mut ComputedStyles, &mut OnEvent)>, ) -> bool { - if let Ok((quad, mut style, mut on_event)) = query.get_mut(entity) { - if style.render_command.resolve() != RenderCommand::Quad { - style.render_command = StyleProp::Value(RenderCommand::Quad); - style.position_type = StyleProp::Value(KPositionType::SelfDirected); - style.left = StyleProp::Value(Units::Pixels(quad.pos.x)); - style.top = StyleProp::Value(Units::Pixels(quad.pos.y)); - style.width = StyleProp::Value(Units::Pixels(quad.size.x)); - style.height = StyleProp::Value(Units::Pixels(quad.size.y)); - style.background_color = StyleProp::Value(quad.color); - style.z_index = StyleProp::Value(quad.z_index); - } + if let Ok((quad, style, mut computed_styles, mut on_event)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: StyleProp::Value(RenderCommand::Quad), + position_type: StyleProp::Value(KPositionType::SelfDirected), + left: StyleProp::Value(Units::Pixels(quad.pos.x)), + top: StyleProp::Value(Units::Pixels(quad.pos.y)), + width: StyleProp::Value(Units::Pixels(quad.size.x)), + height: StyleProp::Value(Units::Pixels(quad.size.y)), + z_index: StyleProp::Value(quad.z_index), + ..Default::default() + }) + .with_style(style) + .with_style(KStyle { + background_color: StyleProp::Value(quad.color), + ..Default::default() + }) + .into(); *on_event = OnEvent::new( move |In((event_dispatcher_context, _, mut event, entity)): In<( @@ -65,6 +72,7 @@ impl Widget for MyQuad {} pub struct MyQuadBundle { my_quad: MyQuad, styles: KStyle, + computed_styles: ComputedStyles, on_event: OnEvent, widget_name: WidgetName, } @@ -75,6 +83,7 @@ impl Default for MyQuadBundle { my_quad: Default::default(), styles: KStyle::default(), on_event: OnEvent::default(), + computed_styles: ComputedStyles::default(), widget_name: MyQuad::default().get_name(), } } diff --git a/examples/simple_state.rs b/examples/simple_state.rs index 0042d2684a05abd4977c1d00e391772e94a734cc..a427a40c0b11f4ab892ac408aefe3c91ee9097c7 100644 --- a/examples/simple_state.rs +++ b/examples/simple_state.rs @@ -15,6 +15,7 @@ struct CurrentCountState { struct CurrentCountBundle { count: CurrentCount, styles: KStyle, + computed_styles: ComputedStyles, widget_name: WidgetName, } @@ -23,6 +24,7 @@ impl Default for CurrentCountBundle { Self { count: CurrentCount::default(), styles: KStyle::default(), + computed_styles: ComputedStyles::default(), widget_name: CurrentCount::default().get_name(), } } diff --git a/examples/tabs/tab_button.rs b/examples/tabs/tab_button.rs index d9ca5dccc2c7cb5996648725ab516499a5760a1a..440afd8918e7784bbe508100be4ba69c62e27c24 100644 --- a/examples/tabs/tab_button.rs +++ b/examples/tabs/tab_button.rs @@ -75,14 +75,14 @@ pub fn tab_button_render( rsx! { <KButtonBundle + styles={KStyle { + background_color: StyleProp::Value(background_color), + border_radius: Corner::all(0.0).into(), + height: StyleProp::Value(Units::Pixels(25.0)), + ..Default::default() + }} button={KButton { text: tab_button.title.clone(), - user_styles: KStyle { - background_color: StyleProp::Value(background_color), - border_radius: Corner::all(0.0).into(), - height: StyleProp::Value(Units::Pixels(25.0)), - ..Default::default() - }, }} on_event={on_event} /> diff --git a/examples/text.rs b/examples/text.rs index b2f82d38f691c2012a5a13f6e94013457b9da7e9..142c89d9c8fe4a7126932630f76738f721e2c32a 100644 --- a/examples/text.rs +++ b/examples/text.rs @@ -9,18 +9,23 @@ pub struct MyWidgetProps { fn my_widget_1_render( In((_widget_context, entity)): In<(KayakWidgetContext, Entity)>, my_resource: Res<MyResource>, - mut query: Query<(&mut MyWidgetProps, &mut KStyle)>, + mut query: Query<(&mut MyWidgetProps, &KStyle, &mut ComputedStyles)>, ) -> bool { - if let Ok((mut my_widget, mut style)) = query.get_mut(entity) { + if let Ok((mut my_widget, style, mut computed_styles)) = query.get_mut(entity) { my_widget.foo = my_resource.0; dbg!(my_widget.foo); // Note: We will see two updates because of the mutable change to styles. // Which means when foo changes MyWidget will render twice! - style.render_command = StyleProp::Value(RenderCommand::Text { - content: format!("My number is: {}", my_widget.foo), - alignment: Alignment::Start, - word_wrap: false, - }); + *computed_styles = KStyle { + render_command: StyleProp::Value(RenderCommand::Text { + content: format!("My number is: {}", my_widget.foo), + alignment: Alignment::Start, + word_wrap: false, + }), + ..Default::default() + } + .with_style(style) + .into(); } true @@ -44,6 +49,7 @@ impl Widget for MyWidgetProps {} pub struct MyWidgetBundle { props: MyWidgetProps, styles: KStyle, + computed_styles: ComputedStyles, widget_name: WidgetName, } @@ -52,6 +58,7 @@ impl Default for MyWidgetBundle { Self { props: Default::default(), styles: Default::default(), + computed_styles: Default::default(), widget_name: MyWidgetProps::default().get_name(), } } diff --git a/examples/todo/input.rs b/examples/todo/input.rs index 12120651cea94a8aa4643d6b3f55fc19f28b0bbc..8080596ab9ce442bd617dd3eab1b4d77f734ba02 100644 --- a/examples/todo/input.rs +++ b/examples/todo/input.rs @@ -13,6 +13,7 @@ pub struct TodoInputBundle { pub widget: TodoInputProps, pub focusable: Focusable, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -21,14 +22,15 @@ impl Default for TodoInputBundle { Self { widget: TodoInputProps::default(), focusable: Default::default(), - styles: KStyle { + styles: KStyle::default(), + computed_styles: ComputedStyles(KStyle { render_command: StyleProp::Value(RenderCommand::Layout), // height: StyleProp::Value(Units::Stretch(1.0)), height: StyleProp::Value(Units::Auto), width: StyleProp::Value(Units::Stretch(1.0)), bottom: StyleProp::Value(Units::Pixels(20.0)), ..KStyle::default() - }, + }), widget_name: TodoInputProps::default().get_name(), } } @@ -85,8 +87,8 @@ pub fn render_todo_input( } <TextBoxBundle styles={KStyle { - bottom: StyleProp::Value(Units::Stretch(1.0)), - top: StyleProp::Value(Units::Stretch(1.0)), + // bottom: StyleProp::Value(Units::Stretch(1.0)), + // top: StyleProp::Value(Units::Stretch(1.0)), ..Default::default() }} text_box={TextBoxProps { @@ -97,14 +99,14 @@ pub fn render_todo_input( on_change={on_change} /> <KButtonBundle + styles={KStyle { + width: StyleProp::Value(Units::Pixels(32.0)), + height: StyleProp::Value(Units::Pixels(32.0)), + left: StyleProp::Value(Units::Pixels(5.0)), + ..Default::default() + }} button={KButton { text: "+".into(), - user_styles: KStyle { - width: StyleProp::Value(Units::Pixels(32.0)), - height: StyleProp::Value(Units::Pixels(32.0)), - left: StyleProp::Value(Units::Pixels(5.0)), - ..Default::default() - } }} on_event={handle_click} /> diff --git a/examples/todo/items.rs b/examples/todo/items.rs index 99c802c71bd50e4ebab2613c1007323748dfcfca..4af3366942d762db2b1f751258723e75f25e0afd 100644 --- a/examples/todo/items.rs +++ b/examples/todo/items.rs @@ -12,6 +12,7 @@ impl Widget for TodoItemsProps {} pub struct TodoItemsBundle { pub widget: TodoItemsProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -19,12 +20,13 @@ impl Default for TodoItemsBundle { fn default() -> Self { Self { widget: TodoItemsProps::default(), - styles: KStyle { + styles: KStyle::default(), + computed_styles: ComputedStyles(KStyle { render_command: StyleProp::Value(RenderCommand::Layout), height: StyleProp::Value(Units::Auto), width: StyleProp::Value(Units::Stretch(1.0)), ..KStyle::default() - }, + }), widget_name: TodoItemsProps::default().get_name(), } } @@ -75,26 +77,26 @@ pub fn render_todo_items( }} > <TextWidgetBundle + styles={KStyle { + right: StyleProp::Value(Units::Stretch(1.0)), + top: StyleProp::Value(Units::Stretch(1.0)), + bottom: StyleProp::Value(Units::Stretch(1.0)), + ..Default::default() + }} text={TextProps { content: content.clone(), - user_styles: KStyle { - right: StyleProp::Value(Units::Stretch(1.0)), - top: StyleProp::Value(Units::Stretch(1.0)), - bottom: StyleProp::Value(Units::Stretch(1.0)), - ..Default::default() - }, ..Default::default() }} /> <KButtonBundle + styles={KStyle { + width: StyleProp::Value(Units::Pixels(32.0)), + height: StyleProp::Value(Units::Pixels(32.0)), + left: StyleProp::Value(Units::Pixels(15.0)), + ..Default::default() + }} button={KButton { text: "X".into(), - user_styles: KStyle { - width: StyleProp::Value(Units::Pixels(32.0)), - height: StyleProp::Value(Units::Pixels(32.0)), - left: StyleProp::Value(Units::Pixels(15.0)), - ..Default::default() - } }} on_event={handle_click} /> diff --git a/examples/vec.rs b/examples/vec.rs index 4d9daf3316a2afd0a860358793400a86bde43b02..adb28c31ac3fc3ca5d17d9a1f2db5d776d898b72 100644 --- a/examples/vec.rs +++ b/examples/vec.rs @@ -40,7 +40,6 @@ impl Widget for MyWidgetProps {} #[derive(Bundle)] pub struct MyWidgetBundle { props: MyWidgetProps, - styles: KStyle, widget_name: WidgetName, } @@ -48,7 +47,6 @@ impl Default for MyWidgetBundle { fn default() -> Self { Self { props: Default::default(), - styles: Default::default(), widget_name: MyWidgetProps::default().get_name(), } } diff --git a/src/calculate_nodes.rs b/src/calculate_nodes.rs index 1a6257e85e29379719e0d037548199e0b47c8184..ad396a671d48b7749c2ad0771a9c1dacdfdb89fa 100644 --- a/src/calculate_nodes.rs +++ b/src/calculate_nodes.rs @@ -11,7 +11,7 @@ use crate::{ prelude::{KStyle, KayakRootContext, Tree}, render::font::FontMapping, render_primitive::RenderPrimitive, - styles::{RenderCommand, StyleProp, Units}, + styles::{ComputedStyles, RenderCommand, StyleProp, Units}, }; pub fn calculate_nodes( @@ -20,7 +20,7 @@ pub fn calculate_nodes( fonts: Res<Assets<KayakFont>>, font_mapping: Res<FontMapping>, query: Query<Entity, With<DirtyNode>>, - all_styles_query: Query<&KStyle>, + all_styles_query: Query<&ComputedStyles>, node_query: Query<(Entity, &Node)>, ) -> KayakRootContext { let mut new_nodes = HashMap::<Entity, (Node, bool)>::default(); @@ -43,6 +43,7 @@ pub fn calculate_nodes( let styles = all_styles_query .get(dirty_entity.0) + .map(|cs| &cs.0) .unwrap_or(&default_styles); // Get the parent styles. Will be one of the following: // 1. Already-resolved node styles (best) @@ -54,7 +55,7 @@ pub fn calculate_nodes( } 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.clone() + parent_styles.0.clone() } else { default_styles.clone() } @@ -211,8 +212,8 @@ fn create_primitive( dirty: &Query<Entity, With<DirtyNode>>, id: WrappedIndex, styles: &mut KStyle, - prev_styles: KStyle, - all_styles_query: &Query<&KStyle>, + _prev_styles: KStyle, + all_styles_query: &Query<&ComputedStyles>, ) -> (RenderPrimitive, bool) { let mut render_primitive = RenderPrimitive::from(&styles.clone()); let mut needs_layout = true; @@ -229,20 +230,19 @@ fn create_primitive( // --- Bind to Font Asset --- // let font_handle = font_mapping.get_handle(font.clone()).unwrap(); if let Some(font) = fonts.get(&font_handle) { - // self.bind(id, &asset); 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.border.resolve(); + 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.border.resolve(); + let border = style.0.border.resolve(); border.top + border.bottom } else { 0.0 @@ -308,24 +308,24 @@ fn create_primitive( } // 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; - } + // if matches!(prev_styles.width, StyleProp::Value(..)) { + // styles.width = prev_styles.width; + // styles.height = prev_styles.height; + // needs_layout = false; + // } (render_primitive, needs_layout) } pub fn find_not_empty_parent( tree: &Tree, - all_styles_query: &Query<&KStyle>, + 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.render_command.resolve(), RenderCommand::Empty) - || matches!(styles.render_command.resolve(), RenderCommand::Layout) + 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 { diff --git a/src/context.rs b/src/context.rs index 0d88087bbce52f6968339a7a58e91b8713d7acde..ac9b8b8e36bdf32896d70b976966ce47c12eb691 100644 --- a/src/context.rs +++ b/src/context.rs @@ -22,8 +22,8 @@ use crate::{ prelude::KayakWidgetContext, render_primitive::RenderPrimitive, styles::{ - Corner, Edge, KCursorIcon, KPositionType, KStyle, LayoutType, RenderCommand, StyleProp, - Units, + ComputedStyles, Corner, Edge, KCursorIcon, KPositionType, KStyle, LayoutType, + RenderCommand, StyleProp, Units, }, tree::{Change, Tree}, widget_state::WidgetState, @@ -821,6 +821,13 @@ fn update_widget( entity.insert(styles); } } + if let Some(styles) = + world.entity(entity.0).get::<ComputedStyles>().cloned() + { + if let Some(mut entity) = world.get_entity_mut(*target_entity) { + entity.insert(styles); + } + } if let Some(children) = world.entity(entity.0).get::<KChildren>().cloned() { @@ -928,6 +935,11 @@ fn update_widget( entity.insert(styles); } } + if let Some(styles) = world.entity(entity.0).get::<ComputedStyles>().cloned() { + if let Some(mut entity) = world.get_entity_mut(*target_entity) { + entity.insert(styles); + } + } if let Some(children) = world.entity(entity.0).get::<KChildren>().cloned() { if let Some(mut entity) = world.get_entity_mut(*target_entity) { entity.insert(children); @@ -985,7 +997,8 @@ impl Plugin for KayakContextPlugin { // Register reflection types. // A bit annoying.. - app.register_type::<KStyle>() + app.register_type::<ComputedStyles>() + .register_type::<KStyle>() .register_type::<KChildren>() .register_type::<WidgetName>() .register_type::<StyleProp<Color>>() diff --git a/src/event_dispatcher.rs b/src/event_dispatcher.rs index ac64268c891159b2d5a294f7f75ba48fba21e5ef..e0750a80b84928459de9798232ec6761ce6ff972 100644 --- a/src/event_dispatcher.rs +++ b/src/event_dispatcher.rs @@ -14,7 +14,7 @@ use crate::{ node::{Node, WrappedIndex}, on_event::OnEvent, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand}, + styles::{ComputedStyles, KStyle, RenderCommand}, Focusable, }; @@ -557,9 +557,9 @@ impl EventDispatcher { } } if self.contains_cursor.is_none() || !self.contains_cursor.unwrap_or_default() { - if let Some(styles) = world.get::<KStyle>(node.0) { + if let Some(styles) = world.get::<ComputedStyles>(node.0) { // Check if the cursor moved onto a widget that qualifies as one that can contain it - if ignore_layout || Self::can_contain_cursor(styles) { + if ignore_layout || Self::can_contain_cursor(&styles.0) { self.contains_cursor = Some(is_contained); } } @@ -601,9 +601,9 @@ impl EventDispatcher { } if self.has_cursor.is_none() { - if let Some(styles) = world.get::<KStyle>(node.0) { + if let Some(styles) = world.get::<ComputedStyles>(node.0) { // Check if the cursor moved onto a widget that qualifies as one that can contain it - if Self::can_contain_cursor(styles) { + if Self::can_contain_cursor(&styles.0) { self.has_cursor = Some(node); } } @@ -666,8 +666,8 @@ impl EventDispatcher { fn resolve_pointer_events(index: WrappedIndex, world: &mut World) -> PointerEvents { let mut pointer_events = PointerEvents::default(); - if let Some(styles) = world.get::<KStyle>(index.0) { - pointer_events = styles.pointer_events.resolve(); + if let Some(styles) = world.get::<ComputedStyles>(index.0) { + pointer_events = styles.0.pointer_events.resolve(); } pointer_events } diff --git a/src/styles/mod.rs b/src/styles/mod.rs index 2ffda25864e0c179e0e809fc2f4d3d60982e277c..8e92d3245704e232ac5d1780b02aed37867f554c 100644 --- a/src/styles/mod.rs +++ b/src/styles/mod.rs @@ -1,3 +1,5 @@ +use bevy::{prelude::Component, reflect::Reflect}; + mod corner; mod edge; mod options_ref; @@ -11,3 +13,12 @@ pub use options_ref::AsRefOption; pub use render_command::RenderCommand; pub use style::*; pub use units::*; + +#[derive(Component, Reflect, Debug, Default, Clone, PartialEq)] +pub struct ComputedStyles(pub KStyle); + +impl Into<ComputedStyles> for KStyle { + fn into(self) -> ComputedStyles { + ComputedStyles(self) + } +} diff --git a/src/widget.rs b/src/widget.rs index bd4a21b66768af14e0da89c916a93afc0ab6af32..1746669e75bdad6c337b50defbd54d38ec094023 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -7,7 +7,7 @@ use crate::{ children::KChildren, context::{Mounted, WidgetName}, prelude::KayakWidgetContext, - styles::KStyle, + styles::{ComputedStyles, KStyle}, }; pub trait Widget: Send + Sync { @@ -57,6 +57,7 @@ pub struct WidgetParam<'w, 's, Props: PartialEq + Component, State: PartialEq + pub old_props_query: Query<'w, 's, &'static Props>, pub mounted_query: Query<'w, 's, Entity, With<Mounted>>, pub style_query: Query<'w, 's, &'static KStyle>, + pub computed_style_query: Query<'w, 's, &'static ComputedStyles>, pub children_query: Query<'w, 's, &'static KChildren>, pub state_query: Query<'w, 's, &'static State>, pub widget_names: Query<'w, 's, &'static WidgetName>, @@ -95,6 +96,21 @@ impl<'w, 's, Props: PartialEq + Component, State: PartialEq + Component> } } + // Compare computed styles + if let (Ok(style), Ok(old_style)) = ( + self.computed_style_query.get(current_entity), + self.computed_style_query.get(previous_entity), + ) { + if style != old_style { + log::trace!( + "Entity computed styles have changed! {}-{}", + self.widget_names.get(current_entity).unwrap().0, + current_entity.index() + ); + return true; + } + } + // Compare children // If children don't exist ignore as mount will add them! if let (Ok(children), Ok(old_children)) = ( diff --git a/src/widgets/app.rs b/src/widgets/app.rs index db871b596648cc32792d3d0623f98a9bd104240d..67b9062199779ba3765624d4c80c386a3294f0b0 100644 --- a/src/widgets/app.rs +++ b/src/widgets/app.rs @@ -5,7 +5,7 @@ use crate::{ children::KChildren, context::WidgetName, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand, StyleProp, Units}, + styles::{ComputedStyles, KStyle, RenderCommand, StyleProp, Units}, widget::{EmptyState, Widget, WidgetParam}, CameraUIKayak, }; @@ -24,6 +24,7 @@ impl Widget for KayakApp {} pub struct KayakAppBundle { pub app: KayakApp, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub widget_name: WidgetName, } @@ -33,6 +34,7 @@ impl Default for KayakAppBundle { Self { app: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), children: Default::default(), widget_name: KayakApp::default().get_name(), } @@ -47,22 +49,24 @@ pub fn app_update( ) -> bool { let mut window_change = false; - if let Ok(app_style) = widget_param.style_query.get(entity) { + if let Ok(app_style) = widget_param.computed_style_query.get(entity) { if let Some(camera_entity) = widget_context.camera_entity { if let Ok(camera) = camera.get(camera_entity) { if let Some(size) = camera.logical_viewport_size() { - if app_style.width != StyleProp::Value(Units::Pixels(size.x)) { + if app_style.0.width != StyleProp::Value(Units::Pixels(size.x)) { window_change = true; } - if app_style.height != StyleProp::Value(Units::Pixels(size.y)) { + if app_style.0.height != StyleProp::Value(Units::Pixels(size.y)) { window_change = true; } } else { let primary_window = windows.get_primary().unwrap(); - if app_style.width != StyleProp::Value(Units::Pixels(primary_window.width())) { + if app_style.0.width != StyleProp::Value(Units::Pixels(primary_window.width())) + { window_change = true; } - if app_style.height != StyleProp::Value(Units::Pixels(primary_window.height())) + if app_style.0.height + != StyleProp::Value(Units::Pixels(primary_window.height())) { window_change = true; } @@ -78,7 +82,7 @@ pub fn app_update( pub fn app_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&mut KStyle, &KChildren)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &KChildren)>, camera: Query<&Camera, With<CameraUIKayak>>, windows: Res<Windows>, images: Res<Assets<Image>>, @@ -105,15 +109,17 @@ pub fn app_render( } } - if let Ok((mut app_style, children)) = query.get_mut(entity) { - if app_style.width != StyleProp::Value(Units::Pixels(width)) { - app_style.width = StyleProp::Value(Units::Pixels(width)); - } - if app_style.height != StyleProp::Value(Units::Pixels(height)) { - app_style.height = StyleProp::Value(Units::Pixels(height)); - } + if let Ok((app_style, mut computed_styles, children)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: RenderCommand::Layout.into(), + width: Units::Pixels(width).into(), + height: Units::Pixels(height).into(), + ..Default::default() + }) + .with_style(app_style) + .into(); - app_style.render_command = StyleProp::Value(RenderCommand::Layout); let parent_id = Some(entity); rsx! { <ClipBundle diff --git a/src/widgets/background.rs b/src/widgets/background.rs index c2146047ecb484a374ae80a9c22e5bf5626ef863..533b96e30d3bc2720febb852c2d4b3ded0fb5327 100644 --- a/src/widgets/background.rs +++ b/src/widgets/background.rs @@ -5,7 +5,7 @@ use crate::{ context::WidgetName, on_event::OnEvent, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand, StyleProp}, + styles::{ComputedStyles, KStyle, RenderCommand}, widget::Widget, }; @@ -24,6 +24,7 @@ impl Widget for Background {} pub struct BackgroundBundle { pub background: Background, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub on_event: OnEvent, pub widget_name: WidgetName, @@ -34,6 +35,7 @@ impl Default for BackgroundBundle { Self { background: Default::default(), styles: Default::default(), + computed_styles: Default::default(), children: Default::default(), on_event: Default::default(), widget_name: Background::default().get_name(), @@ -44,10 +46,16 @@ impl Default for BackgroundBundle { pub fn background_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, _: Commands, - mut query: Query<(&mut KStyle, &KChildren)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &KChildren)>, ) -> bool { - if let Ok((mut style, children)) = query.get_mut(entity) { - style.render_command = StyleProp::Value(RenderCommand::Quad); + if let Ok((style, mut computed_styles, children)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: RenderCommand::Quad.into(), + ..Default::default() + }) + .with_style(style) + .into(); children.process(&widget_context, Some(entity)); } true diff --git a/src/widgets/button.rs b/src/widgets/button.rs index ab772e2de7b527d71a164502a4e650f434858f7c..9187d9070b705b4a456e9b02289c2429f8cff822 100644 --- a/src/widgets/button.rs +++ b/src/widgets/button.rs @@ -11,7 +11,7 @@ use crate::{ event_dispatcher::EventDispatcherContext, on_event::OnEvent, prelude::{KChildren, KayakWidgetContext, Units}, - styles::{Corner, Edge, KCursorIcon, KStyle, RenderCommand, StyleProp}, + styles::{ComputedStyles, Corner, Edge, KCursorIcon, KStyle, RenderCommand, StyleProp}, widget::Widget, widget_state::WidgetState, }; @@ -21,7 +21,6 @@ use super::{ElementBundle, TextProps, TextWidgetBundle}; #[derive(Component, PartialEq, Clone, Default)] pub struct KButton { pub text: String, - pub user_styles: KStyle, } /// Default button widget @@ -30,6 +29,7 @@ pub struct KButton { pub struct KButtonBundle { pub button: KButton, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub on_event: OnEvent, pub widget_name: WidgetName, } @@ -39,6 +39,7 @@ impl Default for KButtonBundle { Self { button: Default::default(), styles: Default::default(), + computed_styles: Default::default(), on_event: Default::default(), widget_name: KButton::default().get_name(), } @@ -55,22 +56,22 @@ pub struct ButtonState { pub fn button_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&KButton, &mut KStyle)>, + mut query: Query<(&KButton, &KStyle, &mut ComputedStyles)>, state_query: Query<&ButtonState>, ) -> bool { - if let Ok((button, mut style)) = query.get_mut(entity) { + if let Ok((button, styles, mut computed_styles)) = query.get_mut(entity) { let hover_color = Color::rgba(0.592, 0.627, 0.749, 1.0); //Color::rgba(0.549, 0.666, 0.933, 1.0); // let color = Color::rgba(0.254, 0.270, 0.349, 1.0); let state_entity = widget_context.use_state(&mut commands, entity, ButtonState { hovering: false }); if let Ok(state) = state_query.get(state_entity) { - *style = KStyle::default() + *computed_styles = KStyle::default() .with_style(KStyle { render_command: StyleProp::Value(RenderCommand::Quad), ..Default::default() }) - .with_style(button.user_styles.clone()) + .with_style(styles) .with_style(KStyle { background_color: Color::rgba(0.254, 0.270, 0.349, 1.0).into(), border_color: if state.hovering { @@ -84,7 +85,8 @@ pub fn button_render( width: Units::Stretch(1.0).into(), cursor: StyleProp::Value(KCursorIcon(CursorIcon::Hand)), ..Default::default() - }); + }) + .into(); let on_event = OnEvent::new( move |In((event_dispatcher_context, _, mut event, _entity)): In<( @@ -121,15 +123,17 @@ pub fn button_render( on_event={on_event} > <TextWidgetBundle + styles={KStyle { + top: Units::Stretch(1.0).into(), + bottom: Units::Stretch(1.0).into(), + left: Units::Stretch(1.0).into(), + right: Units::Stretch(1.0).into(), + ..Default::default() + }} text={TextProps { - alignment: Alignment::Middle, + alignment: Alignment::Start, content: button.text.clone(), size: 16.0, - user_styles: KStyle { - top: Units::Stretch(1.0).into(), - bottom: Units::Stretch(1.0).into(), - ..Default::default() - }, ..Default::default() }} /> diff --git a/src/widgets/clip.rs b/src/widgets/clip.rs index 3f3e3e570f1f1af74e5ac3bacd6308ec0bb89e23..51f53f01aa64379d544cff2c1a4cbe69f321b0bc 100644 --- a/src/widgets/clip.rs +++ b/src/widgets/clip.rs @@ -4,7 +4,7 @@ use crate::{ children::KChildren, context::WidgetName, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand, StyleProp, Units}, + styles::{ComputedStyles, KStyle, RenderCommand, Units}, widget::Widget, }; @@ -22,6 +22,7 @@ impl Widget for Clip {} pub struct ClipBundle { pub clip: Clip, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub widget_name: WidgetName, } @@ -30,12 +31,8 @@ impl Default for ClipBundle { fn default() -> Self { Self { clip: Clip::default(), - styles: KStyle { - render_command: StyleProp::Value(RenderCommand::Clip), - height: StyleProp::Value(Units::Stretch(1.0)), - width: StyleProp::Value(Units::Stretch(1.0)), - ..KStyle::default() - }, + styles: KStyle::default(), + computed_styles: ComputedStyles::default(), children: KChildren::default(), widget_name: Clip::default().get_name(), } @@ -45,10 +42,21 @@ impl Default for ClipBundle { pub fn clip_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, _: Commands, - mut query: Query<(&mut KStyle, &KChildren)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &KChildren)>, ) -> bool { - if let Ok((mut styles, children)) = query.get_mut(entity) { - styles.render_command = StyleProp::Value(RenderCommand::Clip); + if let Ok((styles, mut computed_styles, children)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: RenderCommand::Clip.into(), + ..Default::default() + }) + .with_style(styles) + .with_style(KStyle { + width: Units::Stretch(1.0).into(), + height: Units::Stretch(1.0).into(), + ..Default::default() + }) + .into(); children.process(&widget_context, Some(entity)); } true diff --git a/src/widgets/element.rs b/src/widgets/element.rs index d5663b3bf0a4d4deeea9198d1f85427d928ad3ae..2b97ca13be620fd0bdd671dbb7159047e7568612 100644 --- a/src/widgets/element.rs +++ b/src/widgets/element.rs @@ -5,7 +5,7 @@ use crate::{ context::WidgetName, on_event::OnEvent, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand, StyleProp}, + styles::{ComputedStyles, KStyle, RenderCommand, StyleProp}, widget::Widget, }; @@ -21,6 +21,7 @@ impl Widget for Element {} pub struct ElementBundle { pub element: Element, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub on_event: OnEvent, pub children: KChildren, pub widget_name: WidgetName, @@ -31,6 +32,7 @@ impl Default for ElementBundle { Self { element: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), children: Default::default(), on_event: OnEvent::default(), widget_name: Element::default().get_name(), @@ -41,15 +43,16 @@ impl Default for ElementBundle { pub fn element_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, _: Commands, - mut query: Query<(&mut KStyle, &KChildren)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &KChildren)>, ) -> bool { - if let Ok((mut style, children)) = query.get_mut(entity) { - *style = KStyle::default() - .with_style(style.clone()) + if let Ok((style, mut computed_styles, children)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(style) .with_style(KStyle { render_command: StyleProp::Value(RenderCommand::Layout), ..Default::default() - }); + }) + .into(); children.process(&widget_context, Some(entity)); } true diff --git a/src/widgets/image.rs b/src/widgets/image.rs index bc6d5cfe3f2c6085d1c50d99af58630c3b97a64e..a01004b01d9696a8343ac35348ccacfa55c0d726 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -3,7 +3,7 @@ use bevy::prelude::{Bundle, Component, Entity, Handle, In, Query}; use crate::{ context::WidgetName, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand, StyleProp}, + styles::{ComputedStyles, KStyle, RenderCommand}, widget::Widget, }; @@ -18,6 +18,7 @@ impl Widget for KImage {} pub struct KImageBundle { pub image: KImage, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -26,6 +27,7 @@ impl Default for KImageBundle { Self { image: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), widget_name: KImage::default().get_name(), } } @@ -33,12 +35,19 @@ impl Default for KImageBundle { pub fn image_render( In((_widget_context, entity)): In<(KayakWidgetContext, Entity)>, - mut query: Query<(&mut KStyle, &KImage)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &KImage)>, ) -> bool { - if let Ok((mut style, image)) = query.get_mut(entity) { - style.render_command = StyleProp::Value(RenderCommand::Image { - handle: image.0.clone_weak(), - }); + if let Ok((style, mut computed_styles, image)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: RenderCommand::Image { + handle: image.0.clone_weak(), + } + .into(), + ..Default::default() + }) + .with_style(style) + .into(); } true } diff --git a/src/widgets/nine_patch.rs b/src/widgets/nine_patch.rs index 0dd5b91e2fe6b5051845514da22d15f2fb2bf7c4..d3f55728af0185c5f6c3b98ef09ae7bb82756f79 100644 --- a/src/widgets/nine_patch.rs +++ b/src/widgets/nine_patch.rs @@ -5,7 +5,7 @@ use crate::{ context::WidgetName, on_event::OnEvent, prelude::KayakWidgetContext, - styles::{Edge, KStyle, RenderCommand, StyleProp}, + styles::{ComputedStyles, Edge, KStyle, RenderCommand}, widget::Widget, }; @@ -52,6 +52,7 @@ impl Widget for NinePatch {} pub struct NinePatchBundle { pub nine_patch: NinePatch, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub on_event: OnEvent, pub widget_name: WidgetName, @@ -62,6 +63,7 @@ impl Default for NinePatchBundle { Self { nine_patch: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), children: KChildren::default(), on_event: OnEvent::default(), widget_name: NinePatch::default().get_name(), @@ -72,13 +74,20 @@ impl Default for NinePatchBundle { pub fn nine_patch_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, _: Commands, - mut query: Query<(&mut KStyle, &NinePatch, &KChildren)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &NinePatch, &KChildren)>, ) -> bool { - if let Ok((mut style, nine_patch, children)) = query.get_mut(entity) { - style.render_command = StyleProp::Value(RenderCommand::NinePatch { - border: nine_patch.border, - handle: nine_patch.handle.clone_weak(), - }); + if let Ok((style, mut computed_styles, nine_patch, children)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: RenderCommand::NinePatch { + border: nine_patch.border, + handle: nine_patch.handle.clone_weak(), + } + .into(), + ..Default::default() + }) + .with_style(style) + .into(); children.process(&widget_context, Some(entity)); } diff --git a/src/widgets/scroll/scroll_bar.rs b/src/widgets/scroll/scroll_bar.rs index 5d63688c0f821033014020d579383eb41126f1ce..27ffec41a4dd2703cbb3826d349fed8c5ba2e13c 100644 --- a/src/widgets/scroll/scroll_bar.rs +++ b/src/widgets/scroll/scroll_bar.rs @@ -7,7 +7,7 @@ use crate::{ event_dispatcher::EventDispatcherContext, on_event::OnEvent, prelude::{KChildren, KayakWidgetContext}, - styles::{Corner, Edge, KPositionType, KStyle, RenderCommand, Units}, + styles::{ComputedStyles, Corner, Edge, KPositionType, KStyle, RenderCommand, Units}, widget::Widget, widget_state::WidgetState, widgets::{BackgroundBundle, ClipBundle}, @@ -40,6 +40,7 @@ impl Widget for ScrollBarProps {} pub struct ScrollBarBundle { pub scrollbar_props: ScrollBarProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -48,6 +49,7 @@ impl Default for ScrollBarBundle { Self { scrollbar_props: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), widget_name: ScrollBarProps::default().get_name(), } } @@ -56,10 +58,10 @@ impl Default for ScrollBarBundle { pub fn scroll_bar_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&ScrollBarProps, &mut KStyle)>, + mut query: Query<(&ScrollBarProps, &KStyle, &mut ComputedStyles)>, context_query: Query<&ScrollContext>, ) -> bool { - if let Ok((scrollbar, mut styles)) = query.get_mut(entity) { + if let Ok((scrollbar, styles, mut computed_styles)) = query.get_mut(entity) { if let Some(context_entity) = widget_context.get_context_entity::<ScrollContext>(entity) { if let Ok(scroll_context) = context_query.get(context_entity) { let scroll_x = scroll_context.scroll_x(); @@ -112,22 +114,25 @@ pub fn scroll_bar_render( ); // === Styles === // - *styles = KStyle::default().with_style(KStyle { - render_command: RenderCommand::Layout.into(), - width: if horizontal { - Units::Stretch(1.0) - } else { - Units::Pixels(thickness) - } - .into(), - height: if horizontal { - Units::Pixels(thickness) - } else { - Units::Stretch(1.0) - } - .into(), - ..Default::default() - }); + *computed_styles = KStyle::default() + .with_style(KStyle { + render_command: RenderCommand::Layout.into(), + width: if horizontal { + Units::Stretch(1.0) + } else { + Units::Pixels(thickness) + } + .into(), + height: if horizontal { + Units::Pixels(thickness) + } else { + Units::Stretch(1.0) + } + .into(), + ..Default::default() + }) + .with_style(styles) + .into(); let mut track_style = KStyle::default() diff --git a/src/widgets/scroll/scroll_box.rs b/src/widgets/scroll/scroll_box.rs index 7803295537a7b9e6a2f5662cbffb86ae76d02abd..3a285785b171e880bf5a7607cfbb73fa8cdbd693 100644 --- a/src/widgets/scroll/scroll_box.rs +++ b/src/widgets/scroll/scroll_box.rs @@ -10,7 +10,7 @@ use crate::{ on_event::OnEvent, on_layout::OnLayout, prelude::{constructor, rsx, KayakWidgetContext}, - styles::{KPositionType, KStyle, LayoutType, RenderCommand, Units}, + styles::{ComputedStyles, KPositionType, KStyle, LayoutType, RenderCommand, Units}, widget::Widget, widget_state::WidgetState, widgets::{ @@ -59,6 +59,7 @@ impl Widget for ScrollBoxProps {} pub struct ScrollBoxBundle { pub scroll_box_props: ScrollBoxProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub on_layout: OnLayout, pub widget_name: WidgetName, @@ -69,6 +70,7 @@ impl Default for ScrollBoxBundle { Self { scroll_box_props: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), children: Default::default(), on_layout: Default::default(), widget_name: ScrollBoxProps::default().get_name(), @@ -79,10 +81,17 @@ impl Default for ScrollBoxBundle { pub fn scroll_box_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&ScrollBoxProps, &mut KStyle, &KChildren, &mut OnLayout)>, + mut query: Query<( + &ScrollBoxProps, + &KStyle, + &mut ComputedStyles, + &KChildren, + &mut OnLayout, + )>, mut context_query: ParamSet<(Query<&ScrollContext>, Query<&mut ScrollContext>)>, ) -> bool { - if let Ok((scroll_box, mut styles, scroll_box_children, mut on_layout)) = query.get_mut(entity) + if let Ok((scroll_box, styles, mut computed_styles, scroll_box_children, mut on_layout)) = + query.get_mut(entity) { if let Some(context_entity) = widget_context.get_context_entity::<ScrollContext>(entity) { if let Ok(scroll_context) = context_query.p0().get(context_entity).cloned() { @@ -139,17 +148,18 @@ pub fn scroll_box_render( ); // === Styles === // - *styles = KStyle::default() + *computed_styles = KStyle::default() .with_style(KStyle { render_command: RenderCommand::Layout.into(), ..Default::default() }) - .with_style(styles.clone()) + .with_style(styles) .with_style(KStyle { width: Units::Stretch(1.0).into(), height: Units::Stretch(1.0).into(), ..Default::default() - }); + }) + .into(); let hbox_styles = KStyle::default().with_style(KStyle { render_command: RenderCommand::Layout.into(), diff --git a/src/widgets/scroll/scroll_content.rs b/src/widgets/scroll/scroll_content.rs index 4c11937c57041df47ed75add66e650eb6942dab9..b84188c04dd4deedf2db51dfe615aa7002a40959 100644 --- a/src/widgets/scroll/scroll_content.rs +++ b/src/widgets/scroll/scroll_content.rs @@ -7,7 +7,7 @@ use crate::{ layout::LayoutEvent, on_layout::OnLayout, prelude::KayakWidgetContext, - styles::{KStyle, LayoutType, RenderCommand, Units}, + styles::{ComputedStyles, KStyle, LayoutType, RenderCommand, Units}, widget::Widget, }; @@ -22,6 +22,7 @@ impl Widget for ScrollContentProps {} pub struct ScrollContentBundle { pub scroll_content_props: ScrollContentProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub on_layout: OnLayout, pub widget_name: WidgetName, @@ -32,6 +33,7 @@ impl Default for ScrollContentBundle { Self { scroll_content_props: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), children: Default::default(), on_layout: Default::default(), widget_name: ScrollContentProps::default().get_name(), @@ -41,10 +43,13 @@ impl Default for ScrollContentBundle { pub fn scroll_content_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, - mut query: Query<(&mut KStyle, &KChildren, &mut OnLayout), With<ScrollContentProps>>, + mut query: Query< + (&KStyle, &mut ComputedStyles, &KChildren, &mut OnLayout), + With<ScrollContentProps>, + >, context_query: Query<&ScrollContext>, ) -> bool { - if let Ok((mut styles, children, mut on_layout)) = query.get_mut(entity) { + if let Ok((styles, mut computed_styles, children, mut on_layout)) = query.get_mut(entity) { if let Some(context_entity) = widget_context.get_context_entity::<ScrollContext>(entity) { if let Ok(scroll_context) = context_query.get(context_entity) { // === OnLayout === // @@ -65,7 +70,7 @@ pub fn scroll_content_render( ); // === Styles === // - *styles = KStyle::default() + *computed_styles = KStyle::default() .with_style(KStyle { render_command: RenderCommand::Layout.into(), layout_type: LayoutType::Column.into(), @@ -81,7 +86,8 @@ pub fn scroll_content_render( height: Units::Auto.into(), ..Default::default() }) - .with_style(styles.clone()); + .with_style(styles) + .into(); children.process(&widget_context, Some(entity)); } diff --git a/src/widgets/scroll/scroll_context.rs b/src/widgets/scroll/scroll_context.rs index 5ae99ca79f2cc37c4932c8431141ea17e3e8ee0b..c0cb6d02778665e4ed2aa6e8038de013ee2c6827 100644 --- a/src/widgets/scroll/scroll_context.rs +++ b/src/widgets/scroll/scroll_context.rs @@ -1,7 +1,10 @@ use bevy::prelude::{Bundle, Commands, Component, Entity, In, Query, Vec2}; use crate::{ - children::KChildren, context::WidgetName, prelude::KayakWidgetContext, styles::KStyle, + children::KChildren, + context::WidgetName, + prelude::KayakWidgetContext, + styles::{ComputedStyles, KStyle}, widget::Widget, }; @@ -143,6 +146,7 @@ pub struct ScrollContextProviderBundle { pub scroll_context_provider: ScrollContextProvider, pub children: KChildren, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -152,6 +156,7 @@ impl Default for ScrollContextProviderBundle { scroll_context_provider: Default::default(), children: KChildren::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), widget_name: ScrollContextProvider::default().get_name(), } } @@ -160,11 +165,17 @@ impl Default for ScrollContextProviderBundle { pub fn scroll_context_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&ScrollContextProvider, &KChildren)>, + mut query: Query<( + &ScrollContextProvider, + &KChildren, + &KStyle, + &mut ComputedStyles, + )>, ) -> bool { - if let Ok((context_provider, children)) = query.get_mut(entity) { + if let Ok((context_provider, children, styles, mut computed_styles)) = query.get_mut(entity) { let context_entity = commands.spawn(context_provider.initial_value).id(); widget_context.set_context_entity::<ScrollContext>(Some(entity), context_entity); + *computed_styles = styles.clone().into(); children.process(&widget_context, Some(entity)); } diff --git a/src/widgets/text.rs b/src/widgets/text.rs index 574c7c0324fbcd770360f758257be9548683e9ca..db20b9ca4b22c7a4ac7c14d528f1984b2319c274 100644 --- a/src/widgets/text.rs +++ b/src/widgets/text.rs @@ -4,7 +4,7 @@ use kayak_font::Alignment; use crate::{ context::WidgetName, prelude::KayakWidgetContext, - styles::{KCursorIcon, KStyle, RenderCommand, StyleProp, Units}, + styles::{ComputedStyles, KCursorIcon, KStyle, RenderCommand, StyleProp}, widget::Widget, }; @@ -28,8 +28,6 @@ pub struct TextProps { pub size: f32, /// Text alignment. pub alignment: Alignment, - /// Custom styles to pass in. - pub user_styles: KStyle, /// Basic word wrapping. /// Defautls to true pub word_wrap: bool, @@ -45,7 +43,6 @@ impl Default for TextProps { size: -1.0, alignment: Alignment::Start, word_wrap: true, - user_styles: Default::default(), } } } @@ -58,6 +55,7 @@ impl Widget for TextProps {} pub struct TextWidgetBundle { pub text: TextProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -65,11 +63,8 @@ impl Default for TextWidgetBundle { fn default() -> Self { Self { text: Default::default(), - styles: KStyle { - width: Units::Stretch(1.0).into(), - height: Units::Stretch(1.0).into(), - ..Default::default() - }, + styles: KStyle::default(), + computed_styles: ComputedStyles::default(), widget_name: TextProps::default().get_name(), } } @@ -77,11 +72,11 @@ impl Default for TextWidgetBundle { pub fn text_render( In((_widget_context, entity)): In<(KayakWidgetContext, Entity)>, - mut query: Query<(&mut KStyle, &TextProps)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &TextProps)>, ) -> bool { - if let Ok((mut styles, text)) = query.get_mut(entity) { - *styles = KStyle::default() - .with_style(&text.user_styles) + if let Ok((styles, mut computed_styles, text)) = query.get_mut(entity) { + *computed_styles = KStyle::default() + .with_style(styles) .with_style(KStyle { render_command: StyleProp::Value(RenderCommand::Text { content: text.content.clone(), @@ -108,13 +103,9 @@ pub fn text_render( } else { StyleProp::default() }, - // bottom: Units::Stretch(1.0).into(), - // top: Units::Stretch(1.0).into(), - // left: Units::Stretch(0.0).into(), - // right: Units::Stretch(0.0).into(), ..Default::default() - }); - + }) + .into(); // style.cursor = StyleProp::Value(KCursorIcon(CursorIcon::Hand)); } diff --git a/src/widgets/text_box.rs b/src/widgets/text_box.rs index 2ba680c34861145cffc16d7a237edff0ba6826fd..031a204f5092fcb7a2c0c2441166dd13c2b0e331 100644 --- a/src/widgets/text_box.rs +++ b/src/widgets/text_box.rs @@ -12,7 +12,7 @@ use crate::{ on_layout::OnLayout, prelude::{KChildren, KayakWidgetContext, OnChange}, render::font::FontMapping, - styles::{Edge, KPositionType, KStyle, RenderCommand, StyleProp, Units}, + styles::{ComputedStyles, Edge, KPositionType, KStyle, RenderCommand, StyleProp, Units}, widget::Widget, widget_state::WidgetState, widgets::{ @@ -75,6 +75,7 @@ impl Widget for TextBoxProps {} pub struct TextBoxBundle { pub text_box: TextBoxProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub on_event: OnEvent, pub on_layout: OnLayout, pub on_change: OnChange, @@ -87,6 +88,7 @@ impl Default for TextBoxBundle { Self { text_box: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), on_event: Default::default(), on_layout: Default::default(), on_change: Default::default(), @@ -99,12 +101,20 @@ impl Default for TextBoxBundle { pub fn text_box_render( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&mut KStyle, &TextBoxProps, &mut OnEvent, &OnChange)>, + mut query: Query<( + &KStyle, + &mut ComputedStyles, + &TextBoxProps, + &mut OnEvent, + &OnChange, + )>, mut state_query: ParamSet<(Query<&TextBoxState>, Query<&mut TextBoxState>)>, font_assets: Res<Assets<KayakFont>>, font_mapping: Res<FontMapping>, ) -> bool { - if let Ok((mut styles, text_box, mut on_event, on_change)) = query.get_mut(entity) { + if let Ok((styles, mut computed_styles, text_box, mut on_event, on_change)) = + query.get_mut(entity) + { let state_entity = widget_context.use_state::<TextBoxState>( &mut commands, entity, @@ -136,14 +146,14 @@ pub fn text_box_render( } if let Ok(state) = state_query.p0().get(state_entity) { - *styles = KStyle::default() + *computed_styles = KStyle::default() // Required styles .with_style(KStyle { render_command: RenderCommand::Layout.into(), ..Default::default() }) // Apply any prop-given styles - .with_style(&*styles) + .with_style(styles) // If not set by props, apply these styles .with_style(KStyle { top: Units::Pixels(0.0).into(), @@ -151,7 +161,8 @@ pub fn text_box_render( height: Units::Pixels(26.0).into(), // cursor: CursorIcon::Text.into(), ..Default::default() - }); + }) + .into(); let background_styles = KStyle { render_command: StyleProp::Value(RenderCommand::Quad), @@ -341,11 +352,11 @@ pub fn text_box_render( }}> <ElementBundle styles={scroll_styles}> <TextWidgetBundle + styles={text_styles} text={TextProps { content: text_box.value.clone(), size: 14.0, line_height: Some(18.0), - user_styles: text_styles, word_wrap: false, ..Default::default() }} diff --git a/src/widgets/texture_atlas.rs b/src/widgets/texture_atlas.rs index eab78bf4d6cbc1a91b733096dd627f3fc4119d48..d793326349f913f4c516a703ecda1201fa2d4512 100644 --- a/src/widgets/texture_atlas.rs +++ b/src/widgets/texture_atlas.rs @@ -3,7 +3,7 @@ use bevy::prelude::{Bundle, Component, Entity, Handle, Image, In, Query, Vec2}; use crate::{ context::WidgetName, prelude::KayakWidgetContext, - styles::{KStyle, RenderCommand, StyleProp}, + styles::{ComputedStyles, KStyle, RenderCommand}, widget::Widget, }; @@ -39,6 +39,7 @@ impl Widget for TextureAtlasProps {} pub struct TextureAtlasBundle { pub atlas: TextureAtlasProps, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub widget_name: WidgetName, } @@ -47,6 +48,7 @@ impl Default for TextureAtlasBundle { Self { atlas: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), widget_name: TextureAtlasProps::default().get_name(), } } @@ -54,17 +56,20 @@ impl Default for TextureAtlasBundle { pub fn texture_atlas_render( In((_widget_context, entity)): In<(KayakWidgetContext, Entity)>, - mut query: Query<(&mut KStyle, &TextureAtlasProps)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &TextureAtlasProps)>, ) -> bool { - if let Ok((mut styles, texture_atlas)) = query.get_mut(entity) { - *styles = KStyle { - render_command: StyleProp::Value(RenderCommand::TextureAtlas { + if let Ok((styles, mut computed_styles, texture_atlas)) = query.get_mut(entity) { + *computed_styles = KStyle { + render_command: RenderCommand::TextureAtlas { position: texture_atlas.position, size: texture_atlas.tile_size, handle: texture_atlas.handle.clone_weak(), - }), - ..styles.clone() - }; + } + .into(), + ..Default::default() + } + .with_style(styles) + .into(); } true diff --git a/src/widgets/window.rs b/src/widgets/window.rs index 7a2d88b5b342557fb12f2a8357266b2952883aab..3358245db619f33a77922c11149c0b16a761ee0d 100644 --- a/src/widgets/window.rs +++ b/src/widgets/window.rs @@ -11,7 +11,10 @@ use crate::{ event_dispatcher::EventDispatcherContext, on_event::OnEvent, prelude::KayakWidgetContext, - styles::{Corner, Edge, KCursorIcon, KPositionType, KStyle, RenderCommand, StyleProp, Units}, + styles::{ + ComputedStyles, Corner, Edge, KCursorIcon, KPositionType, KStyle, RenderCommand, StyleProp, + Units, + }, widget::Widget, widget_state::WidgetState, Focusable, @@ -58,6 +61,7 @@ impl Widget for KWindow {} pub struct WindowBundle { pub window: KWindow, pub styles: KStyle, + pub computed_styles: ComputedStyles, pub children: KChildren, pub widget_name: WidgetName, } @@ -67,6 +71,7 @@ impl Default for WindowBundle { Self { window: Default::default(), styles: Default::default(), + computed_styles: ComputedStyles::default(), children: Default::default(), widget_name: KWindow::default().get_name(), } @@ -76,11 +81,13 @@ impl Default for WindowBundle { pub fn window_render( In((widget_context, window_entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, - mut query: Query<(&mut KStyle, &KChildren, &KWindow)>, + mut query: Query<(&KStyle, &mut ComputedStyles, &KChildren, &KWindow)>, state_query: Query<&KWindowState>, mut context_query: Query<&mut WindowContext>, ) -> bool { - if let Ok((mut window_style, window_children, window)) = query.get_mut(window_entity) { + if let Ok((window_style, mut computed_styles, window_children, window)) = + query.get_mut(window_entity) + { let possible_context_entity = widget_context.get_context_entity::<WindowContext>(window_entity); let z_index = if let Some(window_context_entity) = possible_context_entity { @@ -93,11 +100,17 @@ pub fn window_render( None }; - window_style.z_index = if let Some(z_index) = z_index { - StyleProp::Value(z_index as i32 * 1000) - } else { - StyleProp::Default - }; + *computed_styles = KStyle::default() + .with_style(KStyle { + z_index: if let Some(z_index) = z_index { + StyleProp::Value(z_index as i32 * 1000) + } else { + StyleProp::Default + }, + ..Default::default() + }) + .with_style(window_style) + .into(); let title = window.title.clone(); @@ -190,14 +203,14 @@ pub fn window_render( }} > <TextWidgetBundle + styles={KStyle { + top: Units::Stretch(1.0).into(), + bottom: Units::Stretch(1.0).into(), + ..Default::default() + }} text={TextProps { content: title, size: 14.0, - user_styles: KStyle { - top: Units::Stretch(1.0).into(), - bottom: Units::Stretch(1.0).into(), - ..Default::default() - }, ..Default::default() }} />