mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
Clean up CityPicker code using DrawWithTooltips
This commit is contained in:
parent
942f2292fc
commit
3d355f720c
@ -208,6 +208,24 @@ impl<K: Clone + PartialEq, V> VecMap<K, V> {
|
|||||||
self.inner.push((key, ctor()));
|
self.inner.push((key, ctor()));
|
||||||
&mut self.inner.last_mut().unwrap().1
|
&mut self.inner.last_mut().unwrap().1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Doesn't dedupe
|
||||||
|
pub fn push(&mut self, key: K, value: V) {
|
||||||
|
self.inner.push((key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, key: &K) -> Option<&V> {
|
||||||
|
for (k, v) in &self.inner {
|
||||||
|
if k == key {
|
||||||
|
return Some(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Clone + PartialEq, V> Default for VecMap<K, V> {
|
impl<K: Clone + PartialEq, V> Default for VecMap<K, V> {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use abstio::{CityName, Manifest, MapName};
|
use abstio::{CityName, Manifest, MapName};
|
||||||
use geom::{Distance, Percent, Polygon, Pt2D};
|
use abstutil::VecMap;
|
||||||
|
use geom::{Distance, Percent};
|
||||||
use map_model::City;
|
use map_model::City;
|
||||||
use widgetry::{
|
use widgetry::{
|
||||||
Autocomplete, Color, ControlState, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Image, Key,
|
Autocomplete, ControlState, DrawBaselayer, DrawWithTooltips, EventCtx, GeomBatch, GfxCtx,
|
||||||
Line, Outcome, Panel, RewriteColor, ScreenPt, State, Text, TextExt, Transition, Widget,
|
Image, Key, Line, Outcome, Panel, RewriteColor, State, Text, TextExt, Transition, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::load::{FileLoader, MapLoader};
|
use crate::load::{FileLoader, MapLoader};
|
||||||
@ -16,9 +17,6 @@ use crate::AppLike;
|
|||||||
/// Lets the player switch maps.
|
/// Lets the player switch maps.
|
||||||
pub struct CityPicker<A: AppLike> {
|
pub struct CityPicker<A: AppLike> {
|
||||||
panel: Panel,
|
panel: Panel,
|
||||||
// In untranslated screen-space
|
|
||||||
districts: Vec<(MapName, Color, Polygon)>,
|
|
||||||
selected: Option<usize>,
|
|
||||||
// Wrapped in an Option just to make calling from event() work.
|
// Wrapped in an Option just to make calling from event() work.
|
||||||
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut A) -> Transition<A>>>,
|
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut A) -> Transition<A>>>,
|
||||||
}
|
}
|
||||||
@ -46,14 +44,13 @@ impl<A: AppLike + 'static> CityPicker<A> {
|
|||||||
)),
|
)),
|
||||||
Box::new(move |ctx, app, _, maybe_city| {
|
Box::new(move |ctx, app, _, maybe_city| {
|
||||||
// If city.bin exists, use it to draw the district map.
|
// If city.bin exists, use it to draw the district map.
|
||||||
let mut batch = GeomBatch::new();
|
let district_picker = if let Ok(city) = maybe_city {
|
||||||
let mut districts = Vec::new();
|
|
||||||
if let Ok(city) = maybe_city {
|
|
||||||
let bounds = city.boundary.get_bounds();
|
let bounds = city.boundary.get_bounds();
|
||||||
|
|
||||||
let zoom = (0.8 * ctx.canvas.window_width / bounds.width())
|
let zoom = (0.8 * ctx.canvas.window_width / bounds.width())
|
||||||
.min(0.8 * ctx.canvas.window_height / bounds.height());
|
.min(0.8 * ctx.canvas.window_height / bounds.height());
|
||||||
|
|
||||||
|
let mut batch = GeomBatch::new();
|
||||||
batch.push(app.cs().map_background.clone(), city.boundary);
|
batch.push(app.cs().map_background.clone(), city.boundary);
|
||||||
for (area_type, polygon) in city.areas {
|
for (area_type, polygon) in city.areas {
|
||||||
batch.push(DrawArea::fill(area_type, app.cs()), polygon);
|
batch.push(DrawArea::fill(area_type, app.cs()), polygon);
|
||||||
@ -62,15 +59,33 @@ impl<A: AppLike + 'static> CityPicker<A> {
|
|||||||
// If somebody has just generated a new map somewhere with an existing
|
// If somebody has just generated a new map somewhere with an existing
|
||||||
// city.bin, but hasn't updated city.bin yet, that new map will be invisible on
|
// city.bin, but hasn't updated city.bin yet, that new map will be invisible on
|
||||||
// the city-wide diagram.
|
// the city-wide diagram.
|
||||||
|
let mut tooltips = Vec::new();
|
||||||
|
let mut colors = VecMap::new();
|
||||||
for (name, polygon) in city.districts {
|
for (name, polygon) in city.districts {
|
||||||
if &name != app.map().get_name() {
|
if &name != app.map().get_name() {
|
||||||
let color = app.cs().rotating_color_agents(districts.len());
|
let color = app.cs().rotating_color_agents(colors.len());
|
||||||
batch.push(color, polygon.to_outline(Distance::meters(200.0)).unwrap());
|
batch.push(color, polygon.to_outline(Distance::meters(200.0)).unwrap());
|
||||||
districts.push((name, color, polygon.scale(zoom)));
|
let polygon = polygon.scale(zoom);
|
||||||
|
tooltips.push((
|
||||||
|
polygon.clone(),
|
||||||
|
Text::from(nice_map_name(&name)),
|
||||||
|
Some(name.path()),
|
||||||
|
));
|
||||||
|
colors.push(polygon, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch = batch.scale(zoom);
|
DrawWithTooltips::new_widget(
|
||||||
}
|
ctx,
|
||||||
|
batch.scale(zoom),
|
||||||
|
tooltips,
|
||||||
|
Box::new(move |poly| {
|
||||||
|
let color = colors.get(poly).unwrap();
|
||||||
|
GeomBatch::from(vec![(color.alpha(0.5), poly.clone())])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Widget::nothing()
|
||||||
|
};
|
||||||
|
|
||||||
// Use the filesystem to list the buttons on the side.
|
// Use the filesystem to list the buttons on the side.
|
||||||
// (There's no point in listing these from city.bin if it exists -- if somebody
|
// (There's no point in listing these from city.bin if it exists -- if somebody
|
||||||
@ -129,8 +144,6 @@ impl<A: AppLike + 'static> CityPicker<A> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Transition::Replace(Box::new(CityPicker {
|
Transition::Replace(Box::new(CityPicker {
|
||||||
districts,
|
|
||||||
selected: None,
|
|
||||||
on_load: Some(on_load),
|
on_load: Some(on_load),
|
||||||
panel: Panel::new_builder(Widget::col(vec![
|
panel: Panel::new_builder(Widget::col(vec![
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
@ -139,7 +152,7 @@ impl<A: AppLike + 'static> CityPicker<A> {
|
|||||||
]),
|
]),
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
Widget::col(other_places).centered_vert(),
|
Widget::col(other_places).centered_vert(),
|
||||||
batch.into_widget(ctx).named("picker"),
|
district_picker,
|
||||||
Widget::col(this_city).centered_vert(),
|
Widget::col(this_city).centered_vert(),
|
||||||
]),
|
]),
|
||||||
"Don't see the place you want?".text_widget(ctx),
|
"Don't see the place you want?".text_widget(ctx),
|
||||||
@ -209,34 +222,6 @@ impl<A: AppLike + 'static> State<A> for CityPicker<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.redo_mouseover() {
|
|
||||||
self.selected = None;
|
|
||||||
if let Some(cursor) = ctx.canvas.get_cursor_in_screen_space() {
|
|
||||||
let rect = self.panel.rect_of("picker");
|
|
||||||
if rect.contains(cursor) {
|
|
||||||
let pt = Pt2D::new(cursor.x - rect.x1, cursor.y - rect.y1);
|
|
||||||
for (idx, (_, _, poly)) in self.districts.iter().enumerate() {
|
|
||||||
if poly.contains_pt(pt) {
|
|
||||||
self.selected = Some(idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let Some(btn) = self.panel.currently_hovering() {
|
|
||||||
for (idx, (name, _, _)) in self.districts.iter().enumerate() {
|
|
||||||
if &name.path() == btn {
|
|
||||||
self.selected = Some(idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(idx) = self.selected {
|
|
||||||
if ctx.normal_left_click() {
|
|
||||||
return chose_city(ctx, app, self.districts[idx].0.clone(), &mut self.on_load);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Transition::Keep
|
Transition::Keep
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,21 +232,6 @@ impl<A: AppLike + 'static> State<A> for CityPicker<A> {
|
|||||||
fn draw(&self, g: &mut GfxCtx, app: &A) {
|
fn draw(&self, g: &mut GfxCtx, app: &A) {
|
||||||
grey_out_map(g, app);
|
grey_out_map(g, app);
|
||||||
self.panel.draw(g);
|
self.panel.draw(g);
|
||||||
|
|
||||||
if let Some(idx) = self.selected {
|
|
||||||
let (name, color, poly) = &self.districts[idx];
|
|
||||||
let rect = self.panel.rect_of("picker");
|
|
||||||
g.fork(
|
|
||||||
Pt2D::new(0.0, 0.0),
|
|
||||||
ScreenPt::new(rect.x1, rect.y1),
|
|
||||||
1.0,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
g.draw_polygon(color.alpha(0.5), poly.clone());
|
|
||||||
g.unfork();
|
|
||||||
|
|
||||||
g.draw_mouse_tooltip(Text::from(nice_map_name(name)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user