mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
collapsing load/create scenario options directly into mission mode
This commit is contained in:
parent
a6aa46dd61
commit
a7b10b7ec5
@ -11,8 +11,11 @@ use crate::render::DrawOptions;
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::ShowEverything;
|
||||
use crate::ui::UI;
|
||||
use abstutil::Timer;
|
||||
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
|
||||
use geom::Duration;
|
||||
use map_model::Map;
|
||||
use sim::Scenario;
|
||||
|
||||
pub struct MissionEditMode {
|
||||
state: State,
|
||||
@ -21,7 +24,9 @@ pub struct MissionEditMode {
|
||||
enum State {
|
||||
Exploring(ModalMenu),
|
||||
Neighborhood(neighborhood::NeighborhoodEditor),
|
||||
Scenario(scenario::ScenarioEditor),
|
||||
LoadScenario(Wizard),
|
||||
CreateNewScenario(Wizard),
|
||||
EditScenario(scenario::ScenarioEditor),
|
||||
DataViz(dataviz::DataVisualizer),
|
||||
IndividualTrips(individ_trips::TripsVisualizer),
|
||||
AllTrips(all_trips::TripsVisualizer),
|
||||
@ -44,7 +49,8 @@ impl MissionEditMode {
|
||||
(hotkey(Key::S), "set up simulation with PSRC trips"),
|
||||
(hotkey(Key::Q), "create scenario from PSRC trips"),
|
||||
(hotkey(Key::N), "manage neighborhoods"),
|
||||
(hotkey(Key::W), "manage scenarios"),
|
||||
(hotkey(Key::W), "load scenario"),
|
||||
(None, "create new scenario"),
|
||||
],
|
||||
ctx,
|
||||
)),
|
||||
@ -98,10 +104,10 @@ impl MissionEditMode {
|
||||
mode.state = State::Neighborhood(
|
||||
neighborhood::NeighborhoodEditor::PickNeighborhood(Wizard::new()),
|
||||
);
|
||||
} else if menu.action("manage scenarios") {
|
||||
mode.state = State::Scenario(scenario::ScenarioEditor::PickScenario(
|
||||
Wizard::new(),
|
||||
));
|
||||
} else if menu.action("load scenario") {
|
||||
mode.state = State::LoadScenario(Wizard::new());
|
||||
} else if menu.action("create new scenario") {
|
||||
mode.state = State::CreateNewScenario(Wizard::new());
|
||||
}
|
||||
}
|
||||
State::DataViz(ref mut viz) => {
|
||||
@ -134,7 +140,35 @@ impl MissionEditMode {
|
||||
mode.state = MissionEditMode::new(ctx, &mut state.ui).state;
|
||||
}
|
||||
}
|
||||
State::Scenario(ref mut editor) => {
|
||||
State::LoadScenario(ref mut wizard) => {
|
||||
if let Some(scenario) =
|
||||
load_scenario(&state.ui.primary.map, &mut wizard.wrap(ctx))
|
||||
{
|
||||
mode.state =
|
||||
State::EditScenario(scenario::ScenarioEditor::new(scenario, ctx));
|
||||
} else if wizard.aborted() {
|
||||
mode.state = MissionEditMode::new(ctx, &mut state.ui).state;
|
||||
}
|
||||
}
|
||||
State::CreateNewScenario(ref mut wizard) => {
|
||||
let mut wrapped = wizard.wrap(ctx);
|
||||
if let Some(name) = wrapped.input_string("Name the scenario") {
|
||||
mode.state = State::EditScenario(scenario::ScenarioEditor::new(
|
||||
Scenario {
|
||||
scenario_name: name,
|
||||
map_name: state.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 wizard.aborted() {
|
||||
mode.state = MissionEditMode::new(ctx, &mut state.ui).state;
|
||||
}
|
||||
}
|
||||
State::EditScenario(ref mut editor) => {
|
||||
if let Some(new_mode) = editor.event(ctx, &mut state.ui) {
|
||||
state.mode = new_mode;
|
||||
}
|
||||
@ -174,9 +208,12 @@ impl MissionEditMode {
|
||||
State::Neighborhood(ref editor) => {
|
||||
editor.draw(g, &state.ui);
|
||||
}
|
||||
State::Scenario(ref editor) => {
|
||||
State::EditScenario(ref editor) => {
|
||||
editor.draw(g, &state.ui);
|
||||
}
|
||||
State::LoadScenario(ref wizard) | State::CreateNewScenario(ref wizard) => {
|
||||
wizard.draw(g);
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@ -186,3 +223,19 @@ impl MissionEditMode {
|
||||
pub fn input_time(wizard: &mut WrappedWizard, query: &str) -> Option<Duration> {
|
||||
wizard.input_something(query, None, Box::new(|line| Duration::parse(&line)))
|
||||
}
|
||||
|
||||
fn load_scenario(map: &Map, wizard: &mut WrappedWizard) -> Option<Scenario> {
|
||||
let map_name = map.get_name().to_string();
|
||||
wizard
|
||||
.choose_something_no_keys::<String>(
|
||||
"Load which scenario?",
|
||||
Box::new(move || abstutil::list_all_objects("scenarios", &map_name)),
|
||||
)
|
||||
.map(|(_, s)| {
|
||||
abstutil::read_binary(
|
||||
&format!("../data/scenarios/{}/{}.bin", map.get_name(), s),
|
||||
&mut Timer::throwaway(),
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
@ -2,47 +2,38 @@ use crate::game::Mode;
|
||||
use crate::mission::{input_time, MissionEditMode};
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::UI;
|
||||
use abstutil::{Timer, WeightedUsizeChoice};
|
||||
use abstutil::WeightedUsizeChoice;
|
||||
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};
|
||||
|
||||
pub enum ScenarioEditor {
|
||||
PickScenario(Wizard),
|
||||
ManageScenario(ModalMenu, Scenario, LogScroller),
|
||||
EditScenario(Scenario, Wizard),
|
||||
}
|
||||
|
||||
impl ScenarioEditor {
|
||||
fn modal_menu(name: &str, ctx: &EventCtx) -> ModalMenu {
|
||||
ModalMenu::new(
|
||||
&format!("Scenario Editor for {}", name),
|
||||
vec![
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::S), "save"),
|
||||
(hotkey(Key::E), "edit"),
|
||||
(hotkey(Key::I), "instantiate"),
|
||||
],
|
||||
ctx,
|
||||
pub fn new(scenario: Scenario, ctx: &mut EventCtx) -> ScenarioEditor {
|
||||
let scroller = LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
|
||||
ScenarioEditor::ManageScenario(
|
||||
ModalMenu::new(
|
||||
&format!("Scenario Editor for {}", scenario.scenario_name),
|
||||
vec![
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::S), "save"),
|
||||
(hotkey(Key::E), "edit"),
|
||||
(hotkey(Key::I), "instantiate"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
scenario,
|
||||
scroller,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<Mode> {
|
||||
match self {
|
||||
ScenarioEditor::PickScenario(ref mut wizard) => {
|
||||
if let Some(scenario) = pick_scenario(&ui.primary.map, wizard.wrap(ctx)) {
|
||||
let scroller =
|
||||
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
|
||||
*self = ScenarioEditor::ManageScenario(
|
||||
ScenarioEditor::modal_menu(&scenario.scenario_name, ctx),
|
||||
scenario,
|
||||
scroller,
|
||||
);
|
||||
} else if wizard.aborted() {
|
||||
return Some(Mode::Mission(MissionEditMode::new(ctx, ui)));
|
||||
}
|
||||
}
|
||||
ScenarioEditor::ManageScenario(ref mut menu, scenario, ref mut scroller) => {
|
||||
menu.handle_event(ctx, None);
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
@ -67,22 +58,10 @@ impl ScenarioEditor {
|
||||
}
|
||||
ScenarioEditor::EditScenario(ref mut scenario, ref mut wizard) => {
|
||||
if let Some(()) = edit_scenario(&ui.primary.map, scenario, wizard.wrap(ctx)) {
|
||||
let scroller =
|
||||
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
|
||||
// TODO autosave, or at least make it clear there are unsaved edits
|
||||
*self = ScenarioEditor::ManageScenario(
|
||||
ScenarioEditor::modal_menu(&scenario.scenario_name, ctx),
|
||||
scenario.clone(),
|
||||
scroller,
|
||||
);
|
||||
*self = ScenarioEditor::new(scenario.clone(), ctx);
|
||||
} else if wizard.aborted() {
|
||||
let scroller =
|
||||
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
|
||||
*self = ScenarioEditor::ManageScenario(
|
||||
ScenarioEditor::modal_menu(&scenario.scenario_name, ctx),
|
||||
scenario.clone(),
|
||||
scroller,
|
||||
);
|
||||
*self = ScenarioEditor::new(scenario.clone(), ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,9 +70,6 @@ impl ScenarioEditor {
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
match self {
|
||||
ScenarioEditor::PickScenario(wizard) => {
|
||||
wizard.draw(g);
|
||||
}
|
||||
ScenarioEditor::ManageScenario(ref menu, _, scroller) => {
|
||||
scroller.draw(g);
|
||||
menu.draw(g);
|
||||
@ -108,26 +84,6 @@ impl ScenarioEditor {
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_scenario(map: &Map, mut wizard: WrappedWizard) -> Option<Scenario> {
|
||||
let load_existing = "Load existing scenario";
|
||||
let create_new = "Create new scenario";
|
||||
if wizard.choose_string("What scenario to edit?", vec![load_existing, create_new])?
|
||||
== load_existing
|
||||
{
|
||||
load_scenario(map, &mut wizard, "Load which scenario?")
|
||||
} else {
|
||||
let scenario_name = wizard.input_string("Name the scenario")?;
|
||||
Some(Scenario {
|
||||
scenario_name,
|
||||
map_name: 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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_scenario(map: &Map, scenario: &mut Scenario, mut wizard: WrappedWizard) -> Option<()> {
|
||||
let seed_parked = "Seed parked cars";
|
||||
let spawn = "Spawn agents";
|
||||
@ -224,22 +180,6 @@ fn choose_neighborhood(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Op
|
||||
.map(|(n, _)| n)
|
||||
}
|
||||
|
||||
fn load_scenario(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<Scenario> {
|
||||
let map_name = map.get_name().to_string();
|
||||
wizard
|
||||
.choose_something_no_keys::<String>(
|
||||
query,
|
||||
Box::new(move || abstutil::list_all_objects("scenarios", &map_name)),
|
||||
)
|
||||
.map(|(_, s)| {
|
||||
abstutil::read_binary(
|
||||
&format!("../data/scenarios/{}/{}.bin", map.get_name(), s),
|
||||
&mut Timer::throwaway(),
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
fn input_weighted_usize(wizard: &mut WrappedWizard, query: &str) -> Option<WeightedUsizeChoice> {
|
||||
wizard.input_something(
|
||||
query,
|
||||
|
Loading…
Reference in New Issue
Block a user