hack in a way to easily check for ctrl+key. use to jump between

sandbox, debug, and edit modes
This commit is contained in:
Dustin Carlino 2019-05-29 13:28:51 -07:00
parent 35b3e4b7be
commit 53e2c3e905
29 changed files with 248 additions and 157 deletions

View File

@ -5,7 +5,7 @@ use crate::game::{GameState, Mode};
use crate::render::DrawOptions;
use crate::ui::{PerMapUI, ShowEverything, UI};
use abstutil::elapsed_seconds;
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
use geom::{Duration, Line, PolyLine};
use map_model::LANE_THICKNESS;
use sim::{Benchmark, TripID};
@ -42,14 +42,14 @@ impl ABTestMode {
"A/B Test Mode",
vec![
vec![
(Some(Key::Escape), "quit"),
(Some(Key::LeftBracket), "slow down sim"),
(Some(Key::RightBracket), "speed up sim"),
(Some(Key::Space), "run/pause sim"),
(Some(Key::M), "step forwards 0.1s"),
(Some(Key::S), "swap"),
(Some(Key::D), "diff all trips"),
(Some(Key::B), "stop diffing trips"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::LeftBracket), "slow down sim"),
(hotkey(Key::RightBracket), "speed up sim"),
(hotkey(Key::Space), "run/pause sim"),
(hotkey(Key::M), "step forwards 0.1s"),
(hotkey(Key::S), "swap"),
(hotkey(Key::D), "diff all trips"),
(hotkey(Key::B), "stop diffing trips"),
],
CommonState::modal_menu_entries(),
]

View File

