1use crate::{CWString, NullByteError, load_wide_string};
4
5#[derive(Debug, Clone, PartialEq)]
7pub struct FontInfo {
8 pub name: String,
10 pub size: f32,
12}
13impl FontInfo {
14 unsafe fn from_raw(font_info_ptr: *mut aviutl2_sys::config2::FONT_INFO) -> Self {
20 let font_info = unsafe { &*font_info_ptr };
21 let name = unsafe { load_wide_string(font_info.name) };
22 Self {
23 name,
24 size: font_info.size,
25 }
26 }
27}
28
29struct InternalConfigHandle {
30 raw: *mut aviutl2_sys::config2::CONFIG_HANDLE,
31}
32unsafe impl Send for InternalConfigHandle {}
33
34static CONFIG_HANDLE: std::sync::OnceLock<std::sync::Mutex<InternalConfigHandle>> =
35 std::sync::OnceLock::new();
36
37pub fn app_data_path() -> std::path::PathBuf {
39 let path = unsafe {
40 load_wide_string(
41 CONFIG_HANDLE
42 .get()
43 .expect("Config handle not initialized")
44 .lock()
45 .unwrap()
46 .raw
47 .as_ref()
48 .expect("Config handle raw pointer is null")
49 .app_data_path,
50 )
51 };
52 std::path::PathBuf::from(path)
53}
54
55pub fn translate(text: &str) -> String {
60 match translate_strict(text) {
61 Ok(translated) => translated,
62 Err(_) => text.to_string(),
63 }
64}
65
66pub fn translate_strict(text: &str) -> Result<String, NullByteError> {
74 let wide_text = CWString::new(text)?;
75 let translated = unsafe {
76 let handle = CONFIG_HANDLE
77 .get()
78 .expect("Config handle not initialized")
79 .lock()
80 .unwrap();
81 (handle
82 .raw
83 .as_ref()
84 .expect("Config handle raw pointer is null")
85 .translate)(handle.raw, wide_text.as_ptr())
86 };
87 Ok(unsafe { load_wide_string(translated) })
88}
89
90pub fn get_language_text(section: &str, text: &str) -> Result<String, NullByteError> {
99 let wide_section = CWString::new(section)?;
100 let wide_text = CWString::new(text)?;
101 let translated = unsafe {
102 let handle = CONFIG_HANDLE
103 .get()
104 .expect("Config handle not initialized")
105 .lock()
106 .unwrap();
107 (handle
108 .raw
109 .as_ref()
110 .expect("Config handle raw pointer is null")
111 .get_language_text)(handle.raw, wide_section.as_ptr(), wide_text.as_ptr())
112 };
113 Ok(unsafe { load_wide_string(translated) })
114}
115
116pub fn get_font_info(key: &str) -> Result<FontInfo, std::ffi::NulError> {
126 let c_key = std::ffi::CString::new(key)?;
127 let font_info = unsafe {
128 let handle = CONFIG_HANDLE
129 .get()
130 .expect("Config handle not initialized")
131 .lock()
132 .unwrap();
133 let font_info_ptr = (handle
134 .raw
135 .as_ref()
136 .expect("Config handle raw pointer is null")
137 .get_font_info)(handle.raw, c_key.as_ptr());
138 FontInfo::from_raw(font_info_ptr)
139 };
140 Ok(font_info)
141}
142
143pub fn get_color_code(key: &str) -> Result<Option<(u8, u8, u8)>, std::ffi::NulError> {
157 get_all_color_codes(key).map(|codes| codes.into_iter().next())
158}
159
160pub fn get_all_color_codes(key: &str) -> Result<Vec<(u8, u8, u8)>, std::ffi::NulError> {
170 let c_key = std::ffi::CString::new(key)?;
171 let color_codes = unsafe {
172 let handle = CONFIG_HANDLE
173 .get()
174 .expect("Config handle not initialized")
175 .lock()
176 .unwrap();
177 let count = (handle
178 .raw
179 .as_ref()
180 .expect("Config handle raw pointer is null")
181 .get_color_code_index)(handle.raw, c_key.as_ptr(), -1);
182 let mut codes = Vec::with_capacity(count as usize);
183 for i in 0..count {
184 let color_code = (handle
185 .raw
186 .as_ref()
187 .expect("Config handle raw pointer is null")
188 .get_color_code_index)(handle.raw, c_key.as_ptr(), i);
189 let r = ((color_code >> 16) & 0xFF) as u8;
190 let g = ((color_code >> 8) & 0xFF) as u8;
191 let b = (color_code & 0xFF) as u8;
192 codes.push((r, g, b));
193 }
194 codes
195 };
196 Ok(color_codes)
197}
198
199pub fn get_layout_size(key: &str) -> Result<i32, std::ffi::NulError> {
209 let c_key = std::ffi::CString::new(key)?;
210 let layout_size = unsafe {
211 let handle = CONFIG_HANDLE
212 .get()
213 .expect("Config handle not initialized")
214 .lock()
215 .unwrap();
216 (handle
217 .raw
218 .as_ref()
219 .expect("Config handle raw pointer is null")
220 .get_layout_size)(handle.raw, c_key.as_ptr())
221 };
222 Ok(layout_size)
223}
224
225#[doc(hidden)]
226pub fn __initialize_config_handle(raw: *mut aviutl2_sys::config2::CONFIG_HANDLE) {
227 CONFIG_HANDLE
228 .set(std::sync::Mutex::new(InternalConfigHandle { raw }))
229 .unwrap_or_else(|_| {
230 panic!("Config handle is already initialized");
231 });
232}
233
234#[doc(hidden)]
235pub fn __initialize_config_handle_unwind(raw: *mut aviutl2_sys::config2::CONFIG_HANDLE) {
236 if let Err(panic_info) =
237 crate::__catch_unwind_with_panic_info(|| __initialize_config_handle(raw))
238 {
239 tracing::error!("Panic occurred during InitializeConfig: {}", panic_info);
240 let _ = crate::logger::write_error_log(&panic_info);
241 }
242}