nexus\api/
font.rs

1//! Font loading.
2
3use crate::{
4    util::{path_to_c, str_to_c},
5    AddonApi, FontApi, Revertible,
6};
7use imgui::sys::{ImFont, ImFontConfig};
8use std::{
9    ffi::{c_char, c_void},
10    path::Path,
11};
12use windows::Win32::Foundation::HMODULE;
13
14pub type RawFontReceive = unsafe extern "C-unwind" fn(identifier: *const c_char, font: *mut ImFont);
15
16pub type RawFontGet =
17    unsafe extern "C-unwind" fn(identifier: *const c_char, callback: RawFontReceive);
18
19pub type RawFontRelease =
20    unsafe extern "C-unwind" fn(identifier: *const c_char, callback: RawFontReceive);
21
22pub type RawFontAddFromFile = unsafe extern "C-unwind" fn(
23    identifier: *const c_char,
24    font_size: f32,
25    filename: *const c_char,
26    callback: RawFontReceive,
27    config: *mut ImFontConfig,
28);
29
30pub type RawFontAddFromResource = unsafe extern "C-unwind" fn(
31    identifier: *const c_char,
32    font_size: f32,
33    resource_id: u32,
34    module: HMODULE,
35    callback: RawFontReceive,
36    config: *mut ImFontConfig,
37);
38
39pub type RawFontAddFromMemory = unsafe extern "C-unwind" fn(
40    identifier: *const c_char,
41    font_size: f32,
42    data: *const c_void,
43    size: usize,
44    callback: RawFontReceive,
45    config: *mut ImFontConfig,
46);
47
48pub type RawFontResize = unsafe extern "C-unwind" fn(identifier: *const c_char, font_size: f32);
49
50/// Registers a new callback to receive the font with the given identifier.
51pub fn get_font(
52    identifier: impl AsRef<str>,
53    callback: RawFontReceive,
54) -> Revertible<impl Fn() + Send + Sync + 'static> {
55    let FontApi { get, release, .. } = AddonApi::get().font;
56    let identifier = str_to_c(identifier, "failed to convert font identifier");
57    unsafe { get(identifier.as_ptr(), callback) };
58    let revert = move || unsafe { release(identifier.as_ptr(), callback) };
59    revert.into()
60}
61
62/// Releases a previously registered callback for the font with the given identifier.
63pub fn release_font(identifier: impl AsRef<str>, callback: RawFontReceive) {
64    let FontApi { release, .. } = AddonApi::get().font;
65    let identifier = str_to_c(identifier, "failed to convert font identifier");
66    unsafe { release(identifier.as_ptr(), callback) }
67}
68
69/// Adds a font from a file path and sends updates to the callback.
70pub fn add_font_from_file(
71    identifier: impl AsRef<str>,
72    file: impl AsRef<Path>,
73    font_size: f32,
74    config: &mut ImFontConfig,
75    callback: RawFontReceive,
76) -> Revertible<impl Fn() + Send + Sync + 'static> {
77    let FontApi {
78        add_from_file,
79        release,
80        ..
81    } = AddonApi::get().font;
82    let identifier = str_to_c(identifier, "failed to convert font identifier");
83    let file = path_to_c(file, "failed to convert font file path");
84    unsafe {
85        add_from_file(
86            identifier.as_ptr(),
87            font_size,
88            file.as_ptr(),
89            callback,
90            config,
91        )
92    };
93    let revert = move || unsafe { release(identifier.as_ptr(), callback) };
94    revert.into()
95}
96
97/// Adds a font from a resource and sends updates to the callback.
98pub fn add_font_from_resource(
99    identifier: impl AsRef<str>,
100    handle: HMODULE,
101    resource: u32,
102    font_size: f32,
103    config: &mut ImFontConfig,
104    callback: RawFontReceive,
105) -> Revertible<impl Fn() + Send + Sync + 'static> {
106    let FontApi {
107        add_from_resource,
108        release,
109        ..
110    } = AddonApi::get().font;
111    let identifier = str_to_c(identifier, "failed to convert font identifier");
112    unsafe {
113        add_from_resource(
114            identifier.as_ptr(),
115            font_size,
116            resource,
117            handle,
118            callback,
119            config,
120        )
121    };
122    let revert = move || unsafe { release(identifier.as_ptr(), callback) };
123    revert.into()
124}
125
126/// Adds a font from memory and sends updates to the callback.
127pub fn add_font_from_memory(
128    identifier: impl AsRef<str>,
129    data: impl AsRef<[u8]>,
130    font_size: f32,
131    config: &mut ImFontConfig,
132    callback: RawFontReceive,
133) -> Revertible<impl Fn() + Send + Sync + 'static> {
134    let FontApi {
135        add_from_memory,
136        release,
137        ..
138    } = AddonApi::get().font;
139    let identifier = str_to_c(identifier, "failed to convert font identifier");
140    let data = data.as_ref();
141    unsafe {
142        add_from_memory(
143            identifier.as_ptr(),
144            font_size,
145            data.as_ptr().cast(),
146            data.len(),
147            callback,
148            config,
149        )
150    };
151    let revert = move || unsafe { release(identifier.as_ptr(), callback) };
152    revert.into()
153}
154
155/// Macro to wrap a font receive callback.
156///
157/// Generates a [`RawFontReceive`] wrapper around the passed callback.
158///
159/// # Usage
160/// ```no_run
161/// # use nexus::font::*;
162/// let font_receive: RawFontReceive = font_receive!(|id, font| {
163///     use nexus::log::{log, LogLevel};
164///     log(LogLevel::Info, "My Addon", format!("font {id} received"));
165/// });
166/// ```
167#[macro_export]
168macro_rules! font_receive {
169    ( $callback:expr $(,)? ) => {{
170        const __CALLBACK: fn(
171            &::std::primitive::str,
172            ::std::option::Option<&mut $crate::imgui::sys::ImFont>,
173        ) = $callback;
174
175        extern "C-unwind" fn __font_receive_wrapper(
176            identifier: *const ::std::ffi::c_char,
177            font: *mut $crate::imgui::sys::ImFont,
178        ) {
179            let identifier = unsafe { $crate::__macro::str_from_c(identifier) }
180                .expect("invalid identifier in font callback");
181            let font = unsafe { font.as_mut() };
182            __CALLBACK(identifier, font)
183        }
184
185        __font_receive_wrapper
186    }};
187}
188
189pub use font_receive;
190
191/// Resizes an existing font, sending the update to registered callbacks.
192pub fn resize_font(identifier: impl AsRef<str>, font_size: f32) {
193    let FontApi { resize, .. } = AddonApi::get().font;
194    let identifier = str_to_c(identifier, "failed to convert font identifier");
195    unsafe { resize(identifier.as_ptr(), font_size) }
196}