1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 11:45:06 +00:00

LibGUI+WindowServer: Start fleshing out drag&drop functionality

This patch enables basic drag&drop between applications.
You initiate a drag by creating a GDragOperation object and calling
exec() on it. This creates a nested event loop in the calling program
that only returns once the drag operation has ended.

On the receiving side, you get a call to GWidget::drop_event() with
a GDropEvent containing information about the dropped data.

The only data passed right now is a piece of text that's also used
to visually indicate that a drag is happening (by showing the text in
a little box that follows the mouse cursor around.)

There are things to fix here, but we're off to a nice start. :^)
This commit is contained in:
Andreas Kling 2019-12-08 16:50:23 +01:00
parent e09a02ad3f
commit a7f414bba7
19 changed files with 318 additions and 3 deletions

View file

@ -1,4 +1,6 @@
#include <AK/StringBuilder.h>
#include <Kernel/KeyCode.h>
#include <LibGUI/GDragOperation.h>
#include <LibGUI/GItemView.h>
#include <LibGUI/GModel.h>
#include <LibGUI/GPainter.h>
@ -83,6 +85,7 @@ void GItemView::mousedown_event(GMouseEvent& event)
int item_index = item_at_event_position(event.position());
if (event.button() == GMouseButton::Left) {
m_left_mousedown_position = event.position();
if (item_index == -1) {
selection().clear();
} else {
@ -97,6 +100,45 @@ void GItemView::mousedown_event(GMouseEvent& event)
GAbstractView::mousedown_event(event);
}
void GItemView::mousemove_event(GMouseEvent& event)
{
if (!model())
return GAbstractView::mousemove_event(event);
if (event.buttons() & GMouseButton::Left && !selection().is_empty()) {
auto diff = event.position() - m_left_mousedown_position;
auto distance_travelled_squared = diff.x() * diff.x() + diff.y() * diff.y();
constexpr int drag_distance_threshold = 5;
if (distance_travelled_squared > (drag_distance_threshold)) {
dbg() << "Initiate drag!";
auto drag_operation = GDragOperation::construct();
StringBuilder builder;
selection().for_each_index([&](auto& index) {
auto data = model()->data(index);
builder.append(data.to_string());
builder.append(" ");
});
drag_operation->set_text(builder.to_string());
auto outcome = drag_operation->exec();
switch (outcome) {
case GDragOperation::Outcome::Accepted:
dbg() << "Drag was accepted!";
break;
case GDragOperation::Outcome::Cancelled:
dbg() << "Drag was cancelled!";
break;
default:
ASSERT_NOT_REACHED();
break;
}
}
}
GAbstractView::mousemove_event(event);
}
void GItemView::context_menu_event(GContextMenuEvent& event)
{
if (!model())