Menu System with nifty gui (Contribution and Support)

Hello,

I am doing my first steps with nifty and have to say it is great. Thanks for your efforts.

For my game I tried to implement a menu system. Currently it looks as follows:[video]http://youtu.be/IgMCsEypSQs[/video]
The code looks as follows:

[java]

public class MenuItem {
public String name;
public boolean isEnabled;
public boolean hasSubmenu;
public Menu subMenu;
public boolean isSelected;
}

import java.util.HashMap;

import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;

public class NiftyScreenController implements ScreenController {
private Nifty nifty;
private HashMap<String, Menu> menuMap;
static NiftyScreenController instance;

static public NiftyScreenController getInstance() {
	if (instance == null)
		instance = new NiftyScreenController();
	return instance;
}
private  NiftyScreenController() {
	menuMap = new HashMap&lt;String, Menu&gt; ();
}

public void setNifty(Nifty nifty) {
	this.nifty = nifty;
}

public void registerMenu(Menu menu) {
	if (!menuMap.entrySet().contains(menu))
		menuMap.put(menu.getID(), menu);
}

public void bind(Nifty nifty, Screen screen) {
	System.out.println("bind( " + screen.getScreenId() + ")");
}

public void onStartScreen() {
	System.out.println("onStartScreen");
}

public void onEndScreen() {
	System.out.println("onEndScreen");
}

public void quit(){
	nifty.gotoScreen("end");
}

public void showMenu() {
	if (menuMap.containsKey("menu"))
		menuMap.get("menu").show();
}

public void mouseOverMenu(String menuID, String elementId) {
	if (menuMap.containsKey(menuID)) {
		menuMap.get(menuID).mouseOver(elementId);
	}
}

public void menuClicked(String menuID, String elementId) {
	if (menuMap.containsKey(menuID)) {
		menuMap.get(menuID).menuClicked(elementId);
	}
}

public void close(String name) {
	if (menuMap.containsKey("menu"))
		menuMap.get("menu").close();

}

}

import java.util.Vector;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.builder.EffectBuilder;
import de.lessvoid.nifty.builder.PopupBuilder;
import de.lessvoid.nifty.controls.dynamic.ImageCreator;
import de.lessvoid.nifty.controls.dynamic.PanelCreator;
import de.lessvoid.nifty.controls.dynamic.TextCreator;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.render.PanelRenderer;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.tools.Color;

