mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
multiple hotkeys
This commit is contained in:
parent
06759dc58c
commit
64bde1e4a3
@ -366,27 +366,36 @@ impl Key {
|
||||
}
|
||||
|
||||
// TODO This is not an ideal representation at all.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct MultiKey {
|
||||
pub key: Key,
|
||||
pub lctrl: bool,
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub enum MultiKey {
|
||||
Normal(Key),
|
||||
LCtrl(Key),
|
||||
Any(Vec<Key>),
|
||||
}
|
||||
|
||||
impl MultiKey {
|
||||
pub fn describe(self) -> String {
|
||||
if self.lctrl {
|
||||
format!("Ctrl+{}", self.key.describe())
|
||||
} else {
|
||||
self.key.describe()
|
||||
pub fn describe(&self) -> String {
|
||||
match self {
|
||||
MultiKey::Normal(key) => key.describe(),
|
||||
MultiKey::LCtrl(key) => format!("Ctrl+{}", key.describe()),
|
||||
MultiKey::Any(ref keys) => keys
|
||||
.iter()
|
||||
.map(|k| k.describe())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For easy ModalMenu construction
|
||||
pub fn hotkey(key: Key) -> Option<MultiKey> {
|
||||
Some(MultiKey { key, lctrl: false })
|
||||
Some(MultiKey::Normal(key))
|
||||
}
|
||||
|
||||
pub fn lctrl(key: Key) -> Option<MultiKey> {
|
||||
Some(MultiKey { key, lctrl: true })
|
||||
Some(MultiKey::LCtrl(key))
|
||||
}
|
||||
|
||||
pub fn hotkeys(keys: Vec<Key>) -> Option<MultiKey> {
|
||||
Some(MultiKey::Any(keys))
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{hotkey, lctrl, text, Canvas, Event, Key, Line, MultiKey, ScreenPt, Text};
|
||||
use crate::{text, Canvas, Event, Key, Line, MultiKey, ScreenPt, Text};
|
||||
use geom::Duration;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -55,7 +55,7 @@ impl UserInput {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn new_was_pressed(&mut self, multikey: MultiKey) -> bool {
|
||||
pub fn new_was_pressed(&mut self, multikey: &MultiKey) -> bool {
|
||||
// TODO Reserve?
|
||||
|
||||
if self.event_consumed {
|
||||
@ -63,13 +63,12 @@ impl UserInput {
|
||||
}
|
||||
|
||||
if let Event::KeyPress(pressed) = self.event {
|
||||
let mk = if self.lctrl_held {
|
||||
lctrl(pressed)
|
||||
} else {
|
||||
hotkey(pressed)
|
||||
}
|
||||
.unwrap();
|
||||
if mk == multikey {
|
||||
let same = match multikey {
|
||||
MultiKey::Normal(key) => pressed == *key && !self.lctrl_held,
|
||||
MultiKey::LCtrl(key) => pressed == *key && self.lctrl_held,
|
||||
MultiKey::Any(ref keys) => !self.lctrl_held && keys.contains(&pressed),
|
||||
};
|
||||
if same {
|
||||
self.consume_event();
|
||||
return true;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ pub use crate::backend::Drawable;
|
||||
pub use crate::canvas::{Canvas, HorizontalAlignment, VerticalAlignment};
|
||||
pub use crate::color::Color;
|
||||
pub use crate::drawing::{GeomBatch, GfxCtx, Prerender, RewriteColor};
|
||||
pub use crate::event::{hotkey, lctrl, Event, Key, MultiKey};
|
||||
pub use crate::event::{hotkey, hotkeys, lctrl, Event, Key, MultiKey};
|
||||
pub use crate::event_ctx::EventCtx;
|
||||
pub use crate::input::UserInput;
|
||||
pub use crate::managed::{Composite, ManagedWidget, Outcome};
|
||||
|
@ -44,8 +44,7 @@ impl Button {
|
||||
|
||||
draw_normal: ctx.upload(normal),
|
||||
draw_hovered: ctx.upload(hovered),
|
||||
hotkey,
|
||||
tooltip: if let Some(key) = hotkey {
|
||||
tooltip: if let Some(ref key) = hotkey {
|
||||
let mut txt =
|
||||
Text::from(Line(key.describe()).fg(text::HOTKEY_COLOR).size(20)).with_bg();
|
||||
txt.append(Line(format!(" - {}", tooltip)));
|
||||
@ -53,6 +52,7 @@ impl Button {
|
||||
} else {
|
||||
Text::from(Line(tooltip).size(20)).with_bg()
|
||||
},
|
||||
hotkey,
|
||||
hitbox,
|
||||
|
||||
hovering: false,
|
||||
@ -89,7 +89,7 @@ impl Button {
|
||||
self.hovering = false;
|
||||
}
|
||||
|
||||
if let Some(hotkey) = self.hotkey {
|
||||
if let Some(ref hotkey) = self.hotkey {
|
||||
if ctx.input.new_was_pressed(hotkey) {
|
||||
self.clicked = true;
|
||||
self.hovering = false;
|
||||
|
@ -113,7 +113,7 @@ impl ModalMenu {
|
||||
if !choice.active {
|
||||
continue;
|
||||
}
|
||||
if let Some(hotkey) = choice.hotkey {
|
||||
if let Some(ref hotkey) = choice.hotkey {
|
||||
if ctx.input.new_was_pressed(hotkey) {
|
||||
self.chosen_action = Some(choice.label.clone());
|
||||
break;
|
||||
@ -214,7 +214,7 @@ impl ModalMenu {
|
||||
|
||||
for (idx, choice) in self.choices.iter().enumerate() {
|
||||
if choice.active {
|
||||
if let Some(key) = choice.hotkey {
|
||||
if let Some(ref key) = choice.hotkey {
|
||||
txt.add_appended(vec![
|
||||
Line(key.describe()).fg(text::HOTKEY_COLOR),
|
||||
Line(format!(" - {}", choice.label)),
|
||||
@ -228,7 +228,7 @@ impl ModalMenu {
|
||||
txt.highlight_last_line(text::SELECTED_COLOR);
|
||||
}
|
||||
} else {
|
||||
if let Some(key) = choice.hotkey {
|
||||
if let Some(ref key) = choice.hotkey {
|
||||
txt.add(
|
||||
Line(format!("{} - {}", key.describe(), choice.label))
|
||||
.fg(text::INACTIVE_CHOICE_COLOR),
|
||||
|
@ -89,7 +89,7 @@ impl<T: Clone> PopupMenu<T> {
|
||||
if !choice.active {
|
||||
continue;
|
||||
}
|
||||
if let Some(hotkey) = choice.hotkey {
|
||||
if let Some(ref hotkey) = choice.hotkey {
|
||||
if ctx.input.new_was_pressed(hotkey) {
|
||||
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
return;
|
||||
@ -98,7 +98,7 @@ impl<T: Clone> PopupMenu<T> {
|
||||
}
|
||||
|
||||
// Handle nav keys
|
||||
if ctx.input.new_was_pressed(hotkey(Key::Enter).unwrap()) {
|
||||
if ctx.input.new_was_pressed(&hotkey(Key::Enter).unwrap()) {
|
||||
let choice = &self.choices[self.current_idx];
|
||||
if choice.active {
|
||||
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
@ -106,11 +106,11 @@ impl<T: Clone> PopupMenu<T> {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if ctx.input.new_was_pressed(hotkey(Key::UpArrow).unwrap()) {
|
||||
} else if ctx.input.new_was_pressed(&hotkey(Key::UpArrow).unwrap()) {
|
||||
if self.current_idx > 0 {
|
||||
self.current_idx -= 1;
|
||||
}
|
||||
} else if ctx.input.new_was_pressed(hotkey(Key::DownArrow).unwrap()) {
|
||||
} else if ctx.input.new_was_pressed(&hotkey(Key::DownArrow).unwrap()) {
|
||||
if self.current_idx < self.choices.len() - 1 {
|
||||
self.current_idx += 1;
|
||||
}
|
||||
@ -149,7 +149,7 @@ impl<T: Clone> PopupMenu<T> {
|
||||
|
||||
for (idx, choice) in self.choices.iter().enumerate() {
|
||||
if choice.active {
|
||||
if let Some(key) = choice.hotkey {
|
||||
if let Some(ref key) = choice.hotkey {
|
||||
txt.add_appended(vec![
|
||||
Line(key.describe()).fg(text::HOTKEY_COLOR),
|
||||
Line(format!(" - {}", choice.label)),
|
||||
@ -158,7 +158,7 @@ impl<T: Clone> PopupMenu<T> {
|
||||
txt.add(Line(&choice.label));
|
||||
}
|
||||
} else {
|
||||
if let Some(key) = choice.hotkey {
|
||||
if let Some(ref key) = choice.hotkey {
|
||||
txt.add(
|
||||
Line(format!("{} - {}", key.describe(), choice.label))
|
||||
.fg(text::INACTIVE_CHOICE_COLOR),
|
||||
|
@ -487,7 +487,7 @@ impl<T: Clone> Choice<T> {
|
||||
|
||||
pub fn key(mut self, key: Key) -> Choice<T> {
|
||||
assert_eq!(self.hotkey, None);
|
||||
self.hotkey = Some(MultiKey { key, lctrl: false });
|
||||
self.hotkey = hotkey(key);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ impl State for ABTestMode {
|
||||
ui.recalculate_current_selection(ctx);
|
||||
}
|
||||
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(lctrl(Key::D).unwrap()) {
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(&lctrl(Key::D).unwrap()) {
|
||||
return Transition::Push(Box::new(DebugMode::new(ctx)));
|
||||
}
|
||||
|
||||
|
@ -48,10 +48,10 @@ impl CommonState {
|
||||
ui: &mut UI,
|
||||
maybe_speed: Option<&mut SpeedControls>,
|
||||
) -> Option<Transition> {
|
||||
if ctx.input.new_was_pressed(lctrl(Key::S).unwrap()) {
|
||||
if ctx.input.new_was_pressed(&lctrl(Key::S).unwrap()) {
|
||||
ui.opts.dev = !ui.opts.dev;
|
||||
}
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(lctrl(Key::J).unwrap()) {
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(&lctrl(Key::J).unwrap()) {
|
||||
return Some(Transition::Push(warp::EnteringWarp::new()));
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ impl State for EditMode {
|
||||
}
|
||||
}
|
||||
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(lctrl(Key::D).unwrap()) {
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(&lctrl(Key::D).unwrap()) {
|
||||
return Transition::Push(Box::new(DebugMode::new(ctx)));
|
||||
}
|
||||
|
||||
|
@ -79,12 +79,12 @@ impl State for TrafficSignalEditor {
|
||||
ctx.canvas_movement();
|
||||
|
||||
// TODO Buttons for these...
|
||||
if self.current_phase != 0 && ctx.input.new_was_pressed(hotkey(Key::UpArrow).unwrap()) {
|
||||
if self.current_phase != 0 && ctx.input.new_was_pressed(&hotkey(Key::UpArrow).unwrap()) {
|
||||
self.change_phase(self.current_phase - 1, ui, ctx);
|
||||
}
|
||||
|
||||
if self.current_phase != ui.primary.map.get_traffic_signal(self.i).phases.len() - 1
|
||||
&& ctx.input.new_was_pressed(hotkey(Key::DownArrow).unwrap())
|
||||
&& ctx.input.new_was_pressed(&hotkey(Key::DownArrow).unwrap())
|
||||
{
|
||||
self.change_phase(self.current_phase + 1, ui, ctx);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ impl PerObjectActions {
|
||||
if !(key == Key::I && lbl == "show info") {
|
||||
self.actions.borrow_mut().push((key, lbl));
|
||||
}
|
||||
!self.info_panel_open && ctx.input.new_was_pressed(hotkey(key).unwrap())
|
||||
!self.info_panel_open && ctx.input.new_was_pressed(&hotkey(key).unwrap())
|
||||
}
|
||||
|
||||
pub fn consume(&mut self) -> Vec<(Key, String)> {
|
||||
|
@ -7,8 +7,8 @@ use crate::mission::MissionEditMode;
|
||||
use crate::sandbox::{GameplayMode, SandboxMode, TutorialPointer};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{
|
||||
hotkey, Button, Color, Composite, EventCtx, EventLoopMode, GfxCtx, JustDraw, Key, Line,
|
||||
ManagedWidget, Text,
|
||||
hotkey, hotkeys, Button, Color, Composite, EventCtx, EventLoopMode, GfxCtx, JustDraw, Key,
|
||||
Line, ManagedWidget, Text,
|
||||
};
|
||||
use geom::{Duration, Line, Pt2D, Speed};
|
||||
use instant::Instant;
|
||||
@ -37,7 +37,7 @@ impl TitleScreen {
|
||||
Text::from(Line("PLAY")),
|
||||
Color::BLUE,
|
||||
colors::HOVERING,
|
||||
hotkey(Key::Space),
|
||||
hotkeys(vec![Key::Space, Key::Enter]),
|
||||
"start game",
|
||||
ctx,
|
||||
)),
|
||||
|
@ -12,8 +12,9 @@ use crate::sandbox::{
|
||||
use crate::ui::UI;
|
||||
use abstutil::Timer;
|
||||
use ezgui::{
|
||||
hotkey, lctrl, Button, Color, Composite, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key,
|
||||
Line, ManagedWidget, Outcome, RewriteColor, ScreenPt, Text, VerticalAlignment,
|
||||
hotkey, hotkeys, lctrl, Button, Color, Composite, EventCtx, GeomBatch, GfxCtx,
|
||||
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, ScreenPt, Text,
|
||||
VerticalAlignment,
|
||||
};
|
||||
use geom::{Distance, Duration, PolyLine, Polygon, Pt2D, Statistic, Time};
|
||||
use map_model::{BuildingID, IntersectionID, IntersectionType, LaneType, Map, RoadID};
|
||||
@ -1027,8 +1028,7 @@ impl TutorialState {
|
||||
ctx,
|
||||
"../data/system/assets/tools/next.svg",
|
||||
"next message",
|
||||
// TODO Or space or enter
|
||||
hotkey(Key::RightArrow),
|
||||
hotkeys(vec![Key::RightArrow, Key::Space, Key::Enter]),
|
||||
)
|
||||
}
|
||||
.margin(5),
|
||||
@ -1038,7 +1038,7 @@ impl TutorialState {
|
||||
col.push(WrappedComposite::text_bg_button(
|
||||
ctx,
|
||||
"Try it",
|
||||
hotkey(Key::RightArrow),
|
||||
hotkeys(vec![Key::RightArrow, Key::Space, Key::Enter]),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl SandboxMode {
|
||||
}
|
||||
|
||||
fn examine_objects(&self, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transition> {
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(lctrl(Key::D).unwrap()) {
|
||||
if ui.opts.dev && ctx.input.new_was_pressed(&lctrl(Key::D).unwrap()) {
|
||||
return Some(Transition::Push(Box::new(DebugMode::new(ctx))));
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,7 @@ impl SpeedControls {
|
||||
None => {}
|
||||
}
|
||||
|
||||
if ctx.input.new_was_pressed(hotkey(Key::LeftArrow).unwrap()) {
|
||||
if ctx.input.new_was_pressed(&hotkey(Key::LeftArrow).unwrap()) {
|
||||
match self.setting {
|
||||
SpeedSetting::Realtime => self.pause(ctx),
|
||||
SpeedSetting::Fast => {
|
||||
@ -262,7 +262,7 @@ impl SpeedControls {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ctx.input.new_was_pressed(hotkey(Key::RightArrow).unwrap()) {
|
||||
if ctx.input.new_was_pressed(&hotkey(Key::RightArrow).unwrap()) {
|
||||
match self.setting {
|
||||
SpeedSetting::Realtime => {
|
||||
if self.paused {
|
||||
|
Loading…
Reference in New Issue
Block a user