package com.bitwaffle.spaceguts.graphics.gui.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FilenameFilter; import org.lwjgl.opengl.GL11; import org.newdawn.slick.opengl.Texture; import com.bitwaffle.spaceguts.audio.Audio; import com.bitwaffle.spaceguts.graphics.gui.GUI; import com.bitwaffle.spaceguts.graphics.gui.GUIObject; import com.bitwaffle.spaceguts.graphics.gui.button.MenuButton; import com.bitwaffle.spaceguts.graphics.gui.menu.picker.Picker; import com.bitwaffle.spaceguts.physics.Physics; import com.bitwaffle.spaceguts.util.Debug; import com.bitwaffle.spaceguts.util.DisplayHelper; import com.bitwaffle.spaceguts.util.xml.EntitiesParser; import com.bitwaffle.spaceout.resources.Sounds; import com.bitwaffle.spaceout.resources.Textures; /** * Menu to load an XML file. * * @author TranquilMarmot * */ public class LoadMenu extends GUIObject { private Texture background; /** The FilePicker to choose the file */ private Picker<XMLFile> picker; /** button to load the selected file */ private MenuButton loadButton; /** button to go back to the main menu */ private MenuButton backButton; /** whether or not to go back to the main menu on the next update */ private boolean backToMainMenu; /** * whether or not a file has been loaded (if it has, get rid of this menu * and create the pause menu) */ private boolean fileLoaded; /** * Load menu constructor * * @param x * X location of the menu * @param y * Y location of the menu * @param path * The directory to look for files in */ public LoadMenu(int x, int y, final String path) { super(x, y); backToMainMenu = false; fileLoaded = false; // create file picker picker = new Picker<XMLFile>(-50, -20, 20, 200, new XMLFile(path).listFiles(), Textures.MENU_PICKER_ACTIVE, Textures.MENU_PICKER_MOUSEOVER, Textures.MENU_PICKER_PRESSED, Textures.MENU_PICKER_SELECTED); // create load button loadButton = new MenuButton("Load", 119, 28, 115, -17); loadButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(picker.itemHasBeenSelected()){ // initialize physics Physics.initPhysics(); // load entities from XML EntitiesParser.loadEntitiesFromXmlFile(picker.getSelectedItem().getPath()); // create the pause menu GUI.addGUIObject(new PauseMenu()); // raise the file loaded flag fileLoaded = true; Debug.displayDebug = false; } } }); // create the back to main menu button backButton = new MenuButton("Back", 119, 28, 115, 17); backButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Audio.playSoundOnceAtListener(Sounds.BACK); // raise the back to main menu flag backToMainMenu = true; } }); // grab the image (NOTE: this is initialized in MainMenu's constructor) background = Textures.MENU_BACKGROUND2.texture(); } @Override public void update() { picker.update(); loadButton.update(); backButton.update(); if (backToMainMenu) { // remove the load menu GUI.removeGUIObject(this); // add the main menu GUI.addGUIObject(new MainMenu()); } if (fileLoaded) { // remove the load menu GUI.removeGUIObject(this); // let the GUI know that there's no menu up GUI.menuUp = false; } } @Override public void draw() { // draw the background background.bind(); GL11.glBegin(GL11.GL_QUADS); { /* * currentImage.getWidth() and currentImage.getHeight() return the * actual height of the texture. My best guess is that the image * gets put into the smallest possible texture that has dimensions * that are powers of 2 by Slick, because OpenGL can handle those * much better. */ GL11.glTexCoord2f(0, 0); GL11.glVertex2i(0, 0); GL11.glTexCoord2f(background.getWidth(), 0); GL11.glVertex2i(DisplayHelper.windowWidth, 0); GL11.glTexCoord2f(background.getWidth(), background.getHeight()); GL11.glVertex2i(DisplayHelper.windowWidth, DisplayHelper.windowHeight); GL11.glTexCoord2f(0, background.getHeight()); GL11.glVertex2i(0, DisplayHelper.windowHeight); } GL11.glEnd(); picker.draw(); loadButton.draw(); backButton.draw(); Debug.drawVersion(); } @SuppressWarnings("serial") /** * Since the Picker class uses toString to decide what to print out on each ListItem, * but File's toString returns the whole path and not just the file name like we want. * This class extends File and basically just overrides its toString to return just the * name of the file. * * For convenience, there's another inner class in this inner class that filters the files * so that only files with ".xml" are listed. * @author TranquilMarmot * */ class XMLFile extends File{ /** * @param pathname Path to file */ public XMLFile(String pathname) { super(pathname); } /** * @param file File to create XMLFile from */ public XMLFile(File file){ this(file.getAbsolutePath()); } @Override /** * @return Just the file name! That is, everything between the last \ and the last . */ public String toString(){ String path = this.getPath(); int lastSlash = 0, dotIndex = 0; char[] chars = path.toCharArray(); // find the last . for(int i = chars.length - 1; i >= 0; i--){ if(chars[i] == '.'){ dotIndex = i; break; } } // slash changes depending on operating system char slash; String opSys = System.getProperty("os.name").toLowerCase(); if(opSys.contains("windows")) slash = '\\'; else slash = '/'; // find the last \ for(int i = chars.length - 1; i >= 0; i--){ if(chars[i] == slash){ lastSlash = i; break; } } String fileName = path.substring(lastSlash + 1, dotIndex); return fileName; } @Override /** * Lists all files ending with ".xml" */ public XMLFile[] listFiles(){ File[] files = this.listFiles(new XMLFilter()); XMLFile[] cast = new XMLFile[files.length]; for(int i = 0; i < files.length; i++){ cast[i] = new XMLFile(files[i]); } return cast; } /** * Filters out classes not ending in ".xml" * @author TranquilMarmot * */ class XMLFilter implements FilenameFilter{ @Override public boolean accept(File directory, String filename) { CharSequence xml = ".xml"; if(filename.contains(xml)) return true; else return false; } } } }