Leveraging tooltips

I also wanted to mention that the above is exactly why I sat staring at my monitor most of yesterday and not getting anything done. Every solution I considered was either too much work for the user, blindly broadcasted events to every registered listener (which again would be a nightmare for the user to manage anyways) or just didn’t work out after following through the chain of thought.

I’m not sold on the solution above (though, it is as simple as it gets for the end user), I just couldn’t find a working alternative that stayed simple and followed the existing event listener pattern.

Just another update, since I am a freak…

There was no sorting issue with the results (of course… It was a simple error in my code… what a surprise)

The last hold up is, apparently the gui library doesn’t consume movement events when over a ui element atm. It does for button and touch events, however… not for movement.

In the example above, if a gui element is hovering over a scene spatial that has enable event handling, unless the specific control consumes the hover event (like button, etc), these filter past the ui element and effect the scene as well.

I’m thinking this was an oversight on my part, but I’m having to go through quite a bit to ensure that this is the case before adding this.

EDIT: I stated this semi-incorrectly. Mouse/Touch movement is consumed if A mouse button is currently pressed/touch event is currently happening while interacting with a visible element.

@t0neg0d said: Just another update, since I am a freak...

If you’re a freak, you’re definitely MY kind of freak. Thank you for keeping us updated, and for your many contributions to this community.

1 Like

All this sounds awesome, I also have a use for such a feature. Very much look forward to it.

While you are on tooltips, I wonder if I might highjack this thread a little and make a tiny teeny wee feature request. Basically, I want the ability to use any Element as the content for the tooltip. For example, I have an Inventory, and want to be able to show fancy tooltips on items in the inventory. These tooltips could have images, special layout. Text just doesn’t cut for me in this case, so I extended Screen a little and added the concept of the ToolTipProvider interface.

I suspect you might port tooltips to the new TextThing, but even so, I’d prefer total control over what a tip looks like.

[java]
public interface ToolTipProvider {

Element createToolTip();

}
[/java]

One of these can be set at either the screen level (the “defaultToolTipProvider”), or at the Element level (current by having the Element implement the interface, a setter/getter could be stuffed into Element though). Then when the tooltip is shown, this is called to provide the tooltip for the Element. This returned object could be created on the fly at this point, or it could return a shared instance.

Is just a minor thing. I already have this implemented in my own custom components (pretty easy to do), and it doesn’t intrude with normal text based tooltips either. But … it would be neat to have this ability in the core.

I can dig out my changes if you want them, but tbh its a 5 minute job to reimplement :stuck_out_tongue_winking_eye:

RR

1 Like

One last heads up… I’ve been side tracked with the 3d scene support as after @sgold mentioned the need for tooltips for 3d scene objects, in just made sense to add for event handling support through the Screen class.

I’m going to commit the start of this and push out an update now (that may be updated prior to tonight) as it seems to be working rather well.

I’m going to create a new thread so others are aware of the addition and I have a place to track progress on it.

After I get the initial update pushed out, I’ll be making the updates to ToolTips and wanted to see if I could have a look at @rockfire mentioned here so I can incorporate this all at once.

1 Like

@sgold
Lasted commit of Screen added the follwing methods:

[java]
Screen.setForcedToolTip(String toolTipText);
Screen.releaseForcedToolTip();
[/java]

Use them in conjunction with onGetFocus and onLoseFocus and it should do what you want.

I’ll likely update this again (leaving what is currently in place) once I hear from @rockfire about his approach for custom ToolTip Elements.

@t0neg0d - Apologies for delay, here is the code :slight_smile: Ohh, congratulations on the 1000th post by the way.

First of is a simple interface, extend any Element and implement this get customs tooltips.

[java]
public interface ToolTipProvider {

Element createToolTip();

}
[/java]

And now the change to Screen. The below is actually from a subclass of Screen that mainly overrides updateToolTipLocation(). You’ll need to adapt it slightly for use in Screen, and can of course get rid of the bits of reflection (ControlUtil.getInaccessibleField…).

[java]
private ToolTipProvider currentProvider;
private ToolTipProvider currentProvider;
private Element extendedToolTip;

public ToolTipProvider createDefaultToolTipProvider(Element element) {
    return null;
}


@Override
public void updateToolTipLocation() {
    if (getUseToolTips()) {
        Element mouseFocusElement = ControlUtil.getInaccessibleField(Element.class, "mouseFocusElement", this, Screen.class);
        if (mouseFocusElement != null && getApplication().getInputManager().isCursorVisible()) {
            ToolTipProvider toolTipProvider;
            if (mouseFocusElement instanceof ToolTipProvider) {
                toolTipProvider = (ToolTipProvider) mouseFocusElement;
            } else {
                toolTipProvider = createDefaultToolTipProvider(mouseFocusElement);
            }

            if (toolTipProvider != null) {
                if (currentProvider == null || !toolTipProvider.equals(currentProvider) || !currentMouseFocusElement.equals(mouseFocusElement)) {
                    if (extendedToolTip != null) {
                        extendedToolTip.hide();
                        extendedToolTip.removeFromParent();
                    }
                    currentProvider = toolTipProvider;
                    extendedToolTip = currentProvider.createToolTip();
                    currentMouseFocusElement = mouseFocusElement;
                }
                if (extendedToolTip != null) {
                    Vector2f mouseXY = ControlUtil.getInaccessibleField(Vector2f.class, "mouseXY", this, Screen.class);
                    float nextX = mouseXY.x - (extendedToolTip.getWidth() / 2);
                    if (nextX < 0) {
                        nextX = 0;
                    } else if (nextX + extendedToolTip.getWidth() > getWidth()) {
                        nextX = getWidth() - extendedToolTip.getWidth();
                    }
                    float nextY = mouseXY.y - extendedToolTip.getHeight() - 40;
                    if (nextY < 0) {
                        nextY = mouseXY.y + 5;
                    }
                    extendedToolTip.moveTo(nextX, nextY);
                    if (!extendedToolTip.getIsVisible()) {
                        extendedToolTip.show();
                    }
                }
                return;
            }
        }

        if (currentProvider != null) {
            extendedToolTip.hide();
            currentProvider = null;
        }
    }
    super.updateToolTipLocation();
}

[/java]

RR

1 Like

Obligatory video… (for some reason it’s taking forever to process… however below the vid is more important than the vid)

[video]http://youtu.be/Fo6-A-7isdY[/video]

Also… still looking for a good solution for hiding tooltips based on something other than mouse movement. I’ll add it once I find it :wink: For the time being I provided a way of forcing hide on the tool tip element (call this when you hide said button):

[java]
Screen.hideToolTip();
[/java]

@rockfire said: (ControlUtil.getInaccessibleField....). [/java]

RR

I’m trying to catch these as I find them and make them accessible… drop me a note anytime you hit one that needs to be updated :wink:

@t0neg0d said: I'm trying to catch these as I find them and make them accessible... drop me a note anytime you hit one that needs to be updated ;)

That I can do …

  • Those marked with * are subclasses, so protected access is fine
    +Those marked with +, write access or setter is required

TextField.ctrl (might as well do shift, alt and meta too)
Menu.currentHighlightIndex +*
TabControl.tabButtonIndex *
TabControl.tabs *
TabControl.tabPanels *
TabControl.tabSlider *
TabControl.tabXInc +*
TabControl.tabWidth +*
TabControl.tabHeight +*
TabControl.tabResizeBorders +*
RadioButtonGroup tabButtonGroup
ScrollArea.scrollSize
Menu.menuItemHeight +*
Menu.highlightColor *
Menu.hasSubMenus *
Menu.hasToggleItems *
Menu.preferredSize *
Menu.callerElement *
Screen.tabFocusElement
RadioButtonGroup.radioButtons
SlideTray.trayElements
SlideTray.trayPadding
SlideTray.currentElementIndex
AnimText.font

1 Like

@rockfire
I’ve updated all but TextField… as I missed that while going through the list. See the notes below… otherwise, all is as requested:

Menu.currentHighlightIndex – see setHighlight
TabControl.tabWidth – setFixedTabWidth
ScrollArea.scrollSize – see setScrollBarWidth
Menu.menuItemHeight – Currently, this would be overwritten if a setter was accessible
Screen.tabFocusElement – Added get, for other use see setTabFocusElement & resetTabFocusElement
RadioButtonGroup.radioButtons – protected & added getSelected()
SlideTray.trayPadding – protected, getter & setter
AnimText.font – Added getter, setter is already accessible. Also now a protected field

TextField.ctrl, shift, alt, meta – protected now

Great! Thanks a lot… this will simplify my layout extensions amongst other things. Will let you know if any more crop up.

1 Like

Hey, @t0neg0d:

I’ve updated to rev 518, and I’m noticing a new issue. My code looks like this:
[java]
public void onMouseMotionEvent(MouseMotionEvent event) {
float x = event.getX();
float y = event.getY();
Vector2f click2d = new Vector2f(x, y);
Item item = mainViewState.findItem(click2d);
Screen screen = inputState.getGuiScreen();
if (item == null) {
screen.releaseForcedToolTip();
} else {
String tipMessage = item.getTypeName();
screen.setForcedToolTip(tipMessage);
}
}
[/java]

If I move the cursor from a button to a 3-D scene item without any gap between them [which would cause releaseForcedToolTip() to be invoked] then the button’s tooltip continues to be displayed–instead of the item’s tooltip.

@sgold said: Hey, @t0neg0d:

I’ve updated to rev 518, and I’m noticing a new issue. My code looks like this:
[java]
public void onMouseMotionEvent(MouseMotionEvent event) {
float x = event.getX();
float y = event.getY();
Vector2f click2d = new Vector2f(x, y);
Item item = mainViewState.findItem(click2d);
Screen screen = inputState.getGuiScreen();
if (item == null) {
screen.releaseForcedToolTip();
} else {
String tipMessage = item.getTypeName();
screen.setForcedToolTip(tipMessage);
}
}
[/java]

