From 05a5fd91f0e522276477d436bc76d0fafb4ef2ba Mon Sep 17 00:00:00 2001 From: Adrien Burgun Date: Fri, 29 Jul 2022 16:33:16 +0200 Subject: [PATCH] :sparkles: Add variant tags --- species/blobfox/species.toml | 23 +++++++++++ src/main.rs | 6 +-- src/parse.rs | 23 ++++++----- src/template.rs | 79 +++++++++++++++++++++++------------- 4 files changed, 90 insertions(+), 41 deletions(-) diff --git a/species/blobfox/species.toml b/species/blobfox/species.toml index dc894a6..29ff199 100644 --- a/species/blobfox/species.toml +++ b/species/blobfox/species.toml @@ -1,2 +1,25 @@ # Add options in here as needs be name = "blobfox" + +[variants] +base = ["body-basic", "eyes-basic", "mouth-w"] +happy = ["body-basic", "eyes-happy", "mouth-w"] +evil = ["body-basic", "eyes-evil", "mouth-w"] +owo = ["body-basic", "ear-owo", "eyes-happy", "mouth-w"] + +"3c" = ["body-basic", "eyes-basic", "mouth-w", "hand-3c", "left-hand"] +"3c_evil" = ["body-basic", "eyes-evil", "mouth-w", "hand-3c", "left-hand"] + +boop = ["body-basic", "boop", "eyes-basic", "mouth-w"] +boop_aww = ["body-basic", "boop", "eyes-aww", "mouth-w"] +boop_owo = ["body-basic", "ear-owo", "boop", "eyes-owo", "mouth-w"] + +reach = ["body-basic", "eyes-basic", "mouth-w", "hands-reach", "left-hand", "right-hand"] +reach_aww = ["body-basic", "eyes-aww", "mouth-w", "hands-reach", "left-hand", "right-hand"] + +snug = ["body-snug", "eyes-happy", "tail"] +snug_aww = ["body-snug", "eyes-aww", "tail"] +snug_owo = ["body-snug", "ear-owo", "eyes-owo", "tail"] +snug_boop_owo = ["body-snug", "ear-owo", "eyes-owo", "tail", "boop"] + +stabby = ["body-basic", "prop", "eyes-evil", "mouth-w", "hand-3c", "left-hand"] diff --git a/src/main.rs b/src/main.rs index 9e1984a..06f9c67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ fn main() { let output_dir = args.output_dir.clone().unwrap_or(PathBuf::from("output/")); if args.names.is_empty() { - for name in context.species().variants.keys() { + for name in context.species().variant_paths.keys() { generate_variant(&context, name, &output_dir, &args); } } else { @@ -31,9 +31,9 @@ fn main() { } fn generate_variant(context: &RenderingContext, name: &str, output_dir: &PathBuf, args: &Args) { - if let Some(path) = context.species().variants.get(name) { + if let Some(path) = context.species().variant_paths.get(name) { match context.compile(path).and_then(|template| { - template.render_data_to_string(&context.get_data()) + template.render_data_to_string(&context.get_data(name)) }) { Ok(svg) => { match export( diff --git a/src/parse.rs b/src/parse.rs index 7370cbb..be125db 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -31,14 +31,17 @@ pub struct SpeciesDecl { /// The name of the species pub name: String, + #[serde(default)] + pub variants: HashMap>, + #[serde(skip)] - pub templates: HashMap, + pub template_paths: HashMap, #[serde(skip)] - pub variants: HashMap, + pub variant_paths: HashMap, #[serde(skip)] - pub assets: HashMap, + pub asset_paths: HashMap, } /// Loads the given file as an XML tree @@ -63,25 +66,25 @@ pub fn load_species(path: impl AsRef) -> Result { let path = path.as_ref().to_path_buf().join(base); let base = load_species(path)?; - res.templates = base.templates; - res.variants = base.variants; - res.assets = base.assets; + res.template_paths = base.template_paths; + res.variant_paths = base.variant_paths; + res.asset_paths = base.asset_paths; } - // Read the `templates` directory and populate the `templates` field; + // Read the `templates` directory and populate the `template_paths` field; // on error, ignore the directory. for (name, path) in read_dir_xml(path.as_ref().join("templates")) { - res.templates.insert(name, path); + res.template_paths.insert(name, path); } // Read the `variants` directory for (name, path) in read_dir_xml(path.as_ref().join("variants")) { - res.variants.insert(name, path); + res.variant_paths.insert(name, path); } // Read the `assets` directory for (name, path) in read_dir_xml(path.as_ref().join("assets")) { - res.assets.insert(name, path); + res.asset_paths.insert(name, path); } Ok(res) diff --git a/src/template.rs b/src/template.rs index e427eed..59d20fa 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,15 +1,9 @@ -use mustache::{ - Context, - PartialLoader, - Template, - MapBuilder, - Data, -}; use super::*; +use mustache::{Context, Data, MapBuilder, PartialLoader, Template}; use std::collections::HashMap; use std::path::Path; use std::sync::{Arc, Mutex}; -use xmltree::{XMLNode, Element}; +use xmltree::{Element, XMLNode}; #[derive(Debug, Clone)] pub struct RenderingContext { @@ -34,17 +28,21 @@ impl RenderingContext { Context::with_loader(self.clone()).compile(template.chars()) } - fn render_to_string(&self, string: &str) -> Result { + fn render_to_string( + &self, + string: &str, + variant_name: &str, + ) -> Result { Context::with_loader(self.clone()) .compile(string.chars())? - .render_data_to_string(&self.get_data()) + .render_data_to_string(&self.get_data(variant_name)) } - pub fn get_data(&self) -> Data { + pub fn get_data(&self, variant_name: &str) -> Data { let mut builder = MapBuilder::new(); builder = builder.insert_map("variant", |mut builder| { - for variant_name in self.species.variants.keys() { + for variant_name in self.species.variant_paths.keys() { let this = self.clone(); let variant_name = variant_name.to_string(); builder = builder.insert_fn(variant_name.clone(), move |selector| { @@ -52,7 +50,7 @@ impl RenderingContext { if let Some(svg) = svg { if let Some(element) = query_selector(svg, &selector) { if let Some(string) = xml_to_string(element) { - return string + return string; } } } @@ -63,7 +61,7 @@ impl RenderingContext { builder }); - for asset_name in self.species.assets.keys() { + for asset_name in self.species.asset_paths.keys() { let this = self.clone(); let asset_name = asset_name.to_string(); @@ -72,7 +70,7 @@ impl RenderingContext { if let Some(svg) = svg { if let Some(element) = query_selector(svg, &selector) { if let Some(string) = xml_to_string(element) { - return string + return string; } } } @@ -82,21 +80,24 @@ impl RenderingContext { } let this = self.clone(); + let variant_name_owned = variant_name.to_string(); builder = builder.insert_fn("set-fill", move |input| { // Parse `color|xml` if let [color, xml] = input.splitn(2, '|').collect::>()[..] { // Render `color` and `xml` - if let (Ok(color), Ok(xml)) = (this.render_to_string(&color), this.render_to_string(&xml)) { + if let (Ok(color), Ok(xml)) = ( + this.render_to_string(&color, &variant_name_owned), + this.render_to_string(&xml, &variant_name_owned), + ) { // Convert `xml` to XML match Element::parse(xml.as_bytes()) { Ok(mut xml) => { // Substitute the fill color if let Some(style) = xml.attributes.get("style") { - xml.attributes.insert("style".to_string(), format!( - "{};fill: {};", - style, - color - )); + xml.attributes.insert( + "style".to_string(), + format!("{};fill: {};", style, color), + ); } if let Some(_fill) = xml.attributes.get("fill") { xml.attributes.insert("fill".to_string(), color); @@ -121,6 +122,17 @@ impl RenderingContext { } }); + // Variant tags + if let Some(tags) = self.species.variants.get(variant_name) { + builder = builder.insert_map("tags", move |mut builder| { + for tag in tags.iter() { + builder = builder.insert_bool(tag, true); + } + + builder + }); + } + builder.build() } @@ -128,14 +140,17 @@ impl RenderingContext { let rendered = self.rendered_variants.lock().unwrap().get(name).cloned(); if let Some(rendered) = rendered { Some(rendered) - } else if let Some(path) = self.species.variants.get(name) { + } else if let Some(path) = self.species.variant_paths.get(name) { // TODO: log error let template = self.compile(path).ok()?; - let data = self.get_data(); + let data = self.get_data(name); let rendered = template.render_data_to_string(&data).ok()?; let parsed = Element::parse(rendered.as_bytes()).ok()?; - self.rendered_variants.lock().unwrap().insert(name.clone(), parsed.clone()); + self.rendered_variants + .lock() + .unwrap() + .insert(name.clone(), parsed.clone()); Some(parsed) } else { @@ -147,10 +162,13 @@ impl RenderingContext { let loaded = self.loaded_assets.lock().unwrap().get(name).cloned(); if let Some(loaded) = loaded { Some(loaded) - } else if let Some(path) = self.species.assets.get(name) { + } else if let Some(path) = self.species.asset_paths.get(name) { let string = std::fs::read_to_string(path).ok()?; let parsed = Element::parse(string.as_bytes()).ok()?; - self.loaded_assets.lock().unwrap().insert(name.clone(), parsed.clone()); + self.loaded_assets + .lock() + .unwrap() + .insert(name.clone(), parsed.clone()); Some(parsed) } else { @@ -167,7 +185,7 @@ impl PartialLoader for RenderingContext { fn load(&self, name: impl AsRef) -> Result { let name = name.as_ref().to_str().ok_or(mustache::Error::InvalidStr)?; - if let Some(path) = self.species.templates.get(name) { + if let Some(path) = self.species.template_paths.get(name) { Ok(std::fs::read_to_string(path)?) } else { eprintln!("No template named {}", name); @@ -184,7 +202,12 @@ pub fn query_selector(svg: Element, pattern: &str) -> Option { for child in svg.children { if let XMLNode::Element(child) = child { if let ("#", pattern_id) = pattern.split_at(1) { - if child.attributes.get("id").map(|id| id == pattern_id).unwrap_or(false) { + if child + .attributes + .get("id") + .map(|id| id == pattern_id) + .unwrap_or(false) + { return Some(child); } else if child.children.len() > 0 { if let Some(res) = query_selector(child, pattern) {