bundling exclusive editor-like plugins together in one meta plugin,

edit_mode
This commit is contained in:
Dustin Carlino 2018-12-05 13:56:21 -08:00
parent f5201bbfa6
commit da46544e99
13 changed files with 254 additions and 56 deletions

View File

@ -66,3 +66,74 @@ classification.rs floodfill.rs map_edits.rs show_activity
color_picker.rs follow.rs mod.rs show_owner.rs traffic_signal_editor.rs
debug_objects.rs geom_validation.rs neighborhood_summary.rs show_route.rs turn_cycler.rs
diff_all.rs hider.rs road_editor.rs sim_controls.rs warp.rs
Gah, bite this off in slow pieces. First find layer-like things... things that
draw/hide stuff. Tend to have very simple activate/deactive controls. No sim interaction.
Or maybe with the exclusive editors...
- in the short term, could make a plugin that just delegates to a smaller list
- except some are per-map and some are not
- wouldnt need that concept if we dont store plugins when
theyre inactive and have a notion of what can simultaneously
be active...
- figure out what other plugins are valid alongside the exclusive editors...
- should activating an editor reset toggleable layers and hidden stuff? that's debug state...
- when is moving via mouse still valid? color picker (right?), neighborhood, road/intersection editors
- intersection and road editors... just debug. and actually, is that even true?
- running a sim / doing time travel shouldnt be valid
debug stuff: toggleable layers, hider, geom validation, floodfill
alright maybe we actually do have lots of exclusive states...
- the exclusive editors
- note that if we're running an A/B test, none of these are valid! cant edit stuff during a/b test... just run.
- explore
- sim controls | time travel
- bunch of nonblocking stuff... chokepoints, classification, debug, diff all, diff trip, floodfill, follow...
- different keys to deactivate them? :P
- some blocking stuff... search, warp. when these're around, run them first
- dir structure... all the exclusive stuff side-by-side, and then a shared/ for stuff that might apply during different states
- the exclusive editors: a_b_tests.rs draw_neighborhoods.rs map_edits.rs scenarios.rs traffic_signal_editor.rs
color_picker.rs road_editor.rs stop_sign_editor.rs
maybe as an initial step, can we get rid of plugins per map vs per UI and just have one or the other?
- every plugin per map?
- toggleable layers then arent shared... fine
- logs is per UI? whoa, that's actually maybe messy!
- sim ctrl, diff world/trip does need to be independent though.
- every plugin per UI?
- when we load a new map from edits, still have to replace the world.
- would have to argue that no plugin that keeps per-map state can run during A/B test mode!
- or rather, that we cant swap while any of those plugins hold state!
- show owner, turn cycler, debug, follow (need to recalculate)
- time travel (needs a/b support generally)
- show route (totally valid to swap while this is going... grrr.)
maybe step 1...
- make a single 'Mode' for exclusive editors
- skip it if a secondary sim is present (aka in A/B mode)
- it lives per UI, because of above condition
- for now, impl it as a hierarchial plugin itself that just delegates
- keep plugin trait for each of em for convenience in edit mode, though.
- each of the editors can stop having inactive state. have new() that returns option
and probably step 2...
- make a single 'Mode' for normal exploration
- let a bunch of plugins run non-exclusively there, as relevant
- and still have a single blocking plugin possible, like warp
and step 3...
- dismantle the plugin abstraction in UI and probably also the trait. do something different for modes.
- clean up event vs new_event

View File

