dont repeat keypress manually in OSD message

This commit is contained in:
Dustin Carlino 2018-07-26 13:56:23 -07:00
parent d5f002e35c
commit 3fa06fd032
19 changed files with 130 additions and 155 deletions

View File

@ -25,8 +25,6 @@
- be able to change road directions
- basic road edits
- apply edits to live map and recompute everything needed
- multiple edits to a road should work
- tests that edits + reload from scratch are equivalent
- undo support!

View File

@ -42,7 +42,7 @@ impl UI {
impl gui::GUI for UI {
fn event(&mut self, input: &mut UserInput) -> gui::EventLoopMode {
if input.unimportant_key_pressed(Key::Escape, "Press escape to quit") {
if input.unimportant_key_pressed(Key::Escape, "quit") {
process::exit(0);
}
let speed = 5.0;

View File

@ -18,9 +18,9 @@ impl OsmClassifier {
pub fn handle_event(&mut self, input: &mut UserInput) -> bool {
let msg = if self.active {
"Press 6 to stop showing OSM classes"
"stop showing OSM classes"
} else {
"Press 6 to show OSM classifications"
"to show OSM classifications"
};
if input.unimportant_key_pressed(Key::D6, msg) {
self.active = !self.active;

View File

@ -38,7 +38,7 @@ impl ColorPicker {
let mut new_state: Option<ColorPicker> = None;
let active = match self {
ColorPicker::Inactive => {
if input.unimportant_key_pressed(Key::D8, "Press 8 to configure colors") {
if input.unimportant_key_pressed(Key::D8, "configure colors") {
new_state = Some(ColorPicker::Choosing(menu::Menu::new(
Colors::iter().map(|c| c.to_string()).collect(),
)));
@ -64,17 +64,12 @@ impl ColorPicker {
ColorPicker::PickingColor(c, orig_color) => {
if input.key_pressed(
Key::Escape,
&format!(
"Press escape to stop configuring color for {:?} and revert",
c
),
&format!("stop configuring color for {:?} and revert", c),
) {
cs.set(*c, *orig_color);
new_state = Some(ColorPicker::Inactive);
} else if input.key_pressed(
Key::Return,
&format!("Press enter to finalize new color for {:?}", c),
) {
} else if input.key_pressed(Key::Return, &format!("finalize new color for {:?}", c))
{
println!("Setting color for {:?}", c);
new_state = Some(ColorPicker::Inactive);
}

View File

@ -41,13 +41,13 @@ impl Floodfiller {
let active = match self {
Floodfiller::Inactive => false,
Floodfiller::Active { visited, queue } => {
if input.key_pressed(Key::Return, "Press Enter to quit floodfilling") {
if input.key_pressed(Key::Return, "quit floodfilling") {
new_state = Some(Floodfiller::Inactive);
} else if !queue.is_empty() {
if input.key_pressed(Key::Space, "Press space to step floodfilling forwards") {
if input.key_pressed(Key::Space, "step floodfilling forwards") {
step(visited, queue, map);
}
if input.key_pressed(Key::Tab, "Press tab to floodfill the rest of the map") {
if input.key_pressed(Key::Tab, "floodfill the rest of the map") {
loop {
if step(visited, queue, map) {
break;

View File

@ -102,9 +102,7 @@ impl Validator {
current_problem,
} => {
// Initialize or advance?
if !current_problem.is_some()
|| input.key_pressed(Key::N, "Press N to see the next problem")
{
if !current_problem.is_some() || input.key_pressed(Key::N, "see the next problem") {
// TODO do this in a bg thread or something
*current_problem = gen.next();
@ -117,8 +115,7 @@ impl Validator {
println!("No more problems!");
new_state = Some(Validator::Inactive);
}
} else if input.key_pressed(Key::Escape, "Press Escape to stop looking at problems")
{
} else if input.key_pressed(Key::Escape, "stop looking at problems") {
println!("Quit geometry validator");
new_state = Some(Validator::Inactive);
}

View File

@ -41,7 +41,7 @@ impl RoadEditor {
_ => false,
},
RoadEditor::Active(edits) => {
if input.key_pressed(Key::Return, "Press enter to stop editing roads") {
if input.key_pressed(Key::Return, "stop editing roads") {
new_state = Some(RoadEditor::Inactive(edits.clone()));
} else if let SelectionState::SelectedLane(id, _) = *current_selection {
let lane = map.get_l(id);
@ -49,27 +49,27 @@ impl RoadEditor {
let reason = EditReason::BasemapWrong; // TODO be able to choose
if lane.lane_type != LaneType::Driving
&& input.key_pressed(Key::D, "Press D to make this a driving lane")
&& input.key_pressed(Key::D, "make this a driving lane")
{
if edits.change_lane_type(reason, road, lane, LaneType::Driving) {
changed = Some((lane.id, LaneType::Driving));
}
}
if lane.lane_type != LaneType::Parking
&& input.key_pressed(Key::P, "Press p to make this a parking lane")
&& input.key_pressed(Key::P, "make this a parking lane")
{
if edits.change_lane_type(reason, road, lane, LaneType::Parking) {
changed = Some((lane.id, LaneType::Parking));
}
}
if lane.lane_type != LaneType::Biking
&& input.key_pressed(Key::B, "Press b to make this a bike lane")
&& input.key_pressed(Key::B, "make this a bike lane")
{
if edits.change_lane_type(reason, road, lane, LaneType::Biking) {
changed = Some((lane.id, LaneType::Biking));
}
}
if input.key_pressed(Key::Backspace, "Press backspace to delete this lane") {
if input.key_pressed(Key::Backspace, "delete this lane") {
if edits.delete_lane(road, lane) {
println!("Have to reload the map from scratch to pick up this change!");
}

View File

@ -42,7 +42,7 @@ impl SearchState {
let mut new_state: Option<SearchState> = None;
let active = match self {
SearchState::Empty => {
if input.unimportant_key_pressed(Key::Slash, "Press / to start searching") {
if input.unimportant_key_pressed(Key::Slash, "start searching") {
new_state = Some(SearchState::EnteringSearch(TextBox::new()));
true
} else {
@ -59,7 +59,7 @@ impl SearchState {
SearchState::FilterOSM(filter) => {
if input.key_pressed(
Key::Return,
&format!("Press enter to clear the current search for {}", filter),
&format!("clear the current search for {}", filter),
) {
new_state = Some(SearchState::Empty);
}

View File

@ -68,16 +68,14 @@ impl SelectionState {
) {
new_state = Some(SelectionState::TooltipLane(*id));
true
} else if input
.key_pressed(Key::Tab, "Press Tab to cycle through this lane's turns")
{
} else if input.key_pressed(Key::Tab, "cycle through this lane's turns") {
let idx = match *current_turn_index {
Some(i) => i + 1,
None => 0,
};
new_state = Some(SelectionState::SelectedLane(*id, Some(idx)));
true
} else if input.key_pressed(Key::D, "press D to debug") {
} else if input.key_pressed(Key::D, "debug") {
map.get_l(*id).dump_debug();
true
} else {
@ -213,7 +211,7 @@ impl Hider {
}
pub fn event(&mut self, input: &mut UserInput, state: &mut SelectionState) -> bool {
if input.unimportant_key_pressed(Key::K, "Press k to unhide everything") {
if input.unimportant_key_pressed(Key::K, "unhide everything") {
println!("Unhiding {} things", self.items.len());
self.items.clear();
return true;
@ -226,7 +224,7 @@ impl Hider {
_ => None,
};
if let Some(id) = item {
if input.unimportant_key_pressed(Key::H, &format!("Press h to hide {:?}", id)) {
if input.unimportant_key_pressed(Key::H, &format!("hide {:?}", id)) {
self.items.insert(id);
println!("Hiding {:?}", id);
*state = SelectionState::Empty;

View File

@ -33,31 +33,31 @@ impl SimController {
// true if the sim is running
pub fn event(&mut self, input: &mut UserInput, map: &Map, control_map: &ControlMap) -> bool {
if input.unimportant_key_pressed(Key::LeftBracket, "Press [ to slow down sim") {
if input.unimportant_key_pressed(Key::LeftBracket, "slow down sim") {
self.desired_speed -= ADJUST_SPEED;
self.desired_speed = self.desired_speed.max(0.0);
}
if input.unimportant_key_pressed(Key::RightBracket, "Press ] to speed up sim") {
if input.unimportant_key_pressed(Key::RightBracket, "speed up sim") {
self.desired_speed += ADJUST_SPEED;
}
if input.unimportant_key_pressed(Key::O, "Press O to save sim state") {
if input.unimportant_key_pressed(Key::O, "save sim state") {
abstutil::write_json("sim_state", &self.sim).expect("Writing sim state failed");
println!("Wrote sim_state");
}
if input.unimportant_key_pressed(Key::P, "Press P to load sim state") {
if input.unimportant_key_pressed(Key::P, "load sim state") {
self.sim = abstutil::read_json("sim_state").expect("sim state failed");
}
if self.last_step.is_some() {
if input.unimportant_key_pressed(Key::Space, "Press space to pause sim") {
if input.unimportant_key_pressed(Key::Space, "pause sim") {
self.last_step = None;
self.benchmark = None;
self.sim_speed = String::from("paused");
}
} else {
if input.unimportant_key_pressed(Key::Space, "Press space to run sim") {
if input.unimportant_key_pressed(Key::Space, "run sim") {
self.last_step = Some(Instant::now());
self.benchmark = Some(self.sim.start_benchmark());
} else if input.unimportant_key_pressed(Key::M, "press M to run one step") {
} else if input.unimportant_key_pressed(Key::M, "run one step") {
self.sim.step(map, control_map);
}
}

View File

@ -35,9 +35,9 @@ impl SteepnessVisualizer {
pub fn handle_event(&mut self, input: &mut UserInput) -> bool {
let msg = if self.active {
"Press 5 to stop showing steepness"
"stop showing steepness"
} else {
"Press 5 to visualize steepness"
"visualize steepness"
};
if input.unimportant_key_pressed(Key::D5, msg) {
self.active = !self.active;

View File

@ -35,45 +35,37 @@ impl StopSignEditor {
let active = match self {
StopSignEditor::Inactive => false,
StopSignEditor::Active(i) => {
if input.key_pressed(Key::Return, "Press enter to quit the editor") {
if input.key_pressed(Key::Return, "quit the editor") {
new_state = Some(StopSignEditor::Inactive);
} else if let SelectionState::SelectedTurn(id) = *current_selection {
if map.get_t(id).parent == *i {
let sign = &mut control_map.stop_signs.get_mut(i).unwrap();
match sign.get_priority(id) {
TurnPriority::Priority => {
if input.key_pressed(Key::D2, "Press 2 to make this turn yield") {
if input.key_pressed(Key::D2, "make this turn yield") {
sign.set_priority(id, TurnPriority::Yield, map);
}
if input
.key_pressed(Key::D3, "Press 3 to make this turn always stop")
{
if input.key_pressed(Key::D3, "make this turn always stop") {
sign.set_priority(id, TurnPriority::Stop, map);
}
}
TurnPriority::Yield => {
if sign.could_be_priority_turn(id, map)
&& input.key_pressed(
Key::D1,
"Press 1 to let this turn go immediately",
) {
&& input.key_pressed(Key::D1, "let this turn go immediately")
{
sign.set_priority(id, TurnPriority::Priority, map);
}
if input
.key_pressed(Key::D3, "Press 3 to make this turn always stop")
{
if input.key_pressed(Key::D3, "make this turn always stop") {
sign.set_priority(id, TurnPriority::Stop, map);
}
}
TurnPriority::Stop => {
if sign.could_be_priority_turn(id, map)
&& input.key_pressed(
Key::D1,
"Press 1 to let this turn go immediately",
) {
&& input.key_pressed(Key::D1, "let this turn go immediately")
{
sign.set_priority(id, TurnPriority::Priority, map);
}
if input.key_pressed(Key::D2, "Press 2 to make this turn yield") {
if input.key_pressed(Key::D2, "make this turn yield") {
sign.set_priority(id, TurnPriority::Yield, map);
}
}

View File

@ -42,7 +42,7 @@ impl TrafficSignalEditor {
let active = match self {
TrafficSignalEditor::Inactive => false,
TrafficSignalEditor::Active { i, current_cycle } => {
if input.key_pressed(Key::Return, "Press enter to quit the editor") {
if input.key_pressed(Key::Return, "quit the editor") {
new_state = Some(TrafficSignalEditor::Inactive);
} else {
// Change cycles
@ -68,17 +68,13 @@ impl TrafficSignalEditor {
&mut control_map.traffic_signals.get_mut(&i).unwrap().cycles
[*current_cycle];
if cycle.contains(id) {
if input.key_pressed(
Key::Backspace,
"Press Backspace to remove this turn from this cycle",
) {
if input
.key_pressed(Key::Backspace, "remove this turn from this cycle")
{
cycle.remove(id);
}
} else if !cycle.conflicts_with(id, map) {
if input.key_pressed(
Key::Space,
"Press Space to add this turn to this cycle",
) {
if input.key_pressed(Key::Space, "add this turn to this cycle") {
cycle.add(id);
}
}

View File

@ -22,10 +22,8 @@ impl WarpState {
let mut new_state: Option<WarpState> = None;
let active = match self {
WarpState::Empty => {
if input.unimportant_key_pressed(
Key::J,
"Press J to start searching for something to warp to",
) {
if input.unimportant_key_pressed(Key::J, "start searching for something to warp to")
{
new_state = Some(WarpState::EnteringSearch(TextBox::new()));
true
} else {

View File

@ -456,35 +456,31 @@ impl gui::GUI for UI {
SelectionState::SelectedCar(id) => {
// TODO not sure if we should debug like this (pushing the bit down to all the
// layers representing an entity) or by using some scary global mutable singleton
if input.unimportant_key_pressed(Key::D, "press D to debug") {
if input.unimportant_key_pressed(Key::D, "debug") {
self.sim_ctrl.sim.toggle_debug(id);
return gui::EventLoopMode::InputOnly;
}
}
SelectionState::SelectedLane(id, _) => {
if input.key_pressed(Key::F, "Press F to start floodfilling from this lane") {
if input.key_pressed(Key::F, "start floodfilling from this lane") {
self.floodfiller = Floodfiller::start(id);
return gui::EventLoopMode::InputOnly;
}
if input.key_pressed(Key::A, "Press A to start something on this lane") {
if input.key_pressed(Key::A, "start something on this lane") {
self.sim_ctrl.sim.start_agent(&self.map, id);
return gui::EventLoopMode::InputOnly;
}
}
SelectionState::SelectedIntersection(id) => {
if self.control_map.traffic_signals.contains_key(&id) {
if input.key_pressed(
Key::E,
&format!("Press E to edit traffic signal for {:?}", id),
) {
if input.key_pressed(Key::E, &format!("edit traffic signal for {:?}", id)) {
self.traffic_signal_editor = TrafficSignalEditor::start(id);
return gui::EventLoopMode::InputOnly;
}
}
if self.control_map.stop_signs.contains_key(&id) {
if input.key_pressed(Key::E, &format!("Press E to edit stop sign for {:?}", id))
{
if input.key_pressed(Key::E, &format!("edit stop sign for {:?}", id)) {
self.stop_sign_editor = StopSignEditor::start(id);
return gui::EventLoopMode::InputOnly;
}
@ -496,7 +492,7 @@ impl gui::GUI for UI {
// Do this one lastish, since it conflicts with lots of other stuff
stop_if_done!(self.current_selection_state.event(input, &self.map));
if input.unimportant_key_pressed(Key::Escape, "Press escape to quit") {
if input.unimportant_key_pressed(Key::Escape, "quit") {
let state = EditorState {
cam_x: self.canvas.cam_x,
cam_y: self.canvas.cam_y,

View File

@ -1,5 +1,6 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use keys::describe_key;
use piston::input::{Button, Event, IdleArgs, Key, PressEvent};
use std::collections::HashMap;
@ -110,8 +111,8 @@ impl UserInput {
return true;
}
}
// TODO stringify the key, so we don't have to say what to press!
self.important_actions.push(String::from(action));
self.important_actions
.push(format!("Press {} to {}", describe_key(key), action));
false
}
@ -128,7 +129,8 @@ impl UserInput {
return true;
}
}
self.unimportant_actions.push(String::from(action));
self.unimportant_actions
.push(format!("Press {} to {}", describe_key(key), action));
false
}

64
ezgui/src/keys.rs Normal file
View File

@ -0,0 +1,64 @@
use piston::input::Key;
pub(crate) fn describe_key(key: Key) -> String {
match key {
Key::Space => "Space".to_string(),
Key::Escape => "Escape".to_string(),
Key::Return => "Enter".to_string(),
Key::Tab => "Tab".to_string(),
Key::Backspace => "Backspace".to_string(),
_ => {
if let Some(c) = key_to_char(key) {
return c.to_string();
}
format!("{:?}", key)
}
}
}
// Returns uppercase form
pub(crate) fn key_to_char(key: Key) -> Option<char> {
match key {
Key::Space => Some(' '),
Key::A => Some('A'),
Key::B => Some('B'),
Key::C => Some('C'),
Key::D => Some('D'),
Key::E => Some('E'),
Key::F => Some('F'),
Key::G => Some('G'),
Key::H => Some('H'),
Key::I => Some('I'),
Key::J => Some('J'),
Key::K => Some('K'),
Key::L => Some('L'),
Key::M => Some('M'),
Key::N => Some('N'),
Key::O => Some('O'),
Key::P => Some('P'),
Key::Q => Some('Q'),
Key::R => Some('R'),
Key::S => Some('S'),
Key::T => Some('T'),
Key::U => Some('U'),
Key::V => Some('V'),
Key::W => Some('W'),
Key::X => Some('X'),
Key::Y => Some('Y'),
Key::Z => Some('Z'),
Key::D0 => Some('0'),
Key::D1 => Some('1'),
Key::D2 => Some('2'),
Key::D3 => Some('3'),
Key::D4 => Some('4'),
Key::D5 => Some('5'),
Key::D6 => Some('6'),
Key::D7 => Some('7'),
Key::D8 => Some('8'),
Key::D9 => Some('9'),
Key::Slash => Some('/'),
Key::LeftBracket => Some('['),
Key::RightBracket => Some(']'),
_ => None,
}
}

View File

@ -7,6 +7,7 @@ extern crate piston;
pub mod canvas;
pub mod input;
mod keys;
pub mod menu;
pub mod text;
pub mod text_box;

View File

@ -1,5 +1,6 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use keys::key_to_char;
use piston::input::{Button, Event, Key, PressEvent, ReleaseEvent};
// TODO right now, only a single line
@ -55,73 +56,10 @@ impl TextBox {
// Insert
if let Some(Button::Keyboard(key)) = ev.press_args() {
let new_char = match key {
Key::Space => Some(' '),
Key::A if self.shift_pressed => Some('A'),
Key::B if self.shift_pressed => Some('B'),
Key::C if self.shift_pressed => Some('C'),
Key::D if self.shift_pressed => Some('D'),
Key::E if self.shift_pressed => Some('E'),
Key::F if self.shift_pressed => Some('F'),
Key::G if self.shift_pressed => Some('G'),
Key::H if self.shift_pressed => Some('H'),
Key::I if self.shift_pressed => Some('I'),
Key::J if self.shift_pressed => Some('J'),
Key::K if self.shift_pressed => Some('K'),
Key::L if self.shift_pressed => Some('L'),
Key::M if self.shift_pressed => Some('M'),
Key::N if self.shift_pressed => Some('N'),
Key::O if self.shift_pressed => Some('O'),
Key::P if self.shift_pressed => Some('P'),
Key::Q if self.shift_pressed => Some('Q'),
Key::R if self.shift_pressed => Some('R'),
Key::S if self.shift_pressed => Some('S'),
Key::T if self.shift_pressed => Some('T'),
Key::U if self.shift_pressed => Some('U'),
Key::V if self.shift_pressed => Some('V'),
Key::W if self.shift_pressed => Some('W'),
Key::X if self.shift_pressed => Some('X'),
Key::Y if self.shift_pressed => Some('Y'),
Key::Z if self.shift_pressed => Some('Z'),
Key::A => Some('a'),
Key::B => Some('b'),
Key::C => Some('c'),
Key::D => Some('d'),
Key::E => Some('e'),
Key::F => Some('f'),
Key::G => Some('g'),
Key::H => Some('h'),
Key::I => Some('i'),
Key::J => Some('j'),
Key::K => Some('k'),
Key::L => Some('l'),
Key::M => Some('m'),
Key::N => Some('n'),
Key::O => Some('o'),
Key::P => Some('p'),
Key::Q => Some('q'),
Key::R => Some('r'),
Key::S => Some('s'),
Key::T => Some('t'),
Key::U => Some('u'),
Key::V => Some('v'),
Key::W => Some('w'),
Key::X => Some('x'),
Key::Y => Some('y'),
Key::Z => Some('z'),
Key::D0 => Some('0'),
Key::D1 => Some('1'),
Key::D2 => Some('2'),
Key::D3 => Some('3'),
Key::D4 => Some('4'),
Key::D5 => Some('5'),
Key::D6 => Some('6'),
Key::D7 => Some('7'),
Key::D8 => Some('8'),
Key::D9 => Some('9'),
_ => None,
};
if let Some(c) = new_char {
if let Some(mut c) = key_to_char(key) {
if !self.shift_pressed {
c = c.to_lowercase().next().unwrap();
}
self.line.insert(self.cursor_x, c);
self.cursor_x += 1;
}