about to raze editor code

main
Elijah Voigt 2 years ago
parent 6ae7b094ad
commit a100fa8f4a

@ -22,7 +22,7 @@ use bevy::{
prelude::*, prelude::*,
utils::HashSet, utils::HashSet,
}; };
use monologue_trees::{debug::*, ui::*}; use monologue_trees::debug::*;
fn main() { fn main() {
App::new() App::new()
@ -36,7 +36,6 @@ fn main() {
..default() ..default()
}), }),
DebugInfoPlugin, DebugInfoPlugin,
GameUiPlugin,
)) ))
.init_resource::<AssetRegistry>() .init_resource::<AssetRegistry>()
.add_systems(Startup, (initialize_ui,)) .add_systems(Startup, (initialize_ui,))
@ -63,7 +62,6 @@ fn main() {
export_level, export_level,
import_level, import_level,
// Misc/Debug Systems // Misc/Debug Systems
load_bogus,
), ),
) )
.run(); .run();
@ -101,8 +99,8 @@ fn initialize_ui(mut commands: Commands) {
.with_children(|parent| { .with_children(|parent| {
parent parent
.spawn(( .spawn((
GameUiList,
Name::new("GLTFs"), Name::new("GLTFs"),
GltfsUi,
NodeBundle { NodeBundle {
style: Style { style: Style {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
@ -110,31 +108,19 @@ fn initialize_ui(mut commands: Commands) {
}, },
..default() ..default()
}, },
GltfsUi,
)) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn((Name::new("Scenes"), ScenesUi, NodeBundle { ..default() }));
parent.spawn((Name::new("Cameras"), CamerasUi, NodeBundle { ..default() }));
parent.spawn(( parent.spawn((
GameUiList,
Name::new("Scenes"),
NodeBundle { ..default() },
ScenesUi,
));
parent.spawn((
GameUiList,
Name::new("Cameras"),
NodeBundle { ..default() },
CamerasUi,
));
parent.spawn((
GameUiList,
Name::new("Animations"), Name::new("Animations"),
NodeBundle { ..default() },
AnimationsUi, AnimationsUi,
NodeBundle { ..default() },
)); ));
}); });
parent.spawn(( parent.spawn((
GameUiSet,
Name::new("Audio Clips"), Name::new("Audio Clips"),
AudioClipsUi,
NodeBundle { NodeBundle {
style: Style { style: Style {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
@ -142,30 +128,10 @@ fn initialize_ui(mut commands: Commands) {
}, },
..default() ..default()
}, },
AudioClipsUi,
)); ));
}); });
} }
fn load_bogus(
mut events: EventReader<KeyboardInput>,
root: Query<Entity, (With<AnimationsUi>, Without<UiRef<Handle<AnimationClip>>>)>,
mut commands: Commands,
) {
events
.iter()
.filter(
|&KeyboardInput {
key_code, state, ..
}| *key_code == Some(KeyCode::Space) && *state == ButtonState::Pressed,
)
.for_each(|_| {
commands
.spawn((GameUiButton, Name::new("bogus"), NodeBundle { ..default() }))
.set_parent(root.single());
})
}
#[derive(Resource, Default, Debug)] #[derive(Resource, Default, Debug)]
struct AssetRegistry(HashSet<HandleUntyped>); struct AssetRegistry(HashSet<HandleUntyped>);
@ -233,10 +199,9 @@ fn manage_gltf_ui(
}); });
commands commands
.spawn(( .spawn((
GameUiButton,
Name::new(name), Name::new(name),
NodeBundle { ..default() },
GltfsUi, GltfsUi,
ButtonBundle { ..default() },
UiRef::Handle(handle.clone()), UiRef::Handle(handle.clone()),
)) ))
.set_parent(root.single()); .set_parent(root.single());
@ -283,10 +248,9 @@ fn manage_scene_ui(
.for_each(|(handle, name)| { .for_each(|(handle, name)| {
commands commands
.spawn(( .spawn((
GameUiButton,
Name::new(name), Name::new(name),
NodeBundle { ..default() },
ScenesUi, ScenesUi,
ButtonBundle { ..default() },
UiRef::Handle(handle.clone()), UiRef::Handle(handle.clone()),
)) ))
.set_parent(root.single()); .set_parent(root.single());
@ -336,10 +300,9 @@ fn manage_animation_ui(
.for_each(|(handle, name)| { .for_each(|(handle, name)| {
commands commands
.spawn(( .spawn((
GameUiButton,
Name::new(name), Name::new(name),
NodeBundle { ..default() },
AnimationsUi, AnimationsUi,
ButtonBundle { ..default() },
UiRef::Handle(handle.clone()), UiRef::Handle(handle.clone()),
)) ))
.set_parent(root.single()); .set_parent(root.single());
@ -390,9 +353,8 @@ fn manage_audio_ui(
.for_each(|(handle, name)| { .for_each(|(handle, name)| {
commands commands
.spawn(( .spawn((
GameUiButton,
Name::new(name), Name::new(name),
NodeBundle { ..default() }, ButtonBundle { ..default() },
AudioClipsUi, AudioClipsUi,
AudioBundle { AudioBundle {
source: handle.clone(), source: handle.clone(),
@ -409,21 +371,13 @@ fn manage_audio_ui(
/// Play/Loop Audio /// Play/Loop Audio
fn play_audio( fn play_audio(
mut events: Query< mut events: Query<(&Interaction, &AudioSink), (Changed<Interaction>, With<AudioClipsUi>)>,
(&Interaction, &AudioSink, &mut UiElementState),
(Changed<Interaction>, With<AudioClipsUi>),
>,
) { ) {
events events
.iter_mut() .iter_mut()
.for_each(|(interaction, sink, mut state)| match interaction { .for_each(|(interaction, sink)| match interaction {
Interaction::Pressed => { Interaction::Pressed => {
sink.toggle(); sink.toggle();
*state = match *state {
UiElementState::Enabled => UiElementState::Active,
_ => UiElementState::Enabled,
}
} }
_ => (), _ => (),
}); });

@ -68,140 +68,27 @@ fn spawn_tree(parent: &mut ChildBuilder, pos: UiKitPosition, depth: u8, length:
}; };
(0..length).for_each(|_| { (0..length).for_each(|_| {
parent parent
.spawn(UiKitButton::new(Color::PINK)) .spawn((
UiKitButton { color: Color::PINK },
UiKitSelect::default(),
UiKitLabel {
name: "Button".into(),
},
))
.with_children(|parent| { .with_children(|parent| {
if depth > 1 { if depth > 1 {
parent parent
.spawn(UiKitContainer::new(pos)) .spawn((
UiKitContainer { position: pos },
UiKitSelect::default(),
UiKitLabel { name: "Tab".into() },
))
.with_children(|parent| { .with_children(|parent| {
spawn_tree(parent, pos2, depth - 1, length); spawn_tree(parent, pos2, depth - 1, length);
}); });
} }
}); });
}); });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos))
// .with_children(|parent| {
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos))
// .with_children(|parent| {
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos))
// .with_children(|parent| {
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// parent
// .spawn(UiKitButton::new(Color::PINK))
// .with_children(|parent| {
// parent
// .spawn(UiKitContainer::new(pos2))
// .with_children(|parent| {
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// parent.spawn(UiKitButton::new(Color::PINK));
// });
// });
// });
// });
} }
fn init_ui2(mut commands: Commands) { fn init_ui2(mut commands: Commands) {
@ -226,8 +113,8 @@ fn init_ui2(mut commands: Commands) {
.spawn(ButtonBundle { .spawn(ButtonBundle {
style: Style { style: Style {
border: UiRect::all(Val::Px(1.0)), border: UiRect::all(Val::Px(1.0)),
width: Val::Px(200.0), // width: Val::Px(200.0),
height: Val::Px(150.0), // height: Val::Px(150.0),
align_self: AlignSelf::Center, align_self: AlignSelf::Center,
..default() ..default()
}, },
@ -254,7 +141,7 @@ fn init_ui2(mut commands: Commands) {
..default() ..default()
}) })
.with_children(|parent| { .with_children(|parent| {
spawn_tree(parent, UiKitPosition::Left, 3, 7); spawn_tree(parent, UiKitPosition::Left, 3, 4);
}); });
parent parent
@ -289,7 +176,7 @@ fn init_ui2(mut commands: Commands) {
..default() ..default()
}) })
.with_children(|parent| { .with_children(|parent| {
spawn_tree(parent, UiKitPosition::Top, 3, 7); spawn_tree(parent, UiKitPosition::Top, 3, 3);
}); });
}); });
} }

@ -22,124 +22,194 @@ pub struct GameUiPlugin;
impl Plugin for GameUiPlugin { impl Plugin for GameUiPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Update, (select_tab, select_textbox, text_editor, scroll)) app.add_systems(Update, (select_tab, select_textbox, text_editor, scroll))
.add_systems(PostUpdate, selection); .add_systems(
PreUpdate,
(
spawn_container,
spawn_button,
/* manage_labels */ selection,
),
);
} }
} }
#[derive(Debug, Bundle)] pub use self::container::*;
mod container {
use super::*;
#[derive(Debug, Component)]
pub struct UiKitContainer { pub struct UiKitContainer {
node_bundle: NodeBundle, pub position: UiKitPosition,
select: UiKitSelect,
} }
#[derive(Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum UiKitPosition { pub enum UiKitPosition {
Top, Top,
Left, Left,
Right, Right,
} }
impl UiKitContainer { pub fn spawn_container(
pub fn new(position: UiKitPosition) -> Self { events: Query<(Entity, &UiKitContainer, Option<&UiKitLabel>), Added<UiKitContainer>>,
let style = match position { mut commands: Commands,
UiKitPosition::Top => Style { ) {
events.iter().for_each(|(entity, container, label)| {
let base_style = Style {
border: UiRect::all(Val::Px(1.0)), border: UiRect::all(Val::Px(1.0)),
top: Val::Percent(102.0),
left: Val::Px(-2.0),
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
align_items: AlignItems::FlexStart,
display: Display::None, display: Display::None,
..default() ..default()
};
let style = match container.position {
UiKitPosition::Top => Style {
top: Val::Percent(100.0),
align_items: AlignItems::Start,
..base_style
}, },
UiKitPosition::Left => Style { UiKitPosition::Left => Style {
border: UiRect::all(Val::Px(1.0)),
left: Val::Percent(100.0), left: Val::Percent(100.0),
top: Val::Px(-2.0),
flex_direction: FlexDirection::Column,
justify_items: JustifyItems::Start, justify_items: JustifyItems::Start,
display: Display::None, ..base_style
..default()
}, },
UiKitPosition::Right => Style { UiKitPosition::Right => Style {
border: UiRect::all(Val::Px(1.0)),
right: Val::Percent(104.0), right: Val::Percent(104.0),
top: Val::Px(-2.0),
flex_direction: FlexDirection::Column,
justify_items: JustifyItems::Start, justify_items: JustifyItems::Start,
display: Display::None, ..base_style
..default()
}, },
}; };
UiKitContainer { commands
node_bundle: NodeBundle { .entity(entity)
.insert(NodeBundle {
style, style,
background_color: BackgroundColor(Color::PURPLE), background_color: BackgroundColor(Color::PURPLE),
border_color: BorderColor(Color::BLACK), border_color: BorderColor(Color::BLACK),
..default() ..default()
})
.with_children(|parent| {
if let Some(label) = label {
parent.spawn(
TextBundle::from_section(
label.name.clone(),
TextStyle {
color: Color::BLACK,
..default()
}, },
select: UiKitSelect::None, )
.with_style(Style {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
}),
);
} }
});
})
} }
} }
#[derive(Debug, Bundle)] pub use self::label::*;
mod label {
use super::*;
#[derive(Debug, Component)]
pub struct UiKitLabel {
pub name: String,
}
// TODO: Handle modified labels
pub fn manage_labels(
events: Query<(Entity, &UiKitLabel), Added<UiKitLabel>>,
mut commands: Commands,
) {
events.iter().for_each(|(entity, label)| {
commands.entity(entity).with_children(|parent| {
parent.spawn(
TextBundle::from_section(
label.name.clone(),
TextStyle {
color: Color::BLACK,
..default()
},
)
.with_style(Style {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
}),
);
});
});
}
}
pub use self::button::*;
mod button {
use super::*;
#[derive(Debug, Component)]
pub struct UiKitButton { pub struct UiKitButton {
button_bundle: ButtonBundle, pub color: Color,
select: UiKitSelect,
} }
impl UiKitButton { pub fn spawn_button(
pub fn new(color: Color) -> Self { events: Query<(Entity, &UiKitButton, Option<&UiKitLabel>), Added<UiKitButton>>,
UiKitButton { mut commands: Commands,
button_bundle: ButtonBundle { ) {
events.iter().for_each(|(entity, button, label)| {
commands
.entity(entity)
.insert(ButtonBundle {
style: Style { style: Style {
border: UiRect::all(Val::Px(1.0)), border: UiRect::all(Val::Px(1.0)),
width: Val::Px(100.0), // width: Val::Px(100.0),
height: Val::Px(50.0), // height: Val::Px(50.0),
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
..default() ..default()
}, },
background_color: BackgroundColor(color), background_color: BackgroundColor(button.color),
border_color: BorderColor(Color::BLACK), border_color: BorderColor(Color::BLACK),
..default() ..default()
})
.with_children(|parent| {
if let Some(label) = label {
parent.spawn(
TextBundle::from_section(
label.name.clone(),
TextStyle {
color: Color::BLACK,
..default()
}, },
select: UiKitSelect::None, )
.with_style(Style {
align_self: AlignSelf::Center,
justify_self: JustifySelf::Center,
..default()
}),
);
} }
});
});
} }
} }
pub use self::select::*;
mod select {
use super::*;
#[derive(Debug, Component, Copy, Clone, PartialEq)] #[derive(Debug, Component, Copy, Clone, PartialEq)]
pub enum UiKitSelect { pub enum UiKitSelect {
Active, Active,
None, None,
} }
#[derive(Debug, Bundle)] impl Default for UiKitSelect {
pub struct UiKitTextInput { fn default() -> Self {
text_bundle: TextBundle, UiKitSelect::None
interaction: Interaction,
select: UiKitSelect,
}
impl UiKitTextInput {
pub fn new() -> Self {
UiKitTextInput {
text_bundle: TextBundle {
style: Style {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
..default()
},
..default()
},
interaction: Interaction::None,
select: UiKitSelect::None,
}
} }
} }
/// When an item is selected/de-selected change it's display accordingly /// When an item is selected/de-selected change it's display accordingly
fn selection( pub fn selection(
mut events: Query< mut events: Query<
(&mut BackgroundColor, &UiKitSelect, &Children), (&mut BackgroundColor, &UiKitSelect, &Children),
(Changed<UiKitSelect>, With<Button>), (Changed<UiKitSelect>, With<Button>),
@ -163,94 +233,37 @@ fn selection(
}); });
}); });
} }
/// Toggle a UI Nav tree open/closed
///
/// PERF: This is hella not performant, we just usually don't have many elements to iterate over so
/// it's tolerable.
///
// TODO: Should not be able to select multiple children in branch of tree
// TODO: Port to ui.rs
fn select_tab(
events: Query<Entity, (Changed<Interaction>, With<Button>)>,
interactions: Query<&Interaction, With<Button>>,
mut selects: Query<&mut UiKitSelect>,
parents: Query<&Parent>,
children: Query<&Children>,
) {
events.iter().for_each(|entity| {
// Otherwise, update nav tree(s)
if let Ok(interaction) = interactions.get(entity) {
match interaction {
Interaction::Pressed | Interaction::Hovered => {
{
let parent = parents.get(entity).expect("entity has parent");
children
.get(parent.get())
.expect("parent has children")
.iter()
.filter(|&e| *e != entity)
.for_each(|sibling| {
if let Ok(mut select) = selects.get_mut(*sibling) {
*select = UiKitSelect::None
}
});
} }
if let Ok(mut select) = selects.get_mut(entity) { pub use self::text_input::*;
*select = UiKitSelect::Active mod text_input {
} use super::*;
}
Interaction::None => {
// Find the ancestor which does not have a parent
let root_parent = parents
.iter_ancestors(entity)
.find(|&e| parents.get(e).is_err())
.expect("entity has root parent");
let family: Vec<Entity> = children.iter_descendants(root_parent).collect();
let family_inactive = family
.iter()
.filter_map(|member| interactions.get(*member).ok())
.all(|&interaction| interaction == Interaction::None);
// Zero out children
let descendants: Vec<Entity> = children.iter_descendants(entity).collect();
let descendants_inactive = descendants
.iter()
.filter_map(|child| interactions.get(*child).ok())
.all(|&interaction| interaction == Interaction::None);
// The entire tree is inactive #[derive(Debug, Bundle)]
if family_inactive { pub struct UiKitTextInput {
family.iter().for_each(|member| { text_bundle: TextBundle,
if let Ok(mut select) = selects.get_mut(*member) { interaction: Interaction,
*select = UiKitSelect::None select: UiKitSelect,
}
});
if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::None
}
// Just the sub-tree is inactive
} else if descendants_inactive {
descendants.iter().for_each(|child| {
if let Ok(mut select) = selects.get_mut(*child) {
*select = UiKitSelect::None
}
});
if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::None
}
// This node is active (usually a parent of an active child)
} else if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::Active
}
} }
impl UiKitTextInput {
pub fn new() -> Self {
UiKitTextInput {
text_bundle: TextBundle {
style: Style {
// width: Val::Percent(100.0),
// height: Val::Percent(100.0),
..default()
},
..default()
},
interaction: Interaction::None,
select: UiKitSelect::None,
} }
} }
});
} }
fn select_textbox( pub fn select_textbox(
mut events: Query<(&Interaction, &mut UiKitSelect), (With<Text>, Changed<Interaction>)>, mut events: Query<(&Interaction, &mut UiKitSelect), (With<Text>, Changed<Interaction>)>,
) { ) {
events.iter_mut().for_each(|(interaction, mut select)| { events.iter_mut().for_each(|(interaction, mut select)| {
@ -262,7 +275,7 @@ fn select_textbox(
}); });
} }
fn text_editor( pub fn text_editor(
keyboard: Res<Input<KeyCode>>, keyboard: Res<Input<KeyCode>>,
mut events: EventReader<KeyboardInput>, mut events: EventReader<KeyboardInput>,
mut query: Query<&mut Text, With<UiKitSelect>>, mut query: Query<&mut Text, With<UiKitSelect>>,
@ -290,8 +303,8 @@ fn text_editor(
} else { } else {
let c = match kc { let c = match kc {
// Letters // Letters
A | B | C | D | E | F | G | H | I | J | K | L | M | N | O A | B | C | D | E | F | G | H | I | J | K | L | M | N
| P | Q | R | S | T | U | V | W | X | Y | Z => { | O | P | Q | R | S | T | U | V | W | X | Y | Z => {
if keyboard.any_pressed([ShiftLeft, ShiftRight]) { if keyboard.any_pressed([ShiftLeft, ShiftRight]) {
format!("{:?}", kc).to_uppercase() format!("{:?}", kc).to_uppercase()
} else { } else {
@ -345,6 +358,90 @@ fn text_editor(
}, },
) )
} }
}
/// Toggle a UI Nav tree open/closed
///
/// PERF: This is hella not performant, we just usually don't have many elements to iterate over so
/// it's tolerable.
pub fn select_tab(
events: Query<Entity, (Changed<Interaction>, With<Button>)>,
interactions: Query<&Interaction, With<Button>>,
mut selects: Query<&mut UiKitSelect>,
parents: Query<&Parent>,
children: Query<&Children>,
) {
events.iter().for_each(|entity| {
// Otherwise, update nav tree(s)
if let Ok(interaction) = interactions.get(entity) {
match interaction {
Interaction::Pressed | Interaction::Hovered => {
{
let parent = parents.get(entity).expect("entity has parent");
children
.get(parent.get())
.expect("parent has children")
.iter()
.filter(|&e| *e != entity)
.for_each(|sibling| {
if let Ok(mut select) = selects.get_mut(*sibling) {
*select = UiKitSelect::None
}
});
}
if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::Active
}
}
Interaction::None => {
// Find the ancestor which does not have a parent
let root_parent = parents
.iter_ancestors(entity)
.find(|&e| parents.get(e).is_err())
.expect("entity has root parent");
let family: Vec<Entity> = children.iter_descendants(root_parent).collect();
let family_inactive = family
.iter()
.filter_map(|member| interactions.get(*member).ok())
.all(|&interaction| interaction == Interaction::None);
// Zero out children
let descendants: Vec<Entity> = children.iter_descendants(entity).collect();
let descendants_inactive = descendants
.iter()
.filter_map(|child| interactions.get(*child).ok())
.all(|&interaction| interaction == Interaction::None);
// The entire tree is inactive
if family_inactive {
family.iter().for_each(|member| {
if let Ok(mut select) = selects.get_mut(*member) {
*select = UiKitSelect::None
}
});
if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::None
}
// Just the sub-tree is inactive
} else if descendants_inactive {
descendants.iter().for_each(|child| {
if let Ok(mut select) = selects.get_mut(*child) {
*select = UiKitSelect::None
}
});
if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::None
}
// This node is active (usually a parent of an active child)
} else if let Ok(mut select) = selects.get_mut(entity) {
*select = UiKitSelect::Active
}
}
}
}
});
}
// TODO: Reset default position when de-activated // TODO: Reset default position when de-activated
fn scroll( fn scroll(
@ -367,7 +464,7 @@ fn scroll(
// Find the leaf selected entity // Find the leaf selected entity
let leaf = query let leaf = query
.iter() .iter()
.find(|(_, select, _, children, parent)| { .find(|(_, select, _, children, _)| {
// This node is active // This node is active
let self_active = **select == UiKitSelect::Active; let self_active = **select == UiKitSelect::Active;
// All children are not selected // All children are not selected
@ -391,7 +488,6 @@ fn scroll(
MouseScrollUnit::Pixel => 5.0, MouseScrollUnit::Pixel => 5.0,
}; };
style.top.try_sub_assign(Val::Px(delta)); style.top.try_sub_assign(Val::Px(delta));
info!("Top: {:?}", style.top);
} }
} }
}; };

Loading…
Cancel
Save