use cairo::{Context, LineCap};
use palette::Rgba;
use ::{frame, coord, text};
#[derive(Clone, Debug)]
pub struct Mark {
local: coord::Coord,
global: coord::Coord,
label: text::Text,
tick: Tick,
}
impl Mark {
pub fn new(coord: coord::Coord) -> Mark {
Mark {
local: coord,
global: coord::Coord::new(0.0, 0.0),
label: text::Text::new(""),
tick: Tick::new(),
}
}
pub fn set_local(&mut self, coord: coord::Coord) {
self.local = coord;
}
pub fn set_global(&mut self, coord: coord::Coord) {
self.global = coord;
}
pub fn set_label_content(&mut self, content: &str) {
self.label.set_content(content);
}
pub fn set_font_size(&mut self, val: f64) {
self.label.set_font_size(val);
}
pub fn set_label_offset(&mut self, hor: f64, ver: f64) {
self.label.set_offset(hor, ver);
}
pub fn set_tick_color(&mut self, color: Rgba) {
self.tick.set_color(color);
}
pub fn set_tick_width(&mut self, val: f64) {
self.tick.set_width(val);
}
pub fn set_tick_length(&mut self, val: f64) {
self.tick.set_length(val);
}
pub fn set_positive_tick_length(&mut self, val: f64) {
self.tick.set_positive_length(val);
}
pub fn set_negative_tick_length(&mut self, val: f64) {
self.tick.set_negative_length(val);
}
pub fn set_tick_direction(&mut self, direction: &coord::Coord) {
self.tick.set_direction(direction);
}
pub fn global_coord(&self) -> coord::Coord {
self.global.clone()
}
pub fn global_x(&self) -> f64 {
self.global.x()
}
pub fn global_y(&self) -> f64 {
self.global.y()
}
pub fn label(&self) -> text::Text {
self.label.clone()
}
pub fn label_hor_offset(&self) -> f64 {
self.label.hor_offset()
}
pub fn label_ver_offset(&self) -> f64 {
self.label.ver_offset()
}
pub fn scale_label_offset(&mut self, factor: f64) {
self.label.scale_offset(factor);
}
fn scale_size(&mut self, factor: f64) {
self.label.scale_size(factor);
self.tick.scale_size(factor);
}
pub fn fit(&mut self, parent_frame: &frame::Frame) {
self.global = self.local.relative_to(parent_frame);
self.scale_size(parent_frame.diag_len() / 2f64.sqrt());
}
pub fn draw(&self, cr: &Context, fig_rel_height: f64, fig_rel_width: f64) {
self.tick.draw(cr, fig_rel_height, fig_rel_width, self.global_x(), self.global_y());
cr.move_to(self.global_x() + self.label.hor_offset(),
self.global_y() + self.label.ver_offset());
self.label.draw(cr, fig_rel_height, fig_rel_width);
}
}
#[derive(Clone, Debug)]
pub struct Tick {
color: Rgba,
width: f64,
positive_length: f64, negative_length: f64, direction: coord::Coord,
}
impl Tick {
pub fn new() -> Tick {
Tick {
color: Rgba::new(0.0, 0.0, 0.0, 1.0),
width: 0.005,
positive_length: 0.01,
negative_length: 0.01,
direction: coord::Coord::new(0.0, 0.0),
}
}
pub fn set_width(&mut self, val: f64) {
self.width = val;
}
pub fn set_length(&mut self, val: f64) {
self.positive_length = val;
self.negative_length = val;
}
pub fn set_positive_length(&mut self, val: f64) {
self.positive_length = val;
}
pub fn set_negative_length(&mut self, val: f64) {
self.negative_length = val;
}
pub fn set_direction(&mut self, direction: &coord::Coord) {
self.direction = direction.clone()
}
pub fn set_color(&mut self, color: Rgba) {
self.color = color;
}
pub fn set_color_rgb(&mut self, red: f32, green: f32, blue: f32) {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
self.color = Rgba::new(red, green, blue, 1.0);
}
pub fn set_color_rgba(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
let alpha = alpha.max(0.0);
let alpha = alpha.min(1.0);
self.color = Rgba::new(red, green, blue, alpha);
}
pub fn color(&self) -> Rgba {
self.color
}
pub fn direction(&self) -> coord::Coord {
self.direction.clone()
}
pub fn width(&self) -> f64 {
self.width
}
pub fn positive_length(&self) -> f64 {
self.positive_length
}
pub fn negative_length(&self) -> f64 {
self.negative_length
}
fn scale_size(&mut self, factor: f64) {
self.width *= factor;
self.positive_length *= factor;
self.negative_length *= factor;
}
pub fn fit(&mut self, mark_frame: frame::Frame) {
self.scale_size(mark_frame.diag_len() / 2f64.sqrt());
}
pub fn draw(&self, cr: &Context, fig_rel_height: f64, fig_rel_width: f64, x_root: f64, y_root: f64) {
cr.set_line_cap(LineCap::Square);
cr.set_source_rgba(self.color.red as f64, self.color.green as f64,
self.color.blue as f64, self.color.alpha as f64);
let width = self.width * (self.direction.y().abs() * fig_rel_height +
self.direction.x().abs() * fig_rel_width);
cr.set_line_width(width);
let pos_length = self.positive_length * (self.direction.x().abs() * fig_rel_height +
self.direction.y().abs() * fig_rel_width);
cr.move_to(x_root, y_root);
cr.line_to(x_root + self.direction.x().abs() * pos_length,
y_root + self.direction.y().abs() * pos_length);
cr.stroke();
let neg_length = self.negative_length * (self.direction.x().abs() * fig_rel_height +
self.direction.y().abs() * fig_rel_width);
cr.move_to(x_root, y_root);
cr.line_to(x_root - self.direction.x().abs() * neg_length,
y_root - self.direction.y().abs() * neg_length);
cr.stroke();
}
}
#[derive(Clone, Debug)]
pub struct GridLine {
global_start: coord::Coord,
global_end: coord::Coord,
direction: coord::Coord,
width: f64,
color: Rgba,
}
impl GridLine {
pub fn new(start: coord::Coord, end: coord::Coord) -> GridLine {
GridLine {
global_start: start.clone(),
global_end: end.clone(),
direction: start.unit_direction_to(&end),
width: 0.005,
color: Rgba::new(1.0, 1.0, 1.0, 1.0),
}
}
pub fn set_width(&mut self, width: f64) {
self.width = width;
}
pub fn set_color(&mut self, color: Rgba) {
self.color = color;
}
pub fn set_color_rgb(&mut self, red: f32, green: f32, blue: f32) {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
self.color = Rgba::new(red, green, blue, 1.0);
}
pub fn set_color_rgba(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
let alpha = alpha.max(0.0);
let alpha = alpha.min(1.0);
self.color = Rgba::new(red, green, blue, alpha);
}
pub fn scale_size(&mut self, factor: f64) {
self.width *= factor;
}
pub fn draw(&self, cr: &Context, fig_rel_height: f64, fig_rel_width: f64) {
cr.set_source_rgba(self.color.red as f64, self.color.green as f64, self.color.blue as f64,
self.color.alpha as f64);
let width = self.width * (self.direction.x().abs() * fig_rel_width + self.direction.y().abs() * fig_rel_height);
cr.set_line_width(width);
cr.move_to(self.global_start.x(), self.global_start.y());
cr.line_to(self.global_end.x(), self.global_end.y());
cr.stroke();
}
}