From 2a5384cf112fd6858af8f6a90b7b42564de3a4b8 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Sun, 16 Dec 2018 16:18:25 -0800 Subject: [PATCH] making wizard use the new Menu --- editor/src/plugins/edit/a_b_tests.rs | 4 +- editor/src/plugins/edit/draw_neighborhoods.rs | 2 +- editor/src/plugins/edit/map_edits.rs | 2 +- editor/src/plugins/edit/scenarios.rs | 4 +- .../src/plugins/edit/traffic_signal_editor.rs | 4 +- ezgui/src/input.rs | 2 +- ezgui/src/menu.rs | 18 +++++--- ezgui/src/wizard.rs | 41 +++++++++++++------ 8 files changed, 52 insertions(+), 25 deletions(-) diff --git a/editor/src/plugins/edit/a_b_tests.rs b/editor/src/plugins/edit/a_b_tests.rs index ebc1c5b770..095ec54199 100644 --- a/editor/src/plugins/edit/a_b_tests.rs +++ b/editor/src/plugins/edit/a_b_tests.rs @@ -27,7 +27,9 @@ impl Plugin for ABTestManager { fn blocking_event(&mut self, ctx: &mut PluginCtx) -> bool { match self { ABTestManager::PickABTest(ref mut wizard) => { - if let Some(ab_test) = pick_ab_test(&ctx.primary.map, wizard.wrap(ctx.input)) { + if let Some(ab_test) = + pick_ab_test(&ctx.primary.map, wizard.wrap(ctx.input, ctx.canvas)) + { let scroller = LogScroller::new_from_lines(ab_test.describe()); *self = ABTestManager::ManageABTest(ab_test, scroller); } else if wizard.aborted() { diff --git a/editor/src/plugins/edit/draw_neighborhoods.rs b/editor/src/plugins/edit/draw_neighborhoods.rs index 6686ed12f4..bc7d228753 100644 --- a/editor/src/plugins/edit/draw_neighborhoods.rs +++ b/editor/src/plugins/edit/draw_neighborhoods.rs @@ -42,7 +42,7 @@ impl Plugin for DrawNeighborhoodState { match self { DrawNeighborhoodState::PickNeighborhood(ref mut wizard) => { - if let Some(n) = pick_neighborhood(map, wizard.wrap(input)) { + if let Some(n) = pick_neighborhood(map, wizard.wrap(input, ctx.canvas)) { *self = DrawNeighborhoodState::EditNeighborhood(n, None); } else if wizard.aborted() { return false; diff --git a/editor/src/plugins/edit/map_edits.rs b/editor/src/plugins/edit/map_edits.rs index 2017cf4ee9..ad4e8e702f 100644 --- a/editor/src/plugins/edit/map_edits.rs +++ b/editor/src/plugins/edit/map_edits.rs @@ -32,7 +32,7 @@ impl Plugin for EditsManager { &ctx.primary.map, &mut new_primary, &ctx.canvas, - self.wizard.wrap(ctx.input), + self.wizard.wrap(ctx.input, ctx.canvas), ) .is_some() { diff --git a/editor/src/plugins/edit/scenarios.rs b/editor/src/plugins/edit/scenarios.rs index 0c36ebd1b7..123de07d54 100644 --- a/editor/src/plugins/edit/scenarios.rs +++ b/editor/src/plugins/edit/scenarios.rs @@ -31,7 +31,7 @@ impl Plugin for ScenarioManager { match self { ScenarioManager::PickScenario(ref mut wizard) => { - if let Some(scenario) = pick_scenario(map, wizard.wrap(input)) { + if let Some(scenario) = pick_scenario(map, wizard.wrap(input, ctx.canvas)) { let scroller = LogScroller::new_from_lines(scenario.describe()); *self = ScenarioManager::ManageScenario(scenario, scroller); } else if wizard.aborted() { @@ -54,7 +54,7 @@ impl Plugin for ScenarioManager { } } ScenarioManager::EditScenario(ref mut scenario, ref mut wizard) => { - if let Some(()) = edit_scenario(map, scenario, wizard.wrap(input)) { + if let Some(()) = edit_scenario(map, scenario, wizard.wrap(input, ctx.canvas)) { let scroller = LogScroller::new_from_lines(scenario.describe()); // TODO autosave, or at least make it clear there are unsaved edits *self = ScenarioManager::ManageScenario(scenario.clone(), scroller); diff --git a/editor/src/plugins/edit/traffic_signal_editor.rs b/editor/src/plugins/edit/traffic_signal_editor.rs index 76e8ea10a3..4240d19e31 100644 --- a/editor/src/plugins/edit/traffic_signal_editor.rs +++ b/editor/src/plugins/edit/traffic_signal_editor.rs @@ -66,7 +66,7 @@ impl Plugin for TrafficSignalEditor { .cycle_duration_wizard .as_mut() .unwrap() - .wrap(input) + .wrap(input, ctx.canvas) .input_usize_prefilled( "How long should this cycle be?", format!( @@ -88,7 +88,7 @@ impl Plugin for TrafficSignalEditor { if let Some(new_signal) = choose_preset( &ctx.primary.map, self.i, - self.preset_wizard.as_mut().unwrap().wrap(input), + self.preset_wizard.as_mut().unwrap().wrap(input, ctx.canvas), ) { ctx.primary.map.edit_traffic_signal(new_signal); self.preset_wizard = None; diff --git a/ezgui/src/input.rs b/ezgui/src/input.rs index 256144421c..663c072e34 100644 --- a/ezgui/src/input.rs +++ b/ezgui/src/input.rs @@ -37,7 +37,7 @@ impl ContextMenu { None, actions .into_iter() - .map(|(hotkey, action)| (hotkey, action, hotkey)) + .map(|(hotkey, action)| (Some(hotkey), action, hotkey)) .collect(), origin, canvas, diff --git a/ezgui/src/menu.rs b/ezgui/src/menu.rs index b7a3a2bccd..40dfad7923 100644 --- a/ezgui/src/menu.rs +++ b/ezgui/src/menu.rs @@ -4,7 +4,7 @@ use geom::{Polygon, Pt2D}; // Stores some associated data with each choice pub struct Menu { prompt: Option, - choices: Vec<(Key, String, T)>, + choices: Vec<(Option, String, T)>, current_idx: Option, origin: Pt2D, @@ -15,7 +15,7 @@ pub struct Menu { impl Menu { pub fn new( prompt: Option, - choices: Vec<(Key, String, T)>, + choices: Vec<(Option, String, T)>, origin: Pt2D, canvas: &Canvas, ) -> Menu { @@ -27,7 +27,11 @@ impl Menu { let mut txt = Text::new(); // TODO prompt for (hotkey, choice, _) in &choices { - txt.add_line(format!("{} - {}", hotkey.describe(), choice)); + if let Some(key) = hotkey { + txt.add_line(format!("{} - {}", key.describe(), choice)); + } else { + txt.add_line(choice.to_string()); + } } let (screen_width, screen_height) = canvas.text_dims(&txt); // Once a menu is created, all other controls (like zooming) are disabled, so this value @@ -113,8 +117,12 @@ impl Menu { } else { None }; - txt.add_styled_line(hotkey.describe(), Color::BLUE, bg); - txt.append(format!(" - {}", choice), text::TEXT_FG_COLOR, bg); + if let Some(key) = hotkey { + txt.add_styled_line(key.describe(), Color::BLUE, bg); + txt.append(format!(" - {}", choice), text::TEXT_FG_COLOR, bg); + } else { + txt.add_styled_line(choice.to_string(), text::TEXT_FG_COLOR, bg); + } } canvas.draw_text_at(g, txt, self.origin); } diff --git a/ezgui/src/wizard.rs b/ezgui/src/wizard.rs index 8986a0a81f..7011894962 100644 --- a/ezgui/src/wizard.rs +++ b/ezgui/src/wizard.rs @@ -1,4 +1,5 @@ -use crate::{Canvas, GfxCtx, InputResult, LogScroller, ScrollingMenu, TextBox, UserInput}; +use crate::menu::Menu; +use crate::{Canvas, GfxCtx, InputResult, Key, LogScroller, TextBox, UserInput}; use abstutil::Cloneable; use log::warn; use std::collections::VecDeque; @@ -6,7 +7,7 @@ use std::collections::VecDeque; pub struct Wizard { alive: bool, tb: Option, - menu: Option>>, + menu: Option>>, log_scroller: Option, // In the order of queries made @@ -36,13 +37,18 @@ impl Wizard { } } - pub fn wrap<'a>(&'a mut self, input: &'a mut UserInput) -> WrappedWizard<'a> { + pub fn wrap<'a>( + &'a mut self, + input: &'a mut UserInput, + canvas: &'a Canvas, + ) -> WrappedWizard<'a> { assert!(self.alive); let ready_results = VecDeque::from(self.confirmed_state.clone()); WrappedWizard { wizard: self, input, + canvas, ready_results, } } @@ -54,7 +60,7 @@ impl Wizard { // The caller can ask for any type at any time pub fn current_menu_choice(&self) -> Option<&R> { if let Some(ref menu) = self.menu { - let item: &R = menu.current_choice().as_any().downcast_ref::()?; + let item: &R = menu.current_choice()?.as_any().downcast_ref::()?; return Some(item); } None @@ -102,6 +108,7 @@ impl Wizard { pub struct WrappedWizard<'a> { wizard: &'a mut Wizard, input: &'a mut UserInput, + canvas: &'a Canvas, // The downcasts are safe iff the queries made to the wizard are deterministic. ready_results: VecDeque>, @@ -201,16 +208,24 @@ impl<'a> WrappedWizard<'a> { )])); return None; } - let boxed_choices: Vec<(String, Box)> = choices + let boxed_choices: Vec<(Option, String, Box)> = choices .iter() - .map(|(s, item)| (s.to_string(), item.clone_box())) + .map(|(s, item)| (None, s.to_string(), item.clone_box())) .collect(); - self.wizard.menu = Some(ScrollingMenu::new(query, boxed_choices)); + self.wizard.menu = Some(Menu::new( + Some(query.to_string()), + boxed_choices, + self.canvas.center_to_map_pt(), + self.canvas, + )); } - if let Some((choice, item)) = - input_with_menu(&mut self.wizard.menu, &mut self.wizard.alive, self.input) - { + if let Some((choice, item)) = input_with_menu( + &mut self.wizard.menu, + &mut self.wizard.alive, + self.input, + self.canvas, + ) { self.wizard .confirmed_state .push(Box::new((choice.to_string(), item.clone()))); @@ -234,9 +249,10 @@ impl<'a> WrappedWizard<'a> { // The caller initializes the menu, if needed. Pass in Option that must be Some(). // Bit weird to be a free function, but need to borrow a different menu and also the alive bit. fn input_with_menu( - menu: &mut Option>, + menu: &mut Option>, alive: &mut bool, input: &mut UserInput, + canvas: &Canvas, ) -> Option<(String, T)> { assert!(*alive); @@ -245,7 +261,8 @@ fn input_with_menu( return None; } - match menu.as_mut().unwrap().event(input) { + let ev = input.use_event_directly().unwrap(); + match menu.as_mut().unwrap().event(ev, canvas) { InputResult::Canceled => { *menu = None; *alive = false;