173 lines
5.6 KiB
Rust
173 lines
5.6 KiB
Rust
use gtk::prelude::*;
|
|
use gtk::DrawingArea;
|
|
|
|
use std::rc::Rc;
|
|
use std::cell::RefCell;
|
|
|
|
pub struct Graph {
|
|
pub area: DrawingArea,
|
|
pub scale_x_start: f64,
|
|
pub scale_x_size: f64,
|
|
pub scale_y_start: f64,
|
|
pub scale_y_size: f64,
|
|
pub draw_patch: bool,
|
|
pub lines: Vec<Line>
|
|
}
|
|
|
|
pub struct Line {
|
|
points: Vec<(f64,f64)>,
|
|
color: (f64, f64, f64)
|
|
}
|
|
|
|
impl Line {
|
|
pub fn new(r: f64, g: f64, b: f64, points: Vec<(f64,f64)>) -> Self {
|
|
Line {
|
|
points,
|
|
color: (r,g,b)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Graph {
|
|
pub fn new(area: DrawingArea,
|
|
scale_x_start: f64,
|
|
scale_x_size: f64,
|
|
scale_y_start: f64,
|
|
scale_y_size: f64,
|
|
draw_patch: bool,
|
|
lines: Vec<Line>) -> Rc<RefCell<Self>> {
|
|
|
|
let graph = Rc::new(RefCell::new(Graph {
|
|
area,
|
|
scale_x_start,
|
|
scale_x_size,
|
|
scale_y_start,
|
|
scale_y_size,
|
|
draw_patch,
|
|
lines
|
|
}));
|
|
|
|
let graph_tmp = Rc::clone(&graph);
|
|
graph.borrow().area.connect_draw(move |area,ctx| {
|
|
Graph::draw(area, ctx, &graph_tmp);
|
|
Inhibit(false)
|
|
});
|
|
|
|
graph
|
|
}
|
|
|
|
fn draw(area: >k::DrawingArea,
|
|
ctx: &cairo::Context,
|
|
graph: &Rc<RefCell<Graph>>) {
|
|
|
|
ctx.set_source_rgb(0.1, 0.5, 0.5);
|
|
ctx.paint();
|
|
|
|
let width = area.get_allocated_width() as f64;
|
|
let height = area.get_allocated_height() as f64;
|
|
|
|
graph.borrow_mut().adjust_scale_automatic_y();
|
|
graph.borrow_mut().adjust_scale_automatic_x();
|
|
|
|
Graph::draw_boxes(ctx, width, height, 40.0, 20.0, 5.0, 0.3);
|
|
Graph::draw_boxes(ctx, width, height, 40.0, 20.0, 50.0, 0.1);
|
|
|
|
let cell_size = 50.0;
|
|
|
|
let v_bars = math::round::ceil(width/cell_size, 0) as i32;
|
|
let h_bars= math::round::ceil(height/cell_size, 0) as i32;
|
|
|
|
let h_scale = (graph.borrow().scale_x_size)/(v_bars - 1) as f64; // ms
|
|
let v_scale = (graph.borrow().scale_y_size)/(h_bars - 1) as f64; // ms
|
|
|
|
ctx.set_line_width(2.0);
|
|
ctx.set_line_cap(cairo::LineCap::Round);
|
|
let draw_patch = graph.borrow().draw_patch;
|
|
for line in graph.borrow().lines.iter() {
|
|
for p in line.points.iter().enumerate() {
|
|
let xp = if p.0 < line.points.len() - 1 {
|
|
line.points[p.0 + 1]
|
|
} else {
|
|
line.points[p.0]
|
|
};
|
|
ctx.set_source_rgb(line.color.0, line.color.1, line.color.2);
|
|
ctx.move_to(((cell_size as f64)*(xp.0 - graph.borrow().scale_x_start))/h_scale + 40.0, height - ((cell_size as f64)*(xp.1 - graph.borrow().scale_y_start))/v_scale - 20.0);
|
|
ctx.line_to(((cell_size as f64)*(p.1.0 - graph.borrow().scale_x_start))/h_scale + 40.0, height - ((cell_size as f64)*(p.1.1 - graph.borrow().scale_y_start))/v_scale - 20.0);
|
|
ctx.stroke();
|
|
|
|
if draw_patch {
|
|
ctx.set_source_rgb(0.0, 0.0, 1.0);
|
|
ctx.arc(((cell_size as f64)*(p.1.0 - graph.borrow().scale_x_start))/h_scale + 40.0, height - ((cell_size as f64)*(p.1.1 - graph.borrow().scale_y_start))/v_scale - 20.0, 5.0, 0.0, std::f64::consts::PI * 2.0);
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
|
|
ctx.set_source_rgb(0.1, 0.4, 0.4);
|
|
ctx.rectangle(0.0, 0.0, 40.0, height);
|
|
ctx.rectangle(0.0, height - 20.0, width, 20.0);
|
|
ctx.fill();
|
|
|
|
ctx.set_source_rgb(1.0, 1.0, 1.0);
|
|
for x in 0..v_bars {
|
|
let text = math::round::floor(x as f64 * h_scale + graph.borrow().scale_x_start, 1).to_string();
|
|
let f = ctx.text_extents(&text);
|
|
ctx.move_to(40.0 + x as f64 * cell_size - f.width, height - 10.0);
|
|
ctx.show_text(&text);
|
|
}
|
|
|
|
for y in (0..h_bars).rev() {
|
|
let text = math::round::floor(y as f64 * v_scale + graph.borrow().scale_y_start, 1).to_string();
|
|
let f = ctx.text_extents(&text);
|
|
ctx.move_to(40.0 - f.width, height - y as f64 * cell_size - f.height - 15.0);
|
|
ctx.show_text(&text);
|
|
}
|
|
}
|
|
|
|
fn draw_boxes(ctx: &cairo::Context, area_width: f64, area_height: f64, src_x: f64, src_y: f64, cell_size: f64, color: f64) {
|
|
ctx.set_source_rgb(color, color, color);
|
|
ctx.set_line_width(1.0);
|
|
for x in 1..math::round::ceil(area_width/cell_size, 0) as i32 {
|
|
let xi = x as f64 * cell_size + src_x;
|
|
ctx.move_to(xi, 0.0);
|
|
ctx.line_to(xi, area_height - src_y);
|
|
}
|
|
for y in 1..math::round::ceil(area_height/cell_size, 0) as i32 {
|
|
let yi = area_height - y as f64 * cell_size - src_y;
|
|
ctx.move_to(src_x, yi);
|
|
ctx.line_to(area_width, yi);
|
|
}
|
|
ctx.stroke();
|
|
}
|
|
|
|
pub fn adjust_scale_automatic_y(&mut self) {
|
|
|
|
let mut mx:Option<f64> = None;
|
|
let mut mi:Option<f64> = None;
|
|
|
|
for line in self.lines.iter() {
|
|
if let None = mx {
|
|
mx = Some(line.points[0].0);
|
|
}
|
|
|
|
if let None = mi {
|
|
mi = Some(line.points[0].0);
|
|
}
|
|
|
|
for (_,y) in line.points.iter().skip(1) {
|
|
mx = Some(f64::max(mx.unwrap(), *y));
|
|
mi = Some(f64::min(mi.unwrap(), *y));
|
|
}
|
|
}
|
|
|
|
let spread = (mx.unwrap() - mi.unwrap()).abs();
|
|
|
|
self.scale_y_start = mi.unwrap() - spread * 0.1;
|
|
self.scale_y_size = spread * 1.2;
|
|
}
|
|
|
|
pub fn adjust_scale_automatic_x(&mut self) {
|
|
|
|
}
|
|
}
|