use crate::core::Context;
use crate::gfx::{Font, FontMut, FontRef, SubTexture};
use crate::lua::LuaModule;
use crate::misc::BASIC_LATIN;
use mlua::prelude::{LuaError, LuaResult};
use mlua::{BorrowedStr, Lua, UserData, UserDataMethods, Value};
pub struct FontModule;
impl LuaModule for FontModule {
const PATH: &'static str = "Font";
fn load(lua: &Lua) -> LuaResult<Value> {
lua.create_userdata(Self).map(Value::UserData)
}
}
impl UserData for FontModule {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
methods.add_function("new", |_, (size, pixelated): (f32, bool)| {
Ok(Font::new(size, pixelated))
});
methods.add_function(
"from_ttf_file",
|lua, (path, size, pixelated, chars): (BorrowedStr, f32, bool, Option<BorrowedStr>)| {
let chars = chars
.map(|chrs| chrs.to_string())
.unwrap_or_else(|| BASIC_LATIN.chars().collect());
let ctx = Context::from_lua(lua);
Font::from_ttf_file(&ctx.graphics, path.as_ref(), size, pixelated, chars.chars())
.map_err(LuaError::external)?
.ok_or_else(|| LuaError::runtime("failed to pack font"))
.map(|(font, _)| font)
},
);
add_methods(methods);
}
}
impl UserData for Font {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
add_methods(methods);
}
}
fn add_methods<T, M: UserDataMethods<T>>(methods: &mut M) {
fn get_char(s: BorrowedStr) -> LuaResult<char> {
s.chars()
.next()
.ok_or_else(|| LuaError::runtime(format!("invalid char {s:?}")))
}
methods.add_function("size", |_, this: FontRef| Ok(this.size()));
methods.add_function("pixelated", |_, this: FontRef| Ok(this.pixelated()));
methods.add_function(
"set_glyph",
|_, (mut this, chr, sub, adv): (FontMut, BorrowedStr, Option<SubTexture>, f32)| {
this.set_glyph(get_char(chr)?, sub, adv);
Ok(())
},
);
methods.add_function(
"set_kerning",
|_, (mut this, left, right, kern): (FontMut, BorrowedStr, BorrowedStr, f32)| {
let left = get_char(left)?;
let right = get_char(right)?;
this.set_kerning(left, right, kern);
Ok(())
},
);
methods.add_function(
"kerning",
|_, (this, left, right): (FontRef, BorrowedStr, BorrowedStr)| {
let left = get_char(left)?;
let right = get_char(right)?;
Ok(this.kerning(left, right).unwrap_or(0.0))
},
);
}