mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 16:36:02 +03:00
move ownership of GlyphCache into Canvas, so calculating text dimensions can be done during event. Stick the glyphs behind a RefCell to avoid mutability creeping into canvas everywhere
This commit is contained in:
parent
671dad6b02
commit
62bdd92ac3
@ -3,7 +3,9 @@
|
||||
use crate::{text, GfxCtx, Text, UserInput};
|
||||
use geom::{Bounds, Pt2D};
|
||||
use graphics::Transformed;
|
||||
use opengl_graphics::{Filter, GlyphCache, TextureSettings};
|
||||
use piston::window::Size;
|
||||
use std::cell::RefCell;
|
||||
|
||||
const ZOOM_SPEED: f64 = 0.1;
|
||||
|
||||
@ -20,10 +22,24 @@ pub struct Canvas {
|
||||
left_mouse_drag_from: Option<(f64, f64)>,
|
||||
|
||||
pub window_size: Size,
|
||||
|
||||
glyphs: RefCell<GlyphCache<'static>>,
|
||||
}
|
||||
|
||||
impl Canvas {
|
||||
pub fn new() -> Canvas {
|
||||
let texture_settings = TextureSettings::new().filter(Filter::Nearest);
|
||||
// TODO We could also preload everything and not need the RefCell.
|
||||
let glyphs = RefCell::new(
|
||||
GlyphCache::new(
|
||||
// TODO don't assume this exists!
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
(),
|
||||
texture_settings,
|
||||
)
|
||||
.expect("Could not load font"),
|
||||
);
|
||||
|
||||
Canvas {
|
||||
cam_x: 0.0,
|
||||
cam_y: 0.0,
|
||||
@ -37,6 +53,8 @@ impl Canvas {
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
|
||||
glyphs,
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,20 +95,22 @@ impl Canvas {
|
||||
}
|
||||
|
||||
pub fn draw_mouse_tooltip(&self, g: &mut GfxCtx, txt: Text) {
|
||||
let (width, height) = txt.dims(g);
|
||||
let glyphs = &mut self.glyphs.borrow_mut();
|
||||
let (width, height) = txt.dims(glyphs);
|
||||
let x1 = self.cursor_x - (width / 2.0);
|
||||
let y1 = self.cursor_y - (height / 2.0);
|
||||
text::draw_text_bubble(g, (x1, y1), txt);
|
||||
text::draw_text_bubble(g, glyphs, (x1, y1), txt);
|
||||
}
|
||||
|
||||
pub fn draw_text_at(&self, g: &mut GfxCtx, txt: Text, pt: Pt2D) {
|
||||
let (width, height) = txt.dims(g);
|
||||
let glyphs = &mut self.glyphs.borrow_mut();
|
||||
let (width, height) = txt.dims(glyphs);
|
||||
let (x, y) = self.map_to_screen(pt);
|
||||
text::draw_text_bubble(g, (x - (width / 2.0), y - (height / 2.0)), txt);
|
||||
text::draw_text_bubble(g, glyphs, (x - (width / 2.0), y - (height / 2.0)), txt);
|
||||
}
|
||||
|
||||
pub fn draw_text_at_screenspace_topleft(&self, g: &mut GfxCtx, txt: Text, (x, y): (f64, f64)) {
|
||||
text::draw_text_bubble(g, (x, y), txt);
|
||||
text::draw_text_bubble(g, &mut self.glyphs.borrow_mut(), (x, y), txt);
|
||||
}
|
||||
|
||||
pub fn draw_text(
|
||||
@ -102,7 +122,8 @@ impl Canvas {
|
||||
if txt.is_empty() {
|
||||
return;
|
||||
}
|
||||
let (width, height) = txt.dims(g);
|
||||
let glyphs = &mut self.glyphs.borrow_mut();
|
||||
let (width, height) = txt.dims(glyphs);
|
||||
let x1 = match horiz {
|
||||
HorizontalAlignment::Left => 0.0,
|
||||
HorizontalAlignment::Center => (f64::from(self.window_size.width) - width) / 2.0,
|
||||
@ -113,7 +134,11 @@ impl Canvas {
|
||||
VerticalAlignment::Center => (f64::from(self.window_size.height) - height) / 2.0,
|
||||
VerticalAlignment::Bottom => f64::from(self.window_size.height) - height,
|
||||
};
|
||||
text::draw_text_bubble(g, (x1, y1), txt);
|
||||
text::draw_text_bubble(g, glyphs, (x1, y1), txt);
|
||||
}
|
||||
|
||||
pub(crate) fn text_dims(&self, txt: &Text) -> (f64, f64) {
|
||||
txt.dims(&mut self.glyphs.borrow_mut())
|
||||
}
|
||||
|
||||
fn zoom_towards_mouse(&mut self, delta_zoom: f64) {
|
||||
|
@ -343,7 +343,7 @@ pub(crate) struct ContextMenu {
|
||||
}
|
||||
|
||||
impl ContextMenu {
|
||||
pub(crate) fn calculate_geometry(&mut self, g: &mut GfxCtx, canvas: &Canvas) {
|
||||
pub(crate) fn calculate_geometry(&mut self, canvas: &mut Canvas) {
|
||||
if self.geometry.is_some() {
|
||||
return;
|
||||
}
|
||||
@ -352,7 +352,7 @@ impl ContextMenu {
|
||||
for (hotkey, action) in &self.actions {
|
||||
txt.add_line(format!("{} - {}", hotkey.describe(), action));
|
||||
}
|
||||
let (screen_width, screen_height) = txt.dims(g);
|
||||
let (screen_width, screen_height) = canvas.text_dims(&txt);
|
||||
let map_width = screen_width / canvas.cam_zoom;
|
||||
let map_height = screen_height / canvas.cam_zoom;
|
||||
let top_left = Pt2D::new(
|
||||
|
@ -25,27 +25,19 @@ pub use crate::text::{Text, TEXT_FG_COLOR};
|
||||
pub use crate::text_box::TextBox;
|
||||
pub use crate::wizard::{Wizard, WrappedWizard};
|
||||
use geom::Pt2D;
|
||||
use graphics::character::CharacterCache;
|
||||
use graphics::Transformed;
|
||||
use opengl_graphics::{GlGraphics, Texture};
|
||||
use opengl_graphics::GlGraphics;
|
||||
use std::mem;
|
||||
|
||||
//struct GfxCtx<'a, G: 'a + Graphics, C: 'a + CharacterCache<Texture = G::Texture>> {
|
||||
pub struct GfxCtx<'a> {
|
||||
glyphs: &'a mut CharacterCache<Texture = Texture, Error = String>,
|
||||
orig_ctx: graphics::Context,
|
||||
ctx: graphics::Context,
|
||||
gfx: &'a mut GlGraphics,
|
||||
}
|
||||
|
||||
impl<'a> GfxCtx<'a> {
|
||||
pub fn new(
|
||||
glyphs: &'a mut CharacterCache<Texture = Texture, Error = String>,
|
||||
g: &'a mut GlGraphics,
|
||||
c: graphics::Context,
|
||||
) -> GfxCtx<'a> {
|
||||
pub fn new(g: &'a mut GlGraphics, c: graphics::Context) -> GfxCtx<'a> {
|
||||
GfxCtx {
|
||||
glyphs,
|
||||
gfx: g,
|
||||
orig_ctx: c,
|
||||
ctx: c,
|
||||
|
@ -87,7 +87,7 @@ impl<T: Clone> Menu<T> {
|
||||
InputResult::StillActive
|
||||
}
|
||||
|
||||
pub(crate) fn calculate_geometry(&mut self, g: &mut GfxCtx, canvas: &Canvas) {
|
||||
pub(crate) fn calculate_geometry(&mut self, canvas: &mut Canvas) {
|
||||
if self.geometry.is_some() {
|
||||
return;
|
||||
}
|
||||
@ -97,7 +97,7 @@ impl<T: Clone> Menu<T> {
|
||||
for (hotkey, choice, _) in &self.choices {
|
||||
txt.add_line(format!("{} - {}", hotkey.describe(), choice));
|
||||
}
|
||||
let (screen_width, screen_height) = txt.dims(g);
|
||||
let (screen_width, screen_height) = canvas.text_dims(&txt);
|
||||
let map_width = screen_width / canvas.cam_zoom;
|
||||
let map_height = screen_height / canvas.cam_zoom;
|
||||
let top_left = Pt2D::new(
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::input::ContextMenu;
|
||||
use crate::{Canvas, Event, GfxCtx, UserInput};
|
||||
use glutin_window::GlutinWindow;
|
||||
use opengl_graphics::{Filter, GlGraphics, GlyphCache, OpenGL, TextureSettings};
|
||||
use opengl_graphics::{GlGraphics, OpenGL};
|
||||
use piston::event_loop::{EventLoop, EventSettings, Events};
|
||||
use piston::window::{Window, WindowSettings};
|
||||
use std::panic;
|
||||
@ -32,15 +32,6 @@ pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str, initial_width: u32, ini
|
||||
let mut events = Events::new(EventSettings::new().lazy(true));
|
||||
let mut gl = GlGraphics::new(opengl);
|
||||
|
||||
let texture_settings = TextureSettings::new().filter(Filter::Nearest);
|
||||
let mut glyphs = GlyphCache::new(
|
||||
// TODO don't assume this exists!
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
(),
|
||||
texture_settings,
|
||||
)
|
||||
.expect("Could not load font");
|
||||
|
||||
let mut last_event_mode = EventLoopMode::InputOnly;
|
||||
let mut context_menu: Option<ContextMenu> = None;
|
||||
let mut last_data: Option<T> = None;
|
||||
@ -50,7 +41,7 @@ pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str, initial_width: u32, ini
|
||||
// If the very first event is render, then just wait.
|
||||
if let Some(ref data) = last_data {
|
||||
gl.draw(args.viewport(), |c, g| {
|
||||
let mut g = GfxCtx::new(&mut glyphs, g, c);
|
||||
let mut g = GfxCtx::new(g, c);
|
||||
gui.get_mut_canvas()
|
||||
.start_drawing(&mut g, window.draw_size());
|
||||
|
||||
@ -63,9 +54,8 @@ pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str, initial_width: u32, ini
|
||||
|
||||
// Always draw the context-menu last.
|
||||
if let Some(ref mut menu) = context_menu {
|
||||
// TODO Weird to do this here (all to pass along &mut glyphs), but for the
|
||||
// moment, that's how Text::dims works. :\
|
||||
menu.calculate_geometry(&mut g, gui.get_mut_canvas());
|
||||
// TODO Can get rid of this weird method now!
|
||||
menu.calculate_geometry(gui.get_mut_canvas());
|
||||
menu.draw(&mut g, gui.get_mut_canvas());
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,9 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use crate::{Canvas, Color, GfxCtx};
|
||||
use graphics::character::CharacterCache;
|
||||
use graphics::{Image, Rectangle, Transformed};
|
||||
use opengl_graphics::GlyphCache;
|
||||
use textwrap;
|
||||
|
||||
pub const TEXT_FG_COLOR: Color = Color([0.0, 0.0, 0.0, 1.0]);
|
||||
@ -98,7 +100,7 @@ impl Text {
|
||||
self.lines.is_empty()
|
||||
}
|
||||
|
||||
pub fn dims(&self, g: &mut GfxCtx) -> (f64, f64) {
|
||||
pub(crate) fn dims(&self, glyphs: &mut GlyphCache) -> (f64, f64) {
|
||||
let longest_line = self
|
||||
.lines
|
||||
.iter()
|
||||
@ -108,14 +110,14 @@ impl Text {
|
||||
for span in longest_line {
|
||||
concat.push_str(&span.text);
|
||||
}
|
||||
let width = g.glyphs.width(FONT_SIZE, &concat).unwrap();
|
||||
let width = glyphs.width(FONT_SIZE, &concat).unwrap();
|
||||
let height = (self.lines.len() as f64) * LINE_HEIGHT;
|
||||
(width, height)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_text_bubble(g: &mut GfxCtx, (x1, y1): (f64, f64), txt: Text) {
|
||||
let (total_width, total_height) = txt.dims(g);
|
||||
pub fn draw_text_bubble(g: &mut GfxCtx, glyphs: &mut GlyphCache, (x1, y1): (f64, f64), txt: Text) {
|
||||
let (total_width, total_height) = txt.dims(glyphs);
|
||||
Rectangle::new(txt.bg_color.0).draw(
|
||||
[x1, y1, total_width, total_height],
|
||||
&g.orig_ctx.draw_state,
|
||||
@ -130,7 +132,7 @@ pub fn draw_text_bubble(g: &mut GfxCtx, (x1, y1): (f64, f64), txt: Text) {
|
||||
for span in line {
|
||||
if let Some(color) = span.highlight_color {
|
||||
// TODO do we ever want to use total_width?
|
||||
let width = g.glyphs.width(FONT_SIZE, &span.text).unwrap();
|
||||
let width = glyphs.width(FONT_SIZE, &span.text).unwrap();
|
||||
Rectangle::new(color.0).draw(
|
||||
[x, y - LINE_HEIGHT, width, LINE_HEIGHT],
|
||||
&g.orig_ctx.draw_state,
|
||||
@ -142,7 +144,7 @@ pub fn draw_text_bubble(g: &mut GfxCtx, (x1, y1): (f64, f64), txt: Text) {
|
||||
let fg_text = Image::new_color(span.fg_color.0);
|
||||
|
||||
for ch in span.text.chars() {
|
||||
if let Ok(draw_ch) = g.glyphs.character(FONT_SIZE, ch) {
|
||||
if let Ok(draw_ch) = glyphs.character(FONT_SIZE, ch) {
|
||||
let char_ctx = g
|
||||
.orig_ctx
|
||||
.transform
|
||||
|
Loading…
Reference in New Issue
Block a user