[Nifty1.3] Effect imageOverlay bug!

Like I said in my previous post I finally updated my nigtly build version.

And then, all my custom buttons aren’t displayed correctly.

After some research, I think I found the problem :

Most of my custom controls use this kind of effect to display image :

[java]

<onCustom customKey=“iconBook” name=“imageOverlay” filename=“iconBook.png” post=“true” imageMode=“normal” neverStopRendering=“true”/>

<onCustom customKey=“iconChurch” name=“imageOverlay” filename=“iconChurch.png” post=“true” imageMode=“normal” neverStopRendering=“true”/>

[/java]

And in the JAVA part, during the init method I use :

[java]

panelElt.getEffectManager().resetAll();

String panelEffectKey = effectName;

if( panelEffectKey.equals("") )

panelEffectKey = “empty”;

panelElt.startEffect( EffectEventId.onCustom, null, panelEffectKey );

[/java]

It works when the control is loaded visible.

But when the control is loaded hidden, it seems the element is not created.

( It worked on version jME3_2011-03-17 )

Do I need to change the attribute of my effects ( Like adding a timeType or something )

or is it really a bug ?

Thanks in advance !



Edit : Another lead :

I’m doing this during the init() method and the available effects depend on the style used for the control.

Perhaps the style is yet to be loaded during the init() method.

I don’t think there were lots of changes since jME3_2011-03-17 regarding this. Are you sure it worked before?



There have been some changes in the way that the bind() and init() methods are called when a control gets activated/displayed (now all elements of a screen will get the bind() first and then all of the elements get the init()). But you should still be able to start custom effects in init().



What exactly is not working? The overlay effect is not being started when the control is visible=“false”?



Can you enable the logging? Especially for the class de.lessvoid.nifty.effects.Effect?



Nifty should log if a custom key does maybe not match. Maybe you can find something like:

[java]log.info(“starting effect [” + getStateString() + “] canceled because customKey [” + customKey + “] does not match key set at the effect”);[/java]

in the log?

It worked on the previous version :slight_smile:

I’ve put the log at the end of the post.

Here is a simplified example :

Version of my style definition :

[java]

<style id="ae-imgButton-style#panel">

<attributes width="40px" height="40px" childLayout="center"/>

<effect>

<onCustom customKey="empty" name="imageOverlay" filename="empty.png" post="true" imageMode="normal" neverStopRendering="true"/>

<onCustom customKey="iconSystem" name="imageOverlay" filename="iconSystem.png" post="true" imageMode="normal" neverStopRendering="true"/>



</effect>

</style>



<style id="ae-imgButton-style#select">

<effect overlay="true">

<!-- iconSystem –>

<onCustom customKey="iconSystem_hide" name="fade" start="#f" end="#0" length="250" neverStopRendering="true" />

<onCustom customKey="iconSystem_hide" name="imageOverlay" filename="iconSystem_hover.png" post="true" imageMode="normal" neverStopRendering="true"/>

<onCustom customKey="iconSystem_show" name="imageSize" startSize="2.0" endSize="1.0" length="250" />

<onCustom customKey="iconSystem_show" name="fade" start="#0" end="#f" length="250" />

<onCustom customKey="iconSystem_show" name="imageOverlay" filename="iconSystem_hover.png" post="true" imageMode="normal" neverStopRendering="true"/>

</effect>

</style>

[/java]

In my XML :

[java]<control name="ae-imgButton" style="ae-imgButton-style" firstEffect="iconSystem"/>[/java]

And the control :

[java]

@Override

public void bind(

final Nifty niftyParam,

final Screen screenParam,

final Element elementParam,

final Properties propertiesParam,

final Attributes controlDefinitionAttributes)

{

panelElt = elementParam;

panelElt.setFocusable( false );

imageElt = panelElt.findElementByName("select");

firstEffect = propertiesParam.getProperty( "firstEffect" );

if( firstEffect == null )

firstEffect = "";

[…]

@Override

public void init(Properties arg0, Attributes arg1)

{

if( firstEffect != "" )

setEffect( firstEffect, firstState );

}

public void reloadEffect()

{

//


// PanelElt
//
panelElt.getEffectManager().resetAll();
String panelEffectKey = effectName;
if( panelEffectKey.equals("") )
panelEffectKey = "empty";
panelElt.startEffect( EffectEventId.onCustom, null, panelEffectKey );
//
// ImageElt
//
imageElt.getEffectManager().resetAll();
if( ! effectName.equals("") )
{
String imageEffectKey = effectName + "_";
if( checked )
imageEffectKey += "show";
else
imageEffectKey += "hide";
imageElt.startEffect( EffectEventId.onCustom, null, imageEffectKey );
}
}
[/java]
Case 1 : When I add my sheet, I display it directly.
Here is the result :

Case 1 : When I add my sheet, I don't display it directly ( I hide it just after adding it )
Here the result :

The first one is when I display it ( by clicking on the button in the toolbar )
The second one is when I clicked on the button. It changes state and is reloaded. It is relaoded correctly.
The third one is when I click a second time on the button. I revert ti the previous state and is reloaded.
As you can see, the appearance of the button is the third screen, is the same as the appearance of the button in the previous case.
For me, it means that my control works find as long as the control is displayed. But when the controls are hidden, my method reloadEffect() is not correct anymore.
----
Here is the log (Case 2):

Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect canStartEffect
INFO: starting effect [(ImageOverlay[empty])] canceled because customKey [iconSystem] does not match key set at the effect
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect start
INFO: starting effect [(ImageOverlay[iconSystem])] with customKey [iconSystem]
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.render.image.ImageModeHelper getAreaProviderProperty
INFO: imageMode property converted to imageArea property : normal -> fullimage
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.render.image.ImageModeHelper getRenderStrategyProperty
INFO: imageMode property converted to renderStrategy property : normal -> resize
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.EffectProcessor startEffect
INFO: adding effect as active
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect canStartEffect
INFO: starting effect [(Fade[iconSystem_hide])] canceled because customKey [iconSystem] does not match key set at the effect
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect canStartEffect
INFO: starting effect [(ImageOverlay[iconSystem_hide])] canceled because customKey [iconSystem] does not match key set at the effect
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect canStartEffect
INFO: starting effect [(ImageSize[iconSystem_show])] canceled because customKey [iconSystem] does not match key set at the effect
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect canStartEffect
INFO: starting effect [(Fade[iconSystem_show])] canceled because customKey [iconSystem] does not match key set at the effect
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect canStartEffect
INFO: starting effect [(ImageOverlay[iconSystem_show])] canceled because customKey [iconSystem] does not match key set at the effect
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect start
INFO: starting effect [(Fade[iconSystem_hide])] with customKey [iconSystem_hide]
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.EffectProcessor startEffect
INFO: adding effect as active
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.effects.Effect start
INFO: starting effect [(ImageOverlay[iconSystem_hide])] with customKey [iconSystem_hide]
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.render.image.ImageModeHelper getAreaProviderProperty
INFO: imageMode property converted to imageArea property : normal -> fullimage
Apr 20, 2011 11:12:01 AM de.lessvoid.nifty.render.image.ImageModeHelper getRenderStrategyProperty
INFO: imageMode property converted to renderStrategy property : normal -> resize

What is worrying me is the last 4 lines. :)

I’ve done other tests.

And it seems the problem is easier than I thought :

Lets say we have an xml like that

[java]

<panel id=“parent” childLayout=“center” >

<panel id=“child” >

<effect>

<onCustom customKey=“key” name=“imageOverlay” filename=“file.png” post=“true” imageMode=“normal” neverStopRendering=“true”/>

<onHover name=“imageOverlay” filename=“file2.png” imageMode=“normal” post=“true” />

</effect>

</panel>

</panel>

[/java]

When you add the screen, the panel are correctly displayed.

But if you do :

[java]

screen.findElementByName(“parent”).hide();

[/java]

and later

[java]

screen.findElementByName(“parent”).show();

[/java]

the imageOverlay will have disappeared. ( The onHover effect will still be ok )

Edit :

I’ve checked the source of the class Element.



I think I’ve found the problem :

It is in method method hide() :

[java]

public void hide() {

[…]

// start effect and shizzle

startEffect(EffectEventId.onHide, new EndNotify() {

public void perform() {

resetAllEffects();

internalHide();

}

});

}

[/java]



In commit 1360 ( the one used in my previous version), resetAllEffects() was replaced by resetEffects();

Now, when yuou hide an element, you destroy all effect it had (even custom effects). Is it wanted ?

Well, I think the motivation for that change was making sure that all effects will be stopped when an element is hidden. Which is correct because I suspect that when the element gets hidden you really don’t want to have any active effects anymore. So this is in fact expected behaviour.



What you could argue is that one would expect that active custom effects will still be active after you’ve hidden/shown the element. I would agree but this doesn’t happen automatically in the moment. That this has worked in previous versions for you in your special cases was not intended behaviour, you were only lucky that it did :slight_smile:

Errgg… It’s really bad news for me.



It worked since the beginning and all my customControls use imageOverlay on custom effects.



But are you really sure it was not intended ?

Because, after all, I took example on the Nifty style :

[java]

<style id=“nifty-checkbox-style#select”>

<attributes align=“center” valign=“center” width=“32px” height=“32px” />

<effect overlay=“true”>

<onCustom customKey=“show” name=“imageSize” startSize=“2.0” endSize=“1.0” length=“250” post=“true” />

<onCustom customKey=“show” name=“fade” start="#0" end="#f" length=“250” post=“true” />

<onCustom customKey=“show” name=“imageOverlay” filename=“checkbox/checkbox.png” width=“32px” height=“32px” post=“true” neverStopRendering=“true” />

<onCustom customKey=“hide” name=“fade” start="#f" end="#0" length=“250” post=“true” />

<onCustom customKey=“hide” name=“imageOverlay” filename=“checkbox/checkbox.png” width=“32px” height=“32px” post=“true” length=“250” />

<onEnabled name=“fade” start="#4" end="#f" length=“150” post=“false” />

<onDisabled name=“fade” start="#f" end="#4" length=“150” post=“false” />

</effect>

</style>

</nifty-styles>

[/java]



This one won’t work anymore with the new versions.

Whenever you hide a panel containing a checkbox and display it back afterwards, the checked cursor will be missing,

In addition, when you first click on it after that, it will activate the customKey=“hide”, and the checkbox will stil not be checked.



I’m interested with how you will change the default controls ( I may have to do the same thing on mine )

If it interests some people, here is the workaround that I’ve found :

I’ve created a new effect :

[java]

public class CustomKeyEffectReloader implements EffectImpl

{

@Override

public void activate(Nifty nifty, Element element, EffectProperties parameter) {

ControllerWithCustomEffect control = element.getControl( ControllerWithCustomEffect.class );

if( control != null )

control.reloadEffect();

}

@Override

public void execute(

final Element element,

final float normalizedTime,

final Falloff falloff,

final NiftyRenderEngine renderEngine)

{

}

@Override

public void deactivate()

{

}

}

[/java]

All my custom controls that manage custom Effect are implementing ‘ControllerWithCustomEffect’ instead of ‘Controller’

[java]

public interface ControllerWithCustomEffect extends Controller {

public void reloadEffect();

}

[/java]

And in the definitiion of my custom controls, I’ve added those lines :

[java]

<registerEffect name=“customEffectReloader” class=“com.didigame.acariaempire.gui.effects.CustomKeyEffectReloader”/>

[…]

<effect>

<onShow name=“customEffectReloader” />

</effect>

[/java]

With that, it behaves as before.



Edit :

@Void : I’m still interested on how you will do it. I tmay be a cleaner way than mine :slight_smile:

Damn, you’re right! Just checked with the new nifty-default-controls-example project and the checkbox is indeed broken :’(



I’m looking into it …

I’ve just commited this change to Nifty svn:


@public
potential fix for restoring active effects when elements are hidden/shown:

when you have active effects which use neverStopRendering=true then these effects basically never stop. when you hide such elements then these effects will be stopped. this was necessary to stop effects that influence global state. there is for instance the changeMouse effect which changes the mouse cursor. imagine what would happen when such effects would not being stopped when an element will be hidden.

on the other hand when you hide/show these elements then all of the neverStopRendering effects would not be restarted automatically which might lead to odd things (one example was the checkbox standard control. it is using a customEffect that gets triggered everytime the checkbox is in checked state. in this case the checkbox mark will be rendered with a neverStopRendering effect (in that case using an imageOverlay effect). what was happening in that case was that hiding and showing the checkbox would make that effect disappear and with it the checkbox mark would disappear too.

this commit will add the following solution:

when an element is hidden Nifty will remember all active effects that have the neverStopRendering flag set to true. when the element is being shown again all of these effects will be automatically started again. this solves this issue for now.
it's not known if other problems will arise with that.


This fixes the checkbox problem and will probably fix your issue in here too :)

I do hope that it won't break something else. Effects are a tricky beast sometimes because they are so damn versatile ;)

But thanks a lot for being so persistent with this! :D

Really good !

It’s far better than my custom effect on show :slight_smile:



Thanks for solving this.