mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 16:36:02 +03:00
making wizard use the new Menu
This commit is contained in:
parent
3a47cb04e9
commit
2a5384cf11
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -4,7 +4,7 @@ use geom::{Polygon, Pt2D};
|
||||
// Stores some associated data with each choice
|
||||
pub struct Menu<T: Clone> {
|
||||
prompt: Option<String>,
|
||||
choices: Vec<(Key, String, T)>,
|
||||
choices: Vec<(Option<Key>, String, T)>,
|
||||
current_idx: Option<usize>,
|
||||
|
||||
origin: Pt2D,
|
||||
@ -15,7 +15,7 @@ pub struct Menu<T: Clone> {
|
||||
impl<T: Clone> Menu<T> {
|
||||
pub fn new(
|
||||
prompt: Option<String>,
|
||||
choices: Vec<(Key, String, T)>,
|
||||
choices: Vec<(Option<Key>, String, T)>,
|
||||
origin: Pt2D,
|
||||
canvas: &Canvas,
|
||||
) -> Menu<T> {
|
||||
@ -27,7 +27,11 @@ impl<T: Clone> Menu<T> {
|
||||
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<T: Clone> Menu<T> {
|
||||
} 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);
|
||||
}
|
||||
|
@ -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<TextBox>,
|
||||
menu: Option<ScrollingMenu<Box<Cloneable>>>,
|
||||
menu: Option<Menu<Box<Cloneable>>>,
|
||||
log_scroller: Option<LogScroller>,
|
||||
|
||||
// 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<R: 'static + Cloneable>(&self) -> Option<&R> {
|
||||
if let Some(ref menu) = self.menu {
|
||||
let item: &R = menu.current_choice().as_any().downcast_ref::<R>()?;
|
||||
let item: &R = menu.current_choice()?.as_any().downcast_ref::<R>()?;
|
||||
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<Box<Cloneable>>,
|
||||
@ -201,16 +208,24 @@ impl<'a> WrappedWizard<'a> {
|
||||
)]));
|
||||
return None;
|
||||
}
|
||||
let boxed_choices: Vec<(String, Box<Cloneable>)> = choices
|
||||
let boxed_choices: Vec<(Option<Key>, String, Box<Cloneable>)> = 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<T: Clone>(
|
||||
menu: &mut Option<ScrollingMenu<T>>,
|
||||
menu: &mut Option<Menu<T>>,
|
||||
alive: &mut bool,
|
||||
input: &mut UserInput,
|
||||
canvas: &Canvas,
|
||||
) -> Option<(String, T)> {
|
||||
assert!(*alive);
|
||||
|
||||
@ -245,7 +261,8 @@ fn input_with_menu<T: Clone>(
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user