package toritools.leveleditor; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Event; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.filechooser.FileNameExtensionFilter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import toritools.entity.Entity; import toritools.entity.Level; import toritools.entity.ReservedTypes; import toritools.io.Importer; import toritools.map.ToriMapIO; import toritools.map.VariableCase; import toritools.math.Vector2; import toritools.scripting.ScriptUtils; import toritools.xml.ToriXML; /** * The core level editor. What a mess! :D * * @author toriscope * */ public class LevelEditor { private final String configFile = "editor.conf"; /** * The current level file being edited. */ private File levelFile; File workingDirectory; /** * Map of int layers to list of existing entities. */ private List<Entity> entities = new ArrayList<Entity>(); /** * The current placeable entity. */ private Entity current = null; /** * The currently selected entity. */ private Entity selected = null; /** * The panel where the entity selection buttons are added and removed. */ private JPanel buttonPanel = new JPanel(); /** * The root frame. */ private JFrame frame = new JFrame("ToriEditor"); /************** * EDITOR VARIABLES **************/ /** * Size of the grid. Usually square for now. */ private Dimension gridSize = new Dimension(32, 32); /** * This object handles layering information. */ private LayerEditor layerEditor = new LayerEditor(this); /** * This object handles instance variables. */ private VariableEditor varEditor = new VariableEditor(this); /** * This object handles instance variables. */ private BackgroundEditor bgEditor = new BackgroundEditor(this); /** * The text of this is where you can set some neat data to display to the * user. */ private JLabel fileLabel = new JLabel("FILE LABEL"); private JLabel gridLabel = new JLabel("GRID LABEL"); private JLabel levelSizeLabel = new JLabel("WORLD SIZE LABEL"); private JLabel editModeLabel = new JLabel("EDITMODE"); private Vector2 wallStart, wallEnd; private Entity moving; VariableCase variables = new VariableCase(); private enum Mode { WALL_QUEUE, WALL_MAKING, MOVING, PLACE, BG } private Mode mode = Mode.PLACE; /** * Mouse controller. */ private MouseAdapter mouseAdapter = new MouseAdapter() { @Override public void mousePressed(MouseEvent m) { if (mode == Mode.WALL_QUEUE) { wallStart = wallEnd = getClosestGridPoint(new Vector2(m.getPoint())); mode = Mode.WALL_MAKING; } else if (mode == Mode.BG) { if (m.getButton() == MouseEvent.BUTTON3) { for (Entity e : getOverlapping(new Vector2(m.getPoint()))) { if (ReservedTypes.BACKGROUND.equals(e.getType())) { entities.remove(e); } repaint(); } } else { List<Entity> bgs = bgEditor.makeEntities(getClosestGridPoint(new Vector2(m.getPoint()))); for (Entity bg : bgs) { bg.setLayer(layerEditor.getCurrentLayer()); addEntity(bg); } } } else { if (m.getButton() == MouseEvent.BUTTON1) for (Entity ent : entities) { if (new Rectangle.Float(ent.getPos().x, ent.getPos().y, ent.getDim().x, ent.getDim().y) .contains(m.getPoint())) { moving = ent; break; } } } repaint(); } @Override public void mouseDragged(MouseEvent m) { if (mode == Mode.WALL_MAKING) { wallEnd = getClosestGridPoint(new Vector2(m.getPoint())); } else if (moving != null) { moving.setPos(getClosestGridPoint(new Vector2(m.getPoint()))); } repaint(); } @Override public void mouseReleased(MouseEvent m) { if (mode == Mode.WALL_MAKING) { mouseDragged(m); if (wallEnd.x < wallStart.x) { float temp = wallStart.x; wallStart = new Vector2(wallEnd.x, wallStart.y); wallEnd = new Vector2(temp, wallEnd.y); } if (wallEnd.y < wallStart.y) { float temp = wallStart.y; wallStart = new Vector2(wallStart.x, wallEnd.y); wallEnd = new Vector2(wallEnd.x, temp); } Vector2 wallDim = wallEnd.sub(wallStart); if (wallDim.x != 0 && wallDim.y != 0) addEntity(Importer.makeWall(wallStart, wallEnd.sub(wallStart))); mode = Mode.WALL_QUEUE; } else if (moving != null) { mouseDragged(m); moving = null; } repaint(); } @Override public void mouseClicked(MouseEvent arg0) { frame.requestFocus(); if (mode != Mode.BG) { mode = Mode.PLACE; if (arg0.getButton() == MouseEvent.BUTTON3) { selectOverlapping(new Vector2(arg0.getPoint())); varEditor.setEntity(selected); repaint(); } else if (arg0.getButton() == MouseEvent.BUTTON1) { if (current != null) { Vector2 p = new Vector2(arg0.getPoint()); p = getClosestGridPoint(p); Entity e = new Entity(); e.setFile(current.getFile()); e.setPos(p); e.setDim(current.getDim()); e.setSprite(current.getSprite()); e.setLayer(layerEditor.getCurrentLayer()); addEntity(e); } } } repaint(); } }; /** * This JPanel is where the actual drawing take splace. */ @SuppressWarnings("serial") private JPanel drawPanel = new JPanel() { { setPreferredSize(new Dimension(640, 480)); this.addMouseListener(mouseAdapter); this.addMouseMotionListener(mouseAdapter); this.setFocusable(true); } public void paintComponent(Graphics g) { draw((Graphics2D) g); } }; public LevelEditor() throws IOException, ParserConfigurationException, TransformerException { /* * LOAD THE CONFIG FILE. */ try { if (new File(configFile).canRead()) { Node configNode = ToriXML.parse(new File(configFile)).getElementsByTagName("config").item(0); Node recentNode = configNode.getAttributes().getNamedItem("recent"); if (recentNode != null) { File f; if ((f = new File(recentNode.getNodeValue())).exists()) setLevelFile(f); } } } catch (final Exception n) { } setupGUI(); reloadLevel(); /* * Add the keyboard handler. */ frame.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent arg0) { if (arg0.getKeyCode() == KeyEvent.VK_DELETE) { deleteSelected(); } } }); repaint(); } /** * Sets the working level file and the working directory. * * @param file * the level xml file. */ private void setLevelFile(final File file) { this.levelFile = file; this.workingDirectory = file.getParentFile(); } /** * If a level.xml file exists, load the data from it. Uses levelFile. * * @throws IOException * @throws ParserConfigurationException * @throws TransformerException */ private void reloadLevel() throws IOException, ParserConfigurationException, TransformerException { // Create the essential level.xml file clear(); if (levelFile == null) return; if (levelFile.exists()) { Level level = Importer.importLevel(levelFile); variables = level.getVariableCase(); entities.clear(); layerEditor.clear(); for (Entity e : level.getNewEntities()) { File file = new File(e.getFile().replace("\\", "/")); if (file.canRead()) { importEntity(file); } entities.add(e); layerEditor.setLayerVisibility(e.getLayer(), true); } } else { saveLevel(); } saveConfig(); } /** * Save the config file. * * @throws ParserConfigurationException * @throws TransformerException */ private void saveConfig() throws ParserConfigurationException, TransformerException { DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); Document doc = docBuilder.newDocument(); // Create level element Element editorElement = doc.createElement("editor"); doc.appendChild(editorElement); Element configElement = doc.createElement("config"); editorElement.appendChild(configElement); configElement.setAttribute("recent", levelFile.getPath()); ToriXML.saveXMLDoc(new File(configFile), doc); } /** * Create the GUI components and menu. */ private void setupGUI() { frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.setFocusable(true); JPanel dummyPanel = new JPanel(); frame.add(new JScrollPane(drawPanel), BorderLayout.CENTER); frame.add(new JScrollPane(buttonPanel), BorderLayout.EAST); dummyPanel.setLayout(new BoxLayout(dummyPanel, BoxLayout.Y_AXIS)); dummyPanel.add(layerEditor); dummyPanel.add(varEditor); frame.add(dummyPanel, BorderLayout.WEST); /* * Form the status bar */ dummyPanel = new JPanel(); dummyPanel.setBackground(Color.WHITE); dummyPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); dummyPanel.setAlignmentX(Component.LEFT_ALIGNMENT); dummyPanel.add(fileLabel); dummyPanel.add(new JLabel("|")); dummyPanel.add(gridLabel); dummyPanel.add(new JLabel("|")); dummyPanel.add(levelSizeLabel); dummyPanel.add(new JLabel("|")); dummyPanel.add(editModeLabel); frame.add(dummyPanel, BorderLayout.NORTH); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS)); /* * Setup menu */ JMenuBar menuBar = new JMenuBar(); /** * FILE MENU */ JMenu fileMenu = new JMenu("File"); JMenuItem newLevel = new JMenuItem("New"); newLevel.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK)); newLevel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String levelName; if (levelFile != null) levelName = levelFile.getName().substring(0, levelFile.getName().lastIndexOf(".")); else levelName = "new level"; int ret = JOptionPane.showConfirmDialog(null, "Do you want to save changes you made to " + levelName + "?"); if (ret == JOptionPane.YES_OPTION) { try { if (!saveLevel()) return; else saveConfig(); } catch (Exception e) { e.printStackTrace(); } } else if (ret == JOptionPane.CANCEL_OPTION) { return; } clear(); levelFile = null; variables.clear(); repaint(); } }); fileMenu.add(newLevel); JMenuItem open = new JMenuItem("Open"); open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Event.CTRL_MASK)); open.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { File[] files = importNewFileDialog("Open Level File", "XML file (*.xml)", "xml"); if (files.length != 0) { setLevelFile(files[0]); try { reloadLevel(); repaint(); } catch (Exception e) { e.printStackTrace(); } } } }); fileMenu.add(open); JMenuItem save = new JMenuItem("Save"); save.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { if (saveLevel()) JOptionPane.showMessageDialog(null, "Level Saved!"); } catch (Exception e) { e.printStackTrace(); } } }); save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.CTRL_MASK)); fileMenu.add(save); JMenuItem close = new JMenuItem("Close"); close.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { System.exit(0); } }); fileMenu.add(close); menuBar.add(fileMenu); // Entity Menu JMenu entityMenu = new JMenu("Entities"); JMenuItem makeWallEntry = new JMenuItem("Make Wall"); makeWallEntry.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { mode = Mode.WALL_QUEUE; selected = null; repaint(); } }); entityMenu.add(makeWallEntry); makeWallEntry.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK)); JMenuItem importXml = new JMenuItem("Import Entity Template"); importXml.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { for (File f : importNewFileDialog("Load New Entity Template", "Entity files (*.entity)", "entity")) { if (f != null) { try { importEntity(f); repaint(); } catch (FileNotFoundException e) { e.printStackTrace(); } } } } }); entityMenu.add(importXml); importXml.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.CTRL_MASK)); JMenuItem deleteAll = new JMenuItem("Delete All"); deleteAll.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { entities.clear(); repaint(); } }); entityMenu.add(deleteAll); JMenuItem deleteType = new JMenuItem("Delete All By Type"); deleteType.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { String type = JOptionPane.showInputDialog("Type to Delete:"); if (type == null || type.isEmpty()) { return; } List<Entity> trash = new ArrayList<Entity>(); for (Entity e : entities) { if (type.equals(e.getType())) { trash.add(e); } } entities.removeAll(trash); repaint(); } }); entityMenu.add(deleteType); menuBar.add(entityMenu); /** * SETTINGS MENU */ JMenu settingsMenu = new JMenu("Settings"); JMenuItem gridMenu = new JMenuItem("Grid Size"); gridMenu.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { int i = Integer.parseInt(JOptionPane.showInputDialog("Input an integer grid size:")); gridSize.setSize(new Dimension(i, i)); repaint(); } catch (final Exception i) { return; } } }); settingsMenu.add(gridMenu); JMenuItem levelSizeItem = new JMenuItem("Level Size"); levelSizeItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { String result = JOptionPane .showInputDialog("Input an integer world width, height (ex. 1000, 5000):"); String vals[] = result.split(","); variables.setVar("dimensions.x", "" + Integer.parseInt(vals[0].trim())); variables.setVar("dimensions.y", "" + Integer.parseInt(vals[1].trim())); repaint(); } catch (final Exception i) { return; } } }); settingsMenu.add(levelSizeItem); JMenuItem levelVar = new JMenuItem("Set Level Variable"); levelVar.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { String key = JOptionPane.showInputDialog("Variable to set?"); String value = JOptionPane.showInputDialog("value to assign to the key \"" + key + "\"?"); if (!key.isEmpty() && !value.isEmpty()) variables.setVar(key, value); repaint(); } catch (final Exception i) { return; } } }); settingsMenu.add(levelVar); menuBar.add(settingsMenu); JMenu layerMenu = new JMenu("Layer"); JMenuItem moveLayer = new JMenuItem("Move Selected to Layer"); moveLayer.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { if (selected != null) { int i = Integer.parseInt(JOptionPane.showInputDialog("Move to which layer?")); transferEntity(selected, i); repaint(); } varEditor.clear(); repaint(); } catch (final Exception i) { return; } } }); layerMenu.add(moveLayer); JMenuItem moveAllLayer = new JMenuItem("Move Type to Layer"); moveAllLayer.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { String type = JOptionPane.showInputDialog("Type to Change Layer of?"); if (type == null || type.isEmpty()) { return; } int layer = Integer.parseInt(JOptionPane.showInputDialog("Move to which layer?")); List<Entity> switchs = new ArrayList<Entity>(); for (Entity e : entities) { if (type.equals(e.getType())) { switchs.add(e); } } for (Entity e : switchs) { transferEntity(e, layer); } varEditor.clear(); repaint(); } catch (final Exception i) { return; } } }); layerMenu.add(moveAllLayer); menuBar.add(layerMenu); JMenu bgMenu = new JMenu("Background"); JMenuItem selectBg = new JMenuItem("Select New BG"); selectBg.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setCurrentDirectory(workingDirectory); int ret = fileChooser.showDialog(null, "Select Image File"); if (ret == JFileChooser.APPROVE_OPTION) { bgEditor.setImageFile(fileChooser.getSelectedFile()); bgEditor.setupBg(); System.out.println("Found image " + fileChooser.getSelectedFile().getPath()); } } }); bgMenu.add(selectBg); JMenuItem setupBg = new JMenuItem("Edit BG Settings"); setupBg.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { bgEditor.setupBg(); } }); bgMenu.add(setupBg); JMenuItem placeBg = new JMenuItem("Toggle Place BG Mode"); placeBg.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { mode = mode == Mode.BG ? Mode.PLACE : Mode.BG; selected = null; repaint(); } }); bgMenu.add(placeBg); placeBg.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK)); menuBar.add(bgMenu); frame.setJMenuBar(menuBar); frame.pack(); frame.setVisible(true); } /** * Make the first detected overlapping, visible object, selected. * * @param p * the mouse location. */ public void selectOverlapping(final Vector2 p) { Entity selected = null; for (Entity e : entities) { if (new Rectangle((int) e.getPos().getX(), (int) e.getPos().getY(), (int) e.getDim().getX(), (int) e .getDim().getY()).contains(new Point((int) p.x, (int) p.y)) && this.selected != e) { selected = e; break; } } this.selected = selected; } /** * Delete the entity that is currently selected. */ public void deleteSelected() { if (selected != null) { removeEntity(selected); selected = null; } } /** * Delete the first object detected overlapping. * * @param p * the mouse point. */ public void deleteOverlapping(final Vector2 p) { Entity selected = null; for (Entity e : entities) { if (e.getLayer() == layerEditor.getCurrentLayer() && new Rectangle((int) e.getPos().getX(), (int) e.getPos().getY(), (int) e.getDim().getX(), (int) e .getDim().getY()).contains(new Point((int) p.x, (int) p.y)) && this.selected != e) { selected = e; break; } } removeEntity(selected); } /** * Return all overlapping entities * * @param p * the mouse point. */ public List<Entity> getOverlapping(final Vector2 p) { List<Entity> ents = new ArrayList<Entity>(); for (Entity e : entities) { if (e.getLayer() == layerEditor.getCurrentLayer() && new Rectangle((int) e.getPos().getX(), (int) e.getPos().getY(), (int) e.getDim().getX(), (int) e .getDim().getY()).contains(new Point((int) p.x, (int) p.y))) { ents.add(e); } } return ents; } /** * Add an entity, and give it to a layer. * * @param e * the entity */ private void addEntity(final Entity e) { if (e != null) { entities.add(e); repaint(); } } /** * Remove an entity from all layers. * * @param e * entity to remove. */ public void removeEntity(final Entity e) { entities.remove(e); repaint(); } /** * Remove entity from one layer and add to another. * * @param e * entity to move. * @param layer * layer to add to. */ private void transferEntity(final Entity e, final int layer) { removeEntity(e); e.setLayer(layer); e.getVariableCase().setVar("layer", layer + ""); addEntity(e); repaint(); } /** * Save level.xml. * * @return true if the save was successful; false otherwise * @throws ParserConfigurationException * @throws TransformerException * @throws IOException * @throws DOMException */ public boolean saveLevel() throws ParserConfigurationException, TransformerException, DOMException, IOException { DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); Document doc = docBuilder.newDocument(); // Create level element Element levelElement = doc.createElement("level"); doc.appendChild(levelElement); // Add the attributes of the level HashMap<String, String> props = new HashMap<String, String>(); props.putAll(variables.getVariables()); levelElement.setAttribute("map", ToriMapIO.writeMap(null, props)); // Save the objects Element objectsElements = doc.createElement("objects"); levelElement.appendChild(objectsElements); for (Entity e : entities) { HashMap<String, String> map = new HashMap<String, String>(); File f = new File(e.getFile().replace("\\", "/")); if (f.canRead()) { map.put("template", fixFileString(f.getPath().substring( f.getPath().indexOf(workingDirectory.getName()) + workingDirectory.getName().length()))); } map.put("layer", e.getLayer() + ""); map.putAll(e.getVariableCase().getVariables()); map.put("position.x", e.getPos().getX() + ""); map.put("position.y", e.getPos().getY() + ""); Element object = doc.createElement("entity"); object.setAttribute("map", ToriMapIO.writeMap(null, map)); objectsElements.appendChild(object); } if (levelFile != null) { ToriXML.saveXMLDoc(levelFile, doc); return true; } else { File[] files = importNewFileDialog("Save New Level File", "XML file (*.xml)", "xml"); if (files.length != 0) { setLevelFile(files[0]); ToriXML.saveXMLDoc(levelFile, doc); repaint(); return true; } else { return false; } } } /** * Brings up a file chooser * * @param title * The title of the window. * @param description * the file type description. * @param extension * the file extension to filter for. * @return a list of selected files. */ public File[] importNewFileDialog(final String title, final String description, final String extension) { JFileChooser fileChooser = new JFileChooser(); fileChooser.setCurrentDirectory(workingDirectory); FileNameExtensionFilter filter = new FileNameExtensionFilter(description, extension); fileChooser.setFileFilter(filter); fileChooser.setMultiSelectionEnabled(true); fileChooser.setAcceptAllFileFilterUsed(false); int ret = fileChooser.showDialog(null, title); if (ret == JFileChooser.APPROVE_OPTION) { File[] files = fileChooser.getSelectedFiles(); for (int i = 0; i < files.length; i++) { String path = files[i].getAbsolutePath(); String ext = "." + ((FileNameExtensionFilter) fileChooser.getFileFilter()).getExtensions()[0]; if (!path.endsWith(ext)) { files[i] = new File(path + ext); } } return files; } return new File[0]; } /** * Fully import and add an xml entity. if the entity is a new type, it will * be given a new button and added to button panel. * * @param file * the file of the xml. * @return the generated entity. * @throws FileNotFoundException */ public Entity importEntity(final File file) throws FileNotFoundException { HashMap<String, String> data = ToriMapIO.readMap(file); final Entity e = Importer.importEntity(new File(file.getPath().replace("\\", "/")), null); try { String[] s = data.get("sprite.editor").split(","); e.getSprite().set(Integer.parseInt(s[0].trim()), Integer.parseInt(s[1].trim())); } catch (final Exception exc) { // The sprite remains at 1,1; } if (!entityExists(e)) { ImageIcon bI = new ImageIcon(); bI.setImage(ScriptUtils.fetchImage(e.getSprite().getImageIndex()).getScaledInstance(e.getDim().getWidth(), e.getDim().getHeight(), 0)); JButton b = new JButton(bI); b.setToolTipText(data.get("description")); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { setCurrent(e); } }); buttonPanel.add(b); repaint(); } return e; } private boolean entityExists(final Entity e) { for (Entity existingEntity : entities) { if (e.getFile().equals(existingEntity.getFile())) { return true; } } return false; } /** * Draw the state of the level. * * @param g * graphics! */ public void draw(Graphics2D g) { try { g.setColor(Color.GRAY); g.fillRect(0, 0, (int) variables.getFloat("dimensions.x"), (int) variables.getFloat("dimensions.y")); /* * DRAW THE GRID */ if (gridSize.width > 1) { g.setStroke(new BasicStroke(1)); g.setColor(Color.BLACK); for (int x = 0; x < variables.getFloat("dimensions.x"); x += gridSize.width) g.drawLine(x, 0, x, (int) variables.getFloat("dimensions.y")); for (int y = 0; y < drawPanel.getHeight(); y += gridSize.height) g.drawLine(0, y, drawPanel.getWidth(), y); } /** * DRAW ENTITIES in layer order. */ Collections.sort(entities, new Comparator<Entity>() { @Override public int compare(Entity a, Entity b) { int ret = new Integer(b.getLayer()).compareTo(new Integer(a.getLayer())); if (ret == 0) { if (ReservedTypes.WALL.equals(a.getType())) return 1; else if (ReservedTypes.WALL.equals(b.getType())) return -1; else return 0; } else { return ret; } } }); for (Entity e : entities) { if (layerEditor.isLayerVisible(e.getLayer())) e.draw(g); } if (selected != null) { g.setColor(Color.GREEN); g.drawRect((int) selected.getPos().getX(), (int) selected.getPos().getY(), (int) selected.getDim() .getX(), (int) selected.getDim().getY()); } g.setColor(Color.RED); g.draw3DRect(0, 0, (int) variables.getFloat("dimensions.x"), (int) variables.getFloat("dimensions.y"), true); if (mode == Mode.WALL_MAKING) { float wallStartX = wallStart.x; float wallStartY = wallStart.y; float wallEndX = wallEnd.x; float wallEndY = wallEnd.y; if (wallEndX < wallStartX) { float temp = wallStartX; wallStartX = wallEndX; wallEndX = temp; } if (wallEndY < wallStartY) { float temp = wallStartY; wallStartY = wallEndY; wallEndY = temp; } ((Graphics2D) g).setStroke(new BasicStroke(2)); g.drawRect((int) wallStartX, (int) wallStartY, (int) wallEndX - (int) wallStartX, (int) wallEndY - (int) wallStartY); ((Graphics2D) g).setStroke(new BasicStroke(1)); } } catch (Exception f) { } } /** * Clear the GUI state. */ private void clear() { entities.clear(); current = null; selected = null; buttonPanel.removeAll(); layerEditor.clear(); } public void setCurrent(final Entity e) { current = e; } /** * Forces repaint on frame and updates status bar. */ public void repaint() { if (levelFile != null) fileLabel.setText(levelFile.getName().substring(0, levelFile.getName().lastIndexOf("."))); else fileLabel.setText("new level"); gridLabel.setText("Grid: " + (int) gridSize.getWidth() + " x " + (int) gridSize.getHeight()); levelSizeLabel.setText("Level Size: " + (int) variables.getFloat("dimensions.x") + " x " + (int) variables.getFloat("dimensions.y")); if (selected != null) { editModeLabel.setText("Editing Single Entity: " + selected.getType()); } else if (mode == Mode.WALL_QUEUE) { editModeLabel.setText("Click and Drag to Draw Wall"); } else if (mode == Mode.BG) { editModeLabel.setText("Click To Place a BG Tile in Current Layer (Ctrl+B to exit mode)"); } else { editModeLabel.setText("Click to Place Entity"); } drawPanel.setPreferredSize(new Dimension((int) variables.getFloat("dimensions.x"), (int) variables .getFloat("dimensions.y"))); frame.validate(); frame.repaint(); } public Vector2 getClosestGridPoint(final Vector2 p) { return getClosestGridPoint(gridSize, p); } public static Vector2 getClosestGridPoint(final Dimension gridSize, final Vector2 p) { return new Vector2(((int) p.x / (int) gridSize.width) * gridSize.width, ((int) p.y / (int) gridSize.height) * gridSize.height); } /** * Windows sucks! * * @param f * the file to have \ replaced with /. * @return new file name. */ private static String fixFileString(final String f) { return f.replace("\\", "/"); } }