Leveraging tooltips

In addition to the tooltips which the GUI displays when the mouse indicator hovers over buttons and other elements, I wish to display a tooltip when the mouse indicator hovers over a manipulable object in the scene. I have code to detect when the mouse indicator is on an object. Does the GUI provide an easy way to display a tooltip? I’d like to leverage the existing tooltip code as much as possible.

@sgold said: In addition to the tooltips which the GUI displays when the mouse indicator hovers over buttons and other elements, I wish to display a tooltip when the mouse indicator hovers over a manipulable object in the scene. I have code to detect when the mouse indicator is on an object. Does the GUI provide an easy way to display a tooltip? I'd like to leverage the existing tooltip code as much as possible.

I believe it does… one sec and I will let you know.

Yeah… you can set this on any element whether or not it is interactive (for instance hovering over an indicator, etc). Just use the following method:

[java]
public void setToolTipText(String toolTip);
[/java]

EDIT: I believe setting it to null will remove the tool tip display from showing up.

Oh! I mis-read this… give me a sec and I’ll let you know. I believe it is possible

Ok… the short term answer is… no.

The answer after tonight will be… yes. But, would love your input on how you would like this to work.

My initial thought is it will require picking to handled by you and then a call to Screen to update the display state of the ToolTip control. This would need to be handled for mouse focus and lose focus.

The alternative is to add the ability to use the library’s listeners on scene objects and enable a Screen-based picking solution for your scene that can be enabled if needed.

This would also allow you to use scene objects as ui components in all capacities (much like Lemur does).

1 Like

Thanks for the rapid response.

I’m still pretty new to this GUI and don’t have a good overview of the API yet. But here’s how I envision this working:

I write some method that’s invoked every time the mouse indicator hovers on a portion of the screen that’s not part of any GUI element. This might be a Screen method which I override with a subclass or (better yet) part of a listener object which I register with the GUI. The method takes a Vector2f parameter with the screen coordinates of the mouse indicator. My method returns a text string for the tool tip, which the GUI then displays–unless the returned value is null or the empty string.

Sound do-able?

And of course the method should only be invoked if useToolTips==true.

1 Like

Ok… I think I should be able to provide both a generic way of leveraging Tool Tips and provide the listeners to generic scene spatials. I’ll know a little bit more about specifics a little later on today once I’ve have a change to poke around a bit and try a few things. I’m hoping to have this working and n tonight’s update (I’ll also post as soon as it is available from the repo)… but, by tomorrow night’s update by the latest.

This is something I’ve been meaning to get set up, but didn’t have a this must be done now use case until now.

Thanks!!

1 Like

And thank YOU. You’ve been very helpful on the forums lately, and not just to me.

1 Like
@sgold said: And thank YOU. You've been very helpful on the forums lately, and not just to me.

One last note on this… while I’ve been giving it thought, it occured to me that this process will need to account for multi-touch as well. The first update will likely not contain this… I’ll follow it up with another update that adds multi-touch for scene spatials soon after.

An additional request related to tooltips:

When I hide a button with setIsVisible(false) I would expect its tooltip to disappear also.

@sgold said: An additional request related to tooltips:

When I hide a button with setIsVisible(false) I would expect its tooltip to disappear also.

Just to clarify what is happening with this, are you hiding the button and the ToolTip stays until you move the mouse? Or is it appearing where the was?

After I hide the button, the tooltip stays until the mouse moves away from where the button was.

1 Like
@sgold said: After I hide the button, the tooltip stays until the mouse moves away from where the button was.

I’ll see about getting this resolved with the current update I’m plodding through :wink:

@sgold said: After I hide the button, the tooltip stays until the mouse moves away from where the button was.

Just waned to keep you up-to-date on the progress with this as I spent most of yesterday reeling over which approach to take to support 3d scene spatials.

I’m happy to report that I finally decided on an approach that is as non-intrusive as possible and still follows the design pattern used for event handling in Element.

The general idea will work as follows:

  1. Create an empty abstract class that extends Node and implements the listeners you wish to use
    ** Encapsulate whatever Geometry (whether or not it is nested already… this doesn’t effect how it works) you would like to add the event support to.
    ** Either use this node for manipulating your Geometry’s transforms or just forget it exists and use whatever node the loaded asset was in to begin with (this doesn’t really matter as it is the collision results against the Geometries that is used to forward events)
  2. call screen.setUse3DSceneSupport(true);

Since this is going to support all interaction (mouse focus, movement, button, wheel, keyboard, touch and potentially tab focus), I might need an extra day to finish this up. I wasn’t expecting to have a complete mental block when I started looking at this yesterday :wink:

Currently, mouse focus, movement and wheel support is working nicely. The rest should go quickly… but I wanted to pad the time in case I hit something unexpected.

1 Like

Bit more info on this:

I’m not adding any automated interaction (such as drag, resize, etc), what the Geometries do with the forwarded event is completely up to the end user. This will also include the need to Event.setConsumed() if you do not want the event forwarded once used.

I’ll post an example or 4 of how I tested to give an idea of how to use this once it is finished and committed.

1 Like

Oh… also note worthy:

Due to the way this works, you can add as many Geometries as you would like to any extended node and each will fire off the event handling for the parent node.

I look forward to testing the new features when theyr’re ready.

I was just thinking about your proposed implementation. Suppose I want to add a tooltip to a Node that’s already been created. (Perhaps it was loaded from a J3O file or generated by a utility.) Seems to me I’d have to go through some contortions to extend a Node “in place”.

1 Like

