|
|
|
@ -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);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|