1
- use std:: collections:: { HashMap , HashSet } ;
1
+ //! This demo is a stripped-down version of the drag-and-drop implementation in the
2
+ //! [rerun viewer](https://github.com/rerun-io/rerun).
3
+
4
+ use std:: collections:: HashMap ;
2
5
3
6
use eframe:: { egui, egui:: NumExt as _} ;
4
7
@@ -30,20 +33,14 @@ enum Item {
30
33
31
34
#[ derive( Debug ) ]
32
35
enum Command {
33
- /// Set the selection to the given item.
34
- SetSelection ( ItemId ) ,
35
-
36
- /// Toggle the selected state of the given item.
37
- ToggleSelected ( ItemId ) ,
38
-
39
36
/// Move the currently dragged item to the given container and position.
40
37
MoveItem {
41
38
moved_item_id : ItemId ,
42
39
target_container_id : ItemId ,
43
40
target_position_index : usize ,
44
41
} ,
45
42
46
- /// Specify the currently identifed target container to be highlighted.
43
+ /// Specify the currently identified target container to be highlighted.
47
44
HighlightTargetContainer ( ItemId ) ,
48
45
}
49
46
@@ -54,9 +51,6 @@ pub struct HierarchicalDragAndDrop {
54
51
/// Id of the root item (not displayed in the UI)
55
52
root_id : ItemId ,
56
53
57
- /// Set of all selected items
58
- selected_items : HashSet < ItemId > ,
59
-
60
54
/// If a drag is ongoing, this is the id of the destination container (if any was identified)
61
55
///
62
56
/// This is used to highlight the target container.
@@ -79,7 +73,6 @@ impl Default for HierarchicalDragAndDrop {
79
73
let mut res = Self {
80
74
items : std:: iter:: once ( ( root_id, root_item) ) . collect ( ) ,
81
75
root_id,
82
- selected_items : HashSet :: new ( ) ,
83
76
target_container : None ,
84
77
command_receiver,
85
78
command_sender,
@@ -227,10 +220,6 @@ impl HierarchicalDragAndDrop {
227
220
}
228
221
}
229
222
230
- fn selected ( & self , id : ItemId ) -> bool {
231
- self . selected_items . contains ( & id)
232
- }
233
-
234
223
fn send_command ( & self , command : Command ) {
235
224
// The only way this can fail is if the receiver has been dropped.
236
225
self . command_sender . send ( command) . ok ( ) ;
@@ -252,17 +241,6 @@ impl HierarchicalDragAndDrop {
252
241
while let Ok ( command) = self . command_receiver . try_recv ( ) {
253
242
//println!("Received command: {command:?}");
254
243
match command {
255
- Command :: SetSelection ( item_id) => {
256
- self . selected_items . clear ( ) ;
257
- self . selected_items . insert ( item_id) ;
258
- }
259
- Command :: ToggleSelected ( item_id) => {
260
- if self . selected_items . contains ( & item_id) {
261
- self . selected_items . remove ( & item_id) ;
262
- } else {
263
- self . selected_items . insert ( item_id) ;
264
- }
265
- }
266
244
Command :: MoveItem {
267
245
moved_item_id,
268
246
target_container_id,
@@ -276,7 +254,7 @@ impl HierarchicalDragAndDrop {
276
254
}
277
255
278
256
fn container_ui ( & self , ui : & mut egui:: Ui , item_id : ItemId , children : & Vec < ItemId > ) {
279
- let ( _ , header_resp , body_resp) =
257
+ let ( response , head_response , body_resp) =
280
258
egui:: collapsing_header:: CollapsingState :: load_with_default_open (
281
259
ui. ctx ( ) ,
282
260
item_id. into ( ) ,
@@ -293,11 +271,11 @@ impl HierarchicalDragAndDrop {
293
271
self . container_children_ui ( ui, children) ;
294
272
} ) ;
295
273
296
- self . handle_interaction (
274
+ self . handle_drag_and_drop_interaction (
297
275
ui,
298
276
item_id,
299
277
true ,
300
- & header_resp . inner ,
278
+ & head_response . inner . union ( response ) ,
301
279
body_resp. as_ref ( ) . map ( |r| & r. response ) ,
302
280
) ;
303
281
}
@@ -322,16 +300,11 @@ impl HierarchicalDragAndDrop {
322
300
. selectable ( false )
323
301
. sense ( egui:: Sense :: drag ( ) ) ,
324
302
) ;
325
- // let response = re_ui
326
- // .list_item(label)
327
- // .selected(self.selected(item_id))
328
- // .draggable(true)
329
- // .show(ui);
330
303
331
- self . handle_interaction ( ui, item_id, false , & response, None ) ;
304
+ self . handle_drag_and_drop_interaction ( ui, item_id, false , & response, None ) ;
332
305
}
333
306
334
- fn handle_interaction (
307
+ fn handle_drag_and_drop_interaction (
335
308
& self ,
336
309
ui : & egui:: Ui ,
337
310
item_id : ItemId ,
@@ -340,31 +313,15 @@ impl HierarchicalDragAndDrop {
340
313
body_response : Option < & egui:: Response > ,
341
314
) {
342
315
//
343
- // basic selection management
344
- //
345
-
346
- if response. clicked ( ) {
347
- if ui. input ( |i| i. modifiers . command ) {
348
- self . send_command ( Command :: ToggleSelected ( item_id) ) ;
349
- } else {
350
- self . send_command ( Command :: SetSelection ( item_id) ) ;
351
- }
352
- }
353
-
354
- //
355
- // handle drag
316
+ // handle start of drag
356
317
//
357
318
358
319
if response. drag_started ( ) {
359
- // Here, we support dragging a single item at a time, so we set the selection to the dragged item
360
- // if/when we're dragging it proper.
361
- self . send_command ( Command :: SetSelection ( item_id) ) ;
362
-
363
320
egui:: DragAndDrop :: set_payload ( ui. ctx ( ) , item_id) ;
364
321
}
365
322
366
323
//
367
- // handle drop
324
+ // handle candidate drop
368
325
//
369
326
370
327
// find the item being dragged
@@ -397,11 +354,28 @@ impl HierarchicalDragAndDrop {
397
354
previous_container_id,
398
355
} ;
399
356
357
+ //
358
+ // compute the drag target areas based on the item and body responses
359
+ //
360
+
361
+ // adjust the drop target to account for the spacing between items
362
+ let item_rect = response
363
+ . rect
364
+ . expand2 ( egui:: Vec2 :: new ( 0.0 , ui. spacing ( ) . item_spacing . y / 2.0 ) ) ;
365
+ let body_rect = body_response. map ( |r| {
366
+ r. rect
367
+ . expand2 ( egui:: Vec2 :: new ( 0.0 , ui. spacing ( ) . item_spacing . y ) )
368
+ } ) ;
369
+
370
+ //
371
+ // find the candidate drop target
372
+ //
373
+
400
374
let drop_target = crate :: drag_and_drop:: find_drop_target (
401
375
ui,
402
376
& item_desc,
403
- response . rect ,
404
- body_response . map ( |r| r . rect ) ,
377
+ item_rect ,
378
+ body_rect ,
405
379
response. rect . height ( ) ,
406
380
) ;
407
381
@@ -413,10 +387,13 @@ impl HierarchicalDragAndDrop {
413
387
return ;
414
388
}
415
389
390
+ // extend the cursor to the right of the enclosing container
391
+ let mut span_x = drop_target. indicator_span_x ;
392
+ span_x. max = ui. cursor ( ) . right ( ) ;
393
+
416
394
ui. painter ( ) . hline (
417
- drop_target . indicator_span_x ,
395
+ span_x ,
418
396
drop_target. indicator_position_y ,
419
- //TODO: use style
420
397
( 2.0 , egui:: Color32 :: BLACK ) ,
421
398
) ;
422
399
0 commit comments