mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
using popup text box in a few more places to show important messages
This commit is contained in:
parent
b6dee0b35d
commit
e9e6664f61
@ -349,15 +349,14 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
self.wizard.alive = false;
|
||||
}
|
||||
|
||||
// Note this will abort the wizard once done!
|
||||
pub fn acknowledge<S: Into<String>, F: Fn() -> Vec<S>>(
|
||||
&mut self,
|
||||
title: &str,
|
||||
make_lines: F,
|
||||
) -> bool {
|
||||
) -> Option<()> {
|
||||
if !self.ready_results.is_empty() {
|
||||
self.ready_results.pop_front();
|
||||
return true;
|
||||
return Some(());
|
||||
}
|
||||
|
||||
if self.wizard.log_scroller.is_none() {
|
||||
@ -375,9 +374,9 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
{
|
||||
self.wizard.confirmed_state.push(Box::new(()));
|
||||
self.wizard.log_scroller = None;
|
||||
true
|
||||
Some(())
|
||||
} else {
|
||||
false
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::common::route_viewer::RouteViewer;
|
||||
use crate::common::{ColorLegend, RouteExplorer, TripExplorer};
|
||||
use crate::game::{Transition, WizardState};
|
||||
use crate::game::{msg, Transition, WizardState};
|
||||
use crate::render::{AgentColorScheme, MIN_ZOOM_FOR_DETAIL};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{hotkey, Choice, EventCtx, GfxCtx, Key, MenuUnderButton, ModalMenu};
|
||||
@ -71,9 +71,12 @@ impl AgentTools {
|
||||
self.following = Some((trip, None, ui.primary.sim.time()));
|
||||
}
|
||||
TripResult::TripDone => {
|
||||
println!("{} is done or aborted, so no more following", trip);
|
||||
self.following = None;
|
||||
menu.remove_action("stop following agent", ctx);
|
||||
return Some(Transition::Push(msg(
|
||||
"Follower",
|
||||
vec![format!("{} is done or aborted, so no more following", trip)],
|
||||
)));
|
||||
}
|
||||
TripResult::TripDoesntExist => {
|
||||
println!("{} doesn't exist yet, so not following", trip);
|
||||
|
@ -25,10 +25,8 @@ fn warp_to(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transiti
|
||||
EventLoopMode::Animation,
|
||||
));
|
||||
}
|
||||
if wizard.acknowledge("Bad warp ID", || vec![format!("{} isn't a valid ID", to)]) {
|
||||
return Some(Transition::Pop);
|
||||
}
|
||||
None
|
||||
wizard.acknowledge("Bad warp ID", || vec![format!("{} isn't a valid ID", to)])?;
|
||||
Some(Transition::Pop)
|
||||
}
|
||||
|
||||
pub struct Warping {
|
||||
|
@ -551,11 +551,13 @@ fn make_bulk_edit_lanes(road: RoadID) -> Box<dyn State> {
|
||||
cnt += 1;
|
||||
}
|
||||
}
|
||||
// TODO pop this up. warn about road names changing and being weird. :)
|
||||
println!(
|
||||
"Changed {} {:?} lanes to {:?} lanes on {}",
|
||||
cnt, from, to, road_name
|
||||
);
|
||||
// TODO warn about road names changing and being weird. :)
|
||||
wizard.acknowledge("Bulk lane edit", || {
|
||||
vec![format!(
|
||||
"Changed {} {:?} lanes to {:?} lanes on {}",
|
||||
cnt, from, to, road_name
|
||||
)]
|
||||
})?;
|
||||
apply_map_edits(&mut ui.primary, &ui.cs, ctx, edits);
|
||||
Some(Transition::Pop)
|
||||
}))
|
||||
|
@ -193,3 +193,12 @@ impl State for WizardState {
|
||||
self.wizard.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Word wrap
|
||||
pub fn msg<S: Into<String>>(title: &'static str, lines: Vec<S>) -> Box<dyn State> {
|
||||
let str_lines: Vec<String> = lines.into_iter().map(|l| l.into()).collect();
|
||||
WizardState::new(Box::new(move |wiz, ctx, _| {
|
||||
wiz.wrap(ctx).acknowledge(title, || str_lines.clone())?;
|
||||
Some(Transition::Pop)
|
||||
}))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::game::{Transition, WizardState};
|
||||
use crate::game::{msg, Transition, WizardState};
|
||||
use crate::render::AgentColorScheme;
|
||||
use crate::sandbox::{analytics, bus_explorer, spawner, SandboxMode};
|
||||
use crate::ui::UI;
|
||||
@ -195,7 +195,7 @@ impl GameplayState {
|
||||
))));
|
||||
}
|
||||
if self.menu.action("help") {
|
||||
return Some(help(vec!["This simulation is empty by default.", "Try right-clicking an intersection and choosing to spawn agents (or just hover over it and press Z).", "You can also spawn agents from buildings or lanes.", "You can also start a full scenario to get realistic traffic."]));
|
||||
return Some(Transition::Push(msg("Help", vec!["This simulation is empty by default.", "Try right-clicking an intersection and choosing to spawn agents (or just hover over it and press Z).", "You can also spawn agents from buildings or lanes.", "You can also start a full scenario to get realistic traffic."])));
|
||||
}
|
||||
if let Some(new_state) = spawner::AgentSpawner::new(ctx, ui) {
|
||||
return Some(Transition::Push(new_state));
|
||||
@ -209,11 +209,14 @@ impl GameplayState {
|
||||
))));
|
||||
}
|
||||
if self.menu.action("help") {
|
||||
return Some(help(vec![
|
||||
"Do things seem a bit quiet?",
|
||||
"The simulation starts at midnight, so you might need to wait a bit.",
|
||||
"Try using the speed controls on the left.",
|
||||
]));
|
||||
return Some(Transition::Push(msg(
|
||||
"Help",
|
||||
vec![
|
||||
"Do things seem a bit quiet?",
|
||||
"The simulation starts at midnight, so you might need to wait a bit.",
|
||||
"Try using the speed controls on the left.",
|
||||
],
|
||||
)));
|
||||
}
|
||||
}
|
||||
State::OptimizeBus {
|
||||
@ -279,12 +282,15 @@ impl GameplayState {
|
||||
))));
|
||||
}
|
||||
if self.menu.action("help") {
|
||||
return Some(help(vec![
|
||||
"First find where the bus gets stuck.",
|
||||
"Then use edit mode to try to speed things up.",
|
||||
"Try making dedicated bus lanes",
|
||||
"and adjusting traffic signals.",
|
||||
]));
|
||||
return Some(Transition::Push(msg(
|
||||
"Help",
|
||||
vec![
|
||||
"First find where the bus gets stuck.",
|
||||
"Then use edit mode to try to speed things up.",
|
||||
"Try making dedicated bus lanes",
|
||||
"and adjusting traffic signals.",
|
||||
],
|
||||
)));
|
||||
}
|
||||
}
|
||||
State::CreateGridlock { ref mut time } => {
|
||||
@ -304,11 +310,11 @@ impl GameplayState {
|
||||
}
|
||||
|
||||
if self.menu.action("help") {
|
||||
return Some(help(vec![
|
||||
return Some(Transition::Push(msg("Help", vec![
|
||||
"You might notice a few places in the map where gridlock forms already.",
|
||||
"You can make things worse!",
|
||||
"How few lanes can you close for construction before everything grinds to a halt?",
|
||||
]));
|
||||
])));
|
||||
}
|
||||
}
|
||||
State::FasterTrips { mode, ref mut time } => {
|
||||
@ -320,9 +326,10 @@ impl GameplayState {
|
||||
}
|
||||
|
||||
if self.menu.action("help") {
|
||||
return Some(help(vec![
|
||||
"How can you possibly speed up all trips of some mode?",
|
||||
]));
|
||||
return Some(Transition::Push(msg(
|
||||
"Help",
|
||||
vec!["How can you possibly speed up all trips of some mode?"],
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -442,17 +449,6 @@ fn change_scenario(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<
|
||||
))))
|
||||
}
|
||||
|
||||
// TODO Word wrap
|
||||
fn help(lines: Vec<&'static str>) -> Transition {
|
||||
Transition::Push(WizardState::new(Box::new(move |wiz, ctx, _| {
|
||||
if wiz.wrap(ctx).acknowledge("Help", || lines.clone()) {
|
||||
Some(Transition::Pop)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
// Must call menu.event first. Returns true if the caller should set the analytics to the custom
|
||||
// thing.
|
||||
fn manage_analytics(
|
||||
|
@ -8,7 +8,7 @@ mod trip_stats;
|
||||
use crate::common::{time_controls, AgentTools, CommonState, SpeedControls};
|
||||
use crate::debug::DebugMode;
|
||||
use crate::edit::EditMode;
|
||||
use crate::game::{State, Transition, WizardState};
|
||||
use crate::game::{msg, State, Transition, WizardState};
|
||||
use crate::helpers::ID;
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use ezgui::{
|
||||
@ -190,7 +190,7 @@ impl State for SandboxMode {
|
||||
}
|
||||
if self.save_tools.action("load previous sim state") {
|
||||
self.speed.pause();
|
||||
ctx.loading_screen("load previous savestate", |ctx, mut timer| {
|
||||
if let Some(t) = ctx.loading_screen("load previous savestate", |ctx, mut timer| {
|
||||
let prev_state = ui
|
||||
.primary
|
||||
.sim
|
||||
@ -202,14 +202,20 @@ impl State for SandboxMode {
|
||||
Some(new_sim) => {
|
||||
ui.primary.sim = new_sim;
|
||||
ui.recalculate_current_selection(ctx);
|
||||
None
|
||||
}
|
||||
None => println!("Couldn't load previous savestate {:?}", prev_state),
|
||||
None => Some(Transition::Push(msg(
|
||||
"Error",
|
||||
vec![format!("Couldn't load previous savestate {:?}", prev_state)],
|
||||
))),
|
||||
}
|
||||
});
|
||||
}) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if self.save_tools.action("load next sim state") {
|
||||
self.speed.pause();
|
||||
ctx.loading_screen("load next savestate", |ctx, mut timer| {
|
||||
if let Some(t) = ctx.loading_screen("load next savestate", |ctx, mut timer| {
|
||||
let next_state = ui.primary.sim.find_next_savestate(ui.primary.sim.time());
|
||||
match next_state
|
||||
.clone()
|
||||
@ -218,10 +224,16 @@ impl State for SandboxMode {
|
||||
Some(new_sim) => {
|
||||
ui.primary.sim = new_sim;
|
||||
ui.recalculate_current_selection(ctx);
|
||||
None
|
||||
}
|
||||
None => println!("Couldn't load next savestate {:?}", next_state),
|
||||
None => Some(Transition::Push(msg(
|
||||
"Error",
|
||||
vec![format!("Couldn't load next savestate {:?}", next_state)],
|
||||
))),
|
||||
}
|
||||
});
|
||||
}) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if self.save_tools.action("pick a savestate to load") {
|
||||
self.speed.pause();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::common::CommonState;
|
||||
use crate::game::{State, Transition};
|
||||
use crate::game::{msg, State, Transition};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::DrawOptions;
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
@ -213,7 +213,7 @@ impl State for AgentSpawner {
|
||||
if self.maybe_goal.is_some() && ctx.input.contextual_action(Key::F3, "end the agent here") {
|
||||
let mut rng = ui.primary.current_flags.sim_flags.make_rng();
|
||||
let sim = &mut ui.primary.sim;
|
||||
schedule_trip(
|
||||
let err = schedule_trip(
|
||||
&self.from,
|
||||
self.maybe_goal.take().unwrap().0,
|
||||
map,
|
||||
@ -223,7 +223,11 @@ impl State for AgentSpawner {
|
||||
sim.spawn_all_trips(map, &mut Timer::new("spawn trip"), false);
|
||||
sim.step(map, SMALL_DT);
|
||||
ui.recalculate_current_selection(ctx);
|
||||
return Transition::Pop;
|
||||
if let Some(e) = err {
|
||||
return Transition::Replace(msg("Spawning error", vec![e]));
|
||||
} else {
|
||||
return Transition::Pop;
|
||||
}
|
||||
}
|
||||
|
||||
Transition::Keep
|
||||
@ -311,7 +315,14 @@ fn spawn_agents_around(i: IntersectionID, ui: &mut UI, ctx: &EventCtx) {
|
||||
ui.recalculate_current_selection(ctx);
|
||||
}
|
||||
|
||||
fn schedule_trip(src: &Source, raw_goal: Goal, map: &Map, sim: &mut Sim, rng: &mut XorShiftRng) {
|
||||
// Returns optional error message
|
||||
fn schedule_trip(
|
||||
src: &Source,
|
||||
raw_goal: Goal,
|
||||
map: &Map,
|
||||
sim: &mut Sim,
|
||||
rng: &mut XorShiftRng,
|
||||
) -> Option<String> {
|
||||
match src {
|
||||
Source::WalkFromBldg(_) | Source::WalkFromSidewalk(_) => {
|
||||
let start = match src {
|
||||
@ -327,8 +338,7 @@ fn schedule_trip(src: &Source, raw_goal: Goal, map: &Map, sim: &mut Sim, rng: &m
|
||||
if let Some(goal) = SidewalkSpot::end_at_border(to, map) {
|
||||
goal
|
||||
} else {
|
||||
println!("Can't end a walking trip at {}; no sidewalks", to);
|
||||
return;
|
||||
return Some(format!("Can't end a walking trip at {}; no sidewalks", to));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -368,8 +378,7 @@ fn schedule_trip(src: &Source, raw_goal: Goal, map: &Map, sim: &mut Sim, rng: &m
|
||||
if let Some(g) = DrivingGoal::end_at_border(to, vec![LaneType::Driving], map) {
|
||||
g
|
||||
} else {
|
||||
println!("Can't end a car trip at {}; no driving lanes", to);
|
||||
return;
|
||||
return Some(format!("Can't end a car trip at {}; no driving lanes", to));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -387,7 +396,7 @@ fn schedule_trip(src: &Source, raw_goal: Goal, map: &Map, sim: &mut Sim, rng: &m
|
||||
map,
|
||||
);
|
||||
} else {
|
||||
println!("Can't make a car appear at {:?}", from);
|
||||
return Some(format!("Can't make a car appear at {:?}", from));
|
||||
}
|
||||
}
|
||||
Source::WalkFromBldgThenMaybeUseCar(b) => {
|
||||
@ -405,4 +414,5 @@ fn schedule_trip(src: &Source, raw_goal: Goal, map: &Map, sim: &mut Sim, rng: &m
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ fn splash_screen(
|
||||
x if x == tutorial => Some(Transition::Push(Box::new(TutorialMode::new(ctx)))),
|
||||
x if x == mission => Some(Transition::Push(Box::new(MissionEditMode::new(ctx)))),
|
||||
x if x == about => {
|
||||
if wizard.acknowledge("About A/B Street", || {
|
||||
wizard.acknowledge("About A/B Street", || {
|
||||
vec![
|
||||
"Author: Dustin Carlino (dabreegster@gmail.com)",
|
||||
"http://github.com/dabreegster/abstreet",
|
||||
@ -201,14 +201,11 @@ fn splash_screen(
|
||||
"",
|
||||
"Press ENTER to continue",
|
||||
]
|
||||
}) {
|
||||
Some(Transition::Replace(Box::new(SplashScreen {
|
||||
wizard: Wizard::new(),
|
||||
maybe_screensaver: maybe_screensaver.take(),
|
||||
})))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
Some(Transition::Replace(Box::new(SplashScreen {
|
||||
wizard: Wizard::new(),
|
||||
maybe_screensaver: maybe_screensaver.take(),
|
||||
})))
|
||||
}
|
||||
x if x == quit => Some(Transition::Pop),
|
||||
_ => unreachable!(),
|
||||
|
Loading…
Reference in New Issue
Block a user