Add screen resize support and animation timeout

This commit is contained in:
Savanni D'Gerinel 2023-04-09 23:55:15 -04:00
parent bed75dc669
commit 4da592ad45
1 changed files with 150 additions and 19 deletions

View File

@ -10,14 +10,49 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
const WIDTH: i32 = 1920; const WIDTH: i32 = 1600;
const HEIGHT: i32 = 1280; const HEIGHT: i32 = 600;
#[derive(Clone, Copy, Debug)]
enum Event {
Frames(u8),
Time(Duration),
}
struct TimeoutAnimation {
intensity: f64,
duration: f64,
ascending: bool,
}
impl TimeoutAnimation {
fn tick(&mut self, frames_elapsed: u8) {
let step_size = 1. / (self.duration * 60.);
if self.ascending {
self.intensity = self.intensity + step_size * frames_elapsed as f64;
if self.intensity > 1. {
self.intensity = 1.0;
self.ascending = false;
}
} else {
self.intensity = self.intensity - step_size * frames_elapsed as f64;
if self.intensity < 0. {
self.intensity = 0.0;
self.ascending = true;
}
}
}
}
pub struct SplashPrivate { pub struct SplashPrivate {
text: Rc<RefCell<String>>, text: Rc<RefCell<String>>,
time: Rc<RefCell<Duration>>, time: Rc<RefCell<Duration>>,
background: Rc<RefCell<Pattern>>, background: Rc<RefCell<Pattern>>,
time_extents: Rc<RefCell<Option<TextExtents>>>, time_extents: Rc<RefCell<Option<TextExtents>>>,
width: Rc<RefCell<i32>>,
height: Rc<RefCell<i32>>,
timeout_animation: Rc<RefCell<Option<TimeoutAnimation>>>,
} }
impl SplashPrivate { impl SplashPrivate {
@ -30,7 +65,9 @@ impl SplashPrivate {
} }
fn redraw_background(&self) { fn redraw_background(&self) {
let background = ImageSurface::create(Format::Rgb24, WIDTH, HEIGHT).unwrap(); let background =
ImageSurface::create(Format::Rgb24, *self.width.borrow(), *self.height.borrow())
.unwrap();
let context = Context::new(background).unwrap(); let context = Context::new(background).unwrap();
context.push_group(); context.push_group();
context.set_source_rgb(0., 0., 0.); context.set_source_rgb(0., 0., 0.);
@ -39,8 +76,8 @@ impl SplashPrivate {
context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold); context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold);
context.set_font_size(128.); context.set_font_size(128.);
let center_x = WIDTH as f64 / 2.; let center_x = *self.width.borrow() as f64 / 2.;
let center_y = HEIGHT as f64 / 2.; let center_y = *self.height.borrow() as f64 / 2.;
let title_extents = context.text_extents(&self.text.borrow()).unwrap(); let title_extents = context.text_extents(&self.text.borrow()).unwrap();
let title_width = title_extents.width(); let title_width = title_extents.width();
@ -54,7 +91,7 @@ impl SplashPrivate {
start_x: 20., start_x: 20.,
start_y: center_y - 20. - title_height / 2., start_y: center_y - 20. - title_height / 2.,
start_length, start_length,
total_length: WIDTH as f64 - 120., total_length: *self.width.borrow() as f64 - 120.,
cutout_length: title_width, cutout_length: title_width,
height: title_height, height: title_height,
invert: false, invert: false,
@ -89,7 +126,7 @@ impl SplashPrivate {
AsymLine { AsymLine {
orientation: gtk::Orientation::Horizontal, orientation: gtk::Orientation::Horizontal,
start_x: 100., start_x: 100.,
start_y: HEIGHT as f64 / 2. + 100., start_y: *self.height.borrow() as f64 / 2. + 100.,
start_length: 400., start_length: 400.,
height: 50., height: 50.,
total_length: 650., total_length: 650.,
@ -103,8 +140,8 @@ impl SplashPrivate {
context.set_source_rgb(0.7, 0., 1.); context.set_source_rgb(0.7, 0., 1.);
AsymLine { AsymLine {
orientation: gtk::Orientation::Horizontal, orientation: gtk::Orientation::Horizontal,
start_x: WIDTH as f64 / 2. + 100., start_x: *self.width.borrow() as f64 / 2. + 100.,
start_y: HEIGHT as f64 / 2. + 200., start_y: *self.height.borrow() as f64 / 2. + 200.,
start_length: 600., start_length: 600.,
height: 50., height: 50.,
total_length: 650., total_length: 650.,
@ -140,6 +177,9 @@ impl ObjectSubclass for SplashPrivate {
time: Rc::new(RefCell::new(Duration::ZERO)), time: Rc::new(RefCell::new(Duration::ZERO)),
background: Rc::new(RefCell::new(background)), background: Rc::new(RefCell::new(background)),
time_extents: Rc::new(RefCell::new(None)), time_extents: Rc::new(RefCell::new(None)),
width: Rc::new(RefCell::new(WIDTH)),
height: Rc::new(RefCell::new(HEIGHT)),
timeout_animation: Rc::new(RefCell::new(None)),
} }
} }
} }
@ -175,6 +215,8 @@ impl Splash {
let center_x = width as f64 / 2.; let center_x = width as f64 / 2.;
let center_y = height as f64 / 2.; let center_y = height as f64 / 2.;
{}
{ {
context.select_font_face( context.select_font_face(
"Alegreya Sans SC", "Alegreya Sans SC",
@ -195,16 +237,42 @@ impl Splash {
let time_baseline_x = center_x - time_extents.width() / 2.; let time_baseline_x = center_x - time_extents.width() / 2.;
let time_baseline_y = center_y + 100.; let time_baseline_y = center_y + 100.;
/*
match *s.imp().timeout_animation.borrow() {
Some(ref animation) => {
context.set_source_rgb(animation.intensity / 2., 0., 0.);
RoundedRectangle {
x: time_baseline_x - 5.,
y: time_baseline_y + 10.,
width: time_extents.width() + 15.,
height: time_extents.height() + 15.,
}
.draw(&context);
// let _ = context.fill();
}
None => {}
}
*/
let gradient = LinearGradient::new( let gradient = LinearGradient::new(
time_baseline_x, time_baseline_x,
time_baseline_y - time_extents.height(), time_baseline_y - time_extents.height(),
time_baseline_x, time_baseline_x,
time_baseline_y, time_baseline_y,
); );
match *s.imp().timeout_animation.borrow() {
Some(ref animation) => {
gradient.add_color_stop_rgba(0.2, 0.2, 0.0, 1.0, animation.intensity);
gradient.add_color_stop_rgba(0.8, 0.7, 0.0, 1.0, animation.intensity);
let _ = context.set_source(gradient);
}
None => {
gradient.add_color_stop_rgb(0.2, 0.2, 0.0, 1.0); 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); 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.set_source(gradient);
}
}
context.move_to(time_baseline_x, time_baseline_y);
let _ = context.show_text(&time); let _ = context.show_text(&time);
}; };
@ -227,13 +295,37 @@ impl Splash {
} }
}); });
s.connect_resize(|s, width, height| {
*s.imp().width.borrow_mut() = width;
*s.imp().height.borrow_mut() = height;
s.imp().redraw_background();
});
s s
} }
pub fn set_time(&self, time: Duration) { pub fn set_time(&self, time: Duration) {
self.imp().set_time(time); self.imp().set_time(time);
if time == Duration::ZERO {
*self.imp().timeout_animation.borrow_mut() = Some(TimeoutAnimation {
intensity: 1.,
duration: 1.,
ascending: false,
});
}
self.queue_draw(); self.queue_draw();
} }
pub fn tick(&self, frames_elapsed: u8) {
let mut animation = self.imp().timeout_animation.borrow_mut();
match *animation {
Some(ref mut animation) => {
animation.tick(frames_elapsed);
self.queue_draw();
}
None => {}
}
}
} }
struct AsymLineCutout { struct AsymLineCutout {
@ -335,6 +427,36 @@ impl AsymLine {
} }
} }
struct RoundedRectangle {
x: f64,
y: f64,
width: f64,
height: f64,
}
impl RoundedRectangle {
fn draw(&self, context: &Context) {
context.arc(
self.x,
self.y - self.height / 2.,
self.height / 2.,
0.5 * std::f64::consts::PI,
1.5 * std::f64::consts::PI,
);
let _ = context.fill();
context.arc(
self.x + self.width,
self.y - self.height / 2.,
self.height / 2.,
1.5 * std::f64::consts::PI,
0.5 * std::f64::consts::PI,
);
let _ = context.fill();
context.rectangle(self.x, self.y, self.width, -self.height);
let _ = context.fill();
}
}
struct SlashMeter { struct SlashMeter {
orientation: gtk::Orientation, orientation: gtk::Orientation,
start_x: f64, start_x: f64,
@ -382,27 +504,36 @@ fn main() {
app.connect_activate(move |app| { app.connect_activate(move |app| {
let (gtk_tx, gtk_rx) = let (gtk_tx, gtk_rx) =
gtk::glib::MainContext::channel::<Duration>(gtk::glib::PRIORITY_DEFAULT); gtk::glib::MainContext::channel::<Event>(gtk::glib::PRIORITY_DEFAULT);
let window = gtk::ApplicationWindow::new(app); let window = gtk::ApplicationWindow::new(app);
window.present(); window.present();
let mut countdown = Duration::from_secs(5 * 60); let mut countdown = Duration::from_secs(5);
let mut next_tick = Instant::now() + Duration::from_secs(1); let mut next_tick = Instant::now() + Duration::from_secs(1);
let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone()); let splash = Splash::new("GTK Kifu".to_owned(), countdown.clone());
window.set_child(Some(&splash)); window.set_child(Some(&splash));
// window.fullscreen();
gtk_rx.attach(None, move |time| { window.connect_maximized_notify(|window| {
splash.set_time(time); window.fullscreen();
});
gtk_rx.attach(None, move |event| {
match event {
Event::Frames(frames) => splash.tick(frames),
Event::Time(time) => splash.set_time(time),
};
Continue(true) Continue(true)
}); });
std::thread::spawn(move || loop { std::thread::spawn(move || loop {
std::thread::sleep(Duration::from_secs(1)); std::thread::sleep(Duration::from_millis(1000 / 60));
if Instant::now() >= next_tick { let _ = gtk_tx.send(Event::Frames(1));
if Instant::now() >= next_tick && countdown > Duration::from_secs(0) {
countdown = countdown - Duration::from_secs(1); countdown = countdown - Duration::from_secs(1);
let _ = gtk_tx.send(countdown); let _ = gtk_tx.send(Event::Time(countdown));
next_tick = next_tick + Duration::from_secs(1); next_tick = next_tick + Duration::from_secs(1);
} }
}); });