actually, i don't need to support changing font or size mid-line yet. simplifies some info panel code.

This commit is contained in:
Dustin Carlino 2020-04-03 14:26:17 -07:00
parent 24acb27934
commit e0acc4973b
5 changed files with 79 additions and 70 deletions

View File

@ -29,7 +29,7 @@ impl Assets {
text_opts: Options::default(),
};
*a.default_line_height.borrow_mut() =
a.line_height(Font::OverpassRegular, *a.default_font_size.borrow());
a.line_height(text::DEFAULT_FONT, *a.default_font_size.borrow());
a.text_opts.font_directories.push(font_dir);
a
}
@ -92,6 +92,6 @@ impl Assets {
self.line_height_cache.borrow_mut().clear();
self.svg_cache.borrow_mut().clear();
*self.default_line_height.borrow_mut() =
self.line_height(Font::OverpassRegular, *self.default_font_size.borrow());
self.line_height(text::DEFAULT_FONT, *self.default_font_size.borrow());
}
}

View File

@ -1,6 +1,6 @@
use crate::assets::Assets;
use crate::tools::screenshot::{screenshot_current, screenshot_everything};
use crate::{Canvas, Event, EventCtx, GfxCtx, Key, Prerender, UserInput};
use crate::{text, Canvas, Event, EventCtx, GfxCtx, Key, Prerender, UserInput};
use geom::Duration;
use instant::Instant;
use std::cell::Cell;
@ -169,7 +169,7 @@ impl Settings {
window_title: window_title.to_string(),
font_dir: font_dir.to_string(),
profiling_enabled: false,
default_font_size: 21,
default_font_size: text::DEFAULT_FONT_SIZE,
dump_raw_events: false,
scale_factor: 1.0,
}

View File

@ -8,7 +8,11 @@ use std::fmt::Write;
use std::hash::Hasher;
use textwrap;
const FG_COLOR: Color = Color::WHITE;
// Same as body()
pub const DEFAULT_FONT: Font = Font::OverpassRegular;
pub const DEFAULT_FONT_SIZE: usize = 21;
const DEFAULT_FG_COLOR: Color = Color::WHITE;
pub const BG_COLOR: Color = Color::grey(0.3);
pub const SELECTED_COLOR: Color = Color::grey(0.5);
pub const HOTKEY_COLOR: Color = Color::GREEN;
@ -31,13 +35,13 @@ pub enum Font {
pub struct TextSpan {
text: String,
fg_color: Color,
size: Option<usize>,
size: usize,
font: Font,
}
impl TextSpan {
pub fn fg(mut self, color: Color) -> TextSpan {
assert_eq!(self.fg_color, FG_COLOR);
assert_eq!(self.fg_color, DEFAULT_FG_COLOR);
self.fg_color = color;
self
}
@ -50,39 +54,39 @@ impl TextSpan {
pub fn display_title(mut self) -> TextSpan {
self.font = Font::BungeeInlineRegular;
self.size = Some(64);
self.size = 64;
self
}
pub fn big_heading_styled(mut self) -> TextSpan {
self.font = Font::BungeeRegular;
self.size = Some(32);
self.size = 32;
self
}
pub fn big_heading_plain(mut self) -> TextSpan {
self.font = Font::OverpassBold;
self.size = Some(32);
self.size = 32;
self
}
pub fn small_heading(mut self) -> TextSpan {
self.font = Font::OverpassSemiBold;
self.size = Some(26);
self.size = 26;
self
}
// The default
pub fn body(mut self) -> TextSpan {
self.font = Font::OverpassRegular;
self.size = Some(21);
self.size = 21;
self
}
pub fn secondary(mut self) -> TextSpan {
self.font = Font::OverpassRegular;
self.size = Some(21);
self.size = 21;
self.fg_color = Color::hex("#A3A3A3");
self
}
pub fn small(mut self) -> TextSpan {
self.font = Font::OverpassRegular;
self.size = Some(16);
self.size = 16;
self
}
}
@ -92,9 +96,9 @@ impl TextSpan {
pub fn Line<S: Into<String>>(text: S) -> TextSpan {
TextSpan {
text: text.into(),
fg_color: FG_COLOR,
size: None,
font: Font::OverpassRegular,
fg_color: DEFAULT_FG_COLOR,
size: DEFAULT_FONT_SIZE,
font: DEFAULT_FONT,
}
}
@ -120,6 +124,14 @@ impl Text {
txt
}
pub fn from_all(lines: Vec<TextSpan>) -> Text {
let mut txt = Text::new();
for l in lines {
txt.append(l);
}
txt
}
// TODO Remove this
pub fn with_bg(mut self) -> Text {
assert!(self.bg_color.is_none());
@ -136,9 +148,10 @@ impl Text {
// TODO Not exactly sure this is the right place for this, but better than code duplication
pub fn tooltip(hotkey: Option<MultiKey>, action: &str) -> Text {
if let Some(ref key) = hotkey {
let mut txt = Text::from(Line(key.describe()).fg(HOTKEY_COLOR).small());
txt.append(Line(format!(" - {}", action)));
txt
Text::from_all(vec![
Line(key.describe()).fg(HOTKEY_COLOR).small(),
Line(format!(" - {}", action)).small(),
])
} else {
Text::from(Line(action).small())
}
@ -166,22 +179,16 @@ impl Text {
self.lines.last_mut().unwrap().0 = Some(highlight);
}
pub fn append(&mut self, mut line: TextSpan) {
pub fn append(&mut self, line: TextSpan) {
if self.lines.is_empty() {
self.add(line);
return;
}
// Can't override the size mid-line.
assert_eq!(line.size, None);
line.size = self
.lines
.last()
.unwrap()
.1
.last()
.map(|span| span.size)
.unwrap();
// Can't override the size or font mid-line.
let last = self.lines.last().unwrap().1.last().unwrap();
assert_eq!(line.size, last.size);
assert_eq!(line.font, last.font);
self.lines.last_mut().unwrap().1.push(line);
}
@ -203,6 +210,7 @@ impl Text {
}
}
// TODO Not at all correct!
pub fn add_wrapped(&mut self, line: String, width: f64) {
let wrap_to = width / MAX_CHAR_WIDTH;
for l in textwrap::wrap(&line, wrap_to as usize).into_iter() {
@ -247,10 +255,7 @@ impl Text {
for (line_color, line) in self.lines {
// Assume size doesn't change mid-line. Always use this fixed line height per font
// size.
let line_height = assets.line_height(
line[0].font,
line[0].size.unwrap_or(*assets.default_font_size.borrow()),
);
let line_height = assets.line_height(line[0].font, line[0].size);
let line_batch = render_text(line, tolerance, assets);
let line_dims = if line_batch.is_empty() {
@ -311,11 +316,15 @@ impl Text {
fn render_text(spans: Vec<TextSpan>, tolerance: f32, assets: &Assets) -> GeomBatch {
// TODO This assumes size and font don't change mid-line. We might be able to support that now,
// actually.
// https://www.oreilly.com/library/view/svg-text-layout/9781491933817/ch04.html
// Just set a sufficiently large view box
let mut svg = format!(
r##"<svg width="9999" height="9999" viewBox="0 0 9999 9999" xmlns="http://www.w3.org/2000/svg"><text x="0" y="0" font-size="{}" {}>"##,
spans[0].size.unwrap_or(*assets.default_font_size.borrow()),
let mut svg = r##"<svg width="9999" height="9999" viewBox="0 0 9999 9999" xmlns="http://www.w3.org/2000/svg">"##.to_string();
write!(
&mut svg,
r##"<text x="0" y="0" font-size="{}" {}>"##,
spans[0].size,
match spans[0].font {
Font::BungeeInlineRegular => "font-family=\"Bungee Inline\"",
Font::BungeeRegular => "font-family=\"Bungee\"",
@ -323,7 +332,8 @@ fn render_text(spans: Vec<TextSpan>, tolerance: f32, assets: &Assets) -> GeomBat
Font::OverpassRegular => "font-family=\"Overpass\"",
Font::OverpassSemiBold => "font-family=\"Overpass\" font-weight=\"600\"",
}
);
)
.unwrap();
let mut contents = String::new();
for span in spans {
@ -338,8 +348,6 @@ fn render_text(spans: Vec<TextSpan>, tolerance: f32, assets: &Assets) -> GeomBat
}
write!(&mut svg, "{}</text></svg>", contents).unwrap();
//println!("- Rendering: {}", contents);
let svg_tree = match usvg::Tree::from_str(&svg, &assets.text_opts) {
Ok(t) => t,
Err(err) => panic!("render_text({}): {}", contents, err),

View File

@ -2,7 +2,7 @@ use crate::app::App;
use crate::colors;
use crate::info::{building, header_btns, make_table, make_tabs, trip, Details, Tab};
use crate::render::Renderable;
use ezgui::{hotkey, Btn, Color, EventCtx, Key, Line, RewriteColor, TextExt, Widget};
use ezgui::{hotkey, Btn, Color, EventCtx, Key, Line, RewriteColor, Text, TextExt, Widget};
use map_model::Map;
use maplit::btreeset;
use sim::{
@ -60,8 +60,11 @@ pub fn trips(
// TODO Style wrong. Button should be the entire row.
rows.push(
Widget::row(vec![
t.to_string().draw_text(ctx),
Line(trip_mode.ongoing_verb()).secondary().draw(ctx),
Text::from_all(vec![
Line(format!("{} ", t)),
Line(trip_mode.ongoing_verb()).secondary(),
])
.draw(ctx),
if trip_status == "ongoing" {
// TODO Padding doesn't work without wrapping in a row
Widget::row(vec![Line(trip_status)

View File

@ -56,30 +56,28 @@ pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Detail
},
};
// TODO Can we change font mid line please?
col.push(Widget::row(vec![
Widget::row(vec![Line("Trip time").secondary().draw(ctx)]).force_width(ctx, col_width),
props.total_time.to_string().draw_text(ctx),
Line(format!("{} / {} this trip", activity, total_trip_time))
.secondary()
.draw(ctx),
Text::from_all(vec![
Line(props.total_time.to_string()),
Line(format!(" {} / {} this trip", activity, total_trip_time)).secondary(),
])
.draw(ctx),
]));
col.push(Widget::row(vec![
Widget::row(vec![Line("Distance").secondary().draw(ctx)]).force_width(ctx, col_width),
Widget::col(vec![
Widget::row(vec![
props.dist_crossed.describe_rounded().draw_text(ctx),
Line(format!("/{}", props.total_dist.describe_rounded()))
.secondary()
.draw(ctx),
]),
Widget::row(vec![
format!("{} lanes", props.lanes_crossed).draw_text(ctx),
Line(format!("/{}", props.total_lanes))
.secondary()
.draw(ctx),
]),
Text::from_all(vec![
Line(props.dist_crossed.describe_rounded()),
Line(format!("/{}", props.total_dist.describe_rounded())).secondary(),
])
.draw(ctx),
Text::from_all(vec![
Line(format!("{} lanes", props.lanes_crossed)),
Line(format!("/{}", props.total_lanes)).secondary(),
])
.draw(ctx),
]),
]));
@ -87,18 +85,18 @@ pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Detail
Widget::row(vec![Line("Waiting").secondary().draw(ctx)]).force_width(ctx, col_width),
Widget::col(vec![
format!("{} here", props.waiting_here).draw_text(ctx),
Widget::row(vec![
(if props.total_waiting != Duration::ZERO {
format!(
Text::from_all(vec![
if props.total_waiting != Duration::ZERO {
Line(format!(
"{}%",
(100.0 * (props.waiting_here / props.total_waiting)) as usize
)
))
} else {
"0%".to_string()
})
.draw_text(ctx),
Line(format!(" of {} time", activity)).secondary().draw(ctx),
]),
Line("0%")
},
Line(format!(" of {} time", activity)).secondary(),
])
.draw(ctx),
]),
]));