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