@@ -10,7 +10,7 @@ use re_types::blueprint::components::Visible;
10
10
use re_ui:: { drag_and_drop:: DropTarget , list_item, ContextExt as _, DesignTokens , UiExt as _} ;
11
11
use re_viewer_context:: {
12
12
contents_name_style, icon_for_container_kind, CollapseScope , Contents , DataResultNodeOrPath ,
13
- SystemCommandSender ,
13
+ DragAndDropPayload , SystemCommandSender ,
14
14
} ;
15
15
use re_viewer_context:: {
16
16
ContainerId , DataQueryResult , DataResultNode , HoverHighlight , Item , ViewId , ViewerContext ,
@@ -168,7 +168,7 @@ impl BlueprintTree {
168
168
let item_response = ui
169
169
. list_item ( )
170
170
. selected ( ctx. selection ( ) . contains_item ( & item) )
171
- . draggable ( false )
171
+ . draggable ( true ) // allowed for consistency but results in an invalid drag
172
172
. drop_target_style ( self . is_candidate_drop_parent_container ( & container_id) )
173
173
. show_flat (
174
174
ui,
@@ -189,7 +189,7 @@ impl BlueprintTree {
189
189
SelectionUpdateBehavior :: UseSelection ,
190
190
) ;
191
191
self . scroll_to_me_if_needed ( ui, & item, & item_response) ;
192
- ctx. select_hovered_on_click ( & item_response, item) ;
192
+ ctx. handle_select_hover_drag_interactions ( & item_response, item, true ) ;
193
193
194
194
self . handle_root_container_drag_and_drop_interaction (
195
195
viewport,
@@ -270,12 +270,11 @@ impl BlueprintTree {
270
270
SelectionUpdateBehavior :: UseSelection ,
271
271
) ;
272
272
self . scroll_to_me_if_needed ( ui, & item, & response) ;
273
- ctx. select_hovered_on_click ( & response, item) ;
273
+ ctx. handle_select_hover_drag_interactions ( & response, item, true ) ;
274
274
275
275
viewport. set_content_visibility ( ctx, & content, visible) ;
276
276
277
277
self . handle_drag_and_drop_interaction (
278
- ctx,
279
278
viewport,
280
279
ui,
281
280
content,
@@ -406,13 +405,12 @@ impl BlueprintTree {
406
405
SelectionUpdateBehavior :: UseSelection ,
407
406
) ;
408
407
self . scroll_to_me_if_needed ( ui, & item, & response) ;
409
- ctx. select_hovered_on_click ( & response, item) ;
408
+ ctx. handle_select_hover_drag_interactions ( & response, item, true ) ;
410
409
411
410
let content = Contents :: View ( * view_id) ;
412
411
413
412
viewport. set_content_visibility ( ctx, & content, visible) ;
414
413
self . handle_drag_and_drop_interaction (
415
- ctx,
416
414
viewport,
417
415
ui,
418
416
content,
@@ -494,6 +492,7 @@ impl BlueprintTree {
494
492
495
493
let list_item = ui
496
494
. list_item ( )
495
+ . draggable ( true )
497
496
. selected ( is_selected)
498
497
. force_hovered ( is_item_hovered) ;
499
498
@@ -596,7 +595,7 @@ impl BlueprintTree {
596
595
SelectionUpdateBehavior :: UseSelection ,
597
596
) ;
598
597
self . scroll_to_me_if_needed ( ui, & item, & response) ;
599
- ctx. select_hovered_on_click ( & response, item) ;
598
+ ctx. handle_select_hover_drag_interactions ( & response, item, true ) ;
600
599
}
601
600
602
601
/// Add a button to trigger the addition of a new view or container.
@@ -636,16 +635,21 @@ impl BlueprintTree {
636
635
response : & egui:: Response ,
637
636
) {
638
637
//
639
- // check if a drag is in progress and set the cursor accordingly
638
+ // check if a drag with acceptable content is in progress
640
639
//
641
640
642
- let Some ( dragged_item_id ) = egui:: DragAndDrop :: payload ( ui. ctx ( ) ) . map ( |payload| * payload )
641
+ let Some ( dragged_payload ) = egui:: DragAndDrop :: payload :: < DragAndDropPayload > ( ui. ctx ( ) )
643
642
else {
644
- // nothing is being dragged, so nothing to do
645
643
return ;
646
644
} ;
647
645
648
- ui. ctx ( ) . set_cursor_icon ( egui:: CursorIcon :: Grabbing ) ;
646
+ let DragAndDropPayload :: Contents {
647
+ contents : dragged_contents,
648
+ } = dragged_payload. as_ref ( )
649
+ else {
650
+ // nothing we care about is being dragged
651
+ return ;
652
+ } ;
649
653
650
654
//
651
655
// find the drop target
@@ -668,39 +672,34 @@ impl BlueprintTree {
668
672
) ;
669
673
670
674
if let Some ( drop_target) = drop_target {
671
- self . handle_drop_target ( viewport, ui, dragged_item_id , & drop_target) ;
675
+ self . handle_contents_drop_target ( viewport, ui, dragged_contents , & drop_target) ;
672
676
}
673
677
}
674
678
675
679
fn handle_drag_and_drop_interaction (
676
680
& mut self ,
677
- ctx : & ViewerContext < ' _ > ,
678
681
viewport : & ViewportBlueprint ,
679
682
ui : & egui:: Ui ,
680
683
contents : Contents ,
681
684
response : & egui:: Response ,
682
685
body_response : Option < & egui:: Response > ,
683
686
) {
684
687
//
685
- // initiate drag and force single-selection
686
- //
687
-
688
- if response. drag_started ( ) {
689
- ctx. selection_state ( ) . set_selection ( contents. as_item ( ) ) ;
690
- egui:: DragAndDrop :: set_payload ( ui. ctx ( ) , contents) ;
691
- }
692
-
693
- //
694
- // check if a drag is in progress and set the cursor accordingly
688
+ // check if a drag with acceptable content is in progress
695
689
//
696
690
697
- let Some ( dragged_item_id ) = egui:: DragAndDrop :: payload ( ui. ctx ( ) ) . map ( |payload| * payload )
691
+ let Some ( dragged_payload ) = egui:: DragAndDrop :: payload :: < DragAndDropPayload > ( ui. ctx ( ) )
698
692
else {
699
- // nothing is being dragged, so nothing to do
700
693
return ;
701
694
} ;
702
695
703
- ui. ctx ( ) . set_cursor_icon ( egui:: CursorIcon :: Grabbing ) ;
696
+ let DragAndDropPayload :: Contents {
697
+ contents : dragged_contents,
698
+ } = dragged_payload. as_ref ( )
699
+ else {
700
+ // nothing we care about is being dragged
701
+ return ;
702
+ } ;
704
703
705
704
//
706
705
// find our parent, our position within parent, and the previous container (if any)
@@ -752,7 +751,7 @@ impl BlueprintTree {
752
751
) ;
753
752
754
753
if let Some ( drop_target) = drop_target {
755
- self . handle_drop_target ( viewport, ui, dragged_item_id , & drop_target) ;
754
+ self . handle_contents_drop_target ( viewport, ui, dragged_contents , & drop_target) ;
756
755
}
757
756
}
758
757
@@ -763,16 +762,21 @@ impl BlueprintTree {
763
762
empty_space : egui:: Rect ,
764
763
) {
765
764
//
766
- // check if a drag is in progress and set the cursor accordingly
765
+ // check if a drag with acceptable content is in progress
767
766
//
768
767
769
- let Some ( dragged_item_id ) = egui:: DragAndDrop :: payload ( ui. ctx ( ) ) . map ( |payload| * payload )
768
+ let Some ( dragged_payload ) = egui:: DragAndDrop :: payload :: < DragAndDropPayload > ( ui. ctx ( ) )
770
769
else {
771
- // nothing is being dragged, so nothing to do
772
770
return ;
773
771
} ;
774
772
775
- ui. ctx ( ) . set_cursor_icon ( egui:: CursorIcon :: Grabbing ) ;
773
+ let DragAndDropPayload :: Contents {
774
+ contents : dragged_contents,
775
+ } = dragged_payload. as_ref ( )
776
+ else {
777
+ // nothing we care about is being dragged
778
+ return ;
779
+ } ;
776
780
777
781
//
778
782
// prepare a drop target corresponding to "insert last in root container"
@@ -788,25 +792,31 @@ impl BlueprintTree {
788
792
usize:: MAX ,
789
793
) ;
790
794
791
- self . handle_drop_target ( viewport, ui, dragged_item_id , & drop_target) ;
795
+ self . handle_contents_drop_target ( viewport, ui, dragged_contents , & drop_target) ;
792
796
}
793
797
}
794
798
795
- fn handle_drop_target (
799
+ fn handle_contents_drop_target (
796
800
& mut self ,
797
801
viewport : & ViewportBlueprint ,
798
802
ui : & Ui ,
799
- dragged_item_id : Contents ,
803
+ dragged_contents : & [ Contents ] ,
800
804
drop_target : & DropTarget < Contents > ,
801
805
) {
802
- // We cannot allow the target location to be "inside" the dragged item, because that would amount moving
803
- // myself inside of me.
804
- if let Contents :: Container ( dragged_container_id) = & dragged_item_id {
805
- if viewport
806
- . is_contents_in_container ( & drop_target. target_parent_id , dragged_container_id)
807
- {
808
- return ;
806
+ // We cannot allow the target location to be "inside" any of the dragged items, because that
807
+ // would amount to moving myself inside of me.
808
+ let parent_contains_dragged_content = |content : & Contents | {
809
+ if let Contents :: Container ( dragged_container_id) = content {
810
+ if viewport
811
+ . is_contents_in_container ( & drop_target. target_parent_id , dragged_container_id)
812
+ {
813
+ return true ;
814
+ }
809
815
}
816
+ false
817
+ } ;
818
+ if dragged_contents. iter ( ) . any ( parent_contains_dragged_content) {
819
+ return ;
810
820
}
811
821
812
822
ui. painter ( ) . hline (
@@ -822,7 +832,7 @@ impl BlueprintTree {
822
832
823
833
if ui. input ( |i| i. pointer . any_released ( ) ) {
824
834
viewport. move_contents (
825
- dragged_item_id ,
835
+ dragged_contents . to_vec ( ) ,
826
836
target_container_id,
827
837
drop_target. target_position_index ,
828
838
) ;
0 commit comments