1use std::{num::NonZeroU32, rc::Rc, vec};
2
3use winit::{
4 application::ApplicationHandler,
5 dpi::{LogicalSize, PhysicalSize},
6 event::*,
7 event_loop::{ActiveEventLoop, EventLoop},
8 keyboard::{KeyCode, PhysicalKey},
9 window::Window,
10};
11
12use tiny_skia::{Color, Pixmap};
13
14use softbuffer::{Context, Surface};
15
16use crate::{axis::Axis, color, text_render::TextRender};
17
18pub struct Figure {
19 window: Option<Rc<Window>>,
20 context: Option<Context<Rc<Window>>>,
21 surface: Option<Surface<Rc<Window>, Rc<Window>>>,
22
23 pixmap: Pixmap,
24 tr: TextRender,
25 axes: Vec<Axis>,
26 config: Config,
27}
28
29pub struct Config {
30 title: String,
31 size: (u32, u32),
32 layout: (u32, u32),
33}
34impl Default for Config {
35 fn default() -> Self {
36 Self {
37 title: String::from("Painter"),
38 size: (600, 400),
39 layout: (1, 1),
40 }
41 }
42}
43
44impl Figure {
45 pub fn new(config: Config) -> Self {
46 let (width, height) = config.size;
47 let axes = vec![Axis::new(0., 0., (0., 0.))];
48 Self {
49 window: None,
50 context: None,
51 surface: None,
52
53 tr: TextRender::new(),
54 pixmap: Pixmap::new(width, height).unwrap(),
55 axes,
56 config,
57 }
58 }
59 pub fn show(&mut self) {
60 let event_loop = EventLoop::new().unwrap();
61 let _ = event_loop.run_app(self);
62 }
63 pub fn has_family(&self, family: &str) -> bool {
64 self.tr.has_family(family)
65 }
66 pub fn set_font(&mut self, family: &str) {
67 self.tr.load_font(family);
68 }
69
70 fn resize(&mut self, size: PhysicalSize<u32>) {
71 let w = size.width;
72 let h = size.height;
73
74 if let Some(surface) = &mut self.surface {
75 let w = NonZeroU32::new(w).unwrap();
76 let h = NonZeroU32::new(h).unwrap();
77
78 if let Err(e) = surface.resize(w, h) {
79 println!("resize error: {}", e);
80 return;
81 }
82 }
83
84 let pixmap = Pixmap::new(w, h).unwrap();
86 self.pixmap = pixmap;
87 self.config.size = size.into();
88 self.change_axis_size(size);
89 }
90 fn change_axis_size(&mut self, size: PhysicalSize<u32>) {
91 let w = size.width as f32;
92 let h = size.height as f32;
93
94 let (rows, cols) = self.config.layout;
95
96 let each_w = w / cols as f32;
97 let each_h = h / rows as f32;
98
99 for (index, a) in self.axes.iter_mut().enumerate() {
101 let r = (index as u32) / cols;
102 let c = (index as u32) % cols;
103
104 a.change_veiwport((c as f32 * each_w, r as f32 * each_h), (each_w, each_h));
106 }
107 }
108 pub fn add_subplot(&mut self, layout: (u32, u32)) {
109 self.config.layout = layout;
110 self.axes.clear();
111 let (rows, cols) = self.config.layout;
112
113 for _ in 0..rows * cols {
114 self.axes.push(Axis::new(0.0, 0.0, (0.0, 0.0)));
115 }
116 }
117 pub fn nth(&mut self, index: usize) -> Option<&mut Axis> {
118 self.axes.get_mut(index)
119 }
120}
121
122impl ApplicationHandler for Figure {
124 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
125 let config = &mut self.config;
126
127 let window: Rc<Window>;
128 if self.window.is_none() {
129 let attr = Window::default_attributes()
130 .with_title(&config.title)
131 .with_inner_size(LogicalSize::new(config.size.0 as f64, config.size.1 as f64));
132 window = Rc::new(event_loop.create_window(attr).unwrap());
133
134 let context = Context::new(window.clone()).expect("Failed to create context");
136
137 let surface = Surface::new(&context, window.clone()).expect("Failed to create surface");
140 let size = window.as_ref().inner_size();
141 self.config.size = (size.width, size.height);
142
143 let (rows, cols) = self.config.layout;
145 let (total_w, total_h) = self.config.size;
146 let each_w = (total_w / cols) as f32;
147 let each_h = (total_h / rows) as f32;
148
149 for r in 0..rows {
150 for c in 0..cols {
151 let x = c as f32 * each_w;
153 let y = r as f32 * each_h;
154 self.axes[(r * rows + c) as usize].change_veiwport((x, y), (each_w, each_h));
155 }
157 }
158 let pixmap = Pixmap::new(total_w, total_h).unwrap();
159 self.pixmap = pixmap;
160 self.window = Some(window);
161 self.context = Some(context);
162 self.surface = Some(surface);
163 }
164 }
165
166 fn window_event(
167 &mut self, event_loop: &ActiveEventLoop, _window_id: winit::window::WindowId,
168 event: WindowEvent,
169 ) {
170 match event {
171 WindowEvent::CloseRequested => event_loop.exit(),
172 WindowEvent::RedrawRequested => {
173 let (Some(window), Some(surface)) = (&self.window, &mut self.surface) else {
174 return;
175 };
176
177 let size = window.inner_size();
178
179 let (w, h) = (size.width, size.height);
180 if w == 0 || h == 0 {
181 return;
182 }
183
184 let bg = color::get_bg();
186 self
187 .pixmap
188 .fill(Color::from_rgba8(bg[0], bg[1], bg[2], bg[3]));
189
190 let mid = w / 2;
191 let mid_title_len = self.config.title.len() as u32 / 2;
192 const TITLE_SIZE: u32 = 16;
193 let mid = mid - mid_title_len * TITLE_SIZE;
194 let [r, g, b, a] = color::get_fg();
195 self.tr.draw(
196 &mut self.pixmap,
197 &self.config.title,
198 mid as f32,
199 12.,
200 26.,
201 Color::from_rgba8(r, g, b, a),
202 );
203 for a in &mut self.axes {
208 a.render(&mut self.pixmap, &self.tr);
210 }
211 let mut buffer = match surface.buffer_mut() {
213 Ok(b) => b,
214 Err(e) => {
215 println!("surface buffer error: {e}");
216 return;
217 }
218 };
219
220 for (target, src) in buffer.iter_mut().zip(self.pixmap.pixels().iter()) {
222 let r = src.red() as u32;
223 let g = src.green() as u32;
224 let b = src.blue() as u32;
225
226 *target = b | (g << 8) | (r << 16);
228 }
229 let _ = buffer.present();
230 }
231 WindowEvent::Resized(size) => {
233 if size.width == 0 || size.height == 0 {
234 return;
235 }
236 self.resize(size)
237 }
238 WindowEvent::KeyboardInput {
239 event:
240 KeyEvent {
241 physical_key: PhysicalKey::Code(code),
242 state: key_state,
243 ..
244 },
245 ..
246 } => match (code, key_state.is_pressed()) {
247 (KeyCode::Escape, true) => event_loop.exit(),
248 (KeyCode::KeyQ, true) => event_loop.exit(),
249 _ => {}
250 },
251 _ => {}
252 }
253 }
254}