ratatui/widgets/canvas/map.rs
1use strum::{Display, EnumString};
2
3use crate::{
4 style::Color,
5 widgets::canvas::{
6 world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION},
7 Painter, Shape,
8 },
9};
10
11/// Defines how many points are going to be used to draw a [`Map`].
12///
13/// You generally want a [high](MapResolution::High) resolution map.
14#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
15pub enum MapResolution {
16 /// A lesser resolution for the [`Map`] [`Shape`].
17 ///
18 /// Contains about 1000 points.
19 #[default]
20 Low,
21 /// A higher resolution for the [`Map`] [`Shape`].
22 ///
23 /// Contains about 5000 points, you likely want to use [`Marker::Braille`] with this.
24 ///
25 /// [`Marker::Braille`]: (crate::symbols::Marker::Braille)
26 High,
27}
28
29impl MapResolution {
30 const fn data(self) -> &'static [(f64, f64)] {
31 match self {
32 Self::Low => &WORLD_LOW_RESOLUTION,
33 Self::High => &WORLD_HIGH_RESOLUTION,
34 }
35 }
36}
37
38/// A world map
39///
40/// A world map can be rendered with different [resolutions](MapResolution) and [colors](Color).
41#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
42pub struct Map {
43 /// The resolution of the map.
44 ///
45 /// This is the number of points used to draw the map.
46 pub resolution: MapResolution,
47 /// Map color
48 ///
49 /// This is the color of the points of the map.
50 pub color: Color,
51}
52
53impl Shape for Map {
54 fn draw(&self, painter: &mut Painter) {
55 for (x, y) in self.resolution.data() {
56 if let Some((x, y)) = painter.get_point(*x, *y) {
57 painter.paint(x, y, self.color);
58 }
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use strum::ParseError;
66
67 use super::*;
68 use crate::{
69 buffer::Buffer,
70 layout::Rect,
71 symbols::Marker,
72 widgets::{canvas::Canvas, Widget},
73 };
74
75 #[test]
76 fn map_resolution_to_string() {
77 assert_eq!(MapResolution::Low.to_string(), "Low");
78 assert_eq!(MapResolution::High.to_string(), "High");
79 }
80
81 #[test]
82 fn map_resolution_from_str() {
83 assert_eq!("Low".parse(), Ok(MapResolution::Low));
84 assert_eq!("High".parse(), Ok(MapResolution::High));
85 assert_eq!(
86 "".parse::<MapResolution>(),
87 Err(ParseError::VariantNotFound)
88 );
89 }
90
91 #[test]
92 fn default() {
93 let map = Map::default();
94 assert_eq!(map.resolution, MapResolution::Low);
95 assert_eq!(map.color, Color::Reset);
96 }
97
98 #[test]
99 fn draw_low() {
100 let mut buffer = Buffer::empty(Rect::new(0, 0, 80, 40));
101 let canvas = Canvas::default()
102 .marker(Marker::Dot)
103 .x_bounds([-180.0, 180.0])
104 .y_bounds([-90.0, 90.0])
105 .paint(|context| {
106 context.draw(&Map::default());
107 });
108 canvas.render(buffer.area, &mut buffer);
109 let expected = Buffer::with_lines([
110 " ",
111 " ••••••• •• •• •• • ",
112 " •••••••••••••• ••• •••• ••• •• •••• ",
113 " •••••••••••••••• •• ••• ••••••• •• •• ••• ",
114 "• • •• •••••• •••••••••••• •• ••• • ••••• ••••••••• •• • • • • ",
115 "••••• •••• •••••••• •• •• ••• •••• •••• •• • • ",
116 " •••••••• ••••••• ••••• ••• •••••••• • ••••• ",
117 " •• •• •• ••••••• •• ••• •••• •• • ",
118 "••• ••• •••••• •••• •••• •• • •• ",
119 " • ••••••••• •• • ••• • •• •• •• ",
120 " • • •••• •• ••••••••• ••• • • • •• ",
121 " • • ••••• •••• •• •••••• ",
122 " • •• • • •• • ••••• ",
123 " •• •• • • •• •• • ",
124 " •• ••• ••• • • ••••• • ••• ",
125 " • •••• ••• • • • • • •• ",
126 " •••• • • •• • • •• •• ",
127 " ••• •• • • • •• ••• ••• ",
128 " • • • •• • • • • • ",
129 " • • • • • • ••• • • ",
130 " • • • • •• • • • ",
131 " • • •• ••• • ",
132 " • • • • • • • • ",
133 " • • • •• • • • • • ",
134 " • • • • ",
135 " • • • • • • ",
136 " • •• • • • • •• • ",
137 " • • • •••• •• ",
138 " • • •• ••• ",
139 " •• • ",
140 " •• • ",
141 " •• ",
142 " ",
143 " ••• • •••• • • •• • ",
144 " •••• •••••• •••••• •••••• • ••• ",
145 " •• •••••• ••••• •• • ••• • •• ",
146 "• ••••• •• •• •••••• • •• ",
147 "• • • • • • • ",
148 " • ",
149 " ",
150 ]);
151 assert_eq!(buffer, expected);
152 }
153
154 #[test]
155 fn draw_high() {
156 let mut buffer = Buffer::empty(Rect::new(0, 0, 80, 40));
157 let canvas = Canvas::default()
158 .marker(Marker::Braille)
159 .x_bounds([-180.0, 180.0])
160 .y_bounds([-90.0, 90.0])
161 .paint(|context| {
162 context.draw(&Map {
163 resolution: MapResolution::High,
164 ..Default::default()
165 });
166 });
167 canvas.render(buffer.area, &mut buffer);
168 let expected = Buffer::with_lines([
169 " ",
170 " ⢀⣠⠤⠤⠤⠔⢤⣤⡄⠤⡠⣄⠢⠂⢢⠰⣠⡄⣀⡀ ⣀ ",
171 " ⢀⣀⡤⣦⠲⢶⣿⣮⣿⡉⣰⢶⢏⡂ ⢀⣟⠁ ⢺⣻⢿⠏ ⠈⠉⠁ ⢀⣀ ⠈⠓⢳⣢⣂⡀ ",
172 " ⡞⣳⣿⣻⡧⣷⣿⣿⢿⢿⣧⡀⠉⠉⠙⢆ ⣰⠇ ⣠⠞⠃⢉⣄⣀⣠⠴⠊⠉⠁ ⠐⠾⠤⢤⠤⡄⠐⣻⠜⢓⠂ ",
173 "⢍ ⢀⡴⠊⠙⠓⠒⠒⠤⠖⠺⠿⠽⣷⣬⢬⣾⣷⢻⣷⢲⢲⣍⠱⡀ ⠹⡗ ⢀⢐⠟ ⡔⠒⠉⠲⠤⢀⢄⡀⢩⣣⠦⢷⢼⡏⠈ ⠉⠉⠉ ⠈⠈⠉⠖⠤⠆⠒⠭",
174 "⠶⢽⡲⣽⡆ ⠈⣠⣽⣯⡼⢯⣘⡯⠃⠘⡆ ⢰⠒⠁ ⢾⣚⠟ ⢀⠆ ⣔⠆ ⢷⠾⠋⠁ ⠙⠁ ⠠⡤",
175 " ⠠⢧⣄⣀⡶⠦⠤⡀ ⢰⡁ ⠉⡻⠙⣎⡥ ⠘⠲⠇ ⢀⡀⠨⣁⡄⣸⢫⡤⠄ ⣀⢠⣤⠊⣼⠅⠖⠋⠁",
176 " ⣠⠾⠛⠁ ⠈⣱ ⠋⠦⢤⡼ ⠈⠈⠦⡀ ⢀⣿⣇ ⢹⣷⣂⡞⠃ ⢀⣂⡀ ⠏⣜ ",
177 " ⠙⣷⡄ ⠘⠆ ⢀⣀⡠⣗ ⠘⣻⣽⡟⠉⠈ ⢹⡇ ⠟⠁ ",
178 " ⠈⡟ ⢎⣻⡿⠾⠇ ⠘⠇ ⣀⡀ ⣤⣤⡆ ⡠⡦ ⢀⠎⡏ ",
179 " ⡇ ⣀⠏⠋ ⢸⠒⢃⡖⢻⢟⣷⣄⣰⣡⠥⣱ ⢏⣧ ⣀ ⡴⠚⢰⠟ ",
180 " ⢳ ⢸⠃ ⠸⣄⣼⣠⢼⡴⡟⢿⢿⣀⣄ ⠸⡹ ⠘⡯⢿⡇⡠⢼⠁ ",
181 " ⢳⣀ ⢀⠞⠁ ⢠⠋⠁ ⠐⠧⡄⣬⣉⣈⡽ ⢧⠘⢽⠟⠉ ",
182 " ⣿⣄ ⡴⠚⠛⣿⣀ ⢠⠖ ⠈⠁ ⠹⣧ ⢾⣄⡀ ⡼ ⠈ ",
183 " ⣀ ⠘⣿⡄ ⡇ ⣘⣻ ⡏ ⢻⡄ ⠘⠿⢿⠒⠲⡀ ⢀⡀ ⢀⡰⣗ ",
184 " ⠉⠷ ⢫⡀⢧⡼⡟⠉⣛⣳⣦⡀ ⠈⡇ ⠸⣱ ⢀⡼ ⢺ ⡸⠉⢇ ⣾⡏ ⣁ ",
185 " ⠉⠒⢆⡓⡆ ⠠⡃ ⢳⣇⡠⠏ ⠐⡄⡞ ⠘⣇⡀⢱ ⣾⡀ ",
186 " ⢹⣇⣀⣾⡷⠤⡆ ⢣ ⠯⢺⠇ ⢣⣅ ⣽⢱⡔ ⢠⢿⣗ ",
187 " ⠙⢱ ⠘⠦⡄ ⠈⢦⡠⣠⢶⣀ ⡜ ⠈⠿ ⢠⣽⢆ ⢀⣼⡜⠿ ",
188 " ⢀⡞ ⢱⡀ ⢸ ⡔⠁ ⢻⢿⢰⠏⢸⣤⣴⣆ ",
189 " ⢘⠆ ⠙⠢⢄ ⠸⡀ ⡸⠁ ⠈⣞⡎⠥⡟⣿⠠⠿⣷⠒⢤⢀⣆ ",
190 " ⠘⠆ ⢈⠂ ⢳ ⡇ ⠈⠳⠶⣤⣭⣠ ⠋⢧⡬⣟⠉⠷⡄ ",
191 " ⢨ ⡜ ⢸ ⠸ ⣠ ⠁⢁⣰⢶ ⡇⠉⠁ ⠛ ",
192 "⠆ ⠈⢱⡀ ⡆ ⡇ ⢀⡜⡴⢹ ⢰⠏⠁⠘⢶⠹⡀ ⠸ ⢠⡶",
193 " ⠅ ⣸ ⢸ ⢫ ⡞⡊ ⢠⠔⠋ ⢳⡀ ⠐⣦ ",
194 " ⡅ ⡏ ⠈⡆ ⢠⠎ ⠳⠃ ⢸ ⢳ ",
195 " ⠨ ⡸⠁ ⢱ ⡸ ⠈⡇ ⢀⣀⡀ ⢸ ",
196 " ⠸ ⠐⡶⠁ ⠘⠖⠚ ⠣⠒⠋ ⠱⣇ ⢀⠇ ⠰⡄ ",
197 " ⠽ ⣰⡖⠁ ⠘⢚⡊ ⢀⣿⠇",
198 " ⡯⢀⡟ ⠘⠏ ⢠⢾⠃ ",
199 " ⠇⢨⠆ ⢠⡄ ⠈⠁ ",
200 " ⢧⣷⡀⠚ ",
201 " ⠉⠁ ",
202 " ⢀⡀ ",
203 " ⢠⡾⠋ ⣀⡠⠖⢦⣀⣀ ⣀⠤⠦⢤⠤⠶⠤⠖⠦⠤⠤⠤⠴⠤⢤⣄ ",
204 " ⢀⣤⣀ ⡀ ⣼⣻⠙⡆ ⢀⡤⠤⠤⠴⠒⠖⠒⠒⠒⠚⠉⠋⠁ ⢰⡳⠊⠁ ⠈⠉⠉⠒⠤⣤ ",
205 " ⢀⣀⣀⡴⠖⠒⠒⠚⠛⠛⠛⠒⠚⠳⠉⠉⠉⠉⢉⣉⡥⠔⠃ ⢀⣠⠤⠴⠃ ⢠⠞⠁ ",
206 " ⠘⠛⣓⣒⠆ ⠸⠥⣀⣤⡦⠠⣞⣭⣇⣘⠿⠆ ⣖⠛ ",
207 "⠶⠔⠲⠤⠠⠜⢗⠤⠄ ⠘⠉ ⠁ ⠈⠉⠒⠔⠤",
208 " ",
209 ]);
210 assert_eq!(buffer, expected);
211 }
212}