lucasmerlin / hello_egui

A collection of useful crates for egui
https://lucasmerlin.github.io/hello_egui/
MIT License
272 stars 24 forks source link

If the dnd(..).show function chooses to not add a element, the result is a weird gap between list items #17

Closed lambdadeltakay closed 7 months ago

lambdadeltakay commented 7 months ago

I implemented a simple filter search which just doesn't add elements if they don't match and the result is a strange gap between elements.

It seems to increase if the gap represents more elements.

image

lucasmerlin commented 7 months ago

I guess the problem is that it's still adding the item spacing for the filtered items.

A simple fix would be to set the item spacing to 0 before you call dnd:

    ui.spacing_mut().item_spacing.y = 0.0;

And then optionally do the spacing for each item within the list.

Alternatively you could create a filtered vec each frame, that stores the index the item had in the original frame, and then afterwards call shift_vec with the original index. Something like this:

                    let mut filtered = items
                        .iter_mut()
                        // We enumerate so we can get the original index
                        .enumerate()
                        .filter(|(_, item)| item.number.to_string().contains(&filter))
                        .collect::<Vec<_>>();

                    let response = dnd(ui, "dnd").show(
                        filtered.iter_mut(),
                        |ui, (original_idx, item), handle, _dragging| {
                            ui.horizontal(|ui| {
                                let clicked = handle
                                    .sense(Sense::click())
                                    .ui(ui, |ui| {
                                        ui.label("grab");
                                    })
                                    .clicked();
                                if clicked {
                                    println!("clicked {}", item.number);
                                }
                                ui.label(&item.number.to_string());
                            });
                        },
                    );

                    if let Some(update) = response.final_update() {
                        // Get the original indices of the items for the update
                        shift_vec(filtered[update.from].0, filtered[update.to].0, &mut items);
                    }

This is not very efficient since you create a new vec each frame, but a bit cleaner since there are no invisible items where the dnd might want to try to fit the item between.

Let me know if one of the approaches works for you!

lucasmerlin commented 7 months ago

I've added a example showcasing two ways to filter the list. I think in theory I could also add a filter method to the dnd struct but I think it's better if the filtering is handled by the application. I'll close issue for now, let me know if it's still not working for you!

lambdadeltakay commented 7 months ago

Filtering before the DND call worked perfectly as long as I manually implemented the shifting logic

lambdadeltakay commented 7 months ago

Thank you