From 930416598116740366838386a3839b8ae65642b4 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Wed, 4 Sep 2024 08:29:13 -0700 Subject: [PATCH] PendingWindow in PendingApp fix + resize_to_fit --- CHANGELOG.md | 12 +++++++++ src/app.rs | 2 +- src/debug.rs | 2 +- src/widget.rs | 2 +- src/window.rs | 69 ++++++++++++++++++++++++++++++++++++--------------- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4a5ba77..5c43a5975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 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`. + + ### Fixed - `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 changes. This can simplify some data flows such as regenerating a value when 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 diff --git a/src/app.rs b/src/app.rs index a6da131e2..862ef64d4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -333,7 +333,7 @@ pub trait Run: Sized { /// A type that can be opened as a window in an application. pub trait Open: Sized { /// Opens the provided type as a window inside of `app`. - fn open(self, app: &mut App) -> crate::Result> + fn open(self, app: &mut App) -> crate::Result where App: Application + ?Sized; diff --git a/src/debug.rs b/src/debug.rs index e41ba775e..151af9094 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -115,7 +115,7 @@ impl DebugContext { } impl Open for DebugContext { - fn open(self, app: &mut App) -> crate::Result> + fn open(self, app: &mut App) -> crate::Result where App: Application + ?Sized, { diff --git a/src/widget.rs b/src/widget.rs index 89602a7e4..2f20b9ae7 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -474,7 +474,7 @@ impl Open for T where T: MakeWidget, { - fn open(self, app: &mut App) -> crate::Result> + fn open(self, app: &mut App) -> crate::Result where App: Application + ?Sized, { diff --git a/src/window.rs b/src/window.rs index b9a53f4f2..9b97ff927 100644 --- a/src/window.rs +++ b/src/window.rs @@ -498,6 +498,8 @@ where /// The number of samples to perform for each pixel rendered to the screen. /// When 1, multisampling is disabled. pub multisample_count: NonZeroU32, + /// Resizes the window to fit the contents if true. + pub resize_to_fit: Value, on_closed: Option, inner_size: Option>>, @@ -581,6 +583,7 @@ where vsync: true, close_requested: None, zoom: None, + resize_to_fit: Value::Constant(false), } } @@ -626,6 +629,12 @@ where 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) -> Self { + self.resize_to_fit = resize_to_fit.into_value(); + self + } + /// Sets this window's `zoom` factor. /// /// The zoom factor is multiplied with the DPI scaling from the window @@ -712,12 +721,13 @@ impl Open for Window where Behavior: WindowBehavior, { - fn open(self, app: &mut App) -> crate::Result> + fn open(self, app: &mut App) -> crate::Result where App: Application + ?Sized, { let cushy = app.cushy().clone(); - let handle = OpenWindow::::open_with( + let handle = self.pending.handle(); + OpenWindow::::open_with( app, sealed::Context { user: self.context, @@ -743,11 +753,13 @@ where multisample_count: self.multisample_count, close_requested: self.close_requested.map(|cb| Arc::new(Mutex::new(cb))), 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 { @@ -813,7 +825,7 @@ struct OpenWindow { keyboard_activated: Option, min_inner_size: Option>, max_inner_size: Option>, - resize_to_fit: bool, + resize_to_fit: Value, theme: Option>, current_theme: ThemePair, theme_mode: Value, @@ -1181,24 +1193,25 @@ where }) .persist(); } - 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 cushy = settings.cushy.clone(); let fonts = Self::load_fonts( &mut settings, cushy.fonts.clone(), 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() { Some(Value::Dynamic(dynamic)) => { @@ -1238,7 +1251,7 @@ where keyboard_activated: None, min_inner_size: None, max_inner_size: None, - resize_to_fit: false, + resize_to_fit, current_theme, theme, theme_mode, @@ -1285,7 +1298,8 @@ where 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( window, graphics.id(), @@ -1342,6 +1356,7 @@ where }; let render_size = actual_size.min(window_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(); if self.inner_size_generation != inner_size_generation { layout_context.request_inner_size(self.inner_size.get()); @@ -1355,7 +1370,7 @@ where new_size = new_size.min(max_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); } self.root.set_layout(Rect::from(render_size.into_signed())); @@ -1786,6 +1801,7 @@ where graphics: &mut kludgine::Graphics<'_>, context: Self::Context, ) -> Self { + context.pending.opened(window.handle()); let settings = context.settings.borrow_mut(); let cushy = settings.cushy.clone(); let _guard = cushy.enter_runtime(); @@ -2102,6 +2118,7 @@ pub(crate) mod sealed { use kludgine::Color; use parking_lot::Mutex; + use super::PendingWindow; use crate::app::Cushy; use crate::context::sealed::InvalidationStatus; use crate::fonts::FontCollection; @@ -2112,6 +2129,7 @@ pub(crate) mod sealed { pub struct Context { pub user: C, + pub pending: PendingWindow, pub settings: RefCell, } @@ -2136,6 +2154,7 @@ pub(crate) mod sealed { pub on_closed: Option, pub vsync: bool, pub multisample_count: NonZeroU32, + pub resize_to_fit: Value, pub close_requested: Option>>>, } @@ -2608,6 +2627,7 @@ pub struct StandaloneWindowBuilder { scale: f32, transparent: bool, zoom: Dynamic, + resize_to_fit: Value, } impl StandaloneWindowBuilder { @@ -2621,6 +2641,7 @@ impl StandaloneWindowBuilder { scale: 1., zoom: Dynamic::new(Fraction::ONE), transparent: false, + resize_to_fit: Value::Constant(false), } } @@ -2658,6 +2679,13 @@ impl StandaloneWindowBuilder { 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) -> Self { + self.resize_to_fit = resize_to_fit.into_value(); + self + } + /// Returns the initialized window. #[must_use] pub fn finish(self, window: W, device: &wgpu::Device, queue: &wgpu::Queue) -> CushyWindow @@ -2701,6 +2729,7 @@ impl StandaloneWindowBuilder { multisample_count: self.multisample_count, close_requested: None, zoom: self.zoom, + resize_to_fit: self.resize_to_fit, }, ); @@ -3409,6 +3438,7 @@ where .size(size) .scale(scale) .transparent() + .resize_to_fit(resize_to_fit) .finish_virtual(&device, &queue); let mut recorder = Self { @@ -3423,7 +3453,6 @@ where data_size: Size::ZERO, format: PhantomData, }; - recorder.window.cushy.window.resize_to_fit = resize_to_fit; recorder.refresh()?; if resize_to_fit && recorder.window.state.size != recorder.window.size() {