use crate::{CWString, NullByteError, load_wide_string};
#[derive(Debug, Clone, PartialEq)]
pub struct FontInfo {
pub name: String,
pub size: f32,
}
impl FontInfo {
unsafe fn from_raw(font_info_ptr: *mut aviutl2_sys::config2::FONT_INFO) -> Self {
let font_info = unsafe { &*font_info_ptr };
let name = unsafe { load_wide_string(font_info.name) };
Self {
name,
size: font_info.size,
}
}
}
struct InternalConfigHandle {
raw: *mut aviutl2_sys::config2::CONFIG_HANDLE,
}
unsafe impl Send for InternalConfigHandle {}
static CONFIG_HANDLE: std::sync::OnceLock<std::sync::Mutex<InternalConfigHandle>> =
std::sync::OnceLock::new();
pub fn app_data_path() -> std::path::PathBuf {
let path = unsafe {
load_wide_string(
CONFIG_HANDLE
.get()
.expect("Config handle not initialized")
.lock()
.unwrap()
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.app_data_path,
)
};
std::path::PathBuf::from(path)
}
pub fn translate(text: &str) -> String {
match translate_strict(text) {
Ok(translated) => translated,
Err(_) => text.to_string(),
}
}
pub fn translate_strict(text: &str) -> Result<String, NullByteError> {
let wide_text = CWString::new(text)?;
let translated = unsafe {
let handle = CONFIG_HANDLE
.get()
.expect("Config handle not initialized")
.lock()
.unwrap();
(handle
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.translate)(handle.raw, wide_text.as_ptr())
};
Ok(unsafe { load_wide_string(translated) })
}
pub fn get_language_text(section: &str, text: &str) -> Result<String, NullByteError> {
let wide_section = CWString::new(section)?;
let wide_text = CWString::new(text)?;
let translated = unsafe {
let handle = CONFIG_HANDLE
.get()
.expect("Config handle not initialized")
.lock()
.unwrap();
(handle
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.get_language_text)(handle.raw, wide_section.as_ptr(), wide_text.as_ptr())
};
Ok(unsafe { load_wide_string(translated) })
}
pub fn get_font_info(key: &str) -> Result<FontInfo, std::ffi::NulError> {
let c_key = std::ffi::CString::new(key)?;
let font_info = unsafe {
let handle = CONFIG_HANDLE
.get()
.expect("Config handle not initialized")
.lock()
.unwrap();
let font_info_ptr = (handle
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.get_font_info)(handle.raw, c_key.as_ptr());
FontInfo::from_raw(font_info_ptr)
};
Ok(font_info)
}
pub fn get_color_code(key: &str) -> Result<Option<(u8, u8, u8)>, std::ffi::NulError> {
get_all_color_codes(key).map(|codes| codes.into_iter().next())
}
pub fn get_all_color_codes(key: &str) -> Result<Vec<(u8, u8, u8)>, std::ffi::NulError> {
let c_key = std::ffi::CString::new(key)?;
let color_codes = unsafe {
let handle = CONFIG_HANDLE
.get()
.expect("Config handle not initialized")
.lock()
.unwrap();
let count = (handle
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.get_color_code_index)(handle.raw, c_key.as_ptr(), -1);
let mut codes = Vec::with_capacity(count as usize);
for i in 0..count {
let color_code = (handle
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.get_color_code_index)(handle.raw, c_key.as_ptr(), i);
let r = ((color_code >> 16) & 0xFF) as u8;
let g = ((color_code >> 8) & 0xFF) as u8;
let b = (color_code & 0xFF) as u8;
codes.push((r, g, b));
}
codes
};
Ok(color_codes)
}
pub fn get_layout_size(key: &str) -> Result<i32, std::ffi::NulError> {
let c_key = std::ffi::CString::new(key)?;
let layout_size = unsafe {
let handle = CONFIG_HANDLE
.get()
.expect("Config handle not initialized")
.lock()
.unwrap();
(handle
.raw
.as_ref()
.expect("Config handle raw pointer is null")
.get_layout_size)(handle.raw, c_key.as_ptr())
};
Ok(layout_size)
}
#[doc(hidden)]
pub fn __initialize_config_handle(raw: *mut aviutl2_sys::config2::CONFIG_HANDLE) {
CONFIG_HANDLE
.set(std::sync::Mutex::new(InternalConfigHandle { raw }))
.unwrap_or_else(|_| {
panic!("Config handle is already initialized");
});
}
#[doc(hidden)]
pub fn __initialize_config_handle_unwind(raw: *mut aviutl2_sys::config2::CONFIG_HANDLE) {
if let Err(panic_info) =
crate::__catch_unwind_with_panic_info(|| __initialize_config_handle(raw))
{
tracing::error!("Panic occurred during InitializeConfig: {}", panic_info);
let _ = crate::logger::write_error_log(&panic_info);
}
}