public class Menu {

static int widthPercent=12;
static int heightPercent=4;
static int horizontalSpace=1;
static String backgroundString = "#333a";
static String highlightedBackgroundString = "#888a";
static Color backgroundColor = new Color(backgroundString);
static Color highlightedBackgroundColor = new Color(highlightedBackgroundString);
protected int x;
protected int y;
Vector&lt;MenuItem&gt; menuItems;
Vector&lt;Element&gt; panels;
Vector&lt;Element&gt; texts;
Vector&lt;Element&gt; oks;
protected Screen screen;
protected Nifty nifty;
protected boolean isHorizontal;
protected int numberRows;
protected Menu parentMenu;
protected String id;
protected boolean isToggleMenu;
Element popup;
Element panel;
int highlightedIndex = -1;

public Menu(Nifty nifty, Screen screen, int x, int y, boolean isHorizontal, int numberRows) {
	this.nifty = nifty;
	this.screen = screen;
	this.x = x;
	this.y = y;
	this.isHorizontal = isHorizontal;
	this.numberRows = numberRows;
	menuItems = new Vector&lt;MenuItem&gt;();
	panels = new Vector&lt;Element&gt;();
	texts = new Vector&lt;Element&gt;();
	oks = new Vector&lt;Element&gt;();
	this.parentMenu = null;
	this.id =  "menu";
	this.isToggleMenu = false;
}

public Menu(Nifty nifty, Screen screen, boolean isToggleMenu) {
	this(nifty, screen,0,0,false, 0);
	this.isToggleMenu = isToggleMenu;
}

public String getID() {
	return id;
}
public void setID(String id) {
	this.id = id;
}

public void addMenuItem(String name, boolean isEnabled, Menu subMenu) {
	MenuItem menuItem = new MenuItem();
	menuItem.name = name;
	menuItem.isEnabled = isEnabled;
	menuItem.subMenu = subMenu;
	menuItem.hasSubmenu = (subMenu != null);
	menuItems.add(menuItem);
}

public void setXYandIdAndParent(int x, int y, String id, Menu parentMenu) {
	this.x = x;
	this.y = y;
	this.id = id;
	this.parentMenu = parentMenu;
}

public void build() {
	NiftyScreenController.getInstance().registerMenu(this);
	int localX = x;
	int localY = y;
	if (isHorizontal) {
		localY += heightPercent; 
		localX -= widthPercent + horizontalSpace;
	}
	else {
		localX += widthPercent;
		localY -= heightPercent;
	}
	for (int i=0; i &lt; menuItems.size(); i++) {
		if (isHorizontal)
			localX += widthPercent + horizontalSpace;
		else
			localY += heightPercent;
		if (menuItems.get(i).subMenu != null) {
			menuItems.get(i).subMenu.setXYandIdAndParent(localX, localY, id + "." + i, this);
			menuItems.get(i).subMenu.build();
		}
	}
	buildNifty();
}

protected void buildNifty() {
	int localX = x;
	int localY = y;
	PopupBuilder pb = new PopupBuilder("popupBuilder" + id);
	pb.childLayoutAbsolute();
	pb.interactOnClick("close(popup" + id + ")");
	pb.registerPopup(nifty);
	popup = nifty.createPopupWithId("popupBuilder" + id, "popup" + id);
	PanelCreator panelB = new PanelCreator("panelBuilder" + id);
	if (isHorizontal) {
		panelB.setChildLayout("absolute");
		panelB.setWidth("100%");
		panelB.setHeight("" + heightPercent + "%");
	}
	else {
		panelB.setChildLayout("absolute");
		panelB.setWidth("100%");
		panelB.setHeight("100%");
	}
	panel = panelB.create(nifty, screen, popup);

	for (int i=0; i &lt; menuItems.size(); i++) {
		PanelCreator panelC = new PanelCreator(id +  i);
		panelC.setChildLayout("horizontal");
		panelC.setBackgroundColor(backgroundString);
		panelC.setInteractOnMouseOver("mouseOverMenu(" + id + ","+ i + ")");
		panelC.setInteractOnClick("menuClicked(" + id + ","+ i + ")");
		EffectBuilder eb = new EffectBuilder("fade");
		if (isHorizontal) {
			panelC.setHeight("100%");
			panelC.setWidth("" + (widthPercent) + "%");
		}
		else {
			panelC.setHeight("" + heightPercent + "%");
			panelC.setWidth("" + (widthPercent) + "%");		
		}

		panelC.setX("" + localX + "%");
		panelC.setY("" + localY + "%");
		Element p = panelC.create(nifty, screen, panel);
		panels.add(p);
		if (isToggleMenu) {
			ImageCreator ic = new ImageCreator(id + "image" + i);
			ic.setFilename("ok.png");
			ic.setBackgroundImage("ok.png");
			ic.setImageMode("normal");
			ic.setWidth("15%");
			ic.setHeight("75%");
			Element im = ic.create(nifty, screen, p);
			im.hide();
			oks.add(im);			
		}
		TextCreator tb = new TextCreator("text" + id + i);
		tb.setWidth("84%");
		tb.setHeight("100%");
		tb.setColor("777f");
		tb.setTextHAlign("center");
		tb.setFont("aurulent-sans-16.fnt");
		tb.setText(menuItems.get(i).name);
		texts.add(tb.create(nifty, screen, p));
		if (!isHorizontal &amp;&amp; menuItems.get(i).subMenu != null) {
			ImageCreator ic2 = new ImageCreator("pfeil" + id + i);
			ic2.setFilename("pfeil.png");
			ic2.setBackgroundImage("pfeil.png");
			ic2.setWidth("7%");
			ic2.setHeight("100%");
			ic2.create(nifty, screen, p);
		}
		if (isHorizontal) {
			localX += widthPercent + horizontalSpace;
		}
		else {
			localY += heightPercent;
		}

	}
}

public void mouseOver(String itemIndex) {
	int index = Integer.parseInt(itemIndex);
	if (index != highlightedIndex) {
		if (highlightedIndex &gt;= 0) {
			panels.get(highlightedIndex).getRenderer(PanelRenderer.class).setBackgroundColor(backgroundColor);
			if (menuItems.get(highlightedIndex).subMenu != null) {
				menuItems.get(highlightedIndex).subMenu.close();
			}
		}
		highlightedIndex = index;
		panels.get(highlightedIndex).getRenderer(PanelRenderer.class).setBackgroundColor(highlightedBackgroundColor);		

		if (menuItems.get(index).subMenu != null)
			menuItems.get(index).subMenu.show();
	}
}

public void menuClicked(String itemIndex) {
	int index = Integer.parseInt(itemIndex);

	if (menuItems.get(index).subMenu != null) {
		menuItems.get(index).subMenu.show();
	}
	else {
		if (isToggleMenu) {
			if (!menuItems.get(index).isSelected)
				select(index);
		}
		else
			close();
	}
}

public void show() {
	nifty.showPopup(screen, "popup" + id, null);
}

public void close() {
	for (int i=0; i &lt; menuItems.size(); i++) {
		if (menuItems.get(i).subMenu != null)
			menuItems.get(i).subMenu.close();
	}
	if (highlightedIndex &gt;= 0) {
		panels.get(highlightedIndex).getRenderer(PanelRenderer.class).setBackgroundColor(backgroundColor);
		highlightedIndex = -1;
	}
	nifty.closePopup("popup" + id);
}

public void select(int index) {
	for (int i=0; i &lt; menuItems.size(); i++) {
		if (i==index) {
			oks.get(i).show();
		}
		else
			oks.get(i).hide();
	}
}

}

