#![cfg_attr(not(test), no_std)]
#![deny(clippy::missing_inline_in_public_items)]
#![deny(clippy::cargo)]
#![deny(missing_docs)]
#![warn(clippy::all)]
#![allow(clippy::needless_doctest_main)]
pub mod alignment;
pub mod parser;
pub mod rendering;
pub mod style;
pub mod utils;
use alignment::{HorizontalTextAlignment, VerticalTextAlignment};
use embedded_graphics::{prelude::*, primitives::Rectangle};
use rendering::RendererFactory;
use style::{height_mode::HeightMode, TextBoxStyle};
use utils::rect_ext::RectExt;
pub mod prelude {
#[doc(no_inline)]
pub use crate::{
alignment::*,
style::{
height_mode::{Exact, FitToText, HeightMode, ShrinkToText},
TabSize, TextBoxStyle, TextBoxStyleBuilder,
},
StyledTextBox, TextBox,
};
#[doc(no_inline)]
pub use embedded_graphics::{
primitives::Rectangle,
style::{TextStyle, TextStyleBuilder},
};
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct TextBox<'a> {
pub text: &'a str,
pub bounds: Rectangle,
}
impl<'a> TextBox<'a> {
#[inline]
#[must_use]
pub fn new(text: &'a str, bounds: Rectangle) -> Self {
Self {
text,
bounds: bounds.into_well_formed(),
}
}
#[inline]
#[must_use]
pub fn into_styled<C, F, A, V, H>(
self,
style: TextBoxStyle<C, F, A, V, H>,
) -> StyledTextBox<'a, C, F, A, V, H>
where
C: PixelColor,
F: Font + Copy,
A: HorizontalTextAlignment,
V: VerticalTextAlignment,
H: HeightMode,
{
let mut styled = StyledTextBox {
text_box: self,
style,
};
H::apply(&mut styled);
styled
}
}
impl Transform for TextBox<'_> {
#[inline]
#[must_use]
fn translate(&self, by: Point) -> Self {
Self {
bounds: self.bounds.translate(by),
..*self
}
}
#[inline]
fn translate_mut(&mut self, by: Point) -> &mut Self {
self.bounds.translate_mut(by);
self
}
}
impl Dimensions for TextBox<'_> {
#[inline]
#[must_use]
fn top_left(&self) -> Point {
self.bounds.top_left
}
#[inline]
#[must_use]
fn bottom_right(&self) -> Point {
self.bounds.bottom_right
}
#[inline]
#[must_use]
fn size(&self) -> Size {
RectExt::size(self.bounds)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct StyledTextBox<'a, C, F, A, V, H>
where
C: PixelColor,
F: Font + Copy,
A: HorizontalTextAlignment,
V: VerticalTextAlignment,
H: HeightMode,
{
pub text_box: TextBox<'a>,
pub style: TextBoxStyle<C, F, A, V, H>,
}
impl<C, F, A, V, H> StyledTextBox<'_, C, F, A, V, H>
where
C: PixelColor,
F: Font + Copy,
A: HorizontalTextAlignment,
V: VerticalTextAlignment,
H: HeightMode,
{
#[inline]
pub fn fit_height(&mut self) -> &mut Self {
self.fit_height_limited(u32::max_value())
}
#[inline]
pub fn fit_height_limited(&mut self, max_height: u32) -> &mut Self {
let text_height = self
.style
.measure_text_height(self.text_box.text, self.text_box.size().width)
.min(max_height)
.min(i32::max_value() as u32) as i32;
let y = self.text_box.bounds.top_left.y;
let new_y = y.saturating_add(text_height - 1);
self.text_box.bounds.bottom_right.y = new_y;
self
}
}
impl<'a, C, F, A, V, H> Drawable<C> for &'a StyledTextBox<'a, C, F, A, V, H>
where
C: PixelColor,
F: Font + Copy,
A: HorizontalTextAlignment,
V: VerticalTextAlignment,
StyledTextBox<'a, C, F, A, V, H>: RendererFactory<'a, C>,
H: HeightMode,
{
#[inline]
fn draw<D: DrawTarget<C>>(self, display: &mut D) -> Result<(), D::Error> {
display.draw_iter(StyledTextBox::create_renderer(self))
}
}
impl<C, F, A, V, H> Transform for StyledTextBox<'_, C, F, A, V, H>
where
C: PixelColor,
F: Font + Copy,
A: HorizontalTextAlignment,
V: VerticalTextAlignment,
H: HeightMode,
{
#[inline]
#[must_use]
fn translate(&self, by: Point) -> Self {
Self {
text_box: self.text_box.translate(by),
style: self.style,
}
}
#[inline]
fn translate_mut(&mut self, by: Point) -> &mut Self {
self.text_box.bounds.translate_mut(by);
self
}
}
impl<C, F, A, V, H> Dimensions for StyledTextBox<'_, C, F, A, V, H>
where
C: PixelColor,
F: Font + Copy,
A: HorizontalTextAlignment,
V: VerticalTextAlignment,
H: HeightMode,
{
#[inline]
#[must_use]
fn top_left(&self) -> Point {
self.text_box.bounds.top_left
}
#[inline]
#[must_use]
fn bottom_right(&self) -> Point {
self.text_box.bounds.bottom_right
}
#[inline]
#[must_use]
fn size(&self) -> Size {
self.text_box.size()
}
}