From fd1ee92d5f3404d89c08bf9bfdae51670c22b40c Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Thu, 24 Aug 2023 12:32:36 -0700 Subject: [PATCH] buggy but working collapse button + title work --- bin/editor.rs | 238 ++++++++++++++++++++++++++++---------------------- src/ui.rs | 170 ++++++++++++++++++++++++------------ 2 files changed, 251 insertions(+), 157 deletions(-) diff --git a/bin/editor.rs b/bin/editor.rs index 7032f58..f6ff1e9 100644 --- a/bin/editor.rs +++ b/bin/editor.rs @@ -123,120 +123,155 @@ fn initialize_ui(mut commands: Commands) { }; commands - .spawn((NodeBundle { + .spawn(NodeBundle { style: Style { border: UiRect::all(Val::Px(1.0)), margin: UiRect::all(Val::Px(5.0)), padding: UiRect::all(Val::Px(5.0)), - flex_direction: FlexDirection::Row, + flex_direction: FlexDirection::Column, overflow: Overflow::clip(), ..default() }, background_color: Color::WHITE.into(), border_color: Color::BLACK.into(), ..default() - },)) + }) .with_children(|parent| { - // HACK: This is super janky but I think we need it like this for UI layout rules - let mut content_containers: Vec<(String, Entity)> = Vec::new(); - - // Containers with asset content - parent - .spawn(( - NodeBundle { - style: Style { - border: UiRect::all(Val::Px(1.0)), - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - flex_direction: FlexDirection::Column, - overflow: Overflow::clip(), - justify_content: JustifyContent::FlexStart, - ..default() - }, - background_color: Color::WHITE.into(), - border_color: Color::BLACK.into(), + let container = parent + .spawn((NodeBundle { + style: Style { + border: UiRect::all(Val::Px(1.0)), + margin: UiRect::all(Val::Px(5.0)), + padding: UiRect::all(Val::Px(5.0)), + flex_direction: FlexDirection::Row, + overflow: Overflow::clip(), ..default() }, - ui::Sorting(2), - )) + background_color: Color::WHITE.into(), + border_color: Color::BLACK.into(), + ..default() + },)) .with_children(|parent| { - content_containers.push(spawn_tab_container::( - "Font", - parent, - &base_style, - ui::Select::Single, - )); - content_containers.push(spawn_tab_container::( - "Audio", - parent, - &base_style, - ui::Select::Multi, - )); - content_containers.push(spawn_tab_container::( - "Gltf", - parent, - &base_style, - ui::Select::Single, - )); - content_containers.push(spawn_tab_container::( - "Scene", - parent, - &base_style, - ui::Select::Single, - )); - content_containers.push(spawn_tab_container::( - "Animation", - parent, - &base_style, - ui::Select::Multi, - )); - content_containers.push(spawn_tab_container::( - "Camera", - parent, - &base_style, - ui::Select::Single, - )); - }); + // HACK: This is super janky but I think we need it like this for UI layout rules + let mut content_containers: Vec<(String, Entity)> = Vec::new(); + + // Containers with asset content + parent + .spawn(( + NodeBundle { + style: Style { + border: UiRect::all(Val::Px(1.0)), + margin: UiRect::all(Val::Px(5.0)), + padding: UiRect::all(Val::Px(5.0)), + flex_direction: FlexDirection::Column, + overflow: Overflow::clip(), + justify_content: JustifyContent::FlexStart, + ..default() + }, + background_color: Color::WHITE.into(), + border_color: Color::BLACK.into(), + ..default() + }, + ui::Sorting(2), + )) + .with_children(|parent| { + content_containers.push(spawn_tab_container::( + "Font", + parent, + &base_style, + ui::Select::Single, + )); + content_containers.push(spawn_tab_container::( + "Audio", + parent, + &base_style, + ui::Select::Multi, + )); + content_containers.push(spawn_tab_container::( + "Gltf", + parent, + &base_style, + ui::Select::Single, + )); + content_containers.push(spawn_tab_container::( + "Scene", + parent, + &base_style, + ui::Select::Single, + )); + content_containers.push(spawn_tab_container::( + "Animation", + parent, + &base_style, + ui::Select::Multi, + )); + content_containers.push(spawn_tab_container::( + "Camera", + parent, + &base_style, + ui::Select::Single, + )); + }); - // Container for tabs that open/close containers - parent - .spawn(( - NodeBundle { - style: Style { - border: UiRect::all(Val::Px(1.0)), - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), - flex_direction: FlexDirection::Column, - overflow: Overflow::clip(), - ..default() - }, - background_color: Color::WHITE.into(), - border_color: Color::BLACK.into(), - ..default() - }, - ui::Sorting(1), - ui::Select::Single, - )) - .with_children(|parent| { - let b = ButtonBundle { - style: Style { - ..base_style.clone() - }, - background_color: Color::WHITE.into(), - border_color: Color::BLACK.into(), - ..default() - }; - content_containers.iter().for_each(|(name, target)| { - parent.spawn(( - b.clone(), - ui::Title { - name: name.clone(), + // Container for tabs that open/close containers + parent + .spawn(( + NodeBundle { + style: Style { + border: UiRect::all(Val::Px(1.0)), + margin: UiRect::all(Val::Px(5.0)), + padding: UiRect::all(Val::Px(5.0)), + flex_direction: FlexDirection::Column, + overflow: Overflow::clip(), + ..default() + }, + background_color: Color::WHITE.into(), + border_color: Color::BLACK.into(), ..default() }, - ui::Collapse { target: *target }, - )); - }); - }); + ui::Sorting(1), + ui::Select::Single, + )) + .with_children(|parent| { + let b = ButtonBundle { + style: Style { + ..base_style.clone() + }, + background_color: Color::WHITE.into(), + border_color: Color::BLACK.into(), + ..default() + }; + content_containers.iter().for_each(|(name, target)| { + parent.spawn(( + b.clone(), + ui::Title { text: name.clone() }, + ui::Collapse { target: *target }, + ui::Active, + )); + }); + }); + }) + .id(); + parent.spawn(( + NodeBundle { + style: Style { + border: UiRect::all(Val::Px(1.0)), + margin: UiRect::all(Val::Px(5.0)), + padding: UiRect::all(Val::Px(5.0)), + flex_direction: FlexDirection::Row, + overflow: Overflow::clip(), + ..default() + }, + background_color: Color::ALICE_BLUE.into(), + border_color: Color::BLACK.into(), + ..default() + }, + ui::Title { + text: "Assets".into(), + }, + ui::Minimize { target: container }, + ui::Sorting(0), + )); }); } @@ -261,10 +296,7 @@ fn spawn_tab_container( z_index: ZIndex::Local(100), ..default() }, - ui::Title { - name: title.into(), - ..default() - }, + ui::Title { text: title.into() }, T::default(), ui::Scroll, Interaction::default(), @@ -436,7 +468,7 @@ mod assets { border_color: Color::BLACK.into(), ..default() }, - ui::Title { name, ..default() }, + ui::Title { text: name }, )) .set_parent(root.single()) .id() @@ -461,7 +493,7 @@ mod assets { border_color: Color::BLACK.into(), ..default() }, - ui::Title { name, ..default() }, + ui::Title { text: name }, )) .set_parent(root.single()) .id() diff --git a/src/ui.rs b/src/ui.rs index dc7bda4..4407842 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -33,12 +33,13 @@ impl Plugin for GameUiPlugin { Update, ( init_titles, + manage_titles, manage_button_interaction, manage_select_active, manage_cursor, manage_scroll, - manage_collapse_active, manage_collapse_hiding, + manage_collapse_active, show_child_number, manage_sort, ), @@ -50,66 +51,123 @@ pub use title::*; mod title { use super::*; - #[derive(Debug, Component, Default)] + #[derive(Debug, Component)] pub struct Title { - pub name: String, - pub note: Option, + pub text: String, + } + + #[derive(Debug, Component)] + pub struct Note { + pub text: String, + } + + #[derive(Debug, Component)] + pub struct TitleText; + + #[derive(Debug, Component)] + pub struct Minimize { + pub target: Entity, } pub fn init_titles( - events: Query<(Entity, &Title), Or<(Changed, Added<Title>)>>, + events: Query<(Entity, &Title, Option<&Note>, Option<&Minimize>), Added<Title>>, mut commands: Commands, ) { - events.for_each(|(entity, Title { name, note })| { - commands - .entity(entity) - .despawn_descendants() - .with_children(|parent| { - parent - .spawn(( - NodeBundle { - style: Style { - padding: UiRect::all(Val::Px(5.0)), - margin: UiRect::all(Val::Px(5.0)), - border: UiRect::all(Val::Px(1.0)), - flex_direction: FlexDirection::Row, - ..default() + events.for_each(|(entity, title, note, minimize)| { + commands.entity(entity).with_children(|parent| { + parent.spawn(( + TextBundle { + text: Text { + sections: vec![ + TextSection { + value: title.text.clone(), + style: TextStyle { + color: Color::BLACK, + ..default() + }, + }, + TextSection { + value: note + .unwrap_or(&Note { + text: String::new(), + }) + .text + .clone(), + style: TextStyle { + color: Color::BLACK, + ..default() + }, }, + ], + ..default() + }, + style: Style { + margin: UiRect::all(Val::Px(5.0)), + padding: UiRect::all(Val::Px(5.0)), + ..default() + }, + ..default() + }, + Sorting(0), + TitleText, + )); + if let Some(target) = minimize { + parent.spawn(( + ButtonBundle { + style: Style { + border: UiRect::all(Val::Px(1.0)), + margin: UiRect::all(Val::Px(5.0)), + padding: UiRect::all(Val::Px(5.0)), + right: Val::Px(0.0), ..default() }, - Sorting(0), - )) - .with_children(|parent| { - parent.spawn(TextBundle { - text: Text { - sections: vec![ - TextSection { - value: name.clone(), - style: TextStyle { - color: Color::BLACK, - ..default() - }, - }, - TextSection { - value: note.clone().unwrap_or(String::new()), - style: TextStyle { - color: Color::BLACK, - ..default() - }, - }, - ], + background_color: Color::WHITE.into(), + border_color: Color::BLACK.into(), + ..default() + }, + Collapse { + target: target.target, + }, + )); + } + }); + }); + } + + pub fn manage_titles( + events: Query<(&Title, Option<&Note>, &Children), Changed<Title>>, + mut texts: Query<&mut Text, With<TitleText>>, + ) { + events.iter().for_each(|(title, note, children)| { + children.iter().for_each(|child| { + if let Ok(mut text) = texts.get_mut(*child) { + *text = Text { + sections: vec![ + TextSection { + value: title.text.clone(), + style: TextStyle { + color: Color::BLACK, ..default() }, - style: Style { - margin: UiRect::all(Val::Px(5.0)), - padding: UiRect::all(Val::Px(5.0)), + }, + TextSection { + value: note + .unwrap_or(&Note { + text: String::new(), + }) + .text + .clone(), + style: TextStyle { + color: Color::BLACK, ..default() }, - ..default() - }); - }); - }); - }); + }, + ], + ..default() + } + } + }) + }) } } @@ -171,22 +229,26 @@ mod collapse { pub fn show_child_number( events: Query<(Entity, &Children), (Changed<Children>, With<Node>)>, - mut tabs: Query<(&Collapse, &mut Title)>, + mut tabs: Query<(Entity, &Collapse)>, + mut commands: Commands, ) { // Any time a widget changes events.iter().for_each(|(entity, children)| { // Find any tabs which have this as a target tabs.iter_mut() - .find_map(|(collapse, title)| { + .find_map(|(button, collapse)| { if entity == collapse.target { - Some(title) + Some(button) } else { None } }) - .iter_mut() - .for_each(|title| { - title.note = Some(format!("({})", children.len().saturating_sub(1))) + .iter() + .for_each(|button| { + let num_children = children.len(); + commands.entity(*button).insert(Note { + text: format!("({})", num_children), + }); }); }); }