diff --git a/map_gui/src/tools/city_picker.rs b/map_gui/src/tools/city_picker.rs index 4e2c1699c3..3fbdb97cdf 100644 --- a/map_gui/src/tools/city_picker.rs +++ b/map_gui/src/tools/city_picker.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use abstio::{CityName, MapName}; use geom::{Distance, Percent, Polygon, Pt2D}; use map_model::City; @@ -87,22 +89,15 @@ impl CityPicker { ); } - let mut other_cities = vec![Line("Other cities").draw(ctx)]; - for city in CityName::list_all_cities_from_system_data() { - if city == city_name { - continue; - } - // If there's only one map in the city, make the button directly load it. - let city_path = city.to_path(); - let button = ctx.style().btn_outline_light_text(&city_path); - let maps = MapName::list_all_maps_in_city(&city); - if maps.len() == 1 { - other_cities.push(button.build_widget(ctx, &maps[0].path())); - } else { - other_cities.push(button.no_tooltip().build_def(ctx)); - } + let mut other_places = vec![Line("Other places").draw(ctx)]; + for (country, cities) in cities_per_country() { + other_places.push( + ctx.style() + .btn_outline_light_text(&format!("{} in {}", cities.len(), country)) + .build_widget(ctx, &country), + ); } - other_cities.push( + other_places.push( ctx.style() .btn_solid_dark_text("Search all maps") .hotkey(Key::Tab) @@ -119,7 +114,7 @@ impl CityPicker { ctx.style().btn_close_widget(ctx), ]), Widget::row(vec![ - Widget::col(other_cities).centered_vert(), + Widget::col(other_places).centered_vert(), Widget::draw_batch(ctx, batch).named("picker"), Widget::col(this_city).centered_vert(), ]), @@ -189,11 +184,12 @@ impl State for CityPicker { self.on_load.take().unwrap(), )); } - // Browse maps for another city without loading any map there - return Transition::Replace(CityPicker::new_in_city( + // Browse cities for another country + return Transition::Replace(CitiesInCountryPicker::new( ctx, + app, self.on_load.take().unwrap(), - CityName::parse(x).unwrap(), + x, )); } }, @@ -348,3 +344,104 @@ impl State for AllCityPicker { self.panel.draw(g); } } + +struct CitiesInCountryPicker { + panel: Panel, + // Wrapped in an Option just to make calling from event() work. + on_load: Option Transition>>, +} + +impl CitiesInCountryPicker { + fn new( + ctx: &mut EventCtx, + app: &A, + on_load: Box Transition>, + country: &str, + ) -> Box> { + let mut buttons = Vec::new(); + for city in cities_per_country().remove(country).unwrap() { + if &city == app.map().get_city_name() { + continue; + } + buttons.push( + ctx.style() + .btn_outline_light_text(&city.city) + .build_widget(ctx, &city.to_path()) + .margin_right(10) + .margin_below(10), + ); + } + + Box::new(CitiesInCountryPicker { + on_load: Some(on_load), + panel: Panel::new(Widget::col(vec![ + Widget::row(vec![ + Line(format!("Select a city in {}", country)) + .small_heading() + .draw(ctx), + ctx.style().btn_close_widget(ctx), + ]), + Widget::custom_row(buttons).flex_wrap(ctx, Percent::int(70)), + ])) + .exact_size_percent(80, 80) + .build(ctx), + }) + } +} + +impl State for CitiesInCountryPicker { + fn event(&mut self, ctx: &mut EventCtx, app: &mut A) -> Transition { + match self.panel.event(ctx) { + Outcome::Clicked(x) => match x.as_ref() { + "close" => { + // Go back to the screen that lets you choose all countries. + return Transition::Replace(CityPicker::new( + ctx, + app, + self.on_load.take().unwrap(), + )); + } + path => { + let city = CityName::parse(path).unwrap(); + let mut maps = MapName::list_all_maps_in_city(&city); + if maps.len() == 1 { + return Transition::Replace(MapLoader::new( + ctx, + app, + maps.pop().unwrap(), + self.on_load.take().unwrap(), + )); + } + return Transition::Replace(CityPicker::new_in_city( + ctx, + self.on_load.take().unwrap(), + city, + )); + } + }, + _ => {} + } + + Transition::Keep + } + + fn draw_baselayer(&self) -> DrawBaselayer { + DrawBaselayer::PreviousState + } + + fn draw(&self, g: &mut GfxCtx, app: &A) { + grey_out_map(g, app); + self.panel.draw(g); + } +} + +fn cities_per_country() -> BTreeMap> { + let mut per_country = BTreeMap::new(); + for city in CityName::list_all_cities_from_system_data() { + per_country + .entry(city.country.clone()) + .or_insert_with(Vec::new) + .push(city); + } + per_country +}