1use crate::fonts::Font;
11use crate::sys;
12use std::ffi::CString;
13use std::marker::PhantomData;
14use std::ptr;
15use std::rc::Rc;
16
17#[derive(Debug)]
24pub struct FontAtlas {
25 raw: *mut sys::ImFontAtlas,
26 owned: bool,
27 _phantom: PhantomData<*mut sys::ImFontAtlas>,
28}
29
30#[derive(Copy, Clone, Debug, Eq, PartialEq)]
32pub struct FontId(pub(crate) *const sys::ImFont);
33
34pub struct FontLoader {
39 raw: sys::ImFontLoader,
40 name: CString,
41}
42
43impl FontLoader {
44 pub fn new(name: &str) -> Result<Self, std::ffi::NulError> {
46 let name_cstring = CString::new(name)?;
47 let mut raw = sys::ImFontLoader::default();
48 raw.Name = name_cstring.as_ptr();
49
50 Ok(Self {
51 raw,
52 name: name_cstring,
53 })
54 }
55
56 pub(crate) fn as_ptr(&self) -> *const sys::ImFontLoader {
58 &self.raw
59 }
60
61 pub fn with_loader_init<F>(self, _callback: F) -> Self
63 where
64 F: Fn(&mut FontAtlas) -> bool + 'static,
65 {
66 self
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct FontLoaderFlags(pub u32);
75
76impl FontLoaderFlags {
77 pub const NONE: Self = Self(0);
79
80 pub const LOAD_COLOR: Self = Self(1 << 0);
82
83 pub const FORCE_AUTOHINT: Self = Self(1 << 1);
85
86 pub const NO_HINTING: Self = Self(1 << 2);
88
89 pub const NO_AUTOHINT: Self = Self(1 << 3);
91}
92
93impl std::ops::BitOr for FontLoaderFlags {
94 type Output = Self;
95 fn bitor(self, rhs: Self) -> Self::Output {
96 Self(self.0 | rhs.0)
97 }
98}
99
100impl std::ops::BitOrAssign for FontLoaderFlags {
101 fn bitor_assign(&mut self, rhs: Self) {
102 self.0 |= rhs.0;
103 }
104}
105
106#[derive(Debug, Clone)]
111pub struct SharedFontAtlas(pub(crate) Rc<*mut sys::ImFontAtlas>);
112
113impl SharedFontAtlas {
114 pub fn create() -> SharedFontAtlas {
116 unsafe {
117 let raw_atlas = sys::ImFontAtlas_ImFontAtlas();
118 SharedFontAtlas(Rc::new(raw_atlas))
119 }
120 }
121
122 pub(crate) fn as_ptr(&self) -> *const sys::ImFontAtlas {
124 *self.0
125 }
126
127 pub(crate) fn as_ptr_mut(&mut self) -> *mut sys::ImFontAtlas {
129 *self.0
130 }
131}
132
133impl Drop for SharedFontAtlas {
134 fn drop(&mut self) {
135 if Rc::strong_count(&self.0) == 1 {
137 unsafe {
138 let atlas_ptr = *self.0;
139 if !atlas_ptr.is_null() {
140 sys::ImFontAtlas_destroy(atlas_ptr);
141 }
142 }
143 }
144 }
145}
146
147impl FontAtlas {
148 pub fn new() -> Self {
150 unsafe {
151 let raw = sys::ImFontAtlas_ImFontAtlas();
152 Self {
153 raw,
154 owned: true,
155 _phantom: PhantomData,
156 }
157 }
158 }
159
160 pub fn with_font_loader(loader: &FontLoader) -> Self {
162 let mut atlas = Self::new();
163 atlas.set_font_loader(loader);
164 atlas
165 }
166
167 pub(crate) unsafe fn from_raw(raw: *mut sys::ImFontAtlas) -> Self {
172 Self {
173 raw,
174 owned: false,
175 _phantom: PhantomData,
176 }
177 }
178
179 pub fn raw(&self) -> *mut sys::ImFontAtlas {
181 self.raw
182 }
183
184 pub fn set_font_loader(&mut self, loader: &FontLoader) {
189 unsafe {
190 sys::ImFontAtlas_SetFontLoader(self.raw, loader.as_ptr());
191 }
192 }
193
194 pub fn set_font_loader_flags(&mut self, flags: FontLoaderFlags) {
199 unsafe {
200 (*self.raw).FontLoaderFlags = flags.0;
201 }
202 }
203
204 pub fn font_loader_flags(&self) -> FontLoaderFlags {
206 unsafe { FontLoaderFlags((*self.raw).FontLoaderFlags) }
207 }
208
209 #[doc(alias = "AddFont")]
211 pub fn add_font(&mut self, font_sources: &[FontSource<'_>]) -> crate::fonts::FontId {
212 let (head, tail) = font_sources.split_first().unwrap();
213 let font_id = self.add_font_internal(head, false);
214 for font in tail {
215 self.add_font_internal(font, true);
216 }
217 font_id
218 }
219
220 fn add_font_internal(
221 &mut self,
222 font_source: &FontSource<'_>,
223 _merge_mode: bool,
224 ) -> crate::fonts::FontId {
225 match font_source {
226 FontSource::DefaultFontData {
227 size_pixels,
228 config,
229 } => {
230 let size = size_pixels.unwrap_or(0.0);
232 let mut cfg = config.clone().unwrap_or_default();
233 if size > 0.0 {
234 cfg = cfg.size_pixels(size);
235 }
236 let font = self.add_font_default(Some(&cfg));
237 font.id()
238 }
239 FontSource::TtfData {
240 data,
241 size_pixels,
242 config,
243 } => {
244 let size = size_pixels.unwrap_or(0.0);
245 let mut cfg = config.clone().unwrap_or_default();
246 if size > 0.0 {
247 cfg = cfg.size_pixels(size);
248 }
249 let font = self
250 .add_font_from_memory_ttf(data, size, Some(&cfg), None)
251 .expect("Failed to add TTF font from memory");
252 font.id()
253 }
254 FontSource::TtfFile {
255 path,
256 size_pixels,
257 config,
258 } => {
259 let size = size_pixels.unwrap_or(0.0);
260 let mut cfg = config.clone().unwrap_or_default();
261 if size > 0.0 {
262 cfg = cfg.size_pixels(size);
263 }
264 let font = self
265 .add_font_from_file_ttf(path, size, Some(&cfg), None)
266 .expect("Failed to add TTF font from file");
267 font.id()
268 }
269 }
270 }
271
272 #[doc(alias = "AddFont")]
274 pub fn add_font_with_config(&mut self, font_cfg: &FontConfig) -> &mut Font {
275 unsafe {
276 let font_ptr = sys::ImFontAtlas_AddFont(self.raw, font_cfg.raw());
277 Font::from_raw_mut(font_ptr)
278 }
279 }
280
281 #[doc(alias = "AddFontDefault")]
283 pub fn add_font_default(&mut self, font_cfg: Option<&FontConfig>) -> &mut Font {
284 unsafe {
285 let cfg_ptr = font_cfg.map_or(ptr::null(), |cfg| cfg.raw());
286 let font_ptr = sys::ImFontAtlas_AddFontDefault(self.raw, cfg_ptr);
287 Font::from_raw_mut(font_ptr)
288 }
289 }
290
291 #[doc(alias = "AddFontFromFileTTF")]
293 pub fn add_font_from_file_ttf(
294 &mut self,
295 filename: &str,
296 size_pixels: f32,
297 font_cfg: Option<&FontConfig>,
298 glyph_ranges: Option<&[sys::ImWchar]>,
299 ) -> Option<&mut Font> {
300 unsafe {
301 let filename_cstr = std::ffi::CString::new(filename).ok()?;
302 let cfg_ptr = font_cfg.map_or(ptr::null(), |cfg| cfg.raw());
303 let ranges_ptr = glyph_ranges.map_or(ptr::null(), |ranges| ranges.as_ptr());
304
305 let font_ptr = sys::ImFontAtlas_AddFontFromFileTTF(
306 self.raw,
307 filename_cstr.as_ptr(),
308 size_pixels,
309 cfg_ptr,
310 ranges_ptr,
311 );
312
313 if font_ptr.is_null() {
314 None
315 } else {
316 Some(Font::from_raw_mut(font_ptr))
317 }
318 }
319 }
320
321 #[doc(alias = "AddFontFromMemoryTTF")]
323 pub fn add_font_from_memory_ttf(
324 &mut self,
325 font_data: &[u8],
326 size_pixels: f32,
327 font_cfg: Option<&FontConfig>,
328 glyph_ranges: Option<&[sys::ImWchar]>,
329 ) -> Option<&mut Font> {
330 unsafe {
331 let cfg_ptr = font_cfg.map_or(ptr::null(), |cfg| cfg.raw());
332 let ranges_ptr = glyph_ranges.map_or(ptr::null(), |ranges| ranges.as_ptr());
333
334 let font_ptr = sys::ImFontAtlas_AddFontFromMemoryTTF(
335 self.raw,
336 font_data.as_ptr() as *mut std::os::raw::c_void,
337 font_data.len() as i32,
338 size_pixels,
339 cfg_ptr,
340 ranges_ptr,
341 );
342
343 if font_ptr.is_null() {
344 None
345 } else {
346 Some(Font::from_raw_mut(font_ptr))
347 }
348 }
349 }
350
351 #[doc(alias = "RemoveFont")]
353 pub fn remove_font(&mut self, font: &mut Font) {
354 unsafe { sys::ImFontAtlas_RemoveFont(self.raw, font.raw()) }
355 }
356
357 #[doc(alias = "Clear")]
359 pub fn clear(&mut self) {
360 unsafe { sys::ImFontAtlas_Clear(self.raw) }
361 }
362
363 #[doc(alias = "ClearFonts")]
365 pub fn clear_fonts(&mut self) {
366 unsafe { sys::ImFontAtlas_ClearFonts(self.raw) }
367 }
368
369 #[doc(alias = "ClearTexData")]
371 pub fn clear_tex_data(&mut self) {
372 unsafe { sys::ImFontAtlas_ClearTexData(self.raw) }
373 }
374
375 #[doc(alias = "GetGlyphRangesDefault")]
377 pub fn get_glyph_ranges_default(&self) -> &[sys::ImWchar] {
378 unsafe {
379 let ptr = sys::ImFontAtlas_GetGlyphRangesDefault(self.raw);
380 if ptr.is_null() {
381 &[]
382 } else {
383 let mut len = 0;
385 while *ptr.add(len) != 0 {
386 len += 1;
387 }
388 std::slice::from_raw_parts(ptr, len)
389 }
390 }
391 }
392
393 #[doc(alias = "Build")]
397 pub fn build(&mut self) -> bool {
398 if self.raw.is_null() {
399 return false;
400 }
401 unsafe {
402 sys::igImFontAtlasBuildInit(self.raw);
404
405 sys::igImFontAtlasBuildMain(self.raw);
407
408 sys::igImFontAtlasBuildUpdatePointers(self.raw);
410
411 (*self.raw).TexIsBuilt
413 }
414 }
415
416 pub fn is_built(&self) -> bool {
418 if self.raw.is_null() {
419 return false;
420 }
421 unsafe { (*self.raw).TexIsBuilt }
422 }
423
424 pub fn get_tex_data_info(&self) -> Option<(u32, u32)> {
429 if self.raw.is_null() {
430 return None;
431 }
432 unsafe {
433 if (*self.raw).TexIsBuilt {
434 let min_width = (*self.raw).TexMinWidth as u32;
435 let min_height = (*self.raw).TexMinHeight as u32;
436 Some((min_width, min_height))
437 } else {
438 None
439 }
440 }
441 }
442
443 pub unsafe fn get_tex_data_ptr(&self) -> Option<(*const u8, u32, u32)> {
449 if self.raw.is_null() {
450 return None;
451 }
452 unsafe {
453 if (*self.raw).TexIsBuilt {
454 let tex_data = (*self.raw).TexData;
455 if !tex_data.is_null() {
456 let width = (*tex_data).Width as u32;
457 let height = (*tex_data).Height as u32;
458 let pixels = (*tex_data).Pixels;
459 if !pixels.is_null() {
460 Some((pixels, width, height))
461 } else {
462 None
463 }
464 } else {
465 None
466 }
467 } else {
468 None
469 }
470 }
471 }
472
473 pub fn get_tex_ref(&self) -> sys::ImTextureRef {
477 unsafe { (*self.raw).TexRef }
478 }
479
480 pub fn set_tex_ref(&mut self, tex_ref: sys::ImTextureRef) {
482 unsafe {
483 (*self.raw).TexRef = tex_ref;
484 }
485 }
486
487 pub fn tex_data_mut(&mut self) -> Option<&mut crate::texture::TextureData> {
489 let ptr = unsafe { (*self.raw).TexData };
490 if ptr.is_null() {
491 None
492 } else {
493 Some(unsafe { crate::texture::TextureData::from_raw(ptr) })
494 }
495 }
496
497 pub fn set_texture_id(&mut self, tex_id: crate::texture::TextureId) {
500 let tex_ref = sys::ImTextureRef {
502 _TexData: std::ptr::null_mut(),
503 _TexID: tex_id.id() as sys::ImTextureID,
504 };
505 self.set_tex_ref(tex_ref);
506
507 if let Some(td) = self.tex_data_mut() {
509 td.set_tex_id(tex_id);
510 td.set_status(crate::texture::TextureStatus::OK);
511 }
512 }
513
514 pub fn get_tex_data(&self) -> *mut sys::ImTextureData {
518 unsafe { (*self.raw).TexData }
519 }
520
521 pub fn get_tex_uv_scale(&self) -> [f32; 2] {
523 unsafe {
524 let scale = (*self.raw).TexUvScale;
525 [scale.x, scale.y]
526 }
527 }
528
529 pub fn get_tex_uv_white_pixel(&self) -> [f32; 2] {
531 unsafe {
532 let pixel = (*self.raw).TexUvWhitePixel;
533 [pixel.x, pixel.y]
534 }
535 }
536}
537
538impl Default for FontAtlas {
539 fn default() -> Self {
540 Self::new()
541 }
542}
543
544impl Drop for FontAtlas {
545 fn drop(&mut self) {
546 if self.owned && !self.raw.is_null() {
547 unsafe {
548 sys::ImFontAtlas_destroy(self.raw);
549 }
550 }
551 }
552}
553
554#[derive(Debug, Clone)]
559pub struct FontConfig {
560 raw: sys::ImFontConfig,
561}
562
563impl FontConfig {
564 pub fn new() -> Self {
566 Self {
567 raw: Default::default(),
568 }
569 }
570
571 pub(crate) fn raw(&self) -> *const sys::ImFontConfig {
573 &self.raw
574 }
575
576 pub fn size_pixels(mut self, size: f32) -> Self {
580 self.raw.SizePixels = size;
581 self
582 }
583
584 pub fn merge_mode(mut self, merge: bool) -> Self {
586 self.raw.MergeMode = merge;
587 self
588 }
589
590 pub fn font_loader_flags(mut self, flags: FontLoaderFlags) -> Self {
594 self.raw.FontLoaderFlags = flags.0;
595 self
596 }
597
598 pub fn glyph_exclude_ranges(mut self, ranges: &[u32]) -> Self {
602 self.raw.GlyphExcludeRanges = ranges.as_ptr() as *const sys::ImWchar;
603 self
604 }
605
606 pub fn font_loader(mut self, loader: &FontLoader) -> Self {
608 self.raw.FontLoader = loader.as_ptr();
609 self
610 }
611
612 pub fn name(mut self, name: &str) -> Self {
614 let name_bytes = name.as_bytes();
615 let copy_len = std::cmp::min(name_bytes.len(), self.raw.Name.len() - 1);
616
617 for i in 0..self.raw.Name.len() {
619 self.raw.Name[i] = 0;
620 }
621
622 for (i, &byte) in name_bytes.iter().take(copy_len).enumerate() {
624 self.raw.Name[i] = byte as i8;
625 }
626
627 self
628 }
629
630 pub fn glyph_offset(mut self, offset: [f32; 2]) -> Self {
632 self.raw.GlyphOffset.x = offset[0];
633 self.raw.GlyphOffset.y = offset[1];
634 self
635 }
636
637 pub fn glyph_min_advance_x(mut self, advance: f32) -> Self {
639 self.raw.GlyphMinAdvanceX = advance;
640 self
641 }
642
643 pub fn glyph_max_advance_x(mut self, advance: f32) -> Self {
645 self.raw.GlyphMaxAdvanceX = advance;
646 self
647 }
648
649 pub fn glyph_extra_advance_x(mut self, advance: f32) -> Self {
651 self.raw.GlyphExtraAdvanceX = advance;
652 self
653 }
654
655 pub fn rasterizer_multiply(mut self, multiply: f32) -> Self {
657 self.raw.RasterizerMultiply = multiply;
658 self
659 }
660
661 pub fn rasterizer_density(mut self, density: f32) -> Self {
663 self.raw.RasterizerDensity = density;
664 self
665 }
666
667 pub fn pixel_snap_h(mut self, snap: bool) -> Self {
669 self.raw.PixelSnapH = snap;
670 self
671 }
672
673 pub fn pixel_snap_v(mut self, snap: bool) -> Self {
675 self.raw.PixelSnapV = snap;
676 self
677 }
678
679 pub fn oversample_h(mut self, oversample: i8) -> Self {
681 self.raw.OversampleH = oversample;
682 self
683 }
684
685 pub fn oversample_v(mut self, oversample: i8) -> Self {
687 self.raw.OversampleV = oversample;
688 self
689 }
690}
691
692impl Default for FontConfig {
693 fn default() -> Self {
694 Self::new()
695 }
696}
697
698#[derive(Clone, Debug)]
700pub enum FontSource<'a> {
701 DefaultFontData {
705 size_pixels: Option<f32>,
706 config: Option<FontConfig>,
707 },
708
709 TtfData {
713 data: &'a [u8],
714 size_pixels: Option<f32>,
715 config: Option<FontConfig>,
716 },
717
718 TtfFile {
722 path: &'a str,
723 size_pixels: Option<f32>,
724 config: Option<FontConfig>,
725 },
726}
727
728impl<'a> FontSource<'a> {
729 pub fn default_font() -> Self {
731 Self::DefaultFontData {
732 size_pixels: None,
733 config: None,
734 }
735 }
736
737 pub fn default_font_with_size(size: f32) -> Self {
739 Self::DefaultFontData {
740 size_pixels: Some(size),
741 config: None,
742 }
743 }
744
745 pub fn ttf_data(data: &'a [u8]) -> Self {
747 Self::TtfData {
748 data,
749 size_pixels: None,
750 config: None,
751 }
752 }
753
754 pub fn ttf_data_with_size(data: &'a [u8], size: f32) -> Self {
756 Self::TtfData {
757 data,
758 size_pixels: Some(size),
759 config: None,
760 }
761 }
762
763 pub fn ttf_file(path: &'a str) -> Self {
765 Self::TtfFile {
766 path,
767 size_pixels: None,
768 config: None,
769 }
770 }
771
772 pub fn ttf_file_with_size(path: &'a str, size: f32) -> Self {
774 Self::TtfFile {
775 path,
776 size_pixels: Some(size),
777 config: None,
778 }
779 }
780
781 pub fn with_config(mut self, config: FontConfig) -> Self {
783 match &mut self {
784 Self::DefaultFontData { config: cfg, .. } => *cfg = Some(config),
785 Self::TtfData { config: cfg, .. } => *cfg = Some(config),
786 Self::TtfFile { config: cfg, .. } => *cfg = Some(config),
787 }
788 self
789 }
790}
791
792#[derive(Clone, Debug)]
794pub struct FontAtlasTexture<'a> {
795 pub width: u32,
797 pub height: u32,
799 pub data: &'a [u8],
805}