Windows in control definitions not allowed?

Hello,



I have a control definition in my gui XML file and a screen called “start”. It all works fine. When I add a window to the control definition, however, it says “WARNING: screen [start] not found”.



This works fine:



[xml]

<controlDefinition name=“errorwindow” controller=“myGame.gui.ErrorWindowControl”>



</controlDefinition>

[/xml]



But when I add this, the above warning occurs:



[xml]

<controlDefinition name=“errorwindow” controller=“myGame.gui.ErrorWindowControl”>

<control name=“window” id=“test”>



</control>

</controlDefinition>

[/xml]



So are windows in control definitions not allowed or is this a bug?

This was indeed a bug! I’ve fixed that in git for Nifty 1.3.1 now.



Some background information: You can use the control tag inside of controlDefinition without any problems when it is added to a panel that exists inside of a controlDefinition. If you add it directly as a child element to the controlDefinition itself you’ll run into this issue (which is now fixed).



A thing to keep in mind is, that when you use the controlDefinition, then the very first child element of the controlDefinition IS the element that is inserted into the element tree when you use the control you’ve defined with the controlDefinition. So in your case you’ll have the window control where you finally use . I think in your case you are aware of this but in other cases it might not be that obvious.

Alright, some more questions on this:



When I have a window as top element in the control definition and I use my new control, I can see the window and all, but somehow it is not draggable. I also can’t click on the x to close/hide it (When I have buttons inside I can click on them just fine). Do I have to add something to enable this feature?



Now that we speak about buttons:



Is it possible to add interact tags for buttons inside control definitions? If so, when I have an onClick attribute for them, which controller object’s methods does it call?



And last but not least:



Can I override the behavior of the default close button(x) on windows?

Did you add your control to a childLayout=“absolute” layer? This works for me:



[xml]<?xml version="1.0" encoding="UTF-8"?>

<nifty xmlns="http://nifty-gui.sourceforge.net/nifty-1.3.xsd&quot; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd&quot;&gt;

<useStyles filename="nifty-default-styles.xml" />

<useControls filename="nifty-default-controls.xml" />



<controlDefinition name="errorwindow">

<control name="window" id="test" />

</controlDefinition>



<screen id="start">

<layer childLayout="absolute" backgroundColor="#f008">

<control name="errorwindow" x="10" y="10" width="100" height="100" />

</layer>

</screen>

</nifty>[/xml]



I see the Window, I can drag it and I can close it.


Is it possible to add interact tags for buttons inside control definitions? If so, when I have an onClick attribute for them, which controller object’s methods does it call?


Sure, should work. They will go to the innermost controller first, up the whole hierachy to the ScreenController. So in your original example the method will first be looked up at "myGame.gui.ErrorWindowControl" and if Nifty can't find it there it will look up the method at the current ScreenController.

Can I override the behavior of the default close button(x) on windows?


No, not currently. Unless you find the "nifty-window.xml" in the controls project and change it or use it as the template for your own window control ...

The strange thing is: once I add a controller reference to my errorwindow the actual window is somehow not draggable anymore and the x button doesn’t do anything either.

Ah! :slight_smile: No, not strange. Now it makes sense!



Since the window control becomes your control all events that the Window generates (drag’n’drop, close button, etc.) will go to your controller and since you don’t handle all of it, well, nothing happens.


A thing to keep in mind is, that when you use the controlDefinition, then the very first child element of the controlDefinition *IS* the element that is inserted into the element tree when you use the control you’ve defined with the controlDefinition. So in your case you’ll have the window control where you finally use.


What you can do is something like:

[java]package myGame.gui.ErrorWindowControl;

import de.lessvoid.nifty.controls.window.WindowControl;

public class ErrorWindowControl extends WindowControl {
// your stuff here but make sure to call super for things you override
}[/java]

The only method I’ve overriden is bind. I called super.bind(nifty, screen, element, parameter, controlDefinitionAttributes);



Still not working.

This works for me:



[xml]<?xml version="1.0" encoding="UTF-8"?>

<nifty >

<useStyles filename="nifty-default-styles.xml" />

<useControls filename="nifty-default-controls.xml" />



<controlDefinition name="errorwindow" controller="de.lessvoid.nifty.examples.helloworld.Stuff">

<control name="window" id="test" />

</controlDefinition>



<screen id="start">

<layer childLayout="absolute" backgroundColor="#f008">

<control name="errorwindow" x="10" y="10" width="100" height="100" />

</layer>

</screen>

</nifty>[/xml]



[java]package de.lessvoid.nifty.examples.helloworld;



import de.lessvoid.nifty.controls.window.WindowControl;



public class Stuff extends WindowControl {

}[/java]



I can move the window around and I can close it.

Same, but as I said, when I override bind, it doesn’t work anymore.



So I must be missing something else, because I do super.bind(…).



/edit:



I think I found the problem. The problem is that I am trying to get the window’s children with element.findNiftyControl(childrenname, children.class).

However, this freezes the window. So is there a way to get the window’s children without freezing the window?

Please be more specific!



Again, this works for me quite well:



[xml]<?xml version="1.0" encoding="UTF-8"?>

<nifty >

