mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
robustify city picker
This commit is contained in:
parent
239bf74121
commit
8b7d93c64e
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
svg, Color, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, MultiKey, Outcome,
|
||||
RewriteColor, ScreenDims, ScreenPt, Text, Widget, WidgetImpl, WidgetOutput,
|
||||
RewriteColor, ScreenDims, ScreenPt, Text, TextSpan, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
use geom::Polygon;
|
||||
|
||||
@ -142,6 +142,11 @@ impl Btn {
|
||||
BtnBuilder::TextFG(label.clone(), Text::from(Line(label)), None)
|
||||
}
|
||||
|
||||
pub fn text_fg_line<I: Into<String>>(label: I, line: TextSpan) -> BtnBuilder {
|
||||
let label = label.into();
|
||||
BtnBuilder::TextFG(label.clone(), Text::from(line), None)
|
||||
}
|
||||
|
||||
pub fn text_bg<I: Into<String>>(
|
||||
label: I,
|
||||
text: Text,
|
||||
|
@ -1,15 +1,14 @@
|
||||
use crate::app::App;
|
||||
use crate::game::{DrawBaselayer, State, Transition};
|
||||
use crate::helpers::nice_map_name;
|
||||
use crate::render::DrawArea;
|
||||
use ezgui::{
|
||||
hotkey, Btn, Color, Composite, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, ScreenPt, Text,
|
||||
Widget,
|
||||
};
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
use map_model::{AreaType, City};
|
||||
use map_model::City;
|
||||
|
||||
// TODO Also include text buttons
|
||||
// TODO Handle other cities
|
||||
pub struct CityPicker {
|
||||
composite: Composite,
|
||||
// In untranslated screen-space
|
||||
@ -21,40 +20,64 @@ pub struct CityPicker {
|
||||
impl CityPicker {
|
||||
pub fn new(
|
||||
ctx: &mut EventCtx,
|
||||
app: &App,
|
||||
app: &mut App,
|
||||
on_load: Box<dyn Fn(&mut EventCtx, &mut App) -> Transition>,
|
||||
) -> Box<dyn State> {
|
||||
// TODO Handle if the city doesn't exist
|
||||
let city: City = abstutil::read_binary(
|
||||
app.primary.current_selection = None;
|
||||
|
||||
let mut batch = GeomBatch::new();
|
||||
let mut regions = Vec::new();
|
||||
|
||||
if let Ok(city) = abstutil::maybe_read_binary::<City>(
|
||||
format!(
|
||||
"../data/system/cities/{}.bin",
|
||||
app.primary.map.get_city_name()
|
||||
),
|
||||
&mut abstutil::Timer::throwaway(),
|
||||
);
|
||||
) {
|
||||
let bounds = city.boundary.get_bounds();
|
||||
let zoom = (0.8 * ctx.canvas.window_width / bounds.width())
|
||||
.min(0.8 * ctx.canvas.window_height / bounds.height());
|
||||
|
||||
let bounds = city.boundary.get_bounds();
|
||||
let zoom = (0.8 * ctx.canvas.window_width / bounds.width())
|
||||
.min(0.8 * ctx.canvas.window_height / bounds.height());
|
||||
batch.push(app.cs.map_background, city.boundary);
|
||||
for (area_type, polygon) in city.areas {
|
||||
batch.push(DrawArea::color(area_type, &app.cs), polygon);
|
||||
}
|
||||
|
||||
let mut batch = GeomBatch::new();
|
||||
batch.push(app.cs.map_background, city.boundary);
|
||||
for (area_type, polygon) in city.areas {
|
||||
// TODO Refactor
|
||||
let color = match area_type {
|
||||
AreaType::Park => app.cs.grass,
|
||||
AreaType::Water => app.cs.water,
|
||||
AreaType::PedestrianIsland => Color::grey(0.3),
|
||||
AreaType::Island => app.cs.map_background,
|
||||
};
|
||||
batch.push(color, polygon);
|
||||
for (name, polygon) in city.regions {
|
||||
let color = app.cs.rotating_color_agents(regions.len());
|
||||
if &name == app.primary.map.get_name() {
|
||||
batch.push(color.alpha(0.5), polygon.clone());
|
||||
} else {
|
||||
batch.push(color, polygon.to_outline(Distance::meters(200.0)));
|
||||
}
|
||||
regions.push((name, color, polygon.scale(zoom)));
|
||||
}
|
||||
batch = batch.scale(zoom);
|
||||
}
|
||||
|
||||
let mut regions = Vec::new();
|
||||
for (name, polygon) in city.regions {
|
||||
let color = app.cs.rotating_color_agents(regions.len());
|
||||
batch.push(color, polygon.to_outline(Distance::meters(200.0)));
|
||||
regions.push((name, color, polygon.scale(zoom)));
|
||||
let mut other_cities = vec![Line("Other cities").draw(ctx).margin_below(10)];
|
||||
let mut this_city = vec![];
|
||||
for name in abstutil::list_all_objects(abstutil::path_all_maps()) {
|
||||
if let Some((_, color, _)) = regions.iter().find(|(n, _, _)| &name == n) {
|
||||
let btn = Btn::text_fg_line(&name, Line(nice_map_name(&name)).fg(*color))
|
||||
.tooltip(Text::new());
|
||||
this_city.push(
|
||||
if &name == app.primary.map.get_name() {
|
||||
btn.inactive(ctx)
|
||||
} else {
|
||||
btn.build_def(ctx, None)
|
||||
}
|
||||
.margin_below(5),
|
||||
);
|
||||
} else {
|
||||
other_cities.push(
|
||||
Btn::text_fg(nice_map_name(&name))
|
||||
.tooltip(Text::new())
|
||||
.build(ctx, name, None)
|
||||
.margin_below(5),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(CityPicker {
|
||||
@ -64,12 +87,16 @@ impl CityPicker {
|
||||
composite: Composite::new(
|
||||
Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
Line("Click a region").small_heading().draw(ctx),
|
||||
Line("Select a region").small_heading().draw(ctx),
|
||||
Btn::plaintext("X")
|
||||
.build(ctx, "close", hotkey(Key::Escape))
|
||||
.align_right(),
|
||||
]),
|
||||
Widget::draw_batch(ctx, batch.scale(zoom)).named("picker"),
|
||||
Widget::row(vec![
|
||||
Widget::col(other_cities).centered_vert(),
|
||||
Widget::draw_batch(ctx, batch).named("picker"),
|
||||
Widget::col(this_city).centered_vert(),
|
||||
]),
|
||||
])
|
||||
.bg(app.cs.panel_bg)
|
||||
.outline(2.0, Color::WHITE)
|
||||
@ -87,7 +114,12 @@ impl State for CityPicker {
|
||||
"close" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
name => {
|
||||
return ctx.loading_screen("switch map", |ctx, _| {
|
||||
app.switch_map(ctx, abstutil::path_map(name));
|
||||
(self.on_load)(ctx, app)
|
||||
});
|
||||
}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
@ -98,8 +130,15 @@ impl State for CityPicker {
|
||||
let rect = self.composite.rect_of("picker");
|
||||
if rect.contains(cursor) {
|
||||
let pt = Pt2D::new(cursor.x - rect.x1, cursor.y - rect.y1);
|
||||
for (idx, (_, _, poly)) in self.regions.iter().enumerate() {
|
||||
if poly.contains_pt(pt) {
|
||||
for (idx, (name, _, poly)) in self.regions.iter().enumerate() {
|
||||
if name != app.primary.map.get_name() && poly.contains_pt(pt) {
|
||||
self.selected = Some(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if let Some(btn) = self.composite.currently_hovering() {
|
||||
for (idx, (name, _, _)) in self.regions.iter().enumerate() {
|
||||
if name != app.primary.map.get_name() && name == btn {
|
||||
self.selected = Some(idx);
|
||||
break;
|
||||
}
|
||||
|
@ -12,14 +12,17 @@ pub struct DrawArea {
|
||||
|
||||
impl DrawArea {
|
||||
pub fn new(area: &Area, cs: &ColorScheme, all_areas: &mut GeomBatch) -> DrawArea {
|
||||
let color = match area.area_type {
|
||||
all_areas.push(DrawArea::color(area.area_type, cs), area.polygon.clone());
|
||||
DrawArea { id: area.id }
|
||||
}
|
||||
|
||||
pub fn color(area_type: AreaType, cs: &ColorScheme) -> Color {
|
||||
match area_type {
|
||||
AreaType::Park => cs.grass,
|
||||
AreaType::Water => cs.water,
|
||||
AreaType::PedestrianIsland => Color::grey(0.3),
|
||||
AreaType::Island => cs.map_background,
|
||||
};
|
||||
all_areas.push(color, area.polygon.clone());
|
||||
DrawArea { id: area.id }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
use crate::app::{App, Flags};
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::helpers::ID;
|
||||
use crate::render::area::DrawArea;
|
||||
use crate::render::building::DrawBuilding;
|
||||
use crate::render::bus_stop::DrawBusStop;
|
||||
use crate::render::intersection::DrawIntersection;
|
||||
use crate::render::lane::DrawLane;
|
||||
use crate::render::road::DrawRoad;
|
||||
use crate::render::{draw_vehicle, DrawPedCrowd, DrawPedestrian, Renderable};
|
||||
use crate::render::{draw_vehicle, DrawArea, DrawPedCrowd, DrawPedestrian, Renderable};
|
||||
use aabb_quadtree::QuadTree;
|
||||
use abstutil::Timer;
|
||||
use ezgui::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Prerender};
|
||||
|
@ -14,6 +14,7 @@ mod turn;
|
||||
use crate::app::App;
|
||||
use crate::colors::ColorScheme;
|
||||
use crate::helpers::ID;
|
||||
pub use crate::render::area::DrawArea;
|
||||
use crate::render::bike::DrawBike;
|
||||
use crate::render::car::DrawCar;
|
||||
pub use crate::render::intersection::{calculate_corners, DrawIntersection};
|
||||
|
Loading…
Reference in New Issue
Block a user