Merged internal and public WindowHandle types

This commit is contained in:
Jonathan Johnson 2023-12-27 09:04:29 -08:00
parent aa47539518
commit 76528ee374
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
5 changed files with 139 additions and 118 deletions

View file

@ -15,7 +15,6 @@ use kludgine::shapes::{Shape, StrokeOptions};
use kludgine::{Color, Kludgine}; use kludgine::{Color, Kludgine};
use crate::animation::ZeroToOne; use crate::animation::ZeroToOne;
use crate::context::sealed::WindowHandle;
use crate::graphics::Graphics; use crate::graphics::Graphics;
use crate::styles::components::{ use crate::styles::components::{
CornerRadius, FontFamily, FontStyle, FontWeight, HighlightColor, LayoutOrder, LineHeight, CornerRadius, FontFamily, FontStyle, FontWeight, HighlightColor, LayoutOrder, LineHeight,
@ -850,7 +849,6 @@ impl<'window> AsEventContext<'window> for GraphicsContext<'_, 'window, '_, '_, '
pub struct WidgetContext<'context, 'window> { pub struct WidgetContext<'context, 'window> {
current_node: MountedWidget, current_node: MountedWidget,
pub(crate) tree: Tree, pub(crate) tree: Tree,
redraw_status: &'context InvalidationStatus,
window: &'context mut RunningWindow<'window>, window: &'context mut RunningWindow<'window>,
theme: Cow<'context, ThemePair>, theme: Cow<'context, ThemePair>,
cursor: &'context mut CursorState, cursor: &'context mut CursorState,
@ -862,16 +860,12 @@ pub struct WidgetContext<'context, 'window> {
impl<'context, 'window> WidgetContext<'context, 'window> { impl<'context, 'window> WidgetContext<'context, 'window> {
pub(crate) fn new( pub(crate) fn new(
current_node: MountedWidget, current_node: MountedWidget,
redraw_status: &'context InvalidationStatus,
theme: &'context ThemePair, theme: &'context ThemePair,
window: &'context mut RunningWindow<'window>, window: &'context mut RunningWindow<'window>,
theme_mode: ThemeMode, theme_mode: ThemeMode,
cursor: &'context mut CursorState, cursor: &'context mut CursorState,
) -> Self { ) -> Self {
let enabled = current_node.enabled(&WindowHandle { let enabled = current_node.enabled(&window.handle());
kludgine: window.handle(),
redraw_status: redraw_status.clone(),
});
let tree = current_node.tree(); let tree = current_node.tree();
Self { Self {
pending_state: PendingState::Owned(PendingWidgetState { pending_state: PendingState::Owned(PendingWidgetState {
@ -891,7 +885,6 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
}, },
cursor, cursor,
current_node, current_node,
redraw_status,
theme: Cow::Borrowed(theme), theme: Cow::Borrowed(theme),
window, window,
} }
@ -902,7 +895,6 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
WidgetContext { WidgetContext {
tree: self.tree.clone(), tree: self.tree.clone(),
current_node: self.current_node.clone(), current_node: self.current_node.clone(),
redraw_status: self.redraw_status,
window: &mut *self.window, window: &mut *self.window,
theme: Cow::Borrowed(self.theme.as_ref()), theme: Cow::Borrowed(self.theme.as_ref()),
pending_state: self.pending_state.borrowed(), pending_state: self.pending_state.borrowed(),
@ -941,7 +933,6 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
}, },
current_node, current_node,
tree: self.tree.clone(), tree: self.tree.clone(),
redraw_status: self.redraw_status,
window: &mut *self.window, window: &mut *self.window,
theme, theme,
pending_state: self.pending_state.borrowed(), pending_state: self.pending_state.borrowed(),
@ -1157,13 +1148,6 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
self.effective_styles.try_get(query, self) self.effective_styles.try_get(query, self)
} }
pub(crate) fn handle(&self) -> WindowHandle {
WindowHandle {
kludgine: self.window.handle(),
redraw_status: self.redraw_status.clone(),
}
}
/// Returns the window containing this widget. /// Returns the window containing this widget.
#[must_use] #[must_use]
pub fn window(&self) -> &RunningWindow<'window> { pub fn window(&self) -> &RunningWindow<'window> {
@ -1297,6 +1281,19 @@ impl InvalidationStatus {
} }
} }
impl Eq for InvalidationStatus {}
impl PartialEq for InvalidationStatus {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.invalidated, &other.invalidated)
}
}
impl std::hash::Hash for InvalidationStatus {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.invalidated).hash(state);
}
}
/// A type chat can convert to a [`MountedWidget`] through a [`WidgetContext`]. /// A type chat can convert to a [`MountedWidget`] through a [`WidgetContext`].
pub trait ManageWidget { pub trait ManageWidget {
/// The managed type, which can be `Option<MountedWidget>` or /// The managed type, which can be `Option<MountedWidget>` or
@ -1392,52 +1389,11 @@ pub trait Trackable: sealed::Trackable {}
impl<T> Trackable for T where T: sealed::Trackable {} impl<T> Trackable for T where T: sealed::Trackable {}
pub(crate) mod sealed { pub(crate) mod sealed {
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use crate::context::InvalidationStatus;
use crate::widget::WidgetId; use crate::widget::WidgetId;
use crate::window::sealed::WindowCommand; use crate::window::WindowHandle;
pub trait Trackable { pub trait Trackable {
fn redraw_when_changed(&self, handle: WindowHandle); fn redraw_when_changed(&self, handle: WindowHandle);
fn invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId); fn invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId);
} }
#[derive(Clone)]
pub struct WindowHandle {
pub(crate) kludgine: kludgine::app::WindowHandle<WindowCommand>,
pub(crate) redraw_status: InvalidationStatus,
}
impl Eq for WindowHandle {}
impl PartialEq for WindowHandle {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(
&self.redraw_status.invalidated,
&other.redraw_status.invalidated,
)
}
}
impl Hash for WindowHandle {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.redraw_status.invalidated).hash(state);
}
}
impl WindowHandle {
pub fn redraw(&self) {
if self.redraw_status.should_send_refresh() {
let _result = self.kludgine.send(WindowCommand::Redraw);
}
}
pub fn invalidate(&self, widget: WidgetId) {
if self.redraw_status.invalidate(widget) {
self.redraw();
}
}
}
} }

