A small library which provides a custom widget and operation to make drag and drop easier to implement in iced
- For ease of use, make sure to enable the
helpersfeature which requiresiced_runtime
- If you can't enable this feature, the process is very similar. The only difference is that you'd have to implement the helper functions
zones_on_pointandfind_zonesinlib.rsyourself. - These functions convert the
find_zonesoperation into an icedTask
- To start implementing drag and drop functionality, first define two messages with the parameter specifications below:
- a drop message with parameters:
iced::Point,iced::Rectangle - a handler message with parameter:
Vec<(iced::advanced::widget::Id, iced::Rectangle)>
enum Message {
Drop(iced::Point, iced::Rectangle),
HandleZones(Vec<(iced::advanced::widget::Id, iced::Rectangle)>)
}- The
Dropmessage will be published when the left mouse button is released if the widget was being dragged (left click + mouse movement). This message provides the mouse position and layout boundaries of the droppable at the release point. - The
HandleZonesmessage will be published on completion of theiced_drop::zones_on_pointoperation which finds the drop zones under the mouse position. It provides the Id and bounds for each drop zone under the given mouse position. - The general idea is that one can use the arguments of
Dropto feed intozones_on_pointto get aHandleZonesmessage which gives any information necessary to handle general drag-drop implementation.
- Next, create a droppable in the view method and assign the on_drop message. The droppable function takes an
impl Into<Element>object, so it's easy to make a droppable from any iced widget.
iced_drop::droppable("Drop me!").on_drop(Message::Drop);- Next, create a "drop zone." A drop zone is any widget that operates like a container and has some assigned Id. It's important that the widget is assigned some Id or it won't be recognized as a drop zone.
iced::widget::container("Drop zone")
.id(iced::widget::container::Id::new("drop_zone"));- Finally, handle the update logic using the
iced_drop::zones_on_pointoperation and your drop and handler messages
match message {
Message::Drop(cursor_pos, _) => {
return iced_drop::zones_on_point(
Message::HandleZonesFound,
point,
None,
None,
);
}
Message::HandleZones(zones) => {
println!("{:?}", zones)
}
}In this example, we only defined one zone, so the zones vector will either be empty if the droppable was not dropped on the zone, or it will contain the drop_zone created on step 3
There are two examples: color, todo.
The color example is a very basic drag/drop showcase where the user can drag colors into zones and change the zone's color. I would start here.
To run this examples: cargo run -p color
The todo example is a basic todo board application similar to Trello. This is a MUCH more complex example as it handles custom highlighting and nested droppable, but it just shows you can make some pretty cool things with iced.
To run this example try: cargo run -p todo
Note: the todo example might also be a good example on how one can use operations. Check examples/todo/src/operation.rs. I didn't find any other examples of this in the iced repo except for the built-in focus operations.
Right now it's a little annoying having to work with iced's Id type. At some point, I will work on a drop_zone widget that can take some generic clonable type as an id, and I will create a separate find_zones operation that will return a list of this custom Id. This should make it easier to determine which drop zones were found.
Iced is still evolving, and part of the fun is seeing how others use it. If iced_drop shows up anywhere in your work, I’d love to link it here so others can explore, learn, and connect.