How to get this drag and drop working

I am trying to implement the Lemur Drag and Drop demo code into my project to learn how to implement Drag & Drop. But I can not even get it to work just out of the box.

When I implement it as an appState, it does not

        dndInputs=new DragAndDropDemoState(app);
        world.app.getStateManager().attach(dndInputs);
        world.app.getGuiNode().attachChild(dndInputs.getRoot());

All I see are two tiny rectangles in the lower left corner. I found out that they seem to do something, randomly clicking and dragging sometimes gives an error. But it would help if I could style the boxes.

I tried adding styles in my stylesheet:

selector("container1","container","ungamunga"){
    background = windowBG.clone()
    background.setColor(colorBG)  
    PreferredSize = new com.jme3.math.Vector3f(180, 200, 1)
}
selector("container2","container","ungamunga"){
    background = windowBG.clone()
    background.setColor(colorBG)  
    PreferredSize = new com.jme3.math.Vector3f(180, 200, 1)
}

And I tried calling the setSize() method of ContainerNode.

But the boxes do not get any bigger.

If you are running the drag and drop demo from the Lemur demos, there might be some additional setup in the main app itself. Certainly it will be using glass style so I don’t know if that will cause issue.

99.9% sure you cannot set preferred size through a style. It’s something you set directly on the components when you create them.

I recommend that you fork the lemur demo and mess with that code directly to learn and then port the ideas over to your code once you understand what’s going on. I think otherwise you will run into a lot “problems that don’t really matter” trying to get that demo state to run outside of the demo app. (I mean, I’m sure it will be a learning experience but it will be the long way to get where you want to go, probably.)

Being the irresponsible hacker that I am, I did already try to hack my way into the code itself.

First my setup: I just copied the DragAndDropDemoState.java into my own project - and just a minute ago renamed it DragAndDropSystem. My aim is not only fork it, but also make it reusable - at least within my own project.

I tried

container1.setLocalScale(10, 10, 1);

That works as long as I scale x and y equaly.

I also tried changing the size of the geometry:

wire = new WireBox(180, 200, 1);

That did nothing at all.

The setSize() method of ContainerNode does not help either.

However, stackcontrol does seem to grow the container when it gets more items. If I can modify it to work in rows than I am getting close to what I need. That does not seem too daunting.

Another thing I need to figure out is how to add icons to the items…

There is one thing that I am currently wrestling with: when dragging, the item disappears only to reappear when dropped.

I noticed that it is removed from it’s parent in the onDragDetected event, but I don’t see it being attached to any other node for the duration of the dragging operation. I tried tagging it to the dndRoot, the GuiNode and the RootNode, but that did not make it visible either.

Lemur will try to lay things out based on their preferred size. Setting the preferred size is the appropriate way to size a GUI element… you just can’t do it in styling. When the element is added to the guiNode or to a layout, it’s preferred size is used to set its size.

But this does not happen in the demo, right?

I have not tried the demo itself. Maybe I should.

But I do’nt think I have seen it before I started hacking DnDDemoState. So my first guess is that there is a difference between the demo and my code. Could it be styling?

My “random stabs in the dark” knives are all dull. So let’s wait until you see it run correctly before we start finding reasons why things might be different.

In the demo the dndRoot - the node that parents the dnd system - is attached to the root node. In this scenario everything is 3D and when dragging the items are visible.

When I attach dndRoot to the gui node in the clean demo code, the items are no longer visible when dragging. This is the scenario I also use in my project.

Did it start in the regular scene root and then get attached to the guiNode?

Whatever the case, it sounds like it just isn’t where you expect it. If you are going from 3D to GUI you need to remember that the units are waaaaaay different.

If going from gui node to gui node there may be a local to world change the needs to be made before letting it drag around in the full gui node.

When I attach the dndRoot to GuiNode, every operation will be relative to GuiNode. As far as I can find in the source, it entirely works with dndRoot as root.

So what happens - for all the other readers - is that when the dragdetected event is fired, the item is detached from it’s container (whose parent is dndRoot) and a copy is attached to dndRoot.

In the demo code I tried attaching it directly to either GuiNode and RootNode but that did not make the item visible when being dragged.

I think I know where to look: in DefaultDraggable there is a method updateTranslation that is aimed at 3D coordinates. In GuiNode it should work with just the screen coords. Maybe overriding this method in ColoredDraggable - the subclass that is defined and used in the demo - might help.

But is is not entirely clear to me how to obtain the current mouse position.

DefaultDraggable works in 2D and 3D. The Lemur demo has 3D dragging but most of my own actual game code is doing 2D dragging.

The only differences between a 3D scene and a 2D scene is that in 3D 20 units is giant and in a 2D scene 20 units is pretty tiny.

Any time you end up with a case of “I can’t see my object”. Step 1 is to log where it is. It’s probably not where you think it is.

Are you moving from 3D to 2D and back? If so, why?

You were right: it was not where I expected it.

I scaled the entire dndRoot and I think that made things go bad. To fix it, I either do some more tweaking or I find a better way to resize the containers.

setPreferredSize() as mentioned before. That’s the way you resize containers.

You can “scale” your whole UI but you cannot scale just parts of it. This will really confuse lemur that already provides other ways to size things and otherwise ignores local scaling in most cases.

Where should I set preferredSize()?

In the demo, container1, container2 and dndRoot are just Nodes, they do not have the preferredSize() method. I tried doing it on the container dndRoot is attached to, but that does not do anything, de drag-areas stay tiny just a few pixels in size.

Mmm… I thought you were using 2D Lemur Containers for your UI.

I do, but setting preferredSize on those does not resize the DragAndDrop stuf.

This is how I implement the dndDemo into my gui:

        Container row;
        
        row=gui.createRow("rowInputs","Sensors",window);
        
        dndInputs=new DragAndDropSystem(app,row,32,4,6);
        world.app.getStateManager().attach(dndInputs);

        row.attachChild(dndInputs.getRoot());
        for (InputDef in : NEAT.inputs){
           if (in.cluster==-1)  dndInputs.createItem(in.idx, in.icon, in.unlocked);
        }

You may notice that I do not use row.addChild, the Lemur-way. If I would do that, I would get this error message:

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.IllegalArgumentException: Child is not GUI element.

Which is reasonable, because dndRoot is just a Node and not a Lemur Gui element.

I don’t understand why you would attach “dnd root” as a child. It’s a “root” after all.

In the demo, dndRoot was just a convenient root for the DragAndDropDemoState to manage all of it’s children separate from all of the other demo app states.

The demo is self-contained to be a demo. You’d never actually add drag-and-drop to an application this way. You’d have containers that participate in drag-and-drop and they’d have the drag and drop control to participate in drag and drop… but it’s unreasonable to think that every drag-target in the UI would all be managed under some central root. They are all collaborators.

So I’m not really sure what your “DragAndDropSystem” is doing. Usually there would not be some central manager of drag and drops.

I needed a way to keep it positioned relative to wherever my gui is moving or whatever content is changing the position of the elements. An alternative might be updating the coords after the gui changes, but I was not looking forward to that.

Maybe I will have try whipping up a Lemur compatible drag&drop later on. But for now I’ll go with another way to select items.

Tnx for your help again.

But the screen doesn’t move. I don’t understand.

When the object is being dragged, it’s being dragged on the screen. When it’s dropped, it’s dropped on the GUI element where it’s dropped.

Does your 2D UI slide around the screen while the user is dragging and dropping something?

I feel like one of us is misunderstanding what’s going on here.

Lemur’s drag-and-drop works very much like other UI library drag-and-drop. While the dragging is happening, the object is “global” until it gets dropped on another UI element. The drag session interacts with the drag targets to decide whether the object can be dropped on a target, etc… and then decide what happens when it’s dropped. The idea is that you could have some list box nested deep within some UI in one place and drag items out of that into some other view nested deep within some other UI… even from 2D to 3D or 3D to 2D.

So:

…is weird in that light. The guiNode doesn’t usually move.