View file

@ -6,12 +6,11 @@ use alot::{LotId, Lots};
use kludgine::figures::units::{Px, UPx}; use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{Point, Rect, Size}; use kludgine::figures::{Point, Rect, Size};
use crate::context::sealed::WindowHandle;
use crate::styles::{Styles, ThemePair, VisualOrder}; use crate::styles::{Styles, ThemePair, VisualOrder};
use crate::utils::IgnorePoison; use crate::utils::IgnorePoison;
use crate::value::Value; use crate::value::Value;
use crate::widget::{MountedWidget, WidgetId, WidgetInstance}; use crate::widget::{MountedWidget, WidgetId, WidgetInstance};
use crate::window::ThemeMode; use crate::window::{ThemeMode, WindowHandle};
use crate::ConstraintLimit; use crate::ConstraintLimit;
#[derive(Clone, Default)] #[derive(Clone, Default)]

View file

@ -17,11 +17,11 @@ use intentional::Assert;
use kempt::{Map, Sort}; use kempt::{Map, Sort};
use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearInterpolate, Spawn}; use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearInterpolate, Spawn};
use crate::context::sealed::WindowHandle;
use crate::context::{self, WidgetContext}; use crate::context::{self, WidgetContext};
use crate::utils::{run_in_bg, IgnorePoison, WithClone}; use crate::utils::{run_in_bg, IgnorePoison, WithClone};
use crate::widget::{Children, MakeWidget, MakeWidgetWithTag, WidgetId, WidgetInstance}; use crate::widget::{Children, MakeWidget, MakeWidgetWithTag, WidgetId, WidgetInstance};
use crate::widgets::{Radio, Select, Space, Switcher}; use crate::widgets::{Radio, Select, Space, Switcher};
use crate::window::WindowHandle;
/// An instance of a value that provides APIs to observe and react to its /// An instance of a value that provides APIs to observe and react to its
/// contents. /// contents.

View file

