mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
more synthetic fixes: redo mouseover when model changes, avoid panic
with 0-len new road line, fix reused IDs, fix contains_pt for some precomputed polygons
This commit is contained in:
parent
92a4f304f7
commit
353d89cd25
@ -51,9 +51,6 @@ impl<ID: ObjectID> World<ID> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_mouseover(&mut self, ctx: &EventCtx) {
|
pub fn handle_mouseover(&mut self, ctx: &EventCtx) {
|
||||||
if !ctx.redo_mouseover() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.current_selection = None;
|
self.current_selection = None;
|
||||||
|
|
||||||
let cursor = if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
|
let cursor = if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
|
||||||
@ -111,6 +108,6 @@ impl<ID: ObjectID> World<ID> {
|
|||||||
|
|
||||||
pub fn delete_obj(&mut self, id: ID) {
|
pub fn delete_obj(&mut self, id: ID) {
|
||||||
let obj = self.objects.remove(&id).unwrap();
|
let obj = self.objects.remove(&id).unwrap();
|
||||||
self.quadtree.remove(obj.quadtree_id);
|
self.quadtree.remove(obj.quadtree_id).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,9 @@ impl GUI for UI {
|
|||||||
ref mut osd,
|
ref mut osd,
|
||||||
} => {
|
} => {
|
||||||
{
|
{
|
||||||
self.world.handle_mouseover(ctx);
|
if ctx.redo_mouseover() {
|
||||||
|
self.world.handle_mouseover(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
let len = self.hints.hints.len();
|
let len = self.hints.hints.len();
|
||||||
let mut txt = Text::prompt("Fix Map Geometry");
|
let mut txt = Text::prompt("Fix Map Geometry");
|
||||||
@ -284,7 +286,9 @@ impl GUI for UI {
|
|||||||
}
|
}
|
||||||
State::BanTurnsBetween { from, ref mut osd } => {
|
State::BanTurnsBetween { from, ref mut osd } => {
|
||||||
ctx.canvas.handle_event(ctx.input);
|
ctx.canvas.handle_event(ctx.input);
|
||||||
self.world.handle_mouseover(ctx);
|
if ctx.redo_mouseover() {
|
||||||
|
self.world.handle_mouseover(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.input.key_pressed(Key::Escape, "cancel") {
|
if ctx.input.key_pressed(Key::Escape, "cancel") {
|
||||||
self.state = State::main(ctx);
|
self.state = State::main(ctx);
|
||||||
|
@ -148,7 +148,7 @@ impl Polygon {
|
|||||||
top_left.offset(width, height),
|
top_left.offset(width, height),
|
||||||
top_left.offset(Distance::ZERO, height),
|
top_left.offset(Distance::ZERO, height),
|
||||||
],
|
],
|
||||||
indices: vec![0, 1, 2, 2, 3, 0],
|
indices: vec![0, 1, 2, 0, 2, 3],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ pub struct Model {
|
|||||||
intersections: BTreeMap<StableIntersectionID, Intersection>,
|
intersections: BTreeMap<StableIntersectionID, Intersection>,
|
||||||
roads: BTreeMap<StableRoadID, Road>,
|
roads: BTreeMap<StableRoadID, Road>,
|
||||||
buildings: BTreeMap<BuildingID, Building>,
|
buildings: BTreeMap<BuildingID, Building>,
|
||||||
|
// Never reuse IDs, and don't worry about being sequential
|
||||||
|
id_counter: usize,
|
||||||
|
|
||||||
world: World<ID>,
|
world: World<ID>,
|
||||||
}
|
}
|
||||||
@ -137,6 +139,7 @@ impl Model {
|
|||||||
intersections: BTreeMap::new(),
|
intersections: BTreeMap::new(),
|
||||||
roads: BTreeMap::new(),
|
roads: BTreeMap::new(),
|
||||||
buildings: BTreeMap::new(),
|
buildings: BTreeMap::new(),
|
||||||
|
id_counter: 0,
|
||||||
world: World::new(&Bounds::new()),
|
world: World::new(&Bounds::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,6 +266,7 @@ impl Model {
|
|||||||
roads: HashSet::new(),
|
roads: HashSet::new(),
|
||||||
};
|
};
|
||||||
m.intersections.insert(*id, i);
|
m.intersections.insert(*id, i);
|
||||||
|
m.id_counter = m.id_counter.max(id.0 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (id, r) in &data.roads {
|
for (id, r) in &data.roads {
|
||||||
@ -279,6 +283,7 @@ impl Model {
|
|||||||
);
|
);
|
||||||
m.intersections.get_mut(&i1).unwrap().roads.insert(*id);
|
m.intersections.get_mut(&i1).unwrap().roads.insert(*id);
|
||||||
m.intersections.get_mut(&i2).unwrap().roads.insert(*id);
|
m.intersections.get_mut(&i2).unwrap().roads.insert(*id);
|
||||||
|
m.id_counter = m.id_counter.max(id.0 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !exclude_bldgs {
|
if !exclude_bldgs {
|
||||||
@ -288,6 +293,7 @@ impl Model {
|
|||||||
center: b.polygon.center(),
|
center: b.polygon.center(),
|
||||||
};
|
};
|
||||||
m.buildings.insert(idx, b);
|
m.buildings.insert(idx, b);
|
||||||
|
m.id_counter = m.id_counter.max(idx + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +334,8 @@ impl Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_i(&mut self, center: Pt2D, prerender: &Prerender) {
|
pub fn create_i(&mut self, center: Pt2D, prerender: &Prerender) {
|
||||||
let id = StableIntersectionID(self.intersections.len());
|
let id = StableIntersectionID(self.id_counter);
|
||||||
|
self.id_counter += 1;
|
||||||
self.intersections.insert(
|
self.intersections.insert(
|
||||||
id,
|
id,
|
||||||
Intersection {
|
Intersection {
|
||||||
@ -431,7 +438,8 @@ impl Model {
|
|||||||
println!("Road already exists");
|
println!("Road already exists");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let id = StableRoadID(self.roads.len());
|
let id = StableRoadID(self.id_counter);
|
||||||
|
self.id_counter += 1;
|
||||||
self.roads.insert(
|
self.roads.insert(
|
||||||
id,
|
id,
|
||||||
Road {
|
Road {
|
||||||
@ -514,7 +522,8 @@ impl Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_b(&mut self, center: Pt2D, prerender: &Prerender) {
|
pub fn create_b(&mut self, center: Pt2D, prerender: &Prerender) {
|
||||||
let id = self.buildings.len();
|
let id = self.id_counter;
|
||||||
|
self.id_counter += 1;
|
||||||
self.buildings.insert(
|
self.buildings.insert(
|
||||||
id,
|
id,
|
||||||
Building {
|
Building {
|
||||||
|
@ -40,7 +40,9 @@ impl UI {
|
|||||||
impl GUI for UI {
|
impl GUI for UI {
|
||||||
fn event(&mut self, ctx: &mut EventCtx) -> EventLoopMode {
|
fn event(&mut self, ctx: &mut EventCtx) -> EventLoopMode {
|
||||||
ctx.canvas.handle_event(ctx.input);
|
ctx.canvas.handle_event(ctx.input);
|
||||||
self.model.handle_mouseover(ctx);
|
if ctx.redo_mouseover() {
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
let cursor = {
|
let cursor = {
|
||||||
if let Some(c) = ctx.canvas.get_cursor_in_map_space() {
|
if let Some(c) = ctx.canvas.get_cursor_in_map_space() {
|
||||||
@ -99,10 +101,12 @@ impl GUI for UI {
|
|||||||
State::CreatingRoad(i1) => {
|
State::CreatingRoad(i1) => {
|
||||||
if ctx.input.key_pressed(Key::Escape, "stop defining road") {
|
if ctx.input.key_pressed(Key::Escape, "stop defining road") {
|
||||||
self.state = State::Viewing;
|
self.state = State::Viewing;
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
} else if let Some(ID::Intersection(i2)) = self.model.get_selection() {
|
} else if let Some(ID::Intersection(i2)) = self.model.get_selection() {
|
||||||
if i1 != i2 && ctx.input.key_pressed(Key::R, "finalize road") {
|
if i1 != i2 && ctx.input.key_pressed(Key::R, "finalize road") {
|
||||||
self.model.create_road(i1, i2, ctx.prerender);
|
self.model.create_road(i1, i2, ctx.prerender);
|
||||||
self.state = State::Viewing;
|
self.state = State::Viewing;
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,8 +117,10 @@ impl GUI for UI {
|
|||||||
{
|
{
|
||||||
self.model.edit_lanes(id, s, ctx.prerender);
|
self.model.edit_lanes(id, s, ctx.prerender);
|
||||||
self.state = State::Viewing;
|
self.state = State::Viewing;
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
} else if wizard.aborted() {
|
} else if wizard.aborted() {
|
||||||
self.state = State::Viewing;
|
self.state = State::Viewing;
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::SavingModel(ref mut wizard) => {
|
State::SavingModel(ref mut wizard) => {
|
||||||
@ -134,6 +140,7 @@ impl GUI for UI {
|
|||||||
self.state = State::CreatingRoad(i);
|
self.state = State::CreatingRoad(i);
|
||||||
} else if ctx.input.key_pressed(Key::Backspace, "delete intersection") {
|
} else if ctx.input.key_pressed(Key::Backspace, "delete intersection") {
|
||||||
self.model.remove_i(i);
|
self.model.remove_i(i);
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
} else if ctx.input.key_pressed(Key::T, "toggle intersection type") {
|
} else if ctx.input.key_pressed(Key::T, "toggle intersection type") {
|
||||||
self.model.toggle_i_type(i, ctx.prerender);
|
self.model.toggle_i_type(i, ctx.prerender);
|
||||||
} else if ctx.input.key_pressed(Key::L, "label intersection") {
|
} else if ctx.input.key_pressed(Key::L, "label intersection") {
|
||||||
@ -144,6 +151,7 @@ impl GUI for UI {
|
|||||||
self.state = State::MovingBuilding(b);
|
self.state = State::MovingBuilding(b);
|
||||||
} else if ctx.input.key_pressed(Key::Backspace, "delete building") {
|
} else if ctx.input.key_pressed(Key::Backspace, "delete building") {
|
||||||
self.model.remove_b(b);
|
self.model.remove_b(b);
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
} else if ctx.input.key_pressed(Key::L, "label building") {
|
} else if ctx.input.key_pressed(Key::L, "label building") {
|
||||||
self.state = State::LabelingBuilding(b, Wizard::new());
|
self.state = State::LabelingBuilding(b, Wizard::new());
|
||||||
}
|
}
|
||||||
@ -153,6 +161,7 @@ impl GUI for UI {
|
|||||||
.key_pressed(Key::Backspace, &format!("delete road {}", r))
|
.key_pressed(Key::Backspace, &format!("delete road {}", r))
|
||||||
{
|
{
|
||||||
self.model.remove_road(r);
|
self.model.remove_road(r);
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
} else if ctx.input.key_pressed(Key::E, "edit lanes") {
|
} else if ctx.input.key_pressed(Key::E, "edit lanes") {
|
||||||
self.state = State::EditingRoad(r, Wizard::new());
|
self.state = State::EditingRoad(r, Wizard::new());
|
||||||
} else if ctx.input.key_pressed(Key::S, "swap lanes") {
|
} else if ctx.input.key_pressed(Key::S, "swap lanes") {
|
||||||
@ -170,8 +179,12 @@ impl GUI for UI {
|
|||||||
}
|
}
|
||||||
} else if ctx.input.key_pressed(Key::I, "create intersection") {
|
} else if ctx.input.key_pressed(Key::I, "create intersection") {
|
||||||
self.model.create_i(cursor, ctx.prerender);
|
self.model.create_i(cursor, ctx.prerender);
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
|
// TODO Silly bug: Mouseover doesn't actually work! I think the cursor being
|
||||||
|
// dead-center messes up the precomputed triangles.
|
||||||
} else if ctx.input.key_pressed(Key::B, "create building") {
|
} else if ctx.input.key_pressed(Key::B, "create building") {
|
||||||
self.model.create_b(cursor, ctx.prerender);
|
self.model.create_b(cursor, ctx.prerender);
|
||||||
|
self.model.handle_mouseover(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,11 +200,9 @@ impl GUI for UI {
|
|||||||
match self.state {
|
match self.state {
|
||||||
State::CreatingRoad(i1) => {
|
State::CreatingRoad(i1) => {
|
||||||
if let Some(cursor) = g.get_cursor_in_map_space() {
|
if let Some(cursor) = g.get_cursor_in_map_space() {
|
||||||
g.draw_line(
|
if let Some(l) = Line::maybe_new(self.model.get_i_center(i1), cursor) {
|
||||||
Color::GREEN,
|
g.draw_line(Color::GREEN, Distance::meters(5.0), &l);
|
||||||
Distance::meters(5.0),
|
}
|
||||||
&Line::new(self.model.get_i_center(i1), cursor),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::LabelingBuilding(_, ref wizard)
|
State::LabelingBuilding(_, ref wizard)
|
||||||
|
Loading…
Reference in New Issue
Block a user