Compare commits
7 Commits
main
...
feat/autom
Author | SHA1 | Date |
---|---|---|
Shad Amethyst | b1665c6280 | 2 years ago |
Shad Amethyst | 6596e715b1 | 2 years ago |
ENDERZOMBI102 | f6de883236 | 2 years ago |
ENDERZOMBI102 | 972a5f43bd | 2 years ago |
ENDERZOMBI102 | cc121610d5 | 2 years ago |
ENDERZOMBI102 | 74a88cf3af | 2 years ago |
ENDERZOMBI102 | e524e1cbbf | 2 years ago |
@ -1,2 +1,4 @@
|
|||||||
original/
|
original/
|
||||||
output/
|
output/
|
||||||
|
__pycache__
|
||||||
|
target
|
||||||
|
@ -0,0 +1,309 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blobfox"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
|
"xmltree",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "3.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54635806b078b7925d6e36810b1755f2a4b5b4d57560432c1ecf60bcbe10602b"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"clap_derive",
|
||||||
|
"clap_lex",
|
||||||
|
"indexmap",
|
||||||
|
"once_cell",
|
||||||
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
"textwrap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "3.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.126"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.140"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.8.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xml-rs"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xmltree"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
|
||||||
|
dependencies = [
|
||||||
|
"xml-rs",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "blobfox"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
xmltree = "0.10"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_yaml = "0.8"
|
||||||
|
clap = { version = "3.2.14", features = ["derive"] }
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,16 @@
|
|||||||
|
name: 'blobfox'
|
||||||
|
base_off: null
|
||||||
|
variants:
|
||||||
|
'base':
|
||||||
|
src: '../../vector/blobfox.svg'
|
||||||
|
|
||||||
|
'boop':
|
||||||
|
assets:
|
||||||
|
- type: svg
|
||||||
|
name: 'lgbtq_heart'
|
||||||
|
src: 'assets/lgbtq_heart.svg'
|
||||||
|
|
||||||
|
overwrites:
|
||||||
|
- id: 'eye-left'
|
||||||
|
fill: 0xffffffff
|
||||||
|
remove: true
|
@ -0,0 +1,14 @@
|
|||||||
|
name: 'neugeme'
|
||||||
|
base: 'blobfox.yml' # all variants from 'blobfox' will be imported in this unit, unless they are already present
|
||||||
|
variants:
|
||||||
|
'base':
|
||||||
|
overwrites:
|
||||||
|
- id: 'body'
|
||||||
|
fill: 0x02FFFD
|
||||||
|
- id: 'hair'
|
||||||
|
fill: 0x02FFFD
|
||||||
|
- id: 'blobfox'
|
||||||
|
remove: true
|
||||||
|
|
||||||
|
'sleepy':
|
||||||
|
base: 'base'
|
@ -0,0 +1,108 @@
|
|||||||
|
use std::path::{PathBuf, Path};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct Declaration {
|
||||||
|
pub name: String,
|
||||||
|
pub base: Option<String>,
|
||||||
|
pub variants: HashMap<String, Variant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct Variant {
|
||||||
|
pub base: Option<String>,
|
||||||
|
|
||||||
|
pub src: Option<PathBuf>, // Loads every asset from an SVG file
|
||||||
|
#[serde(default)]
|
||||||
|
pub assets: Vec<AssetDecl>, // Loads individual assets
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub overwrites: Vec<Overwrite>, // Operations on assets
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct AssetDecl {
|
||||||
|
pub name: String,
|
||||||
|
pub src: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct Overwrite {
|
||||||
|
pub id: String, // ID of the element to modify
|
||||||
|
|
||||||
|
pub fill: Option<u32>,
|
||||||
|
pub stroke: Option<u32>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub remove: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Declaration {
|
||||||
|
pub fn join(self, parent: Self) -> Self {
|
||||||
|
let mut variants = self.variants;
|
||||||
|
|
||||||
|
for (name, parent_variant) in parent.variants {
|
||||||
|
if let Some(variant) = variants.get_mut(&name) {
|
||||||
|
variant.join(parent_variant);
|
||||||
|
} else {
|
||||||
|
variants.insert(name, parent_variant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name: self.name,
|
||||||
|
base: parent.base,
|
||||||
|
variants
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces every path relative to the yaml file to paths relative to the cwd
|
||||||
|
pub fn canonicalize(&mut self, path: impl AsRef<Path>) {
|
||||||
|
let path = path.as_ref().parent().unwrap_or(&PathBuf::from(".")).to_path_buf();
|
||||||
|
for variant in self.variants.values_mut() {
|
||||||
|
variant.canonicalize(path.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Variant {
|
||||||
|
pub fn join(&mut self, mut parent: Self) {
|
||||||
|
self.assets.append(&mut parent.assets);
|
||||||
|
self.overwrites.append(&mut parent.overwrites);
|
||||||
|
|
||||||
|
if self.base.is_none() {
|
||||||
|
self.base = parent.base;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.src.is_none() {
|
||||||
|
self.src = parent.src; // TODO: handle relative paths
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces every path relative to the yaml file to paths relative to the cwd
|
||||||
|
pub fn canonicalize(&mut self, path: &Path) {
|
||||||
|
match &mut self.src {
|
||||||
|
Some(src_path) => *src_path = path.join(&*src_path),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for asset in &mut self.assets {
|
||||||
|
asset.canonicalize(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for overwrite in &mut self.overwrites {
|
||||||
|
// overwrite.canonicalize(path);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetDecl {
|
||||||
|
/// Replaces every path relative to the yaml file to paths relative to the cwd
|
||||||
|
pub fn canonicalize(&mut self, path: &Path) {
|
||||||
|
match &mut self.src {
|
||||||
|
Some(src_path) => *src_path = path.join(&*src_path),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub mod decl;
|
||||||
|
use decl::*;
|
||||||
|
|
||||||
|
pub mod emote;
|
||||||
|
use emote::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
let mut path = args.decl_file;
|
||||||
|
let raw = std::fs::read_to_string(&path).unwrap();
|
||||||
|
let mut declaration: Declaration = serde_yaml::from_str(&raw).unwrap();
|
||||||
|
declaration.canonicalize(&path);
|
||||||
|
|
||||||
|
while let Some(parent) = std::mem::take(&mut declaration.base) {
|
||||||
|
path = path.parent().unwrap_or(&PathBuf::from(".")).join(parent);
|
||||||
|
let raw = std::fs::read_to_string(&path).unwrap_or_else(|err| {
|
||||||
|
// TODO: print the include stack
|
||||||
|
panic!("Couldn't read {}: {}", path.display(), err);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut parent_decl: Declaration = serde_yaml::from_str(&raw).unwrap();
|
||||||
|
parent_decl.canonicalize(&path);
|
||||||
|
|
||||||
|
declaration = declaration.join(parent_decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:#?}", declaration);
|
||||||
|
|
||||||
|
let mut emotes = HashMap::new();
|
||||||
|
|
||||||
|
let to_generate = if args.names.len() > 0 {
|
||||||
|
args.names
|
||||||
|
} else {
|
||||||
|
declaration.variants.keys().cloned().collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
for name in to_generate {
|
||||||
|
match construct_emote(&name, &declaration, &mut emotes) {
|
||||||
|
Some(emote) => {
|
||||||
|
emotes.insert(name, dbg!(emote));
|
||||||
|
// generate emote
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
eprintln!("Errors occured while generating emote {}, skipping!", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if !emotes.contains_key(&name) {
|
||||||
|
// let emote = Emote::from_decl(variant, &mut emotes);
|
||||||
|
// if let Some(emote) = emote {
|
||||||
|
// emotes.insert(name, emote);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recursively constructs the emote with variant declaration named `named`.
|
||||||
|
/// If the declaration has a base, that base is generated first.
|
||||||
|
// I could unwrap the recursion into a loop with a stack, but I'm lazy :3
|
||||||
|
fn construct_emote(name: &str, declaration: &Declaration, emotes: &mut HashMap<String, Emote>) -> Option<Emote> {
|
||||||
|
if let Some(emote_decl) = declaration.variants.get(name) {
|
||||||
|
if let Some(base_name) = emote_decl.base.clone() {
|
||||||
|
let base = construct_emote(&base_name, declaration, emotes)?;
|
||||||
|
emotes.insert(base_name, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
Emote::from_decl(emote_decl.clone(), &*emotes)
|
||||||
|
} else {
|
||||||
|
eprintln!("No emote named {}!", name);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
struct Args {
|
||||||
|
/// A YAML file containing the declaration from which the emotes should be generated
|
||||||
|
#[clap(short, long, value_parser)]
|
||||||
|
decl_file: PathBuf,
|
||||||
|
|
||||||
|
/// List of the emote names to export
|
||||||
|
#[clap(value_parser)]
|
||||||
|
names: Vec<String>,
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
.idea
|
@ -0,0 +1,5 @@
|
|||||||
|
To run
|
||||||
|
-
|
||||||
|
```bash
|
||||||
|
$ python src/main.py
|
||||||
|
```
|
@ -0,0 +1,201 @@
|
|||||||
|
[[package]]
|
||||||
|
name = "cairocffi"
|
||||||
|
version = "1.3.0"
|
||||||
|
description = "cffi-based cairo bindings for Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cffi = ">=1.1.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest-runner", "pytest-cov", "pytest-flake8", "pytest-isort"]
|
||||||
|
xcb = ["xcffib (>=0.3.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cairosvg"
|
||||||
|
version = "2.5.2"
|
||||||
|
description = "A Simple SVG Converter based on Cairo"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cairocffi = "*"
|
||||||
|
cssselect2 = "*"
|
||||||
|
defusedxml = "*"
|
||||||
|
pillow = "*"
|
||||||
|
tinycss2 = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest-runner", "pytest-cov", "pytest-flake8", "pytest-isort"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "1.15.1"
|
||||||
|
description = "Foreign Function Interface for Python calling C code."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pycparser = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cssselect2"
|
||||||
|
version = "0.6.0"
|
||||||
|
description = "CSS selectors for Python ElementTree"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
tinycss2 = "*"
|
||||||
|
webencodings = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defusedxml"
|
||||||
|
version = "0.7.1"
|
||||||
|
description = "XML bomb protection for Python stdlib modules"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pillow"
|
||||||
|
version = "9.2.0"
|
||||||
|
description = "Python Imaging Library (Fork)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"]
|
||||||
|
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "2.21"
|
||||||
|
description = "C parser in Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyyaml"
|
||||||
|
version = "6.0"
|
||||||
|
description = "YAML parser and emitter for Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinycss2"
|
||||||
|
version = "1.1.1"
|
||||||
|
description = "A tiny CSS parser"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
webencodings = ">=0.4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "types-pyyaml"
|
||||||
|
version = "6.0.10"
|
||||||
|
description = "Typing stubs for PyYAML"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.3.0"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webencodings"
|
||||||
|
version = "0.5.1"
|
||||||
|
description = "Character encoding aliases for legacy web content"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "1.1"
|
||||||
|
python-versions = "^3.10"
|
||||||
|
content-hash = "f53bba5be8f79539f2f1e96e0fccc6feaf7553d646a307ea39be9e6d3cefc64c"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
cairocffi = []
|
||||||
|
cairosvg = []
|
||||||
|
cffi = []
|
||||||
|
cssselect2 = []
|
||||||
|
defusedxml = [
|
||||||
|
{file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
|
||||||
|
{file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
|
||||||
|
]
|
||||||
|
pillow = []
|
||||||
|
pycparser = [
|
||||||
|
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
|
||||||
|
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
|
||||||
|
]
|
||||||
|
pyyaml = [
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
|
||||||
|
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
|
||||||
|
{file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
|
||||||
|
{file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
|
||||||
|
{file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
|
||||||
|
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
|
||||||
|
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
|
||||||
|
]
|
||||||
|
tinycss2 = [
|
||||||
|
{file = "tinycss2-1.1.1-py3-none-any.whl", hash = "sha256:fe794ceaadfe3cf3e686b22155d0da5780dd0e273471a51846d0a02bc204fec8"},
|
||||||
|
{file = "tinycss2-1.1.1.tar.gz", hash = "sha256:b2e44dd8883c360c35dd0d1b5aad0b610e5156c2cb3b33434634e539ead9d8bf"},
|
||||||
|
]
|
||||||
|
types-pyyaml = []
|
||||||
|
typing-extensions = []
|
||||||
|
webencodings = [
|
||||||
|
{file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
|
||||||
|
{file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
|
||||||
|
]
|
@ -0,0 +1,18 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "automate"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["ENDERZOMBI102 <enderzombi102.end@gmail.com>"]
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.10"
|
||||||
|
PyYAML = "^6.0"
|
||||||
|
types-PyYAML = "^6.0.10"
|
||||||
|
CairoSVG = "^2.5.2"
|
||||||
|
typing-extensions = "^4.3.0"
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,15 @@
|
|||||||
|
name: 'blobfox'
|
||||||
|
basedOff: null
|
||||||
|
variants:
|
||||||
|
- name: 'base'
|
||||||
|
src: '../vector/blobfox.svg'
|
||||||
|
|
||||||
|
- name: 'boop'
|
||||||
|
objects:
|
||||||
|
- type: svg
|
||||||
|
src: 'resources/lgbtq_heart.svg'
|
||||||
|
|
||||||
|
overwrites:
|
||||||
|
- id: 'eye-left'
|
||||||
|
color: 0xfffffffff
|
||||||
|
remove: true
|
@ -0,0 +1,11 @@
|
|||||||
|
name: 'neugeme'
|
||||||
|
basedOff: 'blobfox' # all variants from 'blobfox' will be imported in this unit, unless they are already present
|
||||||
|
variants:
|
||||||
|
- name: 'base'
|
||||||
|
overwrites:
|
||||||
|
- id: 'body'
|
||||||
|
color: 0x02FFFD
|
||||||
|
- id: 'hair'
|
||||||
|
color: 0x02FFFD
|
||||||
|
- id: 'blobfox'
|
||||||
|
remove: true
|
@ -0,0 +1,29 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from data.object import Object
|
||||||
|
from data.overwrite import Overwrite
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Emote:
|
||||||
|
name: str
|
||||||
|
origin: list[ str ] #: the origins in order of definition
|
||||||
|
base: str | None = None
|
||||||
|
src: Path | None = None
|
||||||
|
objects: list[Object] = None
|
||||||
|
overwrites: list[Overwrite] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load( cls, data: list[dict], origin: str ) -> list[Self]:
|
||||||
|
return [
|
||||||
|
Emote(
|
||||||
|
origin=[ origin ],
|
||||||
|
**entry | {
|
||||||
|
'base': 'base' if 'base' not in entry and 'src' not in entry else entry.get( 'base', None ),
|
||||||
|
'overwrites': Overwrite.load( entry.get( 'overwrites', [ ] ) ),
|
||||||
|
'objects': Object.load( entry.get( 'objects', [ ] ) )
|
||||||
|
}
|
||||||
|
) for entry in data
|
||||||
|
]
|
@ -0,0 +1,17 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Object:
|
||||||
|
type: str
|
||||||
|
src: Path | None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load( cls, data: list[dict] ) -> list[ Self ]:
|
||||||
|
objects: list[ Object ] = []
|
||||||
|
for obj in data or []:
|
||||||
|
objects += [ Object( **obj ) ]
|
||||||
|
|
||||||
|
return objects
|
@ -0,0 +1,17 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Overwrite:
|
||||||
|
id: str
|
||||||
|
color: str | None = None
|
||||||
|
remove: bool = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load( cls, data: list[dict] ) -> list[Self]:
|
||||||
|
overwrites: list[ Overwrite ] = [ ]
|
||||||
|
for overwrite in data or [ ]:
|
||||||
|
overwrites += [ Overwrite( **overwrite ) ]
|
||||||
|
|
||||||
|
return overwrites
|
@ -0,0 +1,80 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import typing
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Final
|
||||||
|
from collections.abc import Collection, Iterator
|
||||||
|
|
||||||
|
import util
|
||||||
|
from data.emote import Emote
|
||||||
|
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from generator import Generator
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyFinal
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class Variants( Collection[Emote] ):
|
||||||
|
""" An immutable variant list """
|
||||||
|
name: Final[ str ]
|
||||||
|
basedOff: Final[ tuple[ str ] ]
|
||||||
|
variants: Final[ tuple[ Emote ] ]
|
||||||
|
|
||||||
|
def __init__( self, path: Path, gen: Generator ) -> None:
|
||||||
|
data = util.load( path )
|
||||||
|
|
||||||
|
object.__setattr__( self, 'name', data[ 'name' ] )
|
||||||
|
object.__setattr__( self, 'basedOff', data.get( 'basedOff', None ) )
|
||||||
|
|
||||||
|
if data['basedOff']:
|
||||||
|
# loading a set based off another, load the base one before this
|
||||||
|
base = gen.load( path.parent / f'{data["basedOff"]}.yml' )
|
||||||
|
|
||||||
|
# additional emotes may be defined
|
||||||
|
additional = [ ]
|
||||||
|
# apply overwrites and append new emotes to `additional`
|
||||||
|
for emote in Emote.load( data['variants'], self.name ):
|
||||||
|
if emote.name in base:
|
||||||
|
base._applyOverwrite( emote )
|
||||||
|
else:
|
||||||
|
additional += [ emote ]
|
||||||
|
# save the newly created set of emotes
|
||||||
|
object.__setattr__( self, 'variants', base.variants + tuple( additional ) )
|
||||||
|
else:
|
||||||
|
# loading a baseless set, just load it directly
|
||||||
|
object.__setattr__( self, 'variants', tuple( Emote.load( data['variants'], self.name ) ) )
|
||||||
|
|
||||||
|
def __iter__( self ) -> Iterator[Emote ]:
|
||||||
|
return self.variants.__iter__()
|
||||||
|
|
||||||
|
def __contains__( self, item: object ) -> bool:
|
||||||
|
if isinstance( item, str ):
|
||||||
|
for elem in self.variants:
|
||||||
|
if elem.name == item:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
return item in self.variants
|
||||||
|
|
||||||
|
def __getitem__( self, item: int | str ) -> Emote:
|
||||||
|
if isinstance( item, int ):
|
||||||
|
return self.variants[ item ]
|
||||||
|
|
||||||
|
if isinstance( item, str ):
|
||||||
|
for elem in self.variants:
|
||||||
|
if elem.name == item:
|
||||||
|
return elem
|
||||||
|
raise KeyError( f'A variant with name "{item}" does not exist' )
|
||||||
|
|
||||||
|
raise ValueError( f'Invalid __getitem__ input: {item}' )
|
||||||
|
|
||||||
|
def __len__( self ) -> int:
|
||||||
|
return len( self.variants )
|
||||||
|
|
||||||
|
def _applyOverwrite( self, overwriter: Emote ) -> None:
|
||||||
|
emote = self[ overwriter.name ]
|
||||||
|
emote.origin += overwriter.origin
|
||||||
|
emote.overwrites += overwriter.overwrites
|
||||||
|
emote.objects += overwriter.objects
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from PIL.Image import Image
|
||||||
|
from cairosvg.surface import Surface
|
||||||
|
|
||||||
|
from data.emote import Emote
|
||||||
|
from data.variants import Variants
|
||||||
|
|
||||||
|
|
||||||
|
class Generator:
|
||||||
|
declarations: dict[ str, Variants ]
|
||||||
|
surfaces: dict[ str, Surface ]
|
||||||
|
|
||||||
|
def __init__( self, declFile: Path ) -> None:
|
||||||
|
if not declFile.exists():
|
||||||
|
raise FileNotFoundError('Declaration file does not exist!')
|
||||||
|
|
||||||
|
self.declarations = { declFile.name[:-4]: self.load( declFile ) }
|
||||||
|
|
||||||
|
def load( self, declFile: Path ) -> Variants:
|
||||||
|
return Variants( declFile, self )
|
||||||
|
|
||||||
|
def generate( self, emote: Emote ) -> Image:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def export( self, sets: list[str], outputDir: Path = Path( '.' ) ) -> None:
|
||||||
|
"""
|
||||||
|
Generates the images in the given folder
|
||||||
|
\t
|
||||||
|
:param sets: the sets to export to PNGs
|
||||||
|
:param outputDir: output directory
|
||||||
|
"""
|
||||||
|
if not outputDir.exists():
|
||||||
|
outputDir.mkdir()
|
||||||
|
|
||||||
|
for set in sets:
|
||||||
|
# for emote in emotes
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
|
from generator import Generator
|
||||||
|
|
||||||
|
parser = ArgumentParser(
|
||||||
|
prog=( 'automation' + '.exe' if 'win' in os.name.lower() else '' ) if getattr( sys, 'frozen', False ) else 'main.py',
|
||||||
|
description='Generates blobfoxes from yaml and svgs'
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-d',
|
||||||
|
'--declfile',
|
||||||
|
help='Declaration file to export',
|
||||||
|
action='store',
|
||||||
|
type=Path,
|
||||||
|
dest='declFile',
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-e',
|
||||||
|
'--export',
|
||||||
|
help='A comma-separated list of emote to export',
|
||||||
|
action='store',
|
||||||
|
dest='exports',
|
||||||
|
default='<all>'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'-o',
|
||||||
|
'--output',
|
||||||
|
help='Output directory',
|
||||||
|
action='store',
|
||||||
|
type=Path,
|
||||||
|
dest='output',
|
||||||
|
default=Path('.')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Arguments:
|
||||||
|
declFile: Path
|
||||||
|
exports: str
|
||||||
|
output: Path
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args: Arguments = cast( parser.parse_args( sys.argv[1:] ), Arguments )
|
||||||
|
|
||||||
|
gen = Generator( args.declFile )
|
||||||
|
|
||||||
|
gen.export( args.exports.split(','), args.output )
|
||||||
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def load( path: Path ) -> Any:
|
||||||
|
""" Parse the first YAML document in a stream and produce the corresponding Python object. """
|
||||||
|
return yaml.load( path.read_text(), yaml.FullLoader )
|
||||||
|
|
||||||
|
|
||||||
|
def loads( data: str ) -> Any:
|
||||||
|
""" Parse the first YAML document in a string and produce the corresponding Python object. """
|
||||||
|
return yaml.load( data, yaml.FullLoader )
|
Loading…
Reference in new issue