From 774a8462102d7a6dae257532559a27f128a9b428 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Sun, 12 May 2024 19:12:01 -0700 Subject: [PATCH] animate_mouse_button + more example recordings --- .github/workflows/docs.yml | 4 +-- CHANGELOG.md | 2 ++ examples/disclose.rs | 43 +++++++++++++++++++++-- examples/list.rs | 12 +++++-- examples/menu.rs | 70 ++++++++++++++++++++++++++++++++++++-- src/widgets/disclose.rs | 7 +++- src/window.rs | 20 +++++++++++ 7 files changed, 149 insertions(+), 9 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9ecf44a..2691dda 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -58,11 +58,11 @@ jobs: - name: Regenerate Example Images run: | - CAPTURE=1 cargo test -p cushy --examples --all-features + CAPTURE=1 cargo test -p cushy --examples --all-features -r - name: Regenerate Guide Example Images run: | - CAPTURE=1 cargo test -p guide-examples --examples + CAPTURE=1 cargo test -p guide-examples --examples -r - name: Build Guide run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index f69d0a3..f137bc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `AnimationRecorder::animate_keypress` is a new helper that animates a single key press. +- `AnimationRecorder::animate_mouse_button` is a new helper that animates a + single mouse button press and release. ## v0.3.0 (2024-05-12) diff --git a/examples/disclose.rs b/examples/disclose.rs index 3f0c1ab..0438538 100644 --- a/examples/disclose.rs +++ b/examples/disclose.rs @@ -2,7 +2,7 @@ use cushy::widget::MakeWidget; use cushy::widgets::Disclose; use cushy::Run; -fn main() -> cushy::Result { +fn disclose() -> impl MakeWidget { Disclose::new( "This is some inner content" .align_left() @@ -10,5 +10,44 @@ fn main() -> cushy::Result { .into_rows(), ) .labelled_by("This demonstrates the Disclose widget") - .run() +} + +fn main() -> cushy::Result { + disclose().run() +} + +#[test] +fn runs() { + use std::time::Duration; + + use cushy::animation::easings::EaseInOutSine; + use figures::units::Px; + use figures::Point; + use kludgine::app::winit::event::MouseButton; + + cushy::example!(disclose, 600, 300) + .prepare_with(|r| { + r.set_cursor_position(Point::new(Px::new(16), Px::new(64))); + r.set_cursor_visible(true); + }) + .animated(|r| { + r.animate_cursor_to( + Point::new(Px::new(30), Px::new(30)), + Duration::from_millis(500), + EaseInOutSine, + ) + .unwrap(); + r.animate_mouse_button(MouseButton::Left, Duration::from_millis(100)) + .unwrap(); + r.wait_for(Duration::from_secs(1)).unwrap(); + r.animate_mouse_button(MouseButton::Left, Duration::from_millis(100)) + .unwrap(); + r.animate_cursor_to( + Point::new(Px::new(16), Px::new(64)), + Duration::from_millis(500), + EaseInOutSine, + ) + .unwrap(); + r.wait_for(Duration::from_secs(1)).unwrap(); + }); } diff --git a/examples/list.rs b/examples/list.rs index b3a8834..5ed7af9 100644 --- a/examples/list.rs +++ b/examples/list.rs @@ -3,7 +3,7 @@ use cushy::widget::{MakeWidget, WidgetList}; use cushy::widgets::list::ListStyle; use cushy::Run; -fn main() -> cushy::Result { +fn list() -> impl MakeWidget { let current_style: Dynamic = Dynamic::default(); let options = ListStyle::provided() .into_iter() @@ -24,5 +24,13 @@ fn main() -> cushy::Result { .into_columns() .expand() .pad() - .run() +} + +fn main() -> cushy::Result { + list().run() +} + +#[test] +fn runs() { + cushy::example!(list).untested_still_frame(); } diff --git a/examples/menu.rs b/examples/menu.rs index 6b3e572..544f281 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -10,7 +10,7 @@ enum MenuOptions { Third, } -fn main() -> cushy::Result { +fn menu_example() -> impl MakeWidget { let overlay = OverlayLayer::default(); "Click Me" @@ -30,7 +30,10 @@ fn main() -> cushy::Result { .expand() .and(overlay) .into_layers() - .run() +} + +fn main() -> cushy::Result { + menu_example().run() } fn menu(top: bool) -> Menu { @@ -53,3 +56,66 @@ fn menu(top: bool) -> Menu { .with_separator() .with(third) } + +#[test] +fn runs() { + use std::time::Duration; + + use cushy::animation::easings::{EaseInCircular, EaseInOutSine, EaseOutCircular}; + use figures::units::Px; + use figures::Point; + use kludgine::app::winit::event::MouseButton; + + cushy::example!(menu_example, 800, 600) + .prepare_with(|r| { + r.set_cursor_position(Point::new(Px::new(420), Px::new(270))); + r.set_cursor_visible(true); + r.refresh().unwrap(); + }) + .animated(|r| { + r.animate_cursor_to( + Point::new(Px::new(410), Px::new(300)), + Duration::from_millis(500), + EaseInOutSine, + ) + .unwrap(); + r.animate_mouse_button(MouseButton::Left, Duration::from_millis(250)) + .unwrap(); + r.wait_for(Duration::from_millis(500)).unwrap(); + r.animate_cursor_to( + Point::new(Px::new(430), Px::new(325)), + Duration::from_millis(200), + EaseInCircular, + ) + .unwrap(); + r.animate_cursor_to( + Point::new(Px::new(480), Px::new(480)), + Duration::from_millis(400), + EaseOutCircular, + ) + .unwrap(); + r.wait_for(Duration::from_millis(300)).unwrap(); + r.animate_cursor_to( + Point::new(Px::new(620), Px::new(460)), + Duration::from_millis(600), + EaseInOutSine, + ) + .unwrap(); + r.animate_cursor_to( + Point::new(Px::new(460), Px::new(340)), + Duration::from_millis(800), + EaseInOutSine, + ) + .unwrap(); + r.animate_mouse_button(MouseButton::Left, Duration::from_millis(250)) + .unwrap(); + r.wait_for(Duration::from_millis(500)).unwrap(); + r.animate_cursor_to( + Point::new(Px::new(420), Px::new(270)), + Duration::from_millis(500), + EaseInOutSine, + ) + .unwrap(); + r.wait_for(Duration::from_millis(500)).unwrap(); + }); +} diff --git a/src/widgets/disclose.rs b/src/widgets/disclose.rs index 870e311..4d4bbd2 100644 --- a/src/widgets/disclose.rs +++ b/src/widgets/disclose.rs @@ -333,7 +333,7 @@ impl Widget for DiscloseIndicator { fn mouse_up( &mut self, - _location: Option>, + location: Option>, _device_id: DeviceId, _button: kludgine::app::winit::event::MouseButton, context: &mut EventContext<'_>, @@ -343,6 +343,11 @@ impl Widget for DiscloseIndicator { self.deactivate(context); self.collapsed.toggle(); } + let hovering = location.map_or(false, |location| self.hit_test(location, context)); + if hovering != self.hovering_indicator { + self.hovering_indicator = hovering; + context.set_needs_redraw(); + } } fn activate(&mut self, _context: &mut EventContext<'_>) { diff --git a/src/window.rs b/src/window.rs index 930a8eb..d203c5d 100644 --- a/src/window.rs +++ b/src/window.rs @@ -3500,6 +3500,26 @@ where self.wait_for(over) } + /// Animates pressing and releasing a mouse button at the current cursor + /// location. + pub fn animate_mouse_button( + &mut self, + button: MouseButton, + duration: Duration, + ) -> Result<(), VirtualRecorderError> { + let _ = + self.recorder + .window + .mouse_input(DeviceId::Virtual(0), ElementState::Pressed, button); + + self.wait_for(duration)?; + let _ = + self.recorder + .window + .mouse_input(DeviceId::Virtual(0), ElementState::Released, button); + Ok(()) + } + /// Simulates a key down and key up event with the given information. pub fn animate_keypress( &mut self,