2023-04-09 22:20:29 +00:00
|
|
|
use cairo::{
|
|
|
|
Context, FontSlant, FontWeight, Format, ImageSurface, LineCap, LinearGradient, Pattern,
|
|
|
|
};
|
2023-04-09 17:14:10 +00:00
|
|
|
use glib::Object;
|
|
|
|
use gtk::{prelude::*, subclass::prelude::*};
|
|
|
|
use std::{cell::RefCell, rc::Rc};
|
|
|
|
|
2023-04-10 00:07:12 +00:00
|
|
|
const WIDTH: i32 = 1920;
|
|
|
|
const HEIGHT: i32 = 1280;
|
2023-04-09 17:14:10 +00:00
|
|
|
|
|
|
|
pub struct SplashPrivate {
|
|
|
|
text: Rc<RefCell<String>>,
|
|
|
|
time: Rc<RefCell<String>>,
|
|
|
|
background: Rc<RefCell<Pattern>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2023-04-09 22:20:29 +00:00
|
|
|
context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold);
|
2023-04-10 00:07:12 +00:00
|
|
|
context.set_font_size(128.);
|
2023-04-09 17:14:10 +00:00
|
|
|
|
2023-04-09 22:20:29 +00:00
|
|
|
let center_x = WIDTH as f64 / 2.;
|
|
|
|
let center_y = HEIGHT as f64 / 2.;
|
|
|
|
|
2023-04-10 00:07:12 +00:00
|
|
|
let title_extents = context.text_extents(&self.text.borrow()).unwrap();
|
|
|
|
let title_width = title_extents.width();
|
|
|
|
let title_height = title_extents.height();
|
2023-04-09 22:20:29 +00:00
|
|
|
|
2023-04-10 00:07:12 +00:00
|
|
|
{
|
|
|
|
let start_length = center_x - title_width / 2. - title_height - 20.;
|
|
|
|
|
|
|
|
let title_cutout = AsymLineCutout {
|
|
|
|
orientation: gtk::Orientation::Horizontal,
|
|
|
|
start_x: 20.,
|
|
|
|
start_y: center_y - 20. - title_height / 2.,
|
|
|
|
start_length,
|
|
|
|
total_length: WIDTH as f64 - 120.,
|
|
|
|
cutout_length: title_width,
|
|
|
|
height: title_height,
|
|
|
|
invert: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
context.set_line_cap(LineCap::Round);
|
|
|
|
context.set_source_rgb(0.7, 0., 1.);
|
|
|
|
context.set_line_width(2.);
|
|
|
|
title_cutout.draw(&context);
|
|
|
|
let _ = context.stroke();
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let title_baseline_x = center_x - title_width / 2.;
|
2023-04-09 22:20:29 +00:00
|
|
|
let title_baseline_y = center_y - 20.;
|
|
|
|
|
|
|
|
let gradient = LinearGradient::new(
|
|
|
|
title_baseline_x,
|
2023-04-10 00:07:12 +00:00
|
|
|
title_baseline_y - title_height,
|
2023-04-09 22:20:29 +00:00
|
|
|
title_baseline_x,
|
|
|
|
title_baseline_y,
|
|
|
|
);
|
|
|
|
gradient.add_color_stop_rgb(0.2, 0.7, 0.0, 1.0);
|
|
|
|
gradient.add_color_stop_rgb(0.8, 0.2, 0.0, 1.0);
|
|
|
|
context.move_to(title_baseline_x, title_baseline_y);
|
|
|
|
let _ = context.set_source(gradient);
|
|
|
|
let _ = context.show_text(&self.text.borrow());
|
2023-04-10 00:07:12 +00:00
|
|
|
}
|
2023-04-09 22:20:29 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
context.set_source_rgb(0.7, 0., 1.);
|
2023-04-10 00:07:12 +00:00
|
|
|
AsymLine {
|
|
|
|
orientation: gtk::Orientation::Horizontal,
|
|
|
|
start_x: 100.,
|
|
|
|
start_y: HEIGHT as f64 / 2. + 100.,
|
|
|
|
start_length: 400.,
|
|
|
|
height: 50.,
|
|
|
|
total_length: 650.,
|
|
|
|
invert: true,
|
|
|
|
}
|
|
|
|
.draw(&context);
|
|
|
|
let _ = context.stroke();
|
|
|
|
}
|
2023-04-09 22:20:29 +00:00
|
|
|
|
2023-04-10 00:07:12 +00:00
|
|
|
{
|
|
|
|
context.set_source_rgb(0.7, 0., 1.);
|
|
|
|
AsymLine {
|
2023-04-09 22:20:29 +00:00
|
|
|
orientation: gtk::Orientation::Horizontal,
|
2023-04-10 00:07:12 +00:00
|
|
|
start_x: WIDTH as f64 / 2. + 100.,
|
|
|
|
start_y: HEIGHT as f64 / 2. + 200.,
|
|
|
|
start_length: 600.,
|
|
|
|
height: 50.,
|
|
|
|
total_length: 650.,
|
2023-04-09 22:20:29 +00:00
|
|
|
invert: false,
|
|
|
|
}
|
|
|
|
.draw(&context);
|
|
|
|
let _ = context.stroke();
|
2023-04-09 17:14:10 +00:00
|
|
|
}
|
|
|
|
|
2023-04-10 00:07:12 +00:00
|
|
|
{
|
|
|
|
context.set_font_size(128.);
|
|
|
|
let time_extents = context.text_extents(&self.time.borrow()).unwrap();
|
|
|
|
let time_baseline_x = center_x - time_extents.width() / 2.;
|
|
|
|
let time_baseline_y = center_y + 100.;
|
|
|
|
|
|
|
|
let gradient = LinearGradient::new(
|
|
|
|
time_baseline_x,
|
|
|
|
time_baseline_y - time_extents.height(),
|
|
|
|
time_baseline_x,
|
|
|
|
time_baseline_y,
|
|
|
|
);
|
|
|
|
gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0);
|
|
|
|
gradient.add_color_stop_rgb(0.8, 0.7, 0.0, 1.0);
|
|
|
|
context.move_to(time_baseline_x, time_baseline_y);
|
|
|
|
let _ = context.set_source(gradient);
|
|
|
|
let _ = context.show_text(&self.time.borrow());
|
|
|
|
}
|
|
|
|
|
2023-04-09 17:14:10 +00:00
|
|
|
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<SplashPrivate>) @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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-09 22:20:29 +00:00
|
|
|
struct AsymLineCutout {
|
|
|
|
orientation: gtk::Orientation,
|
|
|
|
start_x: f64,
|
|
|
|
start_y: f64,
|
|
|
|
start_length: f64,
|
|
|
|
total_length: f64,
|
|
|
|
cutout_length: f64,
|
|
|
|
height: f64,
|
|
|
|
invert: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsymLineCutout {
|
|
|
|
fn draw(&self, context: &Context) {
|
|
|
|
let dodge = if self.invert {
|
|
|
|
self.height
|
|
|
|
} else {
|
|
|
|
-self.height
|
|
|
|
};
|
|
|
|
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.height,
|
|
|
|
self.start_y + dodge,
|
|
|
|
);
|
|
|
|
context.line_to(
|
|
|
|
self.start_x + self.start_length + self.height + self.cutout_length,
|
|
|
|
self.start_y + dodge,
|
|
|
|
);
|
|
|
|
context.line_to(
|
|
|
|
self.start_x
|
|
|
|
+ self.start_length
|
|
|
|
+ self.height
|
|
|
|
+ self.cutout_length
|
|
|
|
+ (self.height / 2.),
|
|
|
|
self.start_y + dodge / 2.,
|
|
|
|
);
|
|
|
|
context.line_to(self.total_length, self.start_y + dodge / 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(
|
2023-04-10 00:07:12 +00:00
|
|
|
self.start_x + dodge,
|
2023-04-09 22:20:29 +00:00
|
|
|
self.start_y + self.start_length + self.height,
|
|
|
|
);
|
|
|
|
context.line_to(
|
2023-04-10 00:07:12 +00:00
|
|
|
self.start_x + dodge,
|
|
|
|
self.start_y + self.start_length + self.height + self.cutout_length,
|
2023-04-09 22:20:29 +00:00
|
|
|
);
|
|
|
|
context.line_to(
|
2023-04-10 00:07:12 +00:00
|
|
|
self.start_x + dodge / 2.,
|
2023-04-09 22:20:29 +00:00
|
|
|
self.start_y
|
|
|
|
+ self.start_length
|
|
|
|
+ self.height
|
2023-04-10 00:07:12 +00:00
|
|
|
+ self.cutout_length
|
2023-04-09 22:20:29 +00:00
|
|
|
+ (self.height / 2.),
|
|
|
|
);
|
2023-04-10 00:07:12 +00:00
|
|
|
context.line_to(self.start_x + dodge / 2., self.total_length);
|
2023-04-09 22:20:29 +00:00
|
|
|
}
|
|
|
|
_ => panic!("unknown orientation"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-04-10 00:07:12 +00:00
|
|
|
|
|
|
|
struct AsymLine {
|
2023-04-09 17:14:10 +00:00
|
|
|
orientation: gtk::Orientation,
|
|
|
|
start_x: f64,
|
|
|
|
start_y: f64,
|
|
|
|
start_length: f64,
|
2023-04-10 00:07:12 +00:00
|
|
|
height: f64,
|
|
|
|
total_length: f64,
|
|
|
|
invert: bool,
|
2023-04-09 17:14:10 +00:00
|
|
|
}
|
|
|
|
|
2023-04-10 00:07:12 +00:00
|
|
|
impl AsymLine {
|
2023-04-09 17:14:10 +00:00
|
|
|
fn draw(&self, context: &Context) {
|
2023-04-10 00:07:12 +00:00
|
|
|
let dodge = if self.invert {
|
|
|
|
self.height
|
|
|
|
} else {
|
|
|
|
-self.height
|
|
|
|
};
|
2023-04-09 17:14:10 +00:00
|
|
|
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(
|
2023-04-10 00:07:12 +00:00
|
|
|
self.start_x + self.start_length + self.height,
|
|
|
|
self.start_y + dodge,
|
2023-04-09 17:14:10 +00:00
|
|
|
);
|
2023-04-10 00:07:12 +00:00
|
|
|
context.line_to(self.start_x + self.total_length, self.start_y + dodge);
|
2023-04-09 17:14:10 +00:00
|
|
|
}
|
2023-04-10 00:07:12 +00:00
|
|
|
gtk::Orientation::Vertical => {}
|
2023-04-09 17:14:10 +00:00
|
|
|
_ => 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();
|
|
|
|
|
2023-04-09 22:20:29 +00:00
|
|
|
window.set_child(Some(&Splash::new("GTK Kifu".to_owned(), "4:23".to_owned())));
|
2023-04-09 17:14:10 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
app.run();
|
|
|
|
}
|