import Menu;
import NiftyScreenController;

import com.jme3.app.SimpleApplication;
import com.jme3.niftygui.NiftyJmeDisplay;

import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.builder.ScreenBuilder;
import de.lessvoid.nifty.builder.StyleBuilder;
import de.lessvoid.nifty.controls.dynamic.LayerCreator;
import de.lessvoid.nifty.screen.Screen;

public class TestMenu extends SimpleApplication {

private Nifty nifty;
private Screen screen;
Menu mainMenu;

public static void main(String[] args){
	TestMenu app = new TestMenu();
	app.setPauseOnLostFocus(false);
	app.start();
}

public void simpleInitApp() {

	NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager,
			inputManager,
			audioRenderer,
			guiViewPort);
	nifty = niftyDisplay.getNifty();
	nifty.loadStyleFile("nifty-default-styles.xml");
	nifty.loadControlFile("nifty-default-controls.xml");
	nifty.loadStyleFile("button/nifty-button.xml");
	nifty.loadStyleFile("checkbox/nifty-checkbox.xml");
	new StyleBuilder() {{
		id("myStyle");
		backgroundColor("#8fff");
		font("aurulent-sans-16.fnt");
		height("100%");
	}}.build(nifty);
	
	NiftyScreenController.getInstance().setNifty(nifty);
	nifty.registerScreenController(NiftyScreenController.getInstance());
	ScreenBuilder sb = new ScreenBuilder("start");
	sb.controller(NiftyScreenController.getInstance());
	screen = sb.build(nifty);
	LayerCreator lc = new LayerCreator("ii");
	lc.setChildLayout("center");
	lc.createType();
	lc.setInteractOnClick("showMenu()");
	lc.create(nifty, screen, screen.getRootElement());

	nifty.addScreen("id_screen", screen);
	guiViewPort.addProcessor(niftyDisplay);
	nifty.gotoScreen("id_screen");

	mainMenu = new Menu(nifty,screen,0,0,true,1);

	Menu subMenu1 = new Menu(nifty,screen, false);
	subMenu1.addMenuItem("SubMenu1", true, null);
	subMenu1.addMenuItem("SubMenu2", true, null);
	subMenu1.addMenuItem("SubMenu3", true, null);
	subMenu1.addMenuItem("SubMenu4", true, null);
	
	Menu subMenu2 = new Menu(nifty,screen, false);
	Menu subsubMenu223 = new Menu(nifty,screen, true);
	subsubMenu223.addMenuItem("SubMenu1", true, null);
	subsubMenu223.addMenuItem("SubMenu2", true, null);
	subsubMenu223.addMenuItem("SubMenu3", true, null);
	subsubMenu223.addMenuItem("SubMenu4", true, null);
	subsubMenu223.addMenuItem("SubMenu5", true, null);		

	Menu subsubMenu22 = new Menu(nifty,screen, false);
	subsubMenu22.addMenuItem("SubMenu1", true, null);
	subsubMenu22.addMenuItem("SubMenu2", true, subsubMenu223);
	subsubMenu22.addMenuItem("SubMenu3", true, null);
	subsubMenu22.addMenuItem("SubMenu4", true, null);
	subsubMenu22.addMenuItem("SubMenu5", true, null);		
	Menu subsubMenu23 = new Menu(nifty,screen, true);
	subsubMenu23.addMenuItem("SubMenu1", true, null);
	subsubMenu23.addMenuItem("SubMenu2", true, null);
	subsubMenu23.addMenuItem("SubMenu3", true, null);
	subsubMenu23.addMenuItem("SubMenu4", true, null);
	subsubMenu23.addMenuItem("SubMenu5", true, null);		
	subMenu2.addMenuItem("SubMenu1", true, null);
	subMenu2.addMenuItem("SubMenu2", true, subsubMenu22);
	subMenu2.addMenuItem("SubMenu3", true, subsubMenu23);
	subMenu2.addMenuItem("SubMenu4", true, null);
	subMenu2.addMenuItem("SubMenu5", true, null);

	Menu subMenu3 = new Menu(nifty,screen, false);
	subMenu3.addMenuItem("SubMenu1", true, null);
	subMenu3.addMenuItem("SubMenu2", true, null);
	subMenu3.addMenuItem("SubMenu3", true, null);
	subMenu3.addMenuItem("SubMenu4", true, null);

	Menu subMenu4 = new Menu(nifty,screen, true);
	subMenu4.addMenuItem("SubMenu1", true, null);
	subMenu4.addMenuItem("SubMenu2", true, null);
	subMenu4.addMenuItem("SubMenu3", true, null);
	subMenu4.addMenuItem("SubMenu4", true, null);

	mainMenu.addMenuItem("Menu1", true, subMenu1);
	mainMenu.addMenuItem("Menu2", true, subMenu2);		
	mainMenu.addMenuItem("Menu3", true, subMenu3);
	mainMenu.addMenuItem("Menu4", true, subMenu4);
	mainMenu.build();




	// disable the fly cam
	flyCam.setEnabled(false);
	flyCam.setDragToRotate(true);
	inputManager.setCursorVisible(true);

}

}

[/java]

It works in principle well, but i get sometimes ArrayOutOfBounds Exceptions in the FocusHandler. They can be avoided, if the method popState is changed as follows:

[java]
public void popState() {
entries.clear();
entries.addAll(elementBuffer.get(elementBuffer.size() - 1));
// This line is new:
if (keyboardFocusElementBuffer.size()>0)
setKeyFocus(keyboardFocusElementBuffer.remove(keyboardFocusElementBuffer.size() - 1));
// This line is new:
if (mouseFocusElementBuffer.size() > 0)
mouseFocusElement = mouseFocusElementBuffer.remove(mouseFocusElementBuffer.size() - 1);

    mouseFocusElement = null;

}
[/java]

I do not understand the nifty gui enough to see, if there is a problem in my code or if the nifty code should be changed accordingly.
Thanks for your help.

Michael

1 Like