mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 12:12:00 +03:00
convert more to NewModalMenu
This commit is contained in:
parent
d10cbd9b7c
commit
36df2e7908
@ -17,7 +17,7 @@ use map_model::{
|
|||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
|
|
||||||
pub enum EditMode {
|
pub enum EditMode {
|
||||||
ViewingDiffs(CommonState),
|
ViewingDiffs(CommonState, NewModalMenu),
|
||||||
Saving(Wizard),
|
Saving(Wizard),
|
||||||
Loading(Wizard),
|
Loading(Wizard),
|
||||||
EditingStopSign(IntersectionID, NewModalMenu),
|
EditingStopSign(IntersectionID, NewModalMenu),
|
||||||
@ -25,37 +25,39 @@ pub enum EditMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EditMode {
|
impl EditMode {
|
||||||
pub fn new() -> EditMode {
|
pub fn new(ctx: &EventCtx) -> EditMode {
|
||||||
EditMode::ViewingDiffs(CommonState::new())
|
EditMode::ViewingDiffs(
|
||||||
|
CommonState::new(),
|
||||||
|
NewModalMenu::new(
|
||||||
|
"Map Edit Mode",
|
||||||
|
vec![
|
||||||
|
(Key::Escape, "quit"),
|
||||||
|
(Key::S, "save edits"),
|
||||||
|
(Key::L, "load different edits"),
|
||||||
|
],
|
||||||
|
ctx,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
|
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
|
||||||
ctx.canvas.handle_event(ctx.input);
|
match state.mode {
|
||||||
|
Mode::Edit(EditMode::ViewingDiffs(ref mut common, ref mut menu)) => {
|
||||||
// Common functionality
|
|
||||||
let mut txt = Text::prompt("Map Edit Mode");
|
let mut txt = Text::prompt("Map Edit Mode");
|
||||||
|
// TODO Display info/hints on more lines.
|
||||||
txt.add_line(state.ui.primary.map.get_edits().edits_name.clone());
|
txt.add_line(state.ui.primary.map.get_edits().edits_name.clone());
|
||||||
txt.add_line(state.ui.primary.map.get_edits().describe());
|
txt.add_line(state.ui.primary.map.get_edits().describe());
|
||||||
txt.add_line("Right-click a lane or intersection to start editing".to_string());
|
txt.add_line("Right-click a lane or intersection to start editing".to_string());
|
||||||
match state.mode {
|
menu.update_prompt(txt, ctx);
|
||||||
Mode::Edit(EditMode::ViewingDiffs(_))
|
menu.handle_event(ctx);
|
||||||
| Mode::Edit(EditMode::Saving(_))
|
if menu.action("quit") {
|
||||||
| Mode::Edit(EditMode::Loading(_)) => {
|
|
||||||
// TODO Display info/hints on more lines.
|
|
||||||
ctx.input
|
|
||||||
.set_mode_with_new_prompt("Map Edit Mode", txt, ctx.canvas);
|
|
||||||
// TODO Clicking this works, but the key doesn't
|
|
||||||
if ctx.input.modal_action("quit") {
|
|
||||||
// TODO Warn about unsaved edits
|
// TODO Warn about unsaved edits
|
||||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||||
return EventLoopMode::InputOnly;
|
return EventLoopMode::InputOnly;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match state.mode {
|
ctx.canvas.handle_event(ctx.input);
|
||||||
Mode::Edit(EditMode::ViewingDiffs(ref mut common)) => {
|
|
||||||
// TODO Reset when transitioning in/out of this state? Or maybe we just don't draw
|
// TODO Reset when transitioning in/out of this state? Or maybe we just don't draw
|
||||||
// the effects of it. Or eventually, the Option<ID> itself will live in here
|
// the effects of it. Or eventually, the Option<ID> itself will live in here
|
||||||
// directly.
|
// directly.
|
||||||
@ -72,10 +74,10 @@ impl EditMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Only if current edits are unsaved
|
// TODO Only if current edits are unsaved
|
||||||
if ctx.input.modal_action("save edits") {
|
if menu.action("save edits") {
|
||||||
state.mode = Mode::Edit(EditMode::Saving(Wizard::new()));
|
state.mode = Mode::Edit(EditMode::Saving(Wizard::new()));
|
||||||
return EventLoopMode::InputOnly;
|
return EventLoopMode::InputOnly;
|
||||||
} else if ctx.input.modal_action("load different edits") {
|
} else if menu.action("load different edits") {
|
||||||
state.mode = Mode::Edit(EditMode::Loading(Wizard::new()));
|
state.mode = Mode::Edit(EditMode::Loading(Wizard::new()));
|
||||||
return EventLoopMode::InputOnly;
|
return EventLoopMode::InputOnly;
|
||||||
}
|
}
|
||||||
@ -131,7 +133,7 @@ impl EditMode {
|
|||||||
.is_some()
|
.is_some()
|
||||||
|| wizard.aborted()
|
|| wizard.aborted()
|
||||||
{
|
{
|
||||||
state.mode = Mode::Edit(EditMode::new());
|
state.mode = Mode::Edit(EditMode::new(ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::Edit(EditMode::Loading(ref mut wizard)) => {
|
Mode::Edit(EditMode::Loading(ref mut wizard)) => {
|
||||||
@ -141,13 +143,14 @@ impl EditMode {
|
|||||||
"Load which map edits?",
|
"Load which map edits?",
|
||||||
) {
|
) {
|
||||||
apply_map_edits(&mut state.ui, ctx, new_edits);
|
apply_map_edits(&mut state.ui, ctx, new_edits);
|
||||||
state.mode = Mode::Edit(EditMode::new());
|
state.mode = Mode::Edit(EditMode::new(ctx));
|
||||||
} else if wizard.aborted() {
|
} else if wizard.aborted() {
|
||||||
state.mode = Mode::Edit(EditMode::new());
|
state.mode = Mode::Edit(EditMode::new(ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::Edit(EditMode::EditingStopSign(i, ref mut menu)) => {
|
Mode::Edit(EditMode::EditingStopSign(i, ref mut menu)) => {
|
||||||
menu.handle_event(ctx);
|
menu.handle_event(ctx);
|
||||||
|
ctx.canvas.handle_event(ctx.input);
|
||||||
|
|
||||||
state.ui.primary.current_selection = state.ui.handle_mouseover(
|
state.ui.primary.current_selection = state.ui.handle_mouseover(
|
||||||
ctx,
|
ctx,
|
||||||
@ -181,7 +184,7 @@ impl EditMode {
|
|||||||
apply_map_edits(&mut state.ui, ctx, new_edits);
|
apply_map_edits(&mut state.ui, ctx, new_edits);
|
||||||
}
|
}
|
||||||
} else if menu.action("quit") {
|
} else if menu.action("quit") {
|
||||||
state.mode = Mode::Edit(EditMode::new());
|
state.mode = Mode::Edit(EditMode::new(ctx));
|
||||||
} else if menu.action("reset to default") {
|
} else if menu.action("reset to default") {
|
||||||
let mut new_edits = state.ui.primary.map.get_edits().clone();
|
let mut new_edits = state.ui.primary.map.get_edits().clone();
|
||||||
new_edits.stop_sign_overrides.remove(&i);
|
new_edits.stop_sign_overrides.remove(&i);
|
||||||
@ -190,7 +193,7 @@ impl EditMode {
|
|||||||
}
|
}
|
||||||
Mode::Edit(EditMode::EditingTrafficSignal(ref mut editor)) => {
|
Mode::Edit(EditMode::EditingTrafficSignal(ref mut editor)) => {
|
||||||
if editor.event(ctx, &mut state.ui) {
|
if editor.event(ctx, &mut state.ui) {
|
||||||
state.mode = Mode::Edit(EditMode::new());
|
state.mode = Mode::Edit(EditMode::new(ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -201,7 +204,7 @@ impl EditMode {
|
|||||||
|
|
||||||
pub fn draw(state: &GameState, g: &mut GfxCtx) {
|
pub fn draw(state: &GameState, g: &mut GfxCtx) {
|
||||||
match state.mode {
|
match state.mode {
|
||||||
Mode::Edit(EditMode::ViewingDiffs(ref common)) => {
|
Mode::Edit(EditMode::ViewingDiffs(ref common, ref menu)) => {
|
||||||
state.ui.draw(
|
state.ui.draw(
|
||||||
g,
|
g,
|
||||||
common.draw_options(&state.ui),
|
common.draw_options(&state.ui),
|
||||||
@ -209,6 +212,7 @@ impl EditMode {
|
|||||||
&ShowEverything::new(),
|
&ShowEverything::new(),
|
||||||
);
|
);
|
||||||
common.draw(g, &state.ui);
|
common.draw(g, &state.ui);
|
||||||
|
menu.draw(g);
|
||||||
|
|
||||||
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
|
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
|
||||||
// supply a set of things to highlight and have something else take care of drawing
|
// supply a set of things to highlight and have something else take care of drawing
|
||||||
|
@ -56,6 +56,7 @@ impl TrafficSignalEditor {
|
|||||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
|
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
|
||||||
self.menu.handle_event(ctx);
|
self.menu.handle_event(ctx);
|
||||||
self.diagram_top_left = self.menu.get_bottom_left(ctx);
|
self.diagram_top_left = self.menu.get_bottom_left(ctx);
|
||||||
|
ctx.canvas.handle_event(ctx.input);
|
||||||
|
|
||||||
ui.primary.current_selection = ui.handle_mouseover(
|
ui.primary.current_selection = ui.handle_mouseover(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -40,7 +40,7 @@ impl GameState {
|
|||||||
let splash = !flags.no_splash;
|
let splash = !flags.no_splash;
|
||||||
let mut rng = flags.sim_flags.make_rng();
|
let mut rng = flags.sim_flags.make_rng();
|
||||||
let mut game = GameState {
|
let mut game = GameState {
|
||||||
mode: Mode::Sandbox(SandboxMode::new()),
|
mode: Mode::Sandbox(SandboxMode::new(canvas)),
|
||||||
ui: UI::new(flags, prerender, canvas),
|
ui: UI::new(flags, prerender, canvas),
|
||||||
};
|
};
|
||||||
if splash {
|
if splash {
|
||||||
@ -71,45 +71,6 @@ impl GameState {
|
|||||||
impl GUI for GameState {
|
impl GUI for GameState {
|
||||||
fn modal_menus(&self) -> Vec<ModalMenu> {
|
fn modal_menus(&self) -> Vec<ModalMenu> {
|
||||||
vec![
|
vec![
|
||||||
ModalMenu::new(
|
|
||||||
"Map Edit Mode",
|
|
||||||
vec![
|
|
||||||
(Key::Escape, "quit"),
|
|
||||||
(Key::S, "save edits"),
|
|
||||||
(Key::L, "load different edits"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
ModalMenu::new(
|
|
||||||
"Sandbox Mode",
|
|
||||||
vec![
|
|
||||||
(Key::Escape, "quit"),
|
|
||||||
(Key::LeftBracket, "slow down sim"),
|
|
||||||
(Key::RightBracket, "speed up sim"),
|
|
||||||
(Key::O, "save sim state"),
|
|
||||||
(Key::Y, "load previous sim state"),
|
|
||||||
(Key::U, "load next sim state"),
|
|
||||||
(Key::Space, "run/pause sim"),
|
|
||||||
(Key::M, "run one step of sim"),
|
|
||||||
(Key::X, "reset sim"),
|
|
||||||
(Key::S, "seed the sim with agents"),
|
|
||||||
// TODO Strange to always have this. Really it's a case of stacked modal?
|
|
||||||
(Key::F, "stop following agent"),
|
|
||||||
(Key::R, "stop showing agent's route"),
|
|
||||||
// TODO This should probably be a debug thing instead
|
|
||||||
(Key::L, "show/hide route for all agents"),
|
|
||||||
(Key::A, "show/hide active traffic"),
|
|
||||||
(Key::T, "start time traveling"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
ModalMenu::new("Agent Spawner", vec![(Key::Escape, "quit")]),
|
|
||||||
ModalMenu::new(
|
|
||||||
"Time Traveler",
|
|
||||||
vec![
|
|
||||||
(Key::Escape, "quit"),
|
|
||||||
(Key::Comma, "rewind"),
|
|
||||||
(Key::Dot, "forwards"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
ModalMenu::new(
|
ModalMenu::new(
|
||||||
"Debug Mode",
|
"Debug Mode",
|
||||||
vec![
|
vec![
|
||||||
@ -345,7 +306,7 @@ fn splash_screen(
|
|||||||
)?
|
)?
|
||||||
.as_str()
|
.as_str()
|
||||||
{
|
{
|
||||||
x if x == sandbox => break Some(Mode::Sandbox(SandboxMode::new())),
|
x if x == sandbox => break Some(Mode::Sandbox(SandboxMode::new(ctx.canvas))),
|
||||||
x if x == load_map => {
|
x if x == load_map => {
|
||||||
let current_map = ui.primary.map.get_name().to_string();
|
let current_map = ui.primary.map.get_name().to_string();
|
||||||
if let Some((name, _)) = wizard.choose_something_no_keys::<String>(
|
if let Some((name, _)) = wizard.choose_something_no_keys::<String>(
|
||||||
@ -361,14 +322,14 @@ fn splash_screen(
|
|||||||
let mut flags = ui.primary.current_flags.clone();
|
let mut flags = ui.primary.current_flags.clone();
|
||||||
flags.sim_flags.load = PathBuf::from(format!("../data/maps/{}.abst", name));
|
flags.sim_flags.load = PathBuf::from(format!("../data/maps/{}.abst", name));
|
||||||
*ui = UI::new(flags, ctx.prerender, ctx.canvas);
|
*ui = UI::new(flags, ctx.prerender, ctx.canvas);
|
||||||
break Some(Mode::Sandbox(SandboxMode::new()));
|
break Some(Mode::Sandbox(SandboxMode::new(ctx.canvas)));
|
||||||
} else if wizard.aborted() {
|
} else if wizard.aborted() {
|
||||||
break Some(Mode::SplashScreen(Wizard::new(), maybe_screensaver.take()));
|
break Some(Mode::SplashScreen(Wizard::new(), maybe_screensaver.take()));
|
||||||
} else {
|
} else {
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x if x == edit => break Some(Mode::Edit(EditMode::new())),
|
x if x == edit => break Some(Mode::Edit(EditMode::new(ctx))),
|
||||||
x if x == tutorial => {
|
x if x == tutorial => {
|
||||||
break Some(Mode::Tutorial(TutorialMode::Part1(
|
break Some(Mode::Tutorial(TutorialMode::Part1(
|
||||||
ctx.canvas.center_to_map_pt(),
|
ctx.canvas.center_to_map_pt(),
|
||||||
|
@ -48,7 +48,7 @@ impl ScenarioEditor {
|
|||||||
&mut ui.primary.current_flags.sim_flags.make_rng(),
|
&mut ui.primary.current_flags.sim_flags.make_rng(),
|
||||||
&mut Timer::new("instantiate scenario"),
|
&mut Timer::new("instantiate scenario"),
|
||||||
);
|
);
|
||||||
return Some(Mode::Sandbox(SandboxMode::new()));
|
return Some(Mode::Sandbox(SandboxMode::new(ctx.canvas)));
|
||||||
} else if ctx.input.modal_action("visualize") {
|
} else if ctx.input.modal_action("visualize") {
|
||||||
let neighborhoods = Neighborhood::load_all(
|
let neighborhoods = Neighborhood::load_all(
|
||||||
ui.primary.map.get_name(),
|
ui.primary.map.get_name(),
|
||||||
|
@ -8,7 +8,7 @@ use crate::game::{GameState, Mode};
|
|||||||
use crate::render::DrawOptions;
|
use crate::render::DrawOptions;
|
||||||
use crate::ui::ShowEverything;
|
use crate::ui::ShowEverything;
|
||||||
use abstutil::elapsed_seconds;
|
use abstutil::elapsed_seconds;
|
||||||
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, Text, Wizard};
|
use ezgui::{Canvas, EventCtx, EventLoopMode, GfxCtx, Key, NewModalMenu, Text, Wizard};
|
||||||
use geom::Duration;
|
use geom::Duration;
|
||||||
use sim::{Benchmark, Sim, TripID};
|
use sim::{Benchmark, Sim, TripID};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
@ -24,6 +24,7 @@ pub struct SandboxMode {
|
|||||||
state: State,
|
state: State,
|
||||||
// TODO Not while Spawning or TimeTraveling...
|
// TODO Not while Spawning or TimeTraveling...
|
||||||
common: CommonState,
|
common: CommonState,
|
||||||
|
menu: NewModalMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
@ -38,33 +39,44 @@ enum State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SandboxMode {
|
impl SandboxMode {
|
||||||
pub fn new() -> SandboxMode {
|
pub fn new(canvas: &Canvas) -> SandboxMode {
|
||||||
SandboxMode {
|
SandboxMode {
|
||||||
desired_speed: 1.0,
|
desired_speed: 1.0,
|
||||||
state: State::Paused,
|
state: State::Paused,
|
||||||
following: None,
|
following: None,
|
||||||
route_viewer: route_viewer::RouteViewer::Inactive,
|
route_viewer: route_viewer::RouteViewer::Inactive,
|
||||||
show_activity: show_activity::ShowActivity::Inactive,
|
show_activity: show_activity::ShowActivity::Inactive,
|
||||||
time_travel: time_travel::TimeTravel::new(),
|
time_travel: time_travel::TimeTravel::new(canvas),
|
||||||
common: CommonState::new(),
|
common: CommonState::new(),
|
||||||
|
menu: NewModalMenu::hacky_new(
|
||||||
|
"Sandbox Mode",
|
||||||
|
vec![
|
||||||
|
(Key::Escape, "quit"),
|
||||||
|
(Key::LeftBracket, "slow down sim"),
|
||||||
|
(Key::RightBracket, "speed up sim"),
|
||||||
|
(Key::O, "save sim state"),
|
||||||
|
(Key::Y, "load previous sim state"),
|
||||||
|
(Key::U, "load next sim state"),
|
||||||
|
(Key::Space, "run/pause sim"),
|
||||||
|
(Key::M, "run one step of sim"),
|
||||||
|
(Key::X, "reset sim"),
|
||||||
|
(Key::S, "seed the sim with agents"),
|
||||||
|
// TODO Strange to always have this. Really it's a case of stacked modal?
|
||||||
|
(Key::F, "stop following agent"),
|
||||||
|
(Key::R, "stop showing agent's route"),
|
||||||
|
// TODO This should probably be a debug thing instead
|
||||||
|
(Key::L, "show/hide route for all agents"),
|
||||||
|
(Key::A, "show/hide active traffic"),
|
||||||
|
(Key::T, "start time traveling"),
|
||||||
|
],
|
||||||
|
canvas,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
|
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
|
||||||
match state.mode {
|
match state.mode {
|
||||||
Mode::Sandbox(ref mut mode) => {
|
Mode::Sandbox(ref mut mode) => {
|
||||||
ctx.canvas.handle_event(ctx.input);
|
|
||||||
state.ui.primary.current_selection = state.ui.handle_mouseover(
|
|
||||||
ctx,
|
|
||||||
None,
|
|
||||||
&state.ui.primary.sim,
|
|
||||||
&ShowEverything::new(),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
if let Some(evmode) = mode.common.event(ctx, &state.ui) {
|
|
||||||
return evmode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let State::Spawning(ref mut spawner) = mode.state {
|
if let State::Spawning(ref mut spawner) = mode.state {
|
||||||
if spawner.event(ctx, &mut state.ui) {
|
if spawner.event(ctx, &mut state.ui) {
|
||||||
mode.state = State::Paused;
|
mode.state = State::Paused;
|
||||||
@ -110,10 +122,24 @@ impl SandboxMode {
|
|||||||
txt.add_line("Showing active traffic".to_string());
|
txt.add_line("Showing active traffic".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.input
|
mode.menu.update_prompt(txt, ctx);
|
||||||
.set_mode_with_new_prompt("Sandbox Mode", txt, ctx.canvas);
|
mode.menu.handle_event(ctx);
|
||||||
|
|
||||||
if let Some(spawner) = spawner::AgentSpawner::new(ctx, &mut state.ui) {
|
ctx.canvas.handle_event(ctx.input);
|
||||||
|
state.ui.primary.current_selection = state.ui.handle_mouseover(
|
||||||
|
ctx,
|
||||||
|
None,
|
||||||
|
&state.ui.primary.sim,
|
||||||
|
&ShowEverything::new(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
if let Some(evmode) = mode.common.event(ctx, &state.ui) {
|
||||||
|
return evmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(spawner) =
|
||||||
|
spawner::AgentSpawner::new(ctx, &mut state.ui, &mut mode.menu)
|
||||||
|
{
|
||||||
mode.state = State::Spawning(spawner);
|
mode.state = State::Spawning(spawner);
|
||||||
return EventLoopMode::InputOnly;
|
return EventLoopMode::InputOnly;
|
||||||
}
|
}
|
||||||
@ -148,13 +174,13 @@ impl SandboxMode {
|
|||||||
// get_canonical_point_for_trip
|
// get_canonical_point_for_trip
|
||||||
println!("{} is gone... temporarily or not?", trip);
|
println!("{} is gone... temporarily or not?", trip);
|
||||||
}
|
}
|
||||||
if ctx.input.modal_action("stop following agent") {
|
if mode.menu.action("stop following agent") {
|
||||||
mode.following = None;
|
mode.following = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mode.route_viewer.event(ctx, &mut state.ui);
|
mode.route_viewer.event(ctx, &mut state.ui, &mut mode.menu);
|
||||||
mode.show_activity.event(ctx, &mut state.ui);
|
mode.show_activity.event(ctx, &mut state.ui, &mut mode.menu);
|
||||||
if ctx.input.modal_action("start time traveling") {
|
if mode.menu.action("start time traveling") {
|
||||||
mode.state = State::TimeTraveling;
|
mode.state = State::TimeTraveling;
|
||||||
mode.time_travel.start(state.ui.primary.sim.time());
|
mode.time_travel.start(state.ui.primary.sim.time());
|
||||||
// Do this again, in case recording was previously disabled.
|
// Do this again, in case recording was previously disabled.
|
||||||
@ -162,7 +188,7 @@ impl SandboxMode {
|
|||||||
return EventLoopMode::InputOnly;
|
return EventLoopMode::InputOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.input.modal_action("quit") {
|
if mode.menu.action("quit") {
|
||||||
// TODO This shouldn't be necessary when we plumb state around instead of
|
// TODO This shouldn't be necessary when we plumb state around instead of
|
||||||
// sharing it in the old structure.
|
// sharing it in the old structure.
|
||||||
state.ui.primary.sim = Sim::new(
|
state.ui.primary.sim = Sim::new(
|
||||||
@ -174,14 +200,14 @@ impl SandboxMode {
|
|||||||
return EventLoopMode::InputOnly;
|
return EventLoopMode::InputOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.input.modal_action("slow down sim") {
|
if mode.menu.action("slow down sim") {
|
||||||
mode.desired_speed -= ADJUST_SPEED;
|
mode.desired_speed -= ADJUST_SPEED;
|
||||||
mode.desired_speed = mode.desired_speed.max(0.0);
|
mode.desired_speed = mode.desired_speed.max(0.0);
|
||||||
}
|
}
|
||||||
if ctx.input.modal_action("speed up sim") {
|
if mode.menu.action("speed up sim") {
|
||||||
mode.desired_speed += ADJUST_SPEED;
|
mode.desired_speed += ADJUST_SPEED;
|
||||||
}
|
}
|
||||||
if !state.ui.primary.sim.is_empty() && ctx.input.modal_action("reset sim") {
|
if !state.ui.primary.sim.is_empty() && mode.menu.action("reset sim") {
|
||||||
// TODO savestate_every gets lost
|
// TODO savestate_every gets lost
|
||||||
state.ui.primary.sim = Sim::new(
|
state.ui.primary.sim = Sim::new(
|
||||||
&state.ui.primary.map,
|
&state.ui.primary.map,
|
||||||
@ -193,10 +219,10 @@ impl SandboxMode {
|
|||||||
|
|
||||||
match mode.state {
|
match mode.state {
|
||||||
State::Paused => {
|
State::Paused => {
|
||||||
if ctx.input.modal_action("save sim state") {
|
if mode.menu.action("save sim state") {
|
||||||
state.ui.primary.sim.save();
|
state.ui.primary.sim.save();
|
||||||
}
|
}
|
||||||
if ctx.input.modal_action("load previous sim state") {
|
if mode.menu.action("load previous sim state") {
|
||||||
let prev_state = state
|
let prev_state = state
|
||||||
.ui
|
.ui
|
||||||
.primary
|
.primary
|
||||||
@ -215,7 +241,7 @@ impl SandboxMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ctx.input.modal_action("load next sim state") {
|
if mode.menu.action("load next sim state") {
|
||||||
let next_state = state
|
let next_state = state
|
||||||
.ui
|
.ui
|
||||||
.primary
|
.primary
|
||||||
@ -233,13 +259,13 @@ impl SandboxMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.input.modal_action("run/pause sim") {
|
if mode.menu.action("run/pause sim") {
|
||||||
mode.state = State::Running {
|
mode.state = State::Running {
|
||||||
last_step: Instant::now(),
|
last_step: Instant::now(),
|
||||||
benchmark: state.ui.primary.sim.start_benchmark(),
|
benchmark: state.ui.primary.sim.start_benchmark(),
|
||||||
speed: "...".to_string(),
|
speed: "...".to_string(),
|
||||||
};
|
};
|
||||||
} else if ctx.input.modal_action("run one step of sim") {
|
} else if mode.menu.action("run one step of sim") {
|
||||||
state.ui.primary.sim.step(&state.ui.primary.map);
|
state.ui.primary.sim.step(&state.ui.primary.map);
|
||||||
//*ctx.recalculate_current_selection = true;
|
//*ctx.recalculate_current_selection = true;
|
||||||
}
|
}
|
||||||
@ -250,7 +276,7 @@ impl SandboxMode {
|
|||||||
ref mut benchmark,
|
ref mut benchmark,
|
||||||
ref mut speed,
|
ref mut speed,
|
||||||
} => {
|
} => {
|
||||||
if ctx.input.modal_action("run/pause sim") {
|
if mode.menu.action("run/pause sim") {
|
||||||
mode.state = State::Paused;
|
mode.state = State::Paused;
|
||||||
} else if ctx.input.nonblocking_is_update_event() {
|
} else if ctx.input.nonblocking_is_update_event() {
|
||||||
// TODO https://gafferongames.com/post/fix_your_timestep/
|
// TODO https://gafferongames.com/post/fix_your_timestep/
|
||||||
@ -293,6 +319,7 @@ impl SandboxMode {
|
|||||||
&mode.time_travel,
|
&mode.time_travel,
|
||||||
&ShowEverything::new(),
|
&ShowEverything::new(),
|
||||||
);
|
);
|
||||||
|
mode.time_travel.draw(g);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
state.ui.draw(
|
state.ui.draw(
|
||||||
@ -302,6 +329,7 @@ impl SandboxMode {
|
|||||||
&ShowEverything::new(),
|
&ShowEverything::new(),
|
||||||
);
|
);
|
||||||
mode.common.draw(g, &state.ui);
|
mode.common.draw(g, &state.ui);
|
||||||
|
mode.menu.draw(g);
|
||||||
mode.route_viewer.draw(g, &state.ui);
|
mode.route_viewer.draw(g, &state.ui);
|
||||||
mode.show_activity.draw(g, &state.ui);
|
mode.show_activity.draw(g, &state.ui);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::helpers::ID;
|
use crate::helpers::ID;
|
||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use ezgui::{Color, EventCtx, GfxCtx, Key};
|
use ezgui::{Color, EventCtx, GfxCtx, Key, NewModalMenu};
|
||||||
use geom::{Duration, PolyLine};
|
use geom::{Duration, PolyLine};
|
||||||
use map_model::LANE_THICKNESS;
|
use map_model::LANE_THICKNESS;
|
||||||
use sim::{AgentID, TripID};
|
use sim::{AgentID, TripID};
|
||||||
@ -13,14 +13,14 @@ pub enum RouteViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RouteViewer {
|
impl RouteViewer {
|
||||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) {
|
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI, menu: &mut NewModalMenu) {
|
||||||
match self {
|
match self {
|
||||||
RouteViewer::Inactive => {
|
RouteViewer::Inactive => {
|
||||||
if let Some(agent) = ui.primary.current_selection.and_then(|id| id.agent_id()) {
|
if let Some(agent) = ui.primary.current_selection.and_then(|id| id.agent_id()) {
|
||||||
if let Some(trace) = ui.primary.sim.trace_route(agent, &ui.primary.map, None) {
|
if let Some(trace) = ui.primary.sim.trace_route(agent, &ui.primary.map, None) {
|
||||||
*self = RouteViewer::Hovering(ui.primary.sim.time(), agent, trace);
|
*self = RouteViewer::Hovering(ui.primary.sim.time(), agent, trace);
|
||||||
}
|
}
|
||||||
} else if ctx.input.modal_action("show/hide route for all agents") {
|
} else if menu.action("show/hide route for all agents") {
|
||||||
*self = debug_all_routes(ui);
|
*self = debug_all_routes(ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,14 +56,14 @@ impl RouteViewer {
|
|||||||
}
|
}
|
||||||
RouteViewer::Active(time, trip, _) => {
|
RouteViewer::Active(time, trip, _) => {
|
||||||
// TODO Using the modal menu from parent is weird...
|
// TODO Using the modal menu from parent is weird...
|
||||||
if ctx.input.modal_action("stop showing agent's route") {
|
if menu.action("stop showing agent's route") {
|
||||||
*self = RouteViewer::Inactive;
|
*self = RouteViewer::Inactive;
|
||||||
} else if *time != ui.primary.sim.time() {
|
} else if *time != ui.primary.sim.time() {
|
||||||
*self = show_route(*trip, ui);
|
*self = show_route(*trip, ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RouteViewer::DebugAllRoutes(time, _) => {
|
RouteViewer::DebugAllRoutes(time, _) => {
|
||||||
if ctx.input.modal_action("show/hide route for all agents") {
|
if menu.action("show/hide route for all agents") {
|
||||||
*self = RouteViewer::Inactive;
|
*self = RouteViewer::Inactive;
|
||||||
} else if *time != ui.primary.sim.time() {
|
} else if *time != ui.primary.sim.time() {
|
||||||
*self = debug_all_routes(ui);
|
*self = debug_all_routes(ui);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::render::MIN_ZOOM_FOR_DETAIL;
|
use crate::render::MIN_ZOOM_FOR_DETAIL;
|
||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use ezgui::{Color, EventCtx, GfxCtx};
|
use ezgui::{Color, EventCtx, GfxCtx, NewModalMenu};
|
||||||
use geom::{Bounds, Duration, Polygon, Pt2D};
|
use geom::{Bounds, Duration, Polygon, Pt2D};
|
||||||
use map_model::{RoadID, Traversable};
|
use map_model::{RoadID, Traversable};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -12,18 +12,18 @@ pub enum ShowActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ShowActivity {
|
impl ShowActivity {
|
||||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) {
|
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI, menu: &mut NewModalMenu) {
|
||||||
let zoomed = ctx.canvas.cam_zoom >= MIN_ZOOM_FOR_DETAIL;
|
let zoomed = ctx.canvas.cam_zoom >= MIN_ZOOM_FOR_DETAIL;
|
||||||
|
|
||||||
// If we survive past this, recompute current state.
|
// If we survive past this, recompute current state.
|
||||||
match self {
|
match self {
|
||||||
ShowActivity::Inactive => {
|
ShowActivity::Inactive => {
|
||||||
if !ctx.input.modal_action("show/hide active traffic") {
|
if !menu.action("show/hide active traffic") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ShowActivity::Zoomed(time, ref heatmap) => {
|
ShowActivity::Zoomed(time, ref heatmap) => {
|
||||||
if ctx.input.modal_action("show/hide active traffic") {
|
if menu.action("show/hide active traffic") {
|
||||||
*self = ShowActivity::Inactive;
|
*self = ShowActivity::Inactive;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ impl ShowActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ShowActivity::Unzoomed(time, _) => {
|
ShowActivity::Unzoomed(time, _) => {
|
||||||
if ctx.input.modal_action("show/hide active traffic") {
|
if menu.action("show/hide active traffic") {
|
||||||
*self = ShowActivity::Inactive;
|
*self = ShowActivity::Inactive;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::helpers::ID;
|
|||||||
use crate::render::DrawOptions;
|
use crate::render::DrawOptions;
|
||||||
use crate::ui::{ShowEverything, UI};
|
use crate::ui::{ShowEverything, UI};
|
||||||
use abstutil::Timer;
|
use abstutil::Timer;
|
||||||
use ezgui::{EventCtx, GfxCtx, Key};
|
use ezgui::{EventCtx, GfxCtx, Key, NewModalMenu};
|
||||||
use geom::PolyLine;
|
use geom::PolyLine;
|
||||||
use map_model::{
|
use map_model::{
|
||||||
BuildingID, IntersectionID, IntersectionType, LaneType, PathRequest, Position, LANE_THICKNESS,
|
BuildingID, IntersectionID, IntersectionType, LaneType, PathRequest, Position, LANE_THICKNESS,
|
||||||
@ -11,6 +11,7 @@ use rand::seq::SliceRandom;
|
|||||||
use sim::{DrivingGoal, Scenario, SidewalkSpot, TripSpec};
|
use sim::{DrivingGoal, Scenario, SidewalkSpot, TripSpec};
|
||||||
|
|
||||||
pub struct AgentSpawner {
|
pub struct AgentSpawner {
|
||||||
|
menu: NewModalMenu,
|
||||||
from: Source,
|
from: Source,
|
||||||
maybe_goal: Option<(Goal, Option<PolyLine>)>,
|
maybe_goal: Option<(Goal, Option<PolyLine>)>,
|
||||||
}
|
}
|
||||||
@ -28,7 +29,12 @@ enum Goal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AgentSpawner {
|
impl AgentSpawner {
|
||||||
pub fn new(ctx: &mut EventCtx, ui: &mut UI) -> Option<AgentSpawner> {
|
pub fn new(
|
||||||
|
ctx: &mut EventCtx,
|
||||||
|
ui: &mut UI,
|
||||||
|
sandbox_menu: &mut NewModalMenu,
|
||||||
|
) -> Option<AgentSpawner> {
|
||||||
|
let menu = NewModalMenu::new("Agent Spawner", vec![(Key::Escape, "quit")], ctx);
|
||||||
let map = &ui.primary.map;
|
let map = &ui.primary.map;
|
||||||
match ui.primary.current_selection {
|
match ui.primary.current_selection {
|
||||||
Some(ID::Building(id)) => {
|
Some(ID::Building(id)) => {
|
||||||
@ -37,6 +43,7 @@ impl AgentSpawner {
|
|||||||
.contextual_action(Key::F3, "spawn a pedestrian starting here")
|
.contextual_action(Key::F3, "spawn a pedestrian starting here")
|
||||||
{
|
{
|
||||||
return Some(AgentSpawner {
|
return Some(AgentSpawner {
|
||||||
|
menu,
|
||||||
from: Source::Walking(id),
|
from: Source::Walking(id),
|
||||||
maybe_goal: None,
|
maybe_goal: None,
|
||||||
});
|
});
|
||||||
@ -50,6 +57,7 @@ impl AgentSpawner {
|
|||||||
.contextual_action(Key::F4, "spawn a car starting here")
|
.contextual_action(Key::F4, "spawn a car starting here")
|
||||||
{
|
{
|
||||||
return Some(AgentSpawner {
|
return Some(AgentSpawner {
|
||||||
|
menu,
|
||||||
from: Source::Driving(
|
from: Source::Driving(
|
||||||
b.front_path.sidewalk.equiv_pos(driving_lane, map),
|
b.front_path.sidewalk.equiv_pos(driving_lane, map),
|
||||||
),
|
),
|
||||||
@ -65,6 +73,7 @@ impl AgentSpawner {
|
|||||||
.contextual_action(Key::F3, "spawn an agent starting here")
|
.contextual_action(Key::F3, "spawn an agent starting here")
|
||||||
{
|
{
|
||||||
return Some(AgentSpawner {
|
return Some(AgentSpawner {
|
||||||
|
menu,
|
||||||
from: Source::Driving(Position::new(id, map.get_l(id).length() / 2.0)),
|
from: Source::Driving(Position::new(id, map.get_l(id).length() / 2.0)),
|
||||||
maybe_goal: None,
|
maybe_goal: None,
|
||||||
});
|
});
|
||||||
@ -80,8 +89,7 @@ impl AgentSpawner {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if ui.primary.sim.is_empty() {
|
if ui.primary.sim.is_empty() {
|
||||||
// TODO Weird. This mode belongs to the parent SpawnMode, not AgentSpawner.
|
if sandbox_menu.action("seed the sim with agents") {
|
||||||
if ctx.input.modal_action("seed the sim with agents") {
|
|
||||||
Scenario::scaled_run(map, ui.primary.current_flags.num_agents).instantiate(
|
Scenario::scaled_run(map, ui.primary.current_flags.num_agents).instantiate(
|
||||||
&mut ui.primary.sim,
|
&mut ui.primary.sim,
|
||||||
map,
|
map,
|
||||||
@ -100,11 +108,15 @@ impl AgentSpawner {
|
|||||||
// Returns true if the spawner editor is done and we should go back to main sandbox mode.
|
// Returns true if the spawner editor is done and we should go back to main sandbox mode.
|
||||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
|
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
|
||||||
// TODO Instructions to select target building/lane
|
// TODO Instructions to select target building/lane
|
||||||
ctx.input.set_mode("Agent Spawner", ctx.canvas);
|
self.menu.handle_event(ctx);
|
||||||
if ctx.input.modal_action("quit") {
|
if self.menu.action("quit") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.canvas.handle_event(ctx.input);
|
||||||
|
ui.primary.current_selection =
|
||||||
|
ui.handle_mouseover(ctx, None, &ui.primary.sim, &ShowEverything::new(), false);
|
||||||
|
|
||||||
let map = &ui.primary.map;
|
let map = &ui.primary.map;
|
||||||
|
|
||||||
let new_goal = match ui.primary.current_selection {
|
let new_goal = match ui.primary.current_selection {
|
||||||
@ -236,6 +248,8 @@ impl AgentSpawner {
|
|||||||
opts.override_colors.insert(src, ui.cs.get("selected"));
|
opts.override_colors.insert(src, ui.cs.get("selected"));
|
||||||
ui.draw(g, opts, &ui.primary.sim, &ShowEverything::new());
|
ui.draw(g, opts, &ui.primary.sim, &ShowEverything::new());
|
||||||
|
|
||||||
|
self.menu.draw(g);
|
||||||
|
|
||||||
if let Some((_, Some(ref trace))) = self.maybe_goal {
|
if let Some((_, Some(ref trace))) = self.maybe_goal {
|
||||||
g.draw_polygon(ui.cs.get("route"), &trace.make_polygons(LANE_THICKNESS));
|
g.draw_polygon(ui.cs.get("route"), &trace.make_polygons(LANE_THICKNESS));
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use abstutil::MultiMap;
|
use abstutil::MultiMap;
|
||||||
use ezgui::EventCtx;
|
use ezgui::{Canvas, EventCtx, GfxCtx, Key, NewModalMenu, Text};
|
||||||
use geom::Duration;
|
use geom::Duration;
|
||||||
use map_model::{Map, Traversable};
|
use map_model::{Map, Traversable};
|
||||||
use sim::{CarID, DrawCarInput, DrawPedestrianInput, GetDrawAgents, PedestrianID, TIMESTEP};
|
use sim::{CarID, DrawCarInput, DrawPedestrianInput, GetDrawAgents, PedestrianID, TIMESTEP};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
pub struct TimeTravel {
|
pub struct TimeTravel {
|
||||||
|
menu: NewModalMenu,
|
||||||
// TODO Could be more efficient
|
// TODO Could be more efficient
|
||||||
state_per_time: BTreeMap<Duration, StateAtTime>,
|
state_per_time: BTreeMap<Duration, StateAtTime>,
|
||||||
pub current_time: Option<Duration>,
|
pub current_time: Option<Duration>,
|
||||||
@ -23,7 +24,7 @@ struct StateAtTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TimeTravel {
|
impl TimeTravel {
|
||||||
pub fn new() -> TimeTravel {
|
pub fn new(canvas: &Canvas) -> TimeTravel {
|
||||||
TimeTravel {
|
TimeTravel {
|
||||||
state_per_time: BTreeMap::new(),
|
state_per_time: BTreeMap::new(),
|
||||||
current_time: None,
|
current_time: None,
|
||||||
@ -31,6 +32,15 @@ impl TimeTravel {
|
|||||||
first_time: Duration::ZERO,
|
first_time: Duration::ZERO,
|
||||||
last_time: Duration::ZERO,
|
last_time: Duration::ZERO,
|
||||||
should_record: false,
|
should_record: false,
|
||||||
|
menu: NewModalMenu::hacky_new(
|
||||||
|
"Time Traveler",
|
||||||
|
vec![
|
||||||
|
(Key::Escape, "quit"),
|
||||||
|
(Key::Comma, "rewind"),
|
||||||
|
(Key::Dot, "forwards"),
|
||||||
|
],
|
||||||
|
canvas,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,22 +91,27 @@ impl TimeTravel {
|
|||||||
// Returns true if done.
|
// Returns true if done.
|
||||||
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
|
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
|
||||||
let time = self.current_time.unwrap();
|
let time = self.current_time.unwrap();
|
||||||
ctx.input.set_mode_with_prompt(
|
self.menu.handle_event(ctx);
|
||||||
"Time Traveler",
|
self.menu
|
||||||
format!("Time Traveler at {}", time),
|
.update_prompt(Text::prompt(&format!("Time Traveler at {}", time)), ctx);
|
||||||
&ctx.canvas,
|
|
||||||
);
|
ctx.canvas.handle_event(ctx.input);
|
||||||
if time > self.first_time && ctx.input.modal_action("rewind") {
|
|
||||||
|
if time > self.first_time && self.menu.action("rewind") {
|
||||||
self.current_time = Some(time - TIMESTEP);
|
self.current_time = Some(time - TIMESTEP);
|
||||||
} else if time < self.last_time && ctx.input.modal_action("forwards") {
|
} else if time < self.last_time && self.menu.action("forwards") {
|
||||||
self.current_time = Some(time + TIMESTEP);
|
self.current_time = Some(time + TIMESTEP);
|
||||||
} else if ctx.input.modal_action("quit") {
|
} else if self.menu.action("quit") {
|
||||||
self.current_time = None;
|
self.current_time = None;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, g: &mut GfxCtx) {
|
||||||
|
self.menu.draw(g);
|
||||||
|
}
|
||||||
|
|
||||||
fn get_current_state(&self) -> &StateAtTime {
|
fn get_current_state(&self) -> &StateAtTime {
|
||||||
&self.state_per_time[&self.current_time.unwrap()]
|
&self.state_per_time[&self.current_time.unwrap()]
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::widgets::{Menu, Position};
|
use crate::widgets::{Menu, Position};
|
||||||
use crate::{EventCtx, GfxCtx, InputResult, Key, ScreenPt, Text};
|
use crate::{Canvas, EventCtx, GfxCtx, InputResult, Key, ScreenPt, Text};
|
||||||
|
|
||||||
pub struct NewModalMenu {
|
pub struct NewModalMenu {
|
||||||
menu: Menu<Key>,
|
menu: Menu<Key>,
|
||||||
@ -8,6 +8,15 @@ pub struct NewModalMenu {
|
|||||||
|
|
||||||
impl NewModalMenu {
|
impl NewModalMenu {
|
||||||
pub fn new(prompt_line: &str, choices: Vec<(Key, &str)>, ctx: &EventCtx) -> NewModalMenu {
|
pub fn new(prompt_line: &str, choices: Vec<(Key, &str)>, ctx: &EventCtx) -> NewModalMenu {
|
||||||
|
NewModalMenu::hacky_new(prompt_line, choices, ctx.canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Pass EventCtx when constructing the GUI?
|
||||||
|
pub fn hacky_new(
|
||||||
|
prompt_line: &str,
|
||||||
|
choices: Vec<(Key, &str)>,
|
||||||
|
canvas: &Canvas,
|
||||||
|
) -> NewModalMenu {
|
||||||
let mut menu = Menu::new(
|
let mut menu = Menu::new(
|
||||||
Some(Text::prompt(prompt_line)),
|
Some(Text::prompt(prompt_line)),
|
||||||
choices
|
choices
|
||||||
@ -17,7 +26,7 @@ impl NewModalMenu {
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
Position::TopRightOfScreen,
|
Position::TopRightOfScreen,
|
||||||
ctx.canvas,
|
canvas,
|
||||||
);
|
);
|
||||||
menu.mark_all_inactive();
|
menu.mark_all_inactive();
|
||||||
NewModalMenu {
|
NewModalMenu {
|
||||||
@ -62,6 +71,11 @@ impl NewModalMenu {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_prompt(&mut self, txt: Text, _: &EventCtx) {
|
||||||
|
// TODO Do need to recalculate geometry
|
||||||
|
self.menu.change_prompt(txt);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw(&self, g: &mut GfxCtx) {
|
pub fn draw(&self, g: &mut GfxCtx) {
|
||||||
self.menu.draw(g);
|
self.menu.draw(g);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user