Get reference to hint control

Hello,



I have defined my own hint control, which I use for a hint effect.



I use it like this:



[xml]

<panel childLayout="horizontal">

<effect>

<onHover name="hint" hintText="" hintControl="movehint"/>

</effect>

</panel>

[/xml]



Is it somehow possible to get a reference to the hintControl from my Java code?

I’m not sure but if you defined the controller for your moveHint then that should get called when the hint was popped up.



Why do you want the reference?

So I can call methods to it. I know the information I want to display only at runtime.



I have custom list elements and I want to show a hint when hovering over one. That works, but I need to change the hintControl properties during runtime, because the list elements can be added/removed/changed during runtime.

There are methods in the element class which have “effect” in their name, like getEffects().

Does anyone know how these methods work and if this behavior can be implemented through them?

So I guess I will create that effect in my code and attach it during runtime through the registerEffect method. Does that work?



How can I create that effect from my XML in my Java code? I think the relevant class here is Effect?

I think you might need a response from @void256 on this one…

This is how I’ve done Hints in Java:

[java]Hint hint = new Hint();

Properties properties = new Properties();

properties.put(“hintText”, “Text to display in hint”));

EffectProperties prop = new EffectProperties(properties);

// Show hint

hint.activate(nifty, element, prop);

hint.execute(element, 1, new Falloff(), nifty.getRenderEngine());

// Hide hint

hint.deactivate();[/java]

The answer Tumaini gave is only partly correct, I’m afraid. Changing the EffectProperties is correct but directly calling hint.activate() or hint.execute() to show the effect is not recommended. Nifty should call this internally. If you want to show any effect you should probably call element.startEffect().



What you can do to change effect properties prior of showing them is to call something like that:



[java]// get the element

Element element = nifty.getCurrentScreen().findElementByName(“test”);



// get all effects attached to this element (please note that you get a list back and that you need to provide the actual effect class)

List<Effect> hoverHintEffects = element.getEffects(EffectEventId.onHover, Hint.class);



// this is probably not necessary since you know what element and effect you request

if (hoverHintEffects.size() != 1) {

throw new RuntimeException(“sanity check failed”);

}



// simply get the first effect from the list

Effect hoverEffect = hoverHintEffects.get(0);



// and finally change the EffectProperties

hoverEffect.getParameters().setProperty(“hintText”, “change me”);[/java]



If the effect now gets activated - either by Nifty or by yourself - the new value for “hintText” will be used.



PS: I’ve added this answer as the first TODO for the next revision of the Nifty bible :wink:

3 Likes

Ah, thank you, void!

I’ll have to change that in our code then.

Ok, but I am using a custom control which also displays an image and not just a text. How can I change that?



Also, my custom control is always being attached at the top left corner and not where the mouse is and with wrong size values. Why is that? Does it have to subclass a special class for it to work properly?

Looking at the default control that is used to display the default hint:



[xml] <controlDefinition name=“nifty-default-hint” style=“nifty-default-hint”>

<panel style="#panel">

<text id="#hint-text" style="#hint-text" text="$hintText"/>

</panel>

</controlDefinition>[/xml]



there’s nothing too special going on. But the “magic” which might be missing from your control is hidden in the “nifty-default-hint” style for this control:



[xml] <style id=“nifty-default-hint” base=“nifty-panel-bright”>

<attributes childLayout=“center” />

<effect>

<onShow name=“fade” length=“150” start="#0" end="#d" inherit=“true” neverStopRendering=“true” />

<onCustom name=“fade” length=“150” start="#d" end="#0" inherit=“true” neverStopRendering=“true” />

<onActive name=“followMouse” />

</effect>

</style>



<style id=“nifty-default-hint#hint-text” base=“base-font”>

<attributes align=“left” valign=“center” textHAlign=“left” color="#111f" />

</style>[/xml]



It’s using:



[xml]<onActive name=“followMouse” />[/xml]



to automatically follow the mouse and move the hint control around. There is nothing that will resize the control though. This is up to the control itself and would usually use the build in layout mechanism.



Changing your own control content especially if your hint consists of more then a simple text - you mentioned an image - is currently not possible with the build-in hint effect I think. One idea I’ve tried is using onStartEffect but that is called just before the effect gets activated. So your control is not created yet since this is happening in activate >_<



I think your best bet would be to take a look at the de.lessvoid.nifty.effects.impl.Hint class and make your own copy :confused:



Another way would be to init your control in the controllers bind() or init() or onStartScreen() but the problem with this approach would be that you’ll still need a way to get the information you need to display INTO the control instance. Probably with some global state or something but that would suck.



I’d suggest your own version of the hint effect for now…

