1use core::ffi::{c_int, c_char};
4
5use alloc::ffi::NulError;
6use alloc::boxed::Box;
7use fs::Path;
8use sys::ffi::{CString, CStr, LCDFont, LCDFontGlyph, LCDFontPage, LCDBitmap};
9use sys::traits::AsRaw;
10
11pub use sys::ffi::PDStringEncoding as StringEncoding;
12pub use sys::ffi::PDTextWrappingMode as TextWrappingMode;
13pub use sys::ffi::PDTextAlignment as TextAlignment;
14
15use crate::Graphics;
16use crate::bitmap::BitmapRef;
17use crate::error::{Error, ApiError};
18
19
20#[doc(alias = "sys::ffi::playdate_graphics::drawText")]
33#[inline(always)]
34pub fn draw_text<S: AsRef<str>>(text: S, x: c_int, y: c_int) -> Result<c_int, NulError> {
35 Graphics::Default().draw_text(text, x, y)
36}
37
38#[doc(alias = "sys::ffi::playdate_graphics::drawText")]
51#[inline(always)]
52pub fn draw_text_cstr(text: &CStr, encoding: StringEncoding, x: c_int, y: c_int) -> c_int {
53 Graphics::Default().draw_text_cstr(text, encoding, x, y)
54}
55
56#[doc(alias = "sys::ffi::playdate_graphics::drawText")]
66#[inline(always)]
67pub fn draw_text_in_rect<S: AsRef<str>>(text: S,
68 x: c_int,
69 y: c_int,
70 width: c_int,
71 height: c_int,
72 wrap: TextWrappingMode,
73 align: TextAlignment)
74 -> Result<(), NulError> {
75 Graphics::Default().draw_text_in_rect(text, x, y, width, height, wrap, align)
76}
77
78#[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")]
85#[inline(always)]
86pub fn get_text_width<S: AsRef<str>>(text: S, font: Option<&Font>, tracking: c_int) -> Result<c_int, NulError> {
87 Graphics::Default().get_text_width(text, font, tracking)
88}
89
90#[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")]
100#[inline(always)]
101pub fn get_text_width_cstr(text: &CStr, encoding: StringEncoding, font: Option<&Font>, tracking: c_int) -> c_int {
102 Graphics::Default().get_text_width_cstr(text, encoding, font, tracking)
103}
104
105
106#[doc(alias = "sys::ffi::playdate_graphics::getFontHeight")]
113#[inline(always)]
114pub fn get_font_height(font: &Font) -> u8 { Graphics::Default().get_font_height(font) }
115
116#[doc(alias = "sys::ffi::playdate_graphics::setFont")]
123#[inline(always)]
124pub fn set_font(font: &Font) { Graphics::Default().set_font(font) }
125
126#[doc(alias = "sys::ffi::playdate_graphics::getGlyphKerning")]
133#[inline(always)]
134pub fn get_glyph_kerning(glyph: &Glyph, glyph_code: u32, next_code: u32) -> c_int {
135 Graphics::Default().get_glyph_kerning(glyph, glyph_code, next_code)
136}
137
138#[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")]
148#[inline(always)]
149pub fn get_page_glyph(page: &FontPage, c: u32) -> Result<Glyph, Error> {
150 Graphics::Default().get_page_glyph(page, c)
151}
152
153#[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")]
163#[inline(always)]
164pub fn get_page_glyph_with_bitmap<'p>(page: &'p FontPage,
165 c: u32,
166 advance: &mut c_int)
167 -> Result<(Glyph, BitmapRef<'p>), Error> {
168 Graphics::Default().get_page_glyph_with_bitmap(page, c, advance)
169}
170
171
172#[doc(alias = "sys::ffi::playdate_graphics::getFontPage")]
184#[inline(always)]
185pub fn get_font_page(font: &Font, c: u32) -> Result<FontPage, Error> {
186 Graphics::Default().get_font_page(font, c)
187}
188
189
190#[doc(alias = "sys::ffi::playdate_graphics::loadFont")]
197#[inline(always)]
198pub fn load_font<P: AsRef<Path>>(path: P) -> Result<Font, ApiError> { Graphics::Default().load_font(path) }
199
200
201#[doc(alias = "sys::ffi::playdate_graphics::makeFontFromData")]
214#[inline(always)]
215pub fn make_font_from_bytes(data: &[u8], wide: c_int) -> Result<Font, Error> {
216 Graphics::Default().make_font_from_bytes(data, wide)
217}
218
219
220#[doc(alias = "sys::ffi::playdate_graphics::setTextLeading")]
227#[inline(always)]
228pub fn set_text_leading(line_height_adjustment: c_int) {
229 Graphics::Default().set_text_leading(line_height_adjustment)
230}
231
232#[doc(alias = "sys::ffi::playdate_graphics::setTextTracking")]
239#[inline(always)]
240pub fn set_text_tracking(tracking: c_int) { Graphics::Default().set_text_tracking(tracking) }
241
242
243#[doc(alias = "sys::ffi::playdate_graphics::getTextTracking")]
250#[inline(always)]
251pub fn get_text_tracking() -> c_int { Graphics::Default().get_text_tracking() }
252
253
254impl<Api: crate::api::Api> Graphics<Api> {
255 #[doc(alias = "sys::ffi::playdate_graphics::drawText")]
265 pub fn draw_text<S: AsRef<str>>(&self, text: S, x: c_int, y: c_int) -> Result<c_int, NulError> {
266 let s = CString::new(text.as_ref())?;
267 let f = self.0.draw_text();
268 let res = unsafe { f(s.as_ptr().cast(), text.as_ref().len(), StringEncoding::UTF8, x, y) };
269 Ok(res)
270 }
271
272 #[doc(alias = "sys::ffi::playdate_graphics::drawText")]
282 pub fn draw_text_cstr(&self, text: &CStr, encoding: StringEncoding, x: c_int, y: c_int) -> c_int {
283 let f = self.0.draw_text();
284 let len = text.to_bytes().len();
285 unsafe { f(text.as_ptr().cast(), len, encoding, x, y) }
286 }
287
288 #[doc(alias = "sys::ffi::playdate_graphics::drawTextInRect")]
295 pub fn draw_text_in_rect<S: AsRef<str>>(&self,
296 text: S,
297 x: c_int,
298 y: c_int,
299 width: c_int,
300 height: c_int,
301 wrap: TextWrappingMode,
302 align: TextAlignment)
303 -> Result<(), NulError> {
304 let s = CString::new(text.as_ref())?;
305 let f = self.0.draw_text_in_rect();
306 let res = unsafe {
307 f(
308 s.as_ptr().cast(),
309 text.as_ref().len(),
310 StringEncoding::UTF8,
311 x,
312 y,
313 width,
314 height,
315 wrap,
316 align,
317 )
318 };
319 Ok(res)
320 }
321
322 #[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")]
326 pub fn get_text_width<S: AsRef<str>>(&self,
327 text: S,
328 font: Option<&Font>,
329 tracking: c_int)
330 -> Result<c_int, NulError> {
331 let s = CString::new(text.as_ref())?;
332 let f = self.0.get_text_width();
333 let font = font.map(|font| unsafe { font.as_raw() })
334 .unwrap_or(core::ptr::null_mut());
335 let res = unsafe {
336 f(
337 font,
338 s.as_ptr().cast(),
339 text.as_ref().len(),
340 StringEncoding::UTF8,
341 tracking,
342 )
343 };
344 Ok(res)
345 }
346
347 #[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")]
354 pub fn get_text_width_cstr(&self,
355 text: &CStr,
356 encoding: StringEncoding,
357 font: Option<&Font>,
358 tracking: c_int)
359 -> c_int {
360 let f = self.0.get_text_width();
361 let len = text.to_bytes().len();
362 let font = font.map(|font| unsafe { font.as_raw() })
363 .unwrap_or(core::ptr::null_mut());
364 unsafe { f(font, text.as_ptr().cast(), len, encoding, tracking) }
365 }
366
367
368 #[doc(alias = "sys::ffi::playdate_graphics::getFontHeight")]
372 pub fn get_font_height(&self, font: &Font) -> u8 {
373 let f = self.0.get_font_height();
374 unsafe { f(font.as_raw()) }
375 }
376
377 #[doc(alias = "sys::ffi::playdate_graphics::setFont")]
381 pub fn set_font(&self, font: &Font) {
382 let f = self.0.set_font();
383 unsafe { f(font.as_raw()) }
384 }
385
386 #[doc(alias = "sys::ffi::playdate_graphics::getGlyphKerning")]
390 pub fn get_glyph_kerning(&self, glyph: &Glyph, glyph_code: u32, next_code: u32) -> c_int {
391 let f = self.0.get_glyph_kerning();
392 unsafe { f(glyph.as_raw(), glyph_code, next_code) }
393 }
394
395 #[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")]
402 pub fn get_page_glyph(&self, page: &FontPage, c: u32) -> Result<Glyph, Error> {
403 let f = self.0.get_page_glyph();
404 let ptr = unsafe { f(page.as_raw(), c, core::ptr::null_mut(), core::ptr::null_mut()) };
405
406 if ptr.is_null() {
407 Err(Error::Font)
408 } else {
409 Ok(Glyph(ptr))
410 }
411 }
412
413 #[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")]
420 pub fn get_page_glyph_with_bitmap<'p>(&self,
421 page: &'p FontPage,
422 c: u32,
423 advance: &mut c_int)
424 -> Result<(Glyph, BitmapRef<'p>), Error> {
425 let bitmap = Box::new(core::ptr::null_mut() as *mut LCDBitmap);
426 let out_bitmap = Box::into_raw(bitmap);
427
428 let f = self.0.get_page_glyph();
429 let ptr = unsafe { f(page.as_raw(), c, out_bitmap, advance) };
430
431 if ptr.is_null() {
432 Err(Error::Font)
433 } else {
434 let bitmap = unsafe { Box::from_raw(out_bitmap) };
435 if bitmap.is_null() {
436 Err(Error::Font)
437 } else {
438 Ok((Glyph(ptr), BitmapRef::from(*bitmap)))
439 }
440 }
441 }
442
443
444 #[doc(alias = "sys::ffi::playdate_graphics::getFontPage")]
453 pub fn get_font_page(&self, font: &Font, c: u32) -> Result<FontPage, Error> {
454 let f = self.0.get_font_page();
455 let ptr = unsafe { f(font.as_raw(), c) };
456
457 if ptr.is_null() {
458 Err(Error::Font)
459 } else {
460 Ok(FontPage(ptr))
461 }
462 }
463
464
465 #[doc(alias = "sys::ffi::playdate_graphics::loadFont")]
469 pub fn load_font<P: AsRef<Path>>(&self, path: P) -> Result<Font, ApiError> {
470 let mut err = Box::new(core::ptr::null() as *const c_char);
471 let out_err = Box::into_raw(err);
472
473 let path = CString::new(path.as_ref())?;
474
475 let f = self.0.load_font();
476 let ptr = unsafe { f(path.as_ptr() as *mut c_char, out_err as _) };
477
478 if ptr.is_null() {
479 err = unsafe { Box::from_raw(out_err) };
480 if let Some(err) = fs::error::Error::from_ptr(*err) {
481 Err(Error::Fs(err).into())
482 } else {
483 Err(Error::Alloc.into())
484 }
485 } else {
486 Ok(Font(ptr))
487 }
488 }
489
490
491 #[doc(alias = "sys::ffi::playdate_graphics::makeFontFromData")]
501 pub fn make_font_from_bytes(&self, data: &[u8], wide: c_int) -> Result<Font, Error> {
502 let f = self.0.make_font_from_data();
503 let ptr = unsafe { f(data.as_ptr() as _, wide) };
504
505 if ptr.is_null() {
506 Err(Error::Alloc)
507 } else {
508 Ok(Font(ptr))
509 }
510 }
511
512
513 #[doc(alias = "sys::ffi::playdate_graphics::setTextLeading")]
517 pub fn set_text_leading(&self, line_height_adjustment: c_int) {
518 let f = self.0.set_text_leading();
519 unsafe { f(line_height_adjustment) }
520 }
521
522 #[doc(alias = "sys::ffi::playdate_graphics::setTextTracking")]
526 pub fn set_text_tracking(&self, tracking: c_int) {
527 let f = self.0.set_text_tracking();
528 unsafe { f(tracking) }
529 }
530
531 #[doc(alias = "sys::ffi::playdate_graphics::getTextTracking")]
535 pub fn get_text_tracking(&self) -> c_int {
536 let f = self.0.get_text_tracking();
537 unsafe { f() }
538 }
539}
540
541
542pub struct Font(*mut LCDFont);
548
549impl AsRaw for Font {
550 type Type = LCDFont;
551 unsafe fn as_raw(&self) -> *mut Self::Type { self.0 }
552}
553
554pub struct Glyph(*mut LCDFontGlyph);
556
557impl AsRaw for Glyph {
558 type Type = LCDFontGlyph;
559 unsafe fn as_raw(&self) -> *mut Self::Type { self.0 }
560}
561
562pub struct FontPage(*mut LCDFontPage);
564
565impl AsRaw for FontPage {
566 type Type = LCDFontPage;
567 unsafe fn as_raw(&self) -> *mut Self::Type { self.0 }
568}
569
570
571pub trait StringEncodingExt {
572 #![allow(non_upper_case_globals)]
573 const ASCII: StringEncoding = StringEncoding::kASCIIEncoding;
574 const UTF8: StringEncoding = StringEncoding::kUTF8Encoding;
575 const LE16Bit: StringEncoding = StringEncoding::k16BitLEEncoding;
576}
577impl StringEncodingExt for StringEncoding {}
578
579pub trait TextWrappingModeExt {
580 #![allow(non_upper_case_globals)]
581 const Clip: TextWrappingMode = TextWrappingMode::kWrapClip;
582 const Character: TextWrappingMode = TextWrappingMode::kWrapCharacter;
583 const Word: TextWrappingMode = TextWrappingMode::kWrapWord;
584}
585impl TextWrappingModeExt for TextWrappingMode {}
586
587pub trait TextAlignmentExt {
588 #![allow(non_upper_case_globals)]
589 const Left: TextAlignment = TextAlignment::kAlignTextLeft;
590 const Center: TextAlignment = TextAlignment::kAlignTextCenter;
591 const Right: TextAlignment = TextAlignment::kAlignTextRight;
592}
593impl TextAlignmentExt for TextAlignment {}
594
595
596pub mod api {
597 use core::ffi::c_char;
598 use core::ffi::c_int;
599 use core::ffi::c_void;
600
601 use sys::ffi::LCDBitmap;
602 use sys::ffi::LCDFont;
603 use sys::ffi::LCDFontData;
604 use sys::ffi::LCDFontGlyph;
605 use sys::ffi::LCDFontPage;
606 use sys::ffi::PDStringEncoding;
607 use sys::ffi::PDTextWrappingMode;
608 use sys::ffi::PDTextAlignment;
609
610
611 pub type Default = crate::api::Default;
615
616 pub type Cache = crate::api::Cache;
622
623
624 pub trait Api {
626 #[doc(alias = "sys::ffi::playdate_graphics::drawText")]
628 #[inline(always)]
629 fn draw_text(
630 &self)
631 -> unsafe extern "C" fn(text: *const c_void,
632 len: usize,
633 encoding: PDStringEncoding,
634 x: c_int,
635 y: c_int) -> c_int {
636 *sys::api!(graphics.drawText)
637 }
638
639 #[doc(alias = "sys::ffi::playdate_graphics::drawTextInRect")]
641 #[inline(always)]
642 fn draw_text_in_rect(
643 &self)
644 -> unsafe extern "C" fn(text: *const c_void,
645 len: usize,
646 encoding: PDStringEncoding,
647 x: c_int,
648 y: c_int,
649 width: c_int,
650 height: c_int,
651 wrap: PDTextWrappingMode,
652 align: PDTextAlignment) {
653 *sys::api!(graphics.drawTextInRect)
654 }
655
656 #[doc(alias = "sys::ffi::playdate_graphics::getTextWidth")]
658 #[inline(always)]
659 fn get_text_width(
660 &self)
661 -> unsafe extern "C" fn(font: *mut LCDFont,
662 text: *const c_void,
663 len: usize,
664 encoding: PDStringEncoding,
665 tracking: c_int) -> c_int {
666 *sys::api!(graphics.getTextWidth)
667 }
668
669 #[doc(alias = "sys::ffi::playdate_graphics::getFontHeight")]
671 #[inline(always)]
672 fn get_font_height(&self) -> unsafe extern "C" fn(font: *mut LCDFont) -> u8 {
673 *sys::api!(graphics.getFontHeight)
674 }
675
676 #[doc(alias = "sys::ffi::playdate_graphics::setFont")]
678 #[inline(always)]
679 fn set_font(&self) -> unsafe extern "C" fn(font: *mut LCDFont) { *sys::api!(graphics.setFont) }
680
681 #[doc(alias = "sys::ffi::playdate_graphics::setTextTracking")]
683 #[inline(always)]
684 fn set_text_tracking(&self) -> unsafe extern "C" fn(tracking: c_int) {
685 *sys::api!(graphics.setTextTracking)
686 }
687
688 #[doc(alias = "sys::ffi::playdate_graphics::getTextTracking")]
690 #[inline(always)]
691 fn get_text_tracking(&self) -> unsafe extern "C" fn() -> c_int { *sys::api!(graphics.getTextTracking) }
692
693 #[doc(alias = "sys::ffi::playdate_graphics::getGlyphKerning")]
695 #[inline(always)]
696 fn get_glyph_kerning(
697 &self)
698 -> unsafe extern "C" fn(glyph: *mut LCDFontGlyph, glyphcode: u32, nextcode: u32) -> c_int {
699 *sys::api!(graphics.getGlyphKerning)
700 }
701
702 #[doc(alias = "sys::ffi::playdate_graphics::loadFont")]
704 #[inline(always)]
705 fn load_font(&self)
706 -> unsafe extern "C" fn(path: *const c_char, outErr: *mut *const c_char) -> *mut LCDFont {
707 *sys::api!(graphics.loadFont)
708 }
709
710 #[doc(alias = "sys::ffi::playdate_graphics::getFontPage")]
712 #[inline(always)]
713 fn get_font_page(&self) -> unsafe extern "C" fn(font: *mut LCDFont, c: u32) -> *mut LCDFontPage {
714 *sys::api!(graphics.getFontPage)
715 }
716
717 #[doc(alias = "sys::ffi::playdate_graphics::getPageGlyph")]
719 #[inline(always)]
720 fn get_page_glyph(
721 &self)
722 -> unsafe extern "C" fn(page: *mut LCDFontPage,
723 c: u32,
724 bitmap: *mut *mut LCDBitmap,
725 advance: *mut c_int) -> *mut LCDFontGlyph {
726 *sys::api!(graphics.getPageGlyph)
727 }
728
729 #[doc(alias = "sys::ffi::playdate_graphics::makeFontFromData")]
731 #[inline(always)]
732 fn make_font_from_data(&self) -> unsafe extern "C" fn(data: *mut LCDFontData, wide: c_int) -> *mut LCDFont {
733 *sys::api!(graphics.makeFontFromData)
734 }
735
736 #[doc(alias = "sys::ffi::playdate_graphics::setTextLeading")]
738 #[inline(always)]
739 fn set_text_leading(&self) -> unsafe extern "C" fn(lineHeightAdjustment: c_int) {
740 *sys::api!(graphics.setTextLeading)
741 }
742 }
743}