Skip to main content

painter/
figure.rs

1use std::{num::NonZeroU32, rc::Rc};
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 mut axes = Vec::new();
48    axes.push(Axis::new(0., 0., (0., 0.)));
49    Self {
50      window: None,
51      context: None,
52      surface: None,
53
54      tr: TextRender::new(),
55      pixmap: Pixmap::new(width, height).unwrap(),
56      axes,
57      config,
58    }
59  }
60  pub fn show(&mut self) {
61    let event_loop = EventLoop::new().unwrap();
62    let _ = event_loop.run_app(self);
63  }
64  pub fn has_family(&self, family: &str) -> bool {
65    self.tr.has_family(family)
66  }
67  pub fn set_font(&mut self, family: &str) {
68    self.tr.load_font(family);
69  }
70
71  fn resize(&mut self, size: PhysicalSize<u32>) {
72    let w = size.width;
73    let h = size.height;
74
75    if let Some(surface) = &mut self.surface {
76      let w = NonZeroU32::new(w).unwrap();
77      let h = NonZeroU32::new(h).unwrap();
78
79      if let Err(e) = surface.resize(w, h) {
80        println!("resize error: {}", e);
81        return;
82      }
83    }
84
85    // update the inner state
86    let pixmap = Pixmap::new(w, h).unwrap();
87    self.pixmap = pixmap;
88    self.config.size = size.into();
89    self.change_axis_size(size);
90  }
91  fn change_axis_size(&mut self, size: PhysicalSize<u32>) {
92    let w = size.width as f32;
93    let h = size.height as f32;
94
95    let (rows, cols) = self.config.layout;
96
97    let each_w = w / cols as f32;
98    let each_h = h / rows as f32;
99
100    // 更新每个 Axis 的位置和大小
101    for (index, a) in self.axes.iter_mut().enumerate() {
102      let r = (index as u32) / cols;
103      let c = (index as u32) % cols;
104
105      // 更新 Axis 内部的 viewport 或位置属性
106      a.change_veiwport((c as f32 * each_w, r as f32 * each_h), (each_w, each_h));
107    }
108  }
109  pub fn add_subplot(&mut self, layout: (u32, u32)) {
110    self.config.layout = layout;
111    self.axes.clear();
112    let (rows, cols) = self.config.layout;
113
114    for _ in 0..rows * cols {
115      self.axes.push(Axis::new(0.0, 0.0, (0.0, 0.0)));
116    }
117  }
118  pub fn nth(&mut self, index: usize) -> Option<&mut Axis> {
119    self.axes.get_mut(index)
120  }
121}
122
123/// ===========Window Handler==============
124impl ApplicationHandler for Figure {
125  fn resumed(&mut self, event_loop: &ActiveEventLoop) {
126    let config = &mut self.config;
127
128    let window: Rc<Window>;
129    if self.window.is_none() {
130      let attr = Window::default_attributes()
131        .with_title(&config.title)
132        .with_inner_size(LogicalSize::new(config.size.0 as f64, config.size.1 as f64));
133      window = Rc::new(event_loop.create_window(attr).unwrap());
134
135      // Context 需要一个 HasDisplayHandle。Rc<Window> 满足要求。
136      let context = Context::new(window.clone()).expect("Failed to create context");
137
138      // Surface 需要 Context 的引用,以及一个 HasWindowHandle。
139      // 这里第二个参数也传入 window.clone()。
140      let surface = Surface::new(&context, window.clone()).expect("Failed to create surface");
141      let size = window.as_ref().inner_size();
142      self.config.size = (size.width, size.height);
143
144      // if have subplot, create axes, if not, create one
145      let (rows, cols) = self.config.layout;
146      let (total_w, total_h) = self.config.size;
147      let each_w = (total_w / cols) as f32;
148      let each_h = (total_h / rows) as f32;
149
150      for r in 0..rows {
151        for c in 0..cols {
152          // 计算每个子图的左上角坐标
153          let x = c as f32 * each_w;
154          let y = r as f32 * each_h;
155          self.axes[(r * rows + c) as usize].change_veiwport((x, y), (each_w, each_h));
156          // local_axes.push(Axis::new(x, y, (each_w, each_h)));
157        }
158      }
159      let pixmap = Pixmap::new(total_w, total_h).unwrap();
160      self.pixmap = pixmap;
161      self.window = Some(window);
162      self.context = Some(context);
163      self.surface = Some(surface);
164    }
165  }
166
167  fn window_event(
168    &mut self, event_loop: &ActiveEventLoop, _window_id: winit::window::WindowId,
169    event: WindowEvent,
170  ) {
171    match event {
172      WindowEvent::CloseRequested => event_loop.exit(),
173      WindowEvent::RedrawRequested => {
174        let (Some(window), Some(surface)) = (&self.window, &mut self.surface) else {
175          return;
176        };
177
178        let size = window.inner_size();
179
180        let (w, h) = (size.width, size.height);
181        if w == 0 || h == 0 {
182          return;
183        }
184
185        // draw start
186        let bg = color::get_bg();
187        self
188          .pixmap
189          .fill(Color::from_rgba8(bg[0], bg[1], bg[2], bg[3]));
190
191        let mid = w / 2;
192        let mid_title_len = self.config.title.len() as u32 / 2;
193        const TITLE_SIZE: u32 = 16;
194        let mid = mid - mid_title_len * TITLE_SIZE;
195        let [r, g, b, a] = color::get_fg();
196        self.tr.draw(
197          &mut self.pixmap,
198          &self.config.title,
199          mid as f32,
200          12.,
201          26.,
202          Color::from_rgba8(r, g, b, a),
203        );
204        // ================draw into pixmap====
205
206        //
207        // draw axes
208        for a in &mut self.axes {
209          // println!("{} {} {:?}", a.x, a.y, a.veiwport);
210          a.render(&mut self.pixmap, &self.tr);
211        }
212        //===========pixmap to buffer ===============
213        let mut buffer = match surface.buffer_mut() {
214          Ok(b) => b,
215          Err(e) => {
216            println!("surface buffer error: {e}");
217            return;
218          }
219        };
220
221        // 使用 zip 将 pixmap 像素和 buffer 像素一一对应
222        for (target, src) in buffer.iter_mut().zip(self.pixmap.pixels().iter()) {
223          let r = src.red() as u32;
224          let g = src.green() as u32;
225          let b = src.blue() as u32;
226
227          // softbuffer 默认格式通常是 0x00RRGGBB
228          *target = b | (g << 8) | (r << 16);
229        }
230        let _ = buffer.present();
231      }
232      // ==========================================
233      WindowEvent::Resized(size) => {
234        if size.width == 0 || size.height == 0 {
235          return;
236        }
237        self.resize(size)
238      }
239      WindowEvent::KeyboardInput {
240        event:
241          KeyEvent {
242            physical_key: PhysicalKey::Code(code),
243            state: key_state,
244            ..
245          },
246        ..
247      } => match (code, key_state.is_pressed()) {
248        (KeyCode::Escape, true) => event_loop.exit(),
249        _ => {}
250      },
251      _ => {}
252    }
253  }
254}