@ -19,7 +19,6 @@ use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size};
use kludgine::Color; use kludgine::Color;
use crate::app::{Application, Open, PendingApp, Run}; use crate::app::{Application, Open, PendingApp, Run};
use crate::context::sealed::WindowHandle;
use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext}; use crate::context::{AsEventContext, EventContext, GraphicsContext, LayoutContext, WidgetContext};
use crate::styles::components::{ use crate::styles::components::{
FontFamily, FontStyle, FontWeight, Heading1FontFamily, Heading1Style, Heading1Weight, FontFamily, FontStyle, FontWeight, Heading1FontFamily, Heading1Style, Heading1Weight,
@ -43,7 +42,7 @@ use crate::widgets::{
Align, Button, Checkbox, Collapse, Container, Expand, Layers, Resize, Scroll, Space, Stack, Align, Button, Checkbox, Collapse, Container, Expand, Layers, Resize, Scroll, Space, Stack,
Style, Themed, ThemedMode, Validated, Wrap, Style, Themed, ThemedMode, Validated, Wrap,
}; };
use crate::window::{RunningWindow, ThemeMode, Window, WindowBehavior}; use crate::window::{RunningWindow, ThemeMode, Window, WindowBehavior, WindowHandle};
use crate::ConstraintLimit; use crate::ConstraintLimit;
/// A type that makes up a graphical user interface. /// A type that makes up a graphical user interface.

View file

@ -2,6 +2,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::hash::Hash;
use std::ops::{Deref, DerefMut, Not}; use std::ops::{Deref, DerefMut, Not};
use std::path::Path; use std::path::Path;
use std::string::ToString; use std::string::ToString;
@ -17,7 +18,7 @@ use kludgine::app::winit::event::{
use kludgine::app::winit::keyboard::{Key, NamedKey}; use kludgine::app::winit::keyboard::{Key, NamedKey};
use kludgine::app::winit::window; use kludgine::app::winit::window;
use kludgine::app::WindowBehavior as _; use kludgine::app::WindowBehavior as _;
use kludgine::cosmic_text::{Family, FamilyOwned}; use kludgine::cosmic_text::{fontdb, Family, FamilyOwned};
use kludgine::figures::units::{Px, UPx}; use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Ranged, Rect, ScreenScale, Size, Zero}; use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Ranged, Rect, ScreenScale, Size, Zero};
use kludgine::render::Drawing; use kludgine::render::Drawing;
@ -46,6 +47,7 @@ use crate::{initialize_tracing, ConstraintLimit};
/// A currently running Gooey window. /// A currently running Gooey window.
pub struct RunningWindow<'window> { pub struct RunningWindow<'window> {
window: kludgine::app::Window<'window, WindowCommand>, window: kludgine::app::Window<'window, WindowCommand>,
invalidation_status: InvalidationStatus,
gooey: Gooey, gooey: Gooey,
focused: Dynamic<bool>, focused: Dynamic<bool>,
occluded: Dynamic<bool>, occluded: Dynamic<bool>,
@ -55,6 +57,7 @@ pub struct RunningWindow<'window> {
impl<'window> RunningWindow<'window> { impl<'window> RunningWindow<'window> {
pub(crate) fn new( pub(crate) fn new(
window: kludgine::app::Window<'window, WindowCommand>, window: kludgine::app::Window<'window, WindowCommand>,
invalidation_status: &InvalidationStatus,
gooey: &Gooey, gooey: &Gooey,
focused: &Dynamic<bool>, focused: &Dynamic<bool>,
occluded: &Dynamic<bool>, occluded: &Dynamic<bool>,
@ -62,6 +65,7 @@ impl<'window> RunningWindow<'window> {
) -> Self { ) -> Self {
Self { Self {
window, window,
invalidation_status: invalidation_status.clone(),
gooey: gooey.clone(), gooey: gooey.clone(),
focused: focused.clone(), focused: focused.clone(),
occluded: occluded.clone(), occluded: occluded.clone(),
@ -83,6 +87,20 @@ impl<'window> RunningWindow<'window> {
&self.occluded &self.occluded
} }
/// Request that the window closes.
///
/// A window may disallow itself from being closed by customizing
/// [`WindowBehavior::close_requested`].
pub fn request_close(&self) {
self.handle().request_close();
}
/// Returns a handle to this window.
#[must_use]
pub fn handle(&self) -> WindowHandle {
WindowHandle::new(self.window.handle(), self.invalidation_status.clone())
}
/// Returns a dynamic that is synchronized with this window's inner size. /// Returns a dynamic that is synchronized with this window's inner size.
/// ///
/// Whenever the window is resized, this dynamic will be updated with the /// Whenever the window is resized, this dynamic will be updated with the
@ -332,12 +350,14 @@ where
App: Application, App: Application,
{ {
let gooey = app.gooey().clone(); let gooey = app.gooey().clone();
let redraw_status = InvalidationStatus::default();
let handle = GooeyWindow::<Behavior>::open_with( let handle = GooeyWindow::<Behavior>::open_with(
app, app,
sealed::Context { sealed::Context {
user: self.context, user: self.context,
settings: RefCell::new(sealed::WindowSettings { settings: RefCell::new(sealed::WindowSettings {
gooey, gooey,
redraw_status: redraw_status.clone(),
on_closed: self.on_closed, on_closed: self.on_closed,
transparent: self.attributes.transparent, transparent: self.attributes.transparent,
attributes: Some(self.attributes), attributes: Some(self.attributes),
@ -356,7 +376,7 @@ where
}, },
)?; )?;
Ok(handle.map(WindowHandle::from)) Ok(handle.map(|handle| WindowHandle::new(handle, redraw_status)))
} }
fn run_in(self, app: PendingApp) -> crate::Result { fn run_in(self, app: PendingApp) -> crate::Result {
@ -455,7 +475,6 @@ where
EventContext::new( EventContext::new(
WidgetContext::new( WidgetContext::new(
previously_active, previously_active,
&self.redraw_status,
&self.current_theme, &self.current_theme,
window, window,
self.theme_mode.get(), self.theme_mode.get(),
@ -468,7 +487,6 @@ where
EventContext::new( EventContext::new(
WidgetContext::new( WidgetContext::new(
default.clone(), default.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
window, window,
self.theme_mode.get(), self.theme_mode.get(),
@ -487,7 +505,6 @@ where
EventContext::new( EventContext::new(
WidgetContext::new( WidgetContext::new(
keyboard_activated, keyboard_activated,
&self.redraw_status,
&self.current_theme, &self.current_theme,
window, window,
self.theme_mode.get(), self.theme_mode.get(),
@ -517,7 +534,6 @@ where
let mut context = EventContext::new( let mut context = EventContext::new(
WidgetContext::new( WidgetContext::new(
managed, managed,
&self.redraw_status,
&self.current_theme, &self.current_theme,
window, window,
self.theme_mode.get(), self.theme_mode.get(),
@ -591,37 +607,11 @@ where
root_mode.unwrap_or(RootMode::Fit) root_mode.unwrap_or(RootMode::Fit)
} }
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)] fn load_fonts(
enum RootMode { settings: &mut sealed::WindowSettings,
Fit, fontdb: &mut fontdb::Database,
Expand, ) -> FontState {
Align,
}
impl<T> kludgine::app::WindowBehavior<WindowCommand> for GooeyWindow<T>
where
T: WindowBehavior,
{
type Context = sealed::Context<T::Context>;
fn initialize(
window: kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::Graphics<'_>,
context: Self::Context,
) -> Self {
let mut settings = context.settings.borrow_mut();
let gooey = settings.gooey.clone();
let occluded = settings.occluded.take().unwrap_or_default();
let focused = settings.focused.take().unwrap_or_default();
let theme = settings.theme.take().expect("theme always present");
let inner_size = settings.inner_size.take().unwrap_or_default();
let on_closed = settings.on_closed.take();
inner_size.set(window.inner_size());
let fontdb = graphics.font_system().db_mut();
for font_to_load in settings.font_data_to_load.drain(..) { for font_to_load in settings.font_data_to_load.drain(..) {
fontdb.load_font_data(font_to_load); fontdb.load_font_data(font_to_load);
} }
@ -668,6 +658,39 @@ where
|| default_family(Family::Cursive), || default_family(Family::Cursive),
|name| fontdb.set_cursive_family(name), |name| fontdb.set_cursive_family(name),
); );
fonts
}
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
enum RootMode {
Fit,
Expand,
Align,
}
impl<T> kludgine::app::WindowBehavior<WindowCommand> for GooeyWindow<T>
where
T: WindowBehavior,
{
type Context = sealed::Context<T::Context>;
fn initialize(
window: kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::Graphics<'_>,
context: Self::Context,
) -> Self {
let mut settings = context.settings.borrow_mut();
let gooey = settings.gooey.clone();
let occluded = settings.occluded.take().unwrap_or_default();
let focused = settings.focused.take().unwrap_or_default();
let theme = settings.theme.take().expect("theme always present");
let inner_size = settings.inner_size.take().unwrap_or_default();
let on_closed = settings.on_closed.take();
inner_size.set(window.inner_size());
let fonts = Self::load_fonts(&mut settings, graphics.font_system().db_mut());
let theme_mode = match settings.theme_mode.take() { let theme_mode = match settings.theme_mode.take() {
Some(Value::Dynamic(dynamic)) => { Some(Value::Dynamic(dynamic)) => {
@ -678,8 +701,16 @@ where
None => Value::dynamic(window.theme().into()), None => Value::dynamic(window.theme().into()),
}; };
let transparent = settings.transparent; let transparent = settings.transparent;
let redraw_status = settings.redraw_status.clone();
let mut behavior = T::initialize( let mut behavior = T::initialize(
&mut RunningWindow::new(window, &gooey, &focused, &occluded, &inner_size), &mut RunningWindow::new(
window,
&redraw_status,
&gooey,
&focused,
&occluded,
&inner_size,
),
context.user, context.user,
); );
let tree = Tree::default(); let tree = Tree::default();
@ -701,7 +732,7 @@ where
widget: None, widget: None,
}, },
mouse_buttons: AHashMap::default(), mouse_buttons: AHashMap::default(),
redraw_status: InvalidationStatus::default(), redraw_status,
initial_frame: true, initial_frame: true,
occluded, occluded,
focused, focused,
@ -740,6 +771,7 @@ where
let resizable = window.winit().is_resizable(); let resizable = window.winit().is_resizable();
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -752,7 +784,6 @@ where
let mut context = GraphicsContext { let mut context = GraphicsContext {
widget: WidgetContext::new( widget: WidgetContext::new(
self.root.clone(), self.root.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -876,6 +907,7 @@ where
&mut self.behavior, &mut self.behavior,
&mut RunningWindow::new( &mut RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -949,6 +981,7 @@ where
}; };
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -957,7 +990,6 @@ where
let mut target = EventContext::new( let mut target = EventContext::new(
WidgetContext::new( WidgetContext::new(
target, target,
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -994,7 +1026,6 @@ where
let mut target = EventContext::new( let mut target = EventContext::new(
WidgetContext::new( WidgetContext::new(
target, target,
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1055,6 +1086,7 @@ where
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -1063,7 +1095,6 @@ where
let mut widget = EventContext::new( let mut widget = EventContext::new(
WidgetContext::new( WidgetContext::new(
widget, widget,
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1091,6 +1122,7 @@ where
.unwrap_or_else(|| self.tree.widget(self.root.id()).expect("missing widget")); .unwrap_or_else(|| self.tree.widget(self.root.id()).expect("missing widget"));
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -1099,7 +1131,6 @@ where
let mut target = EventContext::new( let mut target = EventContext::new(
WidgetContext::new( WidgetContext::new(
widget, widget,
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1124,6 +1155,7 @@ where
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -1133,7 +1165,6 @@ where
EventContext::new( EventContext::new(
WidgetContext::new( WidgetContext::new(
self.root.clone(), self.root.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1152,7 +1183,6 @@ where
let mut context = EventContext::new( let mut context = EventContext::new(
WidgetContext::new( WidgetContext::new(
handler.clone(), handler.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1177,6 +1207,7 @@ where
if self.cursor.widget.take().is_some() { if self.cursor.widget.take().is_some() {
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -1185,7 +1216,6 @@ where
let mut context = EventContext::new( let mut context = EventContext::new(
WidgetContext::new( WidgetContext::new(
self.root.clone(), self.root.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1207,6 +1237,7 @@ where
) { ) {
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -1217,7 +1248,6 @@ where
EventContext::new( EventContext::new(
WidgetContext::new( WidgetContext::new(
self.root.clone(), self.root.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1236,7 +1266,6 @@ where
&mut EventContext::new( &mut EventContext::new(
WidgetContext::new( WidgetContext::new(
hovered.clone(), hovered.clone(),
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1276,7 +1305,6 @@ where
let mut context = EventContext::new( let mut context = EventContext::new(
WidgetContext::new( WidgetContext::new(
handler, handler,
&self.redraw_status,
&self.current_theme, &self.current_theme,
&mut window, &mut window,
self.theme_mode.get(), self.theme_mode.get(),
@ -1321,6 +1349,7 @@ where
WindowCommand::RequestClose => { WindowCommand::RequestClose => {
let mut window = RunningWindow::new( let mut window = RunningWindow::new(
window, window,
&self.redraw_status,
&self.gooey, &self.gooey,
&self.focused, &self.focused,
&self.occluded, &self.occluded,
@ -1367,6 +1396,7 @@ pub(crate) mod sealed {
use kludgine::figures::Size; use kludgine::figures::Size;
use crate::app::Gooey; use crate::app::Gooey;
use crate::context::InvalidationStatus;
use crate::styles::{FontFamilyList, ThemePair}; use crate::styles::{FontFamilyList, ThemePair};
use crate::value::{Dynamic, Value}; use crate::value::{Dynamic, Value};
use crate::widget::OnceCallback; use crate::widget::OnceCallback;
@ -1379,6 +1409,7 @@ pub(crate) mod sealed {
pub struct WindowSettings { pub struct WindowSettings {
pub gooey: Gooey, pub gooey: Gooey,
pub redraw_status: InvalidationStatus,
pub attributes: Option<WindowAttributes>, pub attributes: Option<WindowAttributes>,
pub occluded: Option<Dynamic<bool>>, pub occluded: Option<Dynamic<bool>>,
pub focused: Option<Dynamic<bool>>, pub focused: Option<Dynamic<bool>>,
@ -1501,20 +1532,56 @@ fn default_family(query: Family<'_>) -> Option<FamilyOwned> {
} }
/// A handle to an open Gooey window. /// A handle to an open Gooey window.
pub struct WindowHandle(kludgine::app::WindowHandle<sealed::WindowCommand>); #[derive(Clone)]
pub struct WindowHandle {
pub(crate) kludgine: kludgine::app::WindowHandle<WindowCommand>,
pub(crate) redraw_status: InvalidationStatus,
}
impl WindowHandle { impl WindowHandle {
pub(crate) fn new(
kludgine: kludgine::app::WindowHandle<WindowCommand>,
redraw_status: InvalidationStatus,
) -> Self {
Self {
kludgine,
redraw_status,
}
}
/// Request that the window closes. /// Request that the window closes.
/// ///
/// A window may disallow itself from being closed by customizing /// A window may disallow itself from being closed by customizing
/// [`WindowBehavior::close_requested`]. /// [`WindowBehavior::close_requested`].
pub fn request_close(&self) { pub fn request_close(&self) {
let _result = self.0.send(sealed::WindowCommand::RequestClose); let _result = self.kludgine.send(sealed::WindowCommand::RequestClose);
}
/// Requests that the window redraws.
pub fn redraw(&self) {
if self.redraw_status.should_send_refresh() {
let _result = self.kludgine.send(WindowCommand::Redraw);
}
}
/// Marks `widget` as invalidated, and if needed, refreshes the window.
pub fn invalidate(&self, widget: WidgetId) {
if self.redraw_status.invalidate(widget) {
self.redraw();
}
} }
} }
impl From<kludgine::app::WindowHandle<sealed::WindowCommand>> for WindowHandle { impl Eq for WindowHandle {}
fn from(handle: kludgine::app::WindowHandle<sealed::WindowCommand>) -> Self {
WindowHandle(handle) impl PartialEq for WindowHandle {
fn eq(&self, other: &Self) -> bool {
self.redraw_status == other.redraw_status
}
}
impl Hash for WindowHandle {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.redraw_status.hash(state);
} }
} }