Ok… I may commit the support as it stands right now, which will give people the ability to leverage the easy event handling in your 3d scene and allow me to continue to work on it without feeling like I am holding anyone up who is interested.

To start, the following events will be handled (I want a bit more time to consider keyboard and touch events… specifically multi-touch)

MouseButtonListener
MouseWheelListener
MouseFocusListener
MouseMovementListener

Here is a quick vid of mouse focus + contextual right-click menus for scene objects:

[video]http://youtu.be/Gqhq5LXksCo[/video]

I’ll post a bit later to let you know when it has been committed… at the moment, I seem to be getting collision results from back to front and I’m not sure what I did wrong :wink:

The code to make the above work was grueling:

ExtendedNode.java
[java]
import com.jme3.scene.Node;
import tonegod.gui.listeners.MouseButtonListener;
import tonegod.gui.listeners.MouseFocusListener;

/**
*

  • @author t0neg0d
    */
    public abstract class ExtendedNode extends Node implements MouseFocusListener, MouseButtonListener { }
    [/java]

Main.java
[java]
import com.jme3.app.SimpleApplication;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import tonegod.gui.controls.menuing.Menu;
import tonegod.gui.core.*;

/**

  • test

  • @author t0neg0d
    */
    public class Main extends SimpleApplication {
    private Screen screen;
    private Menu menu, menu2;

    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    }

    @Override
    public void simpleInitApp() {
    setupCamera();
    createGUIScreen();
    layoutGUI();

     flyCam.setDragToRotate(true);
     inputManager.setCursorVisible(true);
    

    }

    private void setupCamera() {
    inputManager.setCursorVisible(true);
    flyCam.setMoveSpeed(50);
    }

    private void createGUIScreen() {
    screen = new Screen(this);
    screen.setUse3DSceneSupport(true);
    guiNode.addControl(screen);
    }

    private void layoutGUI() {
    createMenus();

     Box box = new Box(1,1,1);
     Sphere sphere = new Sphere(12,12,1);
     
     Material mat = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
     mat.setColor("Color", ColorRGBA.Blue);
     
     Node n = this.getNewGUINode(box, mat.clone(), menu);
     Node n2 = this.getNewGUINode(sphere, mat.clone(), menu2);
     n2.setLocalTranslation(3,0,0);
     
     rootNode.attachChild(n);
     rootNode.attachChild(n2);
    

    }

    private void createMenus() {
    menu = new Menu(screen, Vector2f.ZERO, false) {
    @Override
    public void onMenuItemClicked(int index, Object value, boolean isToggled) {

     	}
     };
     menu.addMenuItem("Contextual Box Menu Item 1", 0, null);
     menu.addMenuItem("Contextual Box Menu Item 2", 1, null);
     menu.addMenuItem("Contextual Box Menu Item 3", 2, null);
     menu.addMenuItem("Contextual Box Menu Item 4", 3, null);
     screen.addElement(menu);
     
     menu2 = new Menu(screen, Vector2f.ZERO, false) {
     	@Override
     	public void onMenuItemClicked(int index, Object value, boolean isToggled) {
     		
     	}
     };
     menu2.addMenuItem("Contextual Sphere Menu Item 1", 0, null);
     menu2.addMenuItem("Contextual Sphere Menu Item 2", 1, null);
     menu2.addMenuItem("Contextual Sphere Menu Item 3", 2, null);
     menu2.addMenuItem("Contextual Sphere Menu Item 4", 3, null);
     screen.addElement(menu2);
    

    }

    private Node getNewGUINode(Mesh mesh, Material mat, final Menu menu) {
    Geometry geom = new Geometry();
    geom.setMesh(mesh);
    ExtendedNode node = new ExtendedNode() {
    public void onGetFocus(MouseMotionEvent evt) {
    ((Geometry)getChild(0)).getMaterial().setColor(“Color”, ColorRGBA.Yellow);
    evt.setConsumed();
    }
    public void onLoseFocus(MouseMotionEvent evt) {
    ((Geometry)getChild(0)).getMaterial().setColor(“Color”, ColorRGBA.Blue);
    evt.setConsumed();
    }
    public void onMouseLeftPressed(MouseButtonEvent evt) { }
    public void onMouseLeftReleased(MouseButtonEvent evt) { }
    public void onMouseRightPressed(MouseButtonEvent evt) { }
    public void onMouseRightReleased(MouseButtonEvent evt) {
    menu.showMenu(null, screen.getMouseXY().x, screen.getMouseXY().y-menu.getHeight());
    evt.setConsumed();
    }
    };
    node.attachChild(geom);
    node.setMaterial(mat);
    return node;
    }

    @Override
    public void simpleUpdate(float tpf) { }
    @Override
    public void simpleRender(RenderManager rm) { }
    }
    [/java]

1 Like
@sgold said: I was just thinking about your proposed implementation. Suppose I want to add a tooltip to a Node that's already been created. (Perhaps it was loaded from a J3O file or generated by a utility.) Seems to me I'd have to go through some contortions to extend a Node "in place".

Yes and no, because the extended node you would throw it inside of does not need to be updated… so you can treat it as an invisible layer by loading model > adding that node to the extended node and just forgetting the wrapper node exists.

EDIT… oh… ya know… the automatic generation utility is a really good idea.

@sgold said: I was just thinking about your proposed implementation. Suppose I want to add a tooltip to a Node that's already been created. (Perhaps it was loaded from a J3O file or generated by a utility.) Seems to me I'd have to go through some contortions to extend a Node "in place".

Also, there will be the option to directly call the ToolTip popup without having to use any of the above. I keep forgetting to mention that :wink:

1 Like