converting editmode over

This commit is contained in:
Dustin Carlino 2019-06-22 11:03:37 -07:00
parent f86e9666d5
commit 6f2f6a3a75
7 changed files with 394 additions and 398 deletions

View File

@ -7,7 +7,7 @@ mod objects;
mod polygons;
use crate::common::CommonState;
//use crate::edit::EditMode;
use crate::edit::EditMode;
use crate::helpers::ID;
use crate::sandbox::SandboxMode;
use crate::state::{State, Transition};
@ -136,13 +136,15 @@ impl State for DebugMode {
}
if self.menu.action("sandbox mode") {
return (
Transition::Push(Box::new(SandboxMode::new(ctx))),
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
}
if self.menu.action("edit mode") {
//state.mode = Mode::Edit(EditMode::new(ctx, ui));
//return EventLoopMode::InputOnly;
return (
Transition::Replace(Box::new(EditMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
}
if self.menu.action("show/hide chokepoints") {
@ -558,7 +560,7 @@ impl State for SearchOSM {
}
}
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
fn draw(&self, g: &mut GfxCtx, _: &UI) {
self.entry.draw(g);
}
}

View File

@ -3,13 +3,13 @@ mod traffic_signals;
use crate::common::CommonState;
use crate::debug::DebugMode;
use crate::game::{GameState, Mode};
use crate::helpers::{ColorScheme, ID};
use crate::render::{
DrawCtx, DrawIntersection, DrawLane, DrawMap, DrawOptions, DrawTurn, Renderable,
MIN_ZOOM_FOR_DETAIL,
};
use crate::sandbox::SandboxMode;
use crate::state::{State, Transition};
use crate::ui::{PerMapUI, ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
@ -21,13 +21,9 @@ use map_model::{
};
use std::collections::{BTreeSet, HashMap};
pub enum EditMode {
ViewingDiffs(CommonState, ModalMenu),
Saving(Wizard),
Loading(Wizard),
EditingStopSign(stop_signs::StopSignEditor),
EditingTrafficSignal(traffic_signals::TrafficSignalEditor),
BulkEditLanes(RoadID, Wizard),
pub struct EditMode {
common: CommonState,
menu: ModalMenu,
}
impl EditMode {
@ -35,9 +31,9 @@ impl EditMode {
// TODO Warn first?
ui.primary.reset_sim();
EditMode::ViewingDiffs(
CommonState::new(),
ModalMenu::new(
EditMode {
common: CommonState::new(),
menu: ModalMenu::new(
"Map Edit Mode",
vec![
vec![
@ -52,344 +48,346 @@ impl EditMode {
.concat(),
ctx,
),
)
}
}
}
impl State for EditMode {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
// The .clone() is probably not that expensive, and it makes later code a bit
// easier to read. :)
let orig_edits = ui.primary.map.get_edits().clone();
let mut txt = Text::prompt("Map Edit Mode");
{
txt.add_line(orig_edits.edits_name.clone());
txt.add_line(format!("{} lanes", orig_edits.lane_overrides.len()));
txt.add_line(format!(
"{} stop signs ",
orig_edits.stop_sign_overrides.len()
));
txt.add_line(format!(
"{} traffic signals",
orig_edits.traffic_signal_overrides.len()
));
txt.add_line("Right-click a lane or intersection to start editing".to_string());
}
self.menu.handle_event(ctx, Some(txt));
ctx.canvas.handle_event(ctx.input);
// TODO Reset when transitioning in/out of this state? Or maybe we just don't draw
// the effects of it. Or eventually, the Option<ID> itself will live in here
// directly.
// TODO Only mouseover lanes and intersections?
if ctx.redo_mouseover() {
ui.primary.current_selection = ui.recalculate_current_selection(
ctx,
&ui.primary.sim,
&ShowEverything::new(),
false,
);
}
if let Some(evmode) = self.common.event(ctx, ui, &mut self.menu) {
return (Transition::Keep, evmode);
}
if self.menu.action("quit") {
// TODO Warn about unsaved edits
// TODO Maybe put a loading screen around these.
ui.primary
.map
.recalculate_pathfinding_after_edits(&mut Timer::new("apply pending map edits"));
return (Transition::Pop, EventLoopMode::InputOnly);
}
if self.menu.action("sandbox mode") {
ui.primary
.map
.recalculate_pathfinding_after_edits(&mut Timer::new("apply pending map edits"));
return (
Transition::Replace(Box::new(SandboxMode::new(ctx))),
EventLoopMode::InputOnly,
);
}
if self.menu.action("debug mode") {
ui.primary
.map
.recalculate_pathfinding_after_edits(&mut Timer::new("apply pending map edits"));
return (
Transition::Replace(Box::new(DebugMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
}
// TODO Only if current edits are unsaved
if self.menu.action("save edits") {
return (
Transition::Push(Box::new(Saving {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
} else if self.menu.action("load different edits") {
return (
Transition::Push(Box::new(Loading {
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
}
if let Some(ID::Lane(id)) = ui.primary.current_selection {
// TODO Urgh, borrow checker.
{
let lane = ui.primary.map.get_l(id);
let road = ui.primary.map.get_r(lane.parent);
if lane.lane_type != LaneType::Sidewalk {
if let Some(new_type) = next_valid_type(road, lane, &ui.primary.map) {
if ctx
.input
.contextual_action(Key::Space, &format!("toggle to {:?}", new_type))
{
let mut new_edits = orig_edits.clone();
new_edits.lane_overrides.insert(lane.id, new_type);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
}
}
}
{
let lane = ui.primary.map.get_l(id);
let road = ui.primary.map.get_r(lane.parent);
if lane.lane_type != LaneType::Sidewalk {
for (lt, name, key) in &[
(LaneType::Driving, "driving", Key::D),
(LaneType::Parking, "parking", Key::P),
(LaneType::Biking, "biking", Key::B),
(LaneType::Bus, "bus", Key::T),
] {
if can_change_lane_type(road, lane, *lt, &ui.primary.map)
&& ctx
.input
.contextual_action(*key, &format!("change to {} lane", name))
{
let mut new_edits = orig_edits.clone();
new_edits.lane_overrides.insert(lane.id, *lt);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
break;
}
}
}
}
if ctx
.input
.contextual_action(Key::U, "bulk edit lanes on this road")
{
return (
Transition::Push(Box::new(BulkEditLanes {
road: ui.primary.map.get_l(id).parent,
wizard: Wizard::new(),
})),
EventLoopMode::InputOnly,
);
} else if orig_edits.lane_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
let mut new_edits = orig_edits.clone();
new_edits.lane_overrides.remove(&id);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
}
if let Some(ID::Intersection(id)) = ui.primary.current_selection {
if ui.primary.map.maybe_get_stop_sign(id).is_some() {
if ctx
.input
.contextual_action(Key::E, &format!("edit stop signs for {}", id))
{
return (
Transition::Push(Box::new(stop_signs::StopSignEditor::new(id, ctx, ui))),
EventLoopMode::InputOnly,
);
} else if orig_edits.stop_sign_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
let mut new_edits = orig_edits.clone();
new_edits.stop_sign_overrides.remove(&id);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
}
if ui.primary.map.maybe_get_traffic_signal(id).is_some() {
if ctx
.input
.contextual_action(Key::E, &format!("edit traffic signal for {}", id))
{
return (
Transition::Push(Box::new(traffic_signals::TrafficSignalEditor::new(
id, ctx, ui,
))),
EventLoopMode::InputOnly,
);
} else if orig_edits.traffic_signal_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
let mut new_edits = orig_edits.clone();
new_edits.traffic_signal_overrides.remove(&id);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
}
}
(Transition::Keep, EventLoopMode::InputOnly)
}
pub fn event(state: &mut GameState, ctx: &mut EventCtx) -> EventLoopMode {
match state.mode {
Mode::Edit(EditMode::ViewingDiffs(ref mut common, ref mut menu)) => {
// The .clone() is probably not that expensive, and it makes later code a bit
// easier to read. :)
let orig_edits = state.ui.primary.map.get_edits().clone();
let mut txt = Text::prompt("Map Edit Mode");
{
txt.add_line(orig_edits.edits_name.clone());
txt.add_line(format!("{} lanes", orig_edits.lane_overrides.len()));
txt.add_line(format!(
"{} stop signs ",
orig_edits.stop_sign_overrides.len()
));
txt.add_line(format!(
"{} traffic signals",
orig_edits.traffic_signal_overrides.len()
));
txt.add_line("Right-click a lane or intersection to start editing".to_string());
}
menu.handle_event(ctx, Some(txt));
fn draw_default_ui(&self) -> bool {
false
}
ctx.canvas.handle_event(ctx.input);
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
ui.draw(
g,
self.common.draw_options(ui),
&ui.primary.sim,
&ShowEverything::new(),
);
// TODO Reset when transitioning in/out of this state? Or maybe we just don't draw
// the effects of it. Or eventually, the Option<ID> itself will live in here
// directly.
// TODO Only mouseover lanes and intersections?
if ctx.redo_mouseover() {
state.ui.primary.current_selection = state.ui.recalculate_current_selection(
ctx,
&state.ui.primary.sim,
&ShowEverything::new(),
false,
// More generally we might want to show the diff between two edits, but for now,
// just show diff relative to basemap.
let edits = ui.primary.map.get_edits();
let ctx = DrawCtx {
cs: &ui.cs,
map: &ui.primary.map,
draw_map: &ui.primary.draw_map,
sim: &ui.primary.sim,
};
let mut opts = DrawOptions::new();
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
// supply a set of things to highlight and have something else take care of drawing
// with detail or not.
if g.canvas.cam_zoom >= MIN_ZOOM_FOR_DETAIL {
g.enable_hatching();
for l in edits.lane_overrides.keys() {
ctx.draw_map.get_l(*l).draw(g, &opts, &ctx);
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
ctx.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
g.disable_hatching();
// The hatching covers up the selection outline, so redraw it.
match ui.primary.current_selection {
Some(ID::Lane(l)) => {
g.draw_polygon(
ui.cs.get("selected"),
&ctx.draw_map.get_l(l).get_outline(&ctx.map),
);
}
if let Some(evmode) = common.event(ctx, &mut state.ui, menu) {
return evmode;
Some(ID::Intersection(i)) => {
g.draw_polygon(
ui.cs.get("selected"),
&ctx.draw_map.get_i(i).get_outline(&ctx.map),
);
}
_ => {}
}
} else {
let color = ui.cs.get_def("unzoomed map diffs", Color::RED);
for l in edits.lane_overrides.keys() {
g.draw_polygon(color, &ctx.map.get_parent(*l).get_thick_polygon().unwrap());
}
if menu.action("quit") {
// TODO Warn about unsaved edits
// TODO Maybe put a loading screen around these.
state
.ui
.primary
.map
.recalculate_pathfinding_after_edits(&mut Timer::new(
"apply pending map edits",
));
state.mode = Mode::SplashScreen(Wizard::new(), None);
return EventLoopMode::InputOnly;
}
if menu.action("sandbox mode") {
state
.ui
.primary
.map
.recalculate_pathfinding_after_edits(&mut Timer::new(
"apply pending map edits",
));
state.mode = Mode::Sandbox(SandboxMode::new(ctx));
return EventLoopMode::InputOnly;
}
if menu.action("debug mode") {
state
.ui
.primary
.map
.recalculate_pathfinding_after_edits(&mut Timer::new(
"apply pending map edits",
));
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()));
return EventLoopMode::InputOnly;
} else if menu.action("load different edits") {
state.mode = Mode::Edit(EditMode::Loading(Wizard::new()));
return EventLoopMode::InputOnly;
}
if let Some(ID::Lane(id)) = state.ui.primary.current_selection {
// TODO Urgh, borrow checker.
{
let lane = state.ui.primary.map.get_l(id);
let road = state.ui.primary.map.get_r(lane.parent);
if lane.lane_type != LaneType::Sidewalk {
if let Some(new_type) =
next_valid_type(road, lane, &state.ui.primary.map)
{
if ctx.input.contextual_action(
Key::Space,
&format!("toggle to {:?}", new_type),
) {
let mut new_edits = orig_edits.clone();
new_edits.lane_overrides.insert(lane.id, new_type);
apply_map_edits(
&mut state.ui.primary,
&state.ui.cs,
ctx,
new_edits,
);
}
}
}
}
{
let lane = state.ui.primary.map.get_l(id);
let road = state.ui.primary.map.get_r(lane.parent);
if lane.lane_type != LaneType::Sidewalk {
for (lt, name, key) in &[
(LaneType::Driving, "driving", Key::D),
(LaneType::Parking, "parking", Key::P),
(LaneType::Biking, "biking", Key::B),
(LaneType::Bus, "bus", Key::T),
] {
if can_change_lane_type(road, lane, *lt, &state.ui.primary.map)
&& ctx.input.contextual_action(
*key,
&format!("change to {} lane", name),
)
{
let mut new_edits = orig_edits.clone();
new_edits.lane_overrides.insert(lane.id, *lt);
apply_map_edits(
&mut state.ui.primary,
&state.ui.cs,
ctx,
new_edits,
);
break;
}
}
}
}
if ctx
.input
.contextual_action(Key::U, "bulk edit lanes on this road")
{
state.mode = Mode::Edit(EditMode::BulkEditLanes(
state.ui.primary.map.get_l(id).parent,
Wizard::new(),
));
} else if orig_edits.lane_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
let mut new_edits = orig_edits.clone();
new_edits.lane_overrides.remove(&id);
apply_map_edits(&mut state.ui.primary, &state.ui.cs, ctx, new_edits);
}
}
if let Some(ID::Intersection(id)) = state.ui.primary.current_selection {
if state.ui.primary.map.maybe_get_stop_sign(id).is_some() {
if ctx
.input
.contextual_action(Key::E, &format!("edit stop signs for {}", id))
{
state.mode = Mode::Edit(EditMode::EditingStopSign(
stop_signs::StopSignEditor::new(id, ctx, &mut state.ui),
));
} else if orig_edits.stop_sign_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
let mut new_edits = orig_edits.clone();
new_edits.stop_sign_overrides.remove(&id);
apply_map_edits(&mut state.ui.primary, &state.ui.cs, ctx, new_edits);
}
}
if state.ui.primary.map.maybe_get_traffic_signal(id).is_some() {
if ctx
.input
.contextual_action(Key::E, &format!("edit traffic signal for {}", id))
{
state.mode = Mode::Edit(EditMode::EditingTrafficSignal(
traffic_signals::TrafficSignalEditor::new(id, ctx, &mut state.ui),
));
} else if orig_edits.traffic_signal_overrides.contains_key(&id)
&& ctx.input.contextual_action(Key::R, "revert")
{
let mut new_edits = orig_edits.clone();
new_edits.traffic_signal_overrides.remove(&id);
apply_map_edits(&mut state.ui.primary, &state.ui.cs, ctx, new_edits);
}
}
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
opts.override_colors.insert(ID::Intersection(*i), color);
ctx.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
Mode::Edit(EditMode::Saving(ref mut wizard)) => {
ctx.canvas.handle_event(ctx.input);
if save_edits(wizard.wrap(ctx), &mut state.ui.primary.map).is_some()
|| wizard.aborted()
{
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
}
}
Mode::Edit(EditMode::Loading(ref mut wizard)) => {
ctx.canvas.handle_event(ctx.input);
if let Some(new_edits) = load_edits(
&state.ui.primary.map,
&mut wizard.wrap(ctx),
"Load which map edits?",
) {
apply_map_edits(&mut state.ui.primary, &state.ui.cs, ctx, new_edits);
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
} else if wizard.aborted() {
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
}
}
Mode::Edit(EditMode::EditingStopSign(ref mut editor)) => {
if editor.event(ctx, &mut state.ui) {
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
}
}
Mode::Edit(EditMode::EditingTrafficSignal(ref mut editor)) => {
if editor.event(ctx, &mut state.ui) {
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
}
}
Mode::Edit(EditMode::BulkEditLanes(r, ref mut wizard)) => {
ctx.canvas.handle_event(ctx.input);
if let Some(edits) = bulk_edit(r, &mut wizard.wrap(ctx), &state.ui.primary.map) {
apply_map_edits(&mut state.ui.primary, &state.ui.cs, ctx, edits);
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
} else if wizard.aborted() {
state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
}
}
_ => unreachable!(),
}
EventLoopMode::InputOnly
self.common.draw(g, ui);
self.menu.draw(g);
}
}
struct Saving {
wizard: Wizard,
}
impl State for Saving {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
ctx.canvas.handle_event(ctx.input);
if save_edits(self.wizard.wrap(ctx), &mut ui.primary.map).is_some() || self.wizard.aborted()
{
(Transition::Pop, EventLoopMode::InputOnly)
} else {
(Transition::Keep, EventLoopMode::InputOnly)
}
}
pub fn draw(state: &GameState, g: &mut GfxCtx) {
match state.mode {
Mode::Edit(EditMode::ViewingDiffs(ref common, ref menu)) => {
state.ui.draw(
g,
common.draw_options(&state.ui),
&state.ui.primary.sim,
&ShowEverything::new(),
);
fn draw(&self, g: &mut GfxCtx, _: &UI) {
// TODO Still draw the diffs, yo
self.wizard.draw(g);
}
}
// More generally we might want to show the diff between two edits, but for now,
// just show diff relative to basemap.
let edits = state.ui.primary.map.get_edits();
struct Loading {
wizard: Wizard,
}
let ctx = DrawCtx {
cs: &state.ui.cs,
map: &state.ui.primary.map,
draw_map: &state.ui.primary.draw_map,
sim: &state.ui.primary.sim,
};
let mut opts = DrawOptions::new();
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
// supply a set of things to highlight and have something else take care of drawing
// with detail or not.
if g.canvas.cam_zoom >= MIN_ZOOM_FOR_DETAIL {
g.enable_hatching();
for l in edits.lane_overrides.keys() {
ctx.draw_map.get_l(*l).draw(g, &opts, &ctx);
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
ctx.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
g.disable_hatching();
// The hatching covers up the selection outline, so redraw it.
match state.ui.primary.current_selection {
Some(ID::Lane(l)) => {
g.draw_polygon(
state.ui.cs.get("selected"),
&ctx.draw_map.get_l(l).get_outline(&ctx.map),
);
}
Some(ID::Intersection(i)) => {
g.draw_polygon(
state.ui.cs.get("selected"),
&ctx.draw_map.get_i(i).get_outline(&ctx.map),
);
}
_ => {}
}
} else {
let color = state.ui.cs.get_def("unzoomed map diffs", Color::RED);
for l in edits.lane_overrides.keys() {
g.draw_polygon(color, &ctx.map.get_parent(*l).get_thick_polygon().unwrap());
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
opts.override_colors.insert(ID::Intersection(*i), color);
ctx.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
}
common.draw(g, &state.ui);
menu.draw(g);
}
Mode::Edit(EditMode::Saving(ref wizard))
| Mode::Edit(EditMode::Loading(ref wizard))
| Mode::Edit(EditMode::BulkEditLanes(_, ref wizard)) => {
state.ui.draw(
g,
DrawOptions::new(),
&state.ui.primary.sim,
&ShowEverything::new(),
);
// TODO Still draw the diffs, yo
wizard.draw(g);
}
Mode::Edit(EditMode::EditingStopSign(ref editor)) => {
editor.draw(g, state);
}
Mode::Edit(EditMode::EditingTrafficSignal(ref editor)) => {
editor.draw(g, state);
}
_ => unreachable!(),
impl State for Loading {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
ctx.canvas.handle_event(ctx.input);
if let Some(new_edits) = load_edits(
&ui.primary.map,
&mut self.wizard.wrap(ctx),
"Load which map edits?",
) {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
(Transition::Pop, EventLoopMode::InputOnly)
} else if self.wizard.aborted() {
(Transition::Pop, EventLoopMode::InputOnly)
} else {
(Transition::Keep, EventLoopMode::InputOnly)
}
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
// TODO Still draw the diffs, yo
self.wizard.draw(g);
}
}
struct BulkEditLanes {
road: RoadID,
wizard: Wizard,
}
impl State for BulkEditLanes {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
ctx.canvas.handle_event(ctx.input);
if let Some(edits) = bulk_edit(self.road, &mut self.wizard.wrap(ctx), &ui.primary.map) {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, edits);
(Transition::Pop, EventLoopMode::InputOnly)
} else if self.wizard.aborted() {
(Transition::Pop, EventLoopMode::InputOnly)
} else {
(Transition::Keep, EventLoopMode::InputOnly)
}
}
fn draw(&self, g: &mut GfxCtx, _: &UI) {
// TODO Still draw the diffs, yo
self.wizard.draw(g);
}
}
fn save_edits(mut wizard: WrappedWizard, map: &mut Map) -> Option<()> {

View File

@ -1,10 +1,10 @@
use crate::common::CommonState;
use crate::edit::apply_map_edits;
use crate::game::GameState;
use crate::helpers::ID;
use crate::render::{DrawIntersection, DrawOptions, DrawTurn};
use crate::state::{State, Transition};
use crate::ui::{ShowEverything, UI};
use ezgui::{hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Text};
use ezgui::{hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, Text};
use geom::Polygon;
use map_model::{IntersectionID, RoadID, TurnID, TurnPriority};
use std::collections::HashMap;
@ -48,9 +48,10 @@ impl StopSignEditor {
selected_turn: None,
}
}
}
// Returns true if the editor is done and we should go back to main edit mode.
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
impl State for StopSignEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
self.menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input);
@ -107,23 +108,23 @@ impl StopSignEditor {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
} else if self.menu.action("quit") {
return true;
return (Transition::Pop, EventLoopMode::InputOnly);
} else if self.menu.action("reset to default") {
let mut new_edits = ui.primary.map.get_edits().clone();
new_edits.stop_sign_overrides.remove(&self.id);
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
false
(Transition::Keep, EventLoopMode::InputOnly)
}
pub fn draw(&self, g: &mut GfxCtx, state: &GameState) {
state.ui.draw(
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
ui.draw(
g,
DrawOptions::new(),
&state.ui.primary.sim,
&ui.primary.sim,
&ShowEverything::new(),
);
let map = &state.ui.primary.map;
let map = &ui.primary.map;
let sign = map.get_stop_sign(self.id);
let mut batch = GeomBatch::new();
@ -132,33 +133,31 @@ impl StopSignEditor {
// The intersection will already draw enabled stop signs
if Some(*r) == self.selected_sign {
batch.push(
state.ui.cs.get_def("selected stop sign", Color::BLUE),
ui.cs.get_def("selected stop sign", Color::BLUE),
octagon.clone(),
);
if !sign.roads[r].enabled {
batch.push(state.ui.cs.get("stop sign pole").alpha(0.6), pole.clone());
batch.push(ui.cs.get("stop sign pole").alpha(0.6), pole.clone());
}
} else if !sign.roads[r].enabled {
batch.push(
state.ui.cs.get("stop sign on side of road").alpha(0.6),
ui.cs.get("stop sign on side of road").alpha(0.6),
octagon.clone(),
);
batch.push(state.ui.cs.get("stop sign pole").alpha(0.6), pole.clone());
batch.push(ui.cs.get("stop sign pole").alpha(0.6), pole.clone());
}
}
for t in &state.ui.primary.draw_map.get_turns(self.id, map) {
for t in &ui.primary.draw_map.get_turns(self.id, map) {
let arrow_color = match sign.get_priority(t.id) {
TurnPriority::Priority => {
state.ui.cs.get_def("priority stop sign turn", Color::GREEN)
}
TurnPriority::Yield => state.ui.cs.get_def("yield stop sign turn", Color::YELLOW),
TurnPriority::Stop => state.ui.cs.get_def("stop turn", Color::RED),
TurnPriority::Banned => state.ui.cs.get_def("banned turn", Color::BLACK),
TurnPriority::Priority => ui.cs.get_def("priority stop sign turn", Color::GREEN),
TurnPriority::Yield => ui.cs.get_def("yield stop sign turn", Color::YELLOW),
TurnPriority::Stop => ui.cs.get_def("stop turn", Color::RED),
TurnPriority::Banned => ui.cs.get_def("banned turn", Color::BLACK),
};
t.draw_icon(
&mut batch,
&state.ui.cs,
&ui.cs,
arrow_color,
self.selected_turn == Some(t.id),
);
@ -167,7 +166,7 @@ impl StopSignEditor {
DrawTurn::draw_dashed(
map.get_t(id),
&mut batch,
state.ui.cs.get_def("selected turn", Color::RED),
ui.cs.get_def("selected turn", Color::RED),
);
}
batch.draw(g);
@ -176,14 +175,14 @@ impl StopSignEditor {
if let Some(r) = self.selected_sign {
let mut osd = Text::from_line("Stop sign for ".to_string());
osd.append(
state.ui.primary.map.get_r(r).get_name(),
Some(state.ui.cs.get("OSD name color")),
ui.primary.map.get_r(r).get_name(),
Some(ui.cs.get("OSD name color")),
);
CommonState::draw_custom_osd(g, osd);
} else if let Some(t) = self.selected_turn {
CommonState::draw_osd(g, &state.ui, Some(ID::Turn(t)));
CommonState::draw_osd(g, ui, Some(ID::Turn(t)));
} else {
CommonState::draw_osd(g, &state.ui, None);
CommonState::draw_osd(g, ui, None);
}
}
}

View File

@ -1,12 +1,13 @@
use crate::common::CommonState;
use crate::edit::apply_map_edits;
use crate::game::GameState;
use crate::helpers::ID;
use crate::render::{draw_signal_cycle, draw_signal_diagram, DrawCtx, DrawOptions, DrawTurn};
use crate::state::{State, Transition};
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
hotkey, Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, MultiKey, Wizard, WrappedWizard,
hotkey, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, ModalMenu, MultiKey, Wizard,
WrappedWizard,
};
use geom::Duration;
use map_model::{ControlTrafficSignal, Cycle, IntersectionID, Map, TurnID, TurnPriority, TurnType};
@ -56,9 +57,10 @@ impl TrafficSignalEditor {
icon_selected: None,
}
}
}
// Returns true if the editor is done and we should go back to main edit mode.
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
impl State for TrafficSignalEditor {
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> (Transition, EventLoopMode) {
self.menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input);
@ -148,7 +150,7 @@ impl TrafficSignalEditor {
}
} else {
if self.menu.action("quit") {
return true;
return (Transition::Pop, EventLoopMode::InputOnly);
}
if self.current_cycle != 0 && self.menu.action("select previous cycle") {
@ -234,41 +236,34 @@ impl TrafficSignalEditor {
apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits);
}
false
(Transition::Keep, EventLoopMode::InputOnly)
}
pub fn draw(&self, g: &mut GfxCtx, state: &GameState) {
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
{
let mut opts = DrawOptions::new();
opts.suppress_traffic_signal_details = Some(self.i);
state
.ui
.draw(g, opts, &state.ui.primary.sim, &ShowEverything::new());
ui.draw(g, opts, &ui.primary.sim, &ShowEverything::new());
}
let mut batch = GeomBatch::new();
let ctx = DrawCtx {
cs: &state.ui.cs,
map: &state.ui.primary.map,
draw_map: &state.ui.primary.draw_map,
sim: &state.ui.primary.sim,
cs: &ui.cs,
map: &ui.primary.map,
draw_map: &ui.primary.draw_map,
sim: &ui.primary.sim,
};
let map = &state.ui.primary.map;
let map = &ui.primary.map;
let cycle = &map.get_traffic_signal(self.i).cycles[self.current_cycle];
for t in &state.ui.primary.draw_map.get_turns(self.i, map) {
for t in &ui.primary.draw_map.get_turns(self.i, map) {
let arrow_color = match cycle.get_priority(t.id) {
TurnPriority::Priority => state
.ui
TurnPriority::Priority => ui
.cs
.get_def("priority turn in current cycle", Color::GREEN),
TurnPriority::Yield => state
.ui
TurnPriority::Yield => ui
.cs
.get_def("yield turn in current cycle", Color::rgb(255, 105, 180)),
TurnPriority::Banned => state
.ui
.cs
.get_def("turn not in current cycle", Color::BLACK),
TurnPriority::Banned => ui.cs.get_def("turn not in current cycle", Color::BLACK),
TurnPriority::Stop => panic!("Can't have TurnPriority::Stop in a traffic signal"),
};
t.draw_icon(
@ -280,7 +275,7 @@ impl TrafficSignalEditor {
}
draw_signal_cycle(cycle, None, &mut batch, &ctx);
if let Some(id) = self.icon_selected {
DrawTurn::draw_dashed(map.get_t(id), &mut batch, state.ui.cs.get("selected turn"));
DrawTurn::draw_dashed(map.get_t(id), &mut batch, ui.cs.get("selected turn"));
}
batch.draw(g);
@ -294,9 +289,9 @@ impl TrafficSignalEditor {
self.menu.draw(g);
if let Some(t) = self.icon_selected {
CommonState::draw_osd(g, &state.ui, Some(ID::Turn(t)));
CommonState::draw_osd(g, ui, Some(ID::Turn(t)));
} else {
CommonState::draw_osd(g, &state.ui, None);
CommonState::draw_osd(g, ui, None);
}
}
}

View File

@ -1,6 +1,6 @@
//use crate::abtest::ABTestMode;
use crate::debug::DebugMode;
//use crate::edit::EditMode;
use crate::edit::EditMode;
//use crate::mission::MissionEditMode;
use crate::render::DrawOptions;
use crate::sandbox::SandboxMode;
@ -277,8 +277,8 @@ fn splash_screen(
None
}
}
/*x if x == edit => break Some(Mode::Edit(EditMode::new(ctx, ui))),
x if x == tutorial => break Some(Mode::Tutorial(TutorialMode::new(ctx, ui))),*/
x if x == edit => Some(Transition::Push(Box::new(EditMode::new(ctx, ui)))),
//x if x == tutorial => break Some(Mode::Tutorial(TutorialMode::new(ctx, ui))),
x if x == debug => Some(Transition::Push(Box::new(DebugMode::new(ctx, ui)))),
/*x if x == mission => break Some(Mode::Mission(MissionEditMode::new(ctx, ui))),
x if x == abtest => {

View File

@ -1,7 +1,7 @@
//mod abtest;
mod common;
mod debug;
//mod edit;
mod edit;
mod game;
mod helpers;
//mod mission;

View File

@ -7,7 +7,7 @@ mod time_travel;
use crate::common::{CommonState, SpeedControls};
use crate::debug::DebugMode;
//use crate::edit::EditMode;
use crate::edit::EditMode;
use crate::state::{State, Transition};
//use crate::mission::input_time;
use crate::ui::{ShowEverything, UI};
@ -181,8 +181,10 @@ impl State for SandboxMode {
);
}
if self.menu.action("edit mode") {
//state.mode = Mode::Edit(EditMode::new(ctx, &mut state.ui));
//return EventLoopMode::InputOnly;
return (
Transition::Replace(Box::new(EditMode::new(ctx, ui))),
EventLoopMode::InputOnly,
);
}
if let Some(dt) = self.speed.event(ctx, &mut self.menu, ui.primary.sim.time()) {