-
Notifications
You must be signed in to change notification settings - Fork 570
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
Statically typed selectors #908
Changes from all commits
e308b1a
9eeac53
20e19de
f77794a
da0ed08
778d7d9
d555325
5b60f3d
13d4ae0
c2a55a2
9cdb7d8
9123bb5
9405582
b6f5601
a42d880
65ca89b
55f623e
18fa50d
c66836d
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 |
---|---|---|
|
@@ -21,8 +21,10 @@ use crate::widget::LabelText; | |
use crate::win_handler::{AppHandler, AppState}; | ||
use crate::window::WindowId; | ||
use crate::{ | ||
theme, AppDelegate, Data, DruidHandler, Env, LocalizedString, MenuDesc, Widget, WidgetExt, | ||
command::AppStateTypeError, theme, AppDelegate, Data, DruidHandler, Env, LocalizedString, | ||
MenuDesc, Widget, WidgetExt, | ||
}; | ||
use std::any::{self, Any}; | ||
|
||
/// A function that modifies the initial environment. | ||
type EnvSetupFn<T> = dyn FnOnce(&mut Env, &T); | ||
|
@@ -54,6 +56,43 @@ pub struct WindowDesc<T> { | |
pub id: WindowId, | ||
} | ||
|
||
/// A description of a window to be instantiated. The user has to guarantee that this | ||
/// represents a `WindowDesc<T>` where `T` is the users `AppState`. | ||
/// | ||
/// This includes a function that can build the root widget, as well as other | ||
/// window properties such as the title. | ||
pub struct AppStateWindowDesc { | ||
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. Naming: I would call this Philosophy: I get that this is a problem that needs to be solved for this PR to work, but I also think it's worth thinking about on its own. What we need:
What's the best way to do this? I'm not totally sure. If we could have some internal type that did what this type is doing, that would be great. One way this might work is if we had convenience methods for things like making a new window or setting a menu; for instance creating a new window might just use a method on It might also be that we require a public type (that appears in the signature of the selector, for instance) but we don't actually need the user to ever interact with it? 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. I though about some kind of wrapper type but I don't think it is possible with the Rust type system. 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 nice thing is that on 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. How so? I mean 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. mm you're right I was thinking that |
||
inner: Box<dyn Any>, | ||
type_name: &'static str, | ||
} | ||
|
||
impl<T: Any> WindowDesc<T> { | ||
/// This turns a typed `WindowDesc<T>` into an untyped `AppStateWindowDesc`. | ||
/// Doing so allows sending `WindowDesc` through `Command`s. | ||
/// It is up to you, to ensure that this `T` represents your application | ||
/// state that you passed to `AppLauncher::launch`. | ||
pub fn into_app_state_menu_desc(self) -> AppStateWindowDesc { | ||
AppStateWindowDesc { | ||
inner: Box::new(self), | ||
type_name: any::type_name::<Self>(), | ||
} | ||
} | ||
} | ||
|
||
impl AppStateWindowDesc { | ||
pub(crate) fn realize<T: Any>(self) -> Result<WindowDesc<T>, AppStateTypeError> { | ||
let inner: Result<Box<WindowDesc<T>>, _> = self.inner.downcast(); | ||
if let Ok(inner) = inner { | ||
Ok(*inner) | ||
} else { | ||
Err(AppStateTypeError::new( | ||
any::type_name::<WindowDesc<T>>(), | ||
self.type_name, | ||
)) | ||
} | ||
} | ||
} | ||
|
||
impl<T: Data> AppLauncher<T> { | ||
/// Create a new `AppLauncher` with the provided window. | ||
pub fn with_window(window: WindowDesc<T>) -> Self { | ||
|
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.
maybe this can just be a separate patch?
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 suppose this could be split into
SHOW_WINDOW
andOPEN_WINDOW
to useTarget
Selector
type safeSelector
intoSelector
andSelectorOnce
EventCtx
to create menus and windows.Splitting the last two out would cause quite some duplicated / wasted work tho, as
SelectorOnce
influences error and return types, while menus creation decides over adding wrapper types or new methods.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.
Even the first one means that I'll have to first declare it to take
WidgetId
and than remove that in a separate PR again.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.
yea, if things are truly entwined than doing it together makes sense, but if there are good dividing points that does make review a lot easier.