1use crate::{
2 style::is_plain_style,
3 text::{is_default_wrap_opts, Span, WrapOpts},
4 Style,
5};
6use serde::{Deserialize, Serialize};
7
8fn is_default_charset(c: &BoxCharset) -> bool {
9 *c == BoxCharset::default()
10}
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
14pub struct Frame {
15 pub ops: Vec<RenderOp>,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct BlitCell {
24 pub glyph: String,
25 #[serde(default, skip_serializing_if = "is_plain_style")]
26 pub style: Style,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
30#[serde(rename_all = "snake_case")]
31pub enum BoxCharset {
32 Ascii,
34 #[default]
36 UnicodeSingle,
37 UnicodeDouble,
39}
40
41fn is_default_truncate_mode(m: &TruncateMode) -> bool {
42 *m == TruncateMode::default()
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
46#[serde(rename_all = "snake_case")]
47pub enum TruncateMode {
48 #[default]
50 Clip,
51 Ellipsis,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56#[serde(tag = "op", rename_all = "snake_case")]
57pub enum RenderOp {
58 Clear,
60
61 ClearLine { y: u16 },
66
67 ClearEol { x: u16, y: u16 },
71
72 ClearBol { x: u16, y: u16 },
76
77 ClearEos { x: u16, y: u16 },
81
82 ClearRect { x: u16, y: u16, w: u16, h: u16 },
86
87 Put {
89 x: u16,
90 y: u16,
91 text: String,
92 #[serde(default, skip_serializing_if = "is_plain_style")]
93 style: Style,
94 },
95
96 PutGlyph {
98 x: u16,
99 y: u16,
100 glyph: String,
101 #[serde(default, skip_serializing_if = "is_plain_style")]
102 style: Style,
103 },
104
105 Label {
109 x: u16,
110 y: u16,
111 w: u16,
113 text: String,
114 #[serde(default, skip_serializing_if = "is_plain_style")]
115 style: Style,
116 #[serde(default, skip_serializing_if = "is_default_truncate_mode")]
117 truncate: TruncateMode,
118 },
119
120 LabelStyled {
124 x: u16,
125 y: u16,
126 w: u16,
128 spans: Vec<Span>,
129 #[serde(default, skip_serializing_if = "is_default_truncate_mode")]
130 truncate: TruncateMode,
131 },
132
133 TextBlock {
137 x: u16,
138 y: u16,
139 w: u16,
140 h: u16,
141 text: String,
142 #[serde(default, skip_serializing_if = "is_plain_style")]
143 style: Style,
144 #[serde(default, skip_serializing_if = "is_default_wrap_opts")]
145 wrap: WrapOpts,
146 },
147
148 TextBlockStyled {
150 x: u16,
151 y: u16,
152 w: u16,
153 h: u16,
154 spans: Vec<Span>,
155 #[serde(default, skip_serializing_if = "is_default_wrap_opts")]
156 wrap: WrapOpts,
157 },
158
159 FillRect {
161 x: u16,
162 y: u16,
163 w: u16,
164 h: u16,
165 glyph: String,
166 #[serde(default, skip_serializing_if = "is_plain_style")]
167 style: Style,
168 },
169
170 Box {
172 x: u16,
173 y: u16,
174 w: u16,
175 h: u16,
176 #[serde(default, skip_serializing_if = "is_default_charset")]
177 charset: BoxCharset,
178 #[serde(default, skip_serializing_if = "is_plain_style")]
179 style: Style,
180 },
181
182 Blit {
186 x: u16,
187 y: u16,
188 w: u16,
189 h: u16,
190 cells: Vec<Option<BlitCell>>,
191 },
192}