Create a cyberpunk-style splash screen with a title and a countdown #39
|
@ -3,14 +3,18 @@ use cairo::{
|
||||||
};
|
};
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{prelude::*, subclass::prelude::*};
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
rc::Rc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
const WIDTH: i32 = 1920;
|
const WIDTH: i32 = 1920;
|
||||||
const HEIGHT: i32 = 1280;
|
const HEIGHT: i32 = 1280;
|
||||||
|
|
||||||
pub struct SplashPrivate {
|
pub struct SplashPrivate {
|
||||||
text: Rc<RefCell<String>>,
|
text: Rc<RefCell<String>>,
|
||||||
time: Rc<RefCell<String>>,
|
time: Rc<RefCell<Duration>>,
|
||||||
background: Rc<RefCell<Pattern>>,
|
background: Rc<RefCell<Pattern>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +23,7 @@ impl SplashPrivate {
|
||||||
*self.text.borrow_mut() = text;
|
*self.text.borrow_mut() = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_time(&self, time: String) {
|
fn set_time(&self, time: Duration) {
|
||||||
*self.time.borrow_mut() = time;
|
*self.time.borrow_mut() = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,25 +112,6 @@ impl SplashPrivate {
|
||||||
let _ = context.stroke();
|
let _ = context.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
let background = context.pop_group().unwrap();
|
let background = context.pop_group().unwrap();
|
||||||
|
|
||||||
*self.background.borrow_mut() = background;
|
*self.background.borrow_mut() = background;
|
||||||
|
@ -150,7 +135,7 @@ impl ObjectSubclass for SplashPrivate {
|
||||||
|
|
||||||
SplashPrivate {
|
SplashPrivate {
|
||||||
text: Rc::new(RefCell::new(String::from(""))),
|
text: Rc::new(RefCell::new(String::from(""))),
|
||||||
time: Rc::new(RefCell::new(String::from(""))),
|
time: Rc::new(RefCell::new(Duration::ZERO)),
|
||||||
background: Rc::new(RefCell::new(background)),
|
background: Rc::new(RefCell::new(background)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +149,7 @@ glib::wrapper! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Splash {
|
impl Splash {
|
||||||
pub fn new(text: String, time: String) -> Self {
|
pub fn new(text: String, time: Duration) -> Self {
|
||||||
let s: Self = Object::builder().build();
|
let s: Self = Object::builder().build();
|
||||||
s.set_width_request(WIDTH);
|
s.set_width_request(WIDTH);
|
||||||
s.set_height_request(HEIGHT);
|
s.set_height_request(HEIGHT);
|
||||||
|
@ -175,15 +160,53 @@ impl Splash {
|
||||||
|
|
||||||
s.set_draw_func({
|
s.set_draw_func({
|
||||||
let s = s.clone();
|
let s = s.clone();
|
||||||
move |_, context, _width, _height| {
|
move |_, context, width, height| {
|
||||||
let background = s.imp().background.borrow();
|
let background = s.imp().background.borrow();
|
||||||
let _ = context.set_source(&*background);
|
let _ = context.set_source(&*background);
|
||||||
let _ = context.paint();
|
let _ = context.paint();
|
||||||
|
|
||||||
|
{
|
||||||
|
let center_x = width as f64 / 2.;
|
||||||
|
let center_y = height as f64 / 2.;
|
||||||
|
|
||||||
|
context.select_font_face(
|
||||||
|
"Alegreya Sans SC",
|
||||||
|
FontSlant::Normal,
|
||||||
|
FontWeight::Bold,
|
||||||
|
);
|
||||||
|
context.set_font_size(128.);
|
||||||
|
|
||||||
|
let time = s.imp().time.borrow().clone();
|
||||||
|
let minutes = time.as_secs() / 60;
|
||||||
|
let seconds = time.as_secs() % 60;
|
||||||
|
let time = format!("{:02}' {:02}\"", minutes, seconds);
|
||||||
|
|
||||||
|
let time_extents = context.text_extents(&time).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(&time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_time(&self, time: Duration) {
|
||||||
|
self.imp().set_time(time);
|
||||||
|
self.queue_draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AsymLineCutout {
|
struct AsymLineCutout {
|
||||||
|
@ -291,10 +314,31 @@ fn main() {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
app.connect_activate(move |app| {
|
app.connect_activate(move |app| {
|
||||||
|
let (gtk_tx, gtk_rx) =
|
||||||
|
gtk::glib::MainContext::channel::<Duration>(gtk::glib::PRIORITY_DEFAULT);
|
||||||
let window = gtk::ApplicationWindow::new(app);
|
let window = gtk::ApplicationWindow::new(app);
|
||||||
window.present();
|
window.present();
|
||||||
|
|
||||||
window.set_child(Some(&Splash::new("GTK Kifu".to_owned(), "4:23".to_owned())));
|
let mut countdown = Duration::from_secs(5 * 60);
|
||||||
|
let mut next_tick = Instant::now() + Duration::from_secs(1);
|
||||||
|
|
||||||
|
let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone());
|
||||||
|
|
||||||
|
window.set_child(Some(&splash));
|
||||||
|
|
||||||
|
gtk_rx.attach(None, move |time| {
|
||||||
|
splash.set_time(time);
|
||||||
|
Continue(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
std::thread::sleep(Duration::from_secs(1));
|
||||||
|
if Instant::now() >= next_tick {
|
||||||
|
countdown = countdown - Duration::from_secs(1);
|
||||||
|
let _ = gtk_tx.send(countdown);
|
||||||
|
next_tick = next_tick + Duration::from_secs(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.run();
|
app.run();
|
||||||
|
|
Loading…
Reference in New Issue