mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 03:35:51 +03:00
stop requiring hotkeys for TopMenu folders
This commit is contained in:
parent
461efe4ef8
commit
e0fd39bb7c
@ -6,7 +6,6 @@ touch `find * | grep '\.rs' | grep -v target | xargs`
|
||||
# TODO Remove all of these exceptions
|
||||
# TODO Report issues for some of these false positives
|
||||
cargo clippy -- \
|
||||
-A clippy::borrowed_box \
|
||||
-A clippy::collapsible_if \
|
||||
-A clippy::cyclomatic_complexity \
|
||||
-A clippy::expect_fun_call \
|
||||
|
@ -9,9 +9,6 @@
|
||||
|
||||
- handle small roads again somehow?
|
||||
- VERY overeager... ate half of the map
|
||||
- can we capture snapshots of incremental changes?
|
||||
- save initial map at every step, be able to load raw + initial with a focus point
|
||||
- generic viewer should be easy... something that stores polygon and ID, wraps the quadtree, etc
|
||||
- deal with loop roads
|
||||
|
||||
- manually draw a picture of the weird intersection to see what would look reasonable. i think we need original road bands from deleted stuff to make decent polygons.
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
## General ezgui stuff
|
||||
|
||||
- trigger screencap from a top menu debug thing WITHOUT a hotkey.
|
||||
- optionally limit canvas scrolling/zooming to some map bounds
|
||||
- T top menu doesnt know when we have a more urgent input thing going!
|
||||
- cant use G for geom debug mode and contextual polygon debug
|
||||
|
@ -25,26 +25,27 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
folders.push(Folder::new(
|
||||
"File",
|
||||
vec![
|
||||
(Key::Comma, "show log console"),
|
||||
(Key::L, "show legend"),
|
||||
(Key::Escape, "quit"),
|
||||
(Some(Key::Comma), "show log console"),
|
||||
(Some(Key::L), "show legend"),
|
||||
(Some(Key::Escape), "quit"),
|
||||
],
|
||||
));
|
||||
if self.state.get_state().enable_debug_controls {
|
||||
folders.push(Folder::new(
|
||||
"Debug",
|
||||
vec![
|
||||
(Key::C, "find chokepoints"),
|
||||
(Key::I, "validate map geometry"),
|
||||
(Key::Num1, "show/hide buildings"),
|
||||
(Key::Num2, "show/hide intersections"),
|
||||
(Key::Num3, "show/hide lanes"),
|
||||
(Key::Num4, "show/hide parcels"),
|
||||
(Key::Num5, "show/hide areas"),
|
||||
(Key::Num6, "show OSM colors"),
|
||||
(Key::Num7, "show/hide extra shapes"),
|
||||
(Key::Num9, "show/hide all turn icons"),
|
||||
(Key::G, "show/hide geometry debug mode"),
|
||||
(None, "screenshot everything"),
|
||||
(None, "find chokepoints"),
|
||||
(None, "validate map geometry"),
|
||||
(Some(Key::Num1), "show/hide buildings"),
|
||||
(Some(Key::Num2), "show/hide intersections"),
|
||||
(Some(Key::Num3), "show/hide lanes"),
|
||||
(Some(Key::Num4), "show/hide parcels"),
|
||||
(Some(Key::Num5), "show/hide areas"),
|
||||
(Some(Key::Num6), "show OSM colors"),
|
||||
(Some(Key::Num7), "show/hide extra shapes"),
|
||||
(Some(Key::Num9), "show/hide all turn icons"),
|
||||
(None, "show/hide geometry debug mode"),
|
||||
],
|
||||
));
|
||||
}
|
||||
@ -52,38 +53,38 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
Folder::new(
|
||||
"Edit",
|
||||
vec![
|
||||
(Key::B, "manage A/B tests"),
|
||||
(Key::Num8, "configure colors"),
|
||||
(Key::N, "manage neighborhoods"),
|
||||
(Key::Q, "manage map edits"),
|
||||
(Key::E, "edit roads"),
|
||||
(Key::W, "manage scenarios"),
|
||||
(Some(Key::B), "manage A/B tests"),
|
||||
(None, "configure colors"),
|
||||
(Some(Key::N), "manage neighborhoods"),
|
||||
(Some(Key::Q), "manage map edits"),
|
||||
(Some(Key::E), "edit roads"),
|
||||
(Some(Key::W), "manage scenarios"),
|
||||
],
|
||||
),
|
||||
Folder::new(
|
||||
"Simulation",
|
||||
vec![
|
||||
(Key::LeftBracket, "slow down sim"),
|
||||
(Key::RightBracket, "speed up sim"),
|
||||
(Key::O, "save sim state"),
|
||||
(Key::Y, "load previous sim state"),
|
||||
(Key::U, "load next sim state"),
|
||||
(Key::Space, "run/pause sim"),
|
||||
(Key::M, "run one step of sim"),
|
||||
(Key::Dot, "show/hide sim info sidepanel"),
|
||||
(Key::T, "start time traveling"),
|
||||
(Key::D, "diff all A/B trips"),
|
||||
(Key::S, "seed the sim with agents"),
|
||||
(Key::LeftAlt, "swap the primary/secondary sim"),
|
||||
(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), "run one step of sim"),
|
||||
(Some(Key::Dot), "show/hide sim info sidepanel"),
|
||||
(Some(Key::T), "start time traveling"),
|
||||
(Some(Key::D), "diff all A/B trips"),
|
||||
(Some(Key::S), "seed the sim with agents"),
|
||||
(Some(Key::LeftAlt), "swap the primary/secondary sim"),
|
||||
],
|
||||
),
|
||||
Folder::new(
|
||||
"View",
|
||||
vec![
|
||||
(Key::Z, "show neighborhood summaries"),
|
||||
(Key::Slash, "search for something"),
|
||||
(Key::A, "show lanes with active traffic"),
|
||||
(Key::J, "warp to an object"),
|
||||
(Some(Key::Z), "show neighborhood summaries"),
|
||||
(Some(Key::Slash), "search for something"),
|
||||
(Some(Key::A), "show lanes with active traffic"),
|
||||
(Some(Key::J), "warp to an object"),
|
||||
],
|
||||
),
|
||||
]);
|
||||
@ -218,10 +219,7 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
ctx.input.populate_osd(&mut hints.osd);
|
||||
|
||||
// TODO a plugin should do this, even though it's such a tiny thing
|
||||
if ctx
|
||||
.input
|
||||
.unimportant_key_pressed(Key::F1, "take screenshot")
|
||||
{
|
||||
if ctx.input.action_chosen("screenshot everything") {
|
||||
let bounds = self.state.get_state().primary.map.get_bounds();
|
||||
assert!(bounds.min_x == 0.0 && bounds.min_y == 0.0);
|
||||
hints.mode = EventLoopMode::ScreenCaptureEverything {
|
||||
|
@ -215,9 +215,13 @@ impl UserInput {
|
||||
}
|
||||
|
||||
if let Some(ref mut menu) = self.top_menu {
|
||||
if let Some(key) = menu.actions.get(action).cloned() {
|
||||
menu.valid_actions.insert(key);
|
||||
self.unimportant_key_pressed(key, action)
|
||||
if let Some(maybe_key) = menu.actions.get(action).cloned() {
|
||||
menu.valid_actions.insert(action.to_string());
|
||||
if let Some(key) = maybe_key {
|
||||
self.unimportant_key_pressed(key, action)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"action_chosen(\"{}\") doesn't match actions in the TopMenu!",
|
||||
@ -291,11 +295,11 @@ impl UserInput {
|
||||
// is semantically correct (think about holding down the key for deleting the current
|
||||
// cycle), but causes annoying flickering.
|
||||
|
||||
if let Some(key) = self.modal_state.modes[mode].get_key(action) {
|
||||
if self.modal_state.modes[mode].get_key(action).is_some() {
|
||||
self.modal_state
|
||||
.mut_active_mode(mode)
|
||||
.unwrap()
|
||||
.mark_active(key);
|
||||
.mark_active(action);
|
||||
// Don't check for the keypress here; Menu's event() will have already processed it
|
||||
// and set chosen_action.
|
||||
false
|
||||
|
@ -234,11 +234,11 @@ impl<T: Clone> Menu<T> {
|
||||
}
|
||||
|
||||
// If there's no matching choice, be silent. The two callers don't care.
|
||||
pub fn mark_active(&mut self, action_key: Key) {
|
||||
for (key, _, ref mut active, _) in self.choices.iter_mut() {
|
||||
if Some(action_key) == *key {
|
||||
pub fn mark_active(&mut self, choice: &str) {
|
||||
for (_, action, ref mut active, _) in self.choices.iter_mut() {
|
||||
if choice == action {
|
||||
if *active {
|
||||
panic!("Menu choice with key {:?} was already active", action_key);
|
||||
panic!("Menu choice for {} was already active", choice);
|
||||
}
|
||||
*active = true;
|
||||
return;
|
||||
|
@ -9,29 +9,31 @@ const HORIZONTAL_PADDING_BETWEEN_ITEMS: f64 = 50.0;
|
||||
|
||||
pub struct TopMenu {
|
||||
folders: Vec<Folder>,
|
||||
pub(crate) actions: HashMap<String, Key>,
|
||||
pub(crate) actions: HashMap<String, Option<Key>>,
|
||||
|
||||
highlighted: Option<usize>,
|
||||
submenu: Option<(usize, Menu<Key>)>,
|
||||
submenu: Option<(usize, Menu<()>)>,
|
||||
// Reset every round
|
||||
pub(crate) valid_actions: HashSet<Key>,
|
||||
pub(crate) valid_actions: HashSet<String>,
|
||||
}
|
||||
|
||||
impl TopMenu {
|
||||
pub fn new(mut folders: Vec<Folder>, canvas: &Canvas) -> TopMenu {
|
||||
let mut keys: HashSet<Key> = HashSet::new();
|
||||
let mut actions: HashMap<String, Key> = HashMap::new();
|
||||
let mut actions: HashMap<String, Option<Key>> = HashMap::new();
|
||||
for f in &folders {
|
||||
for (key, action) in &f.actions {
|
||||
if keys.contains(key) {
|
||||
panic!("TopMenu uses {:?} twice", key);
|
||||
for (maybe_key, action) in &f.actions {
|
||||
if let Some(key) = maybe_key {
|
||||
if keys.contains(key) {
|
||||
panic!("TopMenu uses {:?} twice", key);
|
||||
}
|
||||
keys.insert(*key);
|
||||
}
|
||||
keys.insert(*key);
|
||||
|
||||
if actions.contains_key(action) {
|
||||
panic!("TopMenu assigns \"{:?}\" twice", action);
|
||||
}
|
||||
actions.insert(action.to_string(), *key);
|
||||
actions.insert(action.to_string(), *maybe_key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +61,7 @@ impl TopMenu {
|
||||
|
||||
// Canceled means the top menu isn't blocking input, still active means it is, and done means
|
||||
// something was clicked!
|
||||
pub fn event(&mut self, input: &mut UserInput, canvas: &Canvas) -> InputResult<Key> {
|
||||
pub fn event(&mut self, input: &mut UserInput, canvas: &Canvas) -> InputResult<()> {
|
||||
if let Some(cursor) = input.get_moved_mouse() {
|
||||
// TODO Could quickly filter out by checking y
|
||||
self.highlighted = self
|
||||
@ -81,7 +83,7 @@ impl TopMenu {
|
||||
None,
|
||||
f.actions
|
||||
.iter()
|
||||
.map(|(key, action)| (Some(*key), action.to_string(), *key))
|
||||
.map(|(maybe_key, action)| (*maybe_key, action.to_string(), ()))
|
||||
.collect(),
|
||||
false,
|
||||
Position::TopLeftAt(ScreenPt::new(f.rectangle.x1, f.rectangle.y2)),
|
||||
@ -90,8 +92,8 @@ impl TopMenu {
|
||||
menu.mark_all_inactive();
|
||||
// valid_actions can't change once this submenu is created, so determine what
|
||||
// actions are valid right now.
|
||||
for key in &self.valid_actions {
|
||||
menu.mark_active(*key);
|
||||
for action in &self.valid_actions {
|
||||
menu.mark_active(action);
|
||||
}
|
||||
self.submenu = Some((idx, menu));
|
||||
return InputResult::StillActive;
|
||||
@ -106,10 +108,10 @@ impl TopMenu {
|
||||
self.submenu = None;
|
||||
self.highlighted = None;
|
||||
}
|
||||
InputResult::Done(action, key) => {
|
||||
InputResult::Done(action, _) => {
|
||||
self.submenu = None;
|
||||
self.highlighted = None;
|
||||
return InputResult::Done(action, key);
|
||||
return InputResult::Done(action, ());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -156,13 +158,13 @@ impl TopMenu {
|
||||
|
||||
pub struct Folder {
|
||||
name: String,
|
||||
actions: Vec<(Key, String)>,
|
||||
actions: Vec<(Option<Key>, String)>,
|
||||
|
||||
rectangle: ScreenRectangle,
|
||||
}
|
||||
|
||||
impl Folder {
|
||||
pub fn new(name: &str, actions: Vec<(Key, &str)>) -> Folder {
|
||||
pub fn new(name: &str, actions: Vec<(Option<Key>, &str)>) -> Folder {
|
||||
Folder {
|
||||
name: name.to_string(),
|
||||
actions: actions
|
||||
|
Loading…
Reference in New Issue
Block a user