-
Notifications
You must be signed in to change notification settings - Fork 569
Add closures to AppDelegate #268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,20 +19,12 @@ use std::collections::VecDeque; | |
use crate::{Command, Data, Env, Event, WinCtx, WindowId}; | ||
|
||
/// A context passed in to [`AppDelegate`] functions. | ||
pub struct DelegateCtx<'a, 'b> { | ||
pub struct DelegateCtx<'a> { | ||
pub(crate) source_id: WindowId, | ||
pub(crate) command_queue: &'a mut VecDeque<(WindowId, Command)>, | ||
pub(crate) win_ctx: &'a mut dyn WinCtx<'b>, | ||
} | ||
|
||
impl<'a, 'b> DelegateCtx<'a, 'b> { | ||
/// Get the [`WinCtx`]. | ||
/// | ||
/// [`WinCtx`] trait.WinCtx.html | ||
pub fn win_ctx(&self) -> &dyn WinCtx<'b> { | ||
self.win_ctx | ||
} | ||
|
||
impl<'a> DelegateCtx<'a> { | ||
/// Submit a [`Command`] to be run after this event is handled. | ||
/// | ||
/// Commands are run in the order they are submitted; all commands | ||
|
@@ -56,13 +48,24 @@ impl<'a, 'b> DelegateCtx<'a, 'b> { | |
/// | ||
/// You customize the `AppDelegate` by passing closures during creation. | ||
pub struct AppDelegate<T> { | ||
event_fn: Option<Box<dyn Fn(Event, &mut T, &Env, &mut DelegateCtx) -> Option<Event> + 'static>>, | ||
event_fn: Option< | ||
Box< | ||
dyn Fn(Event, &mut T, &Env, &mut DelegateCtx, &mut dyn WinCtx) -> Option<Event> | ||
+ 'static, | ||
>, | ||
>, | ||
window_added_fn: Option<Box<dyn Fn(WindowId, &mut T, &Env, &mut DelegateCtx)>>, | ||
window_removed_fn: Option<Box<dyn Fn(WindowId, &mut T, &Env, &mut DelegateCtx)>>, | ||
} | ||
|
||
impl<T: Data> AppDelegate<T> { | ||
/// Create a new `AppDelegate`. | ||
pub fn new() -> Self { | ||
AppDelegate { event_fn: None } | ||
AppDelegate { | ||
event_fn: None, | ||
window_added_fn: None, | ||
window_removed_fn: None, | ||
} | ||
} | ||
|
||
/// Set the `AppDelegate`'s event handler. This function receives all events, | ||
|
@@ -73,22 +76,63 @@ impl<T: Data> AppDelegate<T> { | |
/// the `update` method will be called as usual. | ||
pub fn event_handler<F>(mut self, f: F) -> Self | ||
where | ||
F: Fn(Event, &mut T, &Env, &mut DelegateCtx) -> Option<Event> + 'static, | ||
F: Fn(Event, &mut T, &Env, &mut DelegateCtx, &mut dyn WinCtx) -> Option<Event> + 'static, | ||
{ | ||
self.event_fn = Some(Box::new(f)); | ||
self | ||
} | ||
|
||
pub fn window_added_handler<F>(mut self, f: F) -> Self | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The one thing missing in this PR is docs for the public API. |
||
where | ||
F: Fn(WindowId, &mut T, &Env, &mut DelegateCtx) + 'static, | ||
{ | ||
self.window_added_fn = Some(Box::new(f)); | ||
self | ||
} | ||
|
||
pub fn window_removed_handler<F>(mut self, f: F) -> Self | ||
where | ||
F: Fn(WindowId, &mut T, &Env, &mut DelegateCtx) + 'static, | ||
{ | ||
self.window_removed_fn = Some(Box::new(f)); | ||
self | ||
} | ||
|
||
pub(crate) fn event( | ||
&mut self, | ||
event: Event, | ||
data: &mut T, | ||
env: &Env, | ||
ctx: &mut DelegateCtx, | ||
delegate_ctx: &mut DelegateCtx, | ||
win_ctx: &mut dyn WinCtx, | ||
) -> Option<Event> { | ||
match self.event_fn.as_ref() { | ||
Some(f) => (f)(event, data, env, ctx), | ||
Some(f) => (f)(event, data, env, delegate_ctx, win_ctx), | ||
None => Some(event), | ||
} | ||
} | ||
|
||
pub(crate) fn window_added( | ||
&mut self, | ||
window_id: WindowId, | ||
data: &mut T, | ||
env: &Env, | ||
ctx: &mut DelegateCtx, | ||
) { | ||
if let Some(f) = self.window_added_fn.as_ref() { | ||
f(window_id, data, env, ctx); | ||
} | ||
} | ||
|
||
pub(crate) fn window_removed( | ||
&mut self, | ||
window_id: WindowId, | ||
data: &mut T, | ||
env: &Env, | ||
ctx: &mut DelegateCtx, | ||
) { | ||
if let Some(f) = self.window_removed_fn.as_ref() { | ||
f(window_id, data, env, ctx); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -306,14 +306,41 @@ impl<T: Data + 'static> AppState<T> { | |
|
||
fn connect(&mut self, id: WindowId, handle: WindowHandle) { | ||
self.windows.connect(id, handle); | ||
if let Some(delegate) = &mut self.delegate { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So these 10 lines or so are the main place here where I wonder if we can't reduce boilerplate. What I am imagining is a function on fn with_delegate(&mut self, f: impl Fn(&mut AppDelegate, &mut DelegateCtx)); which internally does this whole dance of destructing self and creating the If we had this, we could replace these 12 lines with, self.with_delegate(|del, ctx| del.window_added(id, data, env, ctx)); Does that make sense? |
||
let AppState { | ||
ref mut command_queue, | ||
ref mut data, | ||
ref env, | ||
.. | ||
} = self; | ||
let mut ctx = DelegateCtx { | ||
source_id: id, | ||
command_queue, | ||
}; | ||
delegate.window_added(id, data, env, &mut ctx) | ||
} | ||
} | ||
|
||
pub(crate) fn add_window(&mut self, id: WindowId, window: Window<T>) { | ||
self.windows.add(id, window); | ||
} | ||
|
||
fn remove_window(&mut self, id: WindowId) -> Option<WindowHandle> { | ||
self.windows.remove(id) | ||
let res = self.windows.remove(id); | ||
if let Some(delegate) = &mut self.delegate { | ||
let AppState { | ||
ref mut command_queue, | ||
ref mut data, | ||
ref env, | ||
.. | ||
} = self; | ||
let mut ctx = DelegateCtx { | ||
source_id: id, | ||
command_queue, | ||
}; | ||
delegate.window_removed(id, data, env, &mut ctx) | ||
} | ||
res | ||
} | ||
|
||
fn assemble_window_state<'a>( | ||
|
@@ -413,9 +440,8 @@ impl<T: Data + 'static> AppState<T> { | |
let mut ctx = DelegateCtx { | ||
source_id, | ||
command_queue, | ||
win_ctx, | ||
}; | ||
delegate.event(event, data, env, &mut ctx) | ||
delegate.event(event, data, env, &mut ctx, win_ctx) | ||
} | ||
None => Some(event), | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this complexity isn't worth it, and we should just back up and make
AppDelegate
a trait.If you'd like to try that, it's probably a separate PR, and then we could redo this on top of that? Or I could make that change, whichever is easiest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'd like to try my hand at that. I'll leave this as-is for now then.