If I move the cursor from a button to a 3-D scene item without any gap between them [which would cause releaseForcedToolTip() to be invoked] then the button’s tooltip continues to be displayed–instead of the item’s tooltip.

Sorry for the delay, I was exhausted by 3(ish) yesterday and had to call it for the day. Only a couple more weeks of this before the final surgery and I’ll be all better (thank God… been a loooooong and grueling process). Anyways… enough whining from me.

First, I updated the 3D picking to work the way you requested… it makes the most sense to me (and everyone else who got it waaaaaaay before I did lol). The only catch is… it checks the (main) ViewPort’s in the order they are added. So…

Default
MyViewPort1
MyViewPort2 (dominant)
etc…

Transparency seems to work fine
However, I’m still not sure what to do with transparent vs. solid background with no collision result. Both options (return previous result, return null) seem valid.

Also note: There is no relative distance check anymore, as I thought the two viewports from our discussion were composited together, not two separate views overlayed. Each ViewPort now relies on it’s own camera, etc.

As for the issue mentioned above. Let me drink a bit of coffee so I don’t flounder about and misunderstand the issue :wink: Then I’ll see about getting this and tooltips all squared away proper like. Do bare with me… yesterday was one of those days… lots o pain… little brain =(

EDIT: Just a final note on the picking issue: add/removeScene are no longer used. Though, I’m leaving them stubbed as I would like to eventually allow for minimizing what in your scenes are actually checked and what is just ignored.

Ok… had a bit more coffee and I think I follow what you are seeing here.

This is likely due to the order in which your event handling and screen’s event handling are being received.

In your scenario:

3D scene is checked, then gui

Screen reverses this and skips the scene check if the gui has focus.

I need to setup the scenario you have here to make sure this is the issue and see if there is a way around it, though, I’m fairly sure this is what is happening.

Tool tips are very broken at the moment. GUI buttons don’t show tool tips except where there’s an overlapping forced tool tip.

I peeked at the latest Screen.java and frankly I’m confused by it.
Why are some invocations of setToolTipLocation() followed by
[java]
if (!toolTip.getIsVisible())
toolTip.show();
[/java]
while others are not?

@sgold said: Tool tips are very broken at the moment. GUI buttons don't show tool tips except where there's an overlapping forced tool tip.

I peeked at the latest Screen.java and frankly I’m confused by it.
Why are some invocations of setToolTipLocation() followed by
[java]
if (!toolTip.getIsVisible())
toolTip.show();
[/java]
while others are not?

Are you sure you’re releasing the forced tooltip in all instances?

I just ran the test project I have that uses all controls offered in the GUI, enabled tooltips and everything works as expected for all controls - This includes ORSViewPort, Buttons (all kinds), Sliders, ComboBox/SelectBox, etc, etc.

updateToolTipLocation:
[java]
@Override
public void updateToolTipLocation() {
if (useToolTips) {
if (this.mouseFocusElement != null && getApplication().getInputManager().isCursorVisible()) {
String toolTipText = this.mouseFocusElement.getToolTipText();
if (toolTipText != null) {
if (!toolTip.getText().equals(this.mouseFocusElement.getToolTipText())) {
toolTip.setText(“”);
toolTip.setHeight(25);
float finalWidth = BitmapTextUtil.getTextWidth(toolTip, toolTipText, toolTipMaxWidth);
toolTip.setText(toolTipText);
toolTip.setWidth(finalWidth+(toolTip.getTextPadding()*12));
toolTip.setHeight(toolTip.getTextElement().getHeight()+(toolTip.getTextPadding()*12));
toolTip.getTextElement().setBox(new Rectangle(0,0,toolTip.getWidth()-(toolTip.getTextPadding()*2),toolTip.getHeight()-(toolTip.getTextPadding()*2)));
}
setToolTipLocation();
if (!toolTip.getIsVisible()) // The only instance that needs to check the visibility of the ToolTip window
toolTip.show();
} else {
if (!forcedToolTip) {
toolTip.setText(“”);
toolTip.hide();
} else {
setToolTipLocation(); // Force invocation… ToolTip is already visible
}
}
} else {
if (!forcedToolTip) {
toolTip.setText(“”);
toolTip.hide();
} else {
setToolTipLocation(); // Force invocation… ToolTip is already visible
}
}
}
}
[/java]

@t0neg0d said: Are you sure you're releasing the forced tooltip in all instances?

I’m seeing this issue before I invoke screen.setForcedToolTip() for the first time.

On a hunch, I commented out my code which invokes screen.releaseForcedToolTip() and the issue went away, at least partially. So I think my issue has to do with releasing the forced tool tip when there isn’t one set.

[java]
public void releaseForcedToolTip() {
if (useToolTips) {
forcedToolTip = false;
forcedToolTipText = “”;
toolTip.setText("");
toolTip.hide();
}
}
[/java]

I don’t like that unconditional toolTip.hide()