use std::sync::Arc;
use agg_rust::comp_op::CompOp;
use agg_rust::math_stroke::{LineCap, LineJoin};
use agg_rust::trans_affine::TransAffine;
use crate::color::Color;
use crate::draw_ctx::{DrawCtx, FillRule, GlPaint, LinearGradientPaint, RadialGradientPaint};
use crate::geometry::Rect;
use crate::text::{Font, TextMetrics};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum PathKind {
Empty,
Freeform,
Circle,
Rect,
RoundedRect,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum PathOp {
MoveTo(f64, f64),
LineTo(f64, f64),
CubicTo(f64, f64, f64, f64, f64, f64),
ClosePath,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct PaintOp {
pub color: Color,
pub kind: PathKind,
}
pub(crate) struct PaintRecorder {
transform: TransAffine,
stack: Vec<TransAffine>,
fill_color: Color,
stroke_color: Color,
last_kind: PathKind,
pub fills: Vec<PaintOp>,
pub strokes: Vec<PaintOp>,
pub path_ops: Vec<PathOp>,
}
impl PaintRecorder {
pub(crate) fn new() -> Self {
Self {
transform: TransAffine::new(),
stack: Vec::new(),
fill_color: Color::rgba(0.0, 0.0, 0.0, 0.0),
stroke_color: Color::rgba(0.0, 0.0, 0.0, 0.0),
last_kind: PathKind::Empty,
fills: Vec::new(),
strokes: Vec::new(),
path_ops: Vec::new(),
}
}
pub(crate) fn fills_with(&self, color: Color) -> usize {
self.fills.iter().filter(|op| op.color == color).count()
}
pub(crate) fn strokes_with(&self, color: Color) -> usize {
self.strokes.iter().filter(|op| op.color == color).count()
}
}
impl DrawCtx for PaintRecorder {
fn set_fill_color(&mut self, color: Color) {
self.fill_color = color;
}
fn set_stroke_color(&mut self, color: Color) {
self.stroke_color = color;
}
fn set_fill_linear_gradient(&mut self, _gradient: LinearGradientPaint) {}
fn set_fill_radial_gradient(&mut self, _gradient: RadialGradientPaint) {}
fn set_line_width(&mut self, _w: f64) {}
fn set_line_join(&mut self, _join: LineJoin) {}
fn set_line_cap(&mut self, _cap: LineCap) {}
fn set_miter_limit(&mut self, _limit: f64) {}
fn set_line_dash(&mut self, _dashes: &[f64], _offset: f64) {}
fn set_blend_mode(&mut self, _mode: CompOp) {}
fn set_global_alpha(&mut self, _alpha: f64) {}
fn set_fill_rule(&mut self, _rule: FillRule) {}
fn set_font(&mut self, _font: Arc<Font>) {}
fn set_font_size(&mut self, _size: f64) {}
fn clip_rect(&mut self, _x: f64, _y: f64, _w: f64, _h: f64) {}
fn reset_clip(&mut self) {}
fn clear(&mut self, _color: Color) {}
fn begin_path(&mut self) {
self.last_kind = PathKind::Empty;
self.path_ops.clear();
}
fn move_to(&mut self, x: f64, y: f64) {
self.last_kind = PathKind::Freeform;
self.path_ops.push(PathOp::MoveTo(x, y));
}
fn line_to(&mut self, x: f64, y: f64) {
self.last_kind = PathKind::Freeform;
self.path_ops.push(PathOp::LineTo(x, y));
}
fn cubic_to(&mut self, cx1: f64, cy1: f64, cx2: f64, cy2: f64, x: f64, y: f64) {
self.last_kind = PathKind::Freeform;
self.path_ops
.push(PathOp::CubicTo(cx1, cy1, cx2, cy2, x, y));
}
fn quad_to(&mut self, _cx: f64, _cy: f64, _x: f64, _y: f64) {
self.last_kind = PathKind::Freeform;
}
fn arc_to(&mut self, _cx: f64, _cy: f64, _r: f64, _s: f64, _e: f64, _ccw: bool) {
self.last_kind = PathKind::Freeform;
}
fn circle(&mut self, _cx: f64, _cy: f64, _r: f64) {
self.last_kind = PathKind::Circle;
}
fn rect(&mut self, _x: f64, _y: f64, _w: f64, _h: f64) {
self.last_kind = PathKind::Rect;
}
fn rounded_rect(&mut self, _x: f64, _y: f64, _w: f64, _h: f64, _r: f64) {
self.last_kind = PathKind::RoundedRect;
}
fn close_path(&mut self) {
self.path_ops.push(PathOp::ClosePath);
}
fn fill(&mut self) {
self.fills.push(PaintOp {
color: self.fill_color,
kind: self.last_kind,
});
}
fn stroke(&mut self) {
self.strokes.push(PaintOp {
color: self.stroke_color,
kind: self.last_kind,
});
}
fn fill_and_stroke(&mut self) {
self.fill();
self.stroke();
}
fn draw_triangles_aa(&mut self, _vertices: &[[f32; 3]], _indices: &[u32], _color: Color) {}
fn fill_text(&mut self, _text: &str, _x: f64, _y: f64) {}
fn fill_text_gsv(&mut self, _text: &str, _x: f64, _y: f64, _size: f64) {}
fn measure_text(&self, text: &str) -> Option<TextMetrics> {
Some(TextMetrics {
width: text.chars().count() as f64 * 7.0,
ascent: 10.0,
descent: 3.0,
line_height: 16.0,
})
}
fn transform(&self) -> TransAffine {
self.transform
}
fn save(&mut self) {
self.stack.push(self.transform);
}
fn restore(&mut self) {
if let Some(t) = self.stack.pop() {
self.transform = t;
}
}
fn translate(&mut self, tx: f64, ty: f64) {
self.transform
.premultiply(&TransAffine::new_translation(tx, ty));
}
fn rotate(&mut self, radians: f64) {
self.transform
.premultiply(&TransAffine::new_rotation(radians));
}
fn scale(&mut self, sx: f64, sy: f64) {
self.transform
.premultiply(&TransAffine::new_scaling(sx, sy));
}
fn set_transform(&mut self, m: TransAffine) {
self.transform = m;
}
fn reset_transform(&mut self) {
self.transform = TransAffine::new();
}
fn gl_paint(&mut self, _screen_rect: Rect, _painter: &mut dyn GlPaint) {}
}