@ -20,7 +20,7 @@ impl ABTestManager {
impl Plugin for ABTestManager {
// May return a new primary and secondary UI
fn event(&mut self, ctx: PluginCtx) -> bool {
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let selected = ctx.primary.current_selection;
let mut new_state: Option<ABTestManager> = None;
@ -47,8 +47,8 @@ impl Plugin for ABTestManager {
let ((new_primary, new_primary_plugins), new_secondary) =
launch_test(test, ctx.kml, &ctx.primary.current_flags);
*ctx.primary = new_primary;
ctx.primary_plugins.map(|p_plugins| {
*p_plugins = new_primary_plugins;
ctx.primary_plugins.as_mut().map(|p_plugins| {
**p_plugins = new_primary_plugins;
});
*ctx.secondary = Some(new_secondary);
new_state = Some(ABTestManager::Inactive);

View File

@ -26,8 +26,8 @@ impl ColorPicker {
}
impl Plugin for ColorPicker {
fn event(&mut self, ctx: PluginCtx) -> bool {
let (input, canvas, cs) = (ctx.input, ctx.canvas, ctx.cs);
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let (input, canvas, cs) = (&mut ctx.input, &ctx.canvas, &mut ctx.cs);
let mut new_state: Option<ColorPicker> = None;
match self {

View File

@ -26,9 +26,13 @@ impl DrawNeighborhoodState {
}
impl Plugin for DrawNeighborhoodState {
fn event(&mut self, ctx: PluginCtx) -> bool {
let (input, canvas, map, osd) =
(ctx.input, ctx.canvas, &ctx.primary.map, &mut ctx.hints.osd);
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let (input, canvas, map, osd) = (
&mut ctx.input,
&ctx.canvas,
&ctx.primary.map,
&mut ctx.hints.osd,
);
let gps_bounds = map.get_gps_bounds();
// TODO This can easily be outside of the map boundary...

View File

@ -18,7 +18,7 @@ impl EditsManager {
}
impl Plugin for EditsManager {
fn event(&mut self, ctx: PluginCtx) -> bool {
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let mut new_state: Option<EditsManager> = None;
match self {
EditsManager::Inactive => {
@ -46,8 +46,8 @@ impl Plugin for EditsManager {
}
if let Some((p, plugins)) = new_primary {
*ctx.primary = p;
ctx.primary_plugins.map(|p_plugins| {
*p_plugins = plugins;
ctx.primary_plugins.as_mut().map(|p_plugins| {
**p_plugins = plugins;
});
}
}

View File

@ -0,0 +1,8 @@
pub mod a_b_tests;
pub mod color_picker;
pub mod draw_neighborhoods;
pub mod map_edits;
pub mod road_editor;
pub mod scenarios;
pub mod stop_sign_editor;
pub mod traffic_signal_editor;

View File

@ -14,9 +14,9 @@ impl RoadEditor {
}
impl Plugin for RoadEditor {
fn event(&mut self, ctx: PluginCtx) -> bool {
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let (input, selected, map, draw_map, sim) = (
ctx.input,
&mut ctx.input,
ctx.primary.current_selection,
&mut ctx.primary.map,
&mut ctx.primary.draw_map,

View File

@ -22,8 +22,8 @@ impl ScenarioManager {
}
impl Plugin for ScenarioManager {
fn event(&mut self, ctx: PluginCtx) -> bool {
let (input, map, sim) = (ctx.input, &ctx.primary.map, &mut ctx.primary.sim);
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let (input, map, sim) = (&mut ctx.input, &ctx.primary.map, &mut ctx.primary.sim);
let mut new_state: Option<ScenarioManager> = None;
match self {
@ -53,6 +53,7 @@ impl Plugin for ScenarioManager {
));
} else if input.key_pressed(Key::I, "instantiate this scenario") {
scenario.instantiate(sim, map);
new_state = Some(ScenarioManager::Inactive);
} else if scroller.event(input) {
new_state = Some(ScenarioManager::Inactive);
}

View File

@ -25,8 +25,8 @@ impl StopSignEditor {
}
impl Plugin for StopSignEditor {
fn event(&mut self, mut ctx: PluginCtx) -> bool {
let input = ctx.input;
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let input = &mut ctx.input;
let map = &mut ctx.primary.map;
let selected = ctx.primary.current_selection;

View File

@ -36,8 +36,8 @@ impl TrafficSignalEditor {
}
impl Plugin for TrafficSignalEditor {
fn event(&mut self, ctx: PluginCtx) -> bool {
let input = ctx.input;
fn new_event(&mut self, ctx: &mut PluginCtx) -> bool {
let input = &mut ctx.input;
let selected = ctx.primary.current_selection;
let inactive = match self {

View File

@ -0,0 +1,129 @@
use ezgui::{Color, GfxCtx};
use map_model::IntersectionID;
use objects::{Ctx, ID};
use plugins;
use plugins::edit::stop_sign_editor::StopSignEditor;
use plugins::edit::traffic_signal_editor::TrafficSignalEditor;
use plugins::{Plugin, PluginCtx};
pub struct EditMode {
active_plugin: Option<Box<Plugin>>,
}
impl EditMode {
pub fn new() -> EditMode {
EditMode {
active_plugin: None,
}
}
pub fn show_turn_icons(&self, id: IntersectionID) -> bool {
if let Some(p) = self
.active_plugin
.as_ref()
.and_then(|p| p.downcast_ref::<StopSignEditor>().ok())
{
return p.show_turn_icons(id);
}
if let Some(p) = self
.active_plugin
.as_ref()
.and_then(|p| p.downcast_ref::<TrafficSignalEditor>().ok())
{
return p.show_turn_icons(id);
}
false
}
}
impl Plugin for EditMode {
fn event(&mut self, mut ctx: PluginCtx) -> bool {
if self.active_plugin.is_some() {
if self.active_plugin.as_mut().unwrap().new_event(&mut ctx) {
return true;
} else {
self.active_plugin = None;
return false;
}
}
// TODO Something higher-level should not even invoke EditMode while we're in A/B test
// mode.
if ctx.secondary.is_some() {
return false;
}
// TODO Make better constructors
{
let mut x = plugins::edit::a_b_tests::ABTestManager::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = plugins::edit::color_picker::ColorPicker::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = plugins::edit::draw_neighborhoods::DrawNeighborhoodState::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = plugins::edit::map_edits::EditsManager::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = plugins::edit::road_editor::RoadEditor::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = plugins::edit::scenarios::ScenarioManager::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = StopSignEditor::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
{
let mut x = TrafficSignalEditor::new();
if x.new_event(&mut ctx) {
self.active_plugin = Some(Box::new(x));
return true;
}
}
false
}
fn draw(&self, g: &mut GfxCtx, ctx: Ctx) {
if let Some(ref plugin) = self.active_plugin {
plugin.draw(g, ctx);
}
}
fn color_for(&self, obj: ID, ctx: Ctx) -> Option<Color> {
if let Some(ref plugin) = self.active_plugin {
return plugin.color_for(obj, ctx);
}
None
}
}

View File

@ -1,30 +1,24 @@
pub mod a_b_tests;
pub mod chokepoints;
pub mod classification;
pub mod color_picker;
pub mod debug_objects;
pub mod diff_all;
pub mod diff_worlds;
pub mod draw_neighborhoods;
pub mod edit;
pub mod edit_mode;
pub mod floodfill;
pub mod follow;
pub mod geom_validation;
pub mod hider;
pub mod layers;
pub mod logs;
pub mod map_edits;
pub mod neighborhood_summary;
pub mod road_editor;
pub mod scenarios;
pub mod search;
pub mod show_activity;
pub mod show_owner;
pub mod show_route;
pub mod sim_controls;
pub mod steep;
pub mod stop_sign_editor;
pub mod time_travel;
pub mod traffic_signal_editor;
pub mod turn_cycler;
pub mod warp;
@ -44,7 +38,15 @@ pub trait Plugin: Any {
fn draw(&self, _g: &mut GfxCtx, _ctx: Ctx) {}
fn event(&mut self, ctx: PluginCtx) -> bool;
// True if active
fn event(&mut self, _ctx: PluginCtx) -> bool {
false
}
// TODO Such hacks
fn new_event(&mut self, _ctx: &mut PluginCtx) -> bool {
false
}
}
downcast!(Plugin);

View File

@ -11,9 +11,9 @@ use map_model::{BuildingID, IntersectionID, LaneID, Map};
use objects::{Ctx, RenderingHints, ID, ROOT_MENU};
use piston::input::Key;
use plugins;
use plugins::edit_mode::EditMode;
use plugins::hider::Hider;
use plugins::layers::ToggleableLayers;
use plugins::stop_sign_editor::StopSignEditor;
use plugins::time_travel::TimeTravel;
use plugins::Plugin;
use render::{DrawMap, RenderOptions};
@ -181,22 +181,12 @@ impl PluginsPerMap {
&self.list[1]
}
fn stop_sign_editor(&self) -> &StopSignEditor {
self.list[2].downcast_ref::<StopSignEditor>().unwrap()
}
fn traffic_signal_editor(&self) -> &plugins::traffic_signal_editor::TrafficSignalEditor {
self.list[3]
.downcast_ref::<plugins::traffic_signal_editor::TrafficSignalEditor>()
.unwrap()
}
fn turn_cycler(&self) -> &Box<Plugin> {
&self.list[4]
&self.list[2]
}
fn time_travel(&self) -> &TimeTravel {
self.list[5].downcast_ref::<TimeTravel>().unwrap()
self.list[3].downcast_ref::<TimeTravel>().unwrap()
}
}
@ -242,8 +232,6 @@ impl PerMapUI {
list: vec![
Box::new(Hider::new()),
Box::new(plugins::show_owner::ShowOwnerState::new()),
Box::new(StopSignEditor::new()),
Box::new(plugins::traffic_signal_editor::TrafficSignalEditor::new()),
Box::new(plugins::turn_cycler::TurnCyclerState::new()),
Box::new(plugins::time_travel::TimeTravel::new()),
Box::new(plugins::debug_objects::DebugObjectsState::new()),
@ -253,8 +241,6 @@ impl PerMapUI {
Box::new(plugins::floodfill::Floodfiller::new()),
Box::new(steepness_viz),
Box::new(plugins::geom_validation::Validator::new()),
Box::new(plugins::draw_neighborhoods::DrawNeighborhoodState::new()),
Box::new(plugins::scenarios::ScenarioManager::new()),
Box::new(plugins::chokepoints::ChokepointsFinder::new()),
Box::new(neighborhood_summary),
],
@ -269,12 +255,16 @@ struct PluginsPerUI {
}
impl PluginsPerUI {
fn edit_mode(&self) -> &EditMode {
self.list[0].downcast_ref::<EditMode>().unwrap()
}
fn layers(&self) -> &ToggleableLayers {
self.list[0].downcast_ref::<ToggleableLayers>().unwrap()
self.list[1].downcast_ref::<ToggleableLayers>().unwrap()
}
fn layers_mut(&mut self) -> &mut ToggleableLayers {
self.list[0].downcast_mut::<ToggleableLayers>().unwrap()
self.list[1].downcast_mut::<ToggleableLayers>().unwrap()
}
}
@ -291,17 +281,14 @@ impl UI {
plugins: PluginsPerUI {
list: vec![
Box::new(EditMode::new()),
Box::new(ToggleableLayers::new()),
Box::new(plugins::search::SearchState::new()),
Box::new(plugins::warp::WarpState::new()),
Box::new(plugins::classification::OsmClassifier::new()),
Box::new(plugins::color_picker::ColorPicker::new()),
Box::new(plugins::a_b_tests::ABTestManager::new()),
Box::new(logs),
Box::new(plugins::diff_all::DiffAllState::new()),
Box::new(plugins::diff_worlds::DiffWorldsState::new()),
Box::new(plugins::road_editor::RoadEditor::new()),
Box::new(plugins::map_edits::EditsManager::new()),
Box::new(plugins::sim_controls::SimController::new()),
],
},
@ -530,11 +517,7 @@ pub trait ShowTurnIcons {
impl ShowTurnIcons for UI {
fn show_icons_for(&self, id: IntersectionID) -> bool {
self.plugins.layers().show_all_turn_icons.is_enabled()
|| self.primary_plugins.stop_sign_editor().show_turn_icons(id)
|| self
.primary_plugins
.traffic_signal_editor()
.show_turn_icons(id)
|| self.plugins.edit_mode().show_turn_icons(id)
|| {
if let Some(ID::Turn(t)) = self.primary.current_selection {
t.parent == id