abstreet/editor/src/debug/mod.rs

399 lines
18 KiB
Rust
Raw Normal View History

2019-04-26 02:02:40 +03:00
mod chokepoints;
2019-04-26 20:46:41 +03:00
mod color_picker;
2019-04-26 02:35:09 +03:00
mod connected_roads;
mod neighborhood_summary;
2019-04-26 02:40:26 +03:00
mod objects;
2019-04-26 02:24:10 +03:00
mod polygons;
2019-04-26 02:02:40 +03:00
use crate::common::CommonState;
use crate::game::{GameState, Mode};
use crate::helpers::ID;
use crate::render::DrawOptions;
use crate::ui::{ShowLayers, ShowObject, UI};
use abstutil::Timer;
2019-04-26 20:46:41 +03:00
use ezgui::{
2019-05-02 01:58:11 +03:00
Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu, ScrollingMenu, Text,
2019-05-02 00:59:20 +03:00
TextBox, Wizard,
2019-04-26 20:46:41 +03:00
};
2019-04-26 02:16:21 +03:00
use map_model::RoadID;
use std::collections::HashSet;
pub struct DebugMode {
state: State,
common: CommonState,
2019-04-26 02:02:40 +03:00
chokepoints: Option<chokepoints::ChokepointsFinder>,
2019-04-26 02:16:21 +03:00
show_original_roads: HashSet<RoadID>,
2019-04-26 02:35:09 +03:00
connected_roads: connected_roads::ShowConnectedRoads,
2019-04-26 02:40:26 +03:00
objects: objects::ObjectDebugger,
2019-04-26 08:07:48 +03:00
hidden: HashSet<ID>,
layers: ShowLayers,
search_results: Option<(String, HashSet<ID>)>,
neighborhood_summary: neighborhood_summary::NeighborhoodSummary,
}
enum State {
2019-05-02 01:58:11 +03:00
Exploring(ModalMenu),
2019-04-26 02:24:10 +03:00
Polygons(polygons::PolygonDebugger),
SearchOSM(TextBox),
2019-04-26 20:46:41 +03:00
Colors(color_picker::ColorPicker),
}
impl DebugMode {
pub fn new(ctx: &mut EventCtx, ui: &UI) -> DebugMode {
DebugMode {
2019-05-02 00:59:20 +03:00
state: DebugMode::exploring_state(ctx),
common: CommonState::new(),
2019-04-26 02:02:40 +03:00
chokepoints: None,
2019-04-26 02:16:21 +03:00
show_original_roads: HashSet::new(),
2019-04-26 02:35:09 +03:00
connected_roads: connected_roads::ShowConnectedRoads::new(),
2019-04-26 02:40:26 +03:00
objects: objects::ObjectDebugger::new(),
2019-04-26 08:07:48 +03:00
hidden: HashSet::new(),
layers: ShowLayers::new(),
search_results: None,
neighborhood_summary: neighborhood_summary::NeighborhoodSummary::new(
2019-04-29 19:27:43 +03:00
&ui.primary.map,
&ui.primary.draw_map,
ctx.prerender,
&mut Timer::new("set up DebugMode"),
),
}
}
2019-05-02 00:59:20 +03:00
fn exploring_state(ctx: &EventCtx) -> State {
2019-05-02 01:58:11 +03:00
State::Exploring(ModalMenu::new(
2019-05-02 00:59:20 +03:00
"Debug Mode",
vec![
vec![
(Some(Key::Escape), "quit"),
(Some(Key::C), "show/hide chokepoints"),
(Some(Key::O), "clear original roads shown"),
2019-05-04 00:50:56 +03:00
(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"),
(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"),
],
CommonState::modal_menu_entries(),
]
.concat(),
2019-05-02 00:59:20 +03:00
ctx,
))
}
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
match state.mode {
Mode::Debug(ref mut mode) => {
2019-05-02 00:59:20 +03:00
// TODO Argh, bad hack! Can't do it below because menu is borrowed and ShowObject
// is implemented on the entirety of DebugMode. :(
if let State::Exploring(_) = mode.state {
state.ui.primary.current_selection =
state
.ui
.handle_mouseover(ctx, None, &state.ui.primary.sim, mode, true);
}
2019-05-02 00:59:20 +03:00
match mode.state {
State::Exploring(ref mut menu) => {
2019-05-01 21:42:14 +03:00
let mut txt = Text::prompt("Debug Mode");
2019-04-26 02:24:10 +03:00
if mode.chokepoints.is_some() {
txt.add_line("Showing chokepoints".to_string());
}
if !mode.show_original_roads.is_empty() {
txt.add_line(format!(
"Showing {} original roads",
mode.show_original_roads.len()
));
}
2019-04-26 08:07:48 +03:00
if !mode.hidden.is_empty() {
txt.add_line(format!("Hiding {} things", mode.hidden.len()));
}
if let Some((ref search, ref results)) = mode.search_results {
txt.add_line(format!(
"Search for {} has {} results",
search,
results.len()
));
}
if mode.neighborhood_summary.active {
txt.add_line("Showing neighborhood summaries".to_string());
}
menu.handle_event(ctx, Some(txt));
2019-05-02 00:59:20 +03:00
ctx.canvas.handle_event(ctx.input);
if let Some(evmode) = mode.common.event(ctx, &state.ui, menu) {
2019-05-02 00:59:20 +03:00
return evmode;
}
if menu.action("quit") {
2019-04-26 02:24:10 +03:00
state.mode = Mode::SplashScreen(Wizard::new(), None);
return EventLoopMode::InputOnly;
}
2019-04-26 02:02:40 +03:00
2019-05-02 00:59:20 +03:00
if menu.action("show/hide chokepoints") {
2019-04-26 02:24:10 +03:00
if mode.chokepoints.is_some() {
mode.chokepoints = None;
} else {
// TODO Nothing will actually exist. ;)
mode.chokepoints = Some(chokepoints::ChokepointsFinder::new(
2019-04-29 19:27:43 +03:00
&state.ui.primary.sim,
2019-04-26 02:24:10 +03:00
));
}
}
if !mode.show_original_roads.is_empty() {
2019-05-02 00:59:20 +03:00
if menu.action("clear original roads shown") {
2019-04-26 02:24:10 +03:00
mode.show_original_roads.clear();
}
}
2019-04-29 19:27:43 +03:00
match state.ui.primary.current_selection {
2019-04-26 08:07:48 +03:00
Some(ID::Lane(_))
| Some(ID::Intersection(_))
| Some(ID::ExtraShape(_)) => {
2019-04-29 19:27:43 +03:00
let id = state.ui.primary.current_selection.unwrap();
2019-04-26 08:07:48 +03:00
if ctx
.input
.contextual_action(Key::H, &format!("hide {:?}", id))
{
println!("Hiding {:?}", id);
//*ctx.recalculate_current_selection = true;
2019-04-29 19:27:43 +03:00
state.ui.primary.current_selection = None;
2019-04-26 08:07:48 +03:00
mode.hidden.insert(id);
}
}
2019-05-04 00:50:56 +03:00
None => {
if !mode.hidden.is_empty() && menu.action("unhide everything") {
mode.hidden.clear();
// TODO recalculate current_selection
}
}
2019-04-26 08:07:48 +03:00
_ => {}
}
2019-04-26 02:24:10 +03:00
2019-04-29 19:27:43 +03:00
if let Some(ID::Lane(l)) = state.ui.primary.current_selection {
let id = state.ui.primary.map.get_l(l).parent;
2019-04-26 02:24:10 +03:00
if ctx.input.contextual_action(
Key::V,
&format!("show original geometry of {:?}", id),
) {
mode.show_original_roads.insert(id);
}
}
2019-04-26 02:35:09 +03:00
mode.connected_roads.event(ctx, &state.ui);
2019-04-26 02:40:26 +03:00
mode.objects.event(ctx, &state.ui);
2019-05-02 00:59:20 +03:00
mode.neighborhood_summary.event(&state.ui, menu);
2019-04-26 02:24:10 +03:00
if let Some(debugger) = polygons::PolygonDebugger::new(ctx, &state.ui) {
mode.state = State::Polygons(debugger);
2019-05-02 00:59:20 +03:00
return EventLoopMode::InputOnly;
2019-04-26 02:24:10 +03:00
}
2019-04-26 02:16:21 +03:00
// TODO recalc current selection...
2019-05-02 00:59:20 +03:00
if menu.action("show/hide buildings") {
mode.layers.show_buildings = !mode.layers.show_buildings;
2019-05-02 00:59:20 +03:00
} else if menu.action("show/hide intersections") {
mode.layers.show_intersections = !mode.layers.show_intersections;
2019-05-02 00:59:20 +03:00
} else if menu.action("show/hide lanes") {
mode.layers.show_lanes = !mode.layers.show_lanes;
2019-05-02 00:59:20 +03:00
} else if menu.action("show/hide areas") {
mode.layers.show_areas = !mode.layers.show_areas;
2019-05-02 00:59:20 +03:00
} else if menu.action("show/hide extra shapes") {
mode.layers.show_extra_shapes = !mode.layers.show_extra_shapes;
2019-05-02 00:59:20 +03:00
} else if menu.action("show/hide geometry debug mode") {
mode.layers.geom_debug_mode = !mode.layers.geom_debug_mode;
}
2019-05-02 00:59:20 +03:00
if menu.action("screenshot everything") {
2019-04-29 19:27:43 +03:00
let bounds = state.ui.primary.map.get_bounds();
assert!(bounds.min_x == 0.0 && bounds.min_y == 0.0);
return EventLoopMode::ScreenCaptureEverything {
dir: format!(
"../data/screenshots/pending_{}",
2019-04-29 19:27:43 +03:00
state.ui.primary.map.get_name()
),
zoom: 3.0,
max_x: bounds.max_x,
max_y: bounds.max_y,
};
}
if mode.search_results.is_some() {
2019-05-02 00:59:20 +03:00
if menu.action("clear OSM search results") {
mode.search_results = None;
}
2019-05-02 00:59:20 +03:00
} else if menu.action("search OSM metadata") {
mode.state = State::SearchOSM(TextBox::new("Search for what?", None));
2019-05-02 00:59:20 +03:00
} else if menu.action("configure colors") {
2019-04-26 20:46:41 +03:00
mode.state = State::Colors(color_picker::ColorPicker::Choosing(
ScrollingMenu::new(
"Pick a color to change",
2019-04-29 19:27:43 +03:00
state.ui.cs.color_names(),
2019-04-26 20:46:41 +03:00
),
));
}
2019-04-26 02:24:10 +03:00
EventLoopMode::InputOnly
}
State::Polygons(ref mut debugger) => {
if debugger.event(ctx) {
2019-05-02 00:59:20 +03:00
mode.state = DebugMode::exploring_state(ctx);
2019-04-26 02:24:10 +03:00
}
EventLoopMode::InputOnly
2019-04-26 02:16:21 +03:00
}
State::SearchOSM(ref mut tb) => {
match tb.event(&mut ctx.input) {
InputResult::Canceled => {
2019-05-02 00:59:20 +03:00
mode.state = DebugMode::exploring_state(ctx);
}
InputResult::Done(filter, _) => {
2019-05-02 00:59:20 +03:00
mode.state = DebugMode::exploring_state(ctx);
let mut ids = HashSet::new();
2019-04-29 19:27:43 +03:00
let map = &state.ui.primary.map;
for r in map.all_roads() {
if r.osm_tags
.iter()
.any(|(k, v)| format!("{} = {}", k, v).contains(&filter))
{
for l in r.all_lanes() {
ids.insert(ID::Lane(l));
}
}
}
for b in map.all_buildings() {
if b.osm_tags
.iter()
.any(|(k, v)| format!("{} = {}", k, v).contains(&filter))
{
ids.insert(ID::Building(b.id));
}
}
mode.search_results = Some((filter, ids));
}
InputResult::StillActive => {}
}
EventLoopMode::InputOnly
}
2019-04-26 20:46:41 +03:00
State::Colors(ref mut picker) => {
if picker.event(ctx, &mut state.ui) {
2019-05-02 00:59:20 +03:00
mode.state = DebugMode::exploring_state(ctx);
2019-04-26 20:46:41 +03:00
}
EventLoopMode::InputOnly
}
2019-04-26 02:16:21 +03:00
}
}
_ => unreachable!(),
}
}
pub fn draw(state: &GameState, g: &mut GfxCtx) {
match state.mode {
Mode::Debug(ref mode) => match mode.state {
2019-05-02 00:59:20 +03:00
State::Exploring(ref menu) => {
let mut opts = mode.common.draw_options(&state.ui);
2019-04-30 00:31:12 +03:00
opts.geom_debug_mode = mode.layers.geom_debug_mode;
2019-04-26 02:02:40 +03:00
if let Some(ref chokepoints) = mode.chokepoints {
2019-04-29 19:27:43 +03:00
let color = state.ui.cs.get_def("chokepoint", Color::RED);
2019-04-26 02:02:40 +03:00
for l in &chokepoints.lanes {
opts.override_colors.insert(ID::Lane(*l), color);
2019-04-26 02:02:40 +03:00
}
for i in &chokepoints.intersections {
opts.override_colors.insert(ID::Intersection(*i), color);
2019-04-26 02:02:40 +03:00
}
}
2019-04-26 02:35:09 +03:00
for l in &mode.connected_roads.lanes {
opts.override_colors.insert(
2019-04-26 02:35:09 +03:00
ID::Lane(*l),
2019-04-29 19:27:43 +03:00
state.ui.cs.get("something associated with something else"),
2019-04-26 02:35:09 +03:00
);
}
if let Some((_, ref results)) = mode.search_results {
for id in results {
opts.override_colors
2019-04-29 19:27:43 +03:00
.insert(*id, state.ui.cs.get_def("search result", Color::RED));
}
}
state.ui.draw(g, opts, &state.ui.primary.sim, mode);
2019-04-29 03:11:46 +03:00
mode.common.draw(g, &state.ui);
2019-04-26 02:16:21 +03:00
for id in &mode.show_original_roads {
2019-04-29 19:27:43 +03:00
let r = state.ui.primary.map.get_r(*id);
2019-04-26 02:16:21 +03:00
if let Some(pair) = r.get_center_for_side(true) {
let (pl, width) = pair.unwrap();
g.draw_polygon(
state
.ui
.cs
.get_def("original road forwards", Color::RED.alpha(0.5)),
&pl.make_polygons(width),
);
}
if let Some(pair) = r.get_center_for_side(false) {
let (pl, width) = pair.unwrap();
g.draw_polygon(
state
.ui
.cs
.get_def("original road backwards", Color::BLUE.alpha(0.5)),
&pl.make_polygons(width),
);
}
}
2019-04-26 02:40:26 +03:00
mode.objects.draw(g, &state.ui);
mode.neighborhood_summary.draw(g);
2019-05-02 00:59:20 +03:00
if !g.is_screencap() {
menu.draw(g);
}
}
2019-04-26 02:24:10 +03:00
State::Polygons(ref debugger) => {
2019-04-30 00:31:12 +03:00
let mut opts = DrawOptions::new();
opts.geom_debug_mode = mode.layers.geom_debug_mode;
state.ui.draw(g, opts, &state.ui.primary.sim, mode);
2019-04-26 02:24:10 +03:00
debugger.draw(g, &state.ui);
}
State::SearchOSM(ref tb) => {
2019-04-30 00:31:12 +03:00
let mut opts = DrawOptions::new();
opts.geom_debug_mode = mode.layers.geom_debug_mode;
state.ui.draw(g, opts, &state.ui.primary.sim, mode);
tb.draw(g);
}
2019-04-26 20:46:41 +03:00
State::Colors(ref picker) => {
2019-04-30 00:31:12 +03:00
let mut opts = DrawOptions::new();
opts.geom_debug_mode = mode.layers.geom_debug_mode;
state.ui.draw(g, opts, &state.ui.primary.sim, mode);
2019-04-26 20:46:41 +03:00
picker.draw(g);
}
},
_ => unreachable!(),
}
}
}
impl ShowObject for DebugMode {
fn show(&self, obj: ID) -> bool {
if self.hidden.contains(&obj) {
return false;
}
match obj {
ID::Road(_) | ID::Lane(_) => self.layers.show_lanes,
ID::Building(_) => self.layers.show_buildings,
ID::Intersection(_) => self.layers.show_intersections,
ID::ExtraShape(_) => self.layers.show_extra_shapes,
ID::Area(_) => self.layers.show_areas,
_ => true,
}
}
fn layers(&self) -> &ShowLayers {
&self.layers
}
}