mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 16:36:02 +03:00
declaring modal menus
This commit is contained in:
parent
2194ea38a5
commit
bbacdfb676
@ -1,6 +1,6 @@
|
||||
use crate::objects::Ctx;
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use ezgui::{Color, GfxCtx, Key, Text, TOP_RIGHT};
|
||||
use ezgui::{Color, GfxCtx, Text, TOP_RIGHT};
|
||||
use sim::{ScoreSummary, Tick};
|
||||
|
||||
pub enum ShowScoreState {
|
||||
@ -18,15 +18,12 @@ impl Plugin for ShowScoreState {
|
||||
fn ambient_event(&mut self, ctx: &mut PluginCtx) {
|
||||
match self {
|
||||
ShowScoreState::Inactive => {
|
||||
if ctx.input.action_chosen("show sim info sidepanel") {
|
||||
if ctx.input.action_chosen("show/hide sim info sidepanel") {
|
||||
*self = panel(ctx);
|
||||
}
|
||||
}
|
||||
ShowScoreState::Active(last_tick, _) => {
|
||||
if ctx
|
||||
.input
|
||||
.key_pressed(Key::Dot, "Hide the sim info sidepanel")
|
||||
{
|
||||
if ctx.input.action_chosen("show/hide sim info sidepanel") {
|
||||
*self = ShowScoreState::Inactive;
|
||||
} else if *last_tick != ctx.primary.sim.time {
|
||||
*self = panel(ctx);
|
||||
|
@ -5,7 +5,8 @@ use crate::objects::{Ctx, RenderingHints, ID};
|
||||
use crate::render::RenderOptions;
|
||||
use crate::state::UIState;
|
||||
use ezgui::{
|
||||
Canvas, Color, EventLoopMode, Folder, GfxCtx, Key, Text, TopMenu, UserInput, BOTTOM_LEFT, GUI,
|
||||
Canvas, Color, EventLoopMode, Folder, GfxCtx, Key, ModalMenu, Text, TopMenu, UserInput,
|
||||
BOTTOM_LEFT, GUI,
|
||||
};
|
||||
use kml;
|
||||
use map_model::{BuildingID, LaneID};
|
||||
@ -69,7 +70,7 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
(Key::S, "seed the sim with agents"),
|
||||
(Key::Space, "run/pause sim"),
|
||||
(Key::M, "run one step of sim"),
|
||||
(Key::Dot, "show sim info sidepanel"),
|
||||
(Key::Dot, "show/hide sim info sidepanel"),
|
||||
(Key::T, "start time traveling"),
|
||||
],
|
||||
),
|
||||
@ -87,6 +88,81 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
))
|
||||
}
|
||||
|
||||
fn modal_menus() -> Vec<ModalMenu> {
|
||||
vec![
|
||||
ModalMenu::new(
|
||||
"Traffic Signal Editor",
|
||||
vec![
|
||||
(Key::Enter, "quit"),
|
||||
(Key::D, "change cycle duration"),
|
||||
(Key::P, "choose a preset signal"),
|
||||
(Key::K, "move current cycle up"),
|
||||
(Key::J, "move current cycle down"),
|
||||
(Key::Backspace, "delete current cycle"),
|
||||
(Key::N, "add a new empty cycle"),
|
||||
(Key::M, "add a new pedestrian scramble cycle"),
|
||||
],
|
||||
),
|
||||
ModalMenu::new(
|
||||
"Scenario Editor",
|
||||
vec![(Key::Q, "save"), (Key::E, "edit"), (Key::I, "instantiate")],
|
||||
),
|
||||
ModalMenu::new("Road Editor", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new(
|
||||
"Color Picker",
|
||||
vec![
|
||||
(Key::Backspace, "revert color"),
|
||||
(Key::Enter, "finalize color"),
|
||||
],
|
||||
),
|
||||
ModalMenu::new(
|
||||
"Stop Sign Editor",
|
||||
vec![(Key::Enter, "quit"), (Key::R, "reset to default")],
|
||||
),
|
||||
ModalMenu::new("A/B Test Editor", vec![(Key::R, "run A/B test")]),
|
||||
ModalMenu::new(
|
||||
"Neighborhood Editor",
|
||||
vec![
|
||||
// TODO one key for save XOR quit, based on internal state...
|
||||
(Key::Enter, "save and quit"),
|
||||
(Key::X, "export as an Osmosis polygon filter"),
|
||||
(Key::P, "add a new point"),
|
||||
],
|
||||
),
|
||||
ModalMenu::new(
|
||||
"Time Traveler",
|
||||
vec![
|
||||
(Key::Enter, "quit"),
|
||||
(Key::Comma, "rewind"),
|
||||
(Key::Dot, "forwards"),
|
||||
],
|
||||
),
|
||||
ModalMenu::new(
|
||||
"Geometry Debugger",
|
||||
vec![(Key::Enter, "quit"), (Key::N, "see next problem")],
|
||||
),
|
||||
ModalMenu::new("OSM Classifier", vec![(Key::Num6, "quit")]),
|
||||
ModalMenu::new(
|
||||
"Floodfiller",
|
||||
vec![
|
||||
(Key::Space, "step forwards"),
|
||||
(Key::Tab, "finish floodfilling"),
|
||||
],
|
||||
),
|
||||
ModalMenu::new("Chokepoints Debugger", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new("A/B Trip Explorer", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new("A/B All Trips Explorer", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new("Agent Follower", vec![(Key::F, "quit")]),
|
||||
ModalMenu::new("Search", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new("Neighborhood Summaries", vec![(Key::Z, "quit")]),
|
||||
ModalMenu::new(
|
||||
"Agent Route Debugger",
|
||||
vec![(Key::R, "quit"), (Key::L, "show/hide all agents' routes")],
|
||||
),
|
||||
ModalMenu::new("Active Traffic Visualizer", vec![(Key::A, "quit")]),
|
||||
]
|
||||
}
|
||||
|
||||
fn event(&mut self, input: &mut UserInput) -> (EventLoopMode, RenderingHints) {
|
||||
let mut hints = RenderingHints {
|
||||
mode: EventLoopMode::InputOnly,
|
||||
|
@ -2,7 +2,7 @@ use crate::menu::{Menu, Position};
|
||||
use crate::top_menu::TopMenu;
|
||||
use crate::{Canvas, Event, InputResult, Key, Text};
|
||||
use geom::Pt2D;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
// As we check for user input, record the input and the thing that would happen. This will let us
|
||||
// build up some kind of OSD of possible actions.
|
||||
@ -400,3 +400,34 @@ impl UserInput {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModalMenu {
|
||||
pub(crate) name: String,
|
||||
pub(crate) actions: Vec<(Key, String)>,
|
||||
}
|
||||
|
||||
impl ModalMenu {
|
||||
pub fn new(name: &str, raw_actions: Vec<(Key, &str)>) -> ModalMenu {
|
||||
let mut keys: HashSet<Key> = HashSet::new();
|
||||
let mut action_names: HashSet<String> = HashSet::new();
|
||||
let mut actions = Vec::new();
|
||||
for (key, action) in raw_actions {
|
||||
if keys.contains(&key) {
|
||||
panic!("ModalMenu {} uses {:?} twice", name, key);
|
||||
}
|
||||
keys.insert(key);
|
||||
|
||||
if action_names.contains(action) {
|
||||
panic!("ModalMenu {} defines \"{}\" twice", name, action);
|
||||
}
|
||||
action_names.insert(action.to_string());
|
||||
|
||||
actions.push((key, action.to_string()));
|
||||
}
|
||||
|
||||
ModalMenu {
|
||||
name: name.to_string(),
|
||||
actions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ pub use crate::canvas::{
|
||||
};
|
||||
pub use crate::color::Color;
|
||||
pub use crate::event::{Event, Key};
|
||||
pub use crate::input::UserInput;
|
||||
pub use crate::input::{ModalMenu, UserInput};
|
||||
pub use crate::log_scroller::LogScroller;
|
||||
pub use crate::runner::{run, EventLoopMode, GUI};
|
||||
pub use crate::scrolling_menu::ScrollingMenu;
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::input::ContextMenu;
|
||||
use crate::{Canvas, Event, GfxCtx, TopMenu, UserInput};
|
||||
use crate::{Canvas, Event, GfxCtx, ModalMenu, TopMenu, UserInput};
|
||||
use glutin_window::GlutinWindow;
|
||||
use opengl_graphics::{GlGraphics, OpenGL};
|
||||
use piston::event_loop::{EventLoop, EventSettings, Events};
|
||||
use piston::window::{Window, WindowSettings};
|
||||
use std::collections::HashMap;
|
||||
use std::{panic, process};
|
||||
|
||||
pub trait GUI<T> {
|
||||
@ -11,6 +12,9 @@ pub trait GUI<T> {
|
||||
fn top_menu(_canvas: &Canvas) -> Option<TopMenu> {
|
||||
None
|
||||
}
|
||||
fn modal_menus() -> Vec<ModalMenu> {
|
||||
Vec::new()
|
||||
}
|
||||
fn event(&mut self, input: &mut UserInput) -> (EventLoopMode, T);
|
||||
fn get_mut_canvas(&mut self) -> &mut Canvas;
|
||||
fn draw(&self, g: &mut GfxCtx, data: &T);
|
||||
@ -38,10 +42,16 @@ pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str, initial_width: u32, ini
|
||||
let mut events = Events::new(EventSettings::new().lazy(true));
|
||||
let mut gl = GlGraphics::new(opengl);
|
||||
|
||||
// TODO Probably time to bundle this state up. :)
|
||||
let mut last_event_mode = EventLoopMode::InputOnly;
|
||||
let mut context_menu = ContextMenu::Inactive;
|
||||
let mut top_menu = G::top_menu(gui.get_mut_canvas());
|
||||
let modal_menus: HashMap<String, ModalMenu> = G::modal_menus()
|
||||
.into_iter()
|
||||
.map(|m| (m.name.clone(), m))
|
||||
.collect();
|
||||
let mut last_data: Option<T> = None;
|
||||
|
||||
while let Some(ev) = events.next(&mut window) {
|
||||
use piston::input::{CloseEvent, RenderEvent};
|
||||
if let Some(args) = ev.render_args() {
|
||||
|
Loading…
Reference in New Issue
Block a user