ascii_forge/renderer/
render.rs1use std::{fmt::Display, marker::PhantomData};
2
3use crate::prelude::*;
4
5#[macro_export]
25macro_rules! render {
26 ($buffer:expr, $( $loc:expr => [$($render:expr),* $(,)?]),* $(,)? ) => {{
27 #[allow(unused_mut)]
28 let mut loc;
29 $(
30 loc = Vec2::from($loc);
31 $(loc = $render.render(loc, $buffer.as_mut()));*;
32 let _ = loc;
33 )*
34 loc
35 }};
36}
37
38pub trait Render {
41 fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2;
42 fn size(&self) -> Vec2 {
43 let mut buf = Buffer::new((u16::MAX, u16::MAX));
44 render!(buf, vec2(0, 0) => [ self ]);
45 buf.shrink();
46 buf.size()
47 }
48}
49
50impl Render for char {
52 fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2 {
53 buffer.set(loc, *self);
54 loc
55 }
56 fn size(&self) -> Vec2 {
57 vec2(1, 1)
58 }
59}
60
61impl Render for &str {
62 fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2 {
63 render!(buffer, loc => [ StyledContent::new(ContentStyle::default(), self) ])
64 }
65 fn size(&self) -> Vec2 {
66 StyledContent::new(ContentStyle::default(), self).size()
67 }
68}
69
70impl<R: Render + 'static> From<R> for Box<dyn Render> {
71 fn from(value: R) -> Self {
72 Box::new(value)
73 }
74}
75
76impl<R: Into<Box<dyn Render>> + Clone> Render for Vec<R> {
77 fn render(&self, mut loc: Vec2, buffer: &mut Buffer) -> Vec2 {
78 let items: Vec<Box<dyn Render>> = self.iter().map(|x| x.clone().into()).collect();
79 for item in items {
80 loc = render!(buffer, loc => [ item ]);
81 }
82 loc
83 }
84}
85
86pub struct CharString<D: Display, F: Into<StyledContent<D>> + Clone> {
89 pub text: F,
90 marker: PhantomData<D>,
91}
92
93impl<D: Display, F: Into<StyledContent<D>> + Clone> CharString<D, F> {
94 pub fn new(text: F) -> Self {
95 Self {
96 text,
97 marker: PhantomData {},
98 }
99 }
100}
101
102impl<D: Display, F: Into<StyledContent<D>> + Clone> Render for CharString<D, F> {
103 fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2 {
104 render!(buffer, loc => [ Cell::styled(self.text.clone().into()) ])
105 }
106}
107
108impl Render for String {
109 fn render(&self, loc: Vec2, buffer: &mut Buffer) -> Vec2 {
110 render!(buffer, loc => [ self.as_str() ])
111 }
112}
113
114impl<D: Display> Render for StyledContent<D> {
115 fn render(&self, mut loc: Vec2, buffer: &mut Buffer) -> Vec2 {
116 let base_x = loc.x;
117 for line in format!("{}", self.content()).split('\n') {
118 loc.x = base_x;
119 for char in line.chars().collect::<Vec<char>>() {
120 buffer.set(loc, StyledContent::new(*self.style(), char));
121 loc.x += 1;
122 }
123 loc.y += 1;
124 }
125 loc.y -= 1;
126 loc
127 }
128 fn size(&self) -> Vec2 {
129 let mut width = 0;
130 let mut height = 0;
131 for line in format!("{}", self.content()).split('\n') {
132 width = line.chars().count().max(width);
133 height += 1;
134 }
135 vec2(width as u16, height)
136 }
137}