parent
6596e715b1
commit
b1665c6280
@ -0,0 +1,117 @@
|
||||
use super::{AssetDecl, Variant};
|
||||
|
||||
use xmltree::{XMLNode, Element};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Emote {
|
||||
pub assets: HashMap<String, Asset>,
|
||||
|
||||
// TODO: metadata (contributors, etc.)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Asset {
|
||||
element: Element,
|
||||
}
|
||||
|
||||
impl Emote {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
assets: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_decl(variant_decl: Variant, emotes: &HashMap<String, Emote>) -> Option<Self> {
|
||||
// Load base or src
|
||||
let mut res = if let Some(src) = variant_decl.src {
|
||||
let file = File::open(src).ok()?;
|
||||
let xml = Element::parse(file).ok()?;
|
||||
Self::from_xml(xml)?
|
||||
} else if let Some(base) = variant_decl.base {
|
||||
emotes.get(&base)?.clone()
|
||||
} else {
|
||||
Emote::empty()
|
||||
};
|
||||
|
||||
// Load individual assets
|
||||
for asset_decl in variant_decl.assets {
|
||||
let name = asset_decl.name.clone();
|
||||
res.assets.insert(name, Asset::from_decl(asset_decl)?);
|
||||
}
|
||||
|
||||
// Apply overwrites (TODO)
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
||||
/// Loads an emote from an svg file.
|
||||
/// Top-level `<g>` elements are ignored
|
||||
pub fn from_xml(root: Element) -> Option<Self> {
|
||||
let iter = root.children.into_iter()
|
||||
.map(|elem| -> Box<dyn Iterator<Item=XMLNode>> {
|
||||
if let XMLNode::Element(elem2) = elem {
|
||||
if elem2.name == "g" {
|
||||
Box::new(elem2.children.into_iter())
|
||||
} else {
|
||||
Box::new(Some(XMLNode::Element(elem2)).into_iter())
|
||||
}
|
||||
} else {
|
||||
Box::new(None.into_iter())
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.filter_map(|elem| {
|
||||
match elem {
|
||||
XMLNode::Element(elem) => Some(elem),
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
.filter(filter_drawable);
|
||||
|
||||
let mut assets = HashMap::new();
|
||||
|
||||
for elem in iter {
|
||||
if let Some(name) = elem.attributes.get("label").or(elem.attributes.get("id")).cloned() {
|
||||
let asset = Asset::new(elem);
|
||||
assets.insert(name, asset);
|
||||
}
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
assets
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Asset {
|
||||
pub fn new(element: Element) -> Self {
|
||||
Self {
|
||||
element
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: allow loading assets from other variants (requires a more thorough dependency management)
|
||||
// TODO: allow searching for a specific element
|
||||
pub fn from_decl(declaration: AssetDecl) -> Option<Self> {
|
||||
let mut element = if let Some(src) = declaration.src {
|
||||
let file = File::open(src).ok()?;
|
||||
Element::parse(file).ok()?
|
||||
} else {
|
||||
unimplemented!()
|
||||
};
|
||||
|
||||
Some(Self {
|
||||
element
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This isn't really viable,
|
||||
fn filter_drawable(elem: &Element) -> bool {
|
||||
match elem.name.as_str() {
|
||||
"title" | "sodipodi:namedview" | "image" | "metadata" => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
Loading…
Reference in new issue