-
Notifications
You must be signed in to change notification settings - Fork 863
Popup: Set correct window adapter for the component #11352
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
base: master
Are you sure you want to change the base?
Changes from all commits
f2b74e4
d214fef
102e9ab
b32cee7
ee60b66
fd13575
d21cccc
742b2a1
4663405
5cf7190
e93f76e
3df2707
3cb56ec
497e225
891f54d
586a74a
5af6171
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 |
|---|---|---|
|
|
@@ -516,6 +516,23 @@ fn generate_shared_globals( | |
| _self | ||
| } | ||
|
|
||
| // Clone the SharedGlobals struct but use a different window adapter. This is for example used for popup windows, because they need access to the globals, but need their own window adapter | ||
| #[allow(dead_code)] | ||
| #pub_token fn clone_with_window_adapter(&self, window_adapter: sp::WindowAdapterRc) -> sp::Rc<Self> { | ||
| let _self = sp::Rc::new(Self { | ||
| #(#global_names : self.#global_names.clone(),)* | ||
| #(#from_library_global_names : self.#from_library_global_names.clone(),)* | ||
| window_adapter: ::core::default::Default::default(), | ||
| root_item_tree_weak: self.root_item_tree_weak.clone(), | ||
|
Member
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 think this also need to passed in
Contributor
Author
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 can do. It is only required to init the window_adapter, but since we initialized already,
Contributor
Author
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 problem here is that we need the global to create the item, but on the other side we need the global to create the popup item |
||
| #(#library_shared_globals_names: self.#library_shared_globals_names.clone(),)* | ||
| }); | ||
| _self.window_adapter | ||
| .set(window_adapter) | ||
| .map_err(|_| ()) | ||
| .expect("The window adapter should not be initialized before this call"); | ||
| _self | ||
| } | ||
|
|
||
| fn window_adapter_impl(&self) -> sp::Rc<dyn sp::WindowAdapter> { | ||
| sp::Rc::clone(self.window_adapter_ref().unwrap()) | ||
| } | ||
|
|
@@ -841,7 +858,7 @@ fn generate_sub_component( | |
| root, | ||
| Some(&ParentScope::new(&ctx, None)), | ||
| None, | ||
| false, | ||
| true, | ||
| ) | ||
| }) | ||
| .chain(component.menu_item_trees.iter().map(|tree| { | ||
|
|
@@ -1716,7 +1733,7 @@ fn generate_item_tree( | |
| root: &llr::CompilationUnit, | ||
| parent_ctx: Option<&ParentScope>, | ||
| index_property: Option<llr::PropertyIdx>, | ||
| is_popup_menu: bool, | ||
| is_popup: bool, | ||
| ) -> TokenStream { | ||
| let sub_comp = generate_sub_component(sub_tree.root, root, parent_ctx, index_property, true); | ||
| let inner_component_id = self::inner_component_id(&root.sub_components[sub_tree.root]); | ||
|
|
@@ -1729,14 +1746,14 @@ fn generate_item_tree( | |
| }) | ||
| .collect::<Vec<_>>(); | ||
|
|
||
| let globals = if is_popup_menu { | ||
| let globals = if is_popup { | ||
| quote!(globals) | ||
| } else if parent_ctx.is_some() { | ||
| quote!(parent.upgrade().unwrap().globals.get().unwrap().clone()) | ||
| } else { | ||
| quote!(SharedGlobals::new(sp::VRc::downgrade(&self_dyn_rc))) | ||
| }; | ||
| let globals_arg = is_popup_menu.then(|| quote!(globals: sp::Rc<SharedGlobals>)); | ||
| let globals_arg = is_popup.then(|| quote!(globals: sp::Rc<SharedGlobals>)); | ||
|
|
||
| let embedding_function = if parent_ctx.is_some() { | ||
| quote!(todo!("Components written in Rust can not get embedded yet.")) | ||
|
|
@@ -3286,7 +3303,15 @@ fn compile_builtin_function_call( | |
| let popup_id_name = internal_popup_id(*popup_index as usize); | ||
| component_access_tokens.then(|component_access_tokens| quote!({ | ||
| let parent_item = #parent_item; | ||
| let popup_instance = #popup_window_id::new(#component_access_tokens.self_weak.get().unwrap().clone()).unwrap(); | ||
| // Use the newly created window adapter if we are able to create one. Otherwise use the parent's one | ||
| let globals = if let Some(window_adapter) = sp::WindowInner::from_pub(#window_adapter_tokens.window()).create_popup_window_adapter() { | ||
|
Murmele marked this conversation as resolved.
Member
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 guess a similar change in the C++ and interpreter code will be required.
Contributor
Author
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. yep there I have to add as well
Contributor
Author
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. done |
||
| let globals = #component_access_tokens.globals.get().unwrap().clone_with_window_adapter(window_adapter); | ||
| globals | ||
| } else { | ||
| #component_access_tokens.globals.get().unwrap().clone() | ||
| }; | ||
|
|
||
| let popup_instance = #popup_window_id::new(#component_access_tokens.self_weak.get().unwrap().clone(), globals).unwrap(); | ||
| let popup_instance_vrc = sp::VRc::map(popup_instance.clone(), |x| x); | ||
| let position = { let _self = popup_instance_vrc.as_pin_ref(); #position }; | ||
| if let Some(current_id) = #component_access_tokens.#popup_id_name.take() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,8 +6,8 @@ | |
| #![warn(missing_docs)] | ||
| //! Exposed Window API | ||
| use crate::api::{ | ||
| CloseRequestResponse, LogicalPosition, PhysicalPosition, PhysicalSize, PlatformError, Window, | ||
| WindowPosition, WindowSize, | ||
| CloseRequestResponse, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, | ||
| PlatformError, Window, WindowPosition, WindowSize, | ||
| }; | ||
| use crate::graphics::Color; | ||
| use crate::input::{ | ||
|
|
@@ -178,12 +178,12 @@ pub trait WindowAdapterInternal: core::any::Any { | |
| } | ||
|
|
||
| /// Create a window for a popup. | ||
| /// | ||
| /// `geometry` is the location of the popup in the window coordinate | ||
| /// This function will create only the window adapter but does not show the popup it self | ||
| /// Use this window adapter to create a new popup window and show it with `show_popup()` | ||
| /// | ||
| /// If this function return None (the default implementation), then the | ||
| /// popup will be rendered within the window itself. | ||
| fn create_popup(&self, _geometry: LogicalRect) -> Option<Rc<dyn WindowAdapter>> { | ||
| fn create_popup_window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> { | ||
| None | ||
| } | ||
|
|
||
|
|
@@ -1338,6 +1338,13 @@ impl WindowInner { | |
| .collect() | ||
| }); | ||
| } | ||
| /// Create a new popup window adapter | ||
| /// This window adapter can be used on a popup component and shown with show_popup() | ||
| pub fn create_popup_window_adapter(&self) -> Option<Rc<dyn WindowAdapter>> { | ||
| self.window_adapter() | ||
| .internal(crate::InternalToken) | ||
| .and_then(|s| s.create_popup_window_adapter()) | ||
| } | ||
|
|
||
| /// Show a popup at the given position relative to the `parent_item` and returns its ID. | ||
| /// The returned ID will always be non-zero. | ||
|
|
@@ -1433,28 +1440,35 @@ impl WindowInner { | |
| self.window_adapter() | ||
| }; | ||
|
|
||
| let mut popup_window_adapter = None; | ||
| ItemTreeRc::borrow_pin(popup_componentrc) | ||
| .as_ref() | ||
| .window_adapter(false, &mut popup_window_adapter); | ||
| let popup_window_adapter = | ||
| popup_window_adapter.expect("It must be there because we set the global"); | ||
|
|
||
| // If a popup can be created it is at TopLevel, otherwise it is a ChildWindow | ||
| // of the current window | ||
| let location = match parent_window_adapter | ||
| .internal(crate::InternalToken) | ||
| .and_then(|x| x.create_popup(LogicalRect::new(position, size))) | ||
| { | ||
| None => { | ||
| let clip = LogicalRect::new( | ||
| LogicalPoint::new(0.0 as crate::Coord, 0.0 as crate::Coord), | ||
| self.window_adapter().size().to_logical(self.scale_factor()).to_euclid(), | ||
| ); | ||
| let rect = popup::place_popup( | ||
| popup::Placement::Fixed(LogicalRect::new(position, size)), | ||
| &Some(clip), | ||
| ); | ||
| self.window_adapter().request_redraw(); | ||
| PopupWindowLocation::ChildWindow(rect.origin) | ||
| } | ||
| Some(window_adapter) => { | ||
| WindowInner::from_pub(window_adapter.window()).set_component(popup_componentrc); | ||
| PopupWindowLocation::TopLevel(window_adapter) | ||
| } | ||
| let location = if Rc::ptr_eq(&parent_window_adapter, &popup_window_adapter) { | ||
|
Member
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'm thinking this could potentially be a problem if we had a popup child of another popup and one (custom) platform would only support one layer of popup. But maybe there is no such thing.
Contributor
Author
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. You mean a mix of ChildWindow and TopLevelWindow? |
||
| let clip = LogicalRect::new( | ||
| LogicalPoint::new(0.0 as crate::Coord, 0.0 as crate::Coord), | ||
| self.window_adapter().size().to_logical(self.scale_factor()).to_euclid(), | ||
| ); | ||
| let rect = popup::place_popup( | ||
| popup::Placement::Fixed(LogicalRect::new(position, size)), | ||
| &Some(clip), | ||
| ); | ||
| self.window_adapter().request_redraw(); | ||
| PopupWindowLocation::ChildWindow(rect.origin) | ||
| } else { | ||
| WindowInner::from_pub(popup_window_adapter.window()).set_component(popup_componentrc); | ||
| popup_window_adapter.window().set_position(LogicalPosition::from_euclid(position)); | ||
| popup_window_adapter | ||
| .window() | ||
| .set_size(WindowSize::Logical(LogicalSize::from_euclid(size))); | ||
|
|
||
| popup_window_adapter.set_visible(true).expect("Unable to show popup"); | ||
| PopupWindowLocation::TopLevel(popup_window_adapter) | ||
| }; | ||
|
|
||
| let focus_item = self | ||
|
|
@@ -1952,6 +1966,26 @@ pub mod ffi { | |
| } | ||
| } | ||
|
|
||
| /// Create a popup window adapter. Returns true if a new adapter was created and written to result. | ||
| /// Returns false if the backend does not support top-level popups. | ||
| /// This can be used to set the correct window adapter on a popup component before showing it. | ||
| #[unsafe(no_mangle)] | ||
| pub unsafe extern "C" fn slint_windowrc_create_popup_window_adapter( | ||
| handle: *const WindowAdapterRcOpaque, | ||
| result: *mut WindowAdapterRcOpaque, | ||
| ) -> bool { | ||
| unsafe { | ||
| let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>); | ||
| match WindowInner::from_pub(window_adapter.window()).create_popup_window_adapter() { | ||
| Some(wa) => { | ||
| core::ptr::write(result as *mut Rc<dyn WindowAdapter>, wa); | ||
| true | ||
| } | ||
| None => false, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Close the popup by the given ID. | ||
| #[unsafe(no_mangle)] | ||
| pub unsafe extern "C" fn slint_windowrc_close_popup( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.