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<String, Menu> ();
}
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<MenuItem> menuItems;
Vector<Element> panels;
Vector<Element> texts;
Vector<Element> 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<MenuItem>();
panels = new Vector<Element>();
texts = new Vector<Element>();
oks = new Vector<Element>();
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 < 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 < 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 && 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 >= 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 < menuItems.size(); i++) {
if (menuItems.get(i).subMenu != null)
menuItems.get(i).subMenu.close();
}
if (highlightedIndex >= 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 < 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