mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
hack in a way to easily check for ctrl+key. use to jump between
sandbox, debug, and edit modes
This commit is contained in:
parent
35b3e4b7be
commit
53e2c3e905
@ -5,7 +5,7 @@ use crate::game::{GameState, Mode};
|
||||
use crate::render::DrawOptions;
|
||||
use crate::ui::{PerMapUI, ShowEverything, UI};
|
||||
use abstutil::elapsed_seconds;
|
||||
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
|
||||
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
|
||||
use geom::{Duration, Line, PolyLine};
|
||||
use map_model::LANE_THICKNESS;
|
||||
use sim::{Benchmark, TripID};
|
||||
@ -42,14 +42,14 @@ impl ABTestMode {
|
||||
"A/B Test Mode",
|
||||
vec![
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::LeftBracket), "slow down sim"),
|
||||
(Some(Key::RightBracket), "speed up sim"),
|
||||
(Some(Key::Space), "run/pause sim"),
|
||||
(Some(Key::M), "step forwards 0.1s"),
|
||||
(Some(Key::S), "swap"),
|
||||
(Some(Key::D), "diff all trips"),
|
||||
(Some(Key::B), "stop diffing trips"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::LeftBracket), "slow down sim"),
|
||||
(hotkey(Key::RightBracket), "speed up sim"),
|
||||
(hotkey(Key::Space), "run/pause sim"),
|
||||
(hotkey(Key::M), "step forwards 0.1s"),
|
||||
(hotkey(Key::S), "swap"),
|
||||
(hotkey(Key::D), "diff all trips"),
|
||||
(hotkey(Key::B), "stop diffing trips"),
|
||||
],
|
||||
CommonState::modal_menu_entries(),
|
||||
]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::abtest::{ABTestMode, State};
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::ui::{Flags, PerMapUI, UI};
|
||||
use ezgui::{EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
|
||||
use map_model::Map;
|
||||
use sim::{ABTest, SimFlags};
|
||||
use std::path::PathBuf;
|
||||
@ -26,8 +26,8 @@ impl ABTestSetup {
|
||||
ModalMenu::new(
|
||||
&format!("A/B Test Editor for {}", ab_test.test_name),
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::R), "run A/B test"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::R), "run A/B test"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
|
@ -8,8 +8,8 @@ use crate::render::DrawOptions;
|
||||
use crate::ui::UI;
|
||||
use abstutil::elapsed_seconds;
|
||||
use ezgui::{
|
||||
Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text,
|
||||
VerticalAlignment,
|
||||
hotkey, Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, Key, ModalMenu, MultiKey,
|
||||
Text, VerticalAlignment,
|
||||
};
|
||||
use geom::{Line, Pt2D};
|
||||
use std::collections::BTreeSet;
|
||||
@ -32,12 +32,12 @@ impl CommonState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modal_menu_entries() -> Vec<(Option<Key>, &'static str)> {
|
||||
pub fn modal_menu_entries() -> Vec<(Option<MultiKey>, &'static str)> {
|
||||
vec![
|
||||
(Some(Key::J), "warp"),
|
||||
(hotkey(Key::J), "warp"),
|
||||
// TODO This definitely conflicts with some modes.
|
||||
(Some(Key::K), "navigate"),
|
||||
(Some(Key::F1), "take a screenshot"),
|
||||
(hotkey(Key::K), "navigate"),
|
||||
(hotkey(Key::F1), "take a screenshot"),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::ui::UI;
|
||||
use ezgui::{
|
||||
Canvas, Color, EventCtx, GfxCtx, InputResult, Key, ModalMenu, ScreenPt, ScrollingMenu,
|
||||
hotkey, Canvas, Color, EventCtx, GfxCtx, InputResult, Key, ModalMenu, ScreenPt, ScrollingMenu,
|
||||
};
|
||||
use geom::{Distance, Polygon};
|
||||
|
||||
@ -32,8 +32,8 @@ impl ColorPicker {
|
||||
ModalMenu::new(
|
||||
&format!("Color Picker for {}", name),
|
||||
vec![
|
||||
(Some(Key::Backspace), "revert"),
|
||||
(Some(Key::Escape), "finalize"),
|
||||
(hotkey(Key::Backspace), "revert"),
|
||||
(hotkey(Key::Escape), "finalize"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
|
@ -6,16 +6,18 @@ mod objects;
|
||||
mod polygons;
|
||||
|
||||
use crate::common::CommonState;
|
||||
use crate::edit::EditMode;
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::DrawOptions;
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::{ShowLayers, ShowObject, UI};
|
||||
use abstutil::wraparound_get;
|
||||
use abstutil::Timer;
|
||||
use clipping::CPolygon;
|
||||
use ezgui::{
|
||||
Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu, ScrollingMenu, Text,
|
||||
TextBox, Wizard,
|
||||
hotkey, lctrl, Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu,
|
||||
ScrollingMenu, Text, TextBox, Wizard,
|
||||
};
|
||||
use geom::{Distance, PolyLine, Polygon, Pt2D};
|
||||
use map_model::{IntersectionID, Map, RoadID};
|
||||
@ -69,22 +71,24 @@ impl DebugMode {
|
||||
"Debug Mode",
|
||||
vec![
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::C), "show/hide chokepoints"),
|
||||
(Some(Key::O), "clear original roads shown"),
|
||||
(Some(Key::G), "clear intersection geometry"),
|
||||
(Some(Key::H), "unhide everything"),
|
||||
(Some(Key::Num1), "show/hide buildings"),
|
||||
(Some(Key::Num2), "show/hide intersections"),
|
||||
(Some(Key::Num3), "show/hide lanes"),
|
||||
(Some(Key::Num4), "show/hide areas"),
|
||||
(Some(Key::Num5), "show/hide extra shapes"),
|
||||
(Some(Key::Num6), "show/hide geometry debug mode"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::C), "show/hide chokepoints"),
|
||||
(hotkey(Key::O), "clear original roads shown"),
|
||||
(hotkey(Key::G), "clear intersection geometry"),
|
||||
(hotkey(Key::H), "unhide everything"),
|
||||
(hotkey(Key::Num1), "show/hide buildings"),
|
||||
(hotkey(Key::Num2), "show/hide intersections"),
|
||||
(hotkey(Key::Num3), "show/hide lanes"),
|
||||
(hotkey(Key::Num4), "show/hide areas"),
|
||||
(hotkey(Key::Num5), "show/hide extra shapes"),
|
||||
(hotkey(Key::Num6), "show/hide geometry debug mode"),
|
||||
(None, "screenshot everything"),
|
||||
(Some(Key::Slash), "search OSM metadata"),
|
||||
(Some(Key::M), "clear OSM search results"),
|
||||
(Some(Key::S), "configure colors"),
|
||||
(Some(Key::N), "show/hide neighborhood summaries"),
|
||||
(hotkey(Key::Slash), "search OSM metadata"),
|
||||
(hotkey(Key::M), "clear OSM search results"),
|
||||
(hotkey(Key::S), "configure colors"),
|
||||
(hotkey(Key::N), "show/hide neighborhood summaries"),
|
||||
(lctrl(Key::S), "sandbox mode"),
|
||||
(lctrl(Key::E), "edit mode"),
|
||||
],
|
||||
CommonState::modal_menu_entries(),
|
||||
]
|
||||
@ -147,6 +151,14 @@ impl DebugMode {
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if menu.action("sandbox mode") {
|
||||
state.mode = Mode::Sandbox(SandboxMode::new(ctx));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if menu.action("edit mode") {
|
||||
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
|
||||
if menu.action("show/hide chokepoints") {
|
||||
if mode.chokepoints.is_some() {
|
||||
|
@ -2,7 +2,7 @@ use crate::helpers::ID;
|
||||
use crate::render::calculate_corners;
|
||||
use crate::ui::UI;
|
||||
use abstutil::Timer;
|
||||
use ezgui::{EventCtx, GfxCtx, ItemSlider, Key, Text};
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, ItemSlider, Key, Text};
|
||||
use geom::{Polygon, Pt2D, Triangle};
|
||||
|
||||
pub struct PolygonDebugger {
|
||||
@ -33,7 +33,7 @@ impl PolygonDebugger {
|
||||
pts.iter().map(|pt| Item::Point(*pt)).collect(),
|
||||
"Polygon Debugger",
|
||||
"point",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
center: Some(Pt2D::center(&pts_without_last)),
|
||||
@ -54,7 +54,7 @@ impl PolygonDebugger {
|
||||
.collect(),
|
||||
"Polygon Debugger",
|
||||
"corner",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
center: None,
|
||||
@ -75,7 +75,7 @@ impl PolygonDebugger {
|
||||
.collect(),
|
||||
"Polygon Debugger",
|
||||
"point",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
center: None,
|
||||
@ -93,7 +93,7 @@ impl PolygonDebugger {
|
||||
.collect(),
|
||||
"Polygon Debugger",
|
||||
"triangle",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
center: None,
|
||||
@ -115,7 +115,7 @@ impl PolygonDebugger {
|
||||
pts.iter().map(|pt| Item::Point(*pt)).collect(),
|
||||
"Polygon Debugger",
|
||||
"point",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
center: Some(center),
|
||||
@ -133,7 +133,7 @@ impl PolygonDebugger {
|
||||
.collect(),
|
||||
"Polygon Debugger",
|
||||
"triangle",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
center: None,
|
||||
|
@ -2,15 +2,20 @@ mod stop_signs;
|
||||
mod traffic_signals;
|
||||
|
||||
use crate::common::CommonState;
|
||||
use crate::debug::DebugMode;
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::{
|
||||
DrawCtx, DrawIntersection, DrawLane, DrawMap, DrawOptions, DrawTurn, Renderable,
|
||||
MIN_ZOOM_FOR_DETAIL,
|
||||
};
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard, WrappedWizard};
|
||||
use ezgui::{
|
||||
hotkey, lctrl, Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard,
|
||||
WrappedWizard,
|
||||
};
|
||||
use map_model::{IntersectionID, Lane, LaneID, LaneType, Map, MapEdits, Road, TurnID, TurnType};
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
@ -33,9 +38,11 @@ impl EditMode {
|
||||
"Map Edit Mode",
|
||||
vec![
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::S), "save edits"),
|
||||
(Some(Key::L), "load different edits"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::S), "save edits"),
|
||||
(hotkey(Key::L), "load different edits"),
|
||||
(lctrl(Key::S), "sandbox mode"),
|
||||
(lctrl(Key::D), "debug mode"),
|
||||
],
|
||||
CommonState::modal_menu_entries(),
|
||||
]
|
||||
@ -83,6 +90,15 @@ impl EditMode {
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if menu.action("sandbox mode") {
|
||||
state.mode = Mode::Sandbox(SandboxMode::new(ctx));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if menu.action("debug mode") {
|
||||
state.mode = Mode::Debug(DebugMode::new(ctx, &state.ui));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
|
||||
// TODO Only if current edits are unsaved
|
||||
if menu.action("save edits") {
|
||||
state.mode = Mode::Edit(EditMode::Saving(Wizard::new()));
|
||||
|
@ -4,7 +4,7 @@ use crate::game::GameState;
|
||||
use crate::helpers::ID;
|
||||
use crate::render::{DrawIntersection, DrawOptions, DrawTurn};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use ezgui::{Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Text};
|
||||
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Text};
|
||||
use geom::Polygon;
|
||||
use map_model::{IntersectionID, RoadID, TurnID, TurnPriority};
|
||||
use std::collections::HashMap;
|
||||
@ -37,8 +37,8 @@ impl StopSignEditor {
|
||||
menu: ModalMenu::new(
|
||||
"Stop Sign Editor",
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::R), "reset to default"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::R), "reset to default"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
|
@ -5,7 +5,7 @@ use crate::helpers::ID;
|
||||
use crate::render::{draw_signal_cycle, draw_signal_diagram, DrawCtx, DrawOptions, DrawTurn};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
|
||||
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
|
||||
use geom::Duration;
|
||||
use map_model::{ControlTrafficSignal, Cycle, IntersectionID, Map, TurnID, TurnPriority, TurnType};
|
||||
|
||||
@ -27,17 +27,17 @@ impl TrafficSignalEditor {
|
||||
let menu = ModalMenu::new(
|
||||
&format!("Traffic Signal Editor for {}", id),
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::D), "change cycle duration"),
|
||||
(Some(Key::P), "choose a preset signal"),
|
||||
(Some(Key::R), "reset to original"),
|
||||
(Some(Key::K), "move current cycle up"),
|
||||
(Some(Key::J), "move current cycle down"),
|
||||
(Some(Key::UpArrow), "select previous cycle"),
|
||||
(Some(Key::DownArrow), "select next cycle"),
|
||||
(Some(Key::Backspace), "delete current cycle"),
|
||||
(Some(Key::N), "add a new empty cycle"),
|
||||
(Some(Key::M), "add a new pedestrian scramble cycle"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::D), "change cycle duration"),
|
||||
(hotkey(Key::P), "choose a preset signal"),
|
||||
(hotkey(Key::R), "reset to original"),
|
||||
(hotkey(Key::K), "move current cycle up"),
|
||||
(hotkey(Key::J), "move current cycle down"),
|
||||
(hotkey(Key::UpArrow), "select previous cycle"),
|
||||
(hotkey(Key::DownArrow), "select next cycle"),
|
||||
(hotkey(Key::Backspace), "delete current cycle"),
|
||||
(hotkey(Key::N), "add a new empty cycle"),
|
||||
(hotkey(Key::M), "add a new pedestrian scramble cycle"),
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
|
@ -8,7 +8,9 @@ use crate::sandbox::SandboxMode;
|
||||
use crate::tutorial::TutorialMode;
|
||||
use crate::ui::{EditorState, Flags, ShowEverything, UI};
|
||||
use abstutil::elapsed_seconds;
|
||||
use ezgui::{Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, UserInput, Wizard, GUI};
|
||||
use ezgui::{
|
||||
hotkey, Canvas, EventCtx, EventLoopMode, GfxCtx, Key, LogScroller, UserInput, Wizard, GUI,
|
||||
};
|
||||
use geom::{Duration, Line, Pt2D, Speed};
|
||||
use map_model::Map;
|
||||
use rand::seq::SliceRandom;
|
||||
@ -257,13 +259,13 @@ fn splash_screen(
|
||||
.choose_string_hotkeys(
|
||||
"Welcome to A/B Street!",
|
||||
vec![
|
||||
(Some(Key::S), sandbox),
|
||||
(Some(Key::L), load_map),
|
||||
(Some(Key::E), edit),
|
||||
(Some(Key::T), tutorial),
|
||||
(Some(Key::D), debug),
|
||||
(Some(Key::M), mission),
|
||||
(Some(Key::A), abtest),
|
||||
(hotkey(Key::S), sandbox),
|
||||
(hotkey(Key::L), load_map),
|
||||
(hotkey(Key::E), edit),
|
||||
(hotkey(Key::T), tutorial),
|
||||
(hotkey(Key::D), debug),
|
||||
(hotkey(Key::M), mission),
|
||||
(hotkey(Key::A), abtest),
|
||||
(None, about),
|
||||
(None, quit),
|
||||
],
|
||||
|
@ -2,7 +2,7 @@ use crate::common::CommonState;
|
||||
use crate::mission::{clip_trips, Trip};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::prettyprint_usize;
|
||||
use ezgui::{Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Slider, Text};
|
||||
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Slider, Text};
|
||||
use geom::{Circle, Distance, Duration};
|
||||
use map_model::LANE_THICKNESS;
|
||||
use popdat::psrc::Mode;
|
||||
@ -52,13 +52,13 @@ impl TripsVisualizer {
|
||||
menu: ModalMenu::new(
|
||||
"Trips Visualizer",
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::Dot), "forwards 10 seconds"),
|
||||
(Some(Key::RightArrow), "forwards 30 minutes"),
|
||||
(Some(Key::Comma), "backwards 10 seconds"),
|
||||
(Some(Key::LeftArrow), "backwards 30 minutes"),
|
||||
(Some(Key::F), "goto start of day"),
|
||||
(Some(Key::L), "goto end of day"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::Dot), "forwards 10 seconds"),
|
||||
(hotkey(Key::RightArrow), "forwards 30 minutes"),
|
||||
(hotkey(Key::Comma), "backwards 10 seconds"),
|
||||
(hotkey(Key::LeftArrow), "backwards 30 minutes"),
|
||||
(hotkey(Key::F), "goto start of day"),
|
||||
(hotkey(Key::L), "goto end of day"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
|
@ -3,7 +3,7 @@ use crate::helpers::{rotating_color_total, ID};
|
||||
use crate::ui::UI;
|
||||
use abstutil::{prettyprint_usize, Timer};
|
||||
use ezgui::{
|
||||
Color, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment,
|
||||
hotkey, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, ModalMenu, Text, VerticalAlignment,
|
||||
};
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
use popdat::{Estimate, PopDat};
|
||||
@ -40,11 +40,11 @@ impl DataVisualizer {
|
||||
menu: ModalMenu::new(
|
||||
"Data Visualizer",
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::Space), "toggle table/bar chart"),
|
||||
(Some(Key::Num1), "household vehicles"),
|
||||
(Some(Key::Num2), "commute times"),
|
||||
(Some(Key::Num3), "commute modes"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::Space), "toggle table/bar chart"),
|
||||
(hotkey(Key::Num1), "household vehicles"),
|
||||
(hotkey(Key::Num2), "commute times"),
|
||||
(hotkey(Key::Num3), "commute modes"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
|
@ -2,7 +2,7 @@ use crate::common::CommonState;
|
||||
use crate::mission::{clip_trips, Trip};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::{prettyprint_usize, Timer};
|
||||
use ezgui::{Color, EventCtx, GfxCtx, ItemSlider, Key, Text};
|
||||
use ezgui::{hotkey, Color, EventCtx, GfxCtx, ItemSlider, Key, Text};
|
||||
use geom::{Circle, Distance, Speed};
|
||||
use popdat::PopDat;
|
||||
|
||||
@ -22,7 +22,7 @@ impl TripsVisualizer {
|
||||
trips,
|
||||
"Trips Visualizer",
|
||||
"trip",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use crate::sandbox::SandboxMode;
|
||||
use crate::ui::ShowEverything;
|
||||
use crate::ui::UI;
|
||||
use abstutil::{skip_fail, Timer};
|
||||
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard};
|
||||
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard};
|
||||
use geom::{Distance, Duration, PolyLine};
|
||||
use map_model::{BuildingID, Map, PathRequest, Position};
|
||||
use sim::SidewalkSpot;
|
||||
@ -38,13 +38,13 @@ impl MissionEditMode {
|
||||
state: State::Exploring(ModalMenu::new(
|
||||
"Mission Edit Mode",
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::D), "visualize population data"),
|
||||
(Some(Key::T), "visualize individual PSRC trips"),
|
||||
(Some(Key::A), "visualize all PSRC trips"),
|
||||
(Some(Key::S), "set up simulation with PSRC trips"),
|
||||
(Some(Key::N), "manage neighborhoods"),
|
||||
(Some(Key::W), "manage scenarios"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::D), "visualize population data"),
|
||||
(hotkey(Key::T), "visualize individual PSRC trips"),
|
||||
(hotkey(Key::A), "visualize all PSRC trips"),
|
||||
(hotkey(Key::S), "set up simulation with PSRC trips"),
|
||||
(hotkey(Key::N), "manage neighborhoods"),
|
||||
(hotkey(Key::W), "manage scenarios"),
|
||||
],
|
||||
ctx,
|
||||
)),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::ui::UI;
|
||||
use ezgui::{Color, EventCtx, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
|
||||
use ezgui::{hotkey, Color, EventCtx, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
|
||||
use geom::{Circle, Distance, Line, Polygon, Pt2D};
|
||||
use map_model::{Map, NeighborhoodBuilder};
|
||||
|
||||
@ -18,10 +18,10 @@ impl NeighborhoodEditor {
|
||||
ModalMenu::new(
|
||||
&format!("Neighborhood Editor for {}", name),
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::S), "save"),
|
||||
(Some(Key::X), "export as an Osmosis polygon filter"),
|
||||
(Some(Key::P), "add a new point"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::S), "save"),
|
||||
(hotkey(Key::X), "export as an Osmosis polygon filter"),
|
||||
(hotkey(Key::P), "add a new point"),
|
||||
],
|
||||
ctx,
|
||||
)
|
||||
|
@ -5,7 +5,7 @@ use crate::sandbox::SandboxMode;
|
||||
use crate::ui::UI;
|
||||
use abstutil::WeightedUsizeChoice;
|
||||
use ezgui::{
|
||||
Color, Drawable, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
|
||||
hotkey, Color, Drawable, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard,
|
||||
};
|
||||
use geom::{Distance, Duration, PolyLine, Pt2D};
|
||||
use map_model::{IntersectionID, Map, Neighborhood};
|
||||
@ -24,11 +24,11 @@ impl ScenarioEditor {
|
||||
ModalMenu::new(
|
||||
&format!("Scenario Editor for {}", name),
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::S), "save"),
|
||||
(Some(Key::E), "edit"),
|
||||
(Some(Key::I), "instantiate"),
|
||||
(Some(Key::V), "visualize"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::S), "save"),
|
||||
(hotkey(Key::E), "edit"),
|
||||
(hotkey(Key::I), "instantiate"),
|
||||
(hotkey(Key::V), "visualize"),
|
||||
],
|
||||
ctx,
|
||||
)
|
||||
|
@ -5,11 +5,13 @@ mod spawner;
|
||||
mod time_travel;
|
||||
|
||||
use crate::common::CommonState;
|
||||
use crate::debug::DebugMode;
|
||||
use crate::edit::EditMode;
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::render::DrawOptions;
|
||||
use crate::ui::ShowEverything;
|
||||
use abstutil::elapsed_seconds;
|
||||
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
|
||||
use ezgui::{hotkey, lctrl, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
|
||||
use geom::Duration;
|
||||
use sim::{Benchmark, Sim, TripID};
|
||||
use std::time::Instant;
|
||||
@ -54,24 +56,26 @@ impl SandboxMode {
|
||||
"Sandbox Mode",
|
||||
vec![
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(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), "step forwards 0.1s"),
|
||||
(Some(Key::N), "step forwards 10 mins"),
|
||||
(Some(Key::X), "reset sim"),
|
||||
(Some(Key::S), "seed the sim with agents"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::LeftBracket), "slow down sim"),
|
||||
(hotkey(Key::RightBracket), "speed up sim"),
|
||||
(hotkey(Key::O), "save sim state"),
|
||||
(hotkey(Key::Y), "load previous sim state"),
|
||||
(hotkey(Key::U), "load next sim state"),
|
||||
(hotkey(Key::Space), "run/pause sim"),
|
||||
(hotkey(Key::M), "step forwards 0.1s"),
|
||||
(hotkey(Key::N), "step forwards 10 mins"),
|
||||
(hotkey(Key::X), "reset sim"),
|
||||
(hotkey(Key::S), "seed the sim with agents"),
|
||||
// TODO Strange to always have this. Really it's a case of stacked modal?
|
||||
(Some(Key::F), "stop following agent"),
|
||||
(Some(Key::R), "stop showing agent's route"),
|
||||
(hotkey(Key::F), "stop following agent"),
|
||||
(hotkey(Key::R), "stop showing agent's route"),
|
||||
// TODO This should probably be a debug thing instead
|
||||
(Some(Key::L), "show/hide route for all agents"),
|
||||
(Some(Key::A), "show/hide active traffic"),
|
||||
(Some(Key::T), "start time traveling"),
|
||||
(hotkey(Key::L), "show/hide route for all agents"),
|
||||
(hotkey(Key::A), "show/hide active traffic"),
|
||||
(hotkey(Key::T), "start time traveling"),
|
||||
(lctrl(Key::D), "debug mode"),
|
||||
(lctrl(Key::E), "edit mode"),
|
||||
],
|
||||
CommonState::modal_menu_entries(),
|
||||
]
|
||||
@ -206,6 +210,14 @@ impl SandboxMode {
|
||||
state.mode = Mode::SplashScreen(Wizard::new(), None);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if mode.menu.action("debug mode") {
|
||||
state.mode = Mode::Debug(DebugMode::new(ctx, &state.ui));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if mode.menu.action("edit mode") {
|
||||
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
|
||||
if mode.menu.action("slow down sim") {
|
||||
mode.desired_speed -= ADJUST_SPEED;
|
||||
|
@ -2,7 +2,7 @@ use crate::common::Warper;
|
||||
use crate::helpers::ID;
|
||||
use crate::render::DrawTurn;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
|
||||
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GfxCtx, ItemSlider, Key, Text};
|
||||
use geom::{Distance, Polygon};
|
||||
use map_model::{Traversable, LANE_THICKNESS};
|
||||
use sim::AgentID;
|
||||
@ -63,7 +63,7 @@ impl RouteExplorer {
|
||||
steps,
|
||||
"Route Explorer",
|
||||
"step",
|
||||
vec![(Some(Key::Escape), "quit")],
|
||||
vec![(hotkey(Key::Escape), "quit")],
|
||||
ctx,
|
||||
),
|
||||
entire_trace,
|
||||
|
@ -3,7 +3,7 @@ use crate::helpers::ID;
|
||||
use crate::render::DrawOptions;
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{EventCtx, GfxCtx, Key, ModalMenu};
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu};
|
||||
use geom::{Duration, PolyLine};
|
||||
use map_model::{
|
||||
BuildingID, IntersectionID, IntersectionType, LaneType, PathRequest, Position, LANE_THICKNESS,
|
||||
@ -38,7 +38,7 @@ impl AgentSpawner {
|
||||
ui: &mut UI,
|
||||
sandbox_menu: &mut ModalMenu,
|
||||
) -> Option<AgentSpawner> {
|
||||
let menu = ModalMenu::new("Agent Spawner", vec![(Some(Key::Escape), "quit")], ctx);
|
||||
let menu = ModalMenu::new("Agent Spawner", vec![(hotkey(Key::Escape), "quit")], ctx);
|
||||
let map = &ui.primary.map;
|
||||
match ui.primary.current_selection {
|
||||
Some(ID::Building(id)) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::ui::UI;
|
||||
use abstutil::MultiMap;
|
||||
use ezgui::{EventCtx, GfxCtx, Key, ModalMenu, Text};
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu, Text};
|
||||
use geom::Duration;
|
||||
use map_model::{Map, Traversable};
|
||||
use sim::{CarID, DrawCarInput, DrawPedestrianInput, GetDrawAgents, PedestrianID};
|
||||
@ -30,9 +30,9 @@ impl TimeTravel {
|
||||
menu: ModalMenu::new(
|
||||
"Time Traveler",
|
||||
vec![
|
||||
(Some(Key::Escape), "quit"),
|
||||
(Some(Key::Comma), "rewind"),
|
||||
(Some(Key::Dot), "forwards"),
|
||||
(hotkey(Key::Escape), "quit"),
|
||||
(hotkey(Key::Comma), "rewind"),
|
||||
(hotkey(Key::Dot), "forwards"),
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::game::{GameState, Mode};
|
||||
use crate::render::DrawOptions;
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use ezgui::{EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
|
||||
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text, Wizard};
|
||||
use geom::Pt2D;
|
||||
|
||||
pub struct TutorialMode {
|
||||
@ -21,7 +21,7 @@ impl TutorialMode {
|
||||
ui.primary.reset_sim();
|
||||
|
||||
TutorialMode {
|
||||
menu: ModalMenu::new("Tutorial", vec![(Some(Key::Escape), "quit")], ctx),
|
||||
menu: ModalMenu::new("Tutorial", vec![(hotkey(Key::Escape), "quit")], ctx),
|
||||
state: State::Part1(ctx.canvas.center_to_map_pt()),
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ pub struct Canvas {
|
||||
|
||||
// Kind of just ezgui state awkwardly stuck here...
|
||||
pub(crate) hide_modal_menus: bool,
|
||||
pub(crate) lctrl_held: bool,
|
||||
}
|
||||
|
||||
impl Canvas {
|
||||
@ -59,6 +60,7 @@ impl Canvas {
|
||||
covered_areas: RefCell::new(Vec::new()),
|
||||
|
||||
hide_modal_menus: false,
|
||||
lctrl_held: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ impl Key {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn describe(self: Key) -> String {
|
||||
pub fn describe(self) -> String {
|
||||
match self {
|
||||
Key::Escape => "Escape".to_string(),
|
||||
Key::Enter => "Enter".to_string(),
|
||||
@ -350,3 +350,29 @@ 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,
|
||||
}
|
||||
|
||||
impl MultiKey {
|
||||
pub fn describe(self) -> String {
|
||||
if self.lctrl {
|
||||
format!("Ctrl+{}", self.key.describe())
|
||||
} else {
|
||||
self.key.describe()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For easy ModalMenu construction
|
||||
pub fn hotkey(key: Key) -> Option<MultiKey> {
|
||||
Some(MultiKey { key, lctrl: false })
|
||||
}
|
||||
|
||||
pub fn lctrl(key: Key) -> Option<MultiKey> {
|
||||
Some(MultiKey { key, lctrl: true })
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::widgets::{Menu, Position};
|
||||
use crate::{text, Canvas, Event, InputResult, Key, ScreenPt, Text};
|
||||
use crate::{hotkey, text, Canvas, Event, InputResult, Key, ScreenPt, Text};
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
|
||||
// As we check for user input, record the input and the thing that would happen. This will let us
|
||||
@ -41,7 +41,7 @@ impl ContextMenu {
|
||||
Text::new(),
|
||||
actions
|
||||
.into_iter()
|
||||
.map(|(hotkey, action)| (Some(hotkey), action, hotkey))
|
||||
.map(|(key, action)| (hotkey(key), action, key))
|
||||
.collect(),
|
||||
false,
|
||||
false,
|
||||
@ -71,6 +71,13 @@ impl UserInput {
|
||||
canvas.window_height = height;
|
||||
}
|
||||
|
||||
if input.event == Event::KeyPress(Key::LeftControl) {
|
||||
canvas.lctrl_held = true;
|
||||
}
|
||||
if input.event == Event::KeyRelease(Key::LeftControl) {
|
||||
canvas.lctrl_held = false;
|
||||
}
|
||||
|
||||
// Create the context menu here, even if one already existed.
|
||||
if input.right_mouse_button_pressed() {
|
||||
assert!(!input.event_consumed);
|
||||
|
@ -12,7 +12,7 @@ mod widgets;
|
||||
pub use crate::canvas::{Canvas, HorizontalAlignment, VerticalAlignment, BOTTOM_LEFT, CENTERED};
|
||||
pub use crate::color::Color;
|
||||
pub use crate::drawing::{GeomBatch, GfxCtx};
|
||||
pub use crate::event::{Event, Key};
|
||||
pub use crate::event::{hotkey, lctrl, Event, Key, MultiKey};
|
||||
pub use crate::event_ctx::{Drawable, EventCtx, Prerender};
|
||||
pub use crate::input::UserInput;
|
||||
pub use crate::runner::{run, EventLoopMode, GUI};
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::screen_geom::ScreenRectangle;
|
||||
use crate::{text, Canvas, Event, GfxCtx, InputResult, Key, ScreenPt, Text};
|
||||
use crate::{
|
||||
hotkey, lctrl, text, Canvas, Event, GfxCtx, InputResult, Key, MultiKey, ScreenPt, Text,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
// Stores some associated data with each choice
|
||||
pub struct Menu<T: Clone> {
|
||||
prompt: Text,
|
||||
// The bool is whether this choice is active or not
|
||||
choices: Vec<(Option<Key>, String, bool, T)>,
|
||||
choices: Vec<(Option<MultiKey>, String, bool, T)>,
|
||||
current_idx: Option<usize>,
|
||||
mouse_in_bounds: bool,
|
||||
keys_enabled: bool,
|
||||
@ -35,7 +37,7 @@ impl Position {
|
||||
&self,
|
||||
canvas: &Canvas,
|
||||
prompt: Text,
|
||||
choices: &Vec<(Option<Key>, String, bool, T)>,
|
||||
choices: &Vec<(Option<MultiKey>, String, bool, T)>,
|
||||
) -> Geometry {
|
||||
// This is actually a constant, effectively...
|
||||
let row_height = canvas.line_height(text::FONT_SIZE);
|
||||
@ -99,7 +101,7 @@ impl Position {
|
||||
impl<T: Clone> Menu<T> {
|
||||
pub fn new(
|
||||
prompt: Text,
|
||||
raw_choices: Vec<(Option<Key>, String, T)>,
|
||||
raw_choices: Vec<(Option<MultiKey>, String, T)>,
|
||||
keys_enabled: bool,
|
||||
hideable: bool,
|
||||
pos: Position,
|
||||
@ -220,8 +222,13 @@ impl<T: Clone> Menu<T> {
|
||||
}
|
||||
|
||||
if let Event::KeyPress(key) = ev {
|
||||
let pressed = if canvas.lctrl_held {
|
||||
lctrl(key)
|
||||
} else {
|
||||
hotkey(key)
|
||||
};
|
||||
for (maybe_key, choice, active, data) in &self.choices {
|
||||
if *active && Some(key) == *maybe_key {
|
||||
if *active && pressed == *maybe_key {
|
||||
return InputResult::Done(choice.to_string(), data.clone());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::widgets::{Menu, Position};
|
||||
use crate::{EventCtx, GfxCtx, InputResult, Key, Text};
|
||||
use crate::{EventCtx, GfxCtx, InputResult, MultiKey, Text};
|
||||
|
||||
pub struct ModalMenu {
|
||||
menu: Menu<()>,
|
||||
@ -7,12 +7,16 @@ pub struct ModalMenu {
|
||||
}
|
||||
|
||||
impl ModalMenu {
|
||||
pub fn new(prompt_line: &str, choices: Vec<(Option<Key>, &str)>, ctx: &EventCtx) -> ModalMenu {
|
||||
pub fn new(
|
||||
prompt_line: &str,
|
||||
choices: Vec<(Option<MultiKey>, &str)>,
|
||||
ctx: &EventCtx,
|
||||
) -> ModalMenu {
|
||||
let mut menu = Menu::new(
|
||||
Text::prompt(prompt_line),
|
||||
choices
|
||||
.into_iter()
|
||||
.map(|(key, action)| (key, action.to_string(), ()))
|
||||
.map(|(multikey, action)| (multikey, action.to_string(), ()))
|
||||
.collect(),
|
||||
false,
|
||||
true,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::screen_geom::ScreenRectangle;
|
||||
use crate::{Color, EventCtx, GfxCtx, Key, ModalMenu, Text};
|
||||
use crate::{hotkey, Color, EventCtx, GfxCtx, Key, ModalMenu, MultiKey, Text};
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
|
||||
// Pixels
|
||||
@ -169,7 +169,7 @@ impl<T> ItemSlider<T> {
|
||||
items: Vec<T>,
|
||||
menu_title: &str,
|
||||
noun: &str,
|
||||
other_choices: Vec<(Option<Key>, &str)>,
|
||||
other_choices: Vec<(Option<MultiKey>, &str)>,
|
||||
ctx: &mut EventCtx,
|
||||
) -> ItemSlider<T> {
|
||||
// Lifetime funniness...
|
||||
@ -180,10 +180,10 @@ impl<T> ItemSlider<T> {
|
||||
let first = format!("first {}", noun);
|
||||
let last = format!("last {}", noun);
|
||||
choices.extend(vec![
|
||||
(Some(Key::LeftArrow), prev.as_str()),
|
||||
(Some(Key::RightArrow), next.as_str()),
|
||||
(Some(Key::Comma), first.as_str()),
|
||||
(Some(Key::Dot), last.as_str()),
|
||||
(hotkey(Key::LeftArrow), prev.as_str()),
|
||||
(hotkey(Key::RightArrow), next.as_str()),
|
||||
(hotkey(Key::Comma), first.as_str()),
|
||||
(hotkey(Key::Dot), last.as_str()),
|
||||
]);
|
||||
|
||||
ItemSlider {
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::widgets::{Menu, Position};
|
||||
use crate::{Canvas, GfxCtx, InputResult, Key, LogScroller, Text, TextBox, UserInput};
|
||||
use crate::{
|
||||
hotkey, Canvas, GfxCtx, InputResult, Key, LogScroller, MultiKey, Text, TextBox, UserInput,
|
||||
};
|
||||
use abstutil::Cloneable;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
@ -207,9 +209,9 @@ impl<'a> WrappedWizard<'a> {
|
||||
));
|
||||
return None;
|
||||
}
|
||||
let boxed_choices: Vec<(Option<Key>, String, Box<Cloneable>)> = choices
|
||||
let boxed_choices: Vec<(Option<MultiKey>, String, Box<Cloneable>)> = choices
|
||||
.into_iter()
|
||||
.map(|(key, s, item)| (key, s, item.clone_box()))
|
||||
.map(|(key, s, item)| (key.and_then(hotkey), s, item.clone_box()))
|
||||
.collect();
|
||||
self.wizard.menu = Some(Menu::new(
|
||||
Text::prompt(query),
|
||||
@ -275,13 +277,14 @@ impl<'a> WrappedWizard<'a> {
|
||||
pub fn choose_string_hotkeys(
|
||||
&mut self,
|
||||
query: &str,
|
||||
choices: Vec<(Option<Key>, &str)>,
|
||||
choices: Vec<(Option<MultiKey>, &str)>,
|
||||
) -> Option<String> {
|
||||
// Clone the choices outside of the closure to get around the fact that choices_generator's
|
||||
// lifetime isn't correctly specified.
|
||||
let copied_choices: Vec<(Option<Key>, String, ())> = choices
|
||||
.into_iter()
|
||||
.map(|(key, s)| (key, s.to_string(), ()))
|
||||
// TODO Argh, change all the APIs to take MultiKey
|
||||
.map(|(multikey, s)| (multikey.map(|mk| mk.key), s.to_string(), ()))
|
||||
.collect();
|
||||
self.choose_something(query, Box::new(move || copied_choices.clone()))
|
||||
.map(|(s, _)| s)
|
||||
|
Loading…
Reference in New Issue
Block a user