55
66#[ cfg( all( feature = "wayland" , feature = "winit" , feature = "surface-message" ) ) ]
77use crate :: app:: cosmic:: { WINDOWING_SYSTEM , WindowingSystem } ;
8+ use crate :: surface;
89use crate :: widget:: menu:: {
910 self , CloseCondition , Direction , ItemHeight , ItemWidth , MenuBarState , PathHighlight ,
1011 init_root_menu, menu_roots_diff,
@@ -22,7 +23,7 @@ pub fn context_menu<Message: 'static + Clone>(
2223 content : impl Into < crate :: Element < ' static , Message > > + ' static ,
2324 // on_context: Message,
2425 context_menu : Option < Vec < menu:: Tree < Message > > > ,
25- ) -> ContextMenu < ' static , Message > {
26+ ) -> ContextMenu < ' static , Message , Message > {
2627 let mut this = ContextMenu {
2728 content : content. into ( ) ,
2829 context_menu : context_menu. map ( |menus| {
@@ -33,6 +34,7 @@ pub fn context_menu<Message: 'static + Clone>(
3334 } ) ,
3435 window_id : window:: Id :: RESERVED ,
3536 on_surface_action : None ,
37+ action_map : None ,
3638 } ;
3739
3840 if let Some ( ref mut context_menu) = this. context_menu {
@@ -42,10 +44,42 @@ pub fn context_menu<Message: 'static + Clone>(
4244 this
4345}
4446
47+ /// A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation.
48+ pub fn context_menu_popup < Message : ' static + Clone , AppMessage : ' static + Clone > (
49+ content : impl Into < crate :: Element < ' static , Message > > + ' static ,
50+ // on_context: Message,
51+ context_menu : Option < Vec < menu:: Tree < Message > > > ,
52+ _parent_id : window:: Id ,
53+ _on_surface_action : impl Fn ( surface:: Action ) -> Message + Send + Sync + ' static ,
54+ _map_action : impl Fn ( Message ) -> AppMessage + Send + Sync + ' static ,
55+ ) -> ContextMenu < ' static , Message , AppMessage > {
56+ let this: ContextMenu < ' _ , Message , AppMessage > = ContextMenu {
57+ content : content. into ( ) ,
58+ context_menu : context_menu. map ( |menus| {
59+ vec ! [ menu:: Tree :: with_children(
60+ crate :: Element :: from( crate :: widget:: row:: <' static , Message >( ) ) ,
61+ menus,
62+ ) ]
63+ } ) ,
64+ window_id : window:: Id :: RESERVED ,
65+ on_surface_action : None ,
66+ action_map : None ,
67+ } ;
68+
69+ #[ cfg( all( feature = "winit" , feature = "wayland" ) ) ]
70+ let mut this = this. with_popup ( _parent_id, _on_surface_action, _map_action) ;
71+
72+ if let Some ( ref mut context_menu) = this. context_menu {
73+ context_menu. iter_mut ( ) . for_each ( menu:: Tree :: set_index) ;
74+ }
75+
76+ this
77+ }
78+
4579/// A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation.
4680#[ derive( Setters ) ]
4781#[ must_use]
48- pub struct ContextMenu < ' a , Message > {
82+ pub struct ContextMenu < ' a , Message , AppMessage > {
4983 #[ setters( skip) ]
5084 content : crate :: Element < ' a , Message > ,
5185 #[ setters( skip) ]
@@ -54,9 +88,13 @@ pub struct ContextMenu<'a, Message> {
5488 #[ setters( skip) ]
5589 pub ( crate ) on_surface_action :
5690 Option < Arc < dyn Fn ( crate :: surface:: Action ) -> Message + Send + Sync + ' static > > ,
91+ #[ setters( skip) ]
92+ pub action_map : Option < Arc < dyn Fn ( Message ) -> AppMessage + ' static + Send + Sync > > ,
5793}
5894
59- impl < Message : Clone + ' static > ContextMenu < ' _ , Message > {
95+ impl < ' a , Message : Clone + ' static , AppMessage : Clone + ' static >
96+ ContextMenu < ' a , Message , AppMessage >
97+ {
6098 #[ cfg( all( feature = "wayland" , feature = "winit" , feature = "surface-message" ) ) ]
6199 #[ allow( clippy:: too_many_lines) ]
62100 fn create_popup (
@@ -68,7 +106,10 @@ impl<Message: Clone + 'static> ContextMenu<'_, Message> {
68106 viewport : & iced:: Rectangle ,
69107 my_state : & mut LocalState ,
70108 ) {
71- if self . window_id != window:: Id :: NONE && self . on_surface_action . is_some ( ) {
109+ if self . window_id != window:: Id :: NONE
110+ && self . on_surface_action . is_some ( )
111+ && self . action_map . is_some ( )
112+ {
72113 use crate :: { surface:: action:: destroy_popup, widget:: menu:: Menu } ;
73114 use iced_runtime:: platform_specific:: wayland:: popup:: {
74115 SctkPopupSettings , SctkPositioner ,
@@ -171,6 +212,7 @@ impl<Message: Clone + 'static> ContextMenu<'_, Message> {
171212 ..Default :: default ( )
172213 } ;
173214 let parent = self . window_id ;
215+ let action_map = self . action_map . clone ( ) . unwrap ( ) ;
174216 shell. publish ( ( self . on_surface_action . as_ref ( ) . unwrap ( ) ) (
175217 crate :: surface:: action:: simple_popup (
176218 move || SctkPopupSettings {
@@ -183,27 +225,44 @@ impl<Message: Clone + 'static> ContextMenu<'_, Message> {
183225 input_zone : None ,
184226 } ,
185227 Some ( move || {
228+ let action_map = action_map. clone ( ) ;
186229 crate :: Element :: from (
187230 crate :: widget:: container ( popup_menu. clone ( ) ) . center ( Length :: Fill ) ,
188231 )
189- . map ( crate :: action :: app )
232+ . map ( move |m| crate :: Action :: App ( action_map . clone ( ) ( m ) ) )
190233 } ) ,
191234 ) ,
192235 ) ) ;
193236 }
194237 }
195238
196- pub fn on_surface_action (
239+ #[ cfg( all( feature = "winit" , feature = "wayland" ) ) ]
240+ /// Handle dropdown requests for popup creation.
241+ /// Intended to be used with [`crate::app::message::get_popup`]
242+ pub fn with_popup < NewAppMessage > (
197243 mut self ,
198- handler : impl Fn ( crate :: surface:: Action ) -> Message + Send + Sync + ' static ,
199- ) -> Self {
200- self . on_surface_action = Some ( Arc :: new ( handler) ) ;
201- self
244+ parent_id : window:: Id ,
245+ on_surface_action : impl Fn ( surface:: Action ) -> Message + Send + Sync + ' static ,
246+ action_map : impl Fn ( Message ) -> NewAppMessage + Send + Sync + ' static ,
247+ ) -> ContextMenu < ' a , Message , NewAppMessage > {
248+ let Self {
249+ content,
250+ context_menu,
251+ ..
252+ } = self ;
253+ let new = ContextMenu :: < ' a , Message , NewAppMessage > {
254+ content,
255+ context_menu,
256+ on_surface_action : Some ( Arc :: new ( on_surface_action) ) ,
257+ action_map : Some ( Arc :: new ( action_map) ) ,
258+ window_id : parent_id,
259+ } ;
260+ new
202261 }
203262}
204263
205- impl < Message : ' static + Clone > Widget < Message , crate :: Theme , crate :: Renderer >
206- for ContextMenu < ' _ , Message >
264+ impl < Message : ' static + Clone , AppMessage : ' static + Clone >
265+ Widget < Message , crate :: Theme , crate :: Renderer > for ContextMenu < ' _ , Message , AppMessage >
207266{
208267 fn tag ( & self ) -> tree:: Tag {
209268 tree:: Tag :: of :: < LocalState > ( )
@@ -539,10 +598,10 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
539598 }
540599}
541600
542- impl < ' a , Message : Clone + ' static > From < ContextMenu < ' static , Message > >
543- for crate :: Element < ' static , Message >
601+ impl < ' a , Message : Clone + ' static , AppMessage : Clone + ' static >
602+ From < ContextMenu < ' static , Message , AppMessage > > for crate :: Element < ' static , Message >
544603{
545- fn from ( widget : ContextMenu < ' static , Message > ) -> Self {
604+ fn from ( widget : ContextMenu < ' static , Message , AppMessage > ) -> Self {
546605 Self :: new ( widget)
547606 }
548607}
0 commit comments