prepping for a caching layer by changing render API, plumbing ctx...

getting close
This commit is contained in:
Dustin Carlino 2020-02-06 21:39:23 -08:00
parent 7c76f2d119
commit 3ff56f54cf
36 changed files with 121 additions and 132 deletions

View File

@ -74,7 +74,6 @@ pub struct GfxCtx<'a> {
// TODO Don't be pub. Delegate everything.
pub canvas: &'a Canvas,
pub prerender: &'a Prerender<'a>,
pub(crate) assets: &'a Assets,
pub num_draw_calls: usize,
}
@ -85,7 +84,6 @@ impl<'a> GfxCtx<'a> {
prerender: &'a Prerender<'a>,
target: &'a mut glium::Frame,
program: &'a glium::Program,
assets: &'a Assets,
screencap_mode: bool,
) -> GfxCtx<'a> {
let params = glium::DrawParameters {
@ -110,7 +108,6 @@ impl<'a> GfxCtx<'a> {
num_draw_calls: 0,
screencap_mode,
naming_hint: None,
assets,
}
}
@ -229,10 +226,10 @@ impl<'a> GfxCtx<'a> {
// The text box covers up what's beneath and eats the cursor (for get_cursor_in_map_space).
pub fn draw_blocking_text(
&mut self,
txt: &Text,
txt: Text,
(horiz, vert): (HorizontalAlignment, VerticalAlignment),
) {
let mut dims = txt.dims();
let mut dims = txt.dims(&self.prerender.assets);
let top_left = self.canvas.align_window(dims, horiz, vert);
// TODO This doesn't take effect anymore
if let HorizontalAlignment::FillScreen = horiz {
@ -242,7 +239,7 @@ impl<'a> GfxCtx<'a> {
self.draw_blocking_text_at_screenspace_topleft(txt, top_left);
}
pub(crate) fn draw_blocking_text_at_screenspace_topleft(&mut self, txt: &Text, pt: ScreenPt) {
pub(crate) fn draw_blocking_text_at_screenspace_topleft(&mut self, txt: Text, pt: ScreenPt) {
let mut batch = GeomBatch::new();
self.canvas
.mark_covered_area(txt.clone().render(&mut batch, pt));
@ -256,8 +253,8 @@ impl<'a> GfxCtx<'a> {
}
// TODO Rename these draw_nonblocking_text_*
pub fn draw_text_at(&mut self, txt: &Text, map_pt: Pt2D) {
let dims = txt.dims();
pub fn draw_text_at(&mut self, txt: Text, map_pt: Pt2D) {
let dims = txt.dims(&self.prerender.assets);
let pt = self.canvas.map_to_screen(map_pt);
let mut batch = GeomBatch::new();
txt.clone().render(
@ -269,8 +266,8 @@ impl<'a> GfxCtx<'a> {
self.unfork();
}
pub fn draw_mouse_tooltip(&mut self, txt: &Text) {
let dims = txt.dims();
pub fn draw_mouse_tooltip(&mut self, txt: Text) {
let dims = txt.dims(&self.prerender.assets);
// TODO Maybe also consider the cursor as a valid center
let pt = dims.top_left_for_corner(
ScreenPt::new(self.canvas.cursor_x, self.canvas.cursor_y),
@ -315,7 +312,7 @@ impl<'a> GfxCtx<'a> {
// Delegation to assets
pub fn default_line_height(&self) -> f64 {
self.assets.default_line_height
self.prerender.assets.default_line_height
}
}
@ -450,6 +447,7 @@ glium::implement_vertex!(Vertex, position, style);
// TODO Don't expose this directly
pub struct Prerender<'a> {
pub(crate) assets: Assets,
pub(crate) display: &'a glium::Display,
pub(crate) num_uploads: Cell<usize>,
// TODO Prerender doesn't know what things are temporary and permanent. Could make the API more

View File

@ -1,4 +1,3 @@
use crate::assets::Assets;
use crate::{
Canvas, Color, Event, GfxCtx, HorizontalAlignment, Line, Prerender, ScreenDims, Text,
UserInput, VerticalAlignment,
@ -18,7 +17,6 @@ pub struct EventCtx<'a> {
pub prerender: &'a Prerender<'a>,
pub(crate) program: &'a glium::Program,
pub(crate) assets: &'a Assets,
}
impl<'a> EventCtx<'a> {
@ -33,7 +31,6 @@ impl<'a> EventCtx<'a> {
Box::new(LoadingScreen::new(
self.prerender,
self.program,
self.assets,
self.canvas.window_width,
self.canvas.window_height,
timer_name.clone(),
@ -58,7 +55,6 @@ impl<'a> EventCtx<'a> {
canvas: self.canvas,
prerender: self.prerender,
program: self.program,
assets: self.assets,
};
cb(&mut tmp)
}
@ -158,7 +154,7 @@ impl<'a> EventCtx<'a> {
// Delegation to assets
pub fn default_line_height(&self) -> f64 {
self.assets.default_line_height
self.prerender.assets.default_line_height
}
}
@ -166,7 +162,6 @@ pub struct LoadingScreen<'a> {
canvas: Canvas,
prerender: &'a Prerender<'a>,
program: &'a glium::Program,
assets: &'a Assets,
lines: VecDeque<String>,
max_capacity: usize,
last_drawn: Instant,
@ -177,7 +172,6 @@ impl<'a> LoadingScreen<'a> {
pub fn new(
prerender: &'a Prerender<'a>,
program: &'a glium::Program,
assets: &'a Assets,
initial_width: f64,
initial_height: f64,
title: String,
@ -187,9 +181,8 @@ impl<'a> LoadingScreen<'a> {
LoadingScreen {
prerender,
program,
assets,
lines: VecDeque::new(),
max_capacity: (0.8 * initial_height / assets.default_line_height) as usize,
max_capacity: (0.8 * initial_height / prerender.assets.default_line_height) as usize,
// If the loading callback takes less than 0.2s, we don't redraw at all.
last_drawn: Instant::now(),
title,
@ -218,13 +211,12 @@ impl<'a> LoadingScreen<'a> {
self.prerender,
&mut target,
self.program,
&self.assets,
false,
);
g.clear(Color::BLACK);
// TODO Keep the width fixed.
g.draw_blocking_text(
&txt,
txt,
(HorizontalAlignment::Center, VerticalAlignment::Center),
);
target.finish().unwrap();

View File

@ -34,7 +34,6 @@ pub enum EventLoopMode {
pub(crate) struct State<G: GUI> {
pub(crate) gui: G,
pub(crate) canvas: Canvas,
assets: Assets,
}
impl<G: GUI> State<G> {
@ -80,12 +79,10 @@ impl<G: GUI> State<G> {
}
}
let assets = self.assets;
let mut ctx = EventCtx {
fake_mouseover: false,
input: input,
canvas: &mut canvas,
assets: &assets,
prerender,
program,
};
@ -106,7 +103,6 @@ impl<G: GUI> State<G> {
};
self.gui = gui;
self.canvas = canvas;
self.assets = assets;
(self, event_mode, input_used)
}
@ -120,14 +116,7 @@ impl<G: GUI> State<G> {
screenshot: bool,
) -> Option<String> {
let mut target = display.draw();
let mut g = GfxCtx::new(
&self.canvas,
&prerender,
&mut target,
program,
&self.assets,
screenshot,
);
let mut g = GfxCtx::new(&self.canvas, &prerender, &mut target, program, screenshot);
self.canvas.start_drawing();
@ -255,8 +244,8 @@ pub fn run<G: GUI, F: FnOnce(&mut EventCtx) -> G>(settings: Settings, make_gui:
}
let window_size = events_loop.get_primary_monitor().get_dimensions();
let mut canvas = Canvas::new(window_size.width, window_size.height, hidpi_factor);
let assets = Assets::new(settings.default_font_size);
let prerender = Prerender {
assets: Assets::new(settings.default_font_size),
display: &display,
num_uploads: Cell::new(0),
total_bytes_uploaded: Cell::new(0),
@ -266,16 +255,11 @@ pub fn run<G: GUI, F: FnOnce(&mut EventCtx) -> G>(settings: Settings, make_gui:
fake_mouseover: true,
input: UserInput::new(Event::NoOp, &canvas),
canvas: &mut canvas,
assets: &assets,
prerender: &prerender,
program: &program,
});
let state = State {
canvas,
assets,
gui,
};
let state = State { canvas, gui };
loop_forever(
state,

View File

@ -1,4 +1,5 @@
use crate::{Color, GeomBatch, ScreenDims, ScreenPt, ScreenRectangle};
use crate::assets::Assets;
use crate::{Color, GeomBatch, Prerender, ScreenDims, ScreenPt, ScreenRectangle};
use geom::Polygon;
use std::fmt::Write;
use textwrap;
@ -182,7 +183,7 @@ impl Text {
self.lines.extend(other.lines.clone())
}
pub(crate) fn dims(&self) -> ScreenDims {
pub(crate) fn dims(&self, _: &Assets) -> ScreenDims {
// TODO Still pay attention to this hack, so the loading screen isn't dreadfully slow
if let Some(w) = self.override_width {
return ScreenDims::new(w, self.override_height.unwrap());
@ -238,7 +239,7 @@ impl Text {
ScreenRectangle::top_left(top_left, ScreenDims::new(max_width, y - top_left.y))
}
pub fn render_to_batch(self) -> GeomBatch {
pub fn render_to_batch(self, _: &Prerender) -> GeomBatch {
let mut batch = GeomBatch::new();
self.render(&mut batch, ScreenPt::new(0.0, 0.0));
batch.realign()

View File

@ -80,7 +80,7 @@ impl<T: Clone + Hash + Eq> Autocomplete<T> {
}
g.draw_blocking_text(
&txt,
txt,
(HorizontalAlignment::Center, VerticalAlignment::Center),
);
}

View File

@ -220,7 +220,7 @@ impl Button {
const HORIZ_PADDING: f64 = 30.0;
const VERT_PADDING: f64 = 10.0;
let dims = text.dims();
let dims = text.clone().dims(&ctx.prerender.assets);
let geom = Polygon::rounded_rectangle(
dims.width + 2.0 * HORIZ_PADDING,
dims.height + 2.0 * VERT_PADDING,
@ -255,8 +255,8 @@ impl Button {
let horiz_padding = if padding { 15.0 } else { 0.0 };
let vert_padding = if padding { 8.0 } else { 0.0 };
let dims = unselected_text.dims();
assert_eq!(dims, selected_text.dims());
let dims = unselected_text.clone().dims(&ctx.prerender.assets);
assert_eq!(dims, selected_text.clone().dims(&ctx.prerender.assets));
let geom = Polygon::rectangle(
dims.width + 2.0 * horiz_padding,
dims.height + 2.0 * vert_padding,
@ -281,7 +281,7 @@ impl Button {
let horiz_padding = 15.0;
let vert_padding = 8.0;
txt = txt.change_fg(Color::grey(0.5));
let dims = txt.dims();
let dims = txt.clone().dims(&ctx.prerender.assets);
let mut draw = DrawBoth::new(
ctx,
@ -306,7 +306,7 @@ impl Button {
const VERT_PADDING: f64 = 10.0;
let txt = Text::from(Line(label).fg(Color::BLACK));
let dims = txt.dims();
let dims = txt.clone().dims(&ctx.prerender.assets);
let geom = Polygon::rounded_rectangle(
dims.width + 2.0 * HORIZ_PADDING,
dims.height + 2.0 * VERT_PADDING,

View File

@ -119,7 +119,7 @@ impl Histogram {
let pt = Pt2D::new(cursor.x - self.top_left.x, cursor.y - self.top_left.y);
for (rect, lbl) in &self.rect_labels {
if rect.contains_pt(pt) {
g.draw_mouse_tooltip(lbl);
g.draw_mouse_tooltip(lbl.clone());
break;
}
}

View File

@ -26,7 +26,7 @@ impl ModalMenu {
pub fn new<S1: Into<String>, S2: Into<String>>(
title: S1,
raw_choices: Vec<(Option<MultiKey>, S2)>,
_: &EventCtx,
ctx: &EventCtx,
) -> ModalMenu {
let mut m = ModalMenu {
title: title.into(),
@ -46,7 +46,7 @@ impl ModalMenu {
top_left: ScreenPt::new(0.0, 0.0),
dims: ScreenDims::new(0.0, 0.0),
};
m.dims = m.calculate_txt().dims();
m.dims = m.calculate_txt().dims(&ctx.prerender.assets);
m
}
@ -63,9 +63,9 @@ impl ModalMenu {
self
}
pub fn set_info(&mut self, info: Text) {
pub fn set_info(&mut self, ctx: &EventCtx, info: Text) {
self.info = info.with_bg();
self.dims = self.calculate_txt().dims();
self.dims = self.calculate_txt().dims(&ctx.prerender.assets);
}
pub fn event(&mut self, ctx: &mut EventCtx) {
@ -75,7 +75,7 @@ impl ModalMenu {
if let Some(o) = self.standalone_layout {
layout::stack_vertically(o, ctx, vec![self]);
self.dims = self.calculate_txt().dims();
self.dims = self.calculate_txt().dims(&ctx.prerender.assets);
}
// Handle the mouse
@ -83,7 +83,7 @@ impl ModalMenu {
self.hovering_idx = None;
if let Some(cursor) = ctx.canvas.get_cursor_in_screen_space() {
let mut top_left = self.top_left;
top_left.y += self.info.dims().height;
top_left.y += self.info.clone().dims(&ctx.prerender.assets).height;
if !self.title.is_empty() {
top_left.y += ctx.default_line_height();
}
@ -127,54 +127,54 @@ impl ModalMenu {
}
}
pub fn push_action(&mut self, hotkey: Option<MultiKey>, label: &str) {
pub fn push_action(&mut self, ctx: &EventCtx, hotkey: Option<MultiKey>, label: &str) {
self.choices.push(Choice {
hotkey,
label: label.to_string(),
active: false,
});
self.dims = self.calculate_txt().dims();
self.dims = self.calculate_txt().dims(&ctx.prerender.assets);
}
pub fn remove_action(&mut self, label: &str) {
pub fn remove_action(&mut self, ctx: &EventCtx, label: &str) {
self.choices.retain(|c| c.label != label);
self.dims = self.calculate_txt().dims();
self.dims = self.calculate_txt().dims(&ctx.prerender.assets);
}
pub fn change_action(&mut self, old_label: &str, new_label: &str) {
pub fn change_action(&mut self, ctx: &EventCtx, old_label: &str, new_label: &str) {
for c in self.choices.iter_mut() {
if c.label == old_label {
c.label = new_label.to_string();
self.dims = self.calculate_txt().dims();
self.dims = self.calculate_txt().dims(&ctx.prerender.assets);
return;
}
}
panic!("Menu doesn't have {}", old_label);
}
pub fn maybe_change_action(&mut self, old_label: &str, new_label: &str) {
pub fn maybe_change_action(&mut self, ctx: &EventCtx, old_label: &str, new_label: &str) {
for c in self.choices.iter_mut() {
if c.label == old_label {
c.label = new_label.to_string();
self.dims = self.calculate_txt().dims();
self.dims = self.calculate_txt().dims(&ctx.prerender.assets);
return;
}
}
// Don't panic
}
pub fn swap_action(&mut self, old_label: &str, new_label: &str) -> bool {
pub fn swap_action(&mut self, ctx: &EventCtx, old_label: &str, new_label: &str) -> bool {
if self.action(old_label) {
self.change_action(old_label, new_label);
self.change_action(ctx, old_label, new_label);
true
} else {
false
}
}
pub fn consume_action(&mut self, name: &str) -> bool {
pub fn consume_action(&mut self, ctx: &EventCtx, name: &str) -> bool {
if self.action(name) {
self.remove_action(name);
self.remove_action(ctx, name);
true
} else {
false
@ -200,7 +200,7 @@ impl ModalMenu {
}
pub fn draw(&self, g: &mut GfxCtx) {
g.draw_blocking_text_at_screenspace_topleft(&self.calculate_txt(), self.top_left);
g.draw_blocking_text_at_screenspace_topleft(self.calculate_txt(), self.top_left);
}
fn calculate_txt(&self) -> Text {

View File

@ -209,7 +209,7 @@ impl<T: 'static + Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>> Plot<T>
if txt.num_lines() > 0 {
g.fork_screenspace();
g.draw_circle(Color::RED, &Circle::new(cursor.to_pt(), radius));
g.draw_mouse_tooltip(&txt);
g.draw_mouse_tooltip(txt);
g.unfork();
}
}

View File

@ -18,7 +18,7 @@ pub struct PopupMenu<T: Clone> {
}
impl<T: Clone> PopupMenu<T> {
pub fn new(choices: Vec<Choice<T>>) -> PopupMenu<T> {
pub fn new(ctx: &EventCtx, choices: Vec<Choice<T>>) -> PopupMenu<T> {
let mut m = PopupMenu {
choices,
current_idx: 0,
@ -28,7 +28,7 @@ impl<T: Clone> PopupMenu<T> {
top_left: ScreenPt::new(0.0, 0.0),
dims: ScreenDims::new(0.0, 0.0),
};
m.dims = m.calculate_txt().dims();
m.dims = m.calculate_txt().dims(&ctx.prerender.assets);
m
}
@ -119,7 +119,7 @@ impl<T: Clone> PopupMenu<T> {
}
pub fn draw(&self, g: &mut GfxCtx) {
g.draw_blocking_text_at_screenspace_topleft(&self.calculate_txt(), self.top_left);
g.draw_blocking_text_at_screenspace_topleft(self.calculate_txt(), self.top_left);
}
pub fn current_choice(&self) -> &T {

View File

@ -294,7 +294,7 @@ impl<T> ItemSlider<T> {
abstutil::prettyprint_usize(self.items.len())
)));
txt.extend(&self.items[idx].1);
self.menu.set_info(txt);
self.menu.set_info(ctx, txt);
self.menu.event(ctx);
}
stack_vertically(
@ -432,8 +432,12 @@ impl SliderWithTextBox {
pub fn new(prompt: &str, low: Time, high: Time, ctx: &EventCtx) -> SliderWithTextBox {
SliderWithTextBox {
// TODO Some ratio based on low and high difference
slider: Slider::horizontal(ctx, Text::from(Line(prompt)).dims().width, 25.0),
tb: TextBox::new(prompt, Some(low.to_string())),
slider: Slider::horizontal(
ctx,
Text::from(Line(prompt)).dims(&ctx.prerender.assets).width,
25.0,
),
tb: TextBox::new(ctx, prompt, Some(low.to_string())),
low,
high,
}

View File

@ -1,5 +1,7 @@
use crate::layout::Widget;
use crate::{text, Event, GfxCtx, InputResult, Key, Line, ScreenDims, ScreenPt, Text, UserInput};
use crate::{
text, Event, EventCtx, GfxCtx, InputResult, Key, Line, ScreenDims, ScreenPt, Text, UserInput,
};
// TODO right now, only a single line
@ -15,7 +17,7 @@ pub struct TextBox {
}
impl TextBox {
pub fn new(prompt: &str, prefilled: Option<String>) -> TextBox {
pub fn new(ctx: &EventCtx, prompt: &str, prefilled: Option<String>) -> TextBox {
let line = prefilled.unwrap_or_else(String::new);
let mut tb = TextBox {
prompt: prompt.to_string(),
@ -27,7 +29,7 @@ impl TextBox {
dims: ScreenDims::new(0.0, 0.0),
};
// TODO Assume the dims never exceed the prompt width?
tb.dims = tb.get_text().dims();
tb.dims = tb.get_text().dims(&ctx.prerender.assets);
tb
}
@ -92,7 +94,7 @@ impl TextBox {
}
pub fn draw(&self, g: &mut GfxCtx) {
g.draw_blocking_text_at_screenspace_topleft(&self.get_text(), self.top_left);
g.draw_blocking_text_at_screenspace_topleft(self.get_text(), self.top_left);
}
}

View File

@ -89,7 +89,7 @@ impl Wizard {
}
if self.tb.is_none() {
self.tb = Some(TextBox::new(query, prefilled));
self.tb = Some(TextBox::new(ctx, query, prefilled));
}
layout::stack_vertically(
layout::ContainerOrientation::Centered,
@ -293,6 +293,7 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
.menu(
"menu",
PopupMenu::new(
self.ctx,
choices
.into_iter()
.map(|c| Choice {

View File

@ -82,7 +82,7 @@ impl State for ABTestMode {
by_mode[&TripMode::Drive],
by_mode[&TripMode::Transit]
)));
self.menu.set_info(txt);
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);

View File

@ -72,7 +72,7 @@ fn pick_ab_test(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Tra
for line in ab_test.describe() {
txt.add(Line(line));
}
menu.set_info(txt);
menu.set_info(ctx, txt);
Some(Transition::Replace(Box::new(ABTestSetup { menu, ab_test })))
}

View File

@ -69,7 +69,7 @@ impl ShowBusRoute {
pub fn draw(&self, g: &mut GfxCtx) {
self.colorer.draw(g);
for (label, pt) in &self.labels {
g.draw_text_at(label, *pt);
g.draw_text_at(label.clone(), *pt);
}
let mut batch = GeomBatch::new();

View File

@ -244,7 +244,7 @@ impl CommonState {
}
g.draw_blocking_text(
&osd,
osd,
(HorizontalAlignment::FillScreen, VerticalAlignment::Bottom),
);
}

View File

@ -60,10 +60,10 @@ impl Floodfiller {
}
let mut menu = ModalMenu::new(title, vec![(hotkey(Key::Escape), "quit")], ctx);
menu.set_info(Text::from(Line(format!(
"{} unreachable lanes",
num_unreachable
))));
menu.set_info(
ctx,
Text::from(Line(format!("{} unreachable lanes", num_unreachable))),
);
Some(Box::new(Floodfiller {
menu,

View File

@ -81,7 +81,7 @@ impl State for DebugMode {
if let routes::AllRoutesViewer::Active(_, ref traces) = self.all_routes {
txt.add(Line(format!("Showing {} routes", traces.len())));
}
self.menu.set_info(txt);
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);
@ -151,13 +151,14 @@ impl State for DebugMode {
println!("Hiding {:?}", id);
ui.primary.current_selection = None;
if self.hidden.is_empty() {
self.menu.push_action(hotkey(Key::H), "unhide everything");
self.menu
.push_action(ctx, hotkey(Key::H), "unhide everything");
}
self.hidden.insert(id);
}
}
None => {
if !self.hidden.is_empty() && self.menu.consume_action("unhide everything") {
if !self.hidden.is_empty() && self.menu.consume_action(ctx, "unhide everything") {
self.hidden.clear();
ui.primary.current_selection =
ui.calculate_current_selection(ctx, &ui.primary.sim, self, true);
@ -205,10 +206,10 @@ impl State for DebugMode {
let show = format!("show {}", label);
let hide = format!("hide {}", label);
if *value && self.menu.swap_action(&hide, &show) {
if *value && self.menu.swap_action(ctx, &hide, &show) {
*value = false;
changed = true;
} else if !*value && self.menu.swap_action(&show, &hide) {
} else if !*value && self.menu.swap_action(ctx, &show, &hide) {
*value = true;
changed = true;
}
@ -234,13 +235,13 @@ impl State for DebugMode {
if self.search_results.is_some() {
if self
.menu
.swap_action("clear OSM search results", "search OSM metadata")
.swap_action(ctx, "clear OSM search results", "search OSM metadata")
{
self.search_results = None;
}
} else if self
.menu
.swap_action("search OSM metadata", "clear OSM search results")
.swap_action(ctx, "search OSM metadata", "clear OSM search results")
{
// TODO If the wizard aborts (pressing escape), this crashes.
return Transition::Push(WizardState::new(Box::new(search_osm)));

View File

@ -46,7 +46,7 @@ impl ObjectDebugger {
txt.add(Line(gps.to_string()));
txt.add(Line(format!("{:?}", g.canvas.get_cursor())));
txt.add(Line(format!("zoom: {}", g.canvas.cam_zoom)));
g.draw_mouse_tooltip(&txt);
g.draw_mouse_tooltip(txt);
}
}
}

View File

@ -173,21 +173,21 @@ impl State for PolygonDebugger {
match item {
Item::Point(pt) => {
g.draw_text_at(&Text::from(Line(idx.to_string())).with_bg(), *pt);
g.draw_text_at(Text::from(Line(idx.to_string())).with_bg(), *pt);
}
Item::Triangle(ref tri) => {
for pt in &[tri.pt1, tri.pt2, tri.pt3] {
g.draw_text_at(&Text::from(Line(idx.to_string())).with_bg(), *pt);
g.draw_text_at(Text::from(Line(idx.to_string())).with_bg(), *pt);
}
g.draw_polygon(ui.cs.get("selected"), &Polygon::from_triangle(tri));
}
Item::Polygon(ref poly) => {
g.draw_polygon(ui.cs.get("selected"), poly);
g.draw_text_at(&Text::from(Line(idx.to_string())).with_bg(), poly.center());
g.draw_text_at(Text::from(Line(idx.to_string())).with_bg(), poly.center());
}
}
if let Some(pt) = self.center {
g.draw_text_at(&Text::from(Line("c")).with_bg(), pt);
g.draw_text_at(Text::from(Line("c")).with_bg(), pt);
}
self.slider.draw(g);

View File

@ -10,18 +10,18 @@ pub enum AllRoutesViewer {
}
impl AllRoutesViewer {
pub fn event(&mut self, ui: &mut UI, menu: &mut ModalMenu, _: &EventCtx) {
pub fn event(&mut self, ui: &mut UI, menu: &mut ModalMenu, ctx: &EventCtx) {
let show = "show route for all agents";
let hide = "hide route for all agents";
match self {
AllRoutesViewer::Inactive => {
if menu.swap_action(show, hide) {
if menu.swap_action(ctx, show, hide) {
*self = debug_all_routes(ui);
}
}
AllRoutesViewer::Active(time, _) => {
if menu.swap_action(hide, show) {
if menu.swap_action(ctx, hide, show) {
*self = AllRoutesViewer::Inactive;
} else if *time != ui.primary.sim.time() {
*self = debug_all_routes(ui);

View File

@ -147,10 +147,7 @@ impl GUI for Game {
if self.ui.opts.dev && !g.is_screencap() {
let mut txt = Text::from(Line("DEV"));
txt.highlight_last_line(Color::RED);
g.draw_blocking_text(
&txt,
(HorizontalAlignment::Right, VerticalAlignment::Bottom),
);
g.draw_blocking_text(txt, (HorizontalAlignment::Right, VerticalAlignment::Bottom));
}
/*println!(

View File

@ -101,7 +101,7 @@ impl State for TripsVisualizer {
"{} active trips",
prettyprint_usize(self.active_trips.len())
)));
self.menu.set_info(txt);
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);
ctx.canvas_movement();

View File

@ -159,7 +159,7 @@ impl State for ScenarioManager {
"{} parking spots",
prettyprint_usize(self.total_parking_spots),
)));
self.menu.set_info(txt);
self.menu.set_info(ctx, txt);
}
self.menu.event(ctx);
ctx.canvas_movement();
@ -183,7 +183,7 @@ impl State for ScenarioManager {
return Transition::Push(Box::new(DotMap::new(ctx, ui, &self.scenario)));
}
if self.demand.is_some() && self.menu.consume_action("stop showing paths") {
if self.demand.is_some() && self.menu.consume_action(ctx, "stop showing paths") {
self.demand = None;
}
@ -206,7 +206,8 @@ impl State for ScenarioManager {
&& ui.per_obj.action(ctx, Key::P, "show trips to and from")
{
self.demand = Some(show_demand(&self.scenario, from, to, OD::Bldg(b), ui, ctx));
self.menu.push_action(hotkey(Key::P), "stop showing paths");
self.menu
.push_action(ctx, hotkey(Key::P), "stop showing paths");
}
}
} else if let Some(ID::Intersection(i)) = ui.primary.current_selection {
@ -235,7 +236,8 @@ impl State for ScenarioManager {
ui,
ctx,
));
self.menu.push_action(hotkey(Key::P), "stop showing paths");
self.menu
.push_action(ctx, hotkey(Key::P), "stop showing paths");
}
}
}

View File

@ -58,7 +58,7 @@ impl DrawBuilding {
bldg.osm_tags.get("addr:housenumber").map(|num| {
let mut lbl = GeomBatch::new();
lbl.add_transformed(
Text::from(Line(num.to_string()).fg(Color::BLACK)).render_to_batch(),
Text::from(Line(num.to_string()).fg(Color::BLACK)).render_to_batch(prerender),
bldg.label_center,
0.1,
Angle::ZERO,

View File

@ -112,7 +112,7 @@ impl DrawCar {
// TODO Would rotation make any sense? Or at least adjust position/size while turning.
// Buses are a constant length, so hardcoding this is fine.
draw_default.add_transformed(
Text::from(Line(line).fg(Color::rgb(249, 206, 24))).render_to_batch(),
Text::from(Line(line).fg(Color::rgb(249, 206, 24))).render_to_batch(prerender),
input.body.dist_along(Distance::meters(9.0)).0,
0.07,
Angle::ZERO,

View File

@ -144,7 +144,7 @@ impl Renderable for DrawIntersection {
ctx.opts.traffic_signal_style.clone(),
);
batch.add_transformed(
Text::from(Line(format!("{}", idx + 1)).roboto()).render_to_batch(),
Text::from(Line(format!("{}", idx + 1)).roboto()).render_to_batch(g.prerender),
ctx.map.get_i(self.id).polygon.center(),
0.1,
Angle::ZERO,

View File

@ -209,7 +209,8 @@ impl DrawPedCrowd {
blob.clone(),
);
batch.add_transformed(
Text::from(Line(format!("{}", input.members.len())).fg(Color::BLACK)).render_to_batch(),
Text::from(Line(format!("{}", input.members.len())).fg(Color::BLACK))
.render_to_batch(prerender),
blob.center(),
0.02,
Angle::ZERO,

View File

@ -39,7 +39,7 @@ impl DrawRoad {
// TODO Disabled because it's slow up-front cost
if false {
lbl.add_transformed(
txt.render_to_batch(),
txt.render_to_batch(prerender),
r.center_pts.middle(),
0.1,
Angle::ZERO,

View File

@ -43,6 +43,7 @@ impl GameplayState for CreateGridlock {
self.menu.event(ctx);
manage_acs(
ctx,
&mut self.menu,
ui,
"show agent delay",
@ -52,7 +53,7 @@ impl GameplayState for CreateGridlock {
if self.time != ui.primary.sim.time() {
self.time = ui.primary.sim.time();
self.menu.set_info(gridlock_panel(ui));
self.menu.set_info(ctx, gridlock_panel(ui));
}
None

View File

@ -45,7 +45,7 @@ impl GameplayState for FasterTrips {
if self.time != ui.primary.sim.time() {
self.time = ui.primary.sim.time();
self.menu.set_info(faster_trips_panel(self.mode, ui));
self.menu.set_info(ctx, faster_trips_panel(self.mode, ui));
}
None

View File

@ -63,7 +63,7 @@ impl GameplayState for Freeform {
for line in cnt.describe() {
txt.add(Line(line));
}
g.draw_mouse_tooltip(&txt);
g.draw_mouse_tooltip(txt);
}
}
}

View File

@ -196,6 +196,7 @@ impl GameplayMode {
// Must call menu.event first. Returns true if the caller should set the overlay to the custom
// thing.
fn manage_overlays(
ctx: &EventCtx,
menu: &mut ModalMenu,
ui: &mut UI,
show: &str,
@ -204,14 +205,14 @@ fn manage_overlays(
) -> bool {
// Synchronize menus if needed. Player can change these separately.
if active_originally {
menu.maybe_change_action(show, hide);
menu.maybe_change_action(ctx, show, hide);
} else {
menu.maybe_change_action(hide, show);
menu.maybe_change_action(ctx, hide, show);
}
if !active_originally && menu.swap_action(show, hide) {
if !active_originally && menu.swap_action(ctx, show, hide) {
true
} else if active_originally && menu.swap_action(hide, show) {
} else if active_originally && menu.swap_action(ctx, hide, show) {
ui.overlay = Overlays::Inactive;
false
} else {
@ -221,6 +222,7 @@ fn manage_overlays(
// Must call menu.event first.
fn manage_acs(
ctx: &EventCtx,
menu: &mut ModalMenu,
ui: &mut UI,
show: &str,
@ -231,14 +233,14 @@ fn manage_acs(
// Synchronize menus if needed. Player can change these separately.
if active_originally {
menu.maybe_change_action(show, hide);
menu.maybe_change_action(ctx, show, hide);
} else {
menu.maybe_change_action(hide, show);
menu.maybe_change_action(ctx, hide, show);
}
if !active_originally && menu.swap_action(show, hide) {
if !active_originally && menu.swap_action(ctx, show, hide) {
ui.agent_cs = AgentColorScheme::new(acs, &ui.cs);
} else if active_originally && menu.swap_action(hide, show) {
} else if active_originally && menu.swap_action(ctx, hide, show) {
ui.agent_cs = AgentColorScheme::default(&ui.cs);
}
}

View File

@ -58,6 +58,7 @@ impl GameplayState for OptimizeBus {
}
self.menu.event(ctx);
if manage_overlays(
ctx,
&mut self.menu,
ui,
"show bus route",
@ -70,6 +71,7 @@ impl GameplayState for OptimizeBus {
ui.overlay = Overlays::show_bus_route(self.route, ctx, ui);
}
if manage_overlays(
ctx,
&mut self.menu,
ui,
"show delays over time",
@ -82,6 +84,7 @@ impl GameplayState for OptimizeBus {
ui.overlay = Overlays::delays_over_time(self.route, ctx, ui);
}
if manage_overlays(
ctx,
&mut self.menu,
ui,
"show bus passengers",
@ -98,7 +101,7 @@ impl GameplayState for OptimizeBus {
if self.time != ui.primary.sim.time() {
self.time = ui.primary.sim.time();
self.menu
.set_info(bus_route_panel(self.route, self.stat, ui));
.set_info(ctx, bus_route_panel(self.route, self.stat, ui));
}
if self.menu.action("change statistic") {

View File

@ -359,7 +359,7 @@ impl State for TimeWarpScreen {
)));
txt.add(Line(format!("Press ESCAPE to stop now")));
g.draw_blocking_text(
&txt,
txt,
(HorizontalAlignment::Center, VerticalAlignment::Center),
);
}