hotkeys on the wizard splash screen

This commit is contained in:
Dustin Carlino 2019-04-27 13:37:47 -07:00
parent 8e20e0fa89
commit 01628624c0
4 changed files with 64 additions and 22 deletions

View File

@ -319,17 +319,18 @@ fn choose_preset(
) -> Option<ControlTrafficSignal> {
// TODO I wanted to do all of this work just once per wizard, but we can't touch map inside a
// closure. Grr.
let mut choices: Vec<(String, ControlTrafficSignal)> = Vec::new();
let mut choices: Vec<(Option<Key>, String, ControlTrafficSignal)> = Vec::new();
if let Some(ts) = ControlTrafficSignal::four_way_four_phase(map, id) {
choices.push(("four-phase".to_string(), ts));
choices.push((None, "four-phase".to_string(), ts));
}
if let Some(ts) = ControlTrafficSignal::four_way_two_phase(map, id) {
choices.push(("two-phase".to_string(), ts));
choices.push((None, "two-phase".to_string(), ts));
}
if let Some(ts) = ControlTrafficSignal::three_way(map, id) {
choices.push(("three-phase".to_string(), ts));
choices.push((None, "three-phase".to_string(), ts));
}
choices.push((
None,
"arbitrary assignment".to_string(),
ControlTrafficSignal::greedy_assignment(map, id).unwrap(),
));

View File

@ -8,8 +8,8 @@ use crate::tutorial::TutorialMode;
use crate::ui::UI;
use abstutil::elapsed_seconds;
use ezgui::{
Canvas, EventCtx, EventLoopMode, GfxCtx, LogScroller, ModalMenu, Prerender, TopMenu, UserInput,
Wizard, GUI,
Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, ModalMenu, Prerender, TopMenu,
UserInput, Wizard, GUI,
};
use geom::{Duration, Line, Pt2D, Speed};
use map_model::Map;
@ -193,11 +193,21 @@ fn splash_screen(
// Loop because we might go from About -> top-level menu repeatedly, and recursion is scary.
loop {
// TODO No hotkey for quit because it's just the normal menu escape?
match wizard
.choose_string(
.choose_string_hotkeys(
"Welcome to A/B Street!",
vec![
sandbox, load_map, edit, tutorial, debug, mission, abtest, legacy, about, quit,
(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),
(None, legacy),
(Some(Key::A), about),
(None, quit),
],
)?
.as_str()
@ -205,7 +215,7 @@ fn splash_screen(
x if x == sandbox => break Some(Mode::Sandbox(SandboxMode::new())),
x if x == load_map => {
let current_map = ui.state.primary.map.get_name().to_string();
if let Some((name, _)) = wizard.choose_something::<String>(
if let Some((name, _)) = wizard.choose_something_no_keys::<String>(
"Load which map?",
Box::new(move || {
abstutil::list_all_objects("maps", "")

View File

@ -77,7 +77,7 @@ pub fn choose_neighborhood(map: &Map, wizard: &mut WrappedWizard, query: &str) -
let gps_bounds = map.get_gps_bounds().clone();
// Load the full object, since various plugins visualize the neighborhood when menuing over it
wizard
.choose_something::<Neighborhood>(
.choose_something_no_keys::<Neighborhood>(
query,
Box::new(move || Neighborhood::load_all(&map_name, &gps_bounds)),
)
@ -91,7 +91,7 @@ pub fn load_neighborhood_builder(
) -> Option<NeighborhoodBuilder> {
let map_name = map.get_name().to_string();
wizard
.choose_something::<NeighborhoodBuilder>(
.choose_something_no_keys::<NeighborhoodBuilder>(
query,
Box::new(move || abstutil::load_all_objects("neighborhoods", &map_name)),
)
@ -101,7 +101,7 @@ pub fn load_neighborhood_builder(
pub fn load_scenario(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<Scenario> {
let map_name = map.get_name().to_string();
wizard
.choose_something::<Scenario>(
.choose_something_no_keys::<Scenario>(
query,
Box::new(move || abstutil::load_all_objects("scenarios", &map_name)),
)
@ -111,7 +111,7 @@ pub fn load_scenario(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Opti
pub fn choose_scenario(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<String> {
let map_name = map.get_name().to_string();
wizard
.choose_something::<String>(
.choose_something_no_keys::<String>(
query,
Box::new(move || abstutil::list_all_objects("scenarios", &map_name)),
)
@ -121,7 +121,7 @@ pub fn choose_scenario(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Op
pub fn choose_edits(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<String> {
let map_name = map.get_name().to_string();
wizard
.choose_something::<String>(
.choose_something_no_keys::<String>(
query,
Box::new(move || {
let mut list = abstutil::list_all_objects("edits", &map_name);
@ -136,7 +136,7 @@ pub fn load_edits(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<
// TODO Exclude current?
let map_name = map.get_name().to_string();
wizard
.choose_something::<MapEdits>(
.choose_something_no_keys::<MapEdits>(
query,
Box::new(move || {
let mut list = abstutil::load_all_objects("edits", &map_name);
@ -150,7 +150,7 @@ pub fn load_edits(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<
pub fn load_ab_test(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<ABTest> {
let map_name = map.get_name().to_string();
wizard
.choose_something::<ABTest>(
.choose_something_no_keys::<ABTest>(
query,
Box::new(move || abstutil::load_all_objects("ab_tests", &map_name)),
)

View File

@ -175,7 +175,7 @@ impl<'a> WrappedWizard<'a> {
pub fn choose_something<R: 'static + Clone + Cloneable>(
&mut self,
query: &str,
choices_generator: Box<Fn() -> Vec<(String, R)>>,
choices_generator: Box<Fn() -> Vec<(Option<Key>, String, R)>>,
) -> Option<(String, R)> {
if !self.ready_results.is_empty() {
let first = self.ready_results.pop_front().unwrap();
@ -199,7 +199,7 @@ impl<'a> WrappedWizard<'a> {
}
if self.wizard.menu.is_none() {
let choices: Vec<(String, R)> = choices_generator();
let choices: Vec<(Option<Key>, String, R)> = choices_generator();
if choices.is_empty() {
self.wizard.log_scroller = Some(LogScroller::new(
"Wizard".to_string(),
@ -208,8 +208,8 @@ impl<'a> WrappedWizard<'a> {
return None;
}
let boxed_choices: Vec<(Option<Key>, String, Box<Cloneable>)> = choices
.iter()
.map(|(s, item)| (None, s.to_string(), item.clone_box()))
.into_iter()
.map(|(key, s, item)| (key, s, item.clone_box()))
.collect();
self.wizard.menu = Some(Menu::new(
Some(Text::from_styled_line(
@ -251,11 +251,42 @@ impl<'a> WrappedWizard<'a> {
}
}
pub fn choose_something_no_keys<R: 'static + Clone + Cloneable>(
&mut self,
query: &str,
choices_generator: Box<Fn() -> Vec<(String, R)>>,
) -> Option<(String, R)> {
let wrapped_generator = Box::new(move || {
choices_generator()
.into_iter()
.map(|(name, data)| (None, name, data))
.collect()
});
self.choose_something(query, wrapped_generator)
}
pub fn choose_string(&mut self, query: &str, choices: Vec<&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<(String, ())> =
choices.into_iter().map(|s| (s.to_string(), ())).collect();
let copied_choices: Vec<(Option<Key>, String, ())> = choices
.into_iter()
.map(|s| (None, s.to_string(), ()))
.collect();
self.choose_something(query, Box::new(move || copied_choices.clone()))
.map(|(s, _)| s)
}
pub fn choose_string_hotkeys(
&mut self,
query: &str,
choices: Vec<(Option<Key>, &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(), ()))
.collect();
self.choose_something(query, Box::new(move || copied_choices.clone()))
.map(|(s, _)| s)
}