mirror of
https://github.com/danbulant/cushy
synced 2026-07-05 03:00:43 +00:00
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:
parent
a197bb5e81
commit
6ff766846f
3 changed files with 310 additions and 118 deletions
51
CHANGELOG.md
51
CHANGELOG.md
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
371
src/window.rs
371
src/window.rs
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue