#![allow(deprecated)]
use crate::sys;
#[derive(Debug)]
#[deprecated(
since = "0.1.0",
note = "Use dynamic font loading instead. Glyphs are now loaded on-demand automatically with Dear ImGui 1.92+."
)]
pub struct GlyphRangesBuilder {
raw: *mut sys::ImFontGlyphRangesBuilder,
}
impl GlyphRangesBuilder {
pub fn new() -> Self {
unsafe {
let raw = sys::ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder();
if raw.is_null() {
panic!("ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder() returned null");
}
Self { raw }
}
}
#[doc(alias = "AddText")]
pub fn add_text(&mut self, text: &str) {
unsafe {
let text_start = text.as_ptr() as *const std::os::raw::c_char;
let text_end = text_start.add(text.len());
sys::ImFontGlyphRangesBuilder_AddText(self.raw, text_start, text_end);
}
}
#[doc(alias = "AddRanges")]
pub fn add_ranges(&mut self, ranges: &[u32]) {
if ranges.is_empty() {
return;
}
const IMWCHAR_MAX: u32 = if std::mem::size_of::<sys::ImWchar>() == 2 {
0xFFFF
} else {
0x10FFFF
};
let mut tmp: Vec<sys::ImWchar> = Vec::with_capacity(ranges.len());
for &v in ranges {
assert!(
v <= IMWCHAR_MAX,
"glyph range value {v:#X} exceeded ImWchar max ({IMWCHAR_MAX:#X})"
);
let v = sys::ImWchar::try_from(v).unwrap_or_else(|_| {
panic!("glyph range value {v:#X} was not representable as ImWchar")
});
tmp.push(v);
}
if tmp.last().copied() != Some(0) {
tmp.push(0);
}
unsafe { sys::ImFontGlyphRangesBuilder_AddRanges(self.raw, tmp.as_ptr()) };
}
#[doc(alias = "BuildRanges")]
pub fn build_ranges(&mut self) -> Vec<u32> {
unsafe {
let mut out_ranges = std::mem::MaybeUninit::<sys::ImVector_ImWchar>::uninit();
sys::ImVector_ImWchar_Init(out_ranges.as_mut_ptr());
let mut out_ranges = out_ranges.assume_init();
sys::ImFontGlyphRangesBuilder_BuildRanges(self.raw, &mut out_ranges);
let mut result: Vec<u32> = Vec::new();
if out_ranges.Size > 0 && !out_ranges.Data.is_null() {
let len = match usize::try_from(out_ranges.Size) {
Ok(len) => len,
Err(_) => 0,
};
if len == 0 {
sys::ImVector_ImWchar_UnInit(&mut out_ranges);
return result;
}
result = Vec::with_capacity(len);
for i in 0..len {
result.push(*out_ranges.Data.add(i) as u32);
}
}
sys::ImVector_ImWchar_UnInit(&mut out_ranges);
result
}
}
}
impl Default for GlyphRangesBuilder {
fn default() -> Self {
Self::new()
}
}
impl Drop for GlyphRangesBuilder {
fn drop(&mut self) {
unsafe {
if !self.raw.is_null() {
sys::ImFontGlyphRangesBuilder_destroy(self.raw);
self.raw = std::ptr::null_mut();
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(deprecated)]
fn build_ranges_from(input: &[u32]) -> Vec<u32> {
let mut b = GlyphRangesBuilder::new();
b.add_ranges(input);
b.build_ranges()
}
#[allow(deprecated)]
fn add_ranges_expect_panic(input: &[u32]) {
let mut b = GlyphRangesBuilder::new();
b.add_ranges(input);
}
#[test]
fn add_ranges_rejects_non_bmp_codepoints_when_wchar16() {
if std::mem::size_of::<sys::ImWchar>() != 2 {
return;
}
let res = std::panic::catch_unwind(|| add_ranges_expect_panic(&[0x1_0000, 0]));
assert!(res.is_err());
}
#[test]
fn add_ranges_appends_terminator_if_missing() {
let ranges = build_ranges_from(&[0x20, 0x7E]);
assert_eq!(ranges.last().copied(), Some(0));
}
#[test]
fn add_ranges_accepts_non_bmp_when_wchar32() {
if std::mem::size_of::<sys::ImWchar>() != 4 {
return;
}
let ranges = build_ranges_from(&[0x1_0000, 0x1_0001]);
assert_eq!(ranges.last().copied(), Some(0));
assert!(ranges.contains(&0x1_0000));
assert!(ranges.contains(&0x1_0001));
}
}
pub struct GlyphRanges;
impl GlyphRanges {
pub const DEFAULT: &'static [u32] = &[
0x0020, 0x00FF, 0,
];
pub const KOREAN: &'static [u32] = &[
0x0020, 0x00FF, 0x3131, 0x3163, 0xAC00, 0xD7A3, 0,
];
pub const JAPANESE: &'static [u32] = &[
0x0020, 0x00FF, 0x3000, 0x30FF, 0x31F0, 0x31FF, 0xFF00, 0xFFEF, 0,
];
pub const CHINESE_SIMPLIFIED_COMMON: &'static [u32] = &[
0x0020, 0x00FF, 0x2000, 0x206F, 0x3000, 0x30FF, 0x31F0, 0x31FF, 0xFF00, 0xFFEF, 0x4E00, 0x9FAF, 0,
];
pub const CHINESE_TRADITIONAL_COMMON: &'static [u32] = &[
0x0020, 0x00FF, 0x2000, 0x206F, 0x3000, 0x30FF, 0x31F0, 0x31FF, 0xFF00, 0xFFEF, 0x4E00, 0x9FAF, 0,
];
pub const CYRILLIC: &'static [u32] = &[
0x0020, 0x00FF, 0x0400, 0x052F, 0x2DE0, 0x2DFF, 0xA640, 0xA69F, 0,
];
pub const THAI: &'static [u32] = &[
0x0020, 0x00FF, 0x0E00, 0x0E7F, 0,
];
pub const VIETNAMESE: &'static [u32] = &[
0x0020, 0x00FF, 0x0102, 0x0103, 0x0110, 0x0111, 0x0128, 0x0129, 0x0168, 0x0169, 0x01A0, 0x01A1, 0x01AF, 0x01B0, 0x1EA0, 0x1EF9, 0,
];
}