mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
Make the city picker handle 100's of maps slightly better, by splitting out into a separate list with autocomplete
This commit is contained in:
parent
304e723d77
commit
c8b565e57b
@ -1,13 +1,14 @@
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
use abstutil::prettyprint_usize;
|
||||
use geom::{Distance, Percent, Polygon, Pt2D};
|
||||
use map_model::City;
|
||||
use widgetry::{
|
||||
Btn, Color, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Line, Outcome, Panel, ScreenPt, State,
|
||||
Text, Widget,
|
||||
Autocomplete, Btn, Color, DrawBaselayer, EventCtx, GeomBatch, GfxCtx, Line, Outcome, Panel,
|
||||
ScreenPt, State, Text, TextExt, Widget,
|
||||
};
|
||||
|
||||
use crate::app::App;
|
||||
use crate::game::Transition;
|
||||
use crate::helpers::{grey_out_map, nice_map_name};
|
||||
use crate::helpers::{grey_out_map, nice_map_name, open_browser};
|
||||
use crate::load::MapLoader;
|
||||
use crate::render::DrawArea;
|
||||
|
||||
@ -62,6 +63,7 @@ impl CityPicker {
|
||||
|
||||
let mut other_cities = vec![Line("Other cities").draw(ctx)];
|
||||
let mut this_city = vec![];
|
||||
let mut more_cities = 0;
|
||||
for name in abstutil::list_all_objects(abstutil::path_all_maps()) {
|
||||
if let Some((_, color, _)) = regions.iter().find(|(n, _, _)| &name == n) {
|
||||
let btn = Btn::txt(&name, Text::from(Line(nice_map_name(&name)).fg(*color)))
|
||||
@ -71,33 +73,61 @@ impl CityPicker {
|
||||
} else {
|
||||
btn.build_def(ctx, None)
|
||||
});
|
||||
} else {
|
||||
} else if other_cities.len() < 10 {
|
||||
other_cities.push(
|
||||
Btn::txt(&name, Text::from(Line(nice_map_name(&name))))
|
||||
.tooltip(Text::new())
|
||||
.build_def(ctx, None),
|
||||
);
|
||||
} else {
|
||||
more_cities += 1;
|
||||
}
|
||||
}
|
||||
if more_cities > 0 {
|
||||
other_cities.push(
|
||||
Btn::text_bg2(format!("{} more cities", prettyprint_usize(more_cities))).build(
|
||||
ctx,
|
||||
"more cities",
|
||||
None,
|
||||
),
|
||||
);
|
||||
}
|
||||
if !this_city.is_empty() {
|
||||
this_city.insert(
|
||||
0,
|
||||
format!("More regions in {}", app.primary.map.get_city_name()).draw_text(ctx),
|
||||
);
|
||||
}
|
||||
|
||||
Box::new(CityPicker {
|
||||
regions,
|
||||
selected: None,
|
||||
on_load: Some(on_load),
|
||||
panel: Panel::new(
|
||||
Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
Line("Select a region").small_heading().draw(ctx),
|
||||
Btn::close(ctx),
|
||||
]),
|
||||
Widget::row(vec![
|
||||
Widget::col(other_cities).centered_vert(),
|
||||
Widget::draw_batch(ctx, batch).named("picker"),
|
||||
Widget::col(this_city).centered_vert(),
|
||||
]),
|
||||
])
|
||||
.outline(2.0, Color::WHITE),
|
||||
)
|
||||
panel: Panel::new(Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
Line("Select a region").small_heading().draw(ctx),
|
||||
Btn::close(ctx),
|
||||
]),
|
||||
Widget::row(vec![
|
||||
Widget::col(other_cities).centered_vert(),
|
||||
Widget::draw_batch(ctx, batch).named("picker"),
|
||||
Widget::col(this_city).centered_vert(),
|
||||
]),
|
||||
Widget::custom_row(vec![
|
||||
"Don't see the city you want?"
|
||||
.draw_text(ctx)
|
||||
.centered_vert(),
|
||||
Btn::plaintext_custom(
|
||||
"import new city",
|
||||
Text::from(
|
||||
Line("Import a new city into A/B Street")
|
||||
.fg(Color::hex("#4CA4E5"))
|
||||
.underlined(),
|
||||
),
|
||||
)
|
||||
.build_def(ctx, None),
|
||||
]),
|
||||
]))
|
||||
.build(ctx),
|
||||
})
|
||||
}
|
||||
@ -110,6 +140,17 @@ impl State<App> for CityPicker {
|
||||
"close" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
"more cities" => {
|
||||
return Transition::Replace(AllCityPicker::new(
|
||||
ctx,
|
||||
self.on_load.take().unwrap(),
|
||||
));
|
||||
}
|
||||
"import new city" => {
|
||||
open_browser(
|
||||
"https://dabreegster.github.io/abstreet/howto/new_city.html".to_string(),
|
||||
);
|
||||
}
|
||||
name => {
|
||||
return Transition::Replace(MapLoader::new(
|
||||
ctx,
|
||||
@ -186,3 +227,89 @@ impl State<App> for CityPicker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AllCityPicker {
|
||||
panel: Panel,
|
||||
// Wrapped in an Option just to make calling from event() work.
|
||||
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut App) -> Transition>>,
|
||||
}
|
||||
|
||||
impl AllCityPicker {
|
||||
fn new(
|
||||
ctx: &mut EventCtx,
|
||||
on_load: Box<dyn FnOnce(&mut EventCtx, &mut App) -> Transition>,
|
||||
) -> Box<dyn State<App>> {
|
||||
let mut autocomplete_entries = Vec::new();
|
||||
let mut buttons = Vec::new();
|
||||
|
||||
for name in abstutil::list_all_objects(abstutil::path_all_maps()) {
|
||||
buttons.push(
|
||||
Btn::text_fg(&name)
|
||||
.build_def(ctx, None)
|
||||
.margin_right(10)
|
||||
.margin_below(10),
|
||||
);
|
||||
autocomplete_entries.push((name.clone(), name));
|
||||
}
|
||||
|
||||
Box::new(AllCityPicker {
|
||||
on_load: Some(on_load),
|
||||
panel: Panel::new(Widget::col(vec![
|
||||
Widget::row(vec![
|
||||
Line("Select a region").small_heading().draw(ctx),
|
||||
Btn::close(ctx),
|
||||
]),
|
||||
Widget::row(vec![
|
||||
Widget::draw_svg(ctx, "system/assets/tools/search.svg"),
|
||||
Autocomplete::new(ctx, autocomplete_entries).named("search"),
|
||||
])
|
||||
.padding(8),
|
||||
Widget::custom_row(buttons).flex_wrap(ctx, Percent::int(70)),
|
||||
]))
|
||||
.exact_size_percent(80, 80)
|
||||
.build(ctx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl State<App> for AllCityPicker {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
match self.panel.event(ctx) {
|
||||
Outcome::Clicked(x) => match x.as_ref() {
|
||||
"close" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
name => {
|
||||
return Transition::Replace(MapLoader::new(
|
||||
ctx,
|
||||
app,
|
||||
name.to_string(),
|
||||
self.on_load.take().unwrap(),
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
if let Some(mut names) = self.panel.autocomplete_done::<String>("search") {
|
||||
if !names.is_empty() {
|
||||
return Transition::Replace(MapLoader::new(
|
||||
ctx,
|
||||
app,
|
||||
names.remove(0),
|
||||
self.on_load.take().unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw_baselayer(&self) -> DrawBaselayer {
|
||||
DrawBaselayer::PreviousState
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
grey_out_map(g, app);
|
||||
self.panel.draw(g);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user