use super::{RenderExt, RenderMode};
use crate::{
color::Rgba,
geo::{Point, Rect, Size},
renderer::{pen::Pen, Paster},
texture::Texture,
ttf::font::Font,
};
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum TextAlignX {
Left,
Center,
Right,
}
impl Default for TextAlignX {
fn default() -> Self {
Self::Left
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum TextAlignY {
Top,
Center,
Bottom,
}
impl Default for TextAlignY {
fn default() -> Self {
Self::Top
}
}
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
pub struct TextAlign {
pub x: TextAlignX,
pub y: TextAlignY,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FontRenderOptions {
align: TextAlign,
pivot: Point,
mode: RenderMode,
}
impl FontRenderOptions {
pub fn new() -> Self {
FontRenderOptions {
align: TextAlign::default(),
pivot: Point::default(),
mode: RenderMode::Blended {
foreground: Rgba {
r: 0,
g: 0,
b: 0,
a: 255,
},
},
}
}
pub fn mode(mut self, mode: RenderMode) -> Self {
self.mode = mode;
self
}
pub fn align(mut self, align: TextAlign) -> Self {
self.align = align;
self
}
pub fn pivot(mut self, pivot: Point) -> Self {
self.pivot = pivot;
self
}
fn aligned_pos(&self, Size { width, height }: Size) -> Point {
let x = match self.align.x {
TextAlignX::Left => self.pivot.x,
TextAlignX::Center => self.pivot.x - width as i32 / 2,
TextAlignX::Right => self.pivot.x - width as i32,
};
let y = match self.align.y {
TextAlignY::Top => self.pivot.y,
TextAlignY::Center => self.pivot.y - height as i32 / 2,
TextAlignY::Bottom => self.pivot.y - height as i32,
};
Point { x, y }
}
}
impl Default for FontRenderOptions {
fn default() -> Self {
Self::new()
}
}
pub trait FontRenderExt {
fn text(&self, font: &Font, text: &str, options: FontRenderOptions);
}
impl FontRenderExt for Pen<'_> {
fn text(&self, font: &Font, text: &str, options: FontRenderOptions) {
if text.is_empty() {
return;
}
let surface = font
.render(text, options.mode)
.expect("rendering text failed");
let texture = Texture::from_surface(self.renderer(), &surface);
let size = font
.rendered_size(text)
.expect("calculating text size failed");
let up_left = options.aligned_pos(size);
Paster::new(self.renderer()).paste(&texture, Some(Rect { up_left, size }));
}
}