diff --git a/experiment/src/after_level.rs b/experiment/src/after_level.rs index 46ba0311e8..9c1e933ea5 100644 --- a/experiment/src/after_level.rs +++ b/experiment/src/after_level.rs @@ -1,12 +1,11 @@ use abstutil::prettyprint_usize; -use map_gui::SimpleApp; use widgetry::{ - Btn, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text, Transition, + Btn, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text, VerticalAlignment, Widget, }; use crate::levels::Level; -use crate::session::Session; +use crate::{App, Transition}; const ZOOM: f64 = 2.0; @@ -20,16 +19,14 @@ pub struct Results { impl Results { pub fn new( ctx: &mut EventCtx, - app: &SimpleApp, + app: &mut App, score: usize, level: &Level, - ) -> Box> { + ) -> Box> { ctx.canvas.cam_zoom = ZOOM; ctx.canvas.center_on_map_pt(app.map.get_bounds().center()); - // TODO Store in app - let mut session = Session::new(); - session.record_score(level.title, score); + app.session.record_score(level.title, score); let mut txt = Text::new(); txt.add(Line(format!("Results for {}", level.title)).small_heading()); @@ -41,7 +38,7 @@ impl Results { ))); txt.add(Line("")); txt.add(Line("High scores:")); - for (idx, score) in session.high_scores[level.title].iter().enumerate() { + for (idx, score) in app.session.high_scores[level.title].iter().enumerate() { txt.add(Line(format!("{}) {}", idx + 1, prettyprint_usize(*score)))); } @@ -55,8 +52,8 @@ impl Results { } } -impl State for Results { - fn event(&mut self, ctx: &mut EventCtx, _: &mut SimpleApp) -> Transition { +impl State for Results { + fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Transition { ctx.canvas_movement(); match self.panel.event(ctx) { @@ -72,7 +69,7 @@ impl State for Results { Transition::Keep } - fn draw(&self, g: &mut GfxCtx, _: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, _: &App) { self.panel.draw(g); } } diff --git a/experiment/src/before_level.rs b/experiment/src/before_level.rs index 21203bb2ac..1a60cb9afd 100644 --- a/experiment/src/before_level.rs +++ b/experiment/src/before_level.rs @@ -2,17 +2,18 @@ use std::collections::HashSet; use abstutil::prettyprint_usize; use map_gui::load::MapLoader; -use map_gui::{SimpleApp, ID}; +use map_gui::ID; use map_model::BuildingID; use widgetry::{ Btn, Choice, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, - Text, TextExt, Transition, VerticalAlignment, Widget, + Text, TextExt, VerticalAlignment, Widget, }; use crate::buildings::{BldgState, Buildings}; use crate::game::Game; use crate::levels::Level; use crate::vehicles::Vehicle; +use crate::{App, Transition}; const ZOOM: f64 = 2.0; @@ -24,7 +25,7 @@ pub struct Picker { } impl Picker { - pub fn new(ctx: &mut EventCtx, app: &SimpleApp, level: Level) -> Box> { + pub fn new(ctx: &mut EventCtx, app: &App, level: Level) -> Box> { MapLoader::new( ctx, app, @@ -89,8 +90,8 @@ impl Picker { } } -impl State for Picker { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for Picker { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { ctx.canvas_movement(); if ctx.redo_mouseover() { @@ -132,7 +133,7 @@ impl State for Picker { Transition::Keep } - fn draw(&self, g: &mut GfxCtx, app: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, app: &App) { self.panel.draw(g); g.redraw(&self.bldgs.draw_all); for b in &self.current_picks { diff --git a/experiment/src/buildings.rs b/experiment/src/buildings.rs index 614785542b..c31e52b675 100644 --- a/experiment/src/buildings.rs +++ b/experiment/src/buildings.rs @@ -1,9 +1,10 @@ use std::collections::{HashMap, HashSet}; -use map_gui::SimpleApp; use map_model::{BuildingID, BuildingType}; use widgetry::{Color, Drawable, EventCtx, GeomBatch, Line, Text}; +use crate::App; + pub struct Buildings { // Every building in the map is here, to simplify lookup logic. pub buildings: HashMap, @@ -23,7 +24,7 @@ pub enum BldgState { } impl Buildings { - pub fn new(ctx: &mut EventCtx, app: &SimpleApp, upzones: HashSet) -> Buildings { + pub fn new(ctx: &mut EventCtx, app: &App, upzones: HashSet) -> Buildings { let house_color = app.cs.residential_building; let apartment_color = Color::CYAN; let store_color = Color::YELLOW; diff --git a/experiment/src/game.rs b/experiment/src/game.rs index 1a442b3cdc..acf3ef9ef3 100644 --- a/experiment/src/game.rs +++ b/experiment/src/game.rs @@ -3,11 +3,10 @@ use std::collections::HashSet; use abstutil::prettyprint_usize; use geom::{ArrowCap, Circle, Distance, Duration, PolyLine, Pt2D, Time}; use map_gui::tools::{ChooseSomething, ColorLegend, SimpleMinimap}; -use map_gui::SimpleApp; use map_model::BuildingID; use widgetry::{ Btn, Choice, Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line, - Outcome, Panel, State, Text, TextExt, Transition, UpdateType, VerticalAlignment, Widget, + Outcome, Panel, State, Text, TextExt, UpdateType, VerticalAlignment, Widget, }; use crate::after_level::Results; @@ -17,6 +16,7 @@ use crate::levels::Level; use crate::meters::{custom_bar, make_bar}; use crate::movement::Player; use crate::vehicles::Vehicle; +use crate::{App, Transition}; const ACQUIRE_BOOST_RATE: f64 = 0.5; const BOOST_SPEED_MULTIPLIER: f64 = 2.0; @@ -39,11 +39,11 @@ pub struct Game { impl Game { pub fn new( ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, level: Level, vehicle: Vehicle, upzones: HashSet, - ) -> Box> { + ) -> Box> { let title_panel = Panel::new(Widget::row(vec![ Btn::svg_def("system/assets/tools/home.svg").build(ctx, "back", Key::Escape), "15 min Santa".draw_text(ctx), @@ -153,8 +153,8 @@ impl Game { } } -impl State for Game { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for Game { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { if let Some(dt) = ctx.input.nonblocking_is_update_event() { self.time += dt; @@ -301,7 +301,7 @@ impl State for Game { Transition::Keep } - fn draw(&self, g: &mut GfxCtx, app: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, app: &App) { self.title_panel.draw(g); self.status_panel.draw(g); self.time_panel.draw(g); @@ -364,7 +364,7 @@ struct GameState { impl GameState { fn new( ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, level: Level, vehicle: Vehicle, bldgs: Buildings, @@ -386,7 +386,7 @@ impl GameState { s } - fn recalc_deliveries(&mut self, ctx: &mut EventCtx, app: &SimpleApp) { + fn recalc_deliveries(&mut self, ctx: &mut EventCtx, app: &App) { let mut batch = GeomBatch::new(); for (b, state) in &self.bldgs.buildings { if let BldgState::Done = state { @@ -398,12 +398,7 @@ impl GameState { } // If something changed, return the update to the score - fn present_dropped( - &mut self, - ctx: &mut EventCtx, - app: &SimpleApp, - id: BuildingID, - ) -> Option { + fn present_dropped(&mut self, ctx: &mut EventCtx, app: &App, id: BuildingID) -> Option { if !self.has_energy() { return None; } @@ -442,7 +437,7 @@ impl EnergylessArrow { fn update( &mut self, ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, time: Time, sleigh: Pt2D, all_stores: Vec, diff --git a/experiment/src/lib.rs b/experiment/src/lib.rs index b893180f41..19332ba354 100644 --- a/experiment/src/lib.rs +++ b/experiment/src/lib.rs @@ -14,11 +14,19 @@ mod session; mod title; mod vehicles; +type App = map_gui::SimpleApp; +type Transition = widgetry::Transition; + pub fn main() { widgetry::run(widgetry::Settings::new("experiment"), |ctx| { let mut opts = map_gui::options::Options::default(); opts.color_scheme = map_gui::colors::ColorSchemeChoice::NightMode; - let app = map_gui::SimpleApp::new_with_opts(ctx, abstutil::CmdArgs::new(), opts); + let app = map_gui::SimpleApp::new_with_opts( + ctx, + abstutil::CmdArgs::new(), + opts, + session::Session::new(), + ); let states = vec![title::TitleScreen::new(ctx)]; (app, states) }); diff --git a/experiment/src/movement.rs b/experiment/src/movement.rs index eeb671475e..d03f29c308 100644 --- a/experiment/src/movement.rs +++ b/experiment/src/movement.rs @@ -2,11 +2,12 @@ use std::collections::{HashMap, HashSet}; use abstutil::MultiMap; use geom::{Angle, Circle, Distance, Pt2D, Speed}; -use map_gui::{SimpleApp, ID}; +use map_gui::ID; use map_model::{BuildingID, Direction, IntersectionID, LaneType, RoadID}; use widgetry::EventCtx; use crate::controls::InstantController; +use crate::App; pub const ZOOM: f64 = 10.0; @@ -19,7 +20,7 @@ pub struct Player { } impl Player { - pub fn new(ctx: &mut EventCtx, app: &SimpleApp, start: IntersectionID) -> Player { + pub fn new(ctx: &mut EventCtx, app: &App, start: IntersectionID) -> Player { ctx.canvas.cam_zoom = ZOOM; let pos = app.map.get_i(start).polygon.center(); ctx.canvas.center_on_map_pt(pos); @@ -37,7 +38,7 @@ impl Player { pub fn update_with_speed( &mut self, ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, speed: Speed, ) -> Vec { let (dx, dy) = self.controls.displacement(ctx, speed); @@ -52,7 +53,7 @@ impl Player { fn apply_displacement( &mut self, ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, dx: f64, dy: f64, recurse: bool, @@ -144,7 +145,7 @@ impl Player { } /// Is the player currently on a road with a bus or bike lane? - pub fn on_good_road(&self, app: &SimpleApp) -> bool { + pub fn on_good_road(&self, app: &App) -> bool { if let On::Road(r, _) = self.on { for (_, _, lt) in app.map.get_r(r).lanes_ltr() { if lt == LaneType::Biking || lt == LaneType::Bus { @@ -164,7 +165,7 @@ enum On { } impl On { - fn get_connections(&self, app: &SimpleApp) -> (HashSet, HashSet) { + fn get_connections(&self, app: &App) -> (HashSet, HashSet) { let mut valid_roads = HashSet::new(); let mut valid_intersections = HashSet::new(); match self { @@ -198,7 +199,7 @@ struct BuildingsAlongRoad { } impl BuildingsAlongRoad { - fn new(app: &SimpleApp) -> BuildingsAlongRoad { + fn new(app: &App) -> BuildingsAlongRoad { let mut raw: MultiMap = MultiMap::new(); for b in app.map.all_buildings() { // TODO Happily assuming road and lane length is roughly the same diff --git a/experiment/src/title.rs b/experiment/src/title.rs index 8cde0730ef..ba485ec641 100644 --- a/experiment/src/title.rs +++ b/experiment/src/title.rs @@ -1,18 +1,17 @@ use map_gui::tools::{open_browser, PopupMsg}; -use map_gui::SimpleApp; use widgetry::{ - Btn, DrawBaselayer, EventCtx, GfxCtx, Key, Line, Outcome, Panel, State, Text, Transition, - Widget, + Btn, DrawBaselayer, EventCtx, GfxCtx, Key, Line, Outcome, Panel, State, Text, Widget, }; use crate::levels::Level; +use crate::{App, Transition}; pub struct TitleScreen { panel: Panel, } impl TitleScreen { - pub fn new(ctx: &mut EventCtx) -> Box> { + pub fn new(ctx: &mut EventCtx) -> Box> { let levels = Level::all(); Box::new(TitleScreen { @@ -47,8 +46,8 @@ impl TitleScreen { } } -impl State for TitleScreen { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for TitleScreen { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { match self.panel.event(ctx) { Outcome::Clicked(x) => match x.as_ref() { "quit" => { @@ -102,7 +101,7 @@ impl State for TitleScreen { DrawBaselayer::Custom } - fn draw(&self, g: &mut GfxCtx, app: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, app: &App) { g.clear(app.cs.dialog_bg); self.panel.draw(g); } diff --git a/fifteen_min/src/isochrone.rs b/fifteen_min/src/isochrone.rs index f686aba6c1..4bf6a051f2 100644 --- a/fifteen_min/src/isochrone.rs +++ b/fifteen_min/src/isochrone.rs @@ -3,10 +3,11 @@ use std::collections::HashMap; use abstutil::MultiMap; use geom::{Duration, Polygon}; use map_gui::tools::{amenity_type, Grid}; -use map_gui::SimpleApp; use map_model::{connectivity, BuildingID, Map, Path, PathConstraints, PathRequest}; use widgetry::{Color, Drawable, EventCtx, GeomBatch}; +use crate::App; + /// Represents the area reachable from a single building. pub struct Isochrone { /// The center of the isochrone @@ -24,7 +25,7 @@ pub struct Isochrone { impl Isochrone { pub fn new( ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, start: BuildingID, constraints: PathConstraints, ) -> Isochrone { @@ -57,10 +58,7 @@ impl Isochrone { } } -fn draw_isochrone( - app: &SimpleApp, - time_to_reach_building: &HashMap, -) -> GeomBatch { +fn draw_isochrone(app: &App, time_to_reach_building: &HashMap) -> GeomBatch { // To generate the polygons covering areas between 0-5 mins, 5-10 mins, etc, we have to feed // in a 2D grid of costs. Use a 100x100 meter resolution. let bounds = app.map.get_bounds(); diff --git a/fifteen_min/src/main.rs b/fifteen_min/src/main.rs index 770bdaf5af..dbbe5b41f9 100644 --- a/fifteen_min/src/main.rs +++ b/fifteen_min/src/main.rs @@ -4,9 +4,11 @@ mod viewer; #[macro_use] extern crate log; +type App = map_gui::SimpleApp<()>; + fn main() { widgetry::run(widgetry::Settings::new("15-minute neighborhoods"), |ctx| { - let app = map_gui::SimpleApp::new(ctx, abstutil::CmdArgs::new()); + let app = map_gui::SimpleApp::new(ctx, abstutil::CmdArgs::new(), ()); let states = vec![viewer::Viewer::random_start(ctx, &app)]; (app, states) }); diff --git a/fifteen_min/src/viewer.rs b/fifteen_min/src/viewer.rs index afb41c2673..983b9af225 100644 --- a/fifteen_min/src/viewer.rs +++ b/fifteen_min/src/viewer.rs @@ -6,7 +6,7 @@ use geom::{Distance, Pt2D}; use map_gui::tools::{amenity_type, nice_map_name, CityPicker, PopupMsg}; -use map_gui::{Cached, SimpleApp, ID}; +use map_gui::{Cached, ID}; use map_model::{Building, BuildingID, PathConstraints}; use widgetry::{ lctrl, Btn, Checkbox, Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, @@ -14,6 +14,7 @@ use widgetry::{ }; use crate::isochrone::Isochrone; +use crate::App; /// This is the UI state for exploring the isochrone/walkshed from a single building. pub struct Viewer { @@ -26,17 +27,13 @@ pub struct Viewer { impl Viewer { /// Start with a random building - pub fn random_start(ctx: &mut EventCtx, app: &SimpleApp) -> Box> { + pub fn random_start(ctx: &mut EventCtx, app: &App) -> Box> { let bldgs = app.map.all_buildings(); let start = bldgs[bldgs.len() / 2].id; Viewer::new(ctx, app, start) } - pub fn new( - ctx: &mut EventCtx, - app: &SimpleApp, - start: BuildingID, - ) -> Box> { + pub fn new(ctx: &mut EventCtx, app: &App, start: BuildingID) -> Box> { let constraints = PathConstraints::Pedestrian; let start = app.map.get_b(start); let isochrone = Isochrone::new(ctx, app, start.id, constraints); @@ -52,8 +49,8 @@ impl Viewer { } } -impl State for Viewer { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for Viewer { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { // Allow panning and zooming ctx.canvas_movement(); @@ -155,7 +152,7 @@ impl State for Viewer { Transition::Keep } - fn draw(&self, g: &mut GfxCtx, _: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, _: &App) { g.redraw(&self.isochrone.draw); g.redraw(&self.highlight_start); self.panel.draw(g); @@ -175,12 +172,7 @@ fn draw_star(ctx: &mut EventCtx, center: Pt2D) -> Drawable { ) } -fn build_panel( - ctx: &mut EventCtx, - app: &SimpleApp, - start: &Building, - isochrone: &Isochrone, -) -> Panel { +fn build_panel(ctx: &mut EventCtx, app: &App, start: &Building, isochrone: &Isochrone) -> Panel { let mut rows = Vec::new(); rows.push(Widget::row(vec![ @@ -236,7 +228,7 @@ struct HoverOnBuilding { type HoverKey = (BuildingID, f64); impl HoverOnBuilding { - fn key(ctx: &EventCtx, app: &SimpleApp) -> Option { + fn key(ctx: &EventCtx, app: &App) -> Option { match app.mouseover_unzoomed_buildings(ctx) { Some(ID::Building(b)) => { let scale_factor = if ctx.canvas.cam_zoom >= app.opts.min_zoom_for_detail { @@ -252,7 +244,7 @@ impl HoverOnBuilding { fn value( ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, key: HoverKey, isochrone: &Isochrone, ) -> HoverOnBuilding { diff --git a/map_gui/src/simple_app.rs b/map_gui/src/simple_app.rs index 5afffcbf0b..e203d5fd62 100644 --- a/map_gui/src/simple_app.rs +++ b/map_gui/src/simple_app.rs @@ -11,20 +11,27 @@ use crate::render::{DrawOptions, Renderable}; use crate::{AppLike, ID}; /// Simple app state that just renders a static map, without any dynamic agents on the map. -pub struct SimpleApp { +pub struct SimpleApp { pub map: Map, pub draw_map: DrawMap, pub cs: ColorScheme, pub opts: Options, pub current_selection: Option, + /// Custom per-app state can be stored here + pub session: T, } -impl SimpleApp { - pub fn new(ctx: &mut EventCtx, args: CmdArgs) -> SimpleApp { - SimpleApp::new_with_opts(ctx, args, Options::default()) +impl SimpleApp { + pub fn new(ctx: &mut EventCtx, args: CmdArgs, session: T) -> SimpleApp { + SimpleApp::new_with_opts(ctx, args, Options::default(), session) } - pub fn new_with_opts(ctx: &mut EventCtx, mut args: CmdArgs, mut opts: Options) -> SimpleApp { + pub fn new_with_opts( + ctx: &mut EventCtx, + mut args: CmdArgs, + mut opts: Options, + session: T, + ) -> SimpleApp { ctx.loading_screen("load map", |ctx, mut timer| { opts.update_from_args(&mut args); let map_path = args @@ -42,6 +49,7 @@ impl SimpleApp { cs, opts, current_selection: None, + session, } }) } @@ -189,7 +197,7 @@ impl SimpleApp { } } -impl AppLike for SimpleApp { +impl AppLike for SimpleApp { #[inline] fn map(&self) -> &Map { &self.map @@ -244,7 +252,7 @@ impl AppLike for SimpleApp { pt: Pt2D, target_cam_zoom: Option, _: Option, - ) -> Box> { + ) -> Box>> { Box::new(SimpleWarper { warper: Warper::new(ctx, pt, target_cam_zoom), }) @@ -264,7 +272,7 @@ impl AppLike for SimpleApp { } } -impl SharedAppState for SimpleApp { +impl SharedAppState for SimpleApp { fn draw_default(&self, g: &mut GfxCtx) { self.draw_with_opts(g, DrawOptions::new()); } @@ -282,8 +290,8 @@ struct SimpleWarper { warper: Warper, } -impl State for SimpleWarper { - fn event(&mut self, ctx: &mut EventCtx, _: &mut SimpleApp) -> Transition { +impl State> for SimpleWarper { + fn event(&mut self, ctx: &mut EventCtx, _: &mut SimpleApp) -> Transition> { if self.warper.event(ctx) { Transition::Keep } else { @@ -291,7 +299,7 @@ impl State for SimpleWarper { } } - fn draw(&self, _: &mut GfxCtx, _: &SimpleApp) {} + fn draw(&self, _: &mut GfxCtx, _: &SimpleApp) {} } /// Store a cached key/value pair, only recalculating when the key changes. diff --git a/map_gui/src/tools/minimap.rs b/map_gui/src/tools/minimap.rs index 92ddd3502d..1c65e190e0 100644 --- a/map_gui/src/tools/minimap.rs +++ b/map_gui/src/tools/minimap.rs @@ -25,7 +25,7 @@ pub struct SimpleMinimap { } impl SimpleMinimap { - pub fn new(ctx: &mut EventCtx, app: &SimpleApp, with_zorder: bool) -> SimpleMinimap { + pub fn new(ctx: &mut EventCtx, app: &SimpleApp, with_zorder: bool) -> SimpleMinimap { // Initially pick a zoom to fit the smaller of the entire map's width or height in the // minimap. Arbitrary and probably pretty weird. let bounds = app.map.get_bounds(); @@ -49,7 +49,7 @@ impl SimpleMinimap { m } - pub fn recreate_panel(&mut self, ctx: &mut EventCtx, app: &SimpleApp) { + pub fn recreate_panel(&mut self, ctx: &mut EventCtx, app: &SimpleApp) { if ctx.canvas.cam_zoom < app.opts.min_zoom_for_detail { self.panel = Panel::empty(ctx); return; @@ -138,7 +138,7 @@ impl SimpleMinimap { (pct_x, pct_y) } - pub fn set_zoom(&mut self, ctx: &mut EventCtx, app: &SimpleApp, zoom_lvl: usize) { + pub fn set_zoom(&mut self, ctx: &mut EventCtx, app: &SimpleApp, zoom_lvl: usize) { // Make the frame wind up in the same relative position on the minimap let (pct_x, pct_y) = self.map_to_minimap_pct(ctx.canvas.center_to_map_pt()); @@ -154,7 +154,7 @@ impl SimpleMinimap { self.offset_y = map_center.y() * self.zoom - pct_y * inner_rect.height(); } - fn recenter(&mut self, ctx: &EventCtx, app: &SimpleApp) { + fn recenter(&mut self, ctx: &EventCtx, app: &SimpleApp) { // Recenter the minimap on the screen bounds let map_center = ctx.canvas.center_to_map_pt(); let rect = self.panel.rect_of("minimap"); @@ -169,11 +169,11 @@ impl SimpleMinimap { self.offset_y = off_y.max(0.0).min(bounds.max_y * self.zoom - rect.height()); } - pub fn event( + pub fn event( &mut self, ctx: &mut EventCtx, - app: &mut SimpleApp, - ) -> Option> { + app: &mut SimpleApp, + ) -> Option>> { let zoomed = ctx.canvas.cam_zoom >= app.opts.min_zoom_for_detail; if zoomed != self.zoomed { let just_zoomed_in = zoomed && !self.zoomed; @@ -303,11 +303,16 @@ impl SimpleMinimap { None } - pub fn draw(&self, g: &mut GfxCtx, app: &SimpleApp) { + pub fn draw(&self, g: &mut GfxCtx, app: &SimpleApp) { self.draw_with_extra_layers(g, app, Vec::new()); } - pub fn draw_with_extra_layers(&self, g: &mut GfxCtx, app: &SimpleApp, extra: Vec<&Drawable>) { + pub fn draw_with_extra_layers( + &self, + g: &mut GfxCtx, + app: &SimpleApp, + extra: Vec<&Drawable>, + ) { self.panel.draw(g); if !self.zoomed { return; diff --git a/osm_viewer/src/main.rs b/osm_viewer/src/main.rs index 7c9ff67bc3..6abdd19fbe 100644 --- a/osm_viewer/src/main.rs +++ b/osm_viewer/src/main.rs @@ -2,7 +2,7 @@ mod viewer; fn main() { widgetry::run(widgetry::Settings::new("OpenStreetMap viewer"), |ctx| { - let app = map_gui::SimpleApp::new(ctx, abstutil::CmdArgs::new()); + let app = map_gui::SimpleApp::new(ctx, abstutil::CmdArgs::new(), ()); let states = vec![viewer::Viewer::new(ctx, &app)]; (app, states) }); diff --git a/osm_viewer/src/viewer.rs b/osm_viewer/src/viewer.rs index 9f3f5b42f0..e897707c05 100644 --- a/osm_viewer/src/viewer.rs +++ b/osm_viewer/src/viewer.rs @@ -15,6 +15,8 @@ use widgetry::{ VerticalAlignment, Widget, }; +type App = SimpleApp<()>; + pub struct Viewer { top_panel: Panel, fixed_object_outline: Option, @@ -23,7 +25,7 @@ pub struct Viewer { } impl Viewer { - pub fn new(ctx: &mut EventCtx, app: &SimpleApp) -> Box> { + pub fn new(ctx: &mut EventCtx, app: &App) -> Box> { let with_zorder = true; let mut viewer = Viewer { fixed_object_outline: None, @@ -40,7 +42,7 @@ impl Viewer { fn recalculate_top_panel( &mut self, ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, biz_search_panel: Option, ) { let top_panel = Panel::new(Widget::col(vec![ @@ -75,7 +77,7 @@ impl Viewer { self.top_panel = top_panel; } - fn calculate_tags(&self, ctx: &EventCtx, app: &SimpleApp) -> Widget { + fn calculate_tags(&self, ctx: &EventCtx, app: &App) -> Widget { let mut col = Vec::new(); if self.fixed_object_outline.is_some() { col.push("Click something else to examine it".draw_text(ctx)); @@ -217,8 +219,8 @@ impl Viewer { } } -impl State for Viewer { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for Viewer { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { ctx.canvas_movement(); if ctx.redo_mouseover() { let old_id = app.current_selection.clone(); @@ -347,7 +349,7 @@ impl State for Viewer { DrawBaselayer::Custom } - fn draw(&self, g: &mut GfxCtx, app: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, app: &App) { if g.canvas.cam_zoom < app.opts.min_zoom_for_detail { app.draw_unzoomed(g); } else { @@ -378,7 +380,7 @@ struct BusinessSearch { } impl BusinessSearch { - fn new(ctx: &mut EventCtx, app: &SimpleApp) -> BusinessSearch { + fn new(ctx: &mut EventCtx, app: &App) -> BusinessSearch { let mut counts = Counter::new(); for b in app.map.all_buildings() { for a in &b.amenities { @@ -400,7 +402,7 @@ impl BusinessSearch { } // Updates the highlighted buildings - fn update(&mut self, ctx: &mut EventCtx, app: &SimpleApp) { + fn update(&mut self, ctx: &mut EventCtx, app: &App) { let mut batch = GeomBatch::new(); for b in app.map.all_buildings() { if b.amenities @@ -413,12 +415,7 @@ impl BusinessSearch { self.highlight = ctx.upload(batch); } - fn hovering_on_amenity( - &mut self, - ctx: &mut EventCtx, - app: &SimpleApp, - amenity: Option, - ) { + fn hovering_on_amenity(&mut self, ctx: &mut EventCtx, app: &App, amenity: Option) { if amenity.is_none() { self.hovering_on_amenity = None; return; diff --git a/parking_mapper/src/main.rs b/parking_mapper/src/main.rs index ca79711801..0ab87113db 100644 --- a/parking_mapper/src/main.rs +++ b/parking_mapper/src/main.rs @@ -2,7 +2,7 @@ mod mapper; fn main() { widgetry::run(widgetry::Settings::new("OSM parking mapper"), |ctx| { - let mut app = map_gui::SimpleApp::new(ctx, abstutil::CmdArgs::new()); + let mut app = map_gui::SimpleApp::new(ctx, abstutil::CmdArgs::new(), ()); app.opts.min_zoom_for_detail = 2.0; let states = vec![mapper::ParkingMapper::new(ctx, &app)]; (app, states) diff --git a/parking_mapper/src/mapper.rs b/parking_mapper/src/mapper.rs index 558a174e3b..d72a23b228 100644 --- a/parking_mapper/src/mapper.rs +++ b/parking_mapper/src/mapper.rs @@ -13,6 +13,8 @@ use widgetry::{ Line, Menu, Outcome, Panel, State, Text, TextExt, Transition, VerticalAlignment, Widget, }; +type App = SimpleApp<()>; + pub struct ParkingMapper { panel: Panel, draw_layer: Drawable, @@ -41,16 +43,16 @@ pub enum Value { } impl ParkingMapper { - pub fn new(ctx: &mut EventCtx, app: &SimpleApp) -> Box> { + pub fn new(ctx: &mut EventCtx, app: &App) -> Box> { ParkingMapper::make(ctx, app, Show::TODO, BTreeMap::new()) } fn make( ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, show: Show, data: BTreeMap, - ) -> Box> { + ) -> Box> { let map = &app.map; let color = match show { @@ -189,8 +191,8 @@ impl ParkingMapper { } } -impl State for ParkingMapper { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for ParkingMapper { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { let map = &app.map; ctx.canvas_movement(); @@ -371,7 +373,7 @@ impl State for ParkingMapper { Transition::Keep } - fn draw(&self, g: &mut GfxCtx, _: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, _: &App) { g.redraw(&self.draw_layer); if let Some((_, ref roads)) = self.selected { g.redraw(roads); @@ -391,11 +393,11 @@ struct ChangeWay { impl ChangeWay { fn new( ctx: &mut EventCtx, - app: &SimpleApp, + app: &App, selected: &HashSet, show: Show, data: BTreeMap, - ) -> Box> { + ) -> Box> { let map = &app.map; let osm_way_id = map .get_r(*selected.iter().next().unwrap()) @@ -453,8 +455,8 @@ impl ChangeWay { } } -impl State for ChangeWay { - fn event(&mut self, ctx: &mut EventCtx, app: &mut SimpleApp) -> Transition { +impl State for ChangeWay { + fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { ctx.canvas_movement(); match self.panel.event(ctx) { Outcome::Clicked(x) => match x.as_ref() { @@ -493,7 +495,7 @@ impl State for ChangeWay { } } - fn draw(&self, g: &mut GfxCtx, _: &SimpleApp) { + fn draw(&self, g: &mut GfxCtx, _: &App) { g.redraw(&self.draw); self.panel.draw(g); } @@ -597,7 +599,7 @@ fn generate_osmc( Ok(()) } -fn find_divided_highways(app: &SimpleApp) -> HashSet { +fn find_divided_highways(app: &App) -> HashSet { let map = &app.map; let mut closest: FindClosest = FindClosest::new(map.get_bounds()); // TODO Consider not even filtering by oneway. I keep finding mistakes where people split a @@ -640,7 +642,7 @@ fn find_divided_highways(app: &SimpleApp) -> HashSet { } // TODO Lots of false positives here... why? -fn find_overlapping_stuff(app: &SimpleApp, timer: &mut Timer) -> Vec { +fn find_overlapping_stuff(app: &App, timer: &mut Timer) -> Vec { let map = &app.map; let mut closest: FindClosest = FindClosest::new(map.get_bounds()); for r in map.all_roads() {