1use crate::{Grapheme, TextStyle, View};
2
3use super::cell_primitives::CellPath;
4use super::command::{CellsCommand, RecordedCommand, TextCommand, ViewCommand};
5use super::line_network::LineNetwork;
6use super::{Composition, Position, PositionedCell};
7use crate::view::geometry::Size;
8
9#[derive(Debug)]
11pub struct CanvasContext {
12 size: Size,
13 commands: Vec<RecordedCommand>,
14}
15
16impl CanvasContext {
17 pub(super) fn new(size: Size) -> Self {
18 Self {
19 size,
20 commands: Vec::new(),
21 }
22 }
23
24 pub const fn size(&self) -> Size {
25 self.size
26 }
27
28 pub const fn bounds(&self) -> (Position, Size) {
29 (Position::new(0, 0), self.size)
30 }
31
32 pub fn view(
37 &mut self,
38 origin: Position,
39 view: View,
40 width: Option<usize>,
41 height: Option<usize>,
42 ) {
43 self.view_with(origin, view, width, height, Composition::Replace);
44 }
45
46 pub fn view_with(
50 &mut self,
51 origin: Position,
52 view: View,
53 width: Option<usize>,
54 height: Option<usize>,
55 composition: Composition,
56 ) {
57 self.record(
58 ViewCommand {
59 origin,
60 view,
61 allocation: (width, height),
62 },
63 composition,
64 );
65 }
66
67 pub fn text(&mut self, origin: Position, text: impl Into<String>, style: TextStyle) {
71 self.text_with(origin, text, style, Composition::Overlay);
72 }
73
74 pub fn text_with(
78 &mut self,
79 origin: Position,
80 text: impl Into<String>,
81 style: TextStyle,
82 composition: Composition,
83 ) {
84 self.record(
85 TextCommand {
86 origin,
87 text: text.into(),
88 style,
89 },
90 composition,
91 );
92 }
93
94 pub fn line(&mut self, from: Position, to: Position, marker: &Grapheme, style: TextStyle) {
104 self.line_with(from, to, marker, style, Composition::Overlay);
105 }
106
107 pub fn line_with(
113 &mut self,
114 from: Position,
115 to: Position,
116 marker: &Grapheme,
117 style: TextStyle,
118 composition: Composition,
119 ) {
120 self.record(CellPath::line(from, to, marker, style), composition);
121 }
122
123 pub fn polyline(
129 &mut self,
130 points: impl IntoIterator<Item = Position>,
131 marker: &Grapheme,
132 style: TextStyle,
133 ) {
134 self.polyline_with(points, marker, style, Composition::Overlay);
135 }
136
137 pub fn polyline_with(
143 &mut self,
144 points: impl IntoIterator<Item = Position>,
145 marker: &Grapheme,
146 style: TextStyle,
147 composition: Composition,
148 ) {
149 self.record(CellPath::polyline(points, marker, style), composition);
150 }
151
152 pub fn rectangle(
158 &mut self,
159 origin: Position,
160 width: usize,
161 height: usize,
162 marker: &Grapheme,
163 style: TextStyle,
164 ) {
165 self.rectangle_with(origin, width, height, marker, style, Composition::Overlay);
166 }
167
168 pub fn rectangle_with(
174 &mut self,
175 origin: Position,
176 width: usize,
177 height: usize,
178 marker: &Grapheme,
179 style: TextStyle,
180 composition: Composition,
181 ) {
182 self.record(
183 CellPath::rectangle(origin, width, height, marker, style),
184 composition,
185 );
186 }
187
188 pub fn line_network(&mut self, network: LineNetwork) {
194 self.line_network_with(network, Composition::Overlay);
195 }
196
197 pub fn line_network_with(&mut self, network: LineNetwork, composition: Composition) {
202 self.record(network, composition);
203 }
204
205 pub fn cells(&mut self, cells: impl IntoIterator<Item = PositionedCell>) {
207 self.cells_with(cells, Composition::Overlay);
208 }
209
210 pub fn cells_with(
212 &mut self,
213 cells: impl IntoIterator<Item = PositionedCell>,
214 composition: Composition,
215 ) {
216 self.record(CellsCommand(cells.into_iter().collect()), composition);
217 }
218
219 fn record(
220 &mut self,
221 command: impl super::command::CanvasCommand + 'static,
222 composition: Composition,
223 ) {
224 self.commands
225 .push(RecordedCommand::new(command, composition));
226 }
227
228 pub(super) fn into_commands(self) -> Vec<RecordedCommand> {
229 self.commands
230 }
231}