mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 02:33:54 +03:00
bake-in widgetry assets: image_path -> image_source::{Path, Bytes}
This commit is contained in:
parent
2505d64e8b
commit
4ee6564032
@ -271,7 +271,7 @@ pub fn bio(
|
||||
|
||||
let mut svg_data = Vec::new();
|
||||
svg_face::generate_face(&mut svg_data, &mut rng).unwrap();
|
||||
let batch = GeomBatch::from_svg_contents(svg_data).autocrop();
|
||||
let batch = GeomBatch::from_svg_contents(&svg_data).autocrop();
|
||||
let dims = batch.get_dims();
|
||||
let batch = batch.scale((200.0 / dims.width).min(200.0 / dims.height));
|
||||
rows.push(Widget::draw_batch(ctx, batch).centered_horiz());
|
||||
|
@ -142,7 +142,7 @@ impl<'a> EventCtx<'a> {
|
||||
Widget::custom_col(vec![
|
||||
Widget::draw_batch(
|
||||
self,
|
||||
GeomBatch::from_svg_contents(include_bytes!("../icons/loading.svg").to_vec())
|
||||
GeomBatch::from_svg_contents(&include_bytes!("../icons/loading.svg").to_vec())
|
||||
.scale(5.0),
|
||||
)
|
||||
.container()
|
||||
|
@ -136,9 +136,9 @@ impl GeomBatch {
|
||||
}
|
||||
|
||||
/// Returns a batch containing a parsed SVG string.
|
||||
pub fn from_svg_contents(raw: Vec<u8>) -> GeomBatch {
|
||||
pub fn from_svg_contents(raw: &[u8]) -> GeomBatch {
|
||||
let mut batch = GeomBatch::new();
|
||||
let svg_tree = usvg::Tree::from_data(&raw, &usvg::Options::default()).unwrap();
|
||||
let svg_tree = usvg::Tree::from_data(raw, &usvg::Options::default()).unwrap();
|
||||
svg::add_svg_inner(&mut batch, svg_tree, svg::HIGH_QUALITY).unwrap();
|
||||
batch
|
||||
}
|
||||
|
@ -15,21 +15,46 @@ pub const LOW_QUALITY: f32 = 1.0;
|
||||
// https://github.com/nical/lyon/blob/0d0ee771180fb317b986d9cf30266722e0773e01/examples/wgpu_svg/src/main.rs
|
||||
|
||||
pub fn load_svg(prerender: &Prerender, filename: &str) -> (GeomBatch, Bounds) {
|
||||
if let Some(pair) = prerender.assets.get_cached_svg(filename) {
|
||||
let cache_key = format!("file://{}", filename);
|
||||
if let Some(pair) = prerender.assets.get_cached_svg(&cache_key) {
|
||||
return pair;
|
||||
}
|
||||
|
||||
let raw = (prerender.assets.read_svg)(filename);
|
||||
let svg_tree = usvg::Tree::from_data(&raw, &usvg::Options::default()).unwrap();
|
||||
let mut batch = GeomBatch::new();
|
||||
match add_svg_inner(&mut batch, svg_tree, HIGH_QUALITY) {
|
||||
Ok(bounds) => {
|
||||
let bytes = (prerender.assets.read_svg)(filename);
|
||||
load_svg_from_bytes(&bytes)
|
||||
.map(|(batch, bounds)| {
|
||||
prerender
|
||||
.assets
|
||||
.cache_svg(filename.to_string(), batch.clone(), bounds.clone());
|
||||
.cache_svg(cache_key, batch.clone(), bounds.clone());
|
||||
(batch, bounds)
|
||||
}
|
||||
Err(err) => panic!("{}: {}", filename, err),
|
||||
})
|
||||
.expect(&format!("error loading svg: {}", filename))
|
||||
}
|
||||
|
||||
pub fn load_svg_bytes(
|
||||
prerender: &Prerender,
|
||||
bytes: &[u8],
|
||||
cache_key: &str,
|
||||
) -> anyhow::Result<(GeomBatch, Bounds)> {
|
||||
let cache_key = format!("bytes://{}", cache_key);
|
||||
if let Some(pair) = prerender.assets.get_cached_svg(&cache_key) {
|
||||
return Ok(pair);
|
||||
}
|
||||
|
||||
load_svg_from_bytes(&bytes).map(|(batch, bounds)| {
|
||||
prerender
|
||||
.assets
|
||||
.cache_svg(cache_key, batch.clone(), bounds.clone());
|
||||
(batch, bounds)
|
||||
})
|
||||
}
|
||||
|
||||
fn load_svg_from_bytes(bytes: &[u8]) -> anyhow::Result<(GeomBatch, Bounds)> {
|
||||
let svg_tree = usvg::Tree::from_data(&bytes, &usvg::Options::default()).unwrap();
|
||||
let mut batch = GeomBatch::new();
|
||||
match add_svg_inner(&mut batch, svg_tree, HIGH_QUALITY) {
|
||||
Ok(bounds) => Ok((batch, bounds)),
|
||||
Err(err) => Err(anyhow!(err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,11 +254,27 @@ impl<'b, 'a: 'b> ButtonBuilder<'a> {
|
||||
}
|
||||
|
||||
/// Set the image for the button. If not set, the button will have no image.
|
||||
///
|
||||
/// This will replace any image previously set by [`image_bytes`]
|
||||
pub fn image_path(mut self, path: &'a str) -> Self {
|
||||
// Currently we don't support setting image for other states like "hover", we easily
|
||||
// could, but the API gets more verbose for a thing we don't currently need.
|
||||
let mut image = self.default_style.image.take().unwrap_or_default();
|
||||
image.path = Some(path);
|
||||
image.source = Some(ImageSource::Path(path));
|
||||
self.default_style.image = Some(image);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the image for the button. If not set, the button will have no image.
|
||||
///
|
||||
/// This will replace any image previously set by [`image_path`].
|
||||
/// `bytes`: utf-8 encoded bytes of the svg
|
||||
/// `name`: a label to describe the bytes for debugging purposes
|
||||
pub fn image_bytes(mut self, bytes: &'a [u8], cache_key: &'a str) -> Self {
|
||||
// Currently we don't support setting image for other states like "hover", we easily
|
||||
// could, but the API gets more verbose for a thing we don't currently need.
|
||||
let mut image = self.default_style.image.take().unwrap_or_default();
|
||||
image.source = Some(ImageSource::Bytes { bytes, cache_key });
|
||||
self.default_style.image = Some(image);
|
||||
self
|
||||
}
|
||||
@ -496,12 +512,16 @@ impl<'b, 'a: 'b> ButtonBuilder<'a> {
|
||||
.or(default_style.image.as_ref())
|
||||
.and_then(|image| {
|
||||
let default = default_style.image.as_ref();
|
||||
let image_path = image.path.or(default.and_then(|d| d.path));
|
||||
if image_path.is_none() {
|
||||
let image_source = image
|
||||
.source
|
||||
.as_ref()
|
||||
.or(default.and_then(|d| d.source.as_ref()));
|
||||
if image_source.is_none() {
|
||||
return None;
|
||||
}
|
||||
let image_path = image_path.unwrap();
|
||||
let (mut svg_batch, svg_bounds) = svg::load_svg(ctx.prerender, image_path);
|
||||
let image_source = image_source.unwrap();
|
||||
|
||||
let (mut svg_batch, svg_bounds) = image_source.load(ctx.prerender);
|
||||
if let Some(color) = image.color.or(default.and_then(|d| d.color)) {
|
||||
svg_batch = svg_batch.color(color);
|
||||
}
|
||||
@ -623,9 +643,29 @@ impl<'b, 'a: 'b> ButtonBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum ImageSource<'a> {
|
||||
Path(&'a str),
|
||||
Bytes { bytes: &'a [u8], cache_key: &'a str },
|
||||
}
|
||||
|
||||
impl ImageSource<'_> {
|
||||
fn load(&self, prerender: &crate::Prerender) -> (GeomBatch, geom::Bounds) {
|
||||
match self {
|
||||
ImageSource::Path(image_path) => svg::load_svg(prerender, image_path),
|
||||
ImageSource::Bytes { bytes, cache_key } => {
|
||||
svg::load_svg_bytes(prerender, bytes, cache_key).expect(&format!(
|
||||
"Failed to load svg from bytes. cache_key: {}",
|
||||
cache_key
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Image<'a> {
|
||||
path: Option<&'a str>,
|
||||
source: Option<ImageSource<'a>>,
|
||||
color: Option<RewriteColor>,
|
||||
dims: Option<ScreenDims>,
|
||||
content_mode: ContentMode,
|
||||
|
@ -289,7 +289,7 @@ fn setup_scrollable_canvas(ctx: &mut EventCtx) -> Drawable {
|
||||
for i in 0..10 {
|
||||
let mut svg_data = Vec::new();
|
||||
svg_face::generate_face(&mut svg_data, &mut rng).unwrap();
|
||||
let face = GeomBatch::from_svg_contents(svg_data).autocrop();
|
||||
let face = GeomBatch::from_svg_contents(&svg_data).autocrop();
|
||||
let dims = face.get_dims();
|
||||
batch.append(
|
||||
face.scale((200.0 / dims.width).min(200.0 / dims.height))
|
||||
|
Loading…
Reference in New Issue
Block a user