diff --git a/goryak/src/window.rs b/goryak/src/window.rs index be13a5c5..35620ca9 100644 --- a/goryak/src/window.rs +++ b/goryak/src/window.rs @@ -13,10 +13,11 @@ use crate::{ }; pub struct Window<'a> { - pub title: &'static str, + pub title: Cow<'static, str>, pub pad: Pad, pub radius: f32, pub opened: &'a mut bool, + pub child_spacing: f32, } impl<'a> Window<'a> { @@ -53,9 +54,13 @@ impl<'a> Window<'a> { }); }); }); - textc(on_primary_container(), Cow::Borrowed(self.title)); + textc(on_primary_container(), self.title); divider(outline(), 10.0, 1.0); - children(); + if self.child_spacing != 0.0 { + mincolumn(self.child_spacing, children); + } else { + children(); + } }); }); }); diff --git a/native_app/src/gui/inspect/inspect_human.rs b/native_app/src/gui/inspect/inspect_human.rs deleted file mode 100644 index 53ee37b3..00000000 --- a/native_app/src/gui/inspect/inspect_human.rs +++ /dev/null @@ -1,118 +0,0 @@ -use egui::{Context, Widget}; -use prototypes::ItemID; - -use simulation::economy::Market; -use simulation::map_dynamic::Destination; -use simulation::souls::desire::WorkKind; -use simulation::transportation::Location; -use simulation::{HumanID, Simulation}; - -use crate::gui::inspect::{building_link, follow_button}; -use crate::gui::item_icon; -use crate::uiworld::UiWorld; - -/// Inspect a specific building, showing useful information about it -pub fn inspect_human(uiworld: &UiWorld, sim: &Simulation, ui: &Context, id: HumanID) -> bool { - let Some(human) = sim.get(id) else { - return false; - }; - - let mut is_open = true; - egui::Window::new("Human") - .resizable(false) - .auto_sized() - .open(&mut is_open) - .show(ui, |ui| { - if cfg!(debug_assertions) { - ui.label(format!("{:?}", id)); - } - let pinfo = &human.personal_info; - ui.label(format!("{}{:?} • {}", pinfo.age, pinfo.gender, pinfo.name)); - - match human.location { - Location::Outside => {} - Location::Vehicle(_) => { - ui.label("In a vehicle"); - } - Location::Building(x) => { - ui.horizontal(|ui| { - ui.label("In a building:"); - building_link(uiworld, sim, ui, x); - }); - } - } - - if let Some(ref dest) = human.router.target_dest { - match dest { - Destination::Outside(pos) => { - ui.label(format!("Going to {}", pos)); - } - Destination::Building(b) => { - ui.horizontal(|ui| { - ui.label("Going to building"); - building_link(uiworld, sim, ui, *b); - }); - } - } - } - - ui.horizontal(|ui| { - ui.label("House is"); - building_link(uiworld, sim, ui, human.home.house); - }); - - ui.label(format!("Last ate: {}", human.food.last_ate)); - - if let Some(ref x) = human.work { - ui.horizontal(|ui| { - ui.label("Working at"); - building_link(uiworld, sim, ui, x.workplace); - match x.kind { - WorkKind::Driver { .. } => { - ui.label("as a driver"); - } - WorkKind::Worker => { - ui.label("as a worker"); - } - } - }); - } - - ui.add_space(10.0); - ui.label("Desires"); - ui.horizontal(|ui| { - let mut score = human.food.last_score; - egui::DragValue::new(&mut score).ui(ui); - ui.label("Food"); - }); - ui.horizontal(|ui| { - let mut score = human.home.last_score; - egui::DragValue::new(&mut score).ui(ui); - ui.label("Home"); - }); - ui.horizontal(|ui| { - let mut score = human.work.as_ref().map(|x| x.last_score).unwrap_or(0.0); - egui::DragValue::new(&mut score).ui(ui); - ui.label("Work"); - }); - - let market = sim.read::(); - - ui.add_space(10.0); - - let jobopening = ItemID::new("job-opening"); - for (&item_id, m) in market.iter() { - let Some(v) = m.capital(id.into()) else { - continue; - }; - if item_id == jobopening { - continue; - } - - item_icon(ui, uiworld, item_id, v); - } - - follow_button(uiworld, ui, id); - }); - is_open -} diff --git a/native_app/src/gui/inspect/inspect_vehicle.rs b/native_app/src/gui/inspect/inspect_vehicle.rs deleted file mode 100644 index 85ab0444..00000000 --- a/native_app/src/gui/inspect/inspect_vehicle.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::gui::inspect::{entity_link, follow_button}; -use crate::uiworld::UiWorld; -use egui::Context; -use simulation::transportation::VehicleState; -use simulation::{Simulation, VehicleID}; - -pub fn inspect_vehicle(uiworld: &UiWorld, sim: &Simulation, ui: &Context, id: VehicleID) -> bool { - let Some(v) = sim.get(id) else { - return false; - }; - - let name = format!("{:?}", v.vehicle.kind); - - let mut is_open = true; - egui::Window::new(name) - .resizable(false) - .auto_sized() - .open(&mut is_open) - .show(ui, |ui| { - if cfg!(debug_assertions) { - ui.label(format!("{:?}", id)); - } - - match v.vehicle.state { - VehicleState::Parked(_) => { - ui.label("Parked"); - } - VehicleState::Driving => { - ui.label(format!("Driving at {:.0}km/h", v.speed.0 * 3.6)); - } - VehicleState::Panicking(_) => { - ui.label("Panicking"); - } - VehicleState::RoadToPark(_, _, _) => { - ui.label("Parking"); - } - } - - for (human_id, human) in &sim.world().humans { - if human.router.personal_car == Some(id) { - ui.horizontal(|ui| { - ui.label("Owned by"); - entity_link(uiworld, sim, ui, human_id); - }); - } - } - - follow_button(uiworld, ui, id); - }); - - is_open -} diff --git a/native_app/src/gui/inspect/mod.rs b/native_app/src/gui/inspect/mod.rs index f72374eb..8d69d7ad 100644 --- a/native_app/src/gui/inspect/mod.rs +++ b/native_app/src/gui/inspect/mod.rs @@ -5,16 +5,10 @@ use crate::uiworld::UiWorld; use egui::{Context, Ui, Window}; use inspect_building::inspect_building; use inspect_debug::InspectRenderer; -use inspect_human::inspect_human; -use inspect_vehicle::inspect_vehicle; -use simulation::map::BuildingID; use simulation::{AnyEntity, Simulation}; -use slotmapd::Key; mod inspect_building; mod inspect_debug; -mod inspect_human; -mod inspect_vehicle; pub fn inspector(ui: &Context, uiworld: &UiWorld, sim: &Simulation) { profiling::scope!("hud::inspector"); @@ -28,27 +22,17 @@ pub fn inspector(ui: &Context, uiworld: &UiWorld, sim: &Simulation) { let force_debug_inspect = uiworld.read::().debug_inspector; let mut is_open = true; - match e { - AnyEntity::HumanID(id) if !force_debug_inspect => { - is_open = inspect_human(uiworld, sim, ui, id); - } - AnyEntity::VehicleID(id) if !force_debug_inspect => { - is_open = inspect_vehicle(uiworld, sim, ui, id); - } - AnyEntity::WagonID(_) if !force_debug_inspect => {} - AnyEntity::TrainID(_) if !force_debug_inspect => {} - _ => { - Window::new("Inspect") - .default_size([400.0, 500.0]) - .default_pos([30.0, 160.0]) - .resizable(true) - .open(&mut is_open) - .show(ui, |ui| { - let mut ins = InspectRenderer { entity: e }; - ins.render(uiworld, sim, ui); - uiworld.write::().e = Some(ins.entity); - }); - } + if force_debug_inspect { + Window::new("Inspect") + .default_size([400.0, 500.0]) + .default_pos([30.0, 160.0]) + .resizable(true) + .open(&mut is_open) + .show(ui, |ui| { + let mut ins = InspectRenderer { entity: e }; + ins.render(uiworld, sim, ui); + uiworld.write::().e = Some(ins.entity); + }); } if !is_open { @@ -56,15 +40,6 @@ pub fn inspector(ui: &Context, uiworld: &UiWorld, sim: &Simulation) { } } -pub fn building_link(uiworld: &UiWorld, sim: &Simulation, ui: &mut Ui, b: BuildingID) { - if ui.link(format!("{:?}", b.data())).clicked() { - uiworld.write::().e = Some(b); - if let Some(b) = sim.map().buildings().get(b) { - uiworld.camera_mut().targetpos = b.door_pos; - } - } -} - pub fn entity_link(uiworld: &UiWorld, sim: &Simulation, ui: &mut Ui, e: impl Into) { entity_link_inner(uiworld, sim, ui, e.into()) } @@ -88,14 +63,3 @@ fn entity_link_inner(uiworld: &UiWorld, sim: &Simulation, ui: &mut Ui, e: AnyEnt } } } - -pub fn follow_button(uiworld: &UiWorld, ui: &mut Ui, id: impl Into) { - follow_button_inner(uiworld, ui, id.into()) -} - -fn follow_button_inner(uiworld: &UiWorld, ui: &mut Ui, id: AnyEntity) { - let mut follow = uiworld.write::(); - if follow.0 != Some(id) && ui.small_button("follow").clicked() { - follow.0 = Some(id); - } -} diff --git a/native_app/src/newgui/hud/menu.rs b/native_app/src/newgui/hud/menu.rs index 86cf76e1..d2f7d6ae 100644 --- a/native_app/src/newgui/hud/menu.rs +++ b/native_app/src/newgui/hud/menu.rs @@ -2,7 +2,7 @@ use std::sync::atomic::Ordering; use std::time::Instant; use yakui::widgets::{List, Pad}; -use yakui::{column, reflow, spacer, Alignment, CrossAxisAlignment, Dim2, MainAxisSize}; +use yakui::{column, reflow, spacer, Alignment, CrossAxisAlignment, Dim2}; use goryak::{ blur_bg, button_primary, button_secondary, constrained_viewport, on_primary_container, @@ -62,36 +62,32 @@ fn save_window(gui: &mut GuiState, uiw: &UiWorld) { ExitState::ExitAsk | ExitState::Saving => { let mut opened = true; Window { - title: "Exit Menu", + title: "Exit Menu".into(), pad: Pad::all(15.0), radius: 10.0, opened: &mut opened, + child_spacing: 5.0, } .show(|| { - let mut l = List::column(); - l.item_spacing = 5.0; - l.main_axis_size = MainAxisSize::Min; - l.show(|| { - if let ExitState::Saving = *estate { - textc(on_secondary_container(), "Saving..."); - if !slstate.please_save && !slstate.saving_status.load(Ordering::SeqCst) { - std::process::exit(0); - } - return; - } - if button_secondary("Save and exit").show().clicked { - if let ExitState::ExitAsk = *estate { - slstate.please_save = true; - *estate = ExitState::Saving; - } - } - if button_secondary("Exit without saving").show().clicked { + if let ExitState::Saving = *estate { + textc(on_secondary_container(), "Saving..."); + if !slstate.please_save && !slstate.saving_status.load(Ordering::SeqCst) { std::process::exit(0); } - if button_secondary("Cancel").show().clicked { - *estate = ExitState::NoExit; + return; + } + if button_secondary("Save and exit").show().clicked { + if let ExitState::ExitAsk = *estate { + slstate.please_save = true; + *estate = ExitState::Saving; } - }); + } + if button_secondary("Exit without saving").show().clicked { + std::process::exit(0); + } + if button_secondary("Cancel").show().clicked { + *estate = ExitState::NoExit; + } }); if !opened { diff --git a/native_app/src/newgui/hud/windows/economy.rs b/native_app/src/newgui/hud/windows/economy.rs index a8f1775f..b0180da9 100644 --- a/native_app/src/newgui/hud/windows/economy.rs +++ b/native_app/src/newgui/hud/windows/economy.rs @@ -47,31 +47,27 @@ pub struct EconomyState { /// Shows the economy stats pub fn economy(uiw: &UiWorld, sim: &Simulation, opened: &mut bool) { Window { - title: "Economy", + title: "Economy".into(), pad: Pad::all(10.0), radius: 10.0, opened, + child_spacing: 10.0, } .show(|| { let mut state = uiw.write::(); let ecostats = sim.read::(); pady(10.0, || { - let mut l = List::row(); - l.main_axis_size = MainAxisSize::Min; - l.item_spacing = 10.0; - l.show(|| { - let tabs = &[ - ("Import/Exports", EconomyTab::ImportExports), - ("Internal Trade", EconomyTab::InternalTrade), - ("Market Prices", EconomyTab::MarketPrices), - ]; - - for (label, tab) in tabs { - if selectable_label_primary(state.tab == *tab, label).clicked { - state.tab = *tab; - } + let tabs = &[ + ("Import/Exports", EconomyTab::ImportExports), + ("Internal Trade", EconomyTab::InternalTrade), + ("Market Prices", EconomyTab::MarketPrices), + ]; + + for (label, tab) in tabs { + if selectable_label_primary(state.tab == *tab, label).clicked { + state.tab = *tab; } - }); + } }); pady(10.0, || { diff --git a/native_app/src/newgui/hud/windows/settings.rs b/native_app/src/newgui/hud/windows/settings.rs index f8170109..0b376cfe 100644 --- a/native_app/src/newgui/hud/windows/settings.rs +++ b/native_app/src/newgui/hud/windows/settings.rs @@ -120,10 +120,11 @@ impl Default for SettingsState { /// This window is used to change the settings of the game pub fn settings(uiw: &UiWorld, _: &Simulation, opened: &mut bool) { Window { - title: "Settings", + title: "Settings".into(), pad: Pad::all(10.0), radius: 10.0, opened, + child_spacing: 0.0, } .show(|| { profiling::scope!("gui::window::settings"); diff --git a/native_app/src/newgui/inspect/inspect_human.rs b/native_app/src/newgui/inspect/inspect_human.rs new file mode 100644 index 00000000..a4095196 --- /dev/null +++ b/native_app/src/newgui/inspect/inspect_human.rs @@ -0,0 +1,129 @@ +use goryak::{dragvalue, fixed_spacer, minrow, on_secondary_container, textc, Window}; +use prototypes::ItemID; +use std::borrow::Cow; +use yakui::widgets::Pad; + +use simulation::economy::Market; +use simulation::map_dynamic::Destination; +use simulation::souls::desire::WorkKind; +use simulation::transportation::Location; +use simulation::{HumanID, Simulation}; + +use crate::newgui::inspect::{building_link, follow_button}; +use crate::newgui::item_icon_yakui; +use crate::uiworld::UiWorld; + +/// Inspect a specific building, showing useful information about it +pub fn inspect_human(uiworld: &UiWorld, sim: &Simulation, id: HumanID) -> bool { + let Some(human) = sim.get(id) else { + return false; + }; + + let pinfo = &human.personal_info; + let title = format!("{}{:?} • {}", pinfo.age, pinfo.gender, pinfo.name); + + let mut is_open = true; + + fn label(x: impl Into>) { + textc(on_secondary_container(), x); + } + + Window { + title: title.into(), + pad: Pad::all(10.0), + radius: 10.0, + opened: &mut is_open, + child_spacing: 5.0, + } + .show(|| { + if cfg!(debug_assertions) { + label(format!("{:?}", id)); + } + + match human.location { + Location::Outside => {} + Location::Vehicle(_) => { + label("In a vehicle"); + } + Location::Building(x) => { + minrow(5.0, || { + label("In a building:"); + building_link(uiworld, sim, x); + }); + } + } + + if let Some(ref dest) = human.router.target_dest { + match dest { + Destination::Outside(pos) => { + label(format!("Going to {}", pos)); + } + Destination::Building(b) => { + minrow(5.0, || { + label("Going to building"); + building_link(uiworld, sim, *b); + }); + } + } + } + + minrow(5.0, || { + label("House is"); + building_link(uiworld, sim, human.home.house); + }); + + label(format!("Last ate: {}", human.food.last_ate)); + + if let Some(ref x) = human.work { + minrow(5.0, || { + label("Working at"); + building_link(uiworld, sim, x.workplace); + match x.kind { + WorkKind::Driver { .. } => { + label("as a driver"); + } + WorkKind::Worker => { + label("as a worker"); + } + } + }); + } + + fixed_spacer((0.0, 10.0)); + label("Desires"); + minrow(5.0, || { + let mut score = human.food.last_score; + dragvalue().show(&mut score); + label("Food"); + }); + minrow(5.0, || { + let mut score = human.home.last_score; + dragvalue().show(&mut score); + label("Home"); + }); + minrow(5.0, || { + let mut score = human.work.as_ref().map(|x| x.last_score).unwrap_or(0.0); + dragvalue().show(&mut score); + label("Work"); + }); + + let market = sim.read::(); + + fixed_spacer((0.0, 10.0)); + + let jobopening = ItemID::new("job-opening"); + for (&item_id, m) in market.iter() { + let Some(v) = m.capital(id.into()) else { + continue; + }; + if item_id == jobopening { + continue; + } + + item_icon_yakui(uiworld, item_id, v); + } + + follow_button(uiworld, id); + }); + is_open +} diff --git a/native_app/src/newgui/inspect/inspect_train.rs b/native_app/src/newgui/inspect/inspect_train.rs index 3e0fd31b..de96a7ce 100644 --- a/native_app/src/newgui/inspect/inspect_train.rs +++ b/native_app/src/newgui/inspect/inspect_train.rs @@ -1,6 +1,6 @@ use crate::newgui::inspect::follow_button; use crate::uiworld::UiWorld; -use goryak::{mincolumn, on_secondary_container, textc, Window}; +use goryak::{on_secondary_container, textc, Window}; use simulation::{Simulation, TrainID}; use yakui::widgets::Pad; @@ -12,24 +12,23 @@ pub fn inspect_train(uiworld: &UiWorld, sim: &Simulation, id: TrainID) -> bool { let mut is_open = true; Window { - title: "Train", + title: "Train".into(), pad: Pad::all(10.0), radius: 10.0, opened: &mut is_open, + child_spacing: 5.0, } .show(|| { - mincolumn(5.0, || { - if cfg!(debug_assertions) { - textc(on_secondary_container(), format!("{:?}", id)); - } + if cfg!(debug_assertions) { + textc(on_secondary_container(), format!("{:?}", id)); + } - textc( - on_secondary_container(), - format!("Going at {:.0}km/h", t.speed.0), - ); + textc( + on_secondary_container(), + format!("Going at {:.0}km/h", t.speed.0), + ); - follow_button(uiworld, id); - }); + follow_button(uiworld, id); }); is_open diff --git a/native_app/src/newgui/inspect/inspect_vehicle.rs b/native_app/src/newgui/inspect/inspect_vehicle.rs new file mode 100644 index 00000000..7d08add8 --- /dev/null +++ b/native_app/src/newgui/inspect/inspect_vehicle.rs @@ -0,0 +1,59 @@ +use crate::newgui::inspect::{entity_link, follow_button}; +use crate::uiworld::UiWorld; +use goryak::{minrow, on_secondary_container, textc, Window}; +use simulation::transportation::VehicleState; +use simulation::{Simulation, VehicleID}; +use yakui::widgets::Pad; + +pub fn inspect_vehicle(uiworld: &UiWorld, sim: &Simulation, id: VehicleID) -> bool { + let Some(v) = sim.get(id) else { + return false; + }; + + let name = format!("{:?}", v.vehicle.kind); + + let mut is_open = true; + Window { + title: name.into(), + pad: Pad::all(10.0), + radius: 10.0, + opened: &mut is_open, + child_spacing: 5.0, + } + .show(|| { + if cfg!(debug_assertions) { + textc(on_secondary_container(), format!("{:?}", id)); + } + + match v.vehicle.state { + VehicleState::Parked(_) => { + textc(on_secondary_container(), "Parked"); + } + VehicleState::Driving => { + textc( + on_secondary_container(), + format!("Driving at {:.0}km/h", v.speed.0 * 3.6), + ); + } + VehicleState::Panicking(_) => { + textc(on_secondary_container(), "Panicking"); + } + VehicleState::RoadToPark(_, _, _) => { + textc(on_secondary_container(), "Parking"); + } + } + + for (human_id, human) in &sim.world().humans { + if human.router.personal_car == Some(id) { + minrow(5.0, || { + textc(on_secondary_container(), "Owned by"); + entity_link(uiworld, sim, human_id); + }); + } + } + + follow_button(uiworld, id); + }); + + is_open +} diff --git a/native_app/src/newgui/inspect/mod.rs b/native_app/src/newgui/inspect/mod.rs index a12326ec..e574efe2 100644 --- a/native_app/src/newgui/inspect/mod.rs +++ b/native_app/src/newgui/inspect/mod.rs @@ -3,12 +3,16 @@ use crate::gui::FollowEntity; use crate::newgui::{InspectedBuilding, InspectedEntity}; use crate::uiworld::UiWorld; use goryak::{button_primary, primary_link}; +use inspect_human::inspect_human; use inspect_train::inspect_train; +use inspect_vehicle::inspect_vehicle; use simulation::map::BuildingID; use simulation::{AnyEntity, Simulation}; use slotmapd::Key; +mod inspect_human; mod inspect_train; +mod inspect_vehicle; pub fn new_inspector(uiworld: &UiWorld, sim: &Simulation) { profiling::scope!("hud::inspector"); @@ -20,14 +24,17 @@ pub fn new_inspector(uiworld: &UiWorld, sim: &Simulation) { let e = unwrap_or!(uiworld.read::().e, return); let force_debug_inspect = uiworld.read::().debug_inspector; + if force_debug_inspect { + return; + } let mut is_open = true; match e { AnyEntity::HumanID(id) if !force_debug_inspect => { - //is_open = inspect_human(uiworld, sim, ui, id); + is_open = inspect_human(uiworld, sim, id); } AnyEntity::VehicleID(id) if !force_debug_inspect => { - //is_open = inspect_vehicle(uiworld, sim, ui, id); + is_open = inspect_vehicle(uiworld, sim, id); } AnyEntity::WagonID(id) if !force_debug_inspect => { let Some(w) = sim.world().get(id) else {