194 lines
5.4 KiB
Rust
194 lines
5.4 KiB
Rust
/*
|
|
* Copyright (C) 2022 Umut İnan Erdoğan <umutinanerdogan@pm.me>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
pub mod brush;
|
|
|
|
use std::{mem, ffi::CString};
|
|
use brush::Brush;
|
|
use cairo_sys::*;
|
|
use raw_window_handle::XlibHandle;
|
|
use x11::xlib::{XDefaultScreen, XDefaultVisual, XGetGeometry};
|
|
|
|
pub struct Renderer {
|
|
handle: XlibHandle,
|
|
surface: *mut cairo_surface_t,
|
|
ctx: *mut cairo_t,
|
|
}
|
|
|
|
impl Renderer {
|
|
pub fn new(handle: XlibHandle) -> Self {
|
|
let (width, height) = unsafe {
|
|
let mut root = mem::zeroed();
|
|
let mut x = mem::zeroed();
|
|
let mut y = mem::zeroed();
|
|
let mut width = mem::zeroed();
|
|
let mut height = mem::zeroed();
|
|
let mut border_width = mem::zeroed();
|
|
let mut depth = mem::zeroed();
|
|
assert_ne!(XGetGeometry(
|
|
handle.display as _,
|
|
handle.window.try_into().unwrap(),
|
|
&mut root,
|
|
&mut x,
|
|
&mut y,
|
|
&mut width,
|
|
&mut height,
|
|
&mut border_width,
|
|
&mut depth,
|
|
), 0);
|
|
(width.try_into().unwrap(), height.try_into().unwrap())
|
|
};
|
|
|
|
let surface = unsafe {
|
|
cairo_xlib_surface_create(handle.display as _,
|
|
handle.window,
|
|
XDefaultVisual(handle.display as _, XDefaultScreen(handle.display as _)),
|
|
width,
|
|
height
|
|
)
|
|
};
|
|
|
|
let ctx = unsafe {
|
|
cairo_create(surface)
|
|
};
|
|
|
|
Self {
|
|
handle,
|
|
surface,
|
|
ctx,
|
|
}
|
|
}
|
|
|
|
pub fn begin_draw(&mut self) {
|
|
unsafe {
|
|
// fixme
|
|
let font = CString::new("Georgia").unwrap();
|
|
cairo_select_font_face(
|
|
self.ctx,
|
|
font.as_ptr(),
|
|
FONT_SLANT_NORMAL,
|
|
FONT_WEIGHT_NORMAL,
|
|
);
|
|
cairo_set_font_size(self.ctx, 20.0);
|
|
cairo_set_line_width(self.ctx, 1.0)
|
|
}
|
|
}
|
|
|
|
pub fn clear<C: Into<(f64, f64, f64, f64)>>(&self, color: C) {
|
|
let (r, g, b, a) = color.into();
|
|
unsafe {
|
|
cairo_save(self.ctx);
|
|
cairo_set_source_rgba(self.ctx, r, g, b, a);
|
|
cairo_set_operator(self.ctx, OPERATOR_SOURCE);
|
|
cairo_paint(self.ctx);
|
|
cairo_restore(self.ctx)
|
|
}
|
|
}
|
|
|
|
pub fn draw_rect<R: Into<(f64, f64, f64, f64)>>(&self, rect: R) {
|
|
let (x, y, width, height) = rect.into();
|
|
unsafe {
|
|
cairo_rectangle(self.ctx, x, y, width, height);
|
|
cairo_stroke(self.ctx)
|
|
}
|
|
}
|
|
|
|
pub fn draw_text<R>(&self, text: &str, layout_rect: R)
|
|
where
|
|
R: Into<(f64, f64, f64, f64)>
|
|
{
|
|
let (x, y, _, _) = layout_rect.into();
|
|
let font_extents = self.font_extents();
|
|
let text_extents = self.text_extents(text);
|
|
let text = CString::new(text).unwrap();
|
|
unsafe {
|
|
cairo_move_to(
|
|
self.ctx,
|
|
x - text_extents.x_bearing,
|
|
y
|
|
+ font_extents.height
|
|
+ font_extents.descent
|
|
+ text_extents.y_bearing,
|
|
);
|
|
cairo_show_text(self.ctx, text.as_ptr())
|
|
}
|
|
}
|
|
|
|
pub fn end_draw(&self) {
|
|
unsafe {
|
|
cairo_surface_flush(self.surface)
|
|
}
|
|
}
|
|
|
|
pub fn fill_rect<R: Into<(f64, f64, f64, f64)>>(&self, rect: R) {
|
|
let (x, y, width, height) = rect.into();
|
|
unsafe {
|
|
cairo_rectangle(self.ctx, x, y, width, height);
|
|
cairo_fill(self.ctx)
|
|
}
|
|
}
|
|
|
|
// fixme: this and abletk-direct2d's get_text_size have small differences
|
|
pub fn get_text_size(&self, text: &str) -> (u32, u32) {
|
|
let text_extents = self.text_extents(text);
|
|
let font_extents = self.font_extents();
|
|
let result = (
|
|
text_extents.x_advance as u32,
|
|
(font_extents.ascent + font_extents.descent) as u32,
|
|
);
|
|
result
|
|
}
|
|
|
|
pub fn resized(&mut self, width: u32, height: u32) {
|
|
unsafe {
|
|
cairo_xlib_surface_set_size(
|
|
self.surface,
|
|
width.try_into().unwrap(),
|
|
height.try_into().unwrap(),
|
|
)
|
|
}
|
|
}
|
|
|
|
pub fn set_brush<B: Into<Brush>>(&mut self, brush: B) {
|
|
let brush = brush.into();
|
|
match brush {
|
|
Brush::Solid(r, g, b, a) => unsafe {
|
|
cairo_set_source_rgba(self.ctx, r, g, b, a)
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn size(&self) -> (u32, u32) {
|
|
unsafe {(
|
|
cairo_xlib_surface_get_width(self.surface).try_into().unwrap(),
|
|
cairo_xlib_surface_get_height(self.surface).try_into().unwrap(),
|
|
)}
|
|
}
|
|
|
|
fn text_extents(&self, text: &str) -> TextExtents {
|
|
unsafe {
|
|
let mut extents = mem::zeroed();
|
|
let text = CString::new(text).unwrap();
|
|
cairo_text_extents(
|
|
self.ctx,
|
|
text.as_ptr() as _,
|
|
&mut extents,
|
|
);
|
|
extents
|
|
}
|
|
}
|
|
|
|
fn font_extents(&self) -> FontExtents {
|
|
unsafe {
|
|
let mut extents = mem::zeroed();
|
|
cairo_font_extents(self.ctx, &mut extents);
|
|
extents
|
|
}
|
|
}
|
|
}
|