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