@ -1,7 +1,7 @@
use crate::abtest::{ABTestMode, State};
use crate::game::{GameState, Mode};
use crate::ui::{Flags, PerMapUI, UI};
use ezgui::{EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
use map_model::Map;
use sim::{ABTest, SimFlags};
use std::path::PathBuf;
@ -26,8 +26,8 @@ impl ABTestSetup {
ModalMenu::new(
&format!("A/B Test Editor for {}", ab_test.test_name),
vec![
(Some(Key::Escape), "quit"),
(Some(Key::R), "run A/B test"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::R), "run A/B test"),
],
ctx,
),

View File

@ -8,8 +8,8 @@ use crate::render::DrawOptions;
use crate::ui::UI;
use abstutil::elapsed_seconds;
use ezgui::{
Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text,
VerticalAlignment,
hotkey, Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, MultiKey,
Text, VerticalAlignment,
};
use geom::{Line, Pt2D};
use std::collections::BTreeSet;
@ -32,12 +32,12 @@ impl CommonState {
}
}
pub fn modal_menu_entries() -> Vec<(Option<Key>, &'static str)> {
pub fn modal_menu_entries() -> Vec<(Option<MultiKey>, &'static str)> {
vec![
(Some(Key::J), "warp"),
(hotkey(Key::J), "warp"),
// TODO This definitely conflicts with some modes.
(Some(Key::K), "navigate"),
(Some(Key::F1), "take a screenshot"),
(hotkey(Key::K), "navigate"),
(hotkey(Key::F1), "take a screenshot"),
]
}

View File

@ -1,6 +1,6 @@
use crate::ui::UI;
use ezgui::{
Canvas, Color, EventCtx, GfxCtx, InputResult, Key, ModalMenu, ScreenPt, ScrollingMenu,
hotkey, Canvas, Color, EventCtx, GfxCtx, InputResult, Key, ModalMenu, ScreenPt, ScrollingMenu,
};
use geom::{Distance, Polygon};
@ -32,8 +32,8 @@ impl ColorPicker {
ModalMenu::new(
&format!("Color Picker for {}", name),
vec![
(Some(Key::Backspace), "revert"),
(Some(Key::Escape), "finalize"),
(hotkey(Key::Backspace), "revert"),
(hotkey(Key::Escape), "finalize"),
],
ctx,
),

View File

@ -6,16 +6,18 @@ mod objects;
mod polygons;
use crate::common::CommonState;
use crate::edit::EditMode;
use crate::game::{GameState, Mode};
use crate::helpers::ID;
use crate::render::DrawOptions;
use crate::sandbox::SandboxMode;
use crate::ui::{ShowLayers, ShowObject, UI};
use abstutil::wraparound_get;
use abstutil::Timer;
use clipping::CPolygon;
use ezgui::{
Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu, ScrollingMenu, Text,
TextBox, Wizard,
hotkey, lctrl, Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu,
ScrollingMenu, Text, TextBox, Wizard,
};
use geom::{Distance, PolyLine, Polygon, Pt2D};
use map_model::{IntersectionID, Map, RoadID};
@ -69,22 +71,24 @@ impl DebugMode {
"Debug Mode",
vec![
vec![
(Some(Key::Escape), "quit"),
(Some(Key::C), "show/hide chokepoints"),
(Some(Key::O), "clear original roads shown"),
(Some(Key::G), "clear intersection geometry"),
(Some(Key::H), "unhide everything"),
(Some(Key::Num1), "show/hide buildings"),
(Some(Key::Num2), "show/hide intersections"),
(Some(Key::Num3), "show/hide lanes"),
(Some(Key::Num4), "show/hide areas"),
(Some(Key::Num5), "show/hide extra shapes"),
(Some(Key::Num6), "show/hide geometry debug mode"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::C), "show/hide chokepoints"),
(hotkey(Key::O), "clear original roads shown"),
(hotkey(Key::G), "clear intersection geometry"),
(hotkey(Key::H), "unhide everything"),
(hotkey(Key::Num1), "show/hide buildings"),
(hotkey(Key::Num2), "show/hide intersections"),
(hotkey(Key::Num3), "show/hide lanes"),
(hotkey(Key::Num4), "show/hide areas"),
(hotkey(Key::Num5), "show/hide extra shapes"),
(hotkey(Key::Num6), "show/hide geometry debug mode"),
(None, "screenshot everything"),
(Some(Key::Slash), "search OSM metadata"),
(Some(Key::M), "clear OSM search results"),
(Some(Key::S), "configure colors"),
(Some(Key::N), "show/hide neighborhood summaries"),
(hotkey(Key::Slash), "search OSM metadata"),
(hotkey(Key::M), "clear OSM search results"),
(hotkey(Key::S), "configure colors"),
(hotkey(Key::N), "show/hide neighborhood summaries"),
(lctrl(Key::S), "sandbox mode"),
(lctrl(Key::E), "edit mode"),
],
CommonState::modal_menu_entries(),
]
@ -147,6 +151,14 @@ impl DebugMode {
state.mode = Mode::SplashScreen(Wizard::new(), None);
return EventLoopMode::InputOnly;
}
if menu.action("sandbox mode") {
state.mode = Mode::Sandbox(SandboxMode::new(ctx));
return EventLoopMode::InputOnly;
}
if menu.action("edit mode") {
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
return EventLoopMode::InputOnly;
}
if menu.action("show/hide chokepoints") {
if mode.chokepoints.is_some() {

View File

@ -2,7 +2,7 @@ use crate::helpers::ID;
use crate::render::calculate_corners;
use crate::ui::UI;
use abstutil::Timer;
use ezgui::{EventCtx, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, EventCtx, GfxCtx, ItemSlider, Key, Text};
use geom::{Polygon, Pt2D, Triangle};
pub struct PolygonDebugger {
@ -33,7 +33,7 @@ impl PolygonDebugger {
pts.iter().map(|pt| Item::Point(*pt)).collect(),
"Polygon Debugger",
"point",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
center: Some(Pt2D::center(&pts_without_last)),
@ -54,7 +54,7 @@ impl PolygonDebugger {
.collect(),
"Polygon Debugger",
"corner",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
center: None,
@ -75,7 +75,7 @@ impl PolygonDebugger {
.collect(),
"Polygon Debugger",
"point",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
center: None,
@ -93,7 +93,7 @@ impl PolygonDebugger {
.collect(),
"Polygon Debugger",
"triangle",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
center: None,
@ -115,7 +115,7 @@ impl PolygonDebugger {
pts.iter().map(|pt| Item::Point(*pt)).collect(),
"Polygon Debugger",
"point",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
center: Some(center),
@ -133,7 +133,7 @@ impl PolygonDebugger {
.collect(),
"Polygon Debugger",
"triangle",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
center: None,

View File

@ -2,15 +2,20 @@ mod stop_signs;
mod traffic_signals;
use crate::common::CommonState;
use crate::debug::DebugMode;
use crate::game::{GameState, Mode};
use crate::helpers::ID;
use crate::render::{
DrawCtx, DrawIntersection, DrawLane, DrawMap, DrawOptions, DrawTurn, Renderable,
MIN_ZOOM_FOR_DETAIL,
};
use crate::sandbox::SandboxMode;
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard, WrappedWizard};
use ezgui::{
hotkey, lctrl, Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard,
WrappedWizard,
};
use map_model::{IntersectionID, Lane, LaneID, LaneType, Map, MapEdits, Road, TurnID, TurnType};
use std::collections::{BTreeSet, HashMap};
@ -33,9 +38,11 @@ impl EditMode {
"Map Edit Mode",
vec![
vec![
(Some(Key::Escape), "quit"),
(Some(Key::S), "save edits"),
(Some(Key::L), "load different edits"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::S), "save edits"),
(hotkey(Key::L), "load different edits"),
(lctrl(Key::S), "sandbox mode"),
(lctrl(Key::D), "debug mode"),
],
CommonState::modal_menu_entries(),
]
@ -83,6 +90,15 @@ impl EditMode {
state.mode = Mode::SplashScreen(Wizard::new(), None);
return EventLoopMode::InputOnly;
}
if menu.action("sandbox mode") {
state.mode = Mode::Sandbox(SandboxMode::new(ctx));
return EventLoopMode::InputOnly;
}
if menu.action("debug mode") {
state.mode = Mode::Debug(DebugMode::new(ctx, &state.ui));
return EventLoopMode::InputOnly;
}
// TODO Only if current edits are unsaved
if menu.action("save edits") {
state.mode = Mode::Edit(EditMode::Saving(Wizard::new()));

View File

@ -4,7 +4,7 @@ use crate::game::GameState;
use crate::helpers::ID;
use crate::render::{DrawIntersection, DrawOptions, DrawTurn};
use crate::ui::{ShowEverything, UI};
use ezgui::{Color, EventCtx, 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;
@ -37,8 +37,8 @@ impl StopSignEditor {
menu: ModalMenu::new(
"Stop Sign Editor",
vec![
(Some(Key::Escape), "quit"),
(Some(Key::R), "reset to default"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::R), "reset to default"),
],
ctx,
),

View File

@ -5,7 +5,7 @@ use crate::helpers::ID;
use crate::render::{draw_signal_cycle, draw_signal_diagram, DrawCtx, DrawOptions, DrawTurn};
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use geom::Duration;
use map_model::{ControlTrafficSignal, Cycle, IntersectionID, Map, TurnID, TurnPriority, TurnType};
@ -27,17 +27,17 @@ impl TrafficSignalEditor {
let menu = ModalMenu::new(
&format!("Traffic Signal Editor for {}", id),
vec![
(Some(Key::Escape), "quit"),
(Some(Key::D), "change cycle duration"),
(Some(Key::P), "choose a preset signal"),
(Some(Key::R), "reset to original"),
(Some(Key::K), "move current cycle up"),
(Some(Key::J), "move current cycle down"),
(Some(Key::UpArrow), "select previous cycle"),
(Some(Key::DownArrow), "select next cycle"),
(Some(Key::Backspace), "delete current cycle"),
(Some(Key::N), "add a new empty cycle"),
(Some(Key::M), "add a new pedestrian scramble cycle"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::D), "change cycle duration"),
(hotkey(Key::P), "choose a preset signal"),
(hotkey(Key::R), "reset to original"),
(hotkey(Key::K), "move current cycle up"),
(hotkey(Key::J), "move current cycle down"),
(hotkey(Key::UpArrow), "select previous cycle"),
(hotkey(Key::DownArrow), "select next cycle"),
(hotkey(Key::Backspace), "delete current cycle"),
(hotkey(Key::N), "add a new empty cycle"),
(hotkey(Key::M), "add a new pedestrian scramble cycle"),
],
ctx,
);

View File

@ -8,7 +8,9 @@ use crate::sandbox::SandboxMode;
use crate::tutorial::TutorialMode;
use crate::ui::{EditorState, Flags, ShowEverything, UI};
use abstutil::elapsed_seconds;
use ezgui::{Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, UserInput, Wizard, GUI};
use ezgui::{
hotkey, Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, UserInput, Wizard, GUI,
};
use geom::{Duration, Line, Pt2D, Speed};
use map_model::Map;
use rand::seq::SliceRandom;
@ -257,13 +259,13 @@ fn splash_screen(
.choose_string_hotkeys(
"Welcome to A/B Street!",
vec![
(Some(Key::S), sandbox),
(Some(Key::L), load_map),
(Some(Key::E), edit),
(Some(Key::T), tutorial),
(Some(Key::D), debug),
(Some(Key::M), mission),
(Some(Key::A), abtest),
(hotkey(Key::S), sandbox),
(hotkey(Key::L), load_map),
(hotkey(Key::E), edit),
(hotkey(Key::T), tutorial),
(hotkey(Key::D), debug),
(hotkey(Key::M), mission),
(hotkey(Key::A), abtest),
(None, about),
(None, quit),
],

View File

@ -2,7 +2,7 @@ use crate::common::CommonState;
use crate::mission::{clip_trips, Trip};
use crate::ui::{ShowEverything, UI};
use abstutil::prettyprint_usize;
use ezgui::{Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Slider, Text};
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Slider, Text};
use geom::{Circle, Distance, Duration};
use map_model::LANE_THICKNESS;
use popdat::psrc::Mode;
@ -52,13 +52,13 @@ impl TripsVisualizer {
menu: ModalMenu::new(
"Trips Visualizer",
vec![
(Some(Key::Escape), "quit"),
(Some(Key::Dot), "forwards 10 seconds"),
(Some(Key::RightArrow), "forwards 30 minutes"),
(Some(Key::Comma), "backwards 10 seconds"),
(Some(Key::LeftArrow), "backwards 30 minutes"),
(Some(Key::F), "goto start of day"),
(Some(Key::L), "goto end of day"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::Dot), "forwards 10 seconds"),
(hotkey(Key::RightArrow), "forwards 30 minutes"),
(hotkey(Key::Comma), "backwards 10 seconds"),
(hotkey(Key::LeftArrow), "backwards 30 minutes"),
(hotkey(Key::F), "goto start of day"),
(hotkey(Key::L), "goto end of day"),
],
ctx,
),

View File

@ -3,7 +3,7 @@ use crate::helpers::{rotating_color_total, ID};
use crate::ui::UI;
use abstutil::{prettyprint_usize, Timer};
use ezgui::{
Color, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment,
hotkey, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment,
};
use geom::{Distance, Polygon, Pt2D};
use popdat::{Estimate, PopDat};
@ -40,11 +40,11 @@ impl DataVisualizer {
menu: ModalMenu::new(
"Data Visualizer",
vec![
(Some(Key::Escape), "quit"),
(Some(Key::Space), "toggle table/bar chart"),
(Some(Key::Num1), "household vehicles"),
(Some(Key::Num2), "commute times"),
(Some(Key::Num3), "commute modes"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::Space), "toggle table/bar chart"),
(hotkey(Key::Num1), "household vehicles"),
(hotkey(Key::Num2), "commute times"),
(hotkey(Key::Num3), "commute modes"),
],
ctx,
),

View File

@ -2,7 +2,7 @@ use crate::common::CommonState;
use crate::mission::{clip_trips, Trip};
use crate::ui::{ShowEverything, UI};
use abstutil::{prettyprint_usize, Timer};
use ezgui::{Color, EventCtx, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, Color, EventCtx, GfxCtx, ItemSlider, Key, Text};
use geom::{Circle, Distance, Speed};
use popdat::PopDat;
@ -22,7 +22,7 @@ impl TripsVisualizer {
trips,
"Trips Visualizer",
"trip",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
}

View File

@ -10,7 +10,7 @@ use crate::sandbox::SandboxMode;
use crate::ui::ShowEverything;
use crate::ui::UI;
use abstutil::{skip_fail, Timer};
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard};
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard};
use geom::{Distance, Duration, PolyLine};
use map_model::{BuildingID, Map, PathRequest, Position};
use sim::SidewalkSpot;
@ -38,13 +38,13 @@ impl MissionEditMode {
state: State::Exploring(ModalMenu::new(
"Mission Edit Mode",
vec![
(Some(Key::Escape), "quit"),
(Some(Key::D), "visualize population data"),
(Some(Key::T), "visualize individual PSRC trips"),
(Some(Key::A), "visualize all PSRC trips"),
(Some(Key::S), "set up simulation with PSRC trips"),
(Some(Key::N), "manage neighborhoods"),
(Some(Key::W), "manage scenarios"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::D), "visualize population data"),
(hotkey(Key::T), "visualize individual PSRC trips"),
(hotkey(Key::A), "visualize all PSRC trips"),
(hotkey(Key::S), "set up simulation with PSRC trips"),
(hotkey(Key::N), "manage neighborhoods"),
(hotkey(Key::W), "manage scenarios"),
],
ctx,
)),

View File

@ -1,5 +1,5 @@
use crate::ui::UI;
use ezgui::{Color, EventCtx, 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};
@ -18,10 +18,10 @@ impl NeighborhoodEditor {
ModalMenu::new(
&format!("Neighborhood Editor for {}", name),
vec![
(Some(Key::Escape), "quit"),
(Some(Key::S), "save"),
(Some(Key::X), "export as an Osmosis polygon filter"),
(Some(Key::P), "add a new point"),
(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,
)

View File

@ -5,7 +5,7 @@ use crate::sandbox::SandboxMode;
use crate::ui::UI;
use abstutil::WeightedUsizeChoice;
use ezgui::{
Color, Drawable, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
hotkey, Color, Drawable, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
};
use geom::{Distance, Duration, PolyLine, Pt2D};
use map_model::{IntersectionID, Map, Neighborhood};
@ -24,11 +24,11 @@ impl ScenarioEditor {
ModalMenu::new(
&format!("Scenario Editor for {}", name),
vec![
(Some(Key::Escape), "quit"),
(Some(Key::S), "save"),
(Some(Key::E), "edit"),
(Some(Key::I), "instantiate"),
(Some(Key::V), "visualize"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::S), "save"),
(hotkey(Key::E), "edit"),
(hotkey(Key::I), "instantiate"),
(hotkey(Key::V), "visualize"),
],
ctx,
)

View File

@ -5,11 +5,13 @@ mod spawner;
mod time_travel;
use crate::common::CommonState;
use crate::debug::DebugMode;
use crate::edit::EditMode;
use crate::game::{GameState, Mode};
use crate::render::DrawOptions;
use crate::ui::ShowEverything;
use abstutil::elapsed_seconds;
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
use ezgui::{hotkey, lctrl, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
use geom::Duration;
use sim::{Benchmark, Sim, TripID};
use std::time::Instant;
@ -54,24 +56,26 @@ impl SandboxMode {
"Sandbox Mode",
vec![
vec![
(Some(Key::Escape), "quit"),
(Some(Key::LeftBracket), "slow down sim"),
(Some(Key::RightBracket), "speed up sim"),
(Some(Key::O), "save sim state"),
(Some(Key::Y), "load previous sim state"),
(Some(Key::U), "load next sim state"),
(Some(Key::Space), "run/pause sim"),
(Some(Key::M), "step forwards 0.1s"),
(Some(Key::N), "step forwards 10 mins"),
(Some(Key::X), "reset sim"),
(Some(Key::S), "seed the sim with agents"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::LeftBracket), "slow down sim"),
(hotkey(Key::RightBracket), "speed up sim"),
(hotkey(Key::O), "save sim state"),
(hotkey(Key::Y), "load previous sim state"),
(hotkey(Key::U), "load next sim state"),
(hotkey(Key::Space), "run/pause sim"),
(hotkey(Key::M), "step forwards 0.1s"),
(hotkey(Key::N), "step forwards 10 mins"),
(hotkey(Key::X), "reset sim"),
(hotkey(Key::S), "seed the sim with agents"),
// TODO Strange to always have this. Really it's a case of stacked modal?
(Some(Key::F), "stop following agent"),
(Some(Key::R), "stop showing agent's route"),
(hotkey(Key::F), "stop following agent"),
(hotkey(Key::R), "stop showing agent's route"),
// TODO This should probably be a debug thing instead
(Some(Key::L), "show/hide route for all agents"),
(Some(Key::A), "show/hide active traffic"),
(Some(Key::T), "start time traveling"),
(hotkey(Key::L), "show/hide route for all agents"),
(hotkey(Key::A), "show/hide active traffic"),
(hotkey(Key::T), "start time traveling"),
(lctrl(Key::D), "debug mode"),
(lctrl(Key::E), "edit mode"),
],
CommonState::modal_menu_entries(),
]
@ -206,6 +210,14 @@ impl SandboxMode {
state.mode = Mode::SplashScreen(Wizard::new(), None);
return EventLoopMode::InputOnly;
}
if mode.menu.action("debug mode") {
state.mode = Mode::Debug(DebugMode::new(ctx, &state.ui));
return EventLoopMode::InputOnly;
}
if mode.menu.action("edit mode") {
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
return EventLoopMode::InputOnly;
}
if mode.menu.action("slow down sim") {
mode.desired_speed -= ADJUST_SPEED;

View File

@ -2,7 +2,7 @@ use crate::common::Warper;
use crate::helpers::ID;
use crate::render::DrawTurn;
use crate::ui::UI;
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
use geom::{Distance, Polygon};
use map_model::{Traversable, LANE_THICKNESS};
use sim::AgentID;
@ -63,7 +63,7 @@ impl RouteExplorer {
steps,
"Route Explorer",
"step",
vec![(Some(Key::Escape), "quit")],
vec![(hotkey(Key::Escape), "quit")],
ctx,
),
entire_trace,

View File

@ -3,7 +3,7 @@ use crate::helpers::ID;
use crate::render::DrawOptions;
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{EventCtx, 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,
@ -38,7 +38,7 @@ impl AgentSpawner {
ui: &mut UI,
sandbox_menu: &mut ModalMenu,
) -> Option<AgentSpawner> {
let menu = ModalMenu::new("Agent Spawner", vec![(Some(Key::Escape), "quit")], ctx);
let menu = ModalMenu::new("Agent Spawner", vec![(hotkey(Key::Escape), "quit")], ctx);
let map = &ui.primary.map;
match ui.primary.current_selection {
Some(ID::Building(id)) => {

View File

@ -1,6 +1,6 @@
use crate::ui::UI;
use abstutil::MultiMap;
use ezgui::{EventCtx, GfxCtx, Key, ModalMenu, Text};
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu, Text};
use geom::Duration;
use map_model::{Map, Traversable};
use sim::{CarID, DrawCarInput, DrawPedestrianInput, GetDrawAgents, PedestrianID};
@ -30,9 +30,9 @@ impl TimeTravel {
menu: ModalMenu::new(
"Time Traveler",
vec![
(Some(Key::Escape), "quit"),
(Some(Key::Comma), "rewind"),
(Some(Key::Dot), "forwards"),
(hotkey(Key::Escape), "quit"),
(hotkey(Key::Comma), "rewind"),
(hotkey(Key::Dot), "forwards"),
],
ctx,
),

View File

@ -1,7 +1,7 @@
use crate::game::{GameState, Mode};
use crate::render::DrawOptions;
use crate::ui::{ShowEverything, UI};
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
use geom::Pt2D;
pub struct TutorialMode {
@ -21,7 +21,7 @@ impl TutorialMode {
ui.primary.reset_sim();
TutorialMode {
menu: ModalMenu::new("Tutorial", vec![(Some(Key::Escape), "quit")], ctx),
menu: ModalMenu::new("Tutorial", vec![(hotkey(Key::Escape), "quit")], ctx),
state: State::Part1(ctx.canvas.center_to_map_pt()),
}
}

View File

@ -33,6 +33,7 @@ pub struct Canvas {
// Kind of just ezgui state awkwardly stuck here...
pub(crate) hide_modal_menus: bool,
pub(crate) lctrl_held: bool,
}
impl Canvas {
@ -59,6 +60,7 @@ impl Canvas {
covered_areas: RefCell::new(Vec::new()),
hide_modal_menus: false,
lctrl_held: false,
}
}

View File

@ -237,7 +237,7 @@ impl Key {
}
}
pub fn describe(self: Key) -> String {
pub fn describe(self) -> String {
match self {
Key::Escape => "Escape".to_string(),
Key::Enter => "Enter".to_string(),
@ -350,3 +350,29 @@ impl Key {
})
}
}
// TODO This is not an ideal representation at all.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct MultiKey {
pub key: Key,
pub lctrl: bool,
}
impl MultiKey {
pub fn describe(self) -> String {
if self.lctrl {
format!("Ctrl+{}", self.key.describe())
} else {
self.key.describe()
}
}
}
// For easy ModalMenu construction
pub fn hotkey(key: Key) -> Option<MultiKey> {
Some(MultiKey { key, lctrl: false })
}
pub fn lctrl(key: Key) -> Option<MultiKey> {
Some(MultiKey { key, lctrl: true })
}

View File

@ -1,5 +1,5 @@
use crate::widgets::{Menu, Position};
use crate::{text, Canvas, Event, InputResult, Key, ScreenPt, Text};
use crate::{hotkey, text, Canvas, Event, InputResult, Key, ScreenPt, Text};
use std::collections::{BTreeMap, BTreeSet, HashMap};
// As we check for user input, record the input and the thing that would happen. This will let us
@ -41,7 +41,7 @@ impl ContextMenu {
Text::new(),
actions
.into_iter()
.map(|(hotkey, action)| (Some(hotkey), action, hotkey))
.map(|(key, action)| (hotkey(key), action, key))
.collect(),
false,
false,
@ -71,6 +71,13 @@ impl UserInput {
canvas.window_height = height;
}
if input.event == Event::KeyPress(Key::LeftControl) {
canvas.lctrl_held = true;
}
if input.event == Event::KeyRelease(Key::LeftControl) {
canvas.lctrl_held = false;
}
// Create the context menu here, even if one already existed.
if input.right_mouse_button_pressed() {
assert!(!input.event_consumed);

View File

@ -12,7 +12,7 @@ mod widgets;
pub use crate::canvas::{Canvas, HorizontalAlignment, VerticalAlignment, BOTTOM_LEFT, CENTERED};
pub use crate::color::Color;
pub use crate::drawing::{GeomBatch, GfxCtx};
pub use crate::event::{Event, Key};
pub use crate::event::{hotkey, lctrl, Event, Key, MultiKey};
pub use crate::event_ctx::{Drawable, EventCtx, Prerender};
pub use crate::input::UserInput;
pub use crate::runner::{run, EventLoopMode, GUI};

View File

@ -1,12 +1,14 @@
use crate::screen_geom::ScreenRectangle;
use crate::{text, Canvas, Event, GfxCtx, InputResult, Key, ScreenPt, Text};
use crate::{
hotkey, lctrl, text, Canvas, Event, GfxCtx, InputResult, Key, MultiKey, ScreenPt, Text,
};
use std::collections::HashSet;
// Stores some associated data with each choice
pub struct Menu<T: Clone> {
prompt: Text,
// The bool is whether this choice is active or not
choices: Vec<(Option<Key>, String, bool, T)>,
choices: Vec<(Option<MultiKey>, String, bool, T)>,
current_idx: Option<usize>,
mouse_in_bounds: bool,
keys_enabled: bool,
@ -35,7 +37,7 @@ impl Position {
&self,
canvas: &Canvas,
prompt: Text,
choices: &Vec<(Option<Key>, String, bool, T)>,
choices: &Vec<(Option<MultiKey>, String, bool, T)>,
) -> Geometry {
// This is actually a constant, effectively...
let row_height = canvas.line_height(text::FONT_SIZE);
@ -99,7 +101,7 @@ impl Position {
impl<T: Clone> Menu<T> {
pub fn new(
prompt: Text,
raw_choices: Vec<(Option<Key>, String, T)>,
raw_choices: Vec<(Option<MultiKey>, String, T)>,
keys_enabled: bool,
hideable: bool,
pos: Position,
@ -220,8 +222,13 @@ impl<T: Clone> Menu<T> {
}
if let Event::KeyPress(key) = ev {
let pressed = if canvas.lctrl_held {
lctrl(key)
} else {
hotkey(key)
};
for (maybe_key, choice, active, data) in &self.choices {
if *active && Some(key) == *maybe_key {
if *active && pressed == *maybe_key {
return InputResult::Done(choice.to_string(), data.clone());
}
}

View File

@ -1,5 +1,5 @@
use crate::widgets::{Menu, Position};
use crate::{EventCtx, GfxCtx, InputResult, Key, Text};
use crate::{EventCtx, GfxCtx, InputResult, MultiKey, Text};
pub struct ModalMenu {
menu: Menu<()>,
@ -7,12 +7,16 @@ pub struct ModalMenu {
}
impl ModalMenu {
pub fn new(prompt_line: &str, choices: Vec<(Option<Key>, &str)>, ctx: &EventCtx) -> ModalMenu {
pub fn new(
prompt_line: &str,
choices: Vec<(Option<MultiKey>, &str)>,
ctx: &EventCtx,
) -> ModalMenu {
let mut menu = Menu::new(
Text::prompt(prompt_line),
choices
.into_iter()
.map(|(key, action)| (key, action.to_string(), ()))
.map(|(multikey, action)| (multikey, action.to_string(), ()))
.collect(),
false,
true,

View File

@ -1,5 +1,5 @@
use crate::screen_geom::ScreenRectangle;
use crate::{Color, EventCtx, GfxCtx, Key, ModalMenu, Text};
use crate::{hotkey, Color, EventCtx, GfxCtx, Key, ModalMenu, MultiKey, Text};
use geom::{Distance, Polygon, Pt2D};
// Pixels
@ -169,7 +169,7 @@ impl<T> ItemSlider<T> {
items: Vec<T>,
menu_title: &str,
noun: &str,
other_choices: Vec<(Option<Key>, &str)>,
other_choices: Vec<(Option<MultiKey>, &str)>,
ctx: &mut EventCtx,
) -> ItemSlider<T> {
// Lifetime funniness...
@ -180,10 +180,10 @@ impl<T> ItemSlider<T> {
let first = format!("first {}", noun);
let last = format!("last {}", noun);
choices.extend(vec![
(Some(Key::LeftArrow), prev.as_str()),
(Some(Key::RightArrow), next.as_str()),
(Some(Key::Comma), first.as_str()),
(Some(Key::Dot), last.as_str()),
(hotkey(Key::LeftArrow), prev.as_str()),
(hotkey(Key::RightArrow), next.as_str()),
(hotkey(Key::Comma), first.as_str()),
(hotkey(Key::Dot), last.as_str()),
]);
ItemSlider {

View File

@ -1,5 +1,7 @@
use crate::widgets::{Menu, Position};
use crate::{Canvas, GfxCtx, InputResult, Key, LogScroller, Text, TextBox, UserInput};
use crate::{
hotkey, Canvas, GfxCtx, InputResult, Key, LogScroller, MultiKey, Text, TextBox, UserInput,
};
use abstutil::Cloneable;
use std::collections::VecDeque;
@ -207,9 +209,9 @@ impl<'a> WrappedWizard<'a> {
));
return None;
}
let boxed_choices: Vec<(Option<Key>, String, Box<Cloneable>)> = choices
let boxed_choices: Vec<(Option<MultiKey>, String, Box<Cloneable>)> = choices
.into_iter()
.map(|(key, s, item)| (key, s, item.clone_box()))
.map(|(key, s, item)| (key.and_then(hotkey), s, item.clone_box()))
.collect();
self.wizard.menu = Some(Menu::new(
Text::prompt(query),
@ -275,13 +277,14 @@ impl<'a> WrappedWizard<'a> {
pub fn choose_string_hotkeys(
&mut self,
query: &str,
choices: Vec<(Option<Key>, &str)>,
choices: Vec<(Option<MultiKey>, &str)>,
) -> Option<String> {
// Clone the choices outside of the closure to get around the fact that choices_generator's
// lifetime isn't correctly specified.
let copied_choices: Vec<(Option<Key>, String, ())> = choices
.into_iter()
.map(|(key, s)| (key, s.to_string(), ()))
// TODO Argh, change all the APIs to take MultiKey
.map(|(multikey, s)| (multikey.map(|mk| mk.key), s.to_string(), ()))
.collect();
self.choose_something(query, Box::new(move || copied_choices.clone()))
.map(|(s, _)| s)