moving turn cycling logic out of SelectionState

This commit is contained in:
Dustin Carlino 2018-09-12 16:05:35 -07:00
parent db098eda69
commit 855258ac97
7 changed files with 127 additions and 43 deletions

View File

@ -903,8 +903,29 @@ have to add?
- and clearing selection state maybe
- are we mouseover it? (right order)
- draw it (right order)
- pick the color for it
try a quadtree with any type of object.
alright, time to move color logic. let's see what it takes for each Renderable to decide its own color -- what state do they need?
- dont forget: search active and lane not a match does yield a color.
- woops, sim Draw{Car,Ped} doesnt implement Renderable. but it'll be nested anyway... we dont want to move stuff in the quadtree constantly. the 'get everything onscreen' routine should do that, interpreting Lanes and Intersections in initial pass of results correctly by querying for more stuff.
- actually, still undecided about color and RenderOptions...
- the whole motivation -- one draw() interface can only return a single color. and dont want to add code to UI for every single object type.
- maybe send in Option<Box<Plugin>> of the current thing, and then it can have a more specific method for each object type? or is that too far the other direction again?
- send in Option<Color>, letting each plugin vote?
- maybe if we only have one or two active plugins, it'll be easier to understand?
- would it be weird to invert and send in all the plugins? the point is
kinda for there to be one place to handle interactions between
plugins -- UI. having a strong concept of one active at a time would probably
_really_ help.
- maybe plugins do have a single color_obj(enum of IDs) -> Option<Color>?
- make it easier to fill out RenderOptions for things generically
- next step: extra things like draw_front_path also take cs, not a specific color -- if it makes sense.
- refactor selection plugin's color_something
- selection plugin currently has this weird case where it can cycle through turns at an intersection. MOVE THAT out.
- more generally, move out all custom logic. make other things know if something is selected and do special stuff if so.
- and make it act generic at last! \o/

View File

@ -12,4 +12,5 @@ pub mod steep;
pub mod stop_sign_editor;
pub mod traffic_signal_editor;
pub mod turn_colors;
pub mod turn_cycler;
pub mod warp;

View File

