diff --git a/editor/src/abtest/mod.rs b/editor/src/abtest/mod.rs index e8cc686ca1..b7dd3b2032 100644 --- a/editor/src/abtest/mod.rs +++ b/editor/src/abtest/mod.rs @@ -1,13 +1,11 @@ mod score; -mod setup; +pub mod setup; use crate::common::{CommonState, SpeedControls}; -use crate::game::{GameState, Mode}; -use crate::render::{DrawOptions, MIN_ZOOM_FOR_DETAIL}; +use crate::render::MIN_ZOOM_FOR_DETAIL; +use crate::state::{State, Transition}; use crate::ui::{PerMapUI, ShowEverything, UI}; -use ezgui::{ - hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, Text, Wizard, -}; +use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, Text}; use geom::{Circle, Distance, Duration, Line, PolyLine}; use map_model::{Map, LANE_THICKNESS}; use serde_derive::{Deserialize, Serialize}; @@ -16,9 +14,8 @@ use sim::{Sim, TripID}; pub struct ABTestMode { menu: ModalMenu, speed: SpeedControls, - pub state: State, // TODO Urgh, hack. Need to be able to take() it to switch states sometimes. - pub secondary: Option, + secondary: Option, diff_trip: Option, diff_all: Option, // TODO Not present in Setup state. @@ -26,14 +23,13 @@ pub struct ABTestMode { test_name: String, } -pub enum State { - Setup(setup::ABTestSetup), - Playing, - Scoreboard(score::Scoreboard), -} - impl ABTestMode { - pub fn new(ctx: &mut EventCtx, ui: &mut UI, test_name: &str) -> ABTestMode { + pub fn new( + ctx: &mut EventCtx, + ui: &mut UI, + test_name: &str, + secondary: PerMapUI, + ) -> ABTestMode { ui.primary.current_selection = None; ABTestMode { @@ -58,148 +54,133 @@ impl ABTestMode { ctx, ), speed: SpeedControls::new(ctx, None), - state: State::Setup(setup::ABTestSetup::Pick(Wizard::new())), - secondary: None, + secondary: Some(secondary), diff_trip: None, diff_all: None, common: CommonState::new(), test_name: test_name.to_string(), } } +} - pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode { - match state.mode { - Mode::ABTest(ref mut mode) => { - match mode.state { - State::Setup(_) => { - setup::ABTestSetup::event(state, ctx); - EventLoopMode::InputOnly - } - State::Scoreboard(ref mut s) => { - if s.event(ctx, &state.ui.primary, mode.secondary.as_ref().unwrap()) { - mode.state = State::Playing; - mode.speed.pause(); - } - EventLoopMode::InputOnly - } - State::Playing => { - let mut txt = Text::prompt("A/B Test Mode"); - txt.add_line(state.ui.primary.map.get_edits().edits_name.clone()); - if let Some(ref diff) = mode.diff_trip { - txt.add_line(format!("Showing diff for {}", diff.trip)); - } else if let Some(ref diff) = mode.diff_all { - txt.add_line(format!( - "Showing diffs for all. {} trips same, {} differ", - diff.same_trips, - diff.lines.len() - )); - } - txt.add_line(state.ui.primary.sim.summary()); - mode.menu.handle_event(ctx, Some(txt)); +impl State for ABTestMode { + fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) { + 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 { + txt.add_line(format!("Showing diff for {}", diff.trip)); + } else if let Some(ref diff) = self.diff_all { + txt.add_line(format!( + "Showing diffs for all. {} trips same, {} differ", + diff.same_trips, + diff.lines.len() + )); + } + txt.add_line(ui.primary.sim.summary()); + self.menu.handle_event(ctx, Some(txt)); - ctx.canvas.handle_event(ctx.input); - if ctx.redo_mouseover() { - state.ui.primary.current_selection = - state.ui.recalculate_current_selection( - ctx, - &state.ui.primary.sim, - &ShowEverything::new(), - false, - ); - } - if let Some(evmode) = mode.common.event(ctx, &mut state.ui, &mut mode.menu) - { - return evmode; - } + ctx.canvas.handle_event(ctx.input); + if ctx.redo_mouseover() { + ui.primary.current_selection = ui.recalculate_current_selection( + ctx, + &ui.primary.sim, + &ShowEverything::new(), + false, + ); + } + if let Some(evmode) = self.common.event(ctx, ui, &mut self.menu) { + return (Transition::Keep, evmode); + } - if mode.menu.action("quit") { - // TODO This shouldn't be necessary when we plumb state around instead of - // sharing it in the old structure. - state.ui.primary.reset_sim(); - // Note destroying mode.secondary has some noticeable delay. - state.mode = Mode::SplashScreen(Wizard::new(), None); - return EventLoopMode::InputOnly; - } + if self.menu.action("quit") { + // TODO Should we clear edits too? + ui.primary.reset_sim(); + // Note destroying mode.secondary has some noticeable delay. + return (Transition::Pop, EventLoopMode::InputOnly); + } - if mode.menu.action("swap") { - let secondary = mode.secondary.take().unwrap(); - let primary = std::mem::replace(&mut state.ui.primary, secondary); - mode.secondary = Some(primary); - mode.recalculate_stuff(&mut state.ui, ctx); - } + if self.menu.action("swap") { + let secondary = self.secondary.take().unwrap(); + let primary = std::mem::replace(&mut ui.primary, secondary); + self.secondary = Some(primary); + self.recalculate_stuff(ui, ctx); + } - if mode.menu.action("scoreboard") { - mode.state = State::Scoreboard(score::Scoreboard::new( - ctx, - &state.ui.primary, - mode.secondary.as_ref().unwrap(), - )); - return EventLoopMode::InputOnly; - } + if self.menu.action("scoreboard") { + self.speed.pause(); + return ( + Transition::Push(Box::new(score::Scoreboard::new( + ctx, + &ui.primary, + self.secondary.as_ref().unwrap(), + ))), + EventLoopMode::InputOnly, + ); + } - if mode.menu.action("save state") { - mode.savestate(&mut state.ui.primary); - } + if self.menu.action("save state") { + self.savestate(&mut ui.primary); + } - if mode.diff_trip.is_some() { - if mode.menu.action("stop diffing trips") { - mode.diff_trip = None; - } - } else if mode.diff_all.is_some() { - if mode.menu.action("stop diffing trips") { - mode.diff_all = None; - } - } else { - if state.ui.primary.current_selection.is_none() - && mode.menu.action("diff all trips") - { - mode.diff_all = Some(DiffAllTrips::new( - &mut state.ui.primary, - mode.secondary.as_mut().unwrap(), - )); - } else if let Some(agent) = state - .ui - .primary - .current_selection - .and_then(|id| id.agent_id()) - { - if let Some(trip) = state.ui.primary.sim.agent_to_trip(agent) { - if ctx.input.contextual_action( - Key::B, - &format!("Show {}'s parallel world", agent), - ) { - mode.diff_trip = Some(DiffOneTrip::new( - trip, - &state.ui.primary, - mode.secondary.as_ref().unwrap(), - )); - } - } - } - } - - if let Some(dt) = - mode.speed - .event(ctx, &mut mode.menu, state.ui.primary.sim.time()) - { - mode.step(dt, &mut state.ui, ctx); - } - - if mode.speed.is_paused() { - if mode.menu.action("step forwards 0.1s") { - mode.step(Duration::seconds(0.1), &mut state.ui, ctx); - } - EventLoopMode::InputOnly - } else { - EventLoopMode::Animation - } + if self.diff_trip.is_some() { + if self.menu.action("stop diffing trips") { + self.diff_trip = None; + } + } else if self.diff_all.is_some() { + if self.menu.action("stop diffing trips") { + self.diff_all = None; + } + } else { + if ui.primary.current_selection.is_none() && self.menu.action("diff all trips") { + self.diff_all = Some(DiffAllTrips::new( + &mut ui.primary, + self.secondary.as_mut().unwrap(), + )); + } else if let Some(agent) = ui.primary.current_selection.and_then(|id| id.agent_id()) { + if let Some(trip) = ui.primary.sim.agent_to_trip(agent) { + if ctx + .input + .contextual_action(Key::B, &format!("Show {}'s parallel world", agent)) + { + self.diff_trip = Some(DiffOneTrip::new( + trip, + &ui.primary, + self.secondary.as_ref().unwrap(), + )); } } } - _ => unreachable!(), + } + + if let Some(dt) = self.speed.event(ctx, &mut self.menu, ui.primary.sim.time()) { + self.step(dt, ui, ctx); + } + + if self.speed.is_paused() { + if self.menu.action("step forwards 0.1s") { + self.step(Duration::seconds(0.1), ui, ctx); + } + (Transition::Keep, EventLoopMode::InputOnly) + } else { + (Transition::Keep, EventLoopMode::Animation) } } + fn draw(&self, g: &mut GfxCtx, ui: &UI) { + self.common.draw(g, ui); + + if let Some(ref diff) = self.diff_trip { + diff.draw(g, ui); + } + if let Some(ref diff) = self.diff_all { + diff.draw(g, ui); + } + self.menu.draw(g); + self.speed.draw(g); + } +} + +impl ABTestMode { fn step(&mut self, dt: Duration, ui: &mut UI, ctx: &EventCtx) { ui.primary.sim.step(&ui.primary.map, dt); { @@ -228,50 +209,6 @@ impl ABTestMode { ui.recalculate_current_selection(ctx, &ui.primary.sim, &ShowEverything::new(), false); } - pub fn draw(state: &GameState, g: &mut GfxCtx) { - match state.mode { - Mode::ABTest(ref mode) => match mode.state { - State::Setup(ref setup) => { - state.ui.draw( - g, - DrawOptions::new(), - &state.ui.primary.sim, - &ShowEverything::new(), - ); - setup.draw(g); - } - State::Scoreboard(ref s) => { - state.ui.draw( - g, - DrawOptions::new(), - &state.ui.primary.sim, - &ShowEverything::new(), - ); - s.draw(g); - } - State::Playing => { - state.ui.draw( - g, - mode.common.draw_options(&state.ui), - &state.ui.primary.sim, - &ShowEverything::new(), - ); - mode.common.draw(g, &state.ui); - - if let Some(ref diff) = mode.diff_trip { - diff.draw(g, &state.ui); - } - if let Some(ref diff) = mode.diff_all { - diff.draw(g, &state.ui); - } - mode.menu.draw(g); - mode.speed.draw(g); - } - }, - _ => unreachable!(), - } - } - fn savestate(&mut self, primary: &mut PerMapUI) { // Temporarily move everything into this structure. let blank_map = Map::blank(); diff --git a/editor/src/abtest/score.rs b/editor/src/abtest/score.rs index fa96d440c6..32012ffd22 100644 --- a/editor/src/abtest/score.rs +++ b/editor/src/abtest/score.rs @@ -1,16 +1,18 @@ +use crate::state::{State, Transition}; use crate::ui::PerMapUI; +use crate::ui::UI; use ezgui::{ - hotkey, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment, Wizard, - WrappedWizard, + hotkey, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, + VerticalAlignment, Wizard, WrappedWizard, }; use geom::Duration; use itertools::Itertools; use sim::{FinishedTrips, TripID, TripMode}; use std::collections::BTreeMap; -pub enum Scoreboard { - Summary(ModalMenu, Text), - BrowseTrips(CompareTrips, Wizard), +pub struct Scoreboard { + menu: ModalMenu, + summary: Text, } impl Scoreboard { @@ -76,52 +78,55 @@ impl Scoreboard { } } - Scoreboard::Summary(menu, summary) + Scoreboard { menu, summary } + } +} + +impl State for Scoreboard { + fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) { + self.menu.handle_event(ctx, None); + if self.menu.action("quit") { + return (Transition::Pop, EventLoopMode::InputOnly); + } + if self.menu.action("browse trips") { + /*self = Scoreboard::BrowseTrips( + CompareTrips::new( + primary.sim.get_finished_trips(), + secondary.sim.get_finished_trips(), + ), + Wizard::new(), + );*/ + } + (Transition::Keep, EventLoopMode::InputOnly) } - // Returns true if done and we should go back to main A/B test mode. - pub fn event(&mut self, ctx: &mut EventCtx, primary: &PerMapUI, secondary: &PerMapUI) -> bool { - match self { - Scoreboard::Summary(ref mut menu, _) => { - menu.handle_event(ctx, None); - if menu.action("quit") { - return true; - } - if menu.action("browse trips") { - *self = Scoreboard::BrowseTrips( - CompareTrips::new( - primary.sim.get_finished_trips(), - secondary.sim.get_finished_trips(), - ), - Wizard::new(), - ); - } - } - Scoreboard::BrowseTrips(ref trips, ref mut wizard) => { - if pick_trip(trips, &mut wizard.wrap(ctx)).is_some() { - // TODO show more details... - *self = Scoreboard::new(ctx, primary, secondary); - } else if wizard.aborted() { - *self = Scoreboard::new(ctx, primary, secondary); - } - } + fn draw(&self, g: &mut GfxCtx, _: &UI) { + g.draw_blocking_text( + &self.summary, + (HorizontalAlignment::Center, VerticalAlignment::Center), + ); + self.menu.draw(g); + } +} + +struct BrowseTrips { + trips: CompareTrips, + wizard: Wizard, +} + +impl State for BrowseTrips { + fn event(&mut self, ctx: &mut EventCtx, _: &mut UI) -> (Transition, EventLoopMode) { + if pick_trip(&self.trips, &mut self.wizard.wrap(ctx)).is_some() { + // TODO show more details... + return (Transition::Pop, EventLoopMode::InputOnly); + } else if self.wizard.aborted() { + return (Transition::Pop, EventLoopMode::InputOnly); } - false + (Transition::Keep, EventLoopMode::InputOnly) } - pub fn draw(&self, g: &mut GfxCtx) { - match self { - Scoreboard::Summary(ref menu, ref txt) => { - g.draw_blocking_text( - txt, - (HorizontalAlignment::Center, VerticalAlignment::Center), - ); - menu.draw(g); - } - Scoreboard::BrowseTrips(_, ref wizard) => { - wizard.draw(g); - } - } + fn draw(&self, g: &mut GfxCtx, _: &UI) { + self.wizard.draw(g); } } diff --git a/editor/src/abtest/setup.rs b/editor/src/abtest/setup.rs index 58b49b53bd..70962977f8 100644 --- a/editor/src/abtest/setup.rs +++ b/editor/src/abtest/setup.rs @@ -1,100 +1,114 @@ -use crate::abtest::{ABTestMode, ABTestSavestate, State}; +use crate::abtest::{ABTestMode, ABTestSavestate}; use crate::edit::apply_map_edits; -use crate::game::{GameState, Mode}; use crate::render::DrawMap; +use crate::state::{State, Transition}; use crate::ui::{Flags, PerMapUI, UI}; -use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard}; +use ezgui::{ + hotkey, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard, +}; use geom::Duration; use map_model::{Map, MapEdits}; use sim::{ABTest, Scenario, SimFlags}; use std::path::PathBuf; -pub enum ABTestSetup { - Pick(Wizard), - Manage(ModalMenu, ABTest, LogScroller), - LoadSavestate(ABTest, Wizard), +pub struct PickABTest { + wizard: Wizard, } -impl ABTestSetup { - pub fn event(state: &mut GameState, ctx: &mut EventCtx) { - match state.mode { - Mode::ABTest(ref mut mode) => match mode.state { - State::Setup(ref mut setup) => match setup { - ABTestSetup::Pick(ref mut wizard) => { - if let Some(ab_test) = pick_ab_test(&state.ui.primary.map, wizard.wrap(ctx)) - { - let scroller = - LogScroller::new(ab_test.test_name.clone(), ab_test.describe()); - *setup = ABTestSetup::Manage( - 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 wizard.aborted() { - state.mode = Mode::SplashScreen(Wizard::new(), None); - } - } - ABTestSetup::LoadSavestate(ref test, ref mut wizard) => { - if let Some(ss) = pick_savestate(test, &mut wizard.wrap(ctx)) { - state.mode = launch_savestate(test, ss, &mut state.ui, ctx); - } else if wizard.aborted() { - // TODO Here's where we need to push and pop states. - let scroller = - LogScroller::new(test.test_name.clone(), test.describe()); - *setup = ABTestSetup::Manage( - ModalMenu::new( - &format!("A/B Test Editor for {}", test.test_name), - vec![ - (hotkey(Key::Escape), "quit"), - (hotkey(Key::R), "run A/B test"), - (hotkey(Key::L), "load savestate"), - ], - ctx, - ), - test.clone(), - scroller, - ); - } - } - ABTestSetup::Manage(ref mut menu, test, ref mut scroller) => { - ctx.canvas.handle_event(ctx.input); - menu.handle_event(ctx, None); - if scroller.event(ctx.input) { - state.mode = Mode::SplashScreen(Wizard::new(), None); - } else if menu.action("run A/B test") { - state.mode = launch_test(test, &mut state.ui, ctx); - } else if menu.action("load savestate") { - *setup = ABTestSetup::LoadSavestate(test.clone(), Wizard::new()); - } - } - }, - _ => unreachable!(), - }, - _ => unreachable!(), +impl PickABTest { + pub fn new() -> PickABTest { + PickABTest { + wizard: Wizard::new(), } } +} - pub fn draw(&self, g: &mut GfxCtx) { - match self { - ABTestSetup::Pick(wizard) => { - wizard.draw(g); - } - ABTestSetup::LoadSavestate(_, wizard) => { - wizard.draw(g); - } - ABTestSetup::Manage(ref menu, _, scroller) => { - scroller.draw(g); - menu.draw(g); - } +impl State for PickABTest { + fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) { + 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, + ); + } else if self.wizard.aborted() { + return (Transition::Pop, EventLoopMode::InputOnly); } + (Transition::Keep, EventLoopMode::InputOnly) + } + + fn draw(&self, g: &mut GfxCtx, ui: &UI) { + self.wizard.draw(g); + } +} + +struct ABTestSetup { + menu: ModalMenu, + ab_test: ABTest, + scroller: LogScroller, +} + +impl State for ABTestSetup { + fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) { + ctx.canvas.handle_event(ctx.input); + self.menu.handle_event(ctx, None); + if self.scroller.event(ctx.input) { + return (Transition::Pop, EventLoopMode::InputOnly); + } else if self.menu.action("run A/B test") { + return ( + Transition::Replace(Box::new(launch_test(&self.ab_test, ui, ctx))), + EventLoopMode::InputOnly, + ); + } else if self.menu.action("load savestate") { + return ( + Transition::Push(Box::new(LoadSavestate { + ab_test: self.ab_test.clone(), + wizard: Wizard::new(), + })), + EventLoopMode::InputOnly, + ); + } + (Transition::Keep, EventLoopMode::InputOnly) + } + + fn draw(&self, g: &mut GfxCtx, ui: &UI) { + self.scroller.draw(g); + self.menu.draw(g); + } +} + +struct LoadSavestate { + ab_test: ABTest, + wizard: Wizard, +} + +impl State for LoadSavestate { + fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) { + 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, + ); + } else if self.wizard.aborted() { + return (Transition::Pop, EventLoopMode::InputOnly); + } + (Transition::Keep, EventLoopMode::InputOnly) + } + + fn draw(&self, g: &mut GfxCtx, _: &UI) { + self.wizard.draw(g); } } @@ -119,7 +133,7 @@ fn pick_ab_test(map: &Map, mut wizard: WrappedWizard) -> Option { } } -fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> Mode { +fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> ABTestMode { let secondary = ctx.loading_screen( &format!("Launching A/B test {}", test.test_name), |ctx, mut timer| { @@ -188,13 +202,10 @@ fn launch_test(test: &ABTest, ui: &mut UI, ctx: &mut EventCtx) -> Mode { }, ); - let mut mode = ABTestMode::new(ctx, ui, &test.test_name); - mode.state = State::Playing; - mode.secondary = Some(secondary); - Mode::ABTest(mode) + ABTestMode::new(ctx, ui, &test.test_name, secondary) } -fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut EventCtx) -> Mode { +fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut EventCtx) -> ABTestMode { ctx.loading_screen( &format!("Launch A/B test from savestate {}", ss_path), |ctx, mut timer| { @@ -213,9 +224,7 @@ fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut Event timer.stop("setup primary"); timer.start("setup secondary"); - let mut mode = ABTestMode::new(ctx, ui, &test.test_name); - mode.state = State::Playing; - mode.secondary = Some(PerMapUI { + let secondary = PerMapUI { draw_map: DrawMap::new( &ss.secondary_map, &ui.primary.current_flags, @@ -228,9 +237,10 @@ fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut Event current_selection: None, // TODO Hack... can we just remove these? current_flags: ui.primary.current_flags.clone(), - }); + }; timer.stop("setup secondary"); - Mode::ABTest(mode) + + ABTestMode::new(ctx, ui, &test.test_name, secondary) }, ) } diff --git a/editor/src/game.rs b/editor/src/game.rs index 9392ba9dc1..167b5de280 100644 --- a/editor/src/game.rs +++ b/editor/src/game.rs @@ -1,4 +1,4 @@ -//use crate::abtest::ABTestMode; +use crate::abtest::setup::PickABTest; use crate::debug::DebugMode; use crate::edit::EditMode; //use crate::mission::MissionEditMode; @@ -280,10 +280,8 @@ fn splash_screen( x if x == edit => Some(Transition::Push(Box::new(EditMode::new(ctx, ui)))), //x if x == tutorial => break Some(Mode::Tutorial(TutorialMode::new(ctx, ui))), x if x == debug => Some(Transition::Push(Box::new(DebugMode::new(ctx, ui)))), - /*x if x == mission => break Some(Mode::Mission(MissionEditMode::new(ctx, ui))), - x if x == abtest => { - break Some(Mode::ABTest(ABTestMode::new(ctx, ui, "unnamed a/b test"))) - }*/ + //x if x == mission => break Some(Mode::Mission(MissionEditMode::new(ctx, ui))), + x if x == abtest => Some(Transition::Push(Box::new(PickABTest::new()))), x if x == about => { if wizard.acknowledge( "About A/B Street", diff --git a/editor/src/main.rs b/editor/src/main.rs index 6cd650e1c9..f65846c46c 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -1,4 +1,4 @@ -//mod abtest; +mod abtest; mod common; mod debug; mod edit;