using popup text box in a few more places to show important messages

This commit is contained in:
Dustin Carlino 2019-11-01 11:33:15 -07:00
parent b6dee0b35d
commit e9e6664f61
9 changed files with 96 additions and 70 deletions

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

@ -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(

View File

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

View File

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

View File

@ -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!(),