From cda13c42a200ecad2db036b110adf7c97ef9ae52 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Sat, 6 Jan 2024 14:46:48 -0800 Subject: [PATCH] Guide intro + KeyEvent Also fixed virtual window's refresh handling. --- CHANGELOG.md | 2 + guide/guide-examples/examples/hello-world.rs | 16 +++ guide/guide-examples/examples/intro.rs | 49 ++++++++ guide/guide-examples/src/lib.rs | 97 +++++++++++++--- guide/src/examples/hello_world.png | Bin 0 -> 7058 bytes guide/src/examples/intro.png | Bin 0 -> 90580 bytes guide/src/intro.md | 48 ++++++++ src/context.rs | 4 +- src/tick.rs | 3 +- src/widget.rs | 6 +- src/widgets/custom.rs | 4 +- src/widgets/input.rs | 9 +- src/widgets/slider.rs | 4 +- src/widgets/tilemap.rs | 4 +- src/window.rs | 115 +++++++++++++++++-- 15 files changed, 317 insertions(+), 44 deletions(-) create mode 100644 guide/guide-examples/examples/hello-world.rs create mode 100644 guide/guide-examples/examples/intro.rs create mode 100644 guide/src/examples/hello_world.png create mode 100644 guide/src/examples/intro.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 61bac5f..87e00af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `Label::text` is now named `display` and `Label::new()` now accepts an `IntoReadOnly` instead of `IntoValue`. - `Dynamic::wrap` has been renamed to `into_wrap` for consistency. +- Cushy now has its own `KeyEvent` type, as winit's has private fields. This + prevented simulating input in a `VirtualWindow`. ### Fixed diff --git a/guide/guide-examples/examples/hello-world.rs b/guide/guide-examples/examples/hello-world.rs new file mode 100644 index 0000000..fd91cc0 --- /dev/null +++ b/guide/guide-examples/examples/hello-world.rs @@ -0,0 +1,16 @@ +// ANCHOR: example +use cushy::Run; + +fn main() -> cushy::Result { + "Hello, World!".run() +} +// ANCHOR_END: example + +#[test] +fn book() { + fn hello_world() -> impl MakeWidget { + "Hello, World!" + } + + guide_examples::book_example!(hello_world).untested_still_frame(); +} diff --git a/guide/guide-examples/examples/intro.rs b/guide/guide-examples/examples/intro.rs new file mode 100644 index 0000000..e990df2 --- /dev/null +++ b/guide/guide-examples/examples/intro.rs @@ -0,0 +1,49 @@ +// ANCHOR: example +use cushy::value::{Dynamic, Source}; +use cushy::widget::MakeWidget; +use cushy::widgets::input::{Input, InputValue}; +use cushy::Run; + +fn main() -> cushy::Result { + // Create storage for user to enter a name. + let name: Dynamic = Dynamic::default(); + + // Create our label by using `map_each` to format the name, first checking + // if it is empty. + let greeting: Dynamic = name.map_each(|name| { + let name = if name.is_empty() { "World" } else { name }; + format!("Hello, {name}!") + }); + + // Create the input widget with a placeholder. + let name_input: Input = name.into_input().placeholder("Name"); + + // Stack our widgets as rows, and run the app. + name_input.and(greeting).into_rows().run() +} +// ANCHOR_END: example + +#[test] +fn book() { + use std::time::Duration; + + fn intro() -> impl MakeWidget { + let subject: Dynamic = Dynamic::default(); + let greeting: Dynamic = subject.map_each(|subject| { + let subject = if subject.is_empty() { "World" } else { subject }; + format!("Hello, {subject}!") + }); + + let name_input: Input = subject.into_input().placeholder("Name"); + + name_input.and(greeting).into_rows() + } + + guide_examples::book_example!(intro).animated(|animation| { + animation.wait_for(Duration::from_millis(1_000)).unwrap(); + animation + .animate_text_input("Ferris 🦀", Duration::from_secs(1)) + .unwrap(); + animation.wait_for(Duration::from_millis(1_000)).unwrap(); + }); +} diff --git a/guide/guide-examples/src/lib.rs b/guide/guide-examples/src/lib.rs index 40f2bcb..0e9e8fc 100644 --- a/guide/guide-examples/src/lib.rs +++ b/guide/guide-examples/src/lib.rs @@ -5,13 +5,49 @@ use cushy::figures::units::Px; use cushy::figures::Size; use cushy::widget::MakeWidget; use cushy::widgets::container::ContainerShadow; -use cushy::window::{Rgba8, VirtualRecorder, VirtualRecorderBuilder}; +use cushy::window::{AnimationRecorder, Rgba8, VirtualRecorder, VirtualRecorderBuilder}; -pub struct BookExample { +pub struct BookExampleBuilder { name: &'static str, recorder: VirtualRecorderBuilder, } +impl BookExampleBuilder { + pub fn finish(self) -> BookExample { + let mut recorder = self.recorder.finish().expect("error creating recorder"); + recorder.window.set_focused(true); + BookExample { + name: self.name, + recorder, + } + } + + pub fn untested_still_frame(self) { + self.finish().untested_still_frame() + } + + pub fn prepare_with(self, prepare: Prepare) -> BookExample + where + Prepare: FnOnce(&mut VirtualRecorder), + { + self.finish().prepare_with(prepare) + } + + pub fn still_frame(self, test: Test) + where + Test: FnOnce(&mut VirtualRecorder), + { + self.finish().still_frame(test); + } + + pub fn animated(self, test: Test) + where + Test: FnOnce(&mut AnimationRecorder<'_, Rgba8>), + { + self.finish().animated(test); + } +} + fn target_dir() -> PathBuf { let target_dir = std::env::current_dir() .expect("missing current dir") @@ -27,9 +63,14 @@ fn target_dir() -> PathBuf { target_dir } +pub struct BookExample { + name: &'static str, + recorder: VirtualRecorder, +} + impl BookExample { - pub fn new(name: &'static str, interface: impl MakeWidget) -> Self { - Self { + pub fn build(name: &'static str, interface: impl MakeWidget) -> BookExampleBuilder { + BookExampleBuilder { name, recorder: interface .contain() @@ -42,17 +83,31 @@ impl BookExample { } } - pub fn still_frame(self, test: Test) + pub fn untested_still_frame(self) { + self.still_frame(|_| {}); + } + + pub fn prepare_with(mut self, prepare: Prepare) -> Self + where + Prepare: FnOnce(&mut VirtualRecorder), + { + prepare(&mut self.recorder); + self + } + + pub fn still_frame(mut self, test: Test) where Test: FnOnce(&mut VirtualRecorder), { - let mut recorder = self.recorder.finish().unwrap(); - let capture = std::env::var("CAPTURE").is_ok(); - let errored = std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut recorder))).is_err(); + let errored = + std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut self.recorder))).is_err(); if errored || capture { let path = target_dir().join(format!("{}.png", self.name)); - recorder.image().save(&path).expect("error saving file"); + self.recorder + .image() + .save(&path) + .expect("error saving file"); println!("Wrote {}", path.display()); if errored { @@ -61,16 +116,28 @@ impl BookExample { } } - // pub fn animated(self, test: Test) - // where - // Test: FnOnce(&mut AnimationRecorder<'_, Rgb8>), - // { - // } + pub fn animated(mut self, test: Test) + where + Test: FnOnce(&mut AnimationRecorder<'_, Rgba8>), + { + let mut animation = self.recorder.record_animated_png(60); + let capture = std::env::var("CAPTURE").is_ok(); + let errored = std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut animation))).is_err(); + if errored || capture { + let path = target_dir().join(format!("{}.png", self.name)); + animation.write_to(&path).expect("error saving file"); + println!("Wrote {}", path.display()); + + if errored { + std::process::exit(-1); + } + } + } } #[macro_export] macro_rules! book_example { ($name:ident) => { - guide_examples::BookExample::new(stringify!($name), $name()) + guide_examples::BookExample::build(stringify!($name), $name()) }; } diff --git a/guide/src/examples/hello_world.png b/guide/src/examples/hello_world.png new file mode 100644 index 0000000000000000000000000000000000000000..76c2c795f4e8d20c9a6ba09002eb39e9dad5fd03 GIT binary patch literal 7058 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�)XjfpfRKD3=?kDXL3Ms0MJ2z_hCUViUIYRZ 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 literal 0 HcmV?d00001 diff --git a/guide/src/intro.md b/guide/src/intro.md index fcde68f..e5cb461 100644 --- a/guide/src/intro.md +++ b/guide/src/intro.md @@ -7,6 +7,54 @@ This is a user's guide for [Cushy][cushy], a [Rust][rust] GUI crate. The functionality quickly. This guide is aimed to providing an example-rich walkthrough of how to use and extend Cushy. +## A "Hello, World" Example + +Here's the simplest "Hello, World" example: + +```rust,no_run,no_playground +{{#include ../guide-examples/examples/hello-world.rs:example}} +``` + +When run, the app just displays the text as one would hope: + +![Hello World Example](./examples/hello_world.png) + +That was a little too easy. Let's take it a step further by letting a user type +in their name and have a label display "Hello, {name}!": + +```rust,no_run,no_playground +{{#include ../guide-examples/examples/intro.rs:example}} +``` + +This app looks like this when executed: + +![Hello Ferris Example](./examples/intro.png) + +In this example, both `name` and `greeting` are [`Dynamic`s][dynamic]. A +`Dynamic` is an `Arc>`-like type that is able to invoke a set of +callbacks when its contents is changed. This simple feature is the core of +Cushy's reactive data model. + +Each time `name` is changed, the `map_each` closure will be executed and +`greeting` will be updated with the result. Now that we have the individual +pieces of data our user interface is going to work with, we can start assembling +the interface. + +First, we create `name_input` by converting the `Dynamic` into a text +[`Input`][input]. Since `Dynamic` can be used as a +[`Label`][label], all that's left is laying out our two widgets. + +To layout `name_input` and `greeting`, we use a [`Stack`][stack] to lay out the +widgets as rows. + +Don't worry if this example seems a bit magical or confusing as to how it works. +Cushy can feel magical to use. But, it should never be a mystery. The goal of +this guide is to try and explain how and why Cushy works the way it does. + [cushy]: [rust]: [docs]: <{{docs}}> +[dynamic]: <{{docs}}/value/struct.Dynamic.html> +[input]: <{{docs}}/widgets/input/struct.Input.html> +[label]: <{{docs}}/widgets/label/struct.Label.html> +[stack]: <{{docs}}/widgets/stack/struct.Stack.html> diff --git a/src/context.rs b/src/context.rs index 56b215a..ccc8747 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut}; use figures::units::{Lp, Px, UPx}; use figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size, Zero}; -use kludgine::app::winit::event::{Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase}; +use kludgine::app::winit::event::{Ime, MouseButton, MouseScrollDelta, TouchPhase}; use kludgine::app::winit::window::CursorIcon; use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::{Color, Kludgine, KludgineId}; @@ -19,7 +19,7 @@ use crate::styles::{ComponentDefinition, Styles, Theme, ThemePair}; use crate::tree::Tree; use crate::value::{IntoValue, Source, Value}; use crate::widget::{EventHandling, MountedWidget, RootBehavior, WidgetId, WidgetInstance}; -use crate::window::{CursorState, DeviceId, PlatformWindow, ThemeMode}; +use crate::window::{CursorState, DeviceId, KeyEvent, PlatformWindow, ThemeMode}; use crate::ConstraintLimit; /// A context to an event function. diff --git a/src/tick.rs b/src/tick.rs index b1dfe70..6120618 100644 --- a/src/tick.rs +++ b/src/tick.rs @@ -6,13 +6,14 @@ use ahash::AHashSet; use figures::units::Px; use figures::Point; use intentional::Assert; -use kludgine::app::winit::event::{ElementState, KeyEvent, MouseButton}; +use kludgine::app::winit::event::{ElementState, MouseButton}; use kludgine::app::winit::keyboard::Key; use crate::context::WidgetContext; use crate::utils::IgnorePoison; use crate::value::{Destination, Dynamic}; use crate::widget::{EventHandling, HANDLED, IGNORED}; +use crate::window::KeyEvent; /// A fixed-rate callback that provides access to tracked input on its /// associated widget. diff --git a/src/widget.rs b/src/widget.rs index 25857bf..d30de58 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -12,7 +12,7 @@ use alot::LotId; use figures::units::{Px, UPx}; use figures::{IntoSigned, IntoUnsigned, Point, Rect, Size}; use intentional::Assert; -use kludgine::app::winit::event::{Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase}; +use kludgine::app::winit::event::{Ime, MouseButton, MouseScrollDelta, TouchPhase}; use kludgine::app::winit::window::CursorIcon; use kludgine::Color; @@ -45,8 +45,8 @@ use crate::widgets::{ }; use crate::window::sealed::WindowCommand; use crate::window::{ - CushyWindowBuilder, DeviceId, Rgb8, RunningWindow, ThemeMode, VirtualRecorderBuilder, Window, - WindowBehavior, WindowHandle, WindowLocal, + CushyWindowBuilder, DeviceId, KeyEvent, Rgb8, RunningWindow, ThemeMode, VirtualRecorderBuilder, + Window, WindowBehavior, WindowHandle, WindowLocal, }; use crate::ConstraintLimit; diff --git a/src/widgets/custom.rs b/src/widgets/custom.rs index 8220346..cddac27 100644 --- a/src/widgets/custom.rs +++ b/src/widgets/custom.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; use figures::units::Px; use figures::{Point, Size}; -use kludgine::app::winit::event::{Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase}; +use kludgine::app::winit::event::{Ime, MouseButton, MouseScrollDelta, TouchPhase}; use kludgine::app::winit::window::CursorIcon; use kludgine::Color; @@ -11,7 +11,7 @@ use crate::styles::VisualOrder; use crate::value::{IntoValue, Value}; use crate::widget::{EventHandling, MakeWidget, WidgetRef, WrappedLayout, WrapperWidget, IGNORED}; use crate::widgets::Space; -use crate::window::DeviceId; +use crate::window::{DeviceId, KeyEvent}; use crate::ConstraintLimit; /// A callback-based custom widget. diff --git a/src/widgets/input.rs b/src/widgets/input.rs index 0aec7fe..caf0d43 100644 --- a/src/widgets/input.rs +++ b/src/widgets/input.rs @@ -13,7 +13,7 @@ use figures::{ Abs, FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, Round, ScreenScale, Size, }; use intentional::Cast; -use kludgine::app::winit::event::{ElementState, Ime, KeyEvent}; +use kludgine::app::winit::event::{ElementState, Ime}; use kludgine::app::winit::keyboard::{Key, NamedKey}; use kludgine::app::winit::window::{CursorIcon, ImePurpose}; use kludgine::shapes::{Shape, StrokeOptions}; @@ -27,13 +27,14 @@ use crate::styles::components::{HighlightColor, IntrinsicPadding, OutlineColor, use crate::utils::ModifiersExt; use crate::value::{Destination, Dynamic, Generation, IntoDynamic, IntoValue, Source, Value}; use crate::widget::{Callback, EventHandling, Widget, HANDLED, IGNORED}; +use crate::window::KeyEvent; use crate::{ConstraintLimit, Lazy}; const CURSOR_BLINK_DURATION: Duration = Duration::from_millis(500); /// A text input widget. #[must_use] -pub struct Input { +pub struct Input { /// The value of this widget. pub value: Dynamic, /// The placeholder text to display when no value is present. @@ -1149,8 +1150,6 @@ where ); } context.redraw_in(cursor_state.remaining_until_blink); - } else { - context.redraw_when_changed(context.window().focused()); } } @@ -1190,7 +1189,7 @@ where fn keyboard_input( &mut self, _device_id: crate::window::DeviceId, - input: kludgine::app::winit::event::KeyEvent, + input: KeyEvent, _is_synthetic: bool, context: &mut EventContext<'_>, ) -> EventHandling { diff --git a/src/widgets/slider.rs b/src/widgets/slider.rs index 4987564..9a74cc8 100644 --- a/src/widgets/slider.rs +++ b/src/widgets/slider.rs @@ -21,7 +21,7 @@ use crate::styles::components::{ use crate::styles::{Dimension, HorizontalOrder, VerticalOrder, VisualOrder}; use crate::value::{Destination, Dynamic, IntoDynamic, IntoValue, Source, Value}; use crate::widget::{EventHandling, Widget, HANDLED, IGNORED}; -use crate::window::DeviceId; +use crate::window::{DeviceId, KeyEvent}; use crate::ConstraintLimit; /// A widget that allows sliding between two values. @@ -673,7 +673,7 @@ where fn keyboard_input( &mut self, _device_id: DeviceId, - input: kludgine::app::winit::event::KeyEvent, + input: KeyEvent, _is_synthetic: bool, _context: &mut EventContext<'_>, ) -> EventHandling { diff --git a/src/widgets/tilemap.rs b/src/widgets/tilemap.rs index b976470..80430e5 100644 --- a/src/widgets/tilemap.rs +++ b/src/widgets/tilemap.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use figures::units::{Px, UPx}; use figures::{Point, Size}; use intentional::Cast; -use kludgine::app::winit::event::{ElementState, KeyEvent, MouseScrollDelta, TouchPhase}; +use kludgine::app::winit::event::{ElementState, MouseScrollDelta, TouchPhase}; use kludgine::app::winit::window::CursorIcon; use kludgine::tilemap; use kludgine::tilemap::TileMapFocus; @@ -12,7 +12,7 @@ use crate::context::{EventContext, GraphicsContext, LayoutContext, Trackable}; use crate::tick::Tick; use crate::value::{Dynamic, IntoValue, Value}; use crate::widget::{EventHandling, Widget, HANDLED, IGNORED}; -use crate::window::DeviceId; +use crate::window::{DeviceId, KeyEvent}; use crate::ConstraintLimit; /// A layered tile-based 2d game surface. diff --git a/src/window.rs b/src/window.rs index 7865e9c..bf32c39 100644 --- a/src/window.rs +++ b/src/window.rs @@ -24,9 +24,11 @@ use image::{DynamicImage, RgbImage, RgbaImage}; use intentional::{Assert, Cast}; use kludgine::app::winit::dpi::{PhysicalPosition, PhysicalSize}; use kludgine::app::winit::event::{ - ElementState, Ime, KeyEvent, Modifiers, MouseButton, MouseScrollDelta, TouchPhase, + ElementState, Ime, Modifiers, MouseButton, MouseScrollDelta, TouchPhase, +}; +use kludgine::app::winit::keyboard::{ + Key, KeyCode, KeyLocation, NamedKey, NativeKeyCode, PhysicalKey, SmolStr, }; -use kludgine::app::winit::keyboard::{Key, NamedKey}; use kludgine::app::winit::window::{self, CursorIcon}; use kludgine::app::{winit, WindowBehavior as _}; use kludgine::cosmic_text::{fontdb, Family, FamilyOwned}; @@ -35,6 +37,7 @@ use kludgine::shapes::Shape; use kludgine::wgpu::{self, CompositeAlphaMode, COPY_BYTES_PER_ROW_ALIGNMENT}; use kludgine::{Color, DrawableExt, Kludgine, KludgineId, Origin, Texture}; use tracing::Level; +use unicode_segmentation::UnicodeSegmentation; use crate::animation::{ AnimationTarget, Easing, LinearInterpolate, PercentBetween, Spawn, ZeroToOne, @@ -1298,6 +1301,14 @@ where self.root.invalidate(); } + pub fn set_focused(&mut self, focused: bool) { + self.focused.set(focused); + } + + pub fn set_occluded(&mut self, occluded: bool) { + self.occluded.set(occluded); + } + pub fn keyboard_input( &mut self, window: W, @@ -1674,7 +1685,7 @@ where window: kludgine::app::Window<'_, WindowCommand>, _kludgine: &mut Kludgine, ) { - self.focused.set(window.focused()); + self.set_focused(window.focused()); } fn occlusion_changed( @@ -1682,7 +1693,7 @@ where window: kludgine::app::Window<'_, WindowCommand>, _kludgine: &mut Kludgine, ) { - self.occluded.set(window.ocluded()); + self.set_occluded(window.ocluded()); } fn render<'pass>( @@ -1778,10 +1789,16 @@ where window: kludgine::app::Window<'_, WindowCommand>, kludgine: &mut Kludgine, device_id: winit::event::DeviceId, - input: KeyEvent, + input: winit::event::KeyEvent, is_synthetic: bool, ) { - self.keyboard_input(window, kludgine, device_id.into(), input, is_synthetic); + self.keyboard_input( + window, + kludgine, + device_id.into(), + input.into(), + is_synthetic, + ); } fn mouse_wheel( @@ -2570,6 +2587,14 @@ impl CushyWindow { kludgine::Graphics::new(&mut self.kludgine, device, queue) } + pub fn set_focused(&mut self, focused: bool) { + self.window.set_focused(focused); + } + + pub fn set_occluded(&mut self, occluded: bool) { + self.window.set_occluded(occluded); + } + /// Requests that the window close. /// /// Returns true if the request should be honored. @@ -2699,6 +2724,7 @@ impl VirtualWindow { .map(|i| now.duration_since(i)) .unwrap_or_default(); self.last_rendered_at = Some(now); + self.state.dynamic.redraw_target.set(RedrawTarget::Never); self.cushy.prepare(&mut self.state, device, queue); } @@ -2726,7 +2752,6 @@ impl VirtualWindow { queue: &wgpu::Queue, additional_drawing: Option<&Drawing>, ) -> Option { - self.state.dynamic.redraw_target.set(RedrawTarget::Never); self.cushy .render_with(pass, device, queue, additional_drawing) } @@ -2739,7 +2764,6 @@ impl VirtualWindow { device: &wgpu::Device, queue: &wgpu::Queue, ) -> Option { - self.state.dynamic.redraw_target.set(RedrawTarget::Never); self.cushy.render_into(texture, load_op, device, queue) } @@ -2766,6 +2790,14 @@ impl VirtualWindow { } } + pub fn set_focused(&mut self, focused: bool) { + self.cushy.set_focused(focused); + } + + pub fn set_occluded(&mut self, occluded: bool) { + self.cushy.set_occluded(occluded); + } + /// Returns true if this window should no longer be open. #[must_use] pub fn closed(&self) -> bool { @@ -3363,6 +3395,40 @@ where self.wait_for(over) } + pub fn animate_text_input( + &mut self, + text: &str, + duration: Duration, + ) -> Result<(), VirtualRecorderError> { + let graphemes = text.graphemes(true).count(); + let delay_per_event = + Duration::from_nanos(duration.as_nanos().cast::() / graphemes.cast::() / 2); + for grapheme in text.graphemes(true) { + let grapheme = SmolStr::new(grapheme); + let mut event = KeyEvent { + physical_key: PhysicalKey::Unidentified(NativeKeyCode::Xkb(0)), + logical_key: Key::Character(grapheme.clone()), + text: Some(SmolStr::new(grapheme)), + location: KeyLocation::Standard, + state: ElementState::Pressed, + repeat: false, + }; + let _handled = + self.recorder + .window + .keyboard_input(DeviceId::Virtual(0), event.clone(), true); + self.wait_for(delay_per_event)?; + + event.state = ElementState::Released; + let _handled = self + .recorder + .window + .keyboard_input(DeviceId::Virtual(0), event, true); + self.wait_for(delay_per_event)?; + } + Ok(()) + } + /// Waits for `duration`, rendering frames as needed. pub fn wait_for(&mut self, duration: Duration) -> Result<(), VirtualRecorderError> { self.wait_until(Instant::now() + duration) @@ -3391,7 +3457,7 @@ where RedrawTarget::At(instant) => now.min(instant), }; - if final_frame || next_frame == now { + if final_frame || next_frame <= now { // Try to reuse an existing capture instead of forcing an // allocation. if let Ok(capture) = assembler.resuable_captures.try_recv() { @@ -3399,6 +3465,7 @@ where } let elapsed = now.saturating_duration_since(last_frame); last_frame = now; + println!("Redrawing"); self.recorder.redraw(); let capture = self.recorder.capture.take().assert("always present"); if assembler.sender.send((capture, elapsed)).is_err() { @@ -3447,8 +3514,7 @@ where let mut current_frame_delay = Duration::ZERO; let mut writer = encoder.write_header()?; for frame in &frames { - writer.write_image_data(&frame.data)?; - if current_frame_delay != frame.duration { + if current_frame_delay != frame.duration && frames.len() > 1 { current_frame_delay = frame.duration; // This has a limitation that a single frame can't be longer // than ~6.5 seconds, but it ensures frame timing is more @@ -3458,9 +3524,10 @@ where 10_000, )?; } + writer.write_image_data(&frame.data)?; } - writer.finish()?; + writer.finish().unwrap(); file.sync_all()?; @@ -3604,3 +3671,27 @@ impl FrameAssembler { let _result = result.send(Ok(assembled)); } } + +/// Describes a keyboard input targeting a window. +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct KeyEvent { + pub physical_key: PhysicalKey, + pub logical_key: Key, + pub text: Option, + pub location: KeyLocation, + pub state: ElementState, + pub repeat: bool, +} + +impl From for KeyEvent { + fn from(event: winit::event::KeyEvent) -> Self { + Self { + physical_key: event.physical_key, + logical_key: event.logical_key, + text: event.text, + location: event.location, + state: event.state, + repeat: event.repeat, + } + } +}