Layers aren’t ”clickable”

= Intro =

I want a screen with a starup menu for “play / continue” “story” “reset” “quit”

If the player clicks on “reset” or “quit” I want a confirmation to pop up.

I have implemeted these as layers that are hidden until they are needed - only one layer is visible at a time.



= Problem =

When I switch which layer is visible - the button focus stuff doesn’t get activated … or something.

Here’s a video

http://www.youtube.com/watch?v=6TSA2OzAWNw

When the screen with the blue background comes up the buttons don’t highlight as the mouse goes over them



Here’s the code from my controller:

[java]

private String _lastLayer = null;



public void changeLayer(final String newLayerId) {



final Screen currentScreen = (_niftyDisplay).getNifty().getCurrentScreen();



// hide the last layer

if ( _lastLayer != null ) {

final Element layer = currentScreen.findElementByName(_lastLayer);

layer.hide();

}



// end now if we’re not really doing anything

if ( newLayerId == null || newLayerId.equals("<null>") ) {

_lastLayer = null;

return;

}



// set the new layer visible and record it as the last layer

_lastLayer = newLayerId;

final Element layer = currentScreen.findElementByName(_lastLayer);

layer.show();

}

[/java]



Here are my layers:

[xml]

<layer visible=‘false’ id=‘start.confirmQuit’ backgroundColor="#00000000" childLayout=“center”>

<panel id=‘start.confirmQuit.panel0’ align=“center” valign=“center”

backgroundColor="#5599ffff" childLayout=“vertical” height=“40%”

width=“40%”>



<text font=“console.fnt” text=“Do you really want to quit?” align=“center”

valign=“center” />



<panel id=‘start.confirmQuit.panel0.panelYes’ align=“left” valign=“bottom”

backgroundColor="#ffff00ff" childLayout=“vertical” height=“40%”

width=“40%”>



<control name=“button” label=“Yes, quit” align=“center”>

<interact onClick=“raiseEvent(gui.quit)” />

</control>

</panel>

<panel id=‘start.confirmQuit.panel0.panelNo’ align=“right” valign=“bottom”

backgroundColor="#ff0000ff" childLayout=“vertical” height=“40%”

width=“40%”>

<control name=“button” label=“No, do not quit” align=“right”>

<interact onClick=“changeLayer(start.gui)” />

</control>

</panel>

</panel>

</layer>



<layer visible=‘false’ id=“start.gui” backgroundColor="#00000000" childLayout=“center”>

<panel id=‘start.gui.panel0’ align=“center” valign=“bottom”

backgroundColor="#ffffff99" childLayout=“vertical” height=“80%”

width=“55%”>



<text font=“console.fnt” text=“Hello World!” align=“center”

valign=“center” />



<control name=“button” label=“Play” align=“center”>

<interact onClick=“raiseEvent(gui.play)” />

</control>



<control name=“button” label=“Story” align=“center”>

<interact onClick=“raiseEvent(gui.story)” />

</control>



<control name=“button” label=“Reset” align=“center”>

<interact onClick=“changeLayer(start.confirmReset)” />

</control>



<control name=“button” label=“Quit” align=“center”>

<interact onClick=“changeLayer(start.confirmQuit)” />

</control>



</panel>

</layer>

<layer visible=‘false’ id=‘start.confirmReset’ backgroundColor="#00000000" childLayout=“center”>

<panel id=‘start.confirmReset.panel0’ align=“center” valign=“center”

backgroundColor="#5599ffff" childLayout=“vertical” height=“40%”

width=“40%”>

</panel>

</layer>

[/xml]

I have a similar problem.



What I understood is :

You can’t hide a panel wich contains the current focus otherwise Nifty loose where the focus is and you can’t click on buttons anymore.

This is bothersome. I don’t remember if I saw a post on the tracker for that.



There is a work around :

  • First add some identifer to your buttons :

    [java]

    <layer visible=‘false’ id=“start.gui” backgroundColor="#00000000" childLayout=“center”>

    <panel id=‘start.gui.panel0’ align=“center” valign=“bottom”

    backgroundColor="#ffffff99" childLayout=“vertical” height=“80%”

    width=“55%”>



    <text font=“console.fnt” text=“Hello World!” align=“center”

    valign=“center” />



    <control id=“start.gui.play” name=“button” label=“Play” align=“center”>

    <interact onClick=“raiseEvent(gui.play)” />

    </control>



    <control id=“start.gui.story” name=“button” label=“Story” align=“center”>

    <interact onClick=“raiseEvent(gui.story)” />

    </control>



    <control id=“start.gui.confirmReset” name=“button” label=“Reset” align=“center”>

    <interact onClick=“changeLayer(start.confirmReset)” />

    </control>



    <control id=“start.gui.confirmQuit” name=“button” label=“Quit” align=“center”>

    <interact onClick=“changeLayer(start.confirmQuit)” />

    </control>



    </panel>

    </layer>

    [/java]


  • Then in your screencontroller, fill the bind(…) method :

    [java]

    @Override

    public final void bind( Nifty nifty, Screen screen )

    {

    screen.findElementByName(“start.gui.play”).setFocusable( false );

    screen.findElementByName(“start.gui.story”).setFocusable( false );

    screen.findElementByName(“start.gui.confirmReset”).setFocusable( false );

    screen.findElementByName(“start.gui.confirmQuit”).setFocusable( false );

    }

    [/java]



    You won’t have focus problems anymore but you won’t be able to use the keybords key to select the buttons.
1 Like

Yuck … w00+ w00+ it works!



I’m using this:

EDIT this may be really, broken - it seems to be swapping the resetConfim interaction for the quit confirm one … but I’m out of time

[java]

// use an XPath statement to automate this and complain for all controls that lack an ID value

try {



final DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();

builderFactory.setNamespaceAware(true);

final Document parsedDocument = builderFactory.newDocumentBuilder().parse(getClass().getResourceAsStream("/"+_file));



final XPath newXPath = XPathFactory.newInstance().newXPath();



// TODO : this does not work right

if ( ((NodeList)newXPath.compile("//control[not(@id)]").evaluate(parsedDocument, XPathConstants.NODESET)).getLength() > 0 ) {

throw new IllegalArgumentException(“All control tags must have ids”);

}



final NodeList nodeList = (NodeList) newXPath.compile("//control/@id")

.evaluate(parsedDocument, XPathConstants.NODESET);

for (int i = 0; i < nodeList.getLength(); i++) {

screen.findElementByName(nodeList.item(i).getNodeValue()).setFocusable(false);

}

} catch (XPathExpressionException e) {

// TODO Auto-generated catch block

throw new RuntimeException(“TODO Auto-generated catch block”, e);

} catch (SAXException e) {

// TODO Auto-generated catch block

throw new RuntimeException(“TODO Auto-generated catch block”, e);

} catch (IOException e) {

// TODO Auto-generated catch block

throw new RuntimeException(“TODO Auto-generated catch block”, e);

} catch (ParserConfigurationException e) {

// TODO Auto-generated catch block

throw new RuntimeException(“TODO Auto-generated catch block”, e);

}

[/java]

Personally I created a MessagePanel control for just this. This control creates a pop-up on the screen in the form of a panel, not a layer. At the moment this panel needs to be defined on the screen itself, but I am going to change this to use the new builder patter so I can add and remove it on the fly. This would make for a much cleaner solution since it won’t require you to add anything to your screen XML to be able to use it.



control xml



implementation in a page:

[xml]

<panel id=“error” childLayout=“horizontal” align=“center” width=“250px” height=“100px”>

<panel childLayout=“horizontal” height=“25px” />

<control id=“errorPanel” name=“messagePanel” />

</panel>

[/xml]



controller code



Implementation of the controller:

[java]

Element errorPanel = nifty.getCurrentScreen().findElementByName(“error”);

MessageController errorController = errorPanel.findElementByName(“errorPanel”).getControl(MessageController.class);

errorController.showMessage(“error:” + eMsg.getErrorMessage(), “resources/error.jpg”);

[/java]



This works like a charm for me, although you might need to tweak the controller and the xml a bit since I’m using Nifty 1.3. If you want I should have the Nifty 1.2 version in my svn somewhere as well.

1 Like

hidden elements will correctly lose focus in Nifty 1.3…

Whoa … this thread seems like months ago



JME’s still using 1.2-SNAPSHOT, how hard would it be to update it to 1.3?

It will happen. Soon.