@ -45,7 +45,7 @@ impl RoadEditor {
RoadEditor::Active(edits) => {
if input.key_pressed(Key::Return, "stop editing roads") {
new_state = Some(RoadEditor::Inactive(edits.clone()));
} else if let SelectionState::SelectedLane(id, _) = *current_selection {
} else if let SelectionState::SelectedLane(id) = *current_selection {
let lane = map.get_l(id);
let road = map.get_r(lane.parent);
let reason = EditReason::BasemapWrong; // TODO be able to choose

View File

@ -30,8 +30,7 @@ pub enum ID {
pub enum SelectionState {
Empty,
SelectedIntersection(IntersectionID),
// Second param is the current_turn_index
SelectedLane(LaneID, Option<usize>),
SelectedLane(LaneID),
SelectedBuilding(BuildingID),
SelectedTurn(TurnID),
SelectedCar(CarID),
@ -64,17 +63,10 @@ impl SelectionState {
) -> bool {
let mut new_state: Option<SelectionState> = None;
let active = match self {
SelectionState::SelectedLane(id, current_turn_index) => {
SelectionState::SelectedLane(id) => {
if input.key_pressed(Key::LCtrl, &format!("Hold Ctrl to show {}'s tooltip", id)) {
new_state = Some(SelectionState::Tooltip(ID::Lane(*id)));
true
} else if input.key_pressed(Key::Tab, "cycle through this lane's turns") {
let idx = match *current_turn_index {
Some(i) => i + 1,
None => 0,
};
new_state = Some(SelectionState::SelectedLane(*id, Some(idx)));
true
} else if input.key_pressed(Key::D, "debug") {
map.get_l(*id).dump_debug();
true
@ -174,7 +166,8 @@ impl SelectionState {
| SelectionState::SelectedBuilding(_)
| SelectionState::SelectedCar(_)
| SelectionState::SelectedPedestrian(_)
| SelectionState::SelectedExtraShape(_) => {}
| SelectionState::SelectedExtraShape(_)
| SelectionState::SelectedLane(_) => {}
SelectionState::SelectedIntersection(id) => {
if let Some(signal) = control_map.traffic_signals.get(&id) {
let (cycle, _) = signal.current_cycle_and_remaining_time(sim.time.as_time());
@ -183,30 +176,6 @@ impl SelectionState {
}
}
}
SelectionState::SelectedLane(id, current_turn_index) => {
let relevant_turns = map.get_turns_from_lane(id);
if !relevant_turns.is_empty() {
match current_turn_index {
Some(idx) => {
let turn = relevant_turns[idx % relevant_turns.len()];
let draw_turn = draw_map.get_t(turn.id);
draw_turn.draw_full(g, cs.get(Colors::Turn));
for t in map.get_turns_in_intersection(turn.parent) {
if t.conflicts_with(turn) {
let draw_t = draw_map.get_t(t.id);
// TODO should we instead change color_t?
draw_t.draw(g, cs.get(Colors::ConflictingTurn), cs);
}
}
}
None => for turn in &relevant_turns {
draw_map.get_t(turn.id).draw_full(g, cs.get(Colors::Turn));
},
}
}
//draw_map.get_l(id).draw_debug(g, cs, map.get_l(id));
}
SelectionState::Tooltip(some_id) => {
let lines = match some_id {
ID::Lane(id) => draw_map.get_l(id).tooltip_lines(map),
@ -225,7 +194,7 @@ impl SelectionState {
pub fn color_for(&self, id: ID, cs: &ColorScheme) -> Option<Color> {
let selected = match (self, id) {
(SelectionState::SelectedIntersection(x), ID::Intersection(y)) => *x == y,
(SelectionState::SelectedLane(x, _), ID::Lane(y)) => *x == y,
(SelectionState::SelectedLane(x), ID::Lane(y)) => *x == y,
(SelectionState::SelectedBuilding(x), ID::Building(y)) => *x == y,
(SelectionState::SelectedTurn(x), ID::Turn(y)) => *x == y,
(SelectionState::SelectedCar(x), ID::Car(y)) => *x == y,
@ -245,7 +214,7 @@ impl SelectionState {
fn selection_state_for(some_id: ID) -> SelectionState {
match some_id {
ID::Intersection(id) => SelectionState::SelectedIntersection(id),
ID::Lane(id) => SelectionState::SelectedLane(id, None),
ID::Lane(id) => SelectionState::SelectedLane(id),
ID::Building(id) => SelectionState::SelectedBuilding(id),
ID::Turn(id) => SelectionState::SelectedTurn(id),
ID::Car(id) => SelectionState::SelectedCar(id),
@ -274,7 +243,7 @@ impl Hider {
let item = match state {
SelectionState::SelectedIntersection(id) => Some(ID::Intersection(*id)),
SelectionState::SelectedLane(id, _) => Some(ID::Lane(*id)),
SelectionState::SelectedLane(id) => Some(ID::Lane(*id)),
SelectionState::SelectedBuilding(id) => Some(ID::Building(*id)),
SelectionState::SelectedExtraShape(id) => Some(ID::ExtraShape(*id)),
_ => None,

View File

@ -0,0 +1,87 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use colors::{ColorScheme, Colors};
use ezgui::{GfxCtx, UserInput};
use map_model::{LaneID, Map};
use piston::input::Key;
use plugins::selection::SelectionState;
use render::{DrawMap, Renderable};
#[derive(Clone, Debug)]
pub enum TurnCyclerState {
Inactive,
Active(LaneID, Option<usize>),
}
impl TurnCyclerState {
pub fn new() -> TurnCyclerState {
TurnCyclerState::Inactive
}
pub fn event(&mut self, input: &mut UserInput, current_selection: &SelectionState) -> bool {
let current_id = match current_selection {
SelectionState::SelectedLane(id) => *id,
_ => {
*self = TurnCyclerState::Inactive;
return false;
}
};
let mut new_state: Option<TurnCyclerState> = None;
let active = match self {
TurnCyclerState::Inactive => {
new_state = Some(TurnCyclerState::Active(current_id, None));
false
}
TurnCyclerState::Active(old_id, current_turn_index) => {
if current_id != *old_id {
new_state = Some(TurnCyclerState::Inactive);
false
} else if input.key_pressed(Key::Tab, "cycle through this lane's turns") {
let idx = match *current_turn_index {
Some(i) => i + 1,
None => 0,
};
new_state = Some(TurnCyclerState::Active(current_id, Some(idx)));
true
} else {
false
}
}
};
if let Some(s) = new_state {
*self = s;
}
active
}
pub fn draw(&self, map: &Map, draw_map: &DrawMap, cs: &ColorScheme, g: &mut GfxCtx) {
match self {
TurnCyclerState::Inactive => {}
TurnCyclerState::Active(l, current_turn_index) => {
let relevant_turns = map.get_turns_from_lane(*l);
if !relevant_turns.is_empty() {
match current_turn_index {
Some(idx) => {
let turn = relevant_turns[idx % relevant_turns.len()];
let draw_turn = draw_map.get_t(turn.id);
draw_turn.draw_full(g, cs.get(Colors::Turn));
for t in map.get_turns_in_intersection(turn.parent) {
if t.conflicts_with(turn) {
let draw_t = draw_map.get_t(t.id);
// TODO should we instead change color_t?
draw_t.draw(g, cs.get(Colors::ConflictingTurn), cs);
}
}
}
None => for turn in &relevant_turns {
draw_map.get_t(turn.id).draw_full(g, cs.get(Colors::Turn));
},
}
}
//draw_map.get_l(id).draw_debug(g, cs, map.get_l(id));
}
}
}
}

View File

@ -73,7 +73,7 @@ fn warp(
if let Some(r) = map.maybe_get_r(id) {
let l = map.get_l(r.children_forwards[0].0);
println!("Warping to {}, which belongs to {}", l.id, id);
*selection_state = SelectionState::SelectedLane(l.id, None);
*selection_state = SelectionState::SelectedLane(l.id);
l.first_pt()
} else {
println!("{} doesn't exist", id);
@ -84,7 +84,7 @@ fn warp(
let id = LaneID(idx);
if let Some(l) = map.maybe_get_l(id) {
println!("Warping to {}", id);
*selection_state = SelectionState::SelectedLane(id, None);
*selection_state = SelectionState::SelectedLane(id);
l.first_pt()
} else {
println!("{} doesn't exist", id);

View File

@ -29,6 +29,7 @@ use plugins::steep::SteepnessVisualizer;
use plugins::stop_sign_editor::StopSignEditor;
use plugins::traffic_signal_editor::TrafficSignalEditor;
use plugins::turn_colors::TurnColors;
use plugins::turn_cycler::TurnCyclerState;
use plugins::warp::WarpState;
use render;
use render::Renderable;
@ -75,6 +76,7 @@ pub struct UI {
sim_ctrl: SimController,
color_picker: ColorPicker,
geom_validator: Validator,
turn_cycler: TurnCyclerState,
canvas: Canvas,
// TODO maybe never pass this to other places? Always resolve colors here?
@ -150,6 +152,7 @@ impl UI {
road_editor: RoadEditor::new(edits),
color_picker: ColorPicker::new(),
geom_validator: Validator::new(),
turn_cycler: TurnCyclerState::new(),
canvas: Canvas::new(),
cs: ColorScheme::load("color_scheme").unwrap(),
@ -478,7 +481,7 @@ impl GUI for UI {
);
if self.show_lanes.handle_event(input) {
if let SelectionState::SelectedLane(_, _) = self.current_selection_state {
if let SelectionState::SelectedLane(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
if let SelectionState::Tooltip(ID::Lane(_)) = self.current_selection_state {
@ -533,6 +536,7 @@ impl GUI for UI {
self.geom_validator
.event(input, &mut self.canvas, &self.map)
);
stop_if_done!(self.turn_cycler.event(input, &self.current_selection_state));
if input.unimportant_key_pressed(Key::I, "Validate map geometry") {
self.geom_validator = Validator::start(&self.draw_map);
@ -575,7 +579,7 @@ impl GUI for UI {
return EventLoopMode::InputOnly;
}
}
SelectionState::SelectedLane(id, _) => {
SelectionState::SelectedLane(id) => {
if input.key_pressed(Key::F, "start floodfilling from this lane") {
self.floodfiller = Floodfiller::start(id);
return EventLoopMode::InputOnly;
@ -735,6 +739,8 @@ impl GUI for UI {
}
}
self.turn_cycler
.draw(&self.map, &self.draw_map, &self.cs, g);
self.current_selection_state.draw(
&self.map,
&self.canvas,