<useStyles filename="nifty-default-styles.xml" />

<useControls filename="nifty-default-controls.xml" />



<controlDefinition name="errorwindow" controller="de.lessvoid.nifty.examples.helloworld.Stuff">

<control id="test" name="window">

<control id="button" name="button" label="OK" />

</control>

</controlDefinition>



<screen id="start">

<layer childLayout="absolute" backgroundColor="#f008">

<control name="errorwindow" x="10" y="10" width="100" height="100" />

</layer>

</screen>

</nifty>[/xml]



[java]package de.lessvoid.nifty.examples.helloworld;



import java.util.Properties;



import de.lessvoid.nifty.Nifty;

import de.lessvoid.nifty.controls.Button;

import de.lessvoid.nifty.controls.window.WindowControl;

import de.lessvoid.nifty.elements.Element;

import de.lessvoid.nifty.screen.Screen;

import de.lessvoid.xml.xpp3.Attributes;



public class Stuff extends WindowControl {



@Override

public void bind(

Nifty nifty,

Screen screen,

Element element,

Properties parameter,

Attributes controlDefinitionAttributes) {

super.bind(nifty, screen, element, parameter, controlDefinitionAttributes);



Button button = element.findNiftyControl("button", Button.class);

button.setText("TEST");

}

}[/java]

Alright, here is my ErrorWindowControl:



[java]public class ErrorWindowControl extends WindowControl implements ErrorWindow {



private static final String LABEL_NAME = “errortext”;

private static final String BUTTON_NAME = “okbutton”;

/** Holds the error text. /

private Label m_errorText;

/
* Holds the next messages being displayed after the current has been closed. */

private Queue<String> m_errorMessageQueue;



@Override

public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {

super.bind(nifty, screen, element, parameter, controlDefinitionAttributes);



m_errorMessageQueue = new LinkedList<String>();



m_errorText = element.findNiftyControl(LABEL_NAME, Label.class);



super.closeWindow();

}



@Override

public void closeWindow() {

if(m_errorText != null) {

if(this.getElement().isVisible()) {

if(m_errorMessageQueue.peek() != null) {

m_errorText.setText(m_errorMessageQueue.poll());

super.closeWindow();



new Thread(new Runnable() {



@Override

public void run() {

try {

Thread.sleep(500);

} catch(Exception e) {}



ErrorWindowControl.this.getElement().show();

}

}).start();

} else {

m_errorText.setText("");

super.closeWindow();

}

}

}

}



@Override

public void popUpMessage(String errorMessage) {

if(m_errorText != null) {

if(this.getElement().isVisible()) {

m_errorMessageQueue.offer(errorMessage);

} else if(m_errorMessageQueue.peek() != null) {

m_errorMessageQueue.offer(errorMessage);

} else {

this.getElement().show();

m_errorText.setText(errorMessage);

}

}

}



@Override

public void clearWindow() {

if(m_errorText != null) {

m_errorMessageQueue.clear();

m_errorText.setText("");



if(this.getElement().isVisible())

super.closeWindow();

}

}

}[/java]



In the controller of the start screen I do the following:



[java] @Override

public void onStartScreen() {



if(m_errorDisplayWindow != null)

m_errorDisplayWindow.popUpMessage(“TEST”);

}[/java]



This method call makes the window freeze. I can see the “TEST” message on the window, but it’s frozen.



My control definition:



[xml] <controlDefinition name=“errorwindow” controller=“evocri3Dclient.gui.ErrorWindowControl”>

<control name=“window” id=“errorwindow” title=“Error” hideOnClose=“true” backgroundColor="#303030FF" width=“350px” height=“150px”>

<panel childLayout=“vertical” backgroundColor="#00000000" height=“100%” width=“100%”>

<panel childLayout=“horizontal” backgroundColor="#00000000" height=“85%”>

<image filename=“Interface/error.png” />

<control name=“label” id=“errortext” color="#000000FF" text="" align=“center” />

</panel>

<panel childLayout=“center” backgroundColor="#00000000" height=“15%”>

<control name=“button” id=“okbutton” label=“OK” width=“50%” align=“center” />

</panel>

</panel>

</control>

</controlDefinition>[/xml]



I have no idea what’s wrong. Any help?

How is m_errorDisplayWindow created in your ScreenController? You’ve left that out but I think it’s essential.



What is that Thread doing in the closeWindow() method? O_o This scares me…



Can you describe what you’d like to do? I don’t quite get it …

The m_errorDisplayWindow creation:



[java] @Override

public void bind(Nifty nifty, Screen screen) {

m_errorDisplayWindow = screen.findNiftyControl(“err_0”, ErrorWindow.class);

}

[/java]



In the controller.



That thread is waiting half a second and then it pops up the error window again with the next message it should display. I added it there so that the gui thread won’t be blocked.



The methods should do:



closeWindow(): Close the window if it is open. If there are more error messages to be displayed it should pop it up again after half a second and display the next error message.



popUpMessage(): Pop up the window if it is closed with the given error message. If the window already displays a message, it should queue the message to be displayed after the current message has been closed (so that I can display multiple error messages without having an unlimited amount of error windows).



clearWindow(): Clear everything and close the window.