diff --git a/game/src/edit/lanes.rs b/game/src/edit/lanes.rs index 7c7d807214..38c19826e6 100644 --- a/game/src/edit/lanes.rs +++ b/game/src/edit/lanes.rs @@ -1,17 +1,14 @@ use crate::colors; -use crate::common::{Colorer, CommonState}; +use crate::common::CommonState; use crate::edit::apply_map_edits; use crate::game::{msg, State, Transition, WizardState}; -use crate::helpers::ID; use crate::managed::WrappedComposite; use crate::ui::UI; use ezgui::{ hotkey, Button, Choice, Color, Composite, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, Text, VerticalAlignment, }; -use map_model::{ - connectivity, EditCmd, IntersectionType, LaneID, LaneType, Map, PathConstraints, RoadID, -}; +use map_model::{EditCmd, LaneID, LaneType, Map, RoadID}; use std::collections::BTreeSet; pub struct LaneEditor { @@ -157,47 +154,6 @@ impl State for LaneEditor { None => {} } - /*// Woo, a special case! The construction tool also applies to intersections. - if let Some(ID::Intersection(i)) = ui.primary.current_selection { - if self.brush == Brush::Construction - && ui - .per_obj - .action(ctx, Key::Space, "closed for construction") - { - let it = ui.primary.map.get_i(i).intersection_type; - if it != IntersectionType::Construction && it != IntersectionType::Border { - let mut edits = ui.primary.map.get_edits().clone(); - edits - .commands - .push(EditCmd::CloseIntersection { id: i, orig_it: it }); - apply_map_edits(ctx, ui, edits); - - let (_, disconnected) = - connectivity::find_scc(&ui.primary.map, PathConstraints::Pedestrian); - if !disconnected.is_empty() { - let mut edits = ui.primary.map.get_edits().clone(); - edits.commands.pop(); - apply_map_edits(ctx, ui, edits); - - let mut err_state = msg( - "Error", - vec![format!("{} sidewalks disconnected", disconnected.len())], - ); - - let color = ui.cs.get("unreachable lane"); - let mut c = Colorer::new(Text::new(), vec![("", color)]); - for l in disconnected { - c.add_l(l, color, &ui.primary.map); - } - - err_state.downcast_mut::().unwrap().also_draw = - Some(c.build_zoomed(ctx, ui)); - return Some(Transition::Push(err_state)); - } - } - } - }*/ - Transition::Keep } diff --git a/game/src/edit/mod.rs b/game/src/edit/mod.rs index cda8d6981b..699d1e23cc 100644 --- a/game/src/edit/mod.rs +++ b/game/src/edit/mod.rs @@ -5,9 +5,9 @@ mod traffic_signals; pub use self::lanes::LaneEditor; pub use self::stop_signs::StopSignEditor; pub use self::traffic_signals::TrafficSignalEditor; -use crate::common::{tool_panel, CommonState, Overlays, Warping}; +use crate::common::{tool_panel, Colorer, CommonState, Overlays, Warping}; use crate::debug::DebugMode; -use crate::game::{State, Transition, WizardState}; +use crate::game::{msg, State, Transition, WizardState}; use crate::helpers::ID; use crate::managed::{WrappedComposite, WrappedOutcome}; use crate::render::{DrawIntersection, DrawLane, DrawRoad}; @@ -15,7 +15,9 @@ use crate::sandbox::{GameplayMode, SandboxMode}; use crate::ui::UI; use abstutil::Timer; use ezgui::{hotkey, lctrl, Choice, EventCtx, GfxCtx, Key, Line, ModalMenu, Text, WrappedWizard}; -use map_model::{EditCmd, LaneID, LaneType, MapEdits}; +use map_model::{ + connectivity, EditCmd, IntersectionID, LaneID, LaneType, MapEdits, PathConstraints, +}; use sim::Sim; use std::collections::BTreeSet; @@ -131,7 +133,9 @@ impl State for EditMode { self.suspended_sim.clone(), ))); } - if ui.primary.map.get_i(id).is_closed() && ui.per_obj.action(ctx, Key::R, "revert") { + if ui.primary.map.get_i(id).is_closed() + && ui.per_obj.left_click(ctx, "re-open closed intersection") + { let mut edits = ui.primary.map.get_edits().clone(); edits .commands @@ -316,3 +320,37 @@ pub fn can_edit_lane(mode: &GameplayMode, l: LaneID, ui: &UI) -> bool { && !ui.primary.map.get_l(l).is_sidewalk() && ui.primary.map.get_l(l).lane_type != LaneType::SharedLeftTurn } + +pub fn close_intersection(ctx: &mut EventCtx, ui: &mut UI, i: IntersectionID) -> Transition { + let it = ui.primary.map.get_i(i).intersection_type; + + let mut edits = ui.primary.map.get_edits().clone(); + edits + .commands + .push(EditCmd::CloseIntersection { id: i, orig_it: it }); + apply_map_edits(ctx, ui, edits); + + let (_, disconnected) = connectivity::find_scc(&ui.primary.map, PathConstraints::Pedestrian); + if disconnected.is_empty() { + // Success! Quit the stop sign / signal editor. + return Transition::Pop; + } + + let mut edits = ui.primary.map.get_edits().clone(); + edits.commands.pop(); + apply_map_edits(ctx, ui, edits); + + let mut err_state = msg( + "Error", + vec![format!("{} sidewalks disconnected", disconnected.len())], + ); + + let color = ui.cs.get("unreachable lane"); + let mut c = Colorer::new(Text::new(), vec![("", color)]); + for l in disconnected { + c.add_l(l, color, &ui.primary.map); + } + + err_state.downcast_mut::().unwrap().also_draw = Some(c.build_zoomed(ctx, ui)); + Transition::Push(err_state) +} diff --git a/game/src/edit/stop_signs.rs b/game/src/edit/stop_signs.rs index 569d478b1e..efdf6b236e 100644 --- a/game/src/edit/stop_signs.rs +++ b/game/src/edit/stop_signs.rs @@ -1,5 +1,5 @@ use crate::common::CommonState; -use crate::edit::apply_map_edits; +use crate::edit::{apply_map_edits, close_intersection}; use crate::game::{State, Transition}; use crate::render::{DrawIntersection, DrawOptions}; use crate::ui::{ShowEverything, UI}; @@ -39,6 +39,7 @@ impl StopSignEditor { vec![ (hotkey(Key::Escape), "quit"), (hotkey(Key::R), "reset to default"), + (None, "close intersection for construction"), ], ctx, ), @@ -91,6 +92,8 @@ impl State for StopSignEditor { self.id, ))); apply_map_edits(ctx, ui, edits); + } else if self.menu.action("close intersection for construction") { + return close_intersection(ctx, ui, self.id); } Transition::Keep } diff --git a/game/src/edit/traffic_signals.rs b/game/src/edit/traffic_signals.rs index 1a6f843bf7..0a41dbb720 100644 --- a/game/src/edit/traffic_signals.rs +++ b/game/src/edit/traffic_signals.rs @@ -1,6 +1,6 @@ use crate::colors; use crate::common::CommonState; -use crate::edit::apply_map_edits; +use crate::edit::{apply_map_edits, close_intersection}; use crate::game::{msg, DrawBaselayer, State, Transition, WizardState}; use crate::helpers::plain_list_names; use crate::managed::{WrappedComposite, WrappedOutcome}; @@ -110,6 +110,9 @@ impl State for TrafficSignalEditor { x if x == "Use preset" => { return Transition::Push(change_preset(self.i)); } + x if x == "Close intersection for construction" => { + return close_intersection(ctx, ui, self.i); + } x if x == "Make all-walk" => { let mut new_signal = orig_signal.clone(); if new_signal.convert_to_ped_scramble(&ui.primary.map) { @@ -443,6 +446,11 @@ fn make_diagram(i: IntersectionID, selected: usize, ui: &UI, ctx: &mut EventCtx) hotkey(Key::B), )); } + col.push(WrappedComposite::text_button( + ctx, + "Close intersection for construction", + None, + )); for (idx, phase) in signal.phases.iter().enumerate() { col.push(