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