|
|
|
|
@ -9,6 +9,8 @@ impl Plugin for GameUiPlugin {
|
|
|
|
|
app.add_systems(
|
|
|
|
|
Update,
|
|
|
|
|
(
|
|
|
|
|
init_ui_nav,
|
|
|
|
|
init_ui_tab,
|
|
|
|
|
// UI lists
|
|
|
|
|
init_ui_list,
|
|
|
|
|
// UI Set
|
|
|
|
|
@ -16,109 +18,99 @@ impl Plugin for GameUiPlugin {
|
|
|
|
|
// Buttons
|
|
|
|
|
init_ui_button,
|
|
|
|
|
manage_button_interaction,
|
|
|
|
|
manage_button_title,
|
|
|
|
|
// Collapse systems
|
|
|
|
|
init_ui_collapse,
|
|
|
|
|
manage_collapse,
|
|
|
|
|
toggle_collapse,
|
|
|
|
|
// Cursor
|
|
|
|
|
manage_cursor,
|
|
|
|
|
// Initialize name labels
|
|
|
|
|
init_name,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Ui Navigation Element
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
struct UiNav;
|
|
|
|
|
|
|
|
|
|
/// Collapsed UI element
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub enum UiCollapse {
|
|
|
|
|
Show,
|
|
|
|
|
Hide,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Marker for UiCollapse Button
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
struct UiCollapseButton;
|
|
|
|
|
|
|
|
|
|
/// When a UiCollapse entity is created, populate the open/close button
|
|
|
|
|
fn init_ui_collapse(
|
|
|
|
|
events: Query<(Entity, &UiCollapse), Added<UiCollapse>>,
|
|
|
|
|
fn init_name(
|
|
|
|
|
events: Query<
|
|
|
|
|
(Entity, &Name),
|
|
|
|
|
(
|
|
|
|
|
Added<Name>,
|
|
|
|
|
Or<(
|
|
|
|
|
With<GameUiNav>,
|
|
|
|
|
With<GameUiTab>,
|
|
|
|
|
With<GameUiSet>,
|
|
|
|
|
With<GameUiList>,
|
|
|
|
|
With<GameUiButton>,
|
|
|
|
|
)>,
|
|
|
|
|
),
|
|
|
|
|
>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(|(entity, collapse)| {
|
|
|
|
|
events.iter().for_each(|(entity, name)| {
|
|
|
|
|
commands.entity(entity).with_children(|parent| {
|
|
|
|
|
let name = match collapse {
|
|
|
|
|
UiCollapse::Show => Name::new("Hide"),
|
|
|
|
|
UiCollapse::Hide => Name::new("Show"),
|
|
|
|
|
};
|
|
|
|
|
parent.spawn((
|
|
|
|
|
GameUiButton,
|
|
|
|
|
name,
|
|
|
|
|
UiCollapseButton,
|
|
|
|
|
NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
top: Val::Px(0.0),
|
|
|
|
|
right: Val::Px(0.0),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
parent.spawn(
|
|
|
|
|
TextBundle::from_section(name, TextStyle { ..default() }).with_style(Style {
|
|
|
|
|
top: Val::Px(0.0),
|
|
|
|
|
left: Val::Px(0.0),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
));
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn manage_collapse(
|
|
|
|
|
events: Query<(&UiCollapse, &Children), Changed<UiCollapse>>,
|
|
|
|
|
mut visibility: Query<(&mut Visibility, &mut Style), Without<UiCollapseButton>>,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(|(collapse, children)| {
|
|
|
|
|
children.iter().for_each(|&child| {
|
|
|
|
|
if let Ok((mut vis, mut style)) = visibility.get_mut(child) {
|
|
|
|
|
match collapse {
|
|
|
|
|
UiCollapse::Show => {
|
|
|
|
|
*vis = Visibility::Inherited;
|
|
|
|
|
style.display = Display::Flex;
|
|
|
|
|
}
|
|
|
|
|
UiCollapse::Hide => {
|
|
|
|
|
*vis = Visibility::Hidden;
|
|
|
|
|
style.display = Display::None;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
/// Ui Navigation
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub struct GameUiNav;
|
|
|
|
|
|
|
|
|
|
fn init_ui_nav(events: Query<Entity, Added<GameUiNav>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
let parent = commands
|
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
flex_direction: FlexDirection::Row,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::PINK),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.id();
|
|
|
|
|
|
|
|
|
|
commands
|
|
|
|
|
.entity(entity)
|
|
|
|
|
.insert(NodeBundle {
|
|
|
|
|
style: Style { ..default() },
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.set_parent(parent);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn toggle_collapse(
|
|
|
|
|
mut events: Query<
|
|
|
|
|
(&Interaction, &Parent, &mut Name),
|
|
|
|
|
(Changed<Interaction>, With<UiCollapseButton>),
|
|
|
|
|
>,
|
|
|
|
|
mut collapses: Query<&mut UiCollapse>,
|
|
|
|
|
) {
|
|
|
|
|
events
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.for_each(|(interaction, parent, mut name)| match interaction {
|
|
|
|
|
Interaction::Pressed => {
|
|
|
|
|
if let Ok(mut collapse) = collapses.get_mut(parent.get()) {
|
|
|
|
|
match *collapse {
|
|
|
|
|
UiCollapse::Show => {
|
|
|
|
|
*name = Name::new("Show");
|
|
|
|
|
*collapse = UiCollapse::Hide;
|
|
|
|
|
}
|
|
|
|
|
UiCollapse::Hide => {
|
|
|
|
|
*name = Name::new("Hide");
|
|
|
|
|
*collapse = UiCollapse::Show
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => (),
|
|
|
|
|
});
|
|
|
|
|
/// Ui Tab Element
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub struct GameUiTab;
|
|
|
|
|
|
|
|
|
|
fn init_ui_tab(events: Query<Entity, Added<GameUiTab>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
let parent = commands
|
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.id();
|
|
|
|
|
|
|
|
|
|
commands
|
|
|
|
|
.entity(entity)
|
|
|
|
|
.insert(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
flex_wrap: FlexWrap::Wrap,
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::TEAL),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.set_parent(parent);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Describes the state of an element
|
|
|
|
|
@ -135,32 +127,21 @@ pub enum UiElementState {
|
|
|
|
|
pub struct GameUiList;
|
|
|
|
|
|
|
|
|
|
/// Manage UI Lists: lists of UI entities.
|
|
|
|
|
fn init_ui_list(events: Query<(Entity, &Name), Added<GameUiList>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|(entity, name)| {
|
|
|
|
|
commands
|
|
|
|
|
.entity(entity)
|
|
|
|
|
.insert(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
justify_items: JustifyItems::Center,
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
margin: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
padding: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::RED),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
fn init_ui_list(events: Query<Entity, Added<GameUiList>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
commands.entity(entity).insert(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
justify_items: JustifyItems::Center,
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
margin: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
padding: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent.spawn(
|
|
|
|
|
TextBundle::from_section(name, TextStyle { ..default() }).with_style(Style {
|
|
|
|
|
top: Val::Px(0.0),
|
|
|
|
|
left: Val::Px(0.0),
|
|
|
|
|
..default()
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::RED),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -169,8 +150,22 @@ fn init_ui_list(events: Query<(Entity, &Name), Added<GameUiList>>, mut commands:
|
|
|
|
|
pub struct GameUiSet;
|
|
|
|
|
|
|
|
|
|
/// Manage UI Sets: collections of UI entities.
|
|
|
|
|
fn init_ui_set(events: Query<(Entity, &Name), Added<GameUiSet>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|(entity, name)| {
|
|
|
|
|
fn init_ui_set(events: Query<Entity, Added<GameUiSet>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
let parent = commands
|
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
padding: UiRect::all(Val::Px(5.0)),
|
|
|
|
|
margin: UiRect::all(Val::Px(5.0)),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::BLUE),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.id();
|
|
|
|
|
|
|
|
|
|
commands
|
|
|
|
|
.entity(entity)
|
|
|
|
|
.insert(NodeBundle {
|
|
|
|
|
@ -186,15 +181,7 @@ fn init_ui_set(events: Query<(Entity, &Name), Added<GameUiSet>>, mut commands: C
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
})
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent.spawn(
|
|
|
|
|
TextBundle::from_section(name, TextStyle { ..default() }).with_style(Style {
|
|
|
|
|
top: Val::Px(0.0),
|
|
|
|
|
left: Val::Px(0.0),
|
|
|
|
|
..default()
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
.set_parent(parent);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -203,27 +190,22 @@ fn init_ui_set(events: Query<(Entity, &Name), Added<GameUiSet>>, mut commands: C
|
|
|
|
|
pub struct GameUiButton;
|
|
|
|
|
|
|
|
|
|
/// Manage UI Buttons. interactive buttons.
|
|
|
|
|
fn init_ui_button(events: Query<(Entity, &Name), Added<GameUiButton>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|(entity, name)| {
|
|
|
|
|
commands
|
|
|
|
|
.entity(entity)
|
|
|
|
|
.insert((
|
|
|
|
|
ButtonBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
margin: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
padding: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
background_color: BackgroundColor(Color::GREEN),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
fn init_ui_button(events: Query<Entity, Added<GameUiButton>>, mut commands: Commands) {
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
commands.entity(entity).insert((
|
|
|
|
|
ButtonBundle {
|
|
|
|
|
style: Style {
|
|
|
|
|
margin: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
padding: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
border: UiRect::all(Val::Px(2.0)),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
UiElementState::Enabled,
|
|
|
|
|
))
|
|
|
|
|
.with_children(|parent| {
|
|
|
|
|
parent.spawn(TextBundle::from_section(name, TextStyle::default()));
|
|
|
|
|
});
|
|
|
|
|
background_color: BackgroundColor(Color::GREEN),
|
|
|
|
|
border_color: BorderColor(Color::BLACK),
|
|
|
|
|
..default()
|
|
|
|
|
},
|
|
|
|
|
UiElementState::Enabled,
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -250,19 +232,6 @@ fn manage_button_interaction(
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn manage_button_title(
|
|
|
|
|
events: Query<(&Name, &Children), (Changed<Name>, With<Button>)>,
|
|
|
|
|
mut texts: Query<&mut Text, With<Parent>>,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(|(name, children)| {
|
|
|
|
|
children.iter().for_each(|&child| {
|
|
|
|
|
if let Ok(mut text) = texts.get_mut(child) {
|
|
|
|
|
text.sections[0].value = name.into();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Manage the cursor icon for better immersion
|
|
|
|
|
fn manage_cursor(
|
|
|
|
|
mut primary_window: Query<&mut Window, With<PrimaryWindow>>,
|
|
|
|
|
|