1 Like
@void256 said:
The answer Tumaini gave is only partly correct, I'm afraid. Changing the EffectProperties is correct but directly calling hint.activate() or hint.execute() to show the effect is not recommended. Nifty should call this internally. If you want to show any effect you should probably call element.startEffect().

What you can do to change effect properties prior of showing them is to call something like that:

[java]// get the element
Element element = nifty.getCurrentScreen().findElementByName("test");

// get all effects attached to this element (please note that you get a list back and that you need to provide the actual effect class)
List<Effect> hoverHintEffects = element.getEffects(EffectEventId.onHover, Hint.class);

// this is probably not necessary since you know what element and effect you request
if (hoverHintEffects.size() != 1) {
throw new RuntimeException("sanity check failed");
}

// simply get the first effect from the list
Effect hoverEffect = hoverHintEffects.get(0);

// and finally change the EffectProperties
hoverEffect.getParameters().setProperty("hintText", "change me");[/java]

If the effect now gets activated - either by Nifty or by yourself - the new value for "hintText" will be used.

PS: I've added this answer as the first TODO for the next revision of the Nifty bible ;)


Where do I put this code into? I am using the hint effect for custom list elements. I put it in my ViewConverter's display method. But since this isn't working, I guess it's the wrong place?

The very first place that comes to my mind would be the hint effects “onStartEffect” method callback. So that Nifty calls the method you specify with onStartEffect that gets called just before it displays the hint.



If you implement your own Hint effect you have more options. Nifty will call your effect with the Element instance the effect is attached to. So you could use the element content to directly extract the information you would like to display in the hint. But this depends on your data structure I think.

So when I have an object in my custom ListboxViewConverter of my own type and I want to display the object’s information in a hint effect attached to the list element, how do I get that object from my ListboxViewConverter into my hinteffect?

In that case you have access to the Element - the one you’re supposed to change for your custom Listbox - in your ListBoxViewConverter implementation. And you probably already have added the hint effect to those elements.



I think what you’ve tried first should work: add the above code - the one to change the effect properties - to the ListBoxViewConverter.display() method and change the effect properties of the attached Hint effects there?



If you would provide a complete but sscce - maybe something I can drop directly into the jMonkeyPlattform - I might be of better help figuring this out?

Is it enough to just set the properties?



Because it just keeps the default ones. I tested it with the default hint control with just the text.



What it apparently does is creating a 2nd hint control with the new text and rendering it below the first one.

o_O And it does that when … you do what?



The default hint control is supposed to be added as onHover to an element:



[xml]<onHover name=“hint” hintText=“the actual hint message.” />[/xml]



It should get activated when the hover begins, e.g. the mouse pointer is inside the element area - in that case a temporary layer is added for the display of the hint. When the effect gets deactivated, e.g. the mouse pointer has left the element area - the temporary layer will be removed.



When you set the effect properties before the effect gets activated the text will be changed - I’ve tried it :slight_smile: Usually there is not a second hint element added.



I’m confused now what you’re doing :slight_smile:

I have this custom listbox element and an onHover hint is attached to it.



In its display method I do:



[java]

@Override

public void display(Element elmnt, Move t) {

Element text = elmnt.findElementByName(MOVENAMETEXT_NAME);

TextRenderer textRenderer = text.getRenderer(TextRenderer.class);

Element icon = elmnt.findElementByName(MOVEICON_NAME);

ImageRenderer iconRenderer = icon.getRenderer(ImageRenderer.class);



NiftyImage moveImage = elmnt.getNifty().getRenderEngine().createImage(Move.MOVEIMAGE_PATH + t.getID() + ".png", false);



elmnt.setVisibleToMouseEvents(true);



List<Effect> hoverEffects = elmnt.getEffects(EffectEventId.onHover, Hint.class);



Effect hoverHintEffect = hoverEffects.get(0);



hoverHintEffect.getParameters().setProperty("hintText", t.getName());



if (t != null) {

textRenderer.setText(t.getName());

iconRenderer.setImage(moveImage);

} else {

textRenderer.setText("");

iconRenderer.setImage(null);

}

}

[/java]

I have good and bad news :slight_smile:



The good news is:

You’ve done everything correctly.



The bad news is:

Nifty has a bug where it is possible that an already applied style was applied a second time. This occurs especially when an ElementType is being copied. This is happening inside of the ListBox when the template element is copied for the visible entries in the ListBox. You’ll end up with all effects applied twice to the element.



So in case of the Hint effect you really have two Hint effects unfortunatly. As a hackish work-around you could modify both hint effects - but don’t tell anyone that I’ve told you because this is really ugly :slight_smile:



I’ve fixed the problem for Nifty 1.3.2-SNAPSHOT. So if you’re using a cutting edge Nifty nightly build it should work as expected.



Thanks for being persistent :wink:

Which class files did you change to fix the bug?