1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use eframe::epaint::Margin;
use eframe::{egui, NativeOptions};
use egui::{CentralPanel, Frame, Id, ScrollArea};
use egui_dnd::dnd;
use egui_virtual_list::VirtualList;
use rand::prelude::StdRng;
use rand::{Rng, SeedableRng};
pub fn main() -> eframe::Result<()> {
let mut items: Vec<_> = (0..100_000).collect();
let mut virtual_list = VirtualList::new();
eframe::run_ui_native(
"DnD Virtual List Example",
NativeOptions::default(),
move |ui, _frame| {
CentralPanel::default().show_inside(ui, |ui| {
ScrollArea::vertical().show(ui, |ui| {
let response = dnd(ui, "dnd").show_custom(|ui, iter| {
virtual_list.ui_custom_layout(ui, items.len(), |ui, start_index| {
let item = &items[start_index];
iter.next(
ui,
Id::new(*item), // assumes that each item is a unique hash
start_index,
true,
|ui, dnd_item| {
dnd_item.ui(ui, |ui, handle, _item_state| {
draw_item(ui, handle, *item);
})
},
);
1
});
});
// Use update_vec() (or update your data structure yourself on every frame) for
// smooth dragging and dropping, as updating based on response.final_update()
// after dragging for a long time results in the dragged item failing to render
// and the scroll area jumping slightly upon release
response.update_vec(&mut items);
});
});
},
)
}
fn draw_item(ui: &mut egui::Ui, handle: egui_dnd::Handle, item: i32) {
// For the sake of the example we generate a random height based on the item index
// but if your row height e.g. depends on some text with varying rows this would also work.
let mut rng = StdRng::seed_from_u64(item as u64);
let height = rng.random_range(0..=100);
Frame::canvas(ui.style())
.inner_margin(Margin::symmetric(16, (8 + height / 2) as i8))
.show(ui, |ui| {
ui.set_width(ui.available_width());
handle.ui(ui, |ui| {
ui.label(format!("Item {item}"));
});
});
}