multiple hotkeys

This commit is contained in:
Dustin Carlino 2020-02-25 14:17:49 -08:00
parent 06759dc58c
commit 64bde1e4a3
16 changed files with 60 additions and 52 deletions

View File

@ -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))
}

View File

@ -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;
}

View File

@ -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};

View File

@ -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;

View File

@ -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),

View File

@ -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),

View File

@ -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
}

View File

@ -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)));
}

View File

@ -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()));
}

View File

@ -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)));
}

View File

@ -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);
}

View File

@ -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)> {

View File

@ -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,
)),

View File

@ -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]),
));
}

View File

@ -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))));
}

View File

@ -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 {