|
|
|
@ -1,21 +1,32 @@
|
|
|
|
/// TODO:
|
|
|
|
/// TODO:
|
|
|
|
/// * Text box w/ clear button
|
|
|
|
/// * Text box w/ clear button
|
|
|
|
/// * Names/Labels management
|
|
|
|
|
|
|
|
/// * Button color management
|
|
|
|
/// * Button color management
|
|
|
|
/// * Move code to submodules
|
|
|
|
/// * Move code to submodules
|
|
|
|
|
|
|
|
/// * Generic Minimize/Close Components
|
|
|
|
|
|
|
|
/// * Notice/Warning/Error Popups
|
|
|
|
|
|
|
|
/// * Textbox (ReadOnly)
|
|
|
|
|
|
|
|
/// * Textbox (ReadWrite)
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// BUGS:
|
|
|
|
/// BUGS:
|
|
|
|
/// * When selecting one tree, possible to select another without the first closing.
|
|
|
|
/// * Active::Multi (ex: Audio) vs Active::Single (ex: Assets, Gltf) for different tabs
|
|
|
|
///
|
|
|
|
///
|
|
|
|
use bevy::{
|
|
|
|
use bevy::{
|
|
|
|
input::{
|
|
|
|
asset::Asset,
|
|
|
|
keyboard::KeyboardInput,
|
|
|
|
input::mouse::{MouseScrollUnit, MouseWheel},
|
|
|
|
mouse::{MouseScrollUnit, MouseWheel},
|
|
|
|
|
|
|
|
ButtonState,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
prelude::*,
|
|
|
|
prelude::*,
|
|
|
|
window::PrimaryWindow,
|
|
|
|
window::PrimaryWindow,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
use std::cmp::PartialEq;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component, PartialEq)]
|
|
|
|
|
|
|
|
pub struct TargetAsset<T: Asset> {
|
|
|
|
|
|
|
|
pub handle: Handle<T>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component, PartialEq)]
|
|
|
|
|
|
|
|
pub struct TargetEntity {
|
|
|
|
|
|
|
|
pub entity: Entity,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub struct GameUiPlugin;
|
|
|
|
pub struct GameUiPlugin;
|
|
|
|
|
|
|
|
|
|
|
|
@ -28,7 +39,9 @@ impl Plugin for GameUiPlugin {
|
|
|
|
manage_button_interaction,
|
|
|
|
manage_button_interaction,
|
|
|
|
manage_cursor,
|
|
|
|
manage_cursor,
|
|
|
|
manage_scroll,
|
|
|
|
manage_scroll,
|
|
|
|
manage_collapse,
|
|
|
|
manage_collapse_active,
|
|
|
|
|
|
|
|
manage_collapse_hiding,
|
|
|
|
|
|
|
|
show_child_number,
|
|
|
|
manage_sort,
|
|
|
|
manage_sort,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
@ -39,33 +52,49 @@ pub use title::*;
|
|
|
|
mod title {
|
|
|
|
mod title {
|
|
|
|
use super::*;
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
#[derive(Debug, Component, Default)]
|
|
|
|
pub struct Title {
|
|
|
|
pub struct Title {
|
|
|
|
pub name: String,
|
|
|
|
pub name: String,
|
|
|
|
|
|
|
|
pub note: Option<String>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn init_titles(events: Query<(Entity, &Title), Added<Title>>, mut commands: Commands) {
|
|
|
|
pub fn init_titles(
|
|
|
|
events.for_each(|(entity, Title { name })| {
|
|
|
|
events: Query<(Entity, &Title), Or<(Changed<Title>, Added<Title>)>>,
|
|
|
|
commands.entity(entity).with_children(|parent| {
|
|
|
|
mut commands: Commands,
|
|
|
|
parent.spawn(TextBundle {
|
|
|
|
) {
|
|
|
|
text: Text {
|
|
|
|
events.for_each(|(entity, Title { name, note })| {
|
|
|
|
sections: vec![TextSection {
|
|
|
|
commands
|
|
|
|
value: name.clone(),
|
|
|
|
.entity(entity)
|
|
|
|
style: TextStyle {
|
|
|
|
.despawn_descendants()
|
|
|
|
color: Color::BLACK,
|
|
|
|
.with_children(|parent| {
|
|
|
|
..default()
|
|
|
|
parent.spawn(TextBundle {
|
|
|
|
},
|
|
|
|
text: Text {
|
|
|
|
}],
|
|
|
|
sections: vec![
|
|
|
|
..default()
|
|
|
|
TextSection {
|
|
|
|
},
|
|
|
|
value: name.clone(),
|
|
|
|
style: Style {
|
|
|
|
style: TextStyle {
|
|
|
|
margin: UiRect::all(Val::Px(5.0)),
|
|
|
|
color: Color::BLACK,
|
|
|
|
padding: UiRect::all(Val::Px(5.0)),
|
|
|
|
..default()
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
TextSection {
|
|
|
|
|
|
|
|
value: note.clone().unwrap_or(String::new()),
|
|
|
|
|
|
|
|
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()
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
});
|
|
|
|
..default()
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -79,22 +108,80 @@ mod collapse {
|
|
|
|
pub target: Entity,
|
|
|
|
pub target: Entity,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn manage_collapse(
|
|
|
|
pub fn manage_collapse_active(
|
|
|
|
events: Query<(Entity, &Collapse, &Interaction), (Changed<Interaction>, With<Button>)>,
|
|
|
|
events: Query<
|
|
|
|
mut styles: Query<&mut Style>,
|
|
|
|
(Entity, Option<&Active>, &Parent, &Interaction),
|
|
|
|
|
|
|
|
(Changed<Interaction>, With<Button>, With<Collapse>),
|
|
|
|
|
|
|
|
>,
|
|
|
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
active_children: Query<&Children>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
events
|
|
|
|
events
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
.filter(|(_, _, &interaction)| interaction == Interaction::Pressed)
|
|
|
|
.filter(|(_, _, _, &interaction)| interaction == Interaction::Pressed)
|
|
|
|
.for_each(|(entity, collapse, _)| {
|
|
|
|
.for_each(|(entity, active, parent, _)| {
|
|
|
|
info!("Collapse press on {:?}", entity);
|
|
|
|
match active {
|
|
|
|
if let Ok(mut style) = styles.get_mut(collapse.target) {
|
|
|
|
Some(_) => {
|
|
|
|
style.display = match style.display {
|
|
|
|
commands.entity(entity).remove::<Active>();
|
|
|
|
Display::None => Display::Flex,
|
|
|
|
}
|
|
|
|
Display::Flex | Display::Grid => Display::None,
|
|
|
|
None => {
|
|
|
|
};
|
|
|
|
// Set all other buttons to inactive
|
|
|
|
|
|
|
|
if let Ok(children) = active_children.get(parent.get()) {
|
|
|
|
|
|
|
|
children.iter().for_each(|child| {
|
|
|
|
|
|
|
|
commands.entity(*child).remove::<Active>();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set this butotn to active
|
|
|
|
|
|
|
|
commands.entity(entity).insert(Active);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn manage_collapse_hiding(
|
|
|
|
|
|
|
|
added: Query<Entity, (Added<Active>, With<Collapse>)>,
|
|
|
|
|
|
|
|
mut removed: RemovedComponents<Active>,
|
|
|
|
|
|
|
|
collapses: Query<&Collapse, With<Button>>,
|
|
|
|
|
|
|
|
mut styles: Query<&mut Style>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// Added collapse, display the target entity
|
|
|
|
|
|
|
|
added.iter().for_each(|e| {
|
|
|
|
|
|
|
|
if let Ok(Collapse { target }) = collapses.get(e) {
|
|
|
|
|
|
|
|
if let Ok(mut style) = styles.get_mut(*target) {
|
|
|
|
|
|
|
|
style.display = Display::Flex;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
// Removed collapse, hide the target entity
|
|
|
|
|
|
|
|
removed.iter().for_each(|e| {
|
|
|
|
|
|
|
|
if let Ok(Collapse { target }) = collapses.get(e) {
|
|
|
|
|
|
|
|
if let Ok(mut style) = styles.get_mut(*target) {
|
|
|
|
|
|
|
|
style.display = Display::None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn show_child_number(
|
|
|
|
|
|
|
|
events: Query<(Entity, &Children), (Changed<Children>, With<Node>)>,
|
|
|
|
|
|
|
|
mut tabs: Query<(&Collapse, &mut Title)>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// 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)| {
|
|
|
|
|
|
|
|
if entity == collapse.target {
|
|
|
|
|
|
|
|
Some(title)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.iter_mut()
|
|
|
|
|
|
|
|
.for_each(|title| {
|
|
|
|
|
|
|
|
title.note = Some(format!("({})", children.len().saturating_sub(1)))
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -106,22 +193,39 @@ mod buttons {
|
|
|
|
pub struct Active;
|
|
|
|
pub struct Active;
|
|
|
|
|
|
|
|
|
|
|
|
pub fn manage_button_interaction(
|
|
|
|
pub fn manage_button_interaction(
|
|
|
|
mut events: Query<
|
|
|
|
events: Query<
|
|
|
|
(&Interaction, &mut BackgroundColor, Option<&Active>),
|
|
|
|
(Entity, &Interaction, Option<&Active>),
|
|
|
|
(Changed<Interaction>, With<Button>),
|
|
|
|
(Changed<Interaction>, With<Button>),
|
|
|
|
>,
|
|
|
|
>,
|
|
|
|
|
|
|
|
added_active: Query<Entity, Added<Active>>,
|
|
|
|
|
|
|
|
mut removed_active: RemovedComponents<Active>,
|
|
|
|
|
|
|
|
mut bg_colors: Query<&mut BackgroundColor>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
events.for_each_mut(|(interaction, mut bg_color, active)| match active {
|
|
|
|
added_active.for_each(|e| {
|
|
|
|
Some(_) => match interaction {
|
|
|
|
if let Ok(mut bg_color) = bg_colors.get_mut(e) {
|
|
|
|
Interaction::None => *bg_color = Color::ORANGE.into(),
|
|
|
|
*bg_color = Color::ORANGE.into();
|
|
|
|
Interaction::Pressed => *bg_color = Color::YELLOW.into(),
|
|
|
|
}
|
|
|
|
Interaction::Hovered => *bg_color = Color::RED.into(),
|
|
|
|
});
|
|
|
|
},
|
|
|
|
removed_active.iter().for_each(|e| {
|
|
|
|
None => match interaction {
|
|
|
|
if let Ok(mut bg_color) = bg_colors.get_mut(e) {
|
|
|
|
Interaction::None => *bg_color = Color::GRAY.into(),
|
|
|
|
*bg_color = Color::WHITE.into();
|
|
|
|
Interaction::Pressed => *bg_color = Color::WHITE.into(),
|
|
|
|
}
|
|
|
|
Interaction::Hovered => *bg_color = Color::DARK_GRAY.into(),
|
|
|
|
});
|
|
|
|
},
|
|
|
|
events.for_each(|(entity, interaction, active)| {
|
|
|
|
|
|
|
|
if let Ok(mut bg_color) = bg_colors.get_mut(entity) {
|
|
|
|
|
|
|
|
match active {
|
|
|
|
|
|
|
|
Some(_) => match interaction {
|
|
|
|
|
|
|
|
Interaction::None => *bg_color = Color::ORANGE.into(),
|
|
|
|
|
|
|
|
Interaction::Pressed => *bg_color = Color::YELLOW.into(),
|
|
|
|
|
|
|
|
Interaction::Hovered => *bg_color = Color::RED.into(),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
None => match interaction {
|
|
|
|
|
|
|
|
Interaction::None => *bg_color = Color::WHITE.into(),
|
|
|
|
|
|
|
|
Interaction::Pressed => *bg_color = Color::WHITE.into(),
|
|
|
|
|
|
|
|
Interaction::Hovered => *bg_color = Color::GRAY.into(),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|