mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
prepping for a caching layer by changing render API, plumbing ctx...
getting close
This commit is contained in:
parent
7c76f2d119
commit
3ff56f54cf
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -80,7 +80,7 @@ impl<T: Clone + Hash + Eq> Autocomplete<T> {
|
||||
}
|
||||
|
||||
g.draw_blocking_text(
|
||||
&txt,
|
||||
txt,
|
||||
(HorizontalAlignment::Center, VerticalAlignment::Center),
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 })))
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -244,7 +244,7 @@ impl CommonState {
|
||||
}
|
||||
|
||||
g.draw_blocking_text(
|
||||
&osd,
|
||||
osd,
|
||||
(HorizontalAlignment::FillScreen, VerticalAlignment::Bottom),
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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!(
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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") {
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user