Merge branch '56-add-ui-library' into 'dev'
Add UI Library See merge request softwaregrundprojekt/2025-2026/einzelprojekt/tutorium-moritz/bernroider-dominik/bernroider-dominik!15
This commit is contained in:
@@ -39,37 +39,27 @@ fn setup(mut commands: Commands) {
|
||||
},
|
||||
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||
children![
|
||||
(
|
||||
TextType::Phase,
|
||||
Text::new("..."),
|
||||
TextFont::from_font_size(16.0),
|
||||
TextColor(Color::WHITE)
|
||||
),
|
||||
(
|
||||
TextType::Timer,
|
||||
Text::new("--:--"),
|
||||
TextFont::from_font_size(16.0),
|
||||
TextColor(Color::WHITE)
|
||||
),
|
||||
(
|
||||
Button,
|
||||
text_with_component(TextType::Phase, "...", 16.0, Color::WHITE),
|
||||
text_with_component(TextType::Timer, "...", 16.0, Color::WHITE),
|
||||
button(
|
||||
inventory::components::ButtonType::InventoryOpen,
|
||||
Node::default(),
|
||||
children![(
|
||||
Text::new("Inventar"),
|
||||
TextFont::from_font_size(16.0),
|
||||
TextColor(Color::WHITE)
|
||||
)]
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
"Inventar",
|
||||
16.0
|
||||
),
|
||||
(
|
||||
Button,
|
||||
button(
|
||||
ButtonType::SettingsOpen,
|
||||
Node::default(),
|
||||
children![(
|
||||
Text::new("Einstellungen"),
|
||||
TextFont::from_font_size(16.0),
|
||||
TextColor(Color::WHITE)
|
||||
)]
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
"Einstellungen",
|
||||
16.0
|
||||
)
|
||||
],
|
||||
));
|
||||
|
||||
@@ -10,9 +10,7 @@ pub fn open_settings(commands: &mut Commands) {
|
||||
position_type: PositionType::Absolute,
|
||||
width: percent(100),
|
||||
height: percent(100),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
..Node::center()
|
||||
},
|
||||
ZIndex(1),
|
||||
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||
@@ -21,10 +19,9 @@ pub fn open_settings(commands: &mut Commands) {
|
||||
parent
|
||||
.spawn((
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(700),
|
||||
padding: UiRect::all(px(20.0)),
|
||||
..default()
|
||||
..Node::vstack(px(20))
|
||||
},
|
||||
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
||||
BorderRadius::all(px(10.0)),
|
||||
@@ -32,145 +29,97 @@ pub fn open_settings(commands: &mut Commands) {
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
Node {
|
||||
width: percent(100.0),
|
||||
justify_content: JustifyContent::SpaceBetween,
|
||||
align_items: AlignItems::Center,
|
||||
margin: UiRect::bottom(px(20.0)),
|
||||
column_gap: px(20.0),
|
||||
..default()
|
||||
..Node::hstack(px(20))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Spiel Einstellungen"),
|
||||
TextFont::from_font_size(40.0),
|
||||
TextColor(Color::WHITE),
|
||||
),
|
||||
(
|
||||
Button,
|
||||
text("Spiel Einstellungen", 40.0, Color::WHITE),
|
||||
pill_button(
|
||||
ButtonType::SettingsClose,
|
||||
ButtonVariant::Destructive,
|
||||
Node {
|
||||
width: px(40.0),
|
||||
height: px(40.0),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(40),
|
||||
height: px(40),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(Color::srgb(0.8, 0.2, 0.2)),
|
||||
BorderRadius::MAX,
|
||||
children![(
|
||||
Text::new("X"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE),
|
||||
)]
|
||||
)
|
||||
"X",
|
||||
24.0
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
parent
|
||||
.spawn(Node {
|
||||
width: percent(100),
|
||||
flex_direction: FlexDirection::Column,
|
||||
margin: UiRect::top(px(10.0)),
|
||||
row_gap: px(10.0),
|
||||
..default()
|
||||
})
|
||||
.spawn(Node::vstack(px(10)))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
Button,
|
||||
parent.spawn(button(
|
||||
ButtonType::SettingsExit,
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
width: percent(100),
|
||||
height: px(80),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::horizontal(px(10.0)),
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
BorderRadius::all(px(10)),
|
||||
children![(
|
||||
Text::new("Spiel verlassen"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE)
|
||||
)],
|
||||
"Spiel verlassen",
|
||||
24.0,
|
||||
));
|
||||
|
||||
parent.spawn((
|
||||
Button,
|
||||
parent.spawn(button(
|
||||
ButtonType::SettingsSave,
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
width: percent(100),
|
||||
height: px(80),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::horizontal(px(10.0)),
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
BorderRadius::all(px(10)),
|
||||
children![(
|
||||
Text::new("Spiel speichern"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE)
|
||||
)],
|
||||
"Spiel speichern",
|
||||
24.0,
|
||||
));
|
||||
|
||||
parent.spawn((
|
||||
Node {
|
||||
width: percent(100),
|
||||
flex_direction: FlexDirection::Row,
|
||||
justify_content: JustifyContent::SpaceBetween,
|
||||
align_items: AlignItems::Center,
|
||||
column_gap: px(10),
|
||||
padding: UiRect::horizontal(px(10.0)),
|
||||
..default()
|
||||
justify_content: JustifyContent::Center,
|
||||
..Node::hstack(px(30))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
row_gap: px(10),
|
||||
..default()
|
||||
width: percent(40),
|
||||
..Node::vstack(px(10))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Fokus Phase"),
|
||||
TextFont::from_font_size(12.0),
|
||||
TextColor(Color::WHITE)
|
||||
text("Spiel Einstellungen", 18.0, Color::WHITE),
|
||||
text(
|
||||
"Tipp: Benutze [Umstellen] um in 10er Schritten zu inkrementieren oder dekrementieren!",
|
||||
16.0,
|
||||
Color::WHITE
|
||||
),
|
||||
]
|
||||
),
|
||||
(
|
||||
Node {
|
||||
align_items: AlignItems::Center,
|
||||
..Node::vstack(px(10))
|
||||
},
|
||||
children![
|
||||
text("Fokus Phase", 12.0, Color::WHITE),
|
||||
timer_settings(TimerType::Focus)
|
||||
]
|
||||
),
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
row_gap: px(10),
|
||||
..default()
|
||||
..Node::vstack(px(10))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Kurze Pause"),
|
||||
TextFont::from_font_size(12.0),
|
||||
TextColor(Color::WHITE)
|
||||
),
|
||||
text("Kurze Pause", 12.0, Color::WHITE),
|
||||
timer_settings(TimerType::ShortBreak)
|
||||
]
|
||||
),
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
row_gap: px(10),
|
||||
..default()
|
||||
..Node::vstack(px(10))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Lange Pause"),
|
||||
TextFont::from_font_size(12.0),
|
||||
TextColor(Color::WHITE)
|
||||
),
|
||||
text("Lange Pause", 12.0, Color::WHITE),
|
||||
timer_settings(TimerType::LongBreak)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -4,17 +4,12 @@ use crate::prelude::*;
|
||||
pub fn timer_settings(timer_type: TimerType) -> impl Bundle {
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Row,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
..Node::hstack(px(0))
|
||||
},
|
||||
children![
|
||||
timer_settings_part(SettingsTimerInput::Minutes(timer_type.clone()), 1),
|
||||
(
|
||||
Text::new(":"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE)
|
||||
),
|
||||
text(":", 24.0, Color::WHITE),
|
||||
timer_settings_part(SettingsTimerInput::Seconds(timer_type.clone()), 1),
|
||||
],
|
||||
)
|
||||
@@ -22,52 +17,34 @@ pub fn timer_settings(timer_type: TimerType) -> impl Bundle {
|
||||
|
||||
fn timer_settings_part(input: SettingsTimerInput, amount: u32) -> impl Bundle {
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
..default()
|
||||
},
|
||||
Node::vstack(px(0)),
|
||||
children![
|
||||
(
|
||||
Button,
|
||||
button(
|
||||
ButtonType::SettingsTimerChange {
|
||||
input: input.clone(),
|
||||
amount: amount as i32
|
||||
},
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
width: auto(),
|
||||
justify_content: JustifyContent::Center,
|
||||
width: percent(100),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
children![
|
||||
Text::new("+"),
|
||||
TextFont::from_font_size(12.0),
|
||||
TextColor(Color::WHITE)
|
||||
]
|
||||
"+",
|
||||
12.0
|
||||
),
|
||||
(
|
||||
input.clone(),
|
||||
Text::new("--"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE)
|
||||
),
|
||||
(
|
||||
Button,
|
||||
text_with_component(input.clone(), "--", 24.0, Color::WHITE),
|
||||
button(
|
||||
ButtonType::SettingsTimerChange {
|
||||
input: input.clone(),
|
||||
amount: -(amount as i32),
|
||||
amount: -(amount as i32)
|
||||
},
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
width: auto(),
|
||||
justify_content: JustifyContent::Center,
|
||||
width: percent(100),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
children![
|
||||
Text::new("-"),
|
||||
TextFont::from_font_size(12.0),
|
||||
TextColor(Color::WHITE)
|
||||
]
|
||||
"-",
|
||||
12.0
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -9,9 +9,7 @@ pub fn open_inventory(commands: &mut Commands, items: Query<&ItemStack>) {
|
||||
position_type: PositionType::Absolute,
|
||||
width: percent(100),
|
||||
height: percent(100),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
..Node::center()
|
||||
},
|
||||
ZIndex(1),
|
||||
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||
@@ -20,10 +18,8 @@ pub fn open_inventory(commands: &mut Commands, items: Query<&ItemStack>) {
|
||||
parent
|
||||
.spawn((
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::all(px(20.0)),
|
||||
..default()
|
||||
..Node::vstack(px(0))
|
||||
},
|
||||
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
||||
BorderRadius::all(px(10.0)),
|
||||
@@ -33,45 +29,30 @@ pub fn open_inventory(commands: &mut Commands, items: Query<&ItemStack>) {
|
||||
Node {
|
||||
width: percent(100.0),
|
||||
justify_content: JustifyContent::SpaceBetween,
|
||||
align_items: AlignItems::Center,
|
||||
margin: UiRect::bottom(px(20.0)),
|
||||
column_gap: px(20.0),
|
||||
..default()
|
||||
..Node::hstack(px(20))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Inventar"),
|
||||
TextFont::from_font_size(40.0),
|
||||
TextColor(Color::WHITE),
|
||||
),
|
||||
(
|
||||
Button,
|
||||
text("Inventar", 40.0, Color::WHITE),
|
||||
pill_button(
|
||||
ButtonType::InventoryClose,
|
||||
ButtonVariant::Destructive,
|
||||
Node {
|
||||
width: px(40.0),
|
||||
height: px(40.0),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(40),
|
||||
height: px(40),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(Color::srgb(0.8, 0.2, 0.2)),
|
||||
BorderRadius::MAX,
|
||||
children![(
|
||||
Text::new("X"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE),
|
||||
)]
|
||||
)
|
||||
"X",
|
||||
24.0
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
parent
|
||||
.spawn(Node {
|
||||
width: percent(100),
|
||||
flex_direction: FlexDirection::Column,
|
||||
margin: UiRect::top(px(10.0)),
|
||||
row_gap: px(10.0),
|
||||
..default()
|
||||
..Node::vstack(px(10))
|
||||
})
|
||||
.with_children(|parent| {
|
||||
for itemstack in items.iter() {
|
||||
|
||||
@@ -8,13 +8,10 @@ pub fn list_itemstack(itemstack: &ItemStack) -> impl Bundle {
|
||||
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Row,
|
||||
column_gap: px(8),
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::all(px(4)),
|
||||
..default()
|
||||
..Node::hstack(px(8))
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
BackgroundColor(ButtonVariant::Secondary.normal_background()),
|
||||
BorderRadius::all(px(10)),
|
||||
children![
|
||||
(
|
||||
@@ -24,28 +21,22 @@ pub fn list_itemstack(itemstack: &ItemStack) -> impl Bundle {
|
||||
aspect_ratio: Some(1.0),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(HOVERED_BUTTON),
|
||||
BackgroundColor(ButtonVariant::Secondary.hover_background()),
|
||||
BorderRadius::all(px(10))
|
||||
),
|
||||
(
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
justify_content: JustifyContent::Center,
|
||||
row_gap: px(4),
|
||||
padding: UiRect::vertical(px(4)),
|
||||
..default()
|
||||
..Node::vstack(px(4))
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new(format!("{} ({})", name, itemstack.amount)),
|
||||
TextFont::from_font_size(14.0),
|
||||
TextColor(Color::WHITE)
|
||||
text(
|
||||
format!("{} ({})", name, itemstack.amount),
|
||||
14.0,
|
||||
Color::WHITE
|
||||
),
|
||||
(
|
||||
Text::new(itemstack.item_type.description()),
|
||||
TextFont::from_font_size(10.0),
|
||||
TextColor(Color::WHITE)
|
||||
)
|
||||
text(itemstack.item_type.description(), 10.0, Color::WHITE)
|
||||
]
|
||||
)
|
||||
],
|
||||
|
||||
@@ -92,3 +92,15 @@ impl SavegamePath {
|
||||
Self::new(next_index)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub enum RootMarker {
|
||||
PopupSavegameLoad,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub enum ButtonType {
|
||||
SavegameLoad { savegame_path: SavegamePath },
|
||||
SavegameDelete { savegame_path: SavegamePath },
|
||||
PopupClose,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::features::phase::components::{SessionTracker, TimerSettings};
|
||||
use crate::features::savegame::ui::load_popup_handler;
|
||||
use crate::prelude::*;
|
||||
use messages::*;
|
||||
use std::fs::File;
|
||||
@@ -6,6 +7,7 @@ use std::io::{Read, Write};
|
||||
|
||||
pub mod components;
|
||||
pub mod messages;
|
||||
pub mod ui;
|
||||
|
||||
pub struct SavegamePlugin;
|
||||
|
||||
@@ -16,6 +18,8 @@ impl Plugin for SavegamePlugin {
|
||||
|
||||
app.add_systems(Update, dump_savegame.run_if(in_state(AppState::GameScreen)));
|
||||
app.add_systems(Update, load_savegame.run_if(in_state(AppState::GameScreen)));
|
||||
|
||||
app.add_systems(Update, load_popup_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::super::components::*;
|
||||
use crate::prelude::*;
|
||||
use super::super::components::{ButtonType, RootMarker};
|
||||
use crate::{features::savegame::messages::SavegameLoadMessage, prelude::*};
|
||||
|
||||
pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
commands
|
||||
@@ -9,9 +9,7 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
position_type: PositionType::Absolute,
|
||||
width: percent(100),
|
||||
height: percent(100),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
..Node::center()
|
||||
},
|
||||
ZIndex(1),
|
||||
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||
@@ -22,13 +20,12 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
Node {
|
||||
width: px(600.0),
|
||||
height: px(500.0),
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::all(px(20.0)),
|
||||
..default()
|
||||
align_items: AlignItems::Center,
|
||||
..Node::vstack(px(10))
|
||||
},
|
||||
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
||||
BorderRadius::all(Val::Px(10.0)),
|
||||
BorderRadius::all(px(10.0)),
|
||||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
@@ -40,27 +37,17 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
..default()
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Spielstand Auswahl"),
|
||||
TextFont::from_font_size(40.0),
|
||||
TextColor(Color::WHITE),
|
||||
),
|
||||
(
|
||||
Button,
|
||||
text("Spielstand Auswahl", 40.0, Color::WHITE),
|
||||
pill_button(
|
||||
ButtonType::PopupClose,
|
||||
ButtonVariant::Destructive,
|
||||
Node {
|
||||
width: px(40.0),
|
||||
height: px(40.0),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(40),
|
||||
height: px(40),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(Color::srgb(0.8, 0.2, 0.2)),
|
||||
children![(
|
||||
Text::new("X"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::WHITE),
|
||||
)]
|
||||
"X",
|
||||
24.0
|
||||
)
|
||||
],
|
||||
));
|
||||
@@ -78,20 +65,20 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
for savegame in SavegamePath::list() {
|
||||
parent.spawn((
|
||||
Button,
|
||||
ButtonType::PopupSavegameLoad {
|
||||
ButtonType::SavegameLoad {
|
||||
savegame_path: savegame.path.clone(),
|
||||
},
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
width: percent(100),
|
||||
height: px(80),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
flex_direction: FlexDirection::Row,
|
||||
column_gap: px(10.0),
|
||||
padding: UiRect::horizontal(px(10.0)),
|
||||
..default()
|
||||
..Node::center()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
BackgroundColor(ButtonVariant::Secondary.normal_background()),
|
||||
BorderRadius::all(px(10)),
|
||||
children![
|
||||
(
|
||||
Node {
|
||||
@@ -102,43 +89,35 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
..default()
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new(format!(
|
||||
"Spielstand {}",
|
||||
savegame.index + 1
|
||||
)),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
text(
|
||||
format!("Spielstand {}", savegame.index + 1),
|
||||
24.0,
|
||||
Color::WHITE
|
||||
),
|
||||
(
|
||||
Text::new(format!(
|
||||
text(
|
||||
format!(
|
||||
"Beeren: {}, Fokusphasen abgeschlossen: {}",
|
||||
savegame.total_berries,
|
||||
savegame.completed_focus
|
||||
)),
|
||||
TextFont::from_font_size(18.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
)
|
||||
),
|
||||
18.0,
|
||||
Color::WHITE,
|
||||
),
|
||||
]
|
||||
),
|
||||
(
|
||||
Button,
|
||||
ButtonType::PopupSavegameDelete {
|
||||
pill_button(
|
||||
ButtonType::SavegameDelete {
|
||||
savegame_path: savegame.path.clone()
|
||||
},
|
||||
ButtonVariant::Destructive,
|
||||
Node {
|
||||
width: px(40.0),
|
||||
height: px(40.0),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(40),
|
||||
height: px(40),
|
||||
..default()
|
||||
},
|
||||
children![(
|
||||
Text::new("X"),
|
||||
TextFont::from_font_size(24.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
)]
|
||||
)
|
||||
"X",
|
||||
24.0
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
@@ -146,3 +125,38 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn load_popup_handler(
|
||||
mut commands: Commands,
|
||||
mut next_state: ResMut<NextState<AppState>>,
|
||||
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||
root_query: Query<(Entity, &RootMarker)>,
|
||||
mut savegame_messages: MessageWriter<SavegameLoadMessage>,
|
||||
) {
|
||||
for (interaction, button_type) in &mut interaction_query {
|
||||
match *interaction {
|
||||
Interaction::Pressed => {
|
||||
match button_type {
|
||||
ButtonType::PopupClose => {}
|
||||
ButtonType::SavegameLoad { savegame_path } => {
|
||||
commands.insert_resource(savegame_path.clone());
|
||||
next_state.set(AppState::GameScreen);
|
||||
savegame_messages.write(SavegameLoadMessage);
|
||||
}
|
||||
ButtonType::SavegameDelete { savegame_path } => {
|
||||
if let Err(e) = std::fs::remove_file(savegame_path.clone().0) {
|
||||
println!("Error while deleting savegame: {:?}", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (entity, root) in root_query.iter() {
|
||||
match *root {
|
||||
RootMarker::PopupSavegameLoad => commands.entity(entity).despawn(),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ use crate::prelude::*;
|
||||
#[derive(Component)]
|
||||
pub enum RootMarker {
|
||||
MainMenu,
|
||||
PopupSavegameLoad,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
@@ -11,7 +10,4 @@ pub enum ButtonType {
|
||||
LoadGame,
|
||||
NewGame,
|
||||
Settings,
|
||||
PopupSavegameLoad { savegame_path: SavegamePath },
|
||||
PopupSavegameDelete { savegame_path: SavegamePath },
|
||||
PopupClose,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::{features::savegame::messages::SavegameLoadMessage, prelude::*};
|
||||
use crate::features::savegame::ui::spawn_load_popup;
|
||||
use crate::prelude::*;
|
||||
use components::*;
|
||||
use ui::*;
|
||||
|
||||
pub mod components;
|
||||
pub mod ui;
|
||||
|
||||
pub struct StartScreenPlugin;
|
||||
|
||||
@@ -21,68 +20,45 @@ fn setup(mut commands: Commands) {
|
||||
Node {
|
||||
width: percent(100),
|
||||
height: percent(100),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
flex_direction: FlexDirection::Column,
|
||||
..default()
|
||||
row_gap: px(10),
|
||||
..Node::center()
|
||||
},
|
||||
children![
|
||||
(
|
||||
Text::new("Pomonon Garten"),
|
||||
TextFont::from_font_size(64.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
),
|
||||
(
|
||||
Button,
|
||||
text("Pomomon Garden", 64.0, Color::WHITE),
|
||||
button(
|
||||
ButtonType::LoadGame,
|
||||
ButtonVariant::Primary,
|
||||
Node {
|
||||
width: px(300),
|
||||
height: px(65),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(280),
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
children![(
|
||||
Text::new("Spiel laden"),
|
||||
TextFont::from_font_size(33.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
)]
|
||||
"Spiel laden",
|
||||
33.0
|
||||
),
|
||||
(
|
||||
Button,
|
||||
button(
|
||||
ButtonType::NewGame,
|
||||
ButtonVariant::Primary,
|
||||
Node {
|
||||
width: px(300),
|
||||
height: px(65),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(280),
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
children![(
|
||||
Text::new("Neues Spiel"),
|
||||
TextFont::from_font_size(33.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
)]
|
||||
"Neues Spiel",
|
||||
33.0,
|
||||
),
|
||||
(
|
||||
Button,
|
||||
button(
|
||||
ButtonType::Settings,
|
||||
ButtonVariant::Secondary,
|
||||
Node {
|
||||
width: px(300),
|
||||
height: px(65),
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
width: px(280),
|
||||
padding: UiRect::all(px(10)),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(NORMAL_BUTTON),
|
||||
children![(
|
||||
Text::new("Einstellungen"),
|
||||
TextFont::from_font_size(33.0),
|
||||
TextColor(Color::srgb(0.9, 0.9, 0.9))
|
||||
)]
|
||||
)
|
||||
"Einstellungen",
|
||||
33.0
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
@@ -90,18 +66,11 @@ fn setup(mut commands: Commands) {
|
||||
fn menu(
|
||||
mut commands: Commands,
|
||||
mut next_state: ResMut<NextState<AppState>>,
|
||||
mut interaction_query: Query<
|
||||
(&Interaction, &ButtonType, &mut BackgroundColor),
|
||||
(Changed<Interaction>, With<Button>),
|
||||
>,
|
||||
root_query: Query<(Entity, &RootMarker)>,
|
||||
mut savegame_messages: MessageWriter<SavegameLoadMessage>,
|
||||
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||
) {
|
||||
for (interaction, button_type, mut color) in &mut interaction_query {
|
||||
for (interaction, button_type) in &mut interaction_query {
|
||||
match *interaction {
|
||||
Interaction::Pressed => {
|
||||
*color = PRESSED_BUTTON.into();
|
||||
|
||||
match button_type {
|
||||
ButtonType::LoadGame => {
|
||||
spawn_load_popup(&mut commands);
|
||||
@@ -110,40 +79,10 @@ fn menu(
|
||||
commands.insert_resource(SavegamePath::next());
|
||||
next_state.set(AppState::GameScreen);
|
||||
}
|
||||
ButtonType::PopupClose => {
|
||||
for (entity, root) in root_query.iter() {
|
||||
match *root {
|
||||
RootMarker::PopupSavegameLoad => commands.entity(entity).despawn(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
ButtonType::PopupSavegameLoad { savegame_path } => {
|
||||
commands.insert_resource(savegame_path.clone());
|
||||
next_state.set(AppState::GameScreen);
|
||||
savegame_messages.write(SavegameLoadMessage);
|
||||
}
|
||||
ButtonType::PopupSavegameDelete { savegame_path } => {
|
||||
if let Err(e) = std::fs::remove_file(savegame_path.clone().0) {
|
||||
println!("Error while deleting savegame: {:?}", e);
|
||||
}
|
||||
|
||||
for (entity, root) in root_query.iter() {
|
||||
match *root {
|
||||
RootMarker::PopupSavegameLoad => commands.entity(entity).despawn(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
ButtonType::Settings => todo!(),
|
||||
};
|
||||
}
|
||||
Interaction::Hovered => {
|
||||
*color = HOVERED_BUTTON.into();
|
||||
}
|
||||
Interaction::None => {
|
||||
*color = NORMAL_BUTTON.into();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,3 +6,43 @@ pub struct Scroll {
|
||||
pub entity: Entity,
|
||||
pub delta: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
pub enum ButtonVariant {
|
||||
Primary,
|
||||
Secondary,
|
||||
Destructive,
|
||||
}
|
||||
|
||||
impl ButtonVariant {
|
||||
pub fn normal_background(&self) -> Color {
|
||||
match self {
|
||||
ButtonVariant::Primary => Color::srgb(0.35, 0.17, 0.78),
|
||||
ButtonVariant::Secondary => Color::srgb(0.15, 0.15, 0.15),
|
||||
ButtonVariant::Destructive => Color::srgb(0.79, 0.17, 0.20),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hover_background(&self) -> Color {
|
||||
match self {
|
||||
ButtonVariant::Primary => Color::srgb(0.45, 0.27, 0.88),
|
||||
ButtonVariant::Secondary => Color::srgb(0.25, 0.25, 0.25),
|
||||
ButtonVariant::Destructive => Color::srgb(0.89, 0.27, 0.30),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pressed_background(&self) -> Color {
|
||||
match self {
|
||||
ButtonVariant::Primary => Color::srgb(0.55, 0.37, 0.98),
|
||||
ButtonVariant::Secondary => Color::srgb(0.35, 0.35, 0.35),
|
||||
ButtonVariant::Destructive => Color::srgb(0.99, 0.37, 0.40),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_color(&self) -> Color {
|
||||
match self {
|
||||
ButtonVariant::Primary | ButtonVariant::Destructive => Color::srgb(0.1, 0.1, 0.1),
|
||||
ButtonVariant::Secondary => Color::WHITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
use crate::prelude::{button::update_buttons, *};
|
||||
use bevy::{input::mouse::*, picking::hover::HoverMap};
|
||||
|
||||
pub mod components;
|
||||
pub mod consts;
|
||||
pub mod ui;
|
||||
|
||||
pub struct UiPlugin;
|
||||
|
||||
@@ -10,6 +11,8 @@ impl Plugin for UiPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, scroll_events);
|
||||
app.add_observer(on_scroll_handler);
|
||||
|
||||
app.add_systems(Update, update_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
src/features/ui/ui/button.rs
Normal file
59
src/features/ui/ui/button.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn button(
|
||||
button_type: impl Component,
|
||||
variant: ButtonVariant,
|
||||
mut node: Node,
|
||||
title: impl Into<String>,
|
||||
font_size: f32,
|
||||
) -> impl Bundle {
|
||||
node.justify_content = JustifyContent::Center;
|
||||
node.align_items = AlignItems::Center;
|
||||
|
||||
(
|
||||
Button,
|
||||
button_type,
|
||||
variant.clone(),
|
||||
node,
|
||||
BackgroundColor(variant.normal_background()),
|
||||
BorderRadius::all(px(10)),
|
||||
children![text(title, font_size, variant.text_color())],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pill_button(
|
||||
button_type: impl Component,
|
||||
variant: ButtonVariant,
|
||||
mut node: Node,
|
||||
title: impl Into<String>,
|
||||
font_size: f32,
|
||||
) -> impl Bundle {
|
||||
node.justify_content = JustifyContent::Center;
|
||||
node.align_items = AlignItems::Center;
|
||||
|
||||
(
|
||||
Button,
|
||||
button_type,
|
||||
variant.clone(),
|
||||
node,
|
||||
BackgroundColor(variant.normal_background()),
|
||||
BorderRadius::MAX,
|
||||
children![text(title, font_size, variant.text_color())],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn update_buttons(
|
||||
mut interaction_query: Query<
|
||||
(&Interaction, &ButtonVariant, &mut BackgroundColor),
|
||||
(Changed<Interaction>, With<Button>),
|
||||
>,
|
||||
) {
|
||||
for (interaction, variant, mut color) in &mut interaction_query {
|
||||
*color = match *interaction {
|
||||
Interaction::None => variant.normal_background(),
|
||||
Interaction::Hovered => variant.hover_background(),
|
||||
Interaction::Pressed => variant.pressed_background(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
33
src/features/ui/ui/flexbox.rs
Normal file
33
src/features/ui/ui/flexbox.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
pub trait Flexbox {
|
||||
fn hstack(spacing: Val) -> Self;
|
||||
fn vstack(spacing: Val) -> Self;
|
||||
fn center() -> Self;
|
||||
}
|
||||
|
||||
impl Flexbox for Node {
|
||||
fn hstack(spacing: Val) -> Self {
|
||||
Self {
|
||||
flex_direction: FlexDirection::Row,
|
||||
column_gap: spacing,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
fn vstack(spacing: Val) -> Self {
|
||||
Self {
|
||||
flex_direction: FlexDirection::Column,
|
||||
row_gap: spacing,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
fn center() -> Self {
|
||||
Self {
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/features/ui/ui/mod.rs
Normal file
7
src/features/ui/ui/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
pub mod button;
|
||||
pub mod flexbox;
|
||||
pub mod texts;
|
||||
|
||||
pub use button::{button, pill_button};
|
||||
pub use flexbox::Flexbox;
|
||||
pub use texts::{text, text_with_component};
|
||||
19
src/features/ui/ui/texts.rs
Normal file
19
src/features/ui/ui/texts.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
pub use crate::prelude::*;
|
||||
|
||||
pub fn text(content: impl Into<String>, size: f32, color: Color) -> (Text, TextFont, TextColor) {
|
||||
(
|
||||
Text::new(content),
|
||||
TextFont::from_font_size(size),
|
||||
TextColor(color),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn text_with_component(
|
||||
component: impl Component,
|
||||
content: impl Into<String>,
|
||||
size: f32,
|
||||
color: Color,
|
||||
) -> impl Bundle {
|
||||
let (a, b, c) = text(content, size, color);
|
||||
(component, a, b, c)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ pub use crate::features::{
|
||||
messages::{InteractStartMessage, MoveMessage},
|
||||
},
|
||||
savegame::components::SavegamePath,
|
||||
ui::consts::*,
|
||||
ui::{components::ButtonVariant, consts::*, ui::*},
|
||||
};
|
||||
pub use crate::utils::path::get_internal_path;
|
||||
pub use bevy::prelude::*;
|
||||
|
||||
Reference in New Issue
Block a user