easy way to select and delete big chunk of stuff in synthetic

This commit is contained in:
Dustin Carlino 2019-09-16 10:16:56 -07:00
parent 0543cb015e
commit 4a12cdd36a
5 changed files with 137 additions and 7 deletions

View File

@ -77,5 +77,6 @@ Street strives to set the accessibility bar high, by being a fun, engaging game.
I'm a one-person team. If you want to bring this to your city or if you're
skilled in user experience design, traffic simulation, data visualization, or
civic/government outreach, please contact Dustin Carlino at
<dabreegster@gmail.com>. I also welcome any contributions on
[Patreon](https://www.patreon.com/abstreet).
<dabreegster@gmail.com> or post at
[r/abstreet](https://www.reddit.com/r/abstreet/). I also welcome any
contributions on [Patreon](https://www.patreon.com/abstreet).

View File

@ -0,0 +1,56 @@
// TODO None of this works yet.
use crate::{Color, MultiKey, ScreenDims, ScreenPt, Text};
// TODO This is the concrete state at some time. When something changes, how do we recalculate it?
struct Panel {
rows: Vec<Row>,
top_left: ScreenPt,
bg: Option<Color>,
}
struct Row {
total_width: f64,
total_height: f64,
bg: Option<Color>,
items: Vec<Item>,
}
enum Item {
Text(Text),
Button(Option<MultiKey>, String),
HideIcon,
UnhideIcon,
Spacer(ScreenDims),
}
fn modal_menu_ex() {
let mut panel = Panel {
rows: vec![
Row {
bg: Some(Color::BLUE),
items: vec![Item::Text(Text::from(Line("title").fg(Color::WHITE))), Item::HideIcon],
},
Row {
bg: None,
items: vec![Item::Button(hotkey(Key::L), "load thingy")],
}
Row {
bg: None,
items: vec![Item::Button(hotkey(Key::M), "manage thingy")],
}
Row {
bg: Some(Color::BLACK),
// TODO really the spacer should expand to full width...
items: vec![Item::Spacer(ScreenDims::new(1.0, 30.0))],
},
Row {
bg: None,
items: vec![Item::Button(None, "complex action")],
}
],
bg: Some(Color::grey(0.5)),
};
}
// TODO how could scrolling be built on top of this?

View File

@ -152,6 +152,26 @@ impl Polygon {
}
}
pub fn rectangle_two_corners(pt1: Pt2D, pt2: Pt2D) -> Option<Polygon> {
if Pt2D::new(pt1.x(), 0.0).epsilon_eq(Pt2D::new(pt2.x(), 0.0))
|| Pt2D::new(0.0, pt1.y()).epsilon_eq(Pt2D::new(0.0, pt2.y()))
{
return None;
}
let (x1, width) = if pt1.x() < pt2.x() {
(pt1.x(), Distance::meters(pt2.x() - pt1.x()))
} else {
(pt2.x(), Distance::meters(pt1.x() - pt2.x()))
};
let (y1, height) = if pt1.y() < pt2.y() {
(pt1.y(), Distance::meters(pt2.y() - pt1.y()))
} else {
(pt2.y(), Distance::meters(pt1.y() - pt2.y()))
};
Some(Polygon::rectangle_topleft(Pt2D::new(x1, y1), width, height))
}
pub fn union(self, other: Polygon) -> Polygon {
let mut points = self.points;
let mut indices = self.indices;

View File

@ -1,7 +1,7 @@
mod model;
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, Line, Text, Wizard, GUI};
use geom::{Distance, Line};
use geom::{Distance, Line, Polygon, Pt2D};
use map_model::raw_data::{StableIntersectionID, StableRoadID};
use model::{BuildingID, Direction, Model, ID};
use std::{env, process};
@ -22,6 +22,8 @@ enum State {
CreatingRoad(StableIntersectionID),
EditingRoad(StableRoadID, Wizard),
SavingModel(Wizard),
// bool is if key is down
SelectingRectangle(Pt2D, Pt2D, bool),
}
impl UI {
@ -102,7 +104,7 @@ impl GUI for UI {
self.model.handle_mouseover(ctx);
} else if let Some(ID::Intersection(i2)) = self.model.get_selection() {
if i1 != i2 && ctx.input.key_pressed(Key::R, "finalize road") {
self.model.create_road(i1, i2, ctx.prerender);
self.model.create_r(i1, i2, ctx.prerender);
self.state = State::Viewing;
self.model.handle_mouseover(ctx);
}
@ -159,7 +161,7 @@ impl GUI for UI {
.input
.key_pressed(Key::Backspace, &format!("delete road {}", r))
{
self.model.remove_road(r);
self.model.remove_r(r);
self.model.handle_mouseover(ctx);
} else if ctx.input.key_pressed(Key::E, "edit lanes") {
self.state = State::EditingRoad(r, Wizard::new());
@ -185,6 +187,33 @@ impl GUI for UI {
} else if cursor.is_some() && ctx.input.key_pressed(Key::B, "create building") {
self.model.create_b(cursor.unwrap(), ctx.prerender);
self.model.handle_mouseover(ctx);
} else if cursor.is_some() && ctx.input.key_pressed(Key::LeftShift, "select area") {
self.state = State::SelectingRectangle(cursor.unwrap(), cursor.unwrap(), true);
}
}
State::SelectingRectangle(pt1, ref mut pt2, ref mut keydown) => {
if ctx.input.key_pressed(Key::LeftShift, "select area") {
*keydown = true;
} else if ctx.input.key_released(Key::LeftShift) {
*keydown = false;
}
if *keydown {
if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() {
*pt2 = cursor;
}
}
if ctx.input.key_pressed(Key::Escape, "stop selecting area") {
self.state = State::Viewing;
} else if ctx
.input
.key_pressed(Key::Backspace, "delete everything area")
{
if let Some(rect) = Polygon::rectangle_two_corners(pt1, *pt2) {
self.model.delete_everything_inside(rect);
self.model.handle_mouseover(ctx);
}
self.state = State::Viewing;
}
}
}
@ -232,6 +261,11 @@ impl GUI for UI {
}
}
State::MovingIntersection(_) | State::MovingBuilding(_) => {}
State::SelectingRectangle(pt1, pt2, _) => {
if let Some(rect) = Polygon::rectangle_two_corners(pt1, pt2) {
g.draw_polygon(Color::BLUE.alpha(0.5), &rect);
}
}
};
g.draw_blocking_text(&self.osd, ezgui::BOTTOM_LEFT);

View File

@ -361,6 +361,25 @@ impl Model {
self.road_added(id, prerender);
}
}
pub fn delete_everything_inside(&mut self, area: Polygon) {
for id in self.buildings.keys().cloned().collect::<Vec<_>>() {
if area.contains_pt(self.buildings[&id].center) {
self.remove_b(id);
}
}
for id in self.roads.keys().cloned().collect::<Vec<_>>() {
if area.contains_pt(self.intersections[&self.roads[&id].i1].center) {
self.remove_r(id);
}
}
for id in self.intersections.keys().cloned().collect::<Vec<_>>() {
if area.contains_pt(self.intersections[&id].center) {
self.remove_i(id);
}
}
}
}
impl Model {
@ -475,7 +494,7 @@ impl Model {
}
}
pub fn create_road(
pub fn create_r(
&mut self,
i1: StableIntersectionID,
i2: StableIntersectionID,
@ -561,7 +580,7 @@ impl Model {
}
}
pub fn remove_road(&mut self, id: StableRoadID) {
pub fn remove_r(&mut self, id: StableRoadID) {
self.road_deleted(id);
let r = self.roads.remove(&id).unwrap();