From 9d1c0ad7905e1509746f8d47564f3af532cb608c Mon Sep 17 00:00:00 2001 From: thearturca Date: Sun, 24 Sep 2023 12:37:26 +0300 Subject: [PATCH] feature: animation Commit to pull changes from master --- komorebi/src/animation.rs | 55 +++++++++++++++++++++++++++++++++++++++ komorebi/src/main.rs | 1 + komorebi/src/window.rs | 28 +++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 komorebi/src/animation.rs diff --git a/komorebi/src/animation.rs b/komorebi/src/animation.rs new file mode 100644 index 00000000..2e24743b --- /dev/null +++ b/komorebi/src/animation.rs @@ -0,0 +1,55 @@ +use color_eyre::Result; +use komorebi_core::Rect; +use std::thread::sleep; +use std::time::Duration; +use std::time::Instant; + +pub struct Animation; + +impl Animation { + pub fn lerp(x: i32, new_x: i32, t: f64) -> i32 { + (x as f64 + (new_x - x) as f64 * t) as i32 + } + + pub fn lerp_rect(original_rect: &Rect, new_rect: &Rect, t: f64) -> Rect { + let is_half_way = t > 0.5; + let mut rect = Rect::default(); + rect.top = Animation::lerp(original_rect.top, new_rect.top, t); + rect.left = Animation::lerp(original_rect.left, new_rect.left, t); + rect.bottom = if is_half_way { + new_rect.bottom + } else { + original_rect.bottom + }; + rect.right = if is_half_way { + new_rect.right + } else { + original_rect.right + }; + + rect + } + + pub fn animate(duration: Duration, mut f: impl FnMut(f64) -> Result<()>) -> bool { + let target_frame_time = Duration::from_millis(1000 / 240); + let mut progress = 0.0; + let &animation_start = &Instant::now(); + + while progress < 1.0 { + let tick_start = Instant::now(); + f(progress).unwrap(); + progress = animation_start.elapsed().as_millis() as f64 / duration.as_millis() as f64; + + if progress > 1.0 { + progress = 1.0; + } + + while tick_start.elapsed() < target_frame_time { + sleep(target_frame_time - tick_start.elapsed()); + } + } + + f(progress).unwrap(); + true + } +} diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 801e23af..62f436ab 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -65,6 +65,7 @@ use crate::windows_api::WindowsApi; #[macro_use] mod ring; +mod animation; mod border; mod com; mod container; diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index b991baac..f47f0e92 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -5,6 +5,8 @@ use std::fmt::Display; use std::fmt::Formatter; use std::fmt::Write as _; use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; use color_eyre::eyre::anyhow; use color_eyre::Result; @@ -25,6 +27,7 @@ use komorebi_core::ApplicationIdentifier; use komorebi_core::HidingBehaviour; use komorebi_core::Rect; +use crate::animation::Animation; use crate::styles::ExtendedWindowStyle; use crate::styles::WindowStyle; use crate::window_manager_event::WindowManagerEvent; @@ -122,6 +125,22 @@ impl Window { true, ) } + pub fn animate_position(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> { + let duration = Duration::from_millis(200); + let curr_rect = WindowsApi::window_rect(hwnd).unwrap(); + + if assert_eq!(curr_rect, *layout) { + WindowsApi::position_window(hwnd, layout, top); + } + + let animate_window = |progress: f64| { + let new_rect = Animation::lerp_rect(&curr_rect, layout, progress); + WindowsApi::position_window(hwnd, &new_rect, top); + }; + + Animation::animate(duration, animate_window); + Ok(()) + } pub fn set_position( &mut self, @@ -154,7 +173,14 @@ impl Window { rect.bottom += invisible_borders.bottom; } - WindowsApi::position_window(self.hwnd(), &rect, top) + let hwnd = self.hwnd(); + + thread::spawn(move || { + Window::animate_position(hwnd, &rect, top).unwrap(); + }); + Ok(()) + + // WindowsApi::position_window(self.hwnd(), &rect, top) } pub fn hide(self) {