mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
preps for variable font size
This commit is contained in:
parent
1aa1be6df2
commit
008b2f9de5
@ -245,7 +245,7 @@ pub struct DrawCtx<'a> {
|
||||
|
||||
fn styled_kv(txt: &mut Text, tags: &BTreeMap<String, String>) {
|
||||
for (k, v) in tags {
|
||||
txt.add_styled_line(k.to_string(), Some(Color::RED), None);
|
||||
txt.add_styled_line(k.to_string(), Some(Color::RED), None, None);
|
||||
txt.append(" = ".to_string(), None);
|
||||
txt.append(v.to_string(), Some(Color::CYAN));
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ fn panel(ctx: &mut PluginCtx) -> ShowScoreState {
|
||||
}
|
||||
|
||||
fn summarize(txt: &mut Text, summary: ScoreSummary) {
|
||||
txt.add_styled_line("Walking".to_string(), None, Some(Color::RED.alpha(0.8)));
|
||||
txt.add_styled_line("Walking".to_string(), None, Some(Color::RED.alpha(0.8)), None);
|
||||
txt.add_line(format!(
|
||||
" {}/{} trips done",
|
||||
(summary.total_walking_trips - summary.pending_walking_trips),
|
||||
@ -64,7 +64,7 @@ fn summarize(txt: &mut Text, summary: ScoreSummary) {
|
||||
));
|
||||
txt.add_line(format!(" {} total", summary.total_walking_trip_time));
|
||||
|
||||
txt.add_styled_line("Driving".to_string(), None, Some(Color::BLUE.alpha(0.8)));
|
||||
txt.add_styled_line("Driving".to_string(), None, Some(Color::BLUE.alpha(0.8)), None);
|
||||
txt.add_line(format!(
|
||||
" {}/{} trips done",
|
||||
(summary.total_driving_trips - summary.pending_driving_trips),
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::screen_geom::ScreenRectangle;
|
||||
use crate::{ScreenPt, Text, UserInput};
|
||||
use crate::{text, ScreenPt, Text, UserInput};
|
||||
use geom::{Bounds, Pt2D};
|
||||
use glium_glyph::glyph_brush::rusttype::Scale;
|
||||
use glium_glyph::GlyphBrush;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
const ZOOM_SPEED: f64 = 0.1;
|
||||
|
||||
@ -24,7 +26,7 @@ pub struct Canvas {
|
||||
pub window_height: f64,
|
||||
|
||||
pub(crate) glyphs: RefCell<GlyphBrush<'static, 'static>>,
|
||||
pub(crate) line_height: f64,
|
||||
line_height_per_font_size: RefCell<HashMap<usize, f64>>,
|
||||
|
||||
// TODO Bit weird and hacky to mutate inside of draw() calls.
|
||||
pub(crate) covered_areas: RefCell<Vec<ScreenRectangle>>,
|
||||
@ -35,7 +37,6 @@ impl Canvas {
|
||||
initial_width: f64,
|
||||
initial_height: f64,
|
||||
glyphs: GlyphBrush<'static, 'static>,
|
||||
line_height: f64,
|
||||
) -> Canvas {
|
||||
Canvas {
|
||||
cam_x: 0.0,
|
||||
@ -51,7 +52,7 @@ impl Canvas {
|
||||
window_height: initial_height,
|
||||
|
||||
glyphs: RefCell::new(glyphs),
|
||||
line_height,
|
||||
line_height_per_font_size: RefCell::new(HashMap::new()),
|
||||
covered_areas: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
@ -168,12 +169,25 @@ impl Canvas {
|
||||
// TODO Not super happy about exposing this; fork_screenspace for external callers should be
|
||||
// smarter.
|
||||
pub fn top_menu_height(&self) -> f64 {
|
||||
self.line_height
|
||||
self.line_height(text::FONT_SIZE)
|
||||
}
|
||||
|
||||
pub fn text_dims(&self, txt: &Text) -> (f64, f64) {
|
||||
txt.dims(self)
|
||||
}
|
||||
|
||||
// Don't call this while glyphs are mutably borrowed.
|
||||
pub(crate) fn line_height(&self, font_size: usize) -> f64 {
|
||||
let mut hash = self.line_height_per_font_size.borrow_mut();
|
||||
if hash.contains_key(&font_size) {
|
||||
return hash[&font_size];
|
||||
}
|
||||
let vmetrics = self.glyphs.borrow().fonts()[0].v_metrics(Scale::uniform(font_size as f32));
|
||||
// TODO This works for this font, but could be more paranoid with abs()
|
||||
let line_height = f64::from(vmetrics.ascent - vmetrics.descent + vmetrics.line_gap);
|
||||
hash.insert(font_size, line_height);
|
||||
line_height
|
||||
}
|
||||
}
|
||||
|
||||
pub enum HorizontalAlignment {
|
||||
|
@ -155,7 +155,7 @@ impl<'a> GfxCtx<'a> {
|
||||
};
|
||||
let y1 = match vert {
|
||||
VerticalAlignment::Top => 0.0,
|
||||
VerticalAlignment::BelowTopMenu => self.canvas.line_height,
|
||||
VerticalAlignment::BelowTopMenu => self.canvas.line_height(text::FONT_SIZE),
|
||||
VerticalAlignment::Center => (self.canvas.window_height - height) / 2.0,
|
||||
VerticalAlignment::Bottom => self.canvas.window_height - height,
|
||||
};
|
||||
|
@ -1,11 +1,10 @@
|
||||
use crate::input::{ContextMenu, ModalMenuState};
|
||||
use crate::{
|
||||
text, widgets, Canvas, Event, EventCtx, GfxCtx, HorizontalAlignment, ModalMenu, Prerender,
|
||||
Text, TopMenu, UserInput, VerticalAlignment,
|
||||
widgets, Canvas, Event, EventCtx, GfxCtx, HorizontalAlignment, ModalMenu, Prerender, Text,
|
||||
TopMenu, UserInput, VerticalAlignment,
|
||||
};
|
||||
use glium::glutin;
|
||||
use glium_glyph::glyph_brush::rusttype::Font;
|
||||
use glium_glyph::glyph_brush::rusttype::Scale;
|
||||
use glium_glyph::GlyphBrush;
|
||||
use std::cell::Cell;
|
||||
use std::time::{Duration, Instant};
|
||||
@ -211,13 +210,9 @@ pub fn run<G: GUI, F: FnOnce(&mut Canvas, &Prerender) -> G>(
|
||||
.unwrap();
|
||||
|
||||
let dejavu: &[u8] = include_bytes!("assets/DejaVuSans.ttf");
|
||||
let fonts = vec![Font::from_bytes(dejavu).unwrap()];
|
||||
let vmetrics = fonts[0].v_metrics(Scale::uniform(text::FONT_SIZE));
|
||||
// TODO This works for this font, but could be more paranoid with abs()
|
||||
let line_height = f64::from(vmetrics.ascent - vmetrics.descent + vmetrics.line_gap);
|
||||
let glyphs = GlyphBrush::new(&display, fonts);
|
||||
let glyphs = GlyphBrush::new(&display, vec![Font::from_bytes(dejavu).unwrap()]);
|
||||
|
||||
let mut canvas = Canvas::new(initial_width, initial_height, glyphs, line_height);
|
||||
let mut canvas = Canvas::new(initial_width, initial_height, glyphs);
|
||||
let prerender = Prerender {
|
||||
display: &display,
|
||||
num_uploads: Cell::new(0),
|
||||
|
@ -13,7 +13,7 @@ pub const SELECTED_COLOR: Color = Color::RED;
|
||||
pub const HOTKEY_COLOR: Color = Color::GREEN;
|
||||
pub const INACTIVE_CHOICE_COLOR: Color = Color::grey(0.4);
|
||||
|
||||
pub const FONT_SIZE: f32 = 30.0;
|
||||
pub const FONT_SIZE: usize = 30;
|
||||
// TODO Don't do this!
|
||||
const MAX_CHAR_WIDTH: f64 = 25.0;
|
||||
|
||||
@ -21,7 +21,8 @@ const MAX_CHAR_WIDTH: f64 = 25.0;
|
||||
struct TextSpan {
|
||||
text: String,
|
||||
fg_color: Color,
|
||||
// TODO bold, italic, font size, font style
|
||||
size: usize,
|
||||
// TODO bold, italic, font style
|
||||
}
|
||||
|
||||
impl TextSpan {
|
||||
@ -29,6 +30,7 @@ impl TextSpan {
|
||||
TextSpan {
|
||||
text,
|
||||
fg_color: FG_COLOR,
|
||||
size: FONT_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,12 +87,14 @@ impl Text {
|
||||
line: String,
|
||||
fg_color: Option<Color>,
|
||||
highlight_color: Option<Color>,
|
||||
font_size: Option<usize>,
|
||||
) {
|
||||
self.lines.push((
|
||||
highlight_color,
|
||||
vec![TextSpan {
|
||||
text: line,
|
||||
fg_color: fg_color.unwrap_or(FG_COLOR),
|
||||
size: font_size.unwrap_or(FONT_SIZE),
|
||||
}],
|
||||
));
|
||||
}
|
||||
@ -103,6 +107,7 @@ impl Text {
|
||||
self.lines.last_mut().unwrap().1.push(TextSpan {
|
||||
text,
|
||||
fg_color: fg_color.unwrap_or(FG_COLOR),
|
||||
size: FONT_SIZE,
|
||||
});
|
||||
}
|
||||
|
||||
@ -115,6 +120,9 @@ impl Text {
|
||||
}
|
||||
|
||||
pub(crate) fn dims(&self, canvas: &Canvas) -> (f64, f64) {
|
||||
// Always use the max height, since other stuff like menus assume a fixed height.
|
||||
let height = (self.lines.len() as f64) * canvas.line_height(FONT_SIZE);
|
||||
|
||||
let mut glyphs = canvas.glyphs.borrow_mut();
|
||||
let width = f64::from(
|
||||
self.lines
|
||||
@ -128,7 +136,7 @@ impl Text {
|
||||
glyphs
|
||||
.pixel_bounds(Section {
|
||||
text: &full_line,
|
||||
scale: Scale::uniform(FONT_SIZE),
|
||||
scale: Scale::uniform(FONT_SIZE as f32),
|
||||
..Section::default()
|
||||
})
|
||||
.map(|rect| rect.width())
|
||||
@ -138,8 +146,7 @@ impl Text {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Always use the max height, since other stuff like menus assume a fixed height.
|
||||
(width, (self.lines.len() as f64) * canvas.line_height)
|
||||
(width, height)
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +171,6 @@ pub fn draw_text_bubble(
|
||||
);
|
||||
}
|
||||
|
||||
let mut glyphs = g.canvas.glyphs.borrow_mut();
|
||||
let mut y = top_left.y;
|
||||
for (line_color, line) in &txt.lines {
|
||||
let section = VariedSection {
|
||||
@ -174,7 +180,7 @@ pub fn draw_text_bubble(
|
||||
.map(|span| SectionText {
|
||||
text: &span.text,
|
||||
color: span.fg_color.0,
|
||||
scale: Scale::uniform(FONT_SIZE),
|
||||
scale: Scale::uniform(FONT_SIZE as f32),
|
||||
..SectionText::default()
|
||||
})
|
||||
.collect(),
|
||||
@ -187,13 +193,13 @@ pub fn draw_text_bubble(
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(top_left.x, y),
|
||||
total_width,
|
||||
g.canvas.line_height,
|
||||
g.canvas.line_height(FONT_SIZE),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
y += g.canvas.line_height;
|
||||
glyphs.queue(section);
|
||||
y += g.canvas.line_height(FONT_SIZE);
|
||||
g.canvas.glyphs.borrow_mut().queue(section);
|
||||
}
|
||||
|
||||
g.unfork();
|
||||
|
@ -8,7 +8,7 @@ pub struct LogScroller {
|
||||
impl LogScroller {
|
||||
pub fn new(title: String, lines: Vec<String>) -> LogScroller {
|
||||
let mut text = Text::new();
|
||||
text.add_styled_line(title, None, Some(text::PROMPT_COLOR));
|
||||
text.add_styled_line(title, None, Some(text::PROMPT_COLOR), Some(50));
|
||||
for line in lines {
|
||||
text.add_line(line);
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ impl<T: Clone> Menu<T> {
|
||||
} else {
|
||||
total_width
|
||||
};
|
||||
ScreenPt::new(canvas.window_width - w, canvas.line_height)
|
||||
ScreenPt::new(canvas.window_width - w, canvas.line_height(text::FONT_SIZE))
|
||||
}
|
||||
};
|
||||
|
||||
@ -197,7 +197,7 @@ impl<T: Clone> Menu<T> {
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
let mut txt = Text::new();
|
||||
if let Some(ref line) = self.prompt {
|
||||
txt.add_styled_line(line.to_string(), None, Some(text::PROMPT_COLOR));
|
||||
txt.add_styled_line(line.to_string(), None, Some(text::PROMPT_COLOR), None);
|
||||
}
|
||||
for (idx, (hotkey, choice, active, _)) in self.choices.iter().enumerate() {
|
||||
let bg = if Some(idx) == self.current_idx {
|
||||
@ -207,10 +207,10 @@ impl<T: Clone> Menu<T> {
|
||||
};
|
||||
if *active {
|
||||
if let Some(key) = hotkey {
|
||||
txt.add_styled_line(key.describe(), Some(text::HOTKEY_COLOR), bg);
|
||||
txt.add_styled_line(key.describe(), Some(text::HOTKEY_COLOR), bg, None);
|
||||
txt.append(format!(" - {}", choice), None);
|
||||
} else {
|
||||
txt.add_styled_line(choice.to_string(), None, bg);
|
||||
txt.add_styled_line(choice.to_string(), None, bg, None);
|
||||
}
|
||||
} else {
|
||||
if let Some(key) = hotkey {
|
||||
@ -218,9 +218,10 @@ impl<T: Clone> Menu<T> {
|
||||
format!("{} - {}", key.describe(), choice),
|
||||
Some(text::INACTIVE_CHOICE_COLOR),
|
||||
bg,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
txt.add_styled_line(choice.to_string(), Some(text::INACTIVE_CHOICE_COLOR), bg);
|
||||
txt.add_styled_line(choice.to_string(), Some(text::INACTIVE_CHOICE_COLOR), bg, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ impl<T: Clone> ScrollingMenu<T> {
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
let mut txt = Text::new();
|
||||
txt.add_styled_line(self.prompt.clone(), None, Some(text::PROMPT_COLOR));
|
||||
txt.add_styled_line(self.prompt.clone(), None, Some(text::PROMPT_COLOR), None);
|
||||
|
||||
// TODO Silly results from doing this:
|
||||
// - The menu width changes as we scroll
|
||||
@ -59,7 +59,10 @@ impl<T: Clone> ScrollingMenu<T> {
|
||||
let can_fit = {
|
||||
// Subtract 1 for the prompt, and an additional TODO hacky
|
||||
// few to avoid the bottom OSD and stuff.
|
||||
let n = (g.canvas.window_height / g.canvas.line_height).floor() as isize - 1 - 6;
|
||||
let n = (g.canvas.window_height / g.canvas.line_height(text::FONT_SIZE)).floor()
|
||||
as isize
|
||||
- 1
|
||||
- 6;
|
||||
if n <= 0 {
|
||||
// Weird small window, just display the prompt and bail out.
|
||||
g.draw_blocking_text(&txt, CENTERED);
|
||||
@ -84,7 +87,7 @@ impl<T: Clone> ScrollingMenu<T> {
|
||||
continue;
|
||||
}
|
||||
if self.current_idx == idx {
|
||||
txt.add_styled_line(line.clone(), None, Some(text::SELECTED_COLOR));
|
||||
txt.add_styled_line(line.clone(), None, Some(text::SELECTED_COLOR), None);
|
||||
} else {
|
||||
txt.add_line(line.clone());
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl TextBox {
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
let mut txt = Text::new();
|
||||
txt.add_styled_line(self.prompt.clone(), None, Some(text::PROMPT_COLOR));
|
||||
txt.add_styled_line(self.prompt.clone(), None, Some(text::PROMPT_COLOR), None);
|
||||
|
||||
txt.add_line(self.line[0..self.cursor_x].to_string());
|
||||
if self.cursor_x < self.line.len() {
|
||||
|
@ -126,7 +126,7 @@ impl TopMenu {
|
||||
x1: 0.0,
|
||||
y1: 0.0,
|
||||
x2: g.canvas.window_width,
|
||||
y2: g.canvas.line_height,
|
||||
y2: g.canvas.line_height(text::FONT_SIZE),
|
||||
});
|
||||
|
||||
g.fork_screenspace();
|
||||
@ -135,7 +135,7 @@ impl TopMenu {
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(0.0, 0.0),
|
||||
g.canvas.window_width,
|
||||
g.canvas.line_height,
|
||||
g.canvas.line_height(text::FONT_SIZE),
|
||||
),
|
||||
);
|
||||
g.unfork();
|
||||
|
Loading…
Reference in New Issue
Block a user