PendingWindow in PendingApp fix + resize_to_fit

This commit is contained in:
Jonathan Johnson 2024-09-04 08:29:13 -07:00
parent 6a346ea3ef
commit 9304165981
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
5 changed files with 64 additions and 23 deletions

View file

@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Breaking Changes
- `PendingWindow`s opened into a `PendingApp` now have working `WindowHandle`s.
As a result of this fix, `Open::open()` now returns a `WindowHandle` instead
of an `Option<WindowHandle>`.
### Fixed ### Fixed
- `Collapse`, `OverlayLayer`, and `Progress` all honor the theme components - `Collapse`, `OverlayLayer`, and `Progress` all honor the theme components
@ -39,6 +46,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Watcher` is a new type that executes callbacks when one or more sources - `Watcher` is a new type that executes callbacks when one or more sources
changes. This can simplify some data flows such as regenerating a value when changes. This can simplify some data flows such as regenerating a value when
many one of many UI elements are changed. many one of many UI elements are changed.
- The `resize_to_fit` setting has been added to all window types and is no
longer limited to `VirtualRecorder`s. This setting can be changed using:
- `Window::resize_to_fit`
- `StandaloneWindowBuilder::resize_to_fit`
[139]: https://github.com/khonsulabs/cushy/issues/139 [139]: https://github.com/khonsulabs/cushy/issues/139

View file

@ -333,7 +333,7 @@ pub trait Run: Sized {
/// A type that can be opened as a window in an application. /// A type that can be opened as a window in an application.
pub trait Open: Sized { pub trait Open: Sized {
/// Opens the provided type as a window inside of `app`. /// Opens the provided type as a window inside of `app`.
fn open<App>(self, app: &mut App) -> crate::Result<Option<WindowHandle>> fn open<App>(self, app: &mut App) -> crate::Result<WindowHandle>
where where
App: Application + ?Sized; App: Application + ?Sized;

View file

@ -115,7 +115,7 @@ impl DebugContext {
} }
impl Open for DebugContext { impl Open for DebugContext {
fn open<App>(self, app: &mut App) -> crate::Result<Option<crate::window::WindowHandle>> fn open<App>(self, app: &mut App) -> crate::Result<crate::window::WindowHandle>
where where
App: Application + ?Sized, App: Application + ?Sized,
{ {

View file

@ -474,7 +474,7 @@ impl<T> Open for T
where where
T: MakeWidget, T: MakeWidget,
{ {
fn open<App>(self, app: &mut App) -> crate::Result<Option<crate::window::WindowHandle>> fn open<App>(self, app: &mut App) -> crate::Result<crate::window::WindowHandle>
where where
App: Application + ?Sized, App: Application + ?Sized,
{ {

View file

@ -498,6 +498,8 @@ where
/// The number of samples to perform for each pixel rendered to the screen. /// The number of samples to perform for each pixel rendered to the screen.
/// When 1, multisampling is disabled. /// When 1, multisampling is disabled.
pub multisample_count: NonZeroU32, pub multisample_count: NonZeroU32,
/// Resizes the window to fit the contents if true.
pub resize_to_fit: Value<bool>,
on_closed: Option<OnceCallback>, on_closed: Option<OnceCallback>,
inner_size: Option<Dynamic<Size<UPx>>>, inner_size: Option<Dynamic<Size<UPx>>>,
@ -581,6 +583,7 @@ where
vsync: true, vsync: true,
close_requested: None, close_requested: None,
zoom: None, zoom: None,
resize_to_fit: Value::Constant(false),
} }
} }
@ -626,6 +629,12 @@ where
self self
} }
/// Resizes this window to fit the contents when `resize_to_fit` is true.
pub fn resize_to_fit(mut self, resize_to_fit: impl IntoValue<bool>) -> Self {
self.resize_to_fit = resize_to_fit.into_value();
self
}
/// Sets this window's `zoom` factor. /// Sets this window's `zoom` factor.
/// ///
/// The zoom factor is multiplied with the DPI scaling from the window /// The zoom factor is multiplied with the DPI scaling from the window
@ -712,12 +721,13 @@ impl<Behavior> Open for Window<Behavior>
where where
Behavior: WindowBehavior, Behavior: WindowBehavior,
{ {
fn open<App>(self, app: &mut App) -> crate::Result<Option<WindowHandle>> fn open<App>(self, app: &mut App) -> crate::Result<WindowHandle>
where where
App: Application + ?Sized, App: Application + ?Sized,
{ {
let cushy = app.cushy().clone(); let cushy = app.cushy().clone();
let handle = OpenWindow::<Behavior>::open_with( let handle = self.pending.handle();
OpenWindow::<Behavior>::open_with(
app, app,
sealed::Context { sealed::Context {
user: self.context, user: self.context,
@ -743,11 +753,13 @@ where
multisample_count: self.multisample_count, multisample_count: self.multisample_count,
close_requested: self.close_requested.map(|cb| Arc::new(Mutex::new(cb))), close_requested: self.close_requested.map(|cb| Arc::new(Mutex::new(cb))),
zoom: self.zoom.unwrap_or_else(|| Dynamic::new(Fraction::ONE)), zoom: self.zoom.unwrap_or_else(|| Dynamic::new(Fraction::ONE)),
resize_to_fit: self.resize_to_fit,
}), }),
pending: self.pending,
}, },
)?; )?;
Ok(handle.map(|handle| self.pending.opened(handle))) Ok(handle)
} }
fn run_in(self, mut app: PendingApp) -> crate::Result { fn run_in(self, mut app: PendingApp) -> crate::Result {
@ -813,7 +825,7 @@ struct OpenWindow<T> {
keyboard_activated: Option<WidgetId>, keyboard_activated: Option<WidgetId>,
min_inner_size: Option<Size<UPx>>, min_inner_size: Option<Size<UPx>>,
max_inner_size: Option<Size<UPx>>, max_inner_size: Option<Size<UPx>>,
resize_to_fit: bool, resize_to_fit: Value<bool>,
theme: Option<DynamicReader<ThemePair>>, theme: Option<DynamicReader<ThemePair>>,
current_theme: ThemePair, current_theme: ThemePair,
theme_mode: Value<ThemeMode>, theme_mode: Value<ThemeMode>,
@ -1181,24 +1193,25 @@ where
}) })
.persist(); .persist();
} }
let cushy = settings.cushy.clone(); let cushy = settings.cushy.clone();
let occluded = settings.occluded.clone();
let focused = settings.focused.clone();
let theme = settings.theme.take().unwrap_or_default();
let inner_size = settings.inner_size.clone();
let on_closed = settings.on_closed.take();
let close_requested = settings.close_requested.take();
let vsync = settings.vsync;
let zoom = settings.zoom.clone();
let dpi_scale = Dynamic::new(graphics.dpi_scale());
inner_size.set(window.inner_size());
let fonts = Self::load_fonts( let fonts = Self::load_fonts(
&mut settings, &mut settings,
cushy.fonts.clone(), cushy.fonts.clone(),
graphics.font_system().db_mut(), graphics.font_system().db_mut(),
); );
let occluded = settings.occluded;
let focused = settings.focused;
let theme = settings.theme.unwrap_or_default();
let inner_size = settings.inner_size;
let on_closed = settings.on_closed;
let close_requested = settings.close_requested;
let vsync = settings.vsync;
let zoom = settings.zoom;
let resize_to_fit = settings.resize_to_fit;
let dpi_scale = Dynamic::new(graphics.dpi_scale());
inner_size.set(window.inner_size());
let theme_mode = match settings.theme_mode.take() { let theme_mode = match settings.theme_mode.take() {
Some(Value::Dynamic(dynamic)) => { Some(Value::Dynamic(dynamic)) => {
@ -1238,7 +1251,7 @@ where
keyboard_activated: None, keyboard_activated: None,
min_inner_size: None, min_inner_size: None,
max_inner_size: None, max_inner_size: None,
resize_to_fit: false, resize_to_fit,
current_theme, current_theme,
theme, theme,
theme_mode, theme_mode,
@ -1285,7 +1298,8 @@ where
self.new_frame(graphics); self.new_frame(graphics);
let resizable = window.is_resizable() || self.resize_to_fit; let resize_to_fit = self.resize_to_fit.get();
let resizable = window.is_resizable() || resize_to_fit;
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
graphics.id(), graphics.id(),
@ -1342,6 +1356,7 @@ where
}; };
let render_size = actual_size.min(window_size); let render_size = actual_size.min(window_size);
layout_context.redraw_when_changed(&self.inner_size); layout_context.redraw_when_changed(&self.inner_size);
layout_context.invalidate_when_changed(&self.resize_to_fit);
let inner_size_generation = self.inner_size.generation(); let inner_size_generation = self.inner_size.generation();
if self.inner_size_generation != inner_size_generation { if self.inner_size_generation != inner_size_generation {
layout_context.request_inner_size(self.inner_size.get()); layout_context.request_inner_size(self.inner_size.get());
@ -1355,7 +1370,7 @@ where
new_size = new_size.min(max_size); new_size = new_size.min(max_size);
} }
layout_context.request_inner_size(new_size); layout_context.request_inner_size(new_size);
} else if self.resize_to_fit && window_size != layout_size { } else if resize_to_fit && window_size != layout_size {
layout_context.request_inner_size(layout_size); layout_context.request_inner_size(layout_size);
} }
self.root.set_layout(Rect::from(render_size.into_signed())); self.root.set_layout(Rect::from(render_size.into_signed()));
@ -1786,6 +1801,7 @@ where
graphics: &mut kludgine::Graphics<'_>, graphics: &mut kludgine::Graphics<'_>,
context: Self::Context, context: Self::Context,
) -> Self { ) -> Self {
context.pending.opened(window.handle());
let settings = context.settings.borrow_mut(); let settings = context.settings.borrow_mut();
let cushy = settings.cushy.clone(); let cushy = settings.cushy.clone();
let _guard = cushy.enter_runtime(); let _guard = cushy.enter_runtime();
@ -2102,6 +2118,7 @@ pub(crate) mod sealed {
use kludgine::Color; use kludgine::Color;
use parking_lot::Mutex; use parking_lot::Mutex;
use super::PendingWindow;
use crate::app::Cushy; use crate::app::Cushy;
use crate::context::sealed::InvalidationStatus; use crate::context::sealed::InvalidationStatus;
use crate::fonts::FontCollection; use crate::fonts::FontCollection;
@ -2112,6 +2129,7 @@ pub(crate) mod sealed {
pub struct Context<C> { pub struct Context<C> {
pub user: C, pub user: C,
pub pending: PendingWindow,
pub settings: RefCell<WindowSettings>, pub settings: RefCell<WindowSettings>,
} }
@ -2136,6 +2154,7 @@ pub(crate) mod sealed {
pub on_closed: Option<OnceCallback>, pub on_closed: Option<OnceCallback>,
pub vsync: bool, pub vsync: bool,
pub multisample_count: NonZeroU32, pub multisample_count: NonZeroU32,
pub resize_to_fit: Value<bool>,
pub close_requested: Option<Arc<Mutex<Callback<(), bool>>>>, pub close_requested: Option<Arc<Mutex<Callback<(), bool>>>>,
} }
@ -2608,6 +2627,7 @@ pub struct StandaloneWindowBuilder {
scale: f32, scale: f32,
transparent: bool, transparent: bool,
zoom: Dynamic<Fraction>, zoom: Dynamic<Fraction>,
resize_to_fit: Value<bool>,
} }
impl StandaloneWindowBuilder { impl StandaloneWindowBuilder {
@ -2621,6 +2641,7 @@ impl StandaloneWindowBuilder {
scale: 1., scale: 1.,
zoom: Dynamic::new(Fraction::ONE), zoom: Dynamic::new(Fraction::ONE),
transparent: false, transparent: false,
resize_to_fit: Value::Constant(false),
} }
} }
@ -2658,6 +2679,13 @@ impl StandaloneWindowBuilder {
self self
} }
/// Resizes this window to fit the contents when `resize_to_fit` is true.
#[must_use]
pub fn resize_to_fit(mut self, resize_to_fit: impl IntoValue<bool>) -> Self {
self.resize_to_fit = resize_to_fit.into_value();
self
}
/// Returns the initialized window. /// Returns the initialized window.
#[must_use] #[must_use]
pub fn finish<W>(self, window: W, device: &wgpu::Device, queue: &wgpu::Queue) -> CushyWindow pub fn finish<W>(self, window: W, device: &wgpu::Device, queue: &wgpu::Queue) -> CushyWindow
@ -2701,6 +2729,7 @@ impl StandaloneWindowBuilder {
multisample_count: self.multisample_count, multisample_count: self.multisample_count,
close_requested: None, close_requested: None,
zoom: self.zoom, zoom: self.zoom,
resize_to_fit: self.resize_to_fit,
}, },
); );
@ -3409,6 +3438,7 @@ where
.size(size) .size(size)
.scale(scale) .scale(scale)
.transparent() .transparent()
.resize_to_fit(resize_to_fit)
.finish_virtual(&device, &queue); .finish_virtual(&device, &queue);
let mut recorder = Self { let mut recorder = Self {
@ -3423,7 +3453,6 @@ where
data_size: Size::ZERO, data_size: Size::ZERO,
format: PhantomData, format: PhantomData,
}; };
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() {