@@ -17,15 +17,16 @@ use crate::input::{
17
17
} ;
18
18
use crate :: item_tree:: ItemRc ;
19
19
use crate :: item_tree:: { ItemTreeRc , ItemTreeRef , ItemTreeVTable , ItemTreeWeak } ;
20
- use crate :: items:: PopupClosePolicy ;
21
- use crate :: items:: { ColorScheme , InputType , ItemRef , MouseCursor } ;
20
+ use crate :: items:: { ColorScheme , InputType , ItemRef , MouseCursor , PopupClosePolicy } ;
22
21
use crate :: lengths:: { LogicalLength , LogicalPoint , LogicalRect , SizeLengths } ;
23
22
use crate :: properties:: { Property , PropertyTracker } ;
24
23
use crate :: renderer:: Renderer ;
25
24
use crate :: { Callback , Coord , SharedString } ;
26
25
#[ cfg( not( feature = "std" ) ) ]
27
26
use alloc:: boxed:: Box ;
28
27
use alloc:: rc:: { Rc , Weak } ;
28
+ #[ cfg( not( feature = "std" ) ) ]
29
+ use alloc:: vec:: Vec ;
29
30
use core:: cell:: { Cell , RefCell } ;
30
31
use core:: pin:: Pin ;
31
32
use euclid:: num:: Zero ;
@@ -431,7 +432,8 @@ pub struct WindowInner {
431
432
maximized : Cell < bool > ,
432
433
minimized : Cell < bool > ,
433
434
434
- active_popup : RefCell < Option < PopupWindow > > ,
435
+ /// Stack of currently active popups
436
+ active_popups : RefCell < Vec < PopupWindow > > ,
435
437
had_popup_on_press : Cell < bool > ,
436
438
close_requested : Callback < ( ) , CloseRequestResponse > ,
437
439
click_state : ClickState ,
@@ -492,7 +494,7 @@ impl WindowInner {
492
494
focus_item : Default :: default ( ) ,
493
495
last_ime_text : Default :: default ( ) ,
494
496
cursor_blinker : Default :: default ( ) ,
495
- active_popup : Default :: default ( ) ,
497
+ active_popups : Default :: default ( ) ,
496
498
had_popup_on_press : Default :: default ( ) ,
497
499
close_requested : Default :: default ( ) ,
498
500
click_state : ClickState :: default ( ) ,
@@ -575,7 +577,7 @@ impl WindowInner {
575
577
}
576
578
577
579
if pressed_event {
578
- self . had_popup_on_press . set ( self . active_popup . borrow ( ) . is_some ( ) ) ;
580
+ self . had_popup_on_press . set ( ! self . active_popups . borrow ( ) . is_empty ( ) ) ;
579
581
}
580
582
581
583
let close_policy = self . close_policy ( ) ;
@@ -588,7 +590,7 @@ impl WindowInner {
588
590
location : PopupWindowLocation :: ChildWindow ( coordinates) ,
589
591
component,
590
592
..
591
- } ) = self . active_popup . borrow ( ) . as_ref ( )
593
+ } ) = self . active_popups . borrow ( ) . last ( )
592
594
{
593
595
let geom = ItemTreeRc :: borrow_pin ( component) . as_ref ( ) . item_geometry ( 0 ) ;
594
596
@@ -800,7 +802,7 @@ impl WindowInner {
800
802
801
803
fn move_focus ( & self , start_item : ItemRc , forward : impl Fn ( ItemRc ) -> ItemRc ) -> Option < ItemRc > {
802
804
let mut current_item = start_item;
803
- let mut visited = alloc :: vec :: Vec :: new ( ) ;
805
+ let mut visited = Vec :: new ( ) ;
804
806
805
807
loop {
806
808
if current_item. is_visible ( )
@@ -899,32 +901,29 @@ impl WindowInner {
899
901
& self ,
900
902
render_components : impl FnOnce ( & [ ( & ItemTreeRc , LogicalPoint ) ] ) -> T ,
901
903
) -> Option < T > {
902
- let draw_fn = || {
903
- let component_rc = self . try_component ( ) ?;
904
-
905
- let popup_component =
906
- self . active_popup . borrow ( ) . as_ref ( ) . and_then ( |popup| match popup. location {
907
- PopupWindowLocation :: TopLevel ( ..) => None ,
908
- PopupWindowLocation :: ChildWindow ( coordinates) => {
909
- Some ( ( popup. component . clone ( ) , coordinates) )
904
+ let component_rc = self . try_component ( ) ?;
905
+ Some ( self . pinned_fields . as_ref ( ) . project_ref ( ) . redraw_tracker . evaluate_as_dependency_root (
906
+ || {
907
+ if !self
908
+ . active_popups
909
+ . borrow ( )
910
+ . iter ( )
911
+ . any ( |p| matches ! ( p. location, PopupWindowLocation :: ChildWindow ( ..) ) )
912
+ {
913
+ render_components ( & [ ( & component_rc, LogicalPoint :: default ( ) ) ] )
914
+ } else {
915
+ let borrow = self . active_popups . borrow ( ) ;
916
+ let mut cmps = Vec :: with_capacity ( borrow. len ( ) + 1 ) ;
917
+ cmps. push ( ( & component_rc, LogicalPoint :: default ( ) ) ) ;
918
+ for popup in borrow. iter ( ) {
919
+ if let PopupWindowLocation :: ChildWindow ( location) = & popup. location {
920
+ cmps. push ( ( & popup. component , * location) ) ;
921
+ }
910
922
}
911
- } ) ;
912
-
913
- Some ( if let Some ( ( popup_component, popup_coordinates) ) = popup_component {
914
- render_components ( & [
915
- ( & component_rc, LogicalPoint :: default ( ) ) ,
916
- ( & popup_component, popup_coordinates) ,
917
- ] )
918
- } else {
919
- render_components ( & [ ( & component_rc, LogicalPoint :: default ( ) ) ] )
920
- } )
921
- } ;
922
-
923
- self . pinned_fields
924
- . as_ref ( )
925
- . project_ref ( )
926
- . redraw_tracker
927
- . evaluate_as_dependency_root ( draw_fn)
923
+ render_components ( & cmps)
924
+ }
925
+ } ,
926
+ ) )
928
927
}
929
928
930
929
/// Registers the window with the windowing system, in order to render the component's items and react
@@ -983,6 +982,34 @@ impl WindowInner {
983
982
let position = parent_item. map_to_window (
984
983
parent_item. geometry ( ) . origin + LogicalPoint :: from_untyped ( position) . to_vector ( ) ,
985
984
) ;
985
+ let root_of = |mut item_tree : ItemTreeRc | loop {
986
+ if ItemRc :: new ( item_tree. clone ( ) , 0 ) . downcast :: < crate :: items:: WindowItem > ( ) . is_some ( ) {
987
+ return item_tree;
988
+ }
989
+ let mut r = crate :: item_tree:: ItemWeak :: default ( ) ;
990
+ ItemTreeRc :: borrow_pin ( & item_tree) . as_ref ( ) . parent_node ( & mut r) ;
991
+ match r. upgrade ( ) {
992
+ None => return item_tree,
993
+ Some ( x) => item_tree = x. item_tree ( ) . clone ( ) ,
994
+ }
995
+ } ;
996
+ let parent_root_item_tree = root_of ( parent_item. item_tree ( ) . clone ( ) ) ;
997
+ let ( parent_window_adapter, position) = if let Some ( parent_popup) = self
998
+ . active_popups
999
+ . borrow ( )
1000
+ . iter ( )
1001
+ . find ( |p| ItemTreeRc :: ptr_eq ( & p. component , & parent_root_item_tree) )
1002
+ {
1003
+ match & parent_popup. location {
1004
+ PopupWindowLocation :: TopLevel ( wa) => ( wa. clone ( ) , position) ,
1005
+ PopupWindowLocation :: ChildWindow ( offset) => {
1006
+ ( self . window_adapter ( ) , position + offset. to_vector ( ) )
1007
+ }
1008
+ }
1009
+ } else {
1010
+ ( self . window_adapter ( ) , position)
1011
+ } ;
1012
+
986
1013
let popup_component = ItemTreeRc :: borrow_pin ( popup_componentrc) ;
987
1014
let popup_root = popup_component. as_ref ( ) . get_item_ref ( 0 ) ;
988
1015
@@ -1019,8 +1046,7 @@ impl WindowInner {
1019
1046
height_property. set ( size. height_length ( ) ) ;
1020
1047
} ;
1021
1048
1022
- let location = match self
1023
- . window_adapter ( )
1049
+ let location = match parent_window_adapter
1024
1050
. internal ( crate :: InternalToken )
1025
1051
. and_then ( |x| x. create_popup ( LogicalRect :: new ( position, size) ) )
1026
1052
{
@@ -1042,17 +1068,17 @@ impl WindowInner {
1042
1068
}
1043
1069
} ;
1044
1070
1045
- self . active_popup . replace ( Some ( PopupWindow {
1071
+ self . active_popups . borrow_mut ( ) . push ( PopupWindow {
1046
1072
location,
1047
1073
component : popup_componentrc. clone ( ) ,
1048
1074
close_policy,
1049
- } ) ) ;
1075
+ } ) ;
1050
1076
}
1051
1077
1052
1078
/// Removes any active popup.
1053
1079
/// TODO: this function should take a component ref as parameter, to close a specific popup - i.e. when popup menus create a hierarchy of popups.
1054
1080
pub fn close_popup ( & self ) {
1055
- if let Some ( current_popup) = self . active_popup . replace ( None ) {
1081
+ if let Some ( current_popup) = self . active_popups . borrow_mut ( ) . pop ( ) {
1056
1082
match current_popup. location {
1057
1083
PopupWindowLocation :: ChildWindow ( offset) => {
1058
1084
// Refresh the area that was previously covered by the popup.
@@ -1077,9 +1103,9 @@ impl WindowInner {
1077
1103
1078
1104
/// Returns the close policy of the active popup. PopupClosePolicy::NoAutoClose if there is no active popup.
1079
1105
pub fn close_policy ( & self ) -> PopupClosePolicy {
1080
- self . active_popup
1106
+ self . active_popups
1081
1107
. borrow ( )
1082
- . as_ref ( )
1108
+ . last ( )
1083
1109
. map_or ( PopupClosePolicy :: NoAutoClose , |popup| popup. close_policy )
1084
1110
}
1085
1111
0 commit comments