use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use gtk::cairo::{Context, Format, ImageSurface};
use gtk::prelude::{DrawingAreaExtManual, WidgetExt};
#[derive(Clone, Debug)]
struct Surface {
surface: Rc<RefCell<ImageSurface>>,
}
impl Surface {
fn new(surface: ImageSurface) -> Self {
Self {
surface: Rc::new(RefCell::new(surface)),
}
}
fn get(&self) -> ImageSurface {
self.surface.borrow().clone()
}
fn set(&self, surface: &ImageSurface) {
*self.surface.borrow_mut() = surface.clone();
}
}
#[derive(Debug)]
pub struct DrawContext {
context: Context,
draw_surface: Surface,
edit_surface: ImageSurface,
drawing_area: gtk::DrawingArea,
}
impl DrawContext {
fn new(
draw_surface: &Surface,
edit_surface: &ImageSurface,
drawing_area: >k::DrawingArea,
) -> Self {
Self {
context: Context::new(edit_surface).unwrap(),
draw_surface: draw_surface.clone(),
edit_surface: edit_surface.clone(),
drawing_area: drawing_area.clone(),
}
}
}
impl Deref for DrawContext {
type Target = Context;
fn deref(&self) -> &Self::Target {
&self.context
}
}
impl Drop for DrawContext {
fn drop(&mut self) {
self.draw_surface.set(&self.edit_surface);
self.drawing_area.queue_draw();
}
}
#[derive(Debug)]
#[must_use]
pub struct DrawHandler {
draw_surface: Surface,
edit_surface: ImageSurface,
drawing_area: gtk::DrawingArea,
}
impl Default for DrawHandler {
fn default() -> Self {
Self::new()
}
}
impl DrawHandler {
pub fn new() -> Self {
Self::new_with_drawing_area(gtk::DrawingArea::default())
}
pub fn new_with_drawing_area(drawing_area: gtk::DrawingArea) -> Self {
let draw_surface = Surface::new(ImageSurface::create(Format::ARgb32, 100, 100).unwrap());
let edit_surface = ImageSurface::create(Format::ARgb32, 100, 100).unwrap();
use gtk::glib;
drawing_area.set_draw_func(
glib::clone!(@strong draw_surface => move |_, context, _, _| {
if let Err(error) = context.set_source_surface(&draw_surface.get(), 0.0, 0.0) {
tracing::error!("Cannot set source surface: {:?}", error);
}
if let Err(error) = context.paint() {
tracing::error!("Cannot paint: {:?}", error);
}
}),
);
Self {
draw_surface,
edit_surface,
drawing_area,
}
}
#[allow(deprecated)]
pub fn get_context(&mut self) -> DrawContext {
let allocation = self.drawing_area.allocation();
let scale = self.drawing_area.scale_factor();
let width = allocation.width() * scale;
let height = allocation.height() * scale;
if (width, height) != (self.edit_surface.width(), self.edit_surface.height()) {
match ImageSurface::create(Format::ARgb32, width, height) {
Ok(surface) => {
surface.set_device_scale(f64::from(scale), f64::from(scale));
self.edit_surface = surface;
}
Err(error) => tracing::error!("Cannot resize image surface: {:?}", error),
}
}
DrawContext::new(&self.draw_surface, &self.edit_surface, &self.drawing_area)
}
#[must_use]
pub fn size(&self) -> (i32, i32) {
let scale = self.drawing_area.scale_factor();
(
self.edit_surface.width() / scale,
self.edit_surface.height() / scale,
)
}
#[must_use]
pub fn height(&self) -> i32 {
let scale = self.drawing_area.scale_factor();
self.edit_surface.height() / scale
}
#[must_use]
pub fn width(&self) -> i32 {
let scale = self.drawing_area.scale_factor();
self.edit_surface.width() / scale
}
#[must_use]
pub fn surface_height(&self) -> i32 {
self.edit_surface.height()
}
#[must_use]
pub fn surface_width(&self) -> i32 {
self.edit_surface.width()
}
#[must_use]
pub fn drawing_area(&self) -> >k::DrawingArea {
&self.drawing_area
}
}