less work for the default InputOnly

This commit is contained in:
Dustin Carlino 2019-06-23 17:00:34 -07:00
parent fe38f2ff97
commit 6905595a05
26 changed files with 398 additions and 511 deletions

View File

@ -56,7 +56,7 @@ impl ABTestMode {
}
impl State for ABTestMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let mut txt = Text::prompt("A/B Test Mode");
txt.add_line(ui.primary.map.get_edits().edits_name.clone());
if let Some(ref diff) = self.diff_trip {
@ -80,12 +80,12 @@ impl State for ABTestMode {
false,
);
}
if let Some(pair) = self.common.event(ctx, ui, &mut self.menu) {
return pair;
if let Some(t) = self.common.event(ctx, ui, &mut self.menu) {
return t;
}
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.menu.action("swap") {
@ -96,14 +96,11 @@ impl State for ABTestMode {
}
if self.menu.action("scoreboard") {
return (
Transition::Push(Box::new(score::Scoreboard::new(
ctx,
&ui.primary,
ui.secondary.as_ref().unwrap(),
))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(score::Scoreboard::new(
ctx,
&ui.primary,
ui.secondary.as_ref().unwrap(),
)));
}
if self.menu.action("save state") {
@ -148,9 +145,9 @@ impl State for ABTestMode {
if self.menu.action("step forwards 0.1s") {
self.step(Duration::seconds(0.1), ui, ctx);
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
} else {
(Transition::Keep, EventLoopMode::Animation)
Transition::KeepWithMode(EventLoopMode::Animation)
}
}

View File

@ -2,8 +2,8 @@ use crate::game::{State, Transition};
use crate::ui::PerMapUI;
use crate::ui::UI;
use ezgui::{
hotkey, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text,
VerticalAlignment, Wizard, WrappedWizard,
hotkey, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment, Wizard,
WrappedWizard,
};
use geom::Duration;
use itertools::Itertools;
@ -83,24 +83,21 @@ impl Scoreboard {
}
impl State for Scoreboard {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.menu.action("browse trips") {
return (
Transition::Push(Box::new(BrowseTrips {
trips: CompareTrips::new(
ui.primary.sim.get_finished_trips(),
ui.secondary.as_ref().unwrap().sim.get_finished_trips(),
),
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(BrowseTrips {
trips: CompareTrips::new(
ui.primary.sim.get_finished_trips(),
ui.secondary.as_ref().unwrap().sim.get_finished_trips(),
),
wizard: Wizard::new(),
}));
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -118,14 +115,14 @@ struct BrowseTrips {
}
impl State for BrowseTrips {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
if pick_trip(&self.trips, &mut self.wizard.wrap(ctx)).is_some() {
// TODO show more details...
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {

View File

@ -3,9 +3,7 @@ use crate::edit::apply_map_edits;
use crate::game::{State, Transition};
use crate::render::DrawMap;
use crate::ui::{Flags, PerMapUI, UI};
use ezgui::{
hotkey, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
use geom::Duration;
use map_model::{Map, MapEdits};
use sim::{ABTest, Scenario, SimFlags};
@ -24,29 +22,26 @@ impl PickABTest {
}
impl State for PickABTest {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some(ab_test) = pick_ab_test(&ui.primary.map, self.wizard.wrap(ctx)) {
let scroller = LogScroller::new(ab_test.test_name.clone(), ab_test.describe());
return (
Transition::Replace(Box::new(ABTestSetup {
menu: ModalMenu::new(
&format!("A/B Test Editor for {}", ab_test.test_name),
vec![
(hotkey(Key::Escape), "quit"),
(hotkey(Key::R), "run A/B test"),
(hotkey(Key::L), "load savestate"),
],
ctx,
),
ab_test,
scroller,
})),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(ABTestSetup {
menu: ModalMenu::new(
&format!("A/B Test Editor for {}", ab_test.test_name),
vec![
(hotkey(Key::Escape), "quit"),
(hotkey(Key::R), "run A/B test"),
(hotkey(Key::L), "load savestate"),
],
ctx,
),
ab_test,
scroller,
}));
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -61,26 +56,20 @@ struct ABTestSetup {
}
impl State for ABTestSetup {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
ctx.canvas.handle_event(ctx.input);
self.menu.handle_event(ctx, None);
if self.scroller.event(ctx.input) {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.menu.action("run A/B test") {
return (
Transition::Replace(Box::new(launch_test(&self.ab_test, ui, ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(launch_test(&self.ab_test, ui, ctx)));
} else if self.menu.action("load savestate") {
return (
Transition::Push(Box::new(LoadSavestate {
ab_test: self.ab_test.clone(),
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(LoadSavestate {
ab_test: self.ab_test.clone(),
wizard: Wizard::new(),
}));
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -95,16 +84,13 @@ struct LoadSavestate {
}
impl State for LoadSavestate {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some(ss) = pick_savestate(&self.ab_test, &mut self.wizard.wrap(ctx)) {
return (
Transition::Replace(Box::new(launch_savestate(&self.ab_test, ss, ui, ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(launch_savestate(&self.ab_test, ss, ui, ctx)));
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {

View File

@ -43,24 +43,20 @@ impl CommonState {
ctx: &mut EventCtx,
ui: &mut UI,
menu: &mut ModalMenu,
) -> Option<(Transition, EventLoopMode)> {
) -> Option<Transition> {
if menu.action("warp") {
return Some((
Transition::Push(Box::new(warp::EnteringWarp::new())),
EventLoopMode::InputOnly,
));
return Some(Transition::Push(Box::new(warp::EnteringWarp::new())));
}
if menu.action("navigate") {
return Some((
Transition::Push(Box::new(navigate::Navigator::new(ui))),
EventLoopMode::InputOnly,
));
return Some(Transition::Push(Box::new(navigate::Navigator::new(ui))));
}
self.associated.event(ui);
self.turn_cycler.event(ctx, ui);
if menu.action("take a screenshot") {
return Some((Transition::Keep, EventLoopMode::ScreenCaptureCurrentShot));
return Some(Transition::KeepWithMode(
EventLoopMode::ScreenCaptureCurrentShot,
));
}
None

View File

@ -28,10 +28,10 @@ impl Navigator {
}
impl State for Navigator {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let map = &ui.primary.map;
match self.autocomplete.event(ctx.input) {
InputResult::Canceled => (Transition::Pop, EventLoopMode::InputOnly),
InputResult::Canceled => Transition::Pop,
InputResult::Done(name, ids) => {
// Roads share intersections, so of course there'll be overlap here.
let mut cross_streets = HashSet::new();
@ -45,21 +45,18 @@ impl State for Navigator {
}
}
}
(
Transition::Replace(Box::new(CrossStreet {
first: *ids.iter().next().unwrap(),
autocomplete: Autocomplete::new(
&format!("{} and what?", name),
cross_streets
.into_iter()
.map(|r| (map.get_r(r).get_name(), r))
.collect(),
),
})),
EventLoopMode::InputOnly,
)
Transition::Replace(Box::new(CrossStreet {
first: *ids.iter().next().unwrap(),
autocomplete: Autocomplete::new(
&format!("{} and what?", name),
cross_streets
.into_iter()
.map(|r| (map.get_r(r).get_name(), r))
.collect(),
),
}))
}
InputResult::StillActive => (Transition::Keep, EventLoopMode::InputOnly),
InputResult::StillActive => Transition::Keep,
}
}
@ -75,21 +72,21 @@ struct CrossStreet {
impl State for CrossStreet {
// When None, this is done.
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let map = &ui.primary.map;
match self.autocomplete.event(ctx.input) {
InputResult::Canceled => {
// Just warp to somewhere on the first road
let road = map.get_r(self.first);
println!("Warping to {}", road.get_name());
(
Transition::Replace(Box::new(Warping {
Transition::ReplaceWithMode(
Box::new(Warping {
warper: Warper::new(
ctx,
road.center_pts.dist_along(road.center_pts.length() / 2.0).0,
),
id: ID::Lane(road.all_lanes()[0]),
})),
}),
EventLoopMode::Animation,
)
}
@ -105,15 +102,15 @@ impl State for CrossStreet {
} else {
map.get_i(road.dst_i).polygon.center()
};
(
Transition::Replace(Box::new(Warping {
Transition::ReplaceWithMode(
Box::new(Warping {
warper: Warper::new(ctx, pt),
id: ID::Lane(road.all_lanes()[0]),
})),
}),
EventLoopMode::Animation,
)
}
InputResult::StillActive => (Transition::Keep, EventLoopMode::InputOnly),
InputResult::StillActive => Transition::Keep,
}
}

View File

@ -20,23 +20,23 @@ impl EnteringWarp {
}
impl State for EnteringWarp {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
match self.tb.event(ctx.input) {
InputResult::Canceled => (Transition::Pop, EventLoopMode::InputOnly),
InputResult::Canceled => Transition::Pop,
InputResult::Done(to, _) => {
if let Some((id, pt)) = warp_point(to, &ui.primary) {
(
Transition::Replace(Box::new(Warping {
Transition::ReplaceWithMode(
Box::new(Warping {
warper: Warper::new(ctx, pt),
id,
})),
}),
EventLoopMode::Animation,
)
} else {
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
}
}
InputResult::StillActive => (Transition::Keep, EventLoopMode::InputOnly),
InputResult::StillActive => Transition::Keep,
}
}
@ -51,12 +51,12 @@ pub struct Warping {
}
impl State for Warping {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some(evmode) = self.warper.event(ctx) {
(Transition::Keep, evmode)
Transition::KeepWithMode(evmode)
} else {
ui.primary.current_selection = Some(self.id);
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
}
}

View File

@ -2,7 +2,7 @@ use crate::common::CommonState;
use crate::game::{State, Transition};
use crate::helpers::ID;
use crate::ui::{ShowEverything, UI};
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, Text, WarpingItemSlider};
use ezgui::{EventCtx, GfxCtx, Key, Text, WarpingItemSlider};
use geom::Pt2D;
use map_model::BusStopID;
@ -45,7 +45,7 @@ impl BusRouteExplorer {
}
impl State for BusRouteExplorer {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if ctx.redo_mouseover() {
ui.primary.current_selection = ui.recalculate_current_selection(
ctx,
@ -61,9 +61,9 @@ impl State for BusRouteExplorer {
if done_warping {
ui.primary.current_selection = Some(ID::BusStop(*self.slider.get().1));
}
(Transition::Keep, evmode)
Transition::KeepWithMode(evmode)
} else {
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
}
}

View File

@ -1,8 +1,7 @@
use crate::game::{State, Transition};
use crate::ui::UI;
use ezgui::{
hotkey, Canvas, Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu, ScreenPt,
ScrollingMenu,
hotkey, Canvas, Color, EventCtx, GfxCtx, InputResult, Key, ModalMenu, ScreenPt, ScrollingMenu,
};
use geom::{Distance, Polygon};
@ -24,25 +23,22 @@ impl ColorChooser {
}
impl State for ColorChooser {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
match self.menu.event(&mut ctx.input) {
InputResult::Canceled => (Transition::Pop, EventLoopMode::InputOnly),
InputResult::StillActive => (Transition::Keep, EventLoopMode::InputOnly),
InputResult::Done(name, _) => (
Transition::Replace(Box::new(ColorChanger {
name: name.clone(),
original: ui.cs.get_modified(&name),
menu: ModalMenu::new(
&format!("Color Picker for {}", name),
vec![
(hotkey(Key::Backspace), "revert"),
(hotkey(Key::Escape), "finalize"),
],
ctx,
),
})),
EventLoopMode::InputOnly,
),
InputResult::Canceled => Transition::Pop,
InputResult::StillActive => Transition::Keep,
InputResult::Done(name, _) => Transition::Replace(Box::new(ColorChanger {
name: name.clone(),
original: ui.cs.get_modified(&name),
menu: ModalMenu::new(
&format!("Color Picker for {}", name),
vec![
(hotkey(Key::Backspace), "revert"),
(hotkey(Key::Escape), "finalize"),
],
ctx,
),
})),
}
}
@ -58,14 +54,14 @@ struct ColorChanger {
}
impl State for ColorChanger {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
if self.menu.action("revert") {
ui.cs.reset_modified(&self.name, self.original);
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.menu.action("finalize") {
println!("Setting color for {}", self.name);
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if let Some(pt) = ctx.input.get_moved_mouse() {
@ -78,7 +74,7 @@ impl State for ColorChanger {
.override_color(&self.name, get_color(x as f32, y as f32));
}
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {

View File

@ -88,7 +88,7 @@ impl DebugMode {
}
impl State for DebugMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if ctx.redo_mouseover() {
ui.primary.current_selection =
ui.recalculate_current_selection(ctx, &ui.primary.sim, self, true);
@ -126,24 +126,18 @@ impl State for DebugMode {
self.menu.handle_event(ctx, Some(txt));
ctx.canvas.handle_event(ctx.input);
if let Some(pair) = self.common.event(ctx, ui, &mut self.menu) {
return pair;
if let Some(t) = self.common.event(ctx, ui, &mut self.menu) {
return t;
}
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.menu.action("sandbox mode") {
return (
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(SandboxMode::new(ctx)));
}
if self.menu.action("edit mode") {
return (
Transition::Replace(Box::new(EditMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(EditMode::new(ctx, ui)));
}
if self.menu.action("show/hide chokepoints") {
@ -211,10 +205,7 @@ impl State for DebugMode {
self.neighborhood_summary.event(ui, &mut self.menu);
if let Some(debugger) = polygons::PolygonDebugger::new(ctx, ui) {
return (
Transition::Push(Box::new(debugger)),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(debugger));
}
{
@ -244,15 +235,12 @@ impl State for DebugMode {
if self.menu.action("screenshot everything") {
let bounds = ui.primary.map.get_bounds();
assert!(bounds.min_x == 0.0 && bounds.min_y == 0.0);
return (
Transition::Keep,
EventLoopMode::ScreenCaptureEverything {
dir: format!("../data/screenshots/pending_{}", ui.primary.map.get_name()),
zoom: 3.0,
max_x: bounds.max_x,
max_y: bounds.max_y,
},
);
return Transition::KeepWithMode(EventLoopMode::ScreenCaptureEverything {
dir: format!("../data/screenshots/pending_{}", ui.primary.map.get_name()),
zoom: 3.0,
max_x: bounds.max_x,
max_y: bounds.max_y,
});
}
if self.search_results.is_some() {
@ -260,27 +248,18 @@ impl State for DebugMode {
self.search_results = None;
}
} else if self.menu.action("search OSM metadata") {
return (
Transition::Push(Box::new(SearchOSM {
entry: TextBox::new("Search for what?", None),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(SearchOSM {
entry: TextBox::new("Search for what?", None),
}));
} else if self.menu.action("configure colors") {
return (
Transition::Push(Box::new(color_picker::ColorChooser::new(ui))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(color_picker::ColorChooser::new(ui)));
}
if let Some(explorer) = bus_explorer::BusRouteExplorer::new(ctx, ui) {
return (
Transition::Push(Box::new(explorer)),
EventLoopMode::Animation,
);
return Transition::PushWithMode(Box::new(explorer), EventLoopMode::Animation);
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw_default_ui(&self) -> bool {
@ -526,9 +505,9 @@ struct SearchOSM {
}
impl State for SearchOSM {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
match self.entry.event(&mut ctx.input) {
InputResult::Canceled => (Transition::Pop, EventLoopMode::InputOnly),
InputResult::Canceled => Transition::Pop,
InputResult::Done(filter, _) => {
let mut ids = HashSet::new();
let map = &ui.primary.map;
@ -551,15 +530,11 @@ impl State for SearchOSM {
}
}
(
Transition::PopWithData(Box::new(|state| {
state.downcast_mut::<DebugMode>().unwrap().search_results =
Some((filter, ids));
})),
EventLoopMode::InputOnly,
)
Transition::PopWithData(Box::new(|state| {
state.downcast_mut::<DebugMode>().unwrap().search_results = Some((filter, ids));
}))
}
InputResult::StillActive => (Transition::Keep, EventLoopMode::InputOnly),
InputResult::StillActive => Transition::Keep,
}
}

View File

@ -3,7 +3,7 @@ use crate::helpers::ID;
use crate::render::calculate_corners;
use crate::ui::UI;
use abstutil::Timer;
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, EventCtx, GfxCtx, ItemSlider, Key, Text};
use geom::{Polygon, Pt2D, Triangle};
pub struct PolygonDebugger {
@ -152,14 +152,14 @@ impl PolygonDebugger {
}
impl State for PolygonDebugger {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
self.slider.event(ctx);
ctx.canvas.handle_event(ctx.input);
if self.slider.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -12,10 +12,7 @@ use crate::render::{
use crate::sandbox::SandboxMode;
use crate::ui::{PerMapUI, ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
hotkey, lctrl, Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard,
WrappedWizard,
};
use ezgui::{hotkey, lctrl, Color, EventCtx, GfxCtx, Key, ModalMenu, Text, Wizard, WrappedWizard};
use map_model::{
IntersectionID, Lane, LaneID, LaneType, Map, MapEdits, Road, RoadID, TurnID, TurnType,
};
@ -53,7 +50,7 @@ impl EditMode {
}
impl State for EditMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
// The .clone() is probably not that expensive, and it makes later code a bit
// easier to read. :)
let orig_edits = ui.primary.map.get_edits().clone();
@ -87,41 +84,29 @@ impl State for EditMode {
false,
);
}
if let Some(pair) = self.common.event(ctx, ui, &mut self.menu) {
return pair;
if let Some(t) = self.common.event(ctx, ui, &mut self.menu) {
return t;
}
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.menu.action("sandbox mode") {
return (
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(SandboxMode::new(ctx)));
}
if self.menu.action("debug mode") {
return (
Transition::Replace(Box::new(DebugMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(DebugMode::new(ctx, ui)));
}
// TODO Only if current edits are unsaved
if self.menu.action("save edits") {
return (
Transition::Push(Box::new(Saving {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(Saving {
wizard: Wizard::new(),
}));
} else if self.menu.action("load different edits") {
return (
Transition::Push(Box::new(Loading {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(Loading {
wizard: Wizard::new(),
}));
}
if let Some(ID::Lane(id)) = ui.primary.current_selection {
@ -170,13 +155,10 @@ impl State for EditMode {
.input
.contextual_action(Key::U, "bulk edit lanes on this road")
{
return (
Transition::Push(Box::new(BulkEditLanes {
road: ui.primary.map.get_l(id).parent,
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(BulkEditLanes {
road: ui.primary.map.get_l(id).parent,
wizard: Wizard::new(),
}));
} else if orig_edits.lane_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
@ -191,10 +173,9 @@ impl State for EditMode {
.input
.contextual_action(Key::E, &format!("edit stop signs for {}", id))
{
return (
Transition::Push(Box::new(stop_signs::StopSignEditor::new(id, ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(stop_signs::StopSignEditor::new(
id, ctx, ui,
)));
} else if orig_edits.stop_sign_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
@ -208,12 +189,9 @@ impl State for EditMode {
.input
.contextual_action(Key::E, &format!("edit traffic signal for {}", id))
{
return (
Transition::Push(Box::new(traffic_signals::TrafficSignalEditor::new(
id, ctx, ui,
))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(traffic_signals::TrafficSignalEditor::new(
id, ctx, ui,
)));
} else if orig_edits.traffic_signal_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
@ -224,7 +202,7 @@ impl State for EditMode {
}
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw_default_ui(&self) -> bool {
@ -320,13 +298,13 @@ struct Saving {
}
impl State for Saving {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
ctx.canvas.handle_event(ctx.input);
if save_edits(self.wizard.wrap(ctx), &mut ui.primary.map).is_some() || self.wizard.aborted()
{
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
} else {
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
}
@ -341,7 +319,7 @@ struct Loading {
}
impl State for Loading {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
ctx.canvas.handle_event(ctx.input);
if let Some(new_edits) = load_edits(
&ui.primary.map,
@ -349,11 +327,11 @@ impl State for Loading {
"Load which map edits?",
) {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
} else if self.wizard.aborted() {
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
} else {
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
}
@ -369,15 +347,15 @@ struct BulkEditLanes {
}
impl State for BulkEditLanes {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
ctx.canvas.handle_event(ctx.input);
if let Some(edits) = bulk_edit(self.road, &mut self.wizard.wrap(ctx), &ui.primary.map) {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, edits);
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
} else if self.wizard.aborted() {
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
} else {
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
}

View File

@ -4,7 +4,7 @@ use crate::game::{State, Transition};
use crate::helpers::ID;
use crate::render::{DrawIntersection, DrawOptions, DrawTurn};
use crate::ui::{ShowEverything, UI};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, Text};
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Text};
use geom::Polygon;
use map_model::{IntersectionID, RoadID, TurnID, TurnPriority};
use std::collections::HashMap;
@ -51,7 +51,7 @@ impl StopSignEditor {
}
impl State for StopSignEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input);
@ -108,13 +108,13 @@ impl State for StopSignEditor {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
} else if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.menu.action("reset to default") {
let mut new_edits = ui.primary.map.get_edits().clone();
new_edits.stop_sign_overrides.remove(&self.id);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -6,8 +6,7 @@ use crate::render::{draw_signal_cycle, draw_signal_diagram, DrawCtx, DrawOptions
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, MultiKey, Wizard,
WrappedWizard,
hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, MultiKey, Wizard, WrappedWizard,
};
use geom::Duration;
use map_model::{ControlTrafficSignal, Cycle, IntersectionID, Map, TurnID, TurnPriority, TurnType};
@ -59,7 +58,7 @@ impl TrafficSignalEditor {
}
impl State for TrafficSignalEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input);
@ -149,7 +148,7 @@ impl State for TrafficSignalEditor {
}
} else {
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.current_cycle != 0 && self.menu.action("select previous cycle") {
@ -235,7 +234,7 @@ impl State for TrafficSignalEditor {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -44,30 +44,54 @@ impl Game {
impl GUI for Game {
fn event(&mut self, ctx: &mut EventCtx) -> EventLoopMode {
let (transition, evloop) = self.states.last_mut().unwrap().event(ctx, &mut self.ui);
let transition = self.states.last_mut().unwrap().event(ctx, &mut self.ui);
match transition {
Transition::Keep => {}
Transition::Keep => EventLoopMode::InputOnly,
Transition::Pop => {
self.states.pop().unwrap().on_destroy(&mut self.ui);
if self.states.is_empty() {
self.before_quit(ctx.canvas);
std::process::exit(0);
}
EventLoopMode::InputOnly
}
Transition::PopWithData(cb) => {
self.states.pop().unwrap().on_destroy(&mut self.ui);
cb(self.states.last_mut().unwrap());
EventLoopMode::InputOnly
}
Transition::Push(state) => {
self.states.last_mut().unwrap().on_suspend(&mut self.ui);
self.states.push(state);
EventLoopMode::InputOnly
}
Transition::Replace(state) => {
self.states.pop().unwrap().on_destroy(&mut self.ui);
self.states.push(state);
EventLoopMode::InputOnly
}
// A little repetitive...
Transition::KeepWithMode(evmode) => evmode,
Transition::PopWithMode(evmode) => {
self.states.pop().unwrap().on_destroy(&mut self.ui);
if self.states.is_empty() {
self.before_quit(ctx.canvas);
std::process::exit(0);
}
evmode
}
Transition::PushWithMode(state, evmode) => {
self.states.last_mut().unwrap().on_suspend(&mut self.ui);
self.states.push(state);
evmode
}
Transition::ReplaceWithMode(state, evmode) => {
self.states.pop().unwrap().on_destroy(&mut self.ui);
self.states.push(state);
evmode
}
}
evloop
}
fn draw(&self, g: &mut GfxCtx) {
@ -114,7 +138,9 @@ impl GUI for Game {
}
pub trait State: downcast_rs::Downcast {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode);
// Logically this returns Transition, but since EventLoopMode is almost always
// InputOnly, the variations are encoded by Transition.
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition;
fn draw(&self, g: &mut GfxCtx, ui: &UI);
fn draw_default_ui(&self) -> bool {
true
@ -129,11 +155,19 @@ pub trait State: downcast_rs::Downcast {
downcast_rs::impl_downcast!(State);
//
pub enum Transition {
// These variants imply EventLoopMode::InputOnly.
Keep,
Pop,
// If a state needs to pass data back to the parent, use this. Sadly, runtime type casting.
PopWithData(Box<FnOnce(&mut Box<State>)>),
Push(Box<State>),
Replace(Box<State>),
// These don't.
KeepWithMode(EventLoopMode),
PopWithMode(EventLoopMode),
PushWithMode(Box<State>, EventLoopMode),
ReplaceWithMode(Box<State>, EventLoopMode),
}

View File

@ -87,7 +87,7 @@ impl TripsVisualizer {
}
impl State for TripsVisualizer {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let time = self.current_time();
let mut txt = Text::prompt("Trips Visualizer");
@ -112,7 +112,7 @@ impl State for TripsVisualizer {
let thirty_mins = Duration::minutes(30);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if time != last_time && self.menu.action("forwards 10 seconds") {
self.time_slider
.set_percent(ctx, (time + ten_secs) / last_time);
@ -137,7 +137,7 @@ impl State for TripsVisualizer {
self.time_slider
.set_percent(ctx, ((time + dt) / last_time).min(1.0));
} else {
return (Transition::Keep, EventLoopMode::InputOnly);
return Transition::Keep;
}
// TODO Do this more efficiently. ;)
@ -151,9 +151,9 @@ impl State for TripsVisualizer {
.collect();
if self.speed.is_paused() {
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
} else {
(Transition::Keep, EventLoopMode::Animation)
Transition::KeepWithMode(EventLoopMode::Animation)
}
}

View File

@ -4,8 +4,7 @@ use crate::helpers::{rotating_color_total, ID};
use crate::ui::UI;
use abstutil::{prettyprint_usize, Timer};
use ezgui::{
hotkey, Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text,
VerticalAlignment,
hotkey, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment,
};
use geom::{Distance, Polygon, Pt2D};
use popdat::{Estimate, PopDat};
@ -59,7 +58,7 @@ impl DataVisualizer {
}
}
impl State for DataVisualizer {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let mut txt = Text::prompt("Data Visualizer");
if let Some(ref name) = self.current_tract {
txt.add_line("Census ".to_string());
@ -80,7 +79,7 @@ impl State for DataVisualizer {
// TODO Remember which dataset we're showing and don't allow reseting to the same.
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.current_dataset != 0 && self.menu.action("household vehicles") {
self.current_dataset = 0;
} else if self.current_dataset != 1 && self.menu.action("commute times") {
@ -103,7 +102,7 @@ impl State for DataVisualizer {
}
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -3,7 +3,7 @@ use crate::game::{State, Transition};
use crate::helpers::ID;
use crate::mission::trips::{clip_trips, Trip, TripEndpt};
use crate::ui::{ShowEverything, UI};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, Color, EventCtx, GfxCtx, ItemSlider, Key, Text};
use geom::{Circle, Distance, Line, Speed};
use map_model::BuildingID;
use popdat::psrc;
@ -56,7 +56,7 @@ impl TripsVisualizer {
}
impl State for TripsVisualizer {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.slider.event(ctx);
ctx.canvas.handle_event(ctx.input);
@ -70,9 +70,9 @@ impl State for TripsVisualizer {
}
if self.slider.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -10,7 +10,7 @@ use crate::game::{State, Transition};
use crate::sandbox::SandboxMode;
use crate::ui::UI;
use abstutil::Timer;
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use geom::Duration;
use map_model::Map;
use sim::Scenario;
@ -45,27 +45,18 @@ impl MissionEditMode {
}
impl State for MissionEditMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.menu.action("visualize population data") {
return (
Transition::Push(Box::new(dataviz::DataVisualizer::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(dataviz::DataVisualizer::new(ctx, ui)));
} else if self.menu.action("visualize individual PSRC trips") {
return (
Transition::Push(Box::new(individ_trips::TripsVisualizer::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(individ_trips::TripsVisualizer::new(ctx, ui)));
} else if self.menu.action("visualize all PSRC trips") {
return (
Transition::Push(Box::new(all_trips::TripsVisualizer::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(all_trips::TripsVisualizer::new(ctx, ui)));
} else if self.menu.action("set up simulation with PSRC trips") {
let scenario = trips_to_scenario(
ctx,
@ -84,38 +75,23 @@ impl State for MissionEditMode {
.sim
.step(&ui.primary.map, Duration::const_seconds(0.1));
});
return (
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(SandboxMode::new(ctx)));
} else if self.menu.action("create scenario from PSRC trips") {
return (
Transition::Push(Box::new(TripsToScenario {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(TripsToScenario {
wizard: Wizard::new(),
}));
} else if self.menu.action("manage neighborhoods") {
return (
Transition::Push(Box::new(neighborhood::NeighborhoodPicker::new())),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(neighborhood::NeighborhoodPicker::new()));
} else if self.menu.action("load scenario") {
return (
Transition::Push(Box::new(LoadScenario {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(LoadScenario {
wizard: Wizard::new(),
}));
} else if self.menu.action("create new scenario") {
return (
Transition::Push(Box::new(CreateNewScenario {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(CreateNewScenario {
wizard: Wizard::new(),
}));
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -128,14 +104,14 @@ struct TripsToScenario {
}
impl State for TripsToScenario {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some((t1, t2)) = pick_time_range(self.wizard.wrap(ctx)) {
trips_to_scenario(ctx, ui, t1, t2).save();
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -148,16 +124,13 @@ struct LoadScenario {
}
impl State for LoadScenario {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some(scenario) = load_scenario(&ui.primary.map, &mut self.wizard.wrap(ctx)) {
return (
Transition::Replace(Box::new(scenario::ScenarioManager::new(scenario, ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(scenario::ScenarioManager::new(scenario, ctx)));
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -170,27 +143,24 @@ struct CreateNewScenario {
}
impl State for CreateNewScenario {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let mut wrapped = self.wizard.wrap(ctx);
if let Some(name) = wrapped.input_string("Name the scenario") {
return (
Transition::Replace(Box::new(scenario::ScenarioManager::new(
Scenario {
scenario_name: name,
map_name: ui.primary.map.get_name().to_string(),
seed_parked_cars: Vec::new(),
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
},
ctx,
))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(scenario::ScenarioManager::new(
Scenario {
scenario_name: name,
map_name: ui.primary.map.get_name().to_string(),
seed_parked_cars: Vec::new(),
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
},
ctx,
)));
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {

View File

@ -1,8 +1,6 @@
use crate::game::{State, Transition};
use crate::ui::UI;
use ezgui::{
hotkey, Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard,
};
use ezgui::{hotkey, Color, EventCtx, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use geom::{Circle, Distance, Line, Polygon, Pt2D};
use map_model::{Map, NeighborhoodBuilder};
@ -21,32 +19,29 @@ impl NeighborhoodPicker {
}
impl State for NeighborhoodPicker {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
ctx.canvas.handle_event(ctx.input);
if let Some(n) = pick_neighborhood(&ui.primary.map, self.wizard.wrap(ctx)) {
return (
Transition::Push(Box::new(NeighborhoodEditor {
menu: ModalMenu::new(
&format!("Neighborhood Editor for {}", n.name),
vec![
(hotkey(Key::Escape), "quit"),
(hotkey(Key::S), "save"),
(hotkey(Key::X), "export as an Osmosis polygon filter"),
(hotkey(Key::P), "add a new point"),
],
ctx,
),
neighborhood: n,
mouseover_pt: None,
moving_pt: false,
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(NeighborhoodEditor {
menu: ModalMenu::new(
&format!("Neighborhood Editor for {}", n.name),
vec![
(hotkey(Key::Escape), "quit"),
(hotkey(Key::S), "save"),
(hotkey(Key::X), "export as an Osmosis polygon filter"),
(hotkey(Key::P), "add a new point"),
],
ctx,
),
neighborhood: n,
mouseover_pt: None,
moving_pt: false,
}));
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
@ -74,7 +69,7 @@ struct NeighborhoodEditor {
}
impl State for NeighborhoodEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let gps_bounds = ui.primary.map.get_gps_bounds();
self.menu.handle_event(ctx, None);
@ -93,7 +88,7 @@ impl State for NeighborhoodEditor {
}
} else {
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.neighborhood.points.len() >= 3 && self.menu.action("save") {
self.neighborhood.save();
} else if self.neighborhood.points.len() >= 3
@ -131,7 +126,7 @@ impl State for NeighborhoodEditor {
self.moving_pt = true;
}
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -3,9 +3,7 @@ use crate::mission::input_time;
use crate::sandbox::SandboxMode;
use crate::ui::UI;
use abstutil::WeightedUsizeChoice;
use ezgui::{
hotkey, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
use geom::Duration;
use map_model::{IntersectionID, Map, Neighborhood};
use sim::{BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars, SpawnOverTime};
@ -37,19 +35,16 @@ impl ScenarioManager {
}
impl State for ScenarioManager {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input);
if self.menu.action("save") {
self.scenario.save();
} else if self.menu.action("edit") {
return (
Transition::Push(Box::new(ScenarioEditor {
scenario: self.scenario.clone(),
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(ScenarioEditor {
scenario: self.scenario.clone(),
wizard: Wizard::new(),
}));
} else if self.menu.action("instantiate") {
ctx.loading_screen("instantiate scenario", |_, timer| {
self.scenario.instantiate(
@ -60,14 +55,11 @@ impl State for ScenarioManager {
);
ui.primary.sim.step(&ui.primary.map, Duration::seconds(0.1));
});
return (
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(SandboxMode::new(ctx)));
} else if self.scroller.event(&mut ctx.input) {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -82,24 +74,21 @@ struct ScenarioEditor {
}
impl State for ScenarioEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some(()) = edit_scenario(&ui.primary.map, &mut self.scenario, self.wizard.wrap(ctx))
{
// TODO autosave, or at least make it clear there are unsaved edits
let scenario = self.scenario.clone();
return (
Transition::PopWithData(Box::new(|state| {
let mut manager = state.downcast_mut::<ScenarioManager>().unwrap();
manager.scroller =
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
manager.scenario = scenario;
})),
EventLoopMode::InputOnly,
);
return Transition::PopWithData(Box::new(|state| {
let mut manager = state.downcast_mut::<ScenarioManager>().unwrap();
manager.scroller =
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
manager.scenario = scenario;
}));
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {

View File

@ -72,7 +72,7 @@ impl SandboxMode {
}
impl State for SandboxMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.time_travel.record(ui);
let mut txt = Text::prompt("Sandbox Mode");
@ -106,21 +106,15 @@ impl State for SandboxMode {
false,
);
}
if let Some(pair) = self.common.event(ctx, ui, &mut self.menu) {
return pair;
if let Some(t) = self.common.event(ctx, ui, &mut self.menu) {
return t;
}
if let Some(spawner) = spawner::AgentSpawner::new(ctx, ui, &mut self.menu) {
return (
Transition::Push(Box::new(spawner)),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(spawner));
}
if let Some(explorer) = route_explorer::RouteExplorer::new(ctx, ui) {
return (
Transition::Push(Box::new(explorer)),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(explorer));
}
if self.following.is_none() {
@ -159,27 +153,18 @@ impl State for SandboxMode {
//return EventLoopMode::InputOnly;
}
if self.menu.action("scoreboard") {
return (
Transition::Push(Box::new(score::Scoreboard::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(score::Scoreboard::new(ctx, ui)));
}
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.menu.action("debug mode") {
// TODO Replace or Push?
return (
Transition::Replace(Box::new(DebugMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(DebugMode::new(ctx, ui)));
}
if self.menu.action("edit mode") {
return (
Transition::Replace(Box::new(EditMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(EditMode::new(ctx, ui)));
}
if let Some(dt) = self.speed.event(ctx, &mut self.menu, ui.primary.sim.time()) {
@ -199,10 +184,7 @@ impl State for SandboxMode {
if self.speed.is_paused() {
if !ui.primary.sim.is_empty() && self.menu.action("reset sim") {
ui.primary.reset_sim();
return (
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(SandboxMode::new(ctx)));
}
if self.menu.action("save sim state") {
ui.primary.sim.save();
@ -268,16 +250,13 @@ impl State for SandboxMode {
false,
);
} else if self.menu.action("jump to specific time") {
return (
Transition::Push(Box::new(JumpingToTime {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(JumpingToTime {
wizard: Wizard::new(),
}));
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
} else {
(Transition::Keep, EventLoopMode::Animation)
Transition::KeepWithMode(EventLoopMode::Animation)
}
}
@ -324,7 +303,7 @@ struct JumpingToTime {
}
impl State for JumpingToTime {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
let mut wiz = self.wizard.wrap(ctx);
if let Some(t) = input_time(&mut wiz, "Jump to what time?") {
@ -334,7 +313,7 @@ impl State for JumpingToTime {
"Bad time",
vec![&format!("{} isn't after {}", t, ui.primary.sim.time())],
) {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
} else {
if dt > Duration::ZERO {
@ -343,12 +322,12 @@ impl State for JumpingToTime {
});
}
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {

View File

@ -2,7 +2,7 @@ use crate::common::CommonState;
use crate::game::{State, Transition};
use crate::render::DrawTurn;
use crate::ui::{ShowEverything, UI};
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, Text, WarpingItemSlider};
use ezgui::{Color, EventCtx, GfxCtx, Key, Text, WarpingItemSlider};
use geom::{Distance, Polygon, Pt2D};
use map_model::{Traversable, LANE_THICKNESS};
use sim::AgentID;
@ -66,7 +66,7 @@ impl RouteExplorer {
}
impl State for RouteExplorer {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if ctx.redo_mouseover() {
ui.primary.current_selection = ui.recalculate_current_selection(
ctx,
@ -81,9 +81,9 @@ impl State for RouteExplorer {
// We don't really care about setting current_selection to the current step; drawing covers
// it up anyway.
if let Some((evmode, _)) = self.slider.event(ctx) {
(Transition::Keep, evmode)
Transition::KeepWithMode(evmode)
} else {
(Transition::Pop, EventLoopMode::InputOnly)
Transition::Pop
}
}

View File

@ -1,8 +1,8 @@
use crate::game::{State, Transition};
use crate::ui::UI;
use ezgui::{
hotkey, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text,
VerticalAlignment, Wizard, WrappedWizard,
hotkey, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment, Wizard,
WrappedWizard,
};
use geom::{Duration, DurationHistogram};
use itertools::Itertools;
@ -47,21 +47,18 @@ impl Scoreboard {
}
impl State for Scoreboard {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
self.menu.handle_event(ctx, None);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
if self.menu.action("browse trips") {
return (
Transition::Push(Box::new(BrowseTrips {
trips: ui.primary.sim.get_finished_trips(),
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
return Transition::Push(Box::new(BrowseTrips {
trips: ui.primary.sim.get_finished_trips(),
wizard: Wizard::new(),
}));
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -79,14 +76,14 @@ struct BrowseTrips {
}
impl State for BrowseTrips {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
if pick_trip(&self.trips, &mut self.wizard.wrap(ctx)).is_some() {
// TODO show trip departure, where it started and ended
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
} else if self.wizard.aborted() {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {

View File

@ -4,7 +4,7 @@ use crate::helpers::ID;
use crate::render::DrawOptions;
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu};
use geom::{Duration, PolyLine};
use map_model::{
BuildingID, IntersectionID, IntersectionType, LaneType, PathRequest, Position, LANE_THICKNESS,
@ -116,11 +116,11 @@ impl AgentSpawner {
}
impl State for AgentSpawner {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
// TODO Instructions to select target building/lane
self.menu.handle_event(ctx, None);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
ctx.canvas.handle_event(ctx.input);
@ -144,7 +144,7 @@ impl State for AgentSpawner {
}
_ => {
self.maybe_goal = None;
return (Transition::Keep, EventLoopMode::InputOnly);
return Transition::Keep;
}
};
@ -176,7 +176,7 @@ impl State for AgentSpawner {
);
if lanes.is_empty() {
self.maybe_goal = None;
return (Transition::Keep, EventLoopMode::InputOnly);
return Transition::Keep;
}
Position::new(lanes[0], map.get_l(lanes[0]).length())
}
@ -290,10 +290,10 @@ impl State for AgentSpawner {
&ShowEverything::new(),
false,
);
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw_default_ui(&self) -> bool {

View File

@ -41,27 +41,24 @@ impl SplashScreen {
}
impl State for SplashScreen {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
if let Some((ref mut screensaver, ref mut rng)) = self.maybe_screensaver {
screensaver.update(rng, ctx.input, ctx.canvas, &ui.primary.map);
}
let transition = if let Some(t) =
splash_screen(&mut self.wizard, ctx, ui, &mut self.maybe_screensaver)
{
t
} else if self.wizard.aborted() {
Transition::Pop
} else {
Transition::Keep
};
let evloop = if self.maybe_screensaver.is_some() {
let evmode = if self.maybe_screensaver.is_some() {
EventLoopMode::Animation
} else {
EventLoopMode::InputOnly
};
(transition, evloop)
if let Some(t) = splash_screen(&mut self.wizard, ctx, ui, &mut self.maybe_screensaver) {
t
} else if self.wizard.aborted() {
Transition::PopWithMode(evmode)
} else {
Transition::KeepWithMode(evmode)
}
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -135,6 +132,12 @@ fn splash_screen(
let about = "About";
let quit = "Quit";
let evmode = if maybe_screensaver.is_some() {
EventLoopMode::Animation
} else {
EventLoopMode::InputOnly
};
// TODO No hotkey for quit because it's just the normal menu escape?
match wizard
.choose_string_hotkeys(
@ -172,10 +175,13 @@ fn splash_screen(
// TODO want to clear wizard and screensaver as we leave this state.
Some(Transition::Push(Box::new(SandboxMode::new(ctx))))
} else if wizard.aborted() {
Some(Transition::Replace(Box::new(SplashScreen {
wizard: Wizard::new(),
maybe_screensaver: maybe_screensaver.take(),
})))
Some(Transition::ReplaceWithMode(
Box::new(SplashScreen {
wizard: Wizard::new(),
maybe_screensaver: maybe_screensaver.take(),
}),
evmode,
))
} else {
None
}

View File

@ -1,6 +1,6 @@
use crate::game::{State, Transition};
use crate::ui::UI;
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu, Text};
use geom::Pt2D;
pub struct TutorialMode {
@ -21,7 +21,7 @@ impl TutorialMode {
}
impl State for TutorialMode {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
let mut txt = Text::prompt("Tutorial");
txt.add_line("Click and drag to pan around".to_string());
@ -30,23 +30,20 @@ impl State for TutorialMode {
txt.add_line("".to_string());
txt.add_line("Great! Press ENTER to continue.".to_string());
if ctx.input.key_pressed(Key::Enter, "next step of tutorial") {
return (
Transition::Replace(Box::new(Part2 {
orig_cam_zoom: ctx.canvas.cam_zoom,
menu: ModalMenu::new("Tutorial", vec![(hotkey(Key::Escape), "quit")], ctx),
})),
EventLoopMode::InputOnly,
);
return Transition::Replace(Box::new(Part2 {
orig_cam_zoom: ctx.canvas.cam_zoom,
menu: ModalMenu::new("Tutorial", vec![(hotkey(Key::Escape), "quit")], ctx),
}));
}
}
self.menu.handle_event(ctx, Some(txt));
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
@ -64,7 +61,7 @@ struct Part2 {
}
impl State for Part2 {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) {
fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> Transition {
let mut txt = Text::prompt("Tutorial");
txt.add_line("Use your mouse wheel or touchpad to zoom in and out".to_string());
@ -72,17 +69,17 @@ impl State for Part2 {
txt.add_line("".to_string());
txt.add_line("Great! Press ENTER to continue.".to_string());
if ctx.input.key_pressed(Key::Enter, "next step of tutorial") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
}
self.menu.handle_event(ctx, Some(txt));
ctx.canvas.handle_event(ctx.input);
if self.menu.action("quit") {
return (Transition::Pop, EventLoopMode::InputOnly);
return Transition::Pop;
}
(Transition::Keep, EventLoopMode::InputOnly)
Transition::Keep
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {