diff --git a/book/src/project/CHANGELOG.md b/book/src/project/CHANGELOG.md index b1d8f1e2e7..c9fbf9760a 100644 --- a/book/src/project/CHANGELOG.md +++ b/book/src/project/CHANGELOG.md @@ -587,3 +587,14 @@ changes here. - small UI tweaks for parking, editing multiple signals - fixed last bugs for left-handed driving, should work just as well now - lots of graphics experiments from the hackathon, not merged yet + +0.2.12 + +- new textured color scheme and isometric buildings, in settings +- new layer to show how far away people parked +- Massive UI overhauls: jump to time/delay, edit mode, traffic signal editor (now with offsets), lane editor, bulk lane edit, traffic signal demand (individual intersections and all), loading screen +- the Go API example compares trip times and detects gridlock +- infinite parking mode +- show how long a car has been parked in one spot +- bugfix for some pathfinding costs around uber-turns +- start to show a trip's purpose diff --git a/game/src/colors.rs b/game/src/colors.rs index 9cc2cfd12f..3530a2ec9f 100644 --- a/game/src/colors.rs +++ b/game/src/colors.rs @@ -1,4 +1,5 @@ use crate::common::ColorScale; +use crate::helpers::loading_tips; use widgetry::{Choice, Color, Fill, Style, Texture}; // I've gone back and forth how to organize color scheme code. I was previously against having one @@ -141,7 +142,8 @@ impl ColorScheme { } fn standard() -> ColorScheme { - let gui_style = Style::standard(); + let mut gui_style = Style::standard(); + gui_style.loading_tips = loading_tips(); ColorScheme { // UI hovering: gui_style.hovering_color, diff --git a/game/src/helpers.rs b/game/src/helpers.rs index d4b28fbcbe..e70d20f5ef 100644 --- a/game/src/helpers.rs +++ b/game/src/helpers.rs @@ -287,3 +287,15 @@ pub fn open_browser(url: String) { let _ = webbrowser::open(&url); } } + +pub fn loading_tips() -> Text { + Text::from_multiline(vec![ + Line("Recent changes (September 20)"), + Line(""), + Line("- Try out the new traffic signal editor!"), + Line("- The \"traffic signal demand\" layer shows all intersections through the whole day"), + Line("- New 3D buildings and textured color schemes in settings"), + Line("- Support for bidirectional cycletracks"), + Line("- An API to control A/B Street from any language"), + ]) +} diff --git a/game/src/main.rs b/game/src/main.rs index 6e3c692e7f..3b956af02f 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -76,6 +76,7 @@ fn main() { if let Some(s) = args.optional_parse("--scale_factor", |s| s.parse::()) { settings.scale_factor(s); } + settings.loading_tips(helpers::loading_tips()); let mut mode = None; if let Some(x) = args.optional("--challenge") { diff --git a/widgetry/src/event_ctx.rs b/widgetry/src/event_ctx.rs index 63de0cde1d..bd8cd9f5e0 100644 --- a/widgetry/src/event_ctx.rs +++ b/widgetry/src/event_ctx.rs @@ -1,9 +1,9 @@ use crate::{ - svg, text, Canvas, Color, Drawable, Event, GeomBatch, GfxCtx, Line, Prerender, ScreenDims, - ScreenPt, Style, Text, UserInput, + svg, text, Canvas, Color, Drawable, Event, GeomBatch, GfxCtx, HorizontalAlignment, Line, Panel, + Prerender, ScreenDims, Style, Text, UserInput, VerticalAlignment, Widget, }; use abstutil::{elapsed_seconds, Timer, TimerSink}; -use geom::Polygon; +use geom::{Percent, Polygon}; use instant::Instant; use std::collections::VecDeque; @@ -41,6 +41,7 @@ impl<'a> EventCtx<'a> { &timer_name, Box::new(LoadingScreen::new( self.prerender, + self.style.clone(), self.canvas.get_window_dims(), timer_name.clone(), )), @@ -140,6 +141,7 @@ pub struct LoadingScreen<'a> { impl<'a> LoadingScreen<'a> { pub fn new( prerender: &'a Prerender, + style: Style, initial_size: ScreenDims, title: String, ) -> LoadingScreen<'a> { @@ -154,7 +156,7 @@ impl<'a> LoadingScreen<'a> { last_drawn: Instant::now(), title, canvas, - style: Style::standard(), + style, } } @@ -164,26 +166,72 @@ impl<'a> LoadingScreen<'a> { return; } self.last_drawn = Instant::now(); + let mut ctx = EventCtx { + fake_mouseover: true, + input: UserInput::new(Event::NoOp, &self.canvas), + canvas: &mut self.canvas, + prerender: self.prerender, + style: &mut self.style, + updates_requested: vec![], + }; let mut txt = Text::from(Line(&self.title).small_heading()); for l in &self.lines { txt.add(Line(l)); } + let border = Color::hex("#F4DA22"); + let panel = Panel::new(Widget::row(vec![ + Widget::custom_col(vec![ + Widget::draw_batch( + &ctx, + GeomBatch::load_svg(ctx.prerender, "system/assets/map/dont_walk.svg") + .scale(5.0), + ) + .container() + .bg(Color::BLACK) + .padding(15) + .outline(5.0, border) + .centered_horiz() + .margin_below(5), + Widget::draw_batch( + &ctx, + GeomBatch::from(vec![(Color::grey(0.5), Polygon::rectangle(10.0, 30.0))]), + ) + .centered_horiz(), + ctx.style + .loading_tips + .clone() + .wrap_to_pct(&ctx, 25) + .draw(&ctx) + .container() + .bg(Color::BLACK) + .padding(15) + .outline(5.0, Color::YELLOW) + .force_width_pct(&ctx, Percent::int(30)) + .margin_below(5), + Widget::draw_batch( + &ctx, + GeomBatch::from(vec![(Color::grey(0.5), Polygon::rectangle(10.0, 100.0))]), + ) + .centered_horiz(), + ]) + .centered_vert(), + Widget::draw_batch( + &ctx, + txt.inner_render(&ctx.prerender.assets, svg::LOW_QUALITY), + ) + .container() + .fill_width() + .padding(16) + .bg(text::BG_COLOR), + ])) + .exact_size_percent(80, 80) + .aligned(HorizontalAlignment::Center, VerticalAlignment::Center) + .build_custom(&mut ctx); let mut g = GfxCtx::new(self.prerender, &self.canvas, &self.style, false); g.clear(Color::BLACK); - - let mut batch = GeomBatch::from(vec![( - text::BG_COLOR, - Polygon::rectangle(0.8 * g.canvas.window_width, 0.8 * g.canvas.window_height), - )]); - batch.append(txt.inner_render(&g.prerender.assets, svg::LOW_QUALITY)); - let draw = g.upload(batch); - g.redraw_at( - ScreenPt::new(0.1 * g.canvas.window_width, 0.1 * g.canvas.window_height), - &draw, - ); - + panel.draw(&mut g); g.prerender.inner.draw_finished(g.inner); } } diff --git a/widgetry/src/runner.rs b/widgetry/src/runner.rs index 765d48ba35..1cfa663310 100644 --- a/widgetry/src/runner.rs +++ b/widgetry/src/runner.rs @@ -1,6 +1,6 @@ use crate::assets::Assets; use crate::tools::screenshot::screenshot_everything; -use crate::{Canvas, Event, EventCtx, GfxCtx, Key, Prerender, Style, UpdateType, UserInput}; +use crate::{Canvas, Event, EventCtx, GfxCtx, Key, Prerender, Style, Text, UpdateType, UserInput}; use geom::Duration; use image::{GenericImageView, Pixel}; use instant::Instant; @@ -160,6 +160,7 @@ pub struct Settings { dump_raw_events: bool, scale_factor: Option, window_icon: Option, + loading_tips: Option, } impl Settings { @@ -170,6 +171,7 @@ impl Settings { dump_raw_events: false, scale_factor: None, window_icon: None, + loading_tips: None, } } @@ -190,6 +192,10 @@ impl Settings { pub fn window_icon(&mut self, path: String) { self.window_icon = Some(path); } + + pub fn loading_tips(&mut self, txt: Text) { + self.loading_tips = Some(txt); + } } pub fn run G>(settings: Settings, make_gui: F) -> ! { @@ -216,6 +222,7 @@ pub fn run G>(settings: Settings, scale_factor: RefCell::new(settings.scale_factor.unwrap_or(monitor_scale_factor)), }; let mut style = Style::standard(); + style.loading_tips = settings.loading_tips.unwrap_or_else(Text::new); let initial_size = prerender.window_size(); let mut canvas = Canvas::new(initial_size); diff --git a/widgetry/src/style.rs b/widgetry/src/style.rs index 34b3b67484..4e24a3849b 100644 --- a/widgetry/src/style.rs +++ b/widgetry/src/style.rs @@ -1,4 +1,4 @@ -use crate::Color; +use crate::{Color, Text}; #[derive(Clone)] pub struct Style { @@ -7,6 +7,7 @@ pub struct Style { pub panel_bg: Color, pub hotkey_color: Color, pub hovering_color: Color, + pub loading_tips: Text, } impl Style { @@ -17,6 +18,7 @@ impl Style { panel_bg: Color::grey(0.4), hotkey_color: Color::GREEN, hovering_color: Color::ORANGE, + loading_tips: Text::new(), } } } diff --git a/widgetry/src/widgets/mod.rs b/widgetry/src/widgets/mod.rs index 35142268f5..ef9219f363 100644 --- a/widgetry/src/widgets/mod.rs +++ b/widgetry/src/widgets/mod.rs @@ -135,6 +135,10 @@ impl Widget { self } + pub fn fill_width(mut self) -> Widget { + self.layout.style.size.width = Dimension::Percent(1.0); + self + } pub fn fill_height(mut self) -> Widget { self.layout.style.size.height = Dimension::Percent(1.0); self