Added CushyWindow

While working on the changelog, I realized I didn't provide a type that
allowed a third party developer to provide a
PlatformWindowImplementation. This type now completes it.
This commit is contained in:
Jonathan Johnson 2024-01-04 15:54:58 -08:00
parent a197bb5e81
commit 6ff766846f
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 310 additions and 118 deletions

View file

@ -9,6 +9,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Breaking Changes ### Breaking Changes
- All context types no longer accept a `'window` lifetime. For most end-user
code, it means removing one elided lifetime from these types:
- `WidgetContext`
- `EventContext`
- `LayoutContext`
- `GraphicsContext`
- `WidgetContext`'s `Deref` target is now `&mut dyn PlatformWindow`. This change
ensures all widgets utilize a shared interface between any host architecture.
- All `DeviceId` parameters have been changed to a `DeviceId` type provided by
Cushy. This allows for creating arbitrary input device IDs when creating an
integration with other frameworks or driving simulated input in a
`VirtualWindow`.
- `WidgetRef` is now a `struct` instead of an enum. This refactor changes the - `WidgetRef` is now a `struct` instead of an enum. This refactor changes the
mounted state to be stored in a `WindowLocal`, ensuring `WidgetRef`s work mounted state to be stored in a `WindowLocal`, ensuring `WidgetRef`s work
properly when used in a `WidgetInstance` shared between multiple windows. properly when used in a `WidgetInstance` shared between multiple windows.
@ -60,14 +72,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `WidgetCacheKey` now includes the `KludgineId` of the context it was created - `WidgetCacheKey` now includes the `KludgineId` of the context it was created
from. This ensures if a `WidgetInstance` moves or is shared between windows, from. This ensures if a `WidgetInstance` moves or is shared between windows,
the cache is invalidated. the cache is invalidated.
- All `Dynamic` mapping functions now utilize weak references, and clean up as - All `Dynamic` mapping functions now utilize weak references, and the
necessary if a value is not able to be upgraded. `CallbackHandle` now contains a strong reference to the originating dynamic.
This should have no visible impact on end-user code.
- `ForEach`/`MapEach`'s implementations for tuples are now defined using - `ForEach`/`MapEach`'s implementations for tuples are now defined using
`Source<T>` and `DynamicRead<T>`. This allows combinations of `Dynamic<T>`s `Source<T>` and `DynamicRead<T>`. This allows combinations of `Dynamic<T>`s
and `DynamicReader<T>`s to be used in for_each/map_each expressions. and `DynamicReader<T>`s to be used in for_each/map_each expressions.
### Added ### Added
- Cushy now supports being embedded in any wgpu application. Here are the API
highlights:
- `CushyWindow` is a type that contains the state of a standalone window. It
defines an API designed to enable full control with winit integration into
any wgpu application. This type's design is inspired by wpgu's
"Encapsulating Graphics Work" article. Each of its functions require being
passed a type that implements `PlatformWindowImplementation`, which exposes
all APIs Cushy needs to be fully functional.
- `VirtualWindow` is a type that makes it easy to render a Cushy interface in
any wgpu application where no winit integration is desired. It utilizes
`VirtualState` as its `PlatformWindowImplementation`. This type also exposes
a design inspired by wpgu's "Encapsulating Graphics Work" article.
- `WindowDynamicState` is a set of dynamics that can be updated through
external threads and tasks.
- is a new trait that allows
customizing the behavior that Cushy widgets need to be rendered.
- Cushy now supports easily rendering a virtual window: `VirtualRecorder`. This
type utilizes a `VirtualWindow` and provides easy access to captured images.
This type has the ability to capture animated PNGs as well as still images.
- `figures` is now directly re-exported at this crate's root. Kludgine still - `figures` is now directly re-exported at this crate's root. Kludgine still
also provides this export, so existing references through kludgine will also provides this export, so existing references through kludgine will
continue to work. This was added as an attempt to fix links on docs.rs (see continue to work. This was added as an attempt to fix links on docs.rs (see
@ -115,6 +148,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
clone `self` before calling the `into_` function. This has only been done in clone `self` before calling the `into_` function. This has only been done in
situations where it is known or likely that the clone being performed is situations where it is known or likely that the clone being performed is
cheap. cheap.
- `CallbackHandle` now has `weak()` and `forget_owners()`. These functions allow
a `CallbackHandle` to release its strong references to the `Dynamic` that the
callback is installed on. This enables forming weak callback graphs that clean
up independent of one another.
- `Source<T>::weak_clone` returns a `Dynamic<T>` with a clone of each value
stored in the original source. The returned dynamic holds no strong references
to the original source.
- `Point`, `Size`, and `Rect` now implement `LinearInterpolate`.
- `MakeWidget::build_virtual_window()` returns a builder for a `VirtualWindow`.
- `MakeWidget::build_recorder()` returns a builder for a `VirtualRecorder`.
- `Space::dynamic()` returns a space that dynamically colors itself using
component provided. This allows the spacer to use values from the theme at
runtime.
- `Space::primary()` returns a space that contains the primary color.
[99]: https://github.com/khonsulabs/cushy/issues/99 [99]: https://github.com/khonsulabs/cushy/issues/99
[120]: https://github.com/khonsulabs/cushy/issues/120 [120]: https://github.com/khonsulabs/cushy/issues/120

View file

@ -45,7 +45,7 @@ use crate::widgets::{
}; };
use crate::window::sealed::WindowCommand; use crate::window::sealed::WindowCommand;
use crate::window::{ use crate::window::{
DeviceId, Rgb8, RunningWindow, ThemeMode, VirtualRecorderBuilder, VirtualWindowBuilder, Window, CushyWindowBuilder, DeviceId, Rgb8, RunningWindow, ThemeMode, VirtualRecorderBuilder, Window,
WindowBehavior, WindowHandle, WindowLocal, WindowBehavior, WindowHandle, WindowLocal,
}; };
use crate::ConstraintLimit; use crate::ConstraintLimit;
@ -917,8 +917,8 @@ pub trait MakeWidget: Sized {
} }
/// Returns a builder for a [`VirtualWindow`](crate::window::VirtualWindow). /// Returns a builder for a [`VirtualWindow`](crate::window::VirtualWindow).
fn build_virtual_window(self) -> VirtualWindowBuilder { fn build_virtual_window(self) -> CushyWindowBuilder {
VirtualWindowBuilder::new(self) CushyWindowBuilder::new(self)
} }
/// Returns a builder for a [`VirtualRecorder`](crate::window::VirtualRecorder) /// Returns a builder for a [`VirtualRecorder`](crate::window::VirtualRecorder)

View file

@ -652,10 +652,7 @@ where
App: Application + ?Sized, App: Application + ?Sized,
{ {
let cushy = app.cushy().clone(); let cushy = app.cushy().clone();
// let Some(app) = app.as_app().as_kludgine() else { let handle = OpenWindow::<Behavior>::open_with(
// return Ok(None);
// };
let handle = CushyWindow::<Behavior>::open_with(
app, app,
sealed::Context { sealed::Context {
user: self.context, user: self.context,
@ -730,7 +727,7 @@ pub trait WindowBehavior: Sized + 'static {
} }
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
struct CushyWindow<T> { struct OpenWindow<T> {
behavior: T, behavior: T,
tree: Tree, tree: Tree,
root: MountedWidget, root: MountedWidget,
@ -757,7 +754,7 @@ struct CushyWindow<T> {
on_closed: Option<OnceCallback>, on_closed: Option<OnceCallback>,
} }
impl<T> CushyWindow<T> impl<T> OpenWindow<T>
where where
T: WindowBehavior, T: WindowBehavior,
{ {
@ -1623,7 +1620,7 @@ enum RootMode {
Align, Align,
} }
impl<T> kludgine::app::WindowBehavior<WindowCommand> for CushyWindow<T> impl<T> kludgine::app::WindowBehavior<WindowCommand> for OpenWindow<T>
where where
T: WindowBehavior, T: WindowBehavior,
{ {
@ -1871,7 +1868,7 @@ where
} }
} }
impl<Behavior> Drop for CushyWindow<Behavior> { impl<Behavior> Drop for OpenWindow<Behavior> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(on_closed) = self.on_closed.take() { if let Some(on_closed) = self.on_closed.take() {
on_closed.invoke(()); on_closed.invoke(());
@ -2369,7 +2366,7 @@ impl PlatformWindowImplementation for &mut VirtualState {
} }
/// A builder for a [`VirtualWindow`]. /// A builder for a [`VirtualWindow`].
pub struct VirtualWindowBuilder { pub struct CushyWindowBuilder {
widget: WidgetInstance, widget: WidgetInstance,
multisample_count: u32, multisample_count: u32,
initial_size: Size<UPx>, initial_size: Size<UPx>,
@ -2377,8 +2374,8 @@ pub struct VirtualWindowBuilder {
transparent: bool, transparent: bool,
} }
impl VirtualWindowBuilder { impl CushyWindowBuilder {
/// Returns a new builder for a virtual window that contains `contents`. /// Returns a new builder for a Cushy window that contains `contents`.
#[must_use] #[must_use]
pub fn new(contents: impl MakeWidget) -> Self { pub fn new(contents: impl MakeWidget) -> Self {
Self { Self {
@ -2390,7 +2387,7 @@ impl VirtualWindowBuilder {
} }
} }
/// Sets this virtual window's multi-sample count. /// Sets this window's multi-sample count.
/// ///
/// By default, 4 samples are taken. When 1 sample is used, multisampling is /// By default, 4 samples are taken. When 1 sample is used, multisampling is
/// fully disabled. /// fully disabled.
@ -2400,7 +2397,7 @@ impl VirtualWindowBuilder {
self self
} }
/// Sets the size of the virtual window. /// Sets the size of the window.
#[must_use] #[must_use]
pub fn size<Unit>(mut self, size: Size<Unit>) -> Self pub fn size<Unit>(mut self, size: Size<Unit>) -> Self
where where
@ -2410,7 +2407,7 @@ impl VirtualWindowBuilder {
self self
} }
/// Sets the DPI scaling factor of the virtual window. /// Sets the DPI scaling factor of the window.
#[must_use] #[must_use]
pub fn scale(mut self, scale: f32) -> Self { pub fn scale(mut self, scale: f32) -> Self {
self.scale = scale; self.scale = scale;
@ -2424,58 +2421,26 @@ impl VirtualWindowBuilder {
self self
} }
/// Returns the initialized virtual window. /// Returns the initialized window.
#[must_use] #[must_use]
pub fn finish(self, device: &wgpu::Device, queue: &wgpu::Queue) -> VirtualWindow { pub fn finish<W>(self, window: W, device: &wgpu::Device, queue: &wgpu::Queue) -> CushyWindow
VirtualWindow::new( where
self.widget, W: PlatformWindowImplementation,
self.multisample_count, {
self.initial_size,
self.scale,
self.transparent,
device,
queue,
)
}
}
/// A virtual Cushy window.
///
/// This type allows rendering Cushy applications directly into any wgpu
/// application.
pub struct VirtualWindow {
window: CushyWindow<WidgetInstance>,
kludgine: Kludgine,
last_rendered_at: Option<Instant>,
state: VirtualState,
}
impl VirtualWindow {
/// Returns a new virtual window with the provided specifications.
fn new(
widget: WidgetInstance,
multisample_count: u32,
initial_size: Size<UPx>,
scale: f32,
transparent: bool,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Self {
let mut kludgine = Kludgine::new( let mut kludgine = Kludgine::new(
device, device,
queue, queue,
wgpu::TextureFormat::Rgba8UnormSrgb, wgpu::TextureFormat::Rgba8UnormSrgb,
wgpu::MultisampleState { wgpu::MultisampleState {
count: multisample_count, count: self.multisample_count,
..Default::default() ..Default::default()
}, },
initial_size, self.initial_size,
scale, self.scale,
); );
let mut state = VirtualState::new(); let window = OpenWindow::<WidgetInstance>::new(
let window = CushyWindow::<WidgetInstance>::new( self.widget,
widget.make_widget(), window,
&mut state,
&mut kludgine::Graphics::new(&mut kludgine, device, queue), &mut kludgine::Graphics::new(&mut kludgine, device, queue),
sealed::WindowSettings { sealed::WindowSettings {
cushy: Cushy::new(), cushy: Cushy::new(),
@ -2487,7 +2452,7 @@ impl VirtualWindow {
inner_size: Dynamic::default(), inner_size: Dynamic::default(),
theme: None, theme: None,
theme_mode: None, theme_mode: None,
transparent, transparent: self.transparent,
serif_font_family: FontFamilyList::default(), serif_font_family: FontFamilyList::default(),
sans_serif_font_family: FontFamilyList::default(), sans_serif_font_family: FontFamilyList::default(),
fantasy_font_family: FontFamilyList::default(), fantasy_font_family: FontFamilyList::default(),
@ -2498,25 +2463,41 @@ impl VirtualWindow {
}, },
); );
Self { CushyWindow { window, kludgine }
window,
kludgine,
last_rendered_at: None,
state,
}
} }
/// Returns an initialized [`VirtualWindow`].
#[must_use]
pub fn finish_virtual(self, device: &wgpu::Device, queue: &wgpu::Queue) -> VirtualWindow {
let mut state = VirtualState::new();
let cushy = self.finish(&mut state, device, queue);
VirtualWindow {
cushy,
state,
last_rendered_at: None,
}
}
}
/// A standalone Cushy window.
///
/// This type allows rendering Cushy applications directly into any wgpu
/// application.
pub struct CushyWindow {
window: OpenWindow<WidgetInstance>,
kludgine: Kludgine,
}
impl CushyWindow {
/// Prepares all necessary resources and operations necessary to render the /// Prepares all necessary resources and operations necessary to render the
/// next frame. /// next frame.
pub fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) { pub fn prepare<W>(&mut self, window: W, device: &wgpu::Device, queue: &wgpu::Queue)
let now = Instant::now(); where
self.state.elapsed = self W: PlatformWindowImplementation,
.last_rendered_at {
.map(|i| now.duration_since(i))
.unwrap_or_default();
self.last_rendered_at = Some(now);
self.window.prepare( self.window.prepare(
&mut self.state, window,
&mut kludgine::Graphics::new(&mut self.kludgine, device, queue), &mut kludgine::Graphics::new(&mut self.kludgine, device, queue),
); );
} }
@ -2545,7 +2526,6 @@ impl VirtualWindow {
queue: &wgpu::Queue, queue: &wgpu::Queue,
additional_drawing: Option<&Drawing>, additional_drawing: Option<&Drawing>,
) -> Option<wgpu::SubmissionIndex> { ) -> Option<wgpu::SubmissionIndex> {
self.state.dynamic.redraw_target.set(RedrawTarget::Never);
let mut frame = self.kludgine.next_frame(); let mut frame = self.kludgine.next_frame();
let mut gfx = frame.render(pass, device, queue); let mut gfx = frame.render(pass, device, queue);
self.window.contents.render(1., &mut gfx); self.window.contents.render(1., &mut gfx);
@ -2564,7 +2544,6 @@ impl VirtualWindow {
device: &wgpu::Device, device: &wgpu::Device,
queue: &wgpu::Queue, queue: &wgpu::Queue,
) -> Option<wgpu::SubmissionIndex> { ) -> Option<wgpu::SubmissionIndex> {
self.state.dynamic.redraw_target.set(RedrawTarget::Never);
let mut frame = self.kludgine.next_frame(); let mut frame = self.kludgine.next_frame();
let mut gfx = frame.render_into(texture, load_op, device, queue); let mut gfx = frame.render_into(texture, load_op, device, queue);
self.window.contents.render(1., &mut gfx); self.window.contents.render(1., &mut gfx);
@ -2582,14 +2561,194 @@ impl VirtualWindow {
kludgine::Graphics::new(&mut self.kludgine, device, queue) kludgine::Graphics::new(&mut self.kludgine, device, queue)
} }
/// Requests that the window close.
///
/// Returns true if the request should be honored.
pub fn request_close<W>(&mut self, window: W) -> bool
where
W: PlatformWindowImplementation,
{
self.window.close_requested(window, &mut self.kludgine)
}
/// Returns the current size of the window.
pub const fn size(&self) -> Size<UPx> {
self.kludgine.size()
}
/// Returns the current DPI scale of the window.
pub const fn scale(&self) -> Fraction {
self.kludgine.scale()
}
/// Updates the dimensions and DPI scaling of the window.
pub fn resize(&mut self, new_size: Size<UPx>, new_scale: impl Into<f32>, queue: &wgpu::Queue) {
self.kludgine.resize(new_size, new_scale.into(), queue);
self.window.resized(new_size);
}
/// Provide keyboard input to this virtual window.
///
/// Returns whether the event was [`HANDLED`] or [`IGNORED`].
pub fn keyboard_input<W>(
&mut self,
window: W,
device_id: DeviceId,
input: KeyEvent,
is_synthetic: bool,
) -> EventHandling
where
W: PlatformWindowImplementation,
{
self.window
.keyboard_input(window, &mut self.kludgine, device_id, input, is_synthetic)
}
/// Provides mouse wheel input to this window.
///
/// Returns whether the event was [`HANDLED`] or [`IGNORED`].
pub fn mouse_wheel<W>(
&mut self,
window: W,
device_id: DeviceId,
delta: MouseScrollDelta,
phase: TouchPhase,
) -> EventHandling
where
W: PlatformWindowImplementation,
{
self.window
.mouse_wheel(window, &mut self.kludgine, device_id, delta, phase)
}
/// Provides input manager events to this window.
///
/// Returns whether the event was [`HANDLED`] or [`IGNORED`].
pub fn ime<W>(&mut self, window: W, ime: &Ime) -> EventHandling
where
W: PlatformWindowImplementation,
{
self.window.ime(window, &mut self.kludgine, ime)
}
/// Provides cursor movement events to this window.
pub fn cursor_moved<W>(
&mut self,
window: W,
device_id: DeviceId,
position: impl Into<Point<Px>>,
) where
W: PlatformWindowImplementation,
{
self.window
.cursor_moved(window, &mut self.kludgine, device_id, position);
}
/// Notifies the window that the cursor is no longer within the window.
pub fn cursor_left<W>(&mut self, window: W)
where
W: PlatformWindowImplementation,
{
self.window.cursor_left(window, &mut self.kludgine);
}
/// Provides mouse input events to tihs window.
///
/// Returns whether the event was [`HANDLED`] or [`IGNORED`].
pub fn mouse_input<W>(
&mut self,
window: W,
device_id: DeviceId,
state: ElementState,
button: MouseButton,
) -> EventHandling
where
W: PlatformWindowImplementation,
{
self.window
.mouse_input(window, &mut self.kludgine, device_id, state, button)
}
}
/// A virtual Cushy window.
///
/// This type allows rendering Cushy applications directly into any wgpu
/// application.
pub struct VirtualWindow {
cushy: CushyWindow,
state: VirtualState,
last_rendered_at: Option<Instant>,
}
impl VirtualWindow {
/// Prepares all necessary resources and operations necessary to render the
/// next frame.
pub fn prepare(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) {
let now = Instant::now();
self.state.elapsed = self
.last_rendered_at
.map(|i| now.duration_since(i))
.unwrap_or_default();
self.last_rendered_at = Some(now);
self.cushy.prepare(&mut self.state, device, queue);
}
/// Renders this window in a wgpu render pass created from `pass`.
///
/// Returns the submission index of the last command submission, if any
/// commands were submitted.
pub fn render(
&mut self,
pass: &wgpu::RenderPassDescriptor<'_, '_>,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Option<wgpu::SubmissionIndex> {
self.render_with(pass, device, queue, None)
}
/// Renders this window in a wgpu render pass created from `pass`.
///
/// Returns the submission index of the last command submission, if any
/// commands were submitted.
pub fn render_with(
&mut self,
pass: &wgpu::RenderPassDescriptor<'_, '_>,
device: &wgpu::Device,
queue: &wgpu::Queue,
additional_drawing: Option<&Drawing>,
) -> Option<wgpu::SubmissionIndex> {
self.state.dynamic.redraw_target.set(RedrawTarget::Never);
self.cushy
.render_with(pass, device, queue, additional_drawing)
}
/// Renders this window into `texture` after performing `load_op`.
pub fn render_into(
&mut self,
texture: &kludgine::Texture,
load_op: wgpu::LoadOp<Color>,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Option<wgpu::SubmissionIndex> {
self.state.dynamic.redraw_target.set(RedrawTarget::Never);
self.cushy.render_into(texture, load_op, device, queue)
}
/// Returns a new [`kludgine::Graphics`] context for this window.
#[must_use]
pub fn graphics<'gfx>(
&'gfx mut self,
device: &'gfx wgpu::Device,
queue: &'gfx wgpu::Queue,
) -> kludgine::Graphics<'gfx> {
self.cushy.graphics(device, queue)
}
/// Requests that the window close. /// Requests that the window close.
/// ///
/// Returns true if the request should be honored. /// Returns true if the request should be honored.
pub fn request_close(&mut self) -> bool { pub fn request_close(&mut self) -> bool {
if self if self.cushy.request_close(&mut self.state) {
.window
.close_requested(&mut self.state, &mut self.kludgine)
{
self.state.closed = true; self.state.closed = true;
true true
} else { } else {
@ -2612,18 +2771,17 @@ impl VirtualWindow {
/// Returns the current size of the window. /// Returns the current size of the window.
pub const fn size(&self) -> Size<UPx> { pub const fn size(&self) -> Size<UPx> {
self.kludgine.size() self.cushy.size()
} }
/// Returns the current DPI scale of the window. /// Returns the current DPI scale of the window.
pub const fn scale(&self) -> Fraction { pub const fn scale(&self) -> Fraction {
self.kludgine.scale() self.cushy.scale()
} }
/// Updates the dimensions and DPI scaling of the window. /// Updates the dimensions and DPI scaling of the window.
pub fn resize(&mut self, new_size: Size<UPx>, new_scale: impl Into<f32>, queue: &wgpu::Queue) { pub fn resize(&mut self, new_size: Size<UPx>, new_scale: impl Into<f32>, queue: &wgpu::Queue) {
self.kludgine.resize(new_size, new_scale.into(), queue); self.cushy.resize(new_size, new_scale.into(), queue);
self.window.resized(new_size);
} }
/// Provide keyboard input to this virtual window. /// Provide keyboard input to this virtual window.
@ -2635,13 +2793,8 @@ impl VirtualWindow {
input: KeyEvent, input: KeyEvent,
is_synthetic: bool, is_synthetic: bool,
) -> EventHandling { ) -> EventHandling {
self.window.keyboard_input( self.cushy
&mut self.state, .keyboard_input(&mut self.state, device_id, input, is_synthetic)
&mut self.kludgine,
device_id,
input,
is_synthetic,
)
} }
/// Provides mouse wheel input to this window. /// Provides mouse wheel input to this window.
@ -2653,26 +2806,26 @@ impl VirtualWindow {
delta: MouseScrollDelta, delta: MouseScrollDelta,
phase: TouchPhase, phase: TouchPhase,
) -> EventHandling { ) -> EventHandling {
self.window self.cushy
.mouse_wheel(&mut self.state, &mut self.kludgine, device_id, delta, phase) .mouse_wheel(&mut self.state, device_id, delta, phase)
} }
/// Provides input manager events to this window. /// Provides input manager events to this window.
/// ///
/// Returns whether the event was [`HANDLED`] or [`IGNORED`]. /// Returns whether the event was [`HANDLED`] or [`IGNORED`].
pub fn ime(&mut self, ime: &Ime) -> EventHandling { pub fn ime(&mut self, ime: &Ime) -> EventHandling {
self.window.ime(&mut self.state, &mut self.kludgine, ime) self.cushy.ime(&mut self.state, ime)
} }
/// Provides cursor movement events to this window. /// Provides cursor movement events to this window.
pub fn cursor_moved(&mut self, device_id: DeviceId, position: impl Into<Point<Px>>) { pub fn cursor_moved(&mut self, device_id: DeviceId, position: impl Into<Point<Px>>) {
self.window self.cushy
.cursor_moved(&mut self.state, &mut self.kludgine, device_id, position); .cursor_moved(&mut self.state, device_id, position);
} }
/// Notifies the window that the cursor is no longer within the window. /// Notifies the window that the cursor is no longer within the window.
pub fn cursor_left(&mut self) { pub fn cursor_left(&mut self) {
self.window.cursor_left(&mut self.state, &mut self.kludgine); self.cushy.cursor_left(&mut self.state);
} }
/// Provides mouse input events to tihs window. /// Provides mouse input events to tihs window.
@ -2684,13 +2837,8 @@ impl VirtualWindow {
state: ElementState, state: ElementState,
button: MouseButton, button: MouseButton,
) -> EventHandling { ) -> EventHandling {
self.window.mouse_input( self.cushy
&mut self.state, .mouse_input(&mut self.state, device_id, state, button)
&mut self.kludgine,
device_id,
state,
button,
)
} }
} }
@ -2962,15 +3110,12 @@ where
None, None,
))?; ))?;
let window = VirtualWindow::new( let window = contents
contents.make_widget(), .build_virtual_window()
4, .size(size)
size, .scale(scale)
scale, .transparent()
Format::HAS_ALPHA, .finish_virtual(&device, &queue);
&device,
&queue,
);
let mut recorder = Self { let mut recorder = Self {
window, window,
@ -2984,7 +3129,7 @@ where
data_size: Size::ZERO, data_size: Size::ZERO,
format: PhantomData, format: PhantomData,
}; };
recorder.window.window.resize_to_fit = resize_to_fit; recorder.window.cushy.window.resize_to_fit = resize_to_fit;
recorder.refresh()?; recorder.refresh()?;
if resize_to_fit && recorder.window.state.size != recorder.window.size() { if resize_to_fit && recorder.window.state.size != recorder.window.size() {
@ -3086,7 +3231,7 @@ where
} }
fn redraw(&mut self) { fn redraw(&mut self) {
let mut render_size = self.window.kludgine.size().ceil(); let mut render_size = self.window.size().ceil();
if self.window.state.size != render_size { if self.window.state.size != render_size {
let current_scale = self.window.scale(); let current_scale = self.window.scale();
self.window self.window