use cairo::{Context, FontFace, Format, ImageSurface, LineCap, Pattern}; use glib::Object; use gtk::{prelude::*, subclass::prelude::*}; use std::{cell::RefCell, rc::Rc}; const WIDTH: i32 = 800; const HEIGHT: i32 = 800; pub struct SplashPrivate { text: Rc>, time: Rc>, background: Rc>, } impl SplashPrivate { fn set_text(&self, text: String) { *self.text.borrow_mut() = text; } fn set_time(&self, time: String) { *self.time.borrow_mut() = time; } fn redraw_background(&self) { let background = ImageSurface::create(Format::Rgb24, WIDTH, HEIGHT).unwrap(); let context = Context::new(background).unwrap(); context.push_group(); context.set_source_rgb(0., 0., 0.); let _ = context.paint(); context.set_font_size(64.); let title_extents = context.text_extents(&self.text.borrow()).unwrap(); context.set_source_rgb(0.7, 0., 1.); context.set_line_width(5.); context.set_line_cap(LineCap::Round); AsymLineReturn { orientation: gtk::Orientation::Horizontal, start_x: 20., start_y: 20., start_length: 200., center_length: title_extents.y_advance(), end_length: 100., width: title_extents.height(), } .draw(&context); let _ = context.stroke(); let background = context.pop_group().unwrap(); *self.background.borrow_mut() = background; } } #[glib::object_subclass] impl ObjectSubclass for SplashPrivate { const NAME: &'static str = "Splash"; type Type = Splash; type ParentType = gtk::DrawingArea; fn new() -> SplashPrivate { // Set up a default plain black background let background = ImageSurface::create(Format::Rgb24, WIDTH, HEIGHT).unwrap(); let context = Context::new(background).unwrap(); context.push_group(); context.set_source_rgb(0., 0., 0.); let _ = context.paint(); let background = context.pop_group().unwrap(); SplashPrivate { text: Rc::new(RefCell::new(String::from(""))), time: Rc::new(RefCell::new(String::from(""))), background: Rc::new(RefCell::new(background)), } } } impl ObjectImpl for SplashPrivate {} impl WidgetImpl for SplashPrivate {} impl DrawingAreaImpl for SplashPrivate {} glib::wrapper! { pub struct Splash(ObjectSubclass) @extends gtk::DrawingArea, gtk::Widget; } impl Splash { pub fn new(text: String, time: String) -> Self { let s: Self = Object::builder().build(); s.set_width_request(WIDTH); s.set_height_request(HEIGHT); s.imp().set_text(text); s.imp().set_time(time); s.imp().redraw_background(); s.set_draw_func({ let s = s.clone(); move |_, context, _width, _height| { let background = s.imp().background.borrow(); let _ = context.set_source(&*background); let _ = context.paint(); } }); s } } struct AsymLineReturn { orientation: gtk::Orientation, start_x: f64, start_y: f64, start_length: f64, center_length: f64, end_length: f64, width: f64, } impl AsymLineReturn { fn draw(&self, context: &Context) { match self.orientation { gtk::Orientation::Horizontal => { context.move_to(self.start_x, self.start_y); context.line_to(self.start_x + self.start_length, self.start_y); context.line_to( self.start_x + self.start_length + self.width.abs(), self.start_y + self.width, ); context.line_to( self.start_x + self.start_length + self.width.abs() + self.center_length, self.start_y + self.width, ); context.line_to( self.start_x + self.start_length + self.width.abs() + self.center_length + (self.width.abs() / 2.), self.start_y + self.width / 2., ); context.line_to( self.start_x + self.start_length + self.width.abs() + self.center_length + (self.width.abs() / 2.) + self.end_length, self.start_y + self.width / 2., ); } gtk::Orientation::Vertical => { context.move_to(self.start_x, self.start_y); context.line_to(self.start_x, self.start_y + self.start_length); context.line_to( self.start_x + self.width, self.start_y + self.start_length + self.width.abs(), ); context.line_to( self.start_x + self.width, self.start_y + self.start_length + self.width.abs() + self.center_length, ); context.line_to( self.start_x + self.width / 2., self.start_y + self.start_length + self.width.abs() + self.center_length + (self.width.abs() / 2.), ); context.line_to( self.start_x + self.width / 2., self.start_y + self.start_length + self.width.abs() + self.center_length + (self.width.abs() / 2.) + self.end_length, ); } _ => panic!("unknown orientation"), } } } fn main() { let app = gtk::Application::builder() .application_id("com.luminescent-dreams.cyberpunk-splash") .build(); app.connect_activate(move |app| { let window = gtk::ApplicationWindow::new(app); window.present(); window.set_child(Some(&Splash::new("Kifu".to_owned(), "4:23".to_owned()))); }); app.run(); }