Hey all!
I’m confused and I maybe don’t see the forest because of the trees.
How is DragAndDrop control meant to be used? Let’s say I want to have two objects, one is a “draggable” that can be dragged around. The other is a “droppable” that can receive the draggable object. Does this mean that:
- I have a DragAndDropControl with a DragAndDropListener that return a Draggable from onDragDetected.
- I have a DragAndDropControl with a DragAndDopListener that only listens to the drop and also sets the DragStatus in drag over method?
That’s it, right? I’m trying to implement it but it just doesn’t work properly for me and I got stuck at the “how to make object draggable” part. Either the draggable gets events reported on itself, or I get the following error message constantly:
2023-10-15 23:09:22 WARN DragAndDropControl:221 - Received event for different target, this spatial:com.simsilica.lemur.Panel[elementId=ElementId[panel]], target:com.simsilica.lemur.Panel[elementId=ElementId[panel]], capture=com.simsilica.lemur.Panel[elementId=ElementId[panel]]
Or the third option is that my draggable doesn’t move at all.
What am I doing wrong?
Please see my simple reproduction:
public class LemurDragAndDropTest extends SimpleApplication {
// [....]
@Override
public void simpleInitApp() {
super.simpleInitApp();
GuiGlobals.initialize(this);
Panel draggable = new Panel();
draggable.setName("draggable");
draggable.setBackground(new QuadBackgroundComponent(ColorRGBA.Red));
draggable.setSize(new Vector3f(100f, 100f, 10f));
draggable.setPreferredSize(new Vector3f(100f, 100f, 10f));
draggable.move(600f, 350f, 0f);
guiNode.attachChild(draggable);
draggable.addControl(new DragAndDropControl(new DragAndDropListener() {
@Override
public Draggable onDragDetected(DragEvent event) {
System.out.println("SOURCE DRAG DETECTED");
Spatial item = event.getSession().getDragSource();
event.getSession().set(DragSession.ITEM, item);
event.getSession().set("parent", item.getParent());
Spatial clone = item.clone();
clone.setLocalRotation(item.getWorldRotation());
clone.setLocalTranslation(item.getWorldTranslation());
guiNode.attachChild(clone);
// OPTION 1:
// Uncommenting this causes the red draggable to move a few pixels but after that it
// just stays in one place.
// item.removeFromParent();
// OPTION 2:
// Tried to hide object by moving it far away but it causes draggable reporting onDragOver on itself:
// SOURCE DRAG ENTER
// SOURCE DRAG OVER
// SOURCE DRAG EXIT
// And also constantly throws this error:
// 2023-10-15 23:20:58 WARN DragAndDropControl:221 - Received event for different target, this spatial:com.simsilica.lemur.Panel[elementId=ElementId[panel]], target:com.simsilica.lemur.Panel[elementId=ElementId[panel]], capture=com.simsilica.lemur.Panel[elementId=ElementId[panel]]
// item.move(3000f, 3000f, 20f);
// OPTION 3:
// Comment both item.move and item.removeFromParent() and I will get the same results as Option 2: self
// event reports and "Received event for different target..." error.
return new DefaultDraggable(event.getLocation(), clone, clone.getWorldTranslation(),
Vector3f.UNIT_X, Vector3f.UNIT_Y);
}
@Override
public void onDragEnter(DragEvent event) {
System.out.println("SOURCE DRAG ENTER");
}
@Override
public void onDragExit(DragEvent event) {
System.out.println("SOURCE DRAG EXIT");
}
@Override
public void onDragOver(DragEvent event) {
System.out.println("SOURCE DRAG OVER");
}
@Override
public void onDrop(DragEvent event) {
System.out.println("SOURCE DRAG DROP");
}
@Override
public void onDragDone(DragEvent event) {
System.out.println("SOURCE DRAG DONE");
Spatial item = event.getSession().get(DragSession.ITEM, null);
Node parent = event.getSession().get("parent", null);
parent.attachChild(item);
// Ignore this please.
// I know this is not the proper way, I just quickly slapped it near the cursor where I drop it.
// Vector2f location = event.getSession().getDraggable().getLocation();
// item.setLocalTranslation(location.x, location.y, 20f);
}
}));
Panel droppable = new Panel();
droppable.setName("droppable");
droppable.setBackground(new QuadBackgroundComponent(ColorRGBA.DarkGray));
droppable.setSize(new Vector3f(200f, 200f, 9f));
droppable.setPreferredSize(new Vector3f(200f, 200f, 9f));
droppable.move(100f, 400f, 0f);
guiNode.attachChild(droppable);
droppable.addControl(new DragAndDropControl(new DragAndDropListener() {
@Override
public Draggable onDragDetected(DragEvent event) {
System.out.println("TARGET DRAG ENTER");
return null;
}
@Override
public void onDragEnter(DragEvent event) {
System.out.println("TARGET DRAG ENTER");
}
@Override
public void onDragExit(DragEvent event) {
System.out.println("TARGET DRAG EXIT");
}
@Override
public void onDragOver(DragEvent event) {
System.out.println("TARGET DRAG OVER");
}
@Override
public void onDrop(DragEvent event) {
System.out.println("TARGET DRAG DROP");
}
@Override
public void onDragDone(DragEvent event) {
System.out.println("TARGET DRAG DONE");
}
}));
}
}