mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 08:24:15 +03:00
actually, i don't need to support changing font or size mid-line yet. simplifies some info panel code.
This commit is contained in:
parent
24acb27934
commit
e0acc4973b
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
]),
|
||||
]));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user