use crate::{
bitmap::{Bitmap, BitmapBackend},
brush::{Brush, BrushBackend},
device::{DeviceContext, DeviceContextBackend},
error::GraphicsError,
font::{FontStyle, FontWeight},
geometry::{FRect, FSize, ISize},
layer::{Layer, LayerBackend},
matrix::{Matrix, MatrixBackend},
paint::{BlendMode, Cap, Color, DrawMode, Join},
path::{Path, PathBackend},
text::TextAlignment,
window::Window,
DefaultCanvas, DefaultDeviceContext, DefaultLayer, Float,
};
pub trait CanvasBackend {
type DeviceContextType: DeviceContextBackend;
type BitmapType: BitmapBackend;
type BrushType: BrushBackend;
type LayerType: LayerBackend;
type MatrixType: MatrixBackend;
type PathType: PathBackend;
fn from_layer(context: Option<&Self::DeviceContextType>, layer: &Self::LayerType) -> Result<Self, GraphicsError>
where
Self: Sized;
fn from_window(context: Option<&Self::DeviceContextType>, window: &Window) -> Result<Self, GraphicsError>
where
Self: Sized;
fn device_context(&self) -> Option<&Self::DeviceContextType>;
fn size(&self) -> FSize;
fn pixel_size(&self) -> ISize;
fn bounds(&self) -> FRect {
let size = self.size();
FRect::new(0.0, 0.0, size.width, size.height)
}
fn save(&mut self) -> bool;
fn restore(&mut self) -> bool;
fn begin_draw(&mut self);
fn end_draw(&mut self);
fn get_opacity(&self) -> Float;
fn set_opacity(&mut self, opacity: Float);
fn get_blend_mode(&self) -> BlendMode;
fn set_blend_mode(&mut self, mode: BlendMode);
fn get_draw_mode(&self) -> DrawMode;
fn set_draw_mode(&mut self, mode: DrawMode);
fn get_line_dash(&self) -> (Option<Vec<Float>>, Float);
fn set_line_dash(&mut self, dashes: &[Float], offset: Float);
fn get_matrix(&self) -> Self::MatrixType;
fn set_matrix(&mut self, matrix: &Self::MatrixType);
fn concat_matrix(&mut self, matrix: &Self::MatrixType);
fn get_miter_limit(&self) -> Float;
fn set_miter_limit(&mut self, miter_limit: Float);
fn get_smooth(&self) -> bool;
fn set_smooth(&mut self, smooth: bool);
fn get_stroke_cap(&self) -> Cap;
fn set_stroke_cap(&mut self, cap: Cap);
fn get_stroke_join(&self) -> Join;
fn set_stroke_join(&mut self, join: Join);
fn get_stroke_width(&self) -> Float;
fn set_stroke_width(&mut self, width: Float);
fn set_brush(&mut self, brush: &Self::BrushType);
fn get_font_family(&self) -> &str;
fn set_font_family(&mut self, family: &str);
fn get_font_size(&self) -> Float;
fn set_font_size(&mut self, size: Float);
fn get_font_style(&self) -> FontStyle;
fn set_font_style(&mut self, style: FontStyle);
fn get_font_weight(&self) -> FontWeight;
fn set_font_weight(&mut self, weight: FontWeight);
fn get_text_alignment(&self) -> TextAlignment;
fn set_text_alignment(&mut self, alignment: TextAlignment);
fn get_text_color(&self) -> Color;
fn set_text_color(&mut self, color: Color);
fn rotate(&mut self, angle: Float);
fn scale(&mut self, x: Float, y: Float);
fn translate(&mut self, x: Float, y: Float);
fn clear(&mut self, color: Color);
fn clip_to_rect(&mut self, rect: FRect);
fn clip_to_path(&mut self, path: &Self::PathType);
fn draw_line(&mut self, x1: Float, y1: Float, x2: Float, y2: Float) -> bool {
Self::PathType::new(None)
.map(|mut path| {
path.move_to(x1, y1);
path.line_to(x2, y2);
self.draw_path(&path)
})
.unwrap_or(false)
}
fn draw_rect(&mut self, x: Float, y: Float, width: Float, height: Float) -> bool {
Self::PathType::new(None)
.map(|mut path| {
path.add_rect(x, y, width, height);
self.draw_path(&path)
})
.unwrap_or(false)
}
fn draw_rounded_rect(&mut self, x: Float, y: Float, width: Float, height: Float, radius: Float) -> bool {
Self::PathType::new(None)
.map(|mut path| {
path.add_rounded_rect(x, y, width, height, radius);
self.draw_path(&path)
})
.unwrap_or(false)
}
fn draw_circle(&mut self, x: Float, y: Float, radius: Float) -> bool {
Self::PathType::new(None)
.map(|mut path| {
path.add_circle(x, y, radius);
self.draw_path(&path)
})
.unwrap_or(false)
}
fn draw_ellipse(&mut self, x: Float, y: Float, width: Float, height: Float) -> bool {
Self::PathType::new(None)
.map(|mut path| {
path.add_ellipse(x, y, width, height);
self.draw_path(&path)
})
.unwrap_or(false)
}
fn draw_path(&mut self, path: &Self::PathType) -> bool;
fn draw_bitmap(&mut self, bitmap: &Self::BitmapType, source_rect: Option<FRect>, dest_rect: FRect) -> bool;
fn draw_layer(&mut self, layer: &Self::LayerType, dest_rect: FRect) -> bool;
fn draw_text(&mut self, text: &str, rect: FRect) -> bool;
fn draw_text_at(&mut self, text: &str, x: Float, y: Float) -> bool;
fn fill_rect(&mut self, x: Float, y: Float, width: Float, height: Float, mask: Option<&Self::BitmapType>) -> bool;
fn map_rect(&self, rect: FRect) -> FRect {
let matrix = self.get_matrix();
matrix.map_rect(rect)
}
}
pub struct Canvas<T: CanvasBackend> {
pub(crate) backend: T,
}
impl<T: CanvasBackend> Canvas<T> {
pub fn from_layer(context: Option<&DeviceContext<T::DeviceContextType>>, layer: &Layer<T::LayerType>) -> Result<Self, GraphicsError> {
Ok(Self {
backend: T::from_layer(context.map(|ctx| &ctx.backend), &layer.backend)?,
})
}
pub fn from_window(context: Option<&DeviceContext<T::DeviceContextType>>, window: &Window) -> Result<Self, GraphicsError> {
Ok(Self {
backend: T::from_window(context.map(|ctx| &ctx.backend), window)?,
})
}
pub fn device_context(&self) -> Option<DeviceContext<T::DeviceContextType>> {
self.backend.device_context().map(|ctx| DeviceContext {
backend: ctx.clone(),
})
}
pub fn size(&self) -> FSize {
self.backend.size()
}
pub fn pixel_size(&self) -> ISize {
self.backend.pixel_size()
}
pub fn bounds(&self) -> FRect {
self.backend.bounds()
}
pub fn save(&mut self) -> bool {
self.backend.save()
}
pub fn restore(&mut self) -> bool {
self.backend.restore()
}
pub fn begin_draw(&mut self) {
self.backend.begin_draw()
}
pub fn end_draw(&mut self) {
self.backend.end_draw()
}
pub fn get_opacity(&self) -> Float {
self.backend.get_opacity()
}
pub fn set_opacity(&mut self, opacity: Float) {
self.backend.set_opacity(opacity)
}
pub fn get_blend_mode(&self) -> BlendMode {
self.backend.get_blend_mode()
}
pub fn set_blend_mode(&mut self, mode: BlendMode) {
self.backend.set_blend_mode(mode)
}
pub fn get_draw_mode(&self) -> DrawMode {
self.backend.get_draw_mode()
}
pub fn set_draw_mode(&mut self, mode: DrawMode) {
self.backend.set_draw_mode(mode)
}
pub fn get_line_dash(&self) -> (Option<Vec<Float>>, Float) {
self.backend.get_line_dash()
}
pub fn set_line_dash(&mut self, dashes: &[Float], offset: Float) {
self.backend.set_line_dash(dashes, offset)
}
pub fn get_matrix(&self) -> Matrix<T::MatrixType> {
Matrix {
backend: self.backend.get_matrix(),
}
}
pub fn set_matrix(&mut self, matrix: &Matrix<T::MatrixType>) {
self.backend.set_matrix(&matrix.backend)
}
pub fn concat_matrix(&mut self, matrix: &Matrix<T::MatrixType>) {
self.backend.concat_matrix(&matrix.backend)
}
pub fn get_miter_limit(&self) -> Float {
self.backend.get_miter_limit()
}
pub fn set_miter_limit(&mut self, miter_limit: Float) {
self.backend.set_miter_limit(miter_limit)
}
pub fn get_smooth(&self) -> bool {
self.backend.get_smooth()
}
pub fn set_smooth(&mut self, smooth: bool) {
self.backend.set_smooth(smooth)
}
pub fn get_stroke_cap(&self) -> Cap {
self.backend.get_stroke_cap()
}
pub fn set_stroke_cap(&mut self, cap: Cap) {
self.backend.set_stroke_cap(cap)
}
pub fn get_stroke_join(&self) -> Join {
self.backend.get_stroke_join()
}
pub fn set_stroke_join(&mut self, join: Join) {
self.backend.set_stroke_join(join)
}
pub fn get_stroke_width(&self) -> Float {
self.backend.get_stroke_width()
}
pub fn set_stroke_width(&mut self, width: Float) {
self.backend.set_stroke_width(width)
}
pub fn set_brush(&mut self, brush: &Brush<T::BrushType>) {
self.backend.set_brush(&brush.backend)
}
pub fn get_font_family(&self) -> &str {
self.backend.get_font_family()
}
pub fn set_font_family(&mut self, family: &str) {
self.backend.set_font_family(family)
}
pub fn get_font_size(&self) -> Float {
self.backend.get_font_size()
}
pub fn set_font_size(&mut self, size: Float) {
self.backend.set_font_size(size)
}
pub fn get_font_style(&self) -> FontStyle {
self.backend.get_font_style()
}
pub fn set_font_style(&mut self, style: FontStyle) {
self.backend.set_font_style(style)
}
pub fn get_font_weight(&self) -> FontWeight {
self.backend.get_font_weight()
}
pub fn set_font_weight(&mut self, weight: FontWeight) {
self.backend.set_font_weight(weight)
}
pub fn get_text_alignment(&self) -> TextAlignment {
self.backend.get_text_alignment()
}
pub fn set_text_alignment(&mut self, alignment: TextAlignment) {
self.backend.set_text_alignment(alignment)
}
pub fn get_text_color(&self) -> Color {
self.backend.get_text_color()
}
pub fn set_text_color(&mut self, color: Color) {
self.backend.set_text_color(color)
}
pub fn rotate(&mut self, angle: Float) {
self.backend.rotate(angle)
}
pub fn scale(&mut self, x: Float, y: Float) {
self.backend.scale(x, y)
}
pub fn translate(&mut self, x: Float, y: Float) {
self.backend.translate(x, y)
}
pub fn clear(&mut self, color: Color) {
self.backend.clear(color)
}
pub fn clip_to_rect(&mut self, rect: FRect) {
self.backend.clip_to_rect(rect)
}
pub fn clip_to_path(&mut self, path: &Path<T::PathType>) {
self.backend.clip_to_path(&path.backend)
}
pub fn draw_line(&mut self, x1: Float, y1: Float, x2: Float, y2: Float) -> bool {
self.backend.draw_line(x1, y1, x2, y2)
}
pub fn draw_rect(&mut self, x: Float, y: Float, width: Float, height: Float) -> bool {
self.backend.draw_rect(x, y, width, height)
}
pub fn draw_rounded_rect(&mut self, x: Float, y: Float, width: Float, height: Float, radius: Float) -> bool {
self.backend.draw_rounded_rect(x, y, width, height, radius)
}
pub fn draw_circle(&mut self, x: Float, y: Float, radius: Float) -> bool {
self.backend.draw_circle(x, y, radius)
}
pub fn draw_ellipse(&mut self, x: Float, y: Float, width: Float, height: Float) -> bool {
self.backend.draw_ellipse(x, y, width, height)
}
pub fn draw_path(&mut self, path: &Path<T::PathType>) -> bool {
self.backend.draw_path(&path.backend)
}
pub fn draw_bitmap(&mut self, bitmap: &Bitmap<T::BitmapType>, source_rect: Option<FRect>, dest_rect: FRect) -> bool {
self.backend.draw_bitmap(&bitmap.backend, source_rect, dest_rect)
}
pub fn draw_layer(&mut self, layer: &Layer<T::LayerType>, dest_rect: FRect) -> bool {
self.backend.draw_layer(&layer.backend, dest_rect)
}
pub fn draw_text(&mut self, text: &str, rect: FRect) -> bool {
self.backend.draw_text(text, rect)
}
pub fn draw_text_at(&mut self, text: &str, x: Float, y: Float) -> bool {
self.backend.draw_text_at(text, x, y)
}
pub fn map_rect(&self, rect: FRect) -> FRect {
self.backend.map_rect(rect)
}
pub fn fill_rect(&mut self, x: Float, y: Float, width: Float, height: Float, mask: Option<&Bitmap<T::BitmapType>>) -> bool {
self.backend.fill_rect(x, y, width, height, mask.map(|mask| &mask.backend))
}
}
impl Canvas<DefaultCanvas> {
pub fn default_from_layer(context: Option<&DeviceContext<DefaultDeviceContext>>, layer: &Layer<DefaultLayer>) -> Result<Self, GraphicsError> {
Self::from_layer(context, layer)
}
pub fn default_from_window(context: Option<&DeviceContext<DefaultDeviceContext>>, window: &Window) -> Result<Self, GraphicsError> {
Self::from_window(context, window)
}
}