2019-08-20 23:32:27 +03:00
|
|
|
mod floodfill;
|
2019-04-26 02:40:26 +03:00
|
|
|
mod objects;
|
2019-04-26 02:24:10 +03:00
|
|
|
mod polygons;
|
2019-06-25 00:48:47 +03:00
|
|
|
mod routes;
|
2019-04-26 02:02:40 +03:00
|
|
|
|
2019-12-16 21:10:01 +03:00
|
|
|
use crate::common::{tool_panel, CommonState};
|
2020-02-04 23:52:47 +03:00
|
|
|
use crate::game::{msg, DrawBaselayer, State, Transition, WizardState};
|
2019-04-29 19:56:01 +03:00
|
|
|
use crate::helpers::ID;
|
2020-01-22 21:41:58 +03:00
|
|
|
use crate::managed::{WrappedComposite, WrappedOutcome};
|
2019-04-27 23:58:36 +03:00
|
|
|
use crate::ui::{ShowLayers, ShowObject, UI};
|
2019-04-26 20:46:41 +03:00
|
|
|
use ezgui::{
|
2019-12-13 01:12:14 +03:00
|
|
|
hotkey, Color, Drawable, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, Line, ModalMenu,
|
|
|
|
Text, Wizard,
|
2019-04-26 20:46:41 +03:00
|
|
|
};
|
2019-09-20 00:16:50 +03:00
|
|
|
use geom::Duration;
|
2020-02-18 19:40:05 +03:00
|
|
|
use map_model::IntersectionID;
|
2019-12-07 20:38:06 +03:00
|
|
|
use sim::Sim;
|
2019-04-29 23:55:59 +03:00
|
|
|
use std::collections::HashSet;
|
2019-04-26 01:50:16 +03:00
|
|
|
|
|
|
|
pub struct DebugMode {
|
2019-06-22 19:48:42 +03:00
|
|
|
menu: ModalMenu,
|
2019-04-29 02:29:19 +03:00
|
|
|
common: CommonState,
|
2020-01-22 21:41:58 +03:00
|
|
|
tool_panel: WrappedComposite,
|
2019-04-26 02:40:26 +03:00
|
|
|
objects: objects::ObjectDebugger,
|
2019-04-26 08:07:48 +03:00
|
|
|
hidden: HashSet<ID>,
|
2019-04-26 08:19:54 +03:00
|
|
|
layers: ShowLayers,
|
2019-06-27 00:38:16 +03:00
|
|
|
search_results: Option<SearchResults>,
|
2019-06-25 00:48:47 +03:00
|
|
|
all_routes: routes::AllRoutesViewer,
|
2020-02-18 19:40:05 +03:00
|
|
|
|
|
|
|
highlighted_agents: Option<(IntersectionID, Drawable)>,
|
2019-04-26 01:50:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DebugMode {
|
2019-12-04 02:08:46 +03:00
|
|
|
pub fn new(ctx: &mut EventCtx) -> DebugMode {
|
2019-04-26 01:50:16 +03:00
|
|
|
DebugMode {
|
2019-06-22 19:48:42 +03:00
|
|
|
menu: ModalMenu::new(
|
|
|
|
"Debug Mode",
|
|
|
|
vec![
|
2019-10-30 01:37:19 +03:00
|
|
|
(hotkey(Key::Num1), "hide buildings"),
|
|
|
|
(hotkey(Key::Num2), "hide intersections"),
|
|
|
|
(hotkey(Key::Num3), "hide lanes"),
|
|
|
|
(hotkey(Key::Num4), "hide areas"),
|
|
|
|
(hotkey(Key::Num5), "hide extra shapes"),
|
2019-11-10 01:53:36 +03:00
|
|
|
(hotkey(Key::Num6), "show labels"),
|
2019-10-30 01:37:19 +03:00
|
|
|
(hotkey(Key::R), "show route for all agents"),
|
|
|
|
(None, "screenshot everything"),
|
|
|
|
(hotkey(Key::Slash), "search OSM metadata"),
|
2019-12-07 20:38:06 +03:00
|
|
|
(hotkey(Key::O), "save sim state"),
|
|
|
|
(hotkey(Key::Y), "load previous sim state"),
|
|
|
|
(hotkey(Key::U), "load next sim state"),
|
|
|
|
(None, "pick a savestate to load"),
|
|
|
|
],
|
|
|
|
ctx,
|
|
|
|
),
|
2019-12-16 21:10:01 +03:00
|
|
|
common: CommonState::new(),
|
2020-01-20 02:20:19 +03:00
|
|
|
tool_panel: tool_panel(ctx),
|
2019-04-26 02:40:26 +03:00
|
|
|
objects: objects::ObjectDebugger::new(),
|
2019-04-26 08:07:48 +03:00
|
|
|
hidden: HashSet::new(),
|
2019-04-26 08:19:54 +03:00
|
|
|
layers: ShowLayers::new(),
|
2019-04-26 20:21:05 +03:00
|
|
|
search_results: None,
|
2019-06-25 00:48:47 +03:00
|
|
|
all_routes: routes::AllRoutesViewer::Inactive,
|
2020-02-18 19:40:05 +03:00
|
|
|
highlighted_agents: None,
|
2019-04-26 01:50:16 +03:00
|
|
|
}
|
|
|
|
}
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-04-26 01:50:16 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
impl State for DebugMode {
|
2019-06-24 03:00:34 +03:00
|
|
|
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
|
2019-06-22 19:48:42 +03:00
|
|
|
if ctx.redo_mouseover() {
|
|
|
|
ui.primary.current_selection =
|
2020-02-25 03:41:43 +03:00
|
|
|
ui.calculate_current_selection(ctx, &ui.primary.sim, self, true, false);
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-05-02 00:59:20 +03:00
|
|
|
|
2019-10-12 06:10:12 +03:00
|
|
|
{
|
|
|
|
let mut txt = Text::new();
|
|
|
|
if !self.hidden.is_empty() {
|
|
|
|
txt.add(Line(format!("Hiding {} things", self.hidden.len())));
|
|
|
|
}
|
|
|
|
if let Some(ref results) = self.search_results {
|
|
|
|
txt.add(Line(format!(
|
|
|
|
"Search for {} has {} results",
|
2020-01-25 00:38:15 +03:00
|
|
|
results.query, results.num_matches
|
2019-10-12 06:10:12 +03:00
|
|
|
)));
|
|
|
|
}
|
|
|
|
if let routes::AllRoutesViewer::Active(_, ref traces) = self.all_routes {
|
|
|
|
txt.add(Line(format!("Showing {} routes", traces.len())));
|
|
|
|
}
|
2020-02-07 08:39:23 +03:00
|
|
|
self.menu.set_info(ctx, txt);
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-10-12 06:10:12 +03:00
|
|
|
self.menu.event(ctx);
|
2019-04-26 01:50:16 +03:00
|
|
|
|
2020-01-07 20:43:34 +03:00
|
|
|
ctx.canvas_movement();
|
2019-05-02 00:59:20 +03:00
|
|
|
|
2019-12-13 01:12:14 +03:00
|
|
|
if self.menu.action("save sim state") {
|
2019-12-07 20:38:06 +03:00
|
|
|
ctx.loading_screen("savestate", |_, timer| {
|
|
|
|
timer.start("save sim state");
|
|
|
|
ui.primary.sim.save();
|
|
|
|
timer.stop("save sim state");
|
|
|
|
});
|
|
|
|
}
|
2019-12-13 01:12:14 +03:00
|
|
|
if self.menu.action("load previous sim state") {
|
2019-12-07 20:38:06 +03:00
|
|
|
if let Some(t) = ctx.loading_screen("load previous savestate", |ctx, mut timer| {
|
|
|
|
let prev_state = ui
|
|
|
|
.primary
|
|
|
|
.sim
|
|
|
|
.find_previous_savestate(ui.primary.sim.time());
|
|
|
|
match prev_state
|
|
|
|
.clone()
|
2019-12-18 05:08:59 +03:00
|
|
|
.and_then(|path| Sim::load_savestate(path, &ui.primary.map, &mut timer).ok())
|
2019-12-07 20:38:06 +03:00
|
|
|
{
|
|
|
|
Some(new_sim) => {
|
|
|
|
ui.primary.sim = new_sim;
|
|
|
|
ui.recalculate_current_selection(ctx);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
None => Some(Transition::Push(msg(
|
|
|
|
"Error",
|
|
|
|
vec![format!("Couldn't load previous savestate {:?}", prev_state)],
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}) {
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
}
|
2019-12-13 01:12:14 +03:00
|
|
|
if self.menu.action("load next sim state") {
|
2019-12-07 20:38:06 +03:00
|
|
|
if let Some(t) = ctx.loading_screen("load next savestate", |ctx, mut timer| {
|
|
|
|
let next_state = ui.primary.sim.find_next_savestate(ui.primary.sim.time());
|
|
|
|
match next_state
|
|
|
|
.clone()
|
2019-12-18 05:08:59 +03:00
|
|
|
.and_then(|path| Sim::load_savestate(path, &ui.primary.map, &mut timer).ok())
|
2019-12-07 20:38:06 +03:00
|
|
|
{
|
|
|
|
Some(new_sim) => {
|
|
|
|
ui.primary.sim = new_sim;
|
|
|
|
ui.recalculate_current_selection(ctx);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
None => Some(Transition::Push(msg(
|
|
|
|
"Error",
|
|
|
|
vec![format!("Couldn't load next savestate {:?}", next_state)],
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}) {
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
}
|
2019-12-13 01:12:14 +03:00
|
|
|
if self.menu.action("pick a savestate to load") {
|
2019-12-07 20:38:06 +03:00
|
|
|
return Transition::Push(WizardState::new(Box::new(load_savestate)));
|
|
|
|
}
|
|
|
|
|
2019-10-11 23:09:32 +03:00
|
|
|
self.all_routes.event(ui, &mut self.menu, ctx);
|
2019-06-22 19:48:42 +03:00
|
|
|
match ui.primary.current_selection {
|
|
|
|
Some(ID::Lane(_)) | Some(ID::Intersection(_)) | Some(ID::ExtraShape(_)) => {
|
2019-08-15 01:09:54 +03:00
|
|
|
let id = ui.primary.current_selection.clone().unwrap();
|
2019-12-12 02:04:32 +03:00
|
|
|
if ui.per_obj.action(ctx, Key::H, format!("hide {:?}", id)) {
|
2019-06-22 19:48:42 +03:00
|
|
|
println!("Hiding {:?}", id);
|
|
|
|
ui.primary.current_selection = None;
|
2019-10-11 23:09:32 +03:00
|
|
|
if self.hidden.is_empty() {
|
2020-02-07 08:39:23 +03:00
|
|
|
self.menu
|
|
|
|
.push_action(ctx, hotkey(Key::H), "unhide everything");
|
2019-10-11 23:09:32 +03:00
|
|
|
}
|
2019-06-22 19:48:42 +03:00
|
|
|
self.hidden.insert(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
2020-02-07 08:39:23 +03:00
|
|
|
if !self.hidden.is_empty() && self.menu.consume_action(ctx, "unhide everything") {
|
2019-06-22 19:48:42 +03:00
|
|
|
self.hidden.clear();
|
2019-06-23 19:48:50 +03:00
|
|
|
ui.primary.current_selection =
|
2020-02-25 03:41:43 +03:00
|
|
|
ui.calculate_current_selection(ctx, &ui.primary.sim, self, true, false);
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2019-04-26 02:02:40 +03:00
|
|
|
|
2019-09-07 23:46:47 +03:00
|
|
|
if let Some(ID::Car(id)) = ui.primary.current_selection {
|
2019-12-12 02:04:32 +03:00
|
|
|
if ui
|
|
|
|
.per_obj
|
|
|
|
.action(ctx, Key::Backspace, "forcibly kill this car")
|
2019-09-07 23:46:47 +03:00
|
|
|
{
|
|
|
|
ui.primary.sim.kill_stuck_car(id, &ui.primary.map);
|
|
|
|
ui.primary.sim.step(&ui.primary.map, Duration::seconds(0.1));
|
|
|
|
ui.primary.current_selection = None;
|
2019-12-12 02:04:32 +03:00
|
|
|
} else if ui.per_obj.action(ctx, Key::G, "find front of blockage") {
|
2019-11-02 01:31:26 +03:00
|
|
|
return Transition::Push(msg(
|
|
|
|
"Blockage results",
|
|
|
|
vec![format!(
|
|
|
|
"{} is ultimately blocked by {}",
|
|
|
|
id,
|
|
|
|
ui.primary.sim.find_blockage_front(id, &ui.primary.map)
|
|
|
|
)],
|
|
|
|
));
|
2019-09-07 23:46:47 +03:00
|
|
|
}
|
|
|
|
}
|
2020-02-18 19:40:05 +03:00
|
|
|
if let Some(ID::Intersection(id)) = ui.primary.current_selection {
|
|
|
|
if self
|
|
|
|
.highlighted_agents
|
|
|
|
.as_ref()
|
|
|
|
.map(|(i, _)| id != *i)
|
|
|
|
.unwrap_or(true)
|
|
|
|
{
|
|
|
|
let mut batch = GeomBatch::new();
|
|
|
|
for a in ui.primary.sim.get_accepted_agents(id) {
|
|
|
|
batch.push(
|
|
|
|
ui.cs.get("something associated with something else"),
|
|
|
|
ui.primary
|
|
|
|
.draw_map
|
|
|
|
.get_obj(
|
|
|
|
ID::from_agent(a),
|
|
|
|
ui,
|
|
|
|
&mut ui.primary.draw_map.agents.borrow_mut(),
|
|
|
|
ctx.prerender,
|
|
|
|
)
|
|
|
|
.unwrap()
|
|
|
|
.get_outline(&ui.primary.map),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
self.highlighted_agents = Some((id, ctx.upload(batch)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.highlighted_agents = None;
|
|
|
|
}
|
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
self.objects.event(ctx, ui);
|
|
|
|
|
|
|
|
if let Some(debugger) = polygons::PolygonDebugger::new(ctx, ui) {
|
2019-06-24 03:00:34 +03:00
|
|
|
return Transition::Push(Box::new(debugger));
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-04-26 02:24:10 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
{
|
2019-10-11 23:09:32 +03:00
|
|
|
let mut changed = false;
|
|
|
|
|
|
|
|
for (label, value) in vec![
|
|
|
|
("buildings", &mut self.layers.show_buildings),
|
|
|
|
("intersections", &mut self.layers.show_intersections),
|
|
|
|
("lanes", &mut self.layers.show_lanes),
|
|
|
|
("areas", &mut self.layers.show_areas),
|
|
|
|
("extra shapes", &mut self.layers.show_extra_shapes),
|
|
|
|
("labels", &mut self.layers.show_labels),
|
|
|
|
] {
|
|
|
|
let show = format!("show {}", label);
|
|
|
|
let hide = format!("hide {}", label);
|
|
|
|
|
2020-02-07 08:39:23 +03:00
|
|
|
if *value && self.menu.swap_action(ctx, &hide, &show) {
|
2019-10-11 23:09:32 +03:00
|
|
|
*value = false;
|
|
|
|
changed = true;
|
2020-02-07 08:39:23 +03:00
|
|
|
} else if !*value && self.menu.swap_action(ctx, &show, &hide) {
|
2019-10-11 23:09:32 +03:00
|
|
|
*value = true;
|
|
|
|
changed = true;
|
|
|
|
}
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-04-26 02:24:10 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
if changed {
|
2019-06-23 19:48:50 +03:00
|
|
|
ui.primary.current_selection =
|
2020-02-25 03:41:43 +03:00
|
|
|
ui.calculate_current_selection(ctx, &ui.primary.sim, self, true, false);
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
|
|
|
}
|
2019-04-26 02:16:21 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
if self.menu.action("screenshot everything") {
|
|
|
|
let bounds = ui.primary.map.get_bounds();
|
|
|
|
assert!(bounds.min_x == 0.0 && bounds.min_y == 0.0);
|
2019-06-24 03:00:34 +03:00
|
|
|
return Transition::KeepWithMode(EventLoopMode::ScreenCaptureEverything {
|
2019-08-05 02:25:40 +03:00
|
|
|
dir: abstutil::path_pending_screenshots(ui.primary.map.get_name()),
|
2019-06-24 03:00:34 +03:00
|
|
|
zoom: 3.0,
|
|
|
|
max_x: bounds.max_x,
|
|
|
|
max_y: bounds.max_y,
|
|
|
|
});
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-04-26 08:19:54 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
if self.search_results.is_some() {
|
2019-10-11 23:15:14 +03:00
|
|
|
if self
|
|
|
|
.menu
|
2020-02-07 08:39:23 +03:00
|
|
|
.swap_action(ctx, "clear OSM search results", "search OSM metadata")
|
2019-10-11 23:15:14 +03:00
|
|
|
{
|
2019-06-22 19:48:42 +03:00
|
|
|
self.search_results = None;
|
|
|
|
}
|
2019-10-11 23:15:14 +03:00
|
|
|
} else if self
|
|
|
|
.menu
|
2020-02-07 08:39:23 +03:00
|
|
|
.swap_action(ctx, "search OSM metadata", "clear OSM search results")
|
2019-10-11 23:15:14 +03:00
|
|
|
{
|
2019-11-24 18:21:30 +03:00
|
|
|
// TODO If the wizard aborts (pressing escape), this crashes.
|
2019-08-07 23:28:46 +03:00
|
|
|
return Transition::Push(WizardState::new(Box::new(search_osm)));
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-04-26 20:15:25 +03:00
|
|
|
|
2019-11-15 07:00:52 +03:00
|
|
|
if let Some(floodfiller) = floodfill::Floodfiller::new(ctx, ui) {
|
2019-08-20 23:32:27 +03:00
|
|
|
return Transition::Push(floodfiller);
|
|
|
|
}
|
2019-04-26 20:21:05 +03:00
|
|
|
|
2020-01-23 02:17:33 +03:00
|
|
|
if let Some(t) = self.common.event(ctx, ui, None) {
|
2019-12-12 02:25:43 +03:00
|
|
|
return t;
|
|
|
|
}
|
2019-12-16 21:10:01 +03:00
|
|
|
match self.tool_panel.event(ctx, ui) {
|
2020-01-22 21:41:58 +03:00
|
|
|
Some(WrappedOutcome::Transition(t)) => t,
|
|
|
|
Some(WrappedOutcome::Clicked(x)) => match x.as_ref() {
|
2019-12-16 21:10:01 +03:00
|
|
|
"back" => Transition::Pop,
|
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
|
|
|
None => Transition::Keep,
|
|
|
|
}
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-06-07 02:03:22 +03:00
|
|
|
|
2020-02-04 23:52:47 +03:00
|
|
|
fn draw_baselayer(&self) -> DrawBaselayer {
|
|
|
|
DrawBaselayer::Custom
|
2019-04-26 01:50:16 +03:00
|
|
|
}
|
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
|
|
|
let mut opts = self.common.draw_options(ui);
|
2019-08-16 22:38:39 +03:00
|
|
|
opts.label_buildings = self.layers.show_labels;
|
|
|
|
opts.label_roads = self.layers.show_labels;
|
2019-06-22 19:48:42 +03:00
|
|
|
ui.draw(g, opts, &ui.primary.sim, self);
|
2019-06-27 00:38:16 +03:00
|
|
|
|
2020-01-25 00:38:15 +03:00
|
|
|
if let Some(ref results) = self.search_results {
|
|
|
|
g.redraw(&results.draw);
|
2019-06-27 00:38:16 +03:00
|
|
|
}
|
2020-02-18 19:40:05 +03:00
|
|
|
if let Some((_, ref draw)) = self.highlighted_agents {
|
|
|
|
g.redraw(draw);
|
|
|
|
}
|
2019-06-27 00:38:16 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
self.objects.draw(g, ui);
|
2019-06-25 00:48:47 +03:00
|
|
|
self.all_routes.draw(g, ui);
|
2019-05-02 00:59:20 +03:00
|
|
|
|
2019-06-22 19:48:42 +03:00
|
|
|
if !g.is_screencap() {
|
|
|
|
self.menu.draw(g);
|
2019-11-04 23:55:04 +03:00
|
|
|
self.common.draw(g, ui);
|
2019-12-16 21:10:01 +03:00
|
|
|
self.tool_panel.draw(g);
|
2019-04-26 01:50:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-26 02:56:38 +03:00
|
|
|
|
|
|
|
impl ShowObject for DebugMode {
|
2019-08-15 01:09:54 +03:00
|
|
|
fn show(&self, obj: &ID) -> bool {
|
|
|
|
if self.hidden.contains(obj) {
|
2019-04-26 08:19:54 +03:00
|
|
|
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
|
2019-04-26 02:56:38 +03:00
|
|
|
}
|
|
|
|
}
|
2019-05-17 23:27:30 +03:00
|
|
|
|
2019-08-07 23:28:46 +03:00
|
|
|
fn search_osm(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transition> {
|
|
|
|
let filter = wiz.wrap(ctx).input_string("Search for what?")?;
|
2020-01-25 00:38:15 +03:00
|
|
|
let mut num_matches = 0;
|
2019-08-07 23:28:46 +03:00
|
|
|
let mut batch = GeomBatch::new();
|
2019-06-22 19:48:42 +03:00
|
|
|
|
2020-01-25 00:38:15 +03:00
|
|
|
// TODO Case insensitive
|
2019-08-07 23:28:46 +03:00
|
|
|
let map = &ui.primary.map;
|
|
|
|
let color = ui.cs.get_def("search result", Color::RED);
|
|
|
|
for r in map.all_roads() {
|
|
|
|
if r.osm_tags
|
|
|
|
.iter()
|
|
|
|
.any(|(k, v)| format!("{} = {}", k, v).contains(&filter))
|
|
|
|
{
|
2020-01-25 00:38:15 +03:00
|
|
|
num_matches += 1;
|
2020-01-29 04:26:14 +03:00
|
|
|
batch.push(color, r.get_thick_polygon(map).unwrap());
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
|
|
|
}
|
2019-08-07 23:28:46 +03:00
|
|
|
for b in map.all_buildings() {
|
|
|
|
if b.osm_tags
|
|
|
|
.iter()
|
|
|
|
.any(|(k, v)| format!("{} = {}", k, v).contains(&filter))
|
2020-01-29 02:57:45 +03:00
|
|
|
|| b.amenities
|
|
|
|
.iter()
|
|
|
|
.any(|(n, a)| n.contains(&filter) || a.contains(&filter))
|
2019-08-07 23:28:46 +03:00
|
|
|
{
|
2020-01-25 00:38:15 +03:00
|
|
|
num_matches += 1;
|
2019-08-07 23:28:46 +03:00
|
|
|
batch.push(color, b.polygon.clone());
|
|
|
|
}
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-11-14 21:54:11 +03:00
|
|
|
for a in map.all_areas() {
|
|
|
|
if a.osm_tags
|
|
|
|
.iter()
|
|
|
|
.any(|(k, v)| format!("{} = {}", k, v).contains(&filter))
|
|
|
|
{
|
2020-01-25 00:38:15 +03:00
|
|
|
num_matches += 1;
|
2019-11-14 21:54:11 +03:00
|
|
|
batch.push(color, a.polygon.clone());
|
|
|
|
}
|
|
|
|
}
|
2019-08-07 23:28:46 +03:00
|
|
|
|
|
|
|
let results = SearchResults {
|
|
|
|
query: filter,
|
2020-01-25 00:38:15 +03:00
|
|
|
num_matches,
|
|
|
|
draw: batch.upload(ctx),
|
2019-08-07 23:28:46 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
Some(Transition::PopWithData(Box::new(|state, _, _| {
|
|
|
|
state.downcast_mut::<DebugMode>().unwrap().search_results = Some(results);
|
|
|
|
})))
|
2019-06-22 19:48:42 +03:00
|
|
|
}
|
2019-06-27 00:38:16 +03:00
|
|
|
|
|
|
|
struct SearchResults {
|
|
|
|
query: String,
|
2020-01-25 00:38:15 +03:00
|
|
|
num_matches: usize,
|
|
|
|
draw: Drawable,
|
2019-06-27 00:38:16 +03:00
|
|
|
}
|
2019-12-07 20:38:06 +03:00
|
|
|
|
|
|
|
fn load_savestate(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transition> {
|
|
|
|
let ss = wiz.wrap(ctx).choose_string("Load which savestate?", || {
|
|
|
|
abstutil::list_all_objects(ui.primary.sim.save_dir())
|
|
|
|
})?;
|
|
|
|
// TODO Oh no, we have to do path construction here :(
|
|
|
|
let ss_path = format!("{}/{}.bin", ui.primary.sim.save_dir(), ss);
|
|
|
|
|
|
|
|
ctx.loading_screen("load savestate", |ctx, mut timer| {
|
2019-12-18 05:08:59 +03:00
|
|
|
ui.primary.sim = Sim::load_savestate(ss_path, &ui.primary.map, &mut timer)
|
|
|
|
.expect("Can't load savestate");
|
2019-12-07 20:38:06 +03:00
|
|
|
ui.recalculate_current_selection(ctx);
|
|
|
|
});
|
|
|
|
Some(Transition::Pop)
|
|
|
|
}
|