MouseEventControl >> Method Paramter "Spatial capture"

Lemur’s MouseEventControl class allows you to put a mouse listener onto a spatial. It’s the coolest invention since sliced bread.

There are four main methods for mouse interactivity. They are:

mouseButtonEvent(MouseButtonEvent event, Spatial target, Spatial capture)
mouseEntered(MouseButtonEvent event, Spatial target, Spatial capture)
mouseExit(MouseButtonEvent event, Spatial target, Spatial capture)
mouseMoved(MouseButtonEvent event, Spatial target, Spatial capture)

I would like to know what the last parameter “Spatial capture” refers to and how it can be used.

Are there any code examples of this?

‘target’ is the object upon which this event/pick actually happened. ‘capture’ is the object that was the target when the mouse button down event was received and consumed.

This is commonly used in drag operations, for example. If you press down on the draggable then you don’t want to stop dragging just because the user happened to move so fast as to no longer be ‘picking’ that draggable… so you use ‘capture’ instead.

DragHandler is an example of this.

I tried using the mousebuttonevent to create a simple mouseclick listener, but found that I couldn’t get the coordinates (world) where the event happened. So I reverted to using a raytrace.

If you come across a solution for this, I’d be delighted.

You mean the world location on the object? For that, you would use a CursorListener instead. It’s just like MouseListener except it gives you all of the collision information as it has its own event structure and is not limited by JMEs mouse events.

1 Like

Can I attach a cursor listener to a spatial as well?

It works exactly the same except that you use CursorEventControl instead.

Sorry this is kinda unrelated, but is there a place where I can download recent lemur builds or I have to build it myself? Also are there any tutorials on the subject other than demo code?

I haven’t done a build in a while but I should… though I guess not too much has changed other than a couple bug fixes. Actually, I’m wrong about that as the changelog is pretty sizeable. :smile:

I haven’t pushed an update because of straddling the line between two JME versions right now. In the short term, your best bet is to build from source if you want the latest stuff, I guess.

With my life as it is right now (wife with brain cancer, busy day job, etc.), I haven’t had too much time for documentation other than what is posted here and other than what’s in the Lemur Gems code.

When I try the CursorEvent, I get a nullpointer when trying to get the event.getCollision().getContactPoint() - any idea why this is?

private void addClickListener(Geometry geom) {
        CursorEventControl.addListenersToSpatial(geom,
                new DefaultCursorListener() {
            @Override
            protected void click(CursorButtonEvent event, Spatial target, Spatial capture) {
                System.out.println("Event coordinates: "+event.getCollision().getContactPoint());
            }
        });
        /*
        MouseEventControl.addListenersToSpatial(geom,
                new DefaultMouseListener() {
            @Override
            protected void click(MouseButtonEvent event, Spatial target, Spatial capture) {
                System.out.println(event.getX() + ","+event.getY());
            }
        });
        */
    }

Hmmm… for some reason, the collisions are not calculated or passed for button events. Only for motion events. Entered and exited don’t have it either.

I think there was a very good reason for this but for the life of me I can’t remember what.

For button events, it might be that the event might be delivered to a spatial that didn’t actually receive the collision.

It may have only been for performance and convenience. The button handling always forwards to the mouseMove handling to make sure that a mouse move is always delivered. For many elements, this would be necessary for proper visual state handling. Every time I look at this code at this post’s prompting, I have something tickling my brain telling me that there was a very good reason for passing null for button events but I just can’t place it. And reading the code has offered no insight. This is one place where past-me was a real dick in not leaving a good comment.

You should be able to get around this just by tucking away the CollisionResult from the most recent move event. I feel like that’s a shallow answer but it should work. (And if it doesn’t, then it may indicate why I passed null in the first place. ;))

I will be thinking hard about this one as I’m bound to run into some similar cases myself soon.

Allright, thanks for getting back to me. Right now I can live with a raytrace. I just found it handy to have a listener ready for recieving events on spatials.

As said, you can still use the listener, just keep a field that contains the last CollisionResult (or even the whole cursor move event) from the last cursorMoved call. cursorMoved is guaranteed to be called immediately before the button event.

And if I ever fix the issue then it’s only an easy change in your listener should you want to go back to the ‘natural’ way.