/******************************************************************************* * Rhythos Editor is a game editor and project management tool for making RPGs on top of the Rhythos Game system. * * Copyright (C) 2013 David Maletz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package mrpg.editor.tools; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import mrpg.display.WorldPanel; import mrpg.editor.Clipboard; import mrpg.editor.History; import mrpg.editor.TilesetViewer; import mrpg.world.Cell; import mrpg.world.Tile; import mrpg.world.World; public class SelectTool implements Tool { private final WorldPanel world; private final History history; private History.Entry entry; private boolean addedEntry; private int sel_x1 = Integer.MIN_VALUE, sel_y1, sel_x2, sel_y2; private Tile bg_tiles[] = null; public Listener listener; public SelectTool(WorldPanel w, TilesetViewer v, History h){world = w; history = h;} private static final float[] dashed = new float[]{8.0f}; public void paint(Graphics g, int stX, int stY, int mouseX, int mouseY){} public void paintTop(Graphics g, double scale, int stX, int stY, int mouseX, int mouseY){ if(sel_x1 != Integer.MIN_VALUE){ Graphics2D g2d = (Graphics2D)g.create(); int ts = (int)Math.floor(world.tile_size*scale); int x = Math.min(sel_x1, sel_x2)*ts, y = Math.min(sel_y1, sel_y2)*ts, width = (Math.abs(sel_x2-sel_x1)+1)*ts-2, height = (Math.abs(sel_y2-sel_y1)+1)*ts-2; g2d.setPaint(Color.black); float f = world.getFrame()*3; g2d.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 8.0f, dashed, f)); g2d.drawRect(x, y, width, height); g2d.setPaint(Color.white); g2d.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 8.0f, dashed, 8.0f+f)); g2d.drawRect(x, y, width, height); } } public void repaint(int stX, int stY, int mouseX, int mouseY){ double s = world.getScale(); int x = Math.max(0, (int)Math.floor((Math.min(stX, mouseX)*world.tile_size-1)*s-1)), y = Math.max(0, (int)Math.floor((Math.min(stY, mouseY)*world.tile_size-1)*s-1)); world.repaint(x, y, (int)Math.ceil(((Math.max(stX, mouseX)+1)*world.tile_size+2)*s+2)-x, (int)Math.ceil(((Math.max(stY, mouseY)+1)*world.tile_size+2)*s+2)-y); } public void updateSelection(int mouseX, int mouseY, int oldSelWidth, int oldSelHeight){} public void mouseDragged(int mouseX, int mouseY, int x, int y){ if(sel_x1 == Integer.MIN_VALUE){ sel_x1 = mouseX; sel_y1 = mouseY; sel_x2 = mouseX; sel_y2 = mouseY; repaint(mouseX, mouseY, mouseX, mouseY); } } private int clamp(int val, int min, int max){return Math.min(max, Math.max(min, val));} public void mouseDragged(int stX, int stY, int oldMouseX, int oldMouseY, int mouseX, int mouseY){ if(bg_tiles != null && oldMouseX <= Math.max(sel_x1, sel_x2) && oldMouseX >= Math.min(sel_x1, sel_x2) && oldMouseY <= Math.max(sel_y1, sel_y2) && oldMouseY >= Math.min(sel_y1, sel_y2)){ int dx = mouseX-oldMouseX, dy = mouseY-oldMouseY; World w = world.getWorld(); int level = world.getEditLevel(); int _sy = Math.min(sel_y1, sel_y2), _sx = Math.min(sel_x1, sel_x2), width = Math.abs(sel_x1-sel_x2)+1; int sy = clamp(Math.min(sel_y1, sel_y2), 0, w.getHeight()-1), ey = clamp(Math.max(sel_y1, sel_y2), 0, w.getHeight()-1), sx = clamp(Math.min(sel_x1, sel_x2), 0, w.getWidth()-1), ex = clamp(Math.max(sel_x1, sel_x2), 0, w.getWidth()-1); for(int y=sy; y<=ey; y++) for(int x=sx; x<=ex; x++){ Cell c = w.getCell(x, y); int i = (y-_sy)*width+(x-_sx); if(c != null){ Tile t = c.getTile(level); entry.changeTile(x, y, t, bg_tiles[i]); c.setTile(bg_tiles[i], level); bg_tiles[i] = t; } else bg_tiles[i] = Tile.empty; } _sy += dy; _sx += dx; sy = clamp(_sy, 0, w.getHeight()-1); ey = clamp(Math.max(sel_y1, sel_y2)+dy, 0, w.getHeight()-1); sx = clamp(_sx, 0, w.getWidth()-1); ex = clamp(Math.max(sel_x1, sel_x2)+dx, 0, w.getWidth()-1); for(int y=sy; y<=ey; y++) for(int x=sx; x<=ex; x++){ int i = (y-_sy)*width+(x-_sx); Tile t = bg_tiles[i]; Cell c = w.getCell(x, y); if(c == null) c = w.addCell(x, y); if(c == null) continue; bg_tiles[i] = c.getTile(level); entry.changeTile(x, y, bg_tiles[i], t); c.setTile(t, level); } repaint(sx-dx-1, sy-dy-1, ex-dx+1, ey-dy+1); sel_x1 += dx; sel_y1 += dy; sel_x2 += dx; sel_y2 += dy; repaint(sx-1, sy-1, ex+1, ey+1); if(!addedEntry) addedEntry = history.addEntry(entry); } else { sel_x1 = stX; sel_y1 = stY; sel_x2 = mouseX; sel_y2 = mouseY; repaint(stX, stY, oldMouseX, oldMouseY); repaint(stX, stY, mouseX, mouseY); } } public void mouseMoved(int oldMouseX, int oldMouseY, int mouseX, int mouseY){ if(sel_x1 != Integer.MIN_VALUE && mouseX <= Math.max(sel_x1, sel_x2) && mouseX >= Math.min(sel_x1, sel_x2) && mouseY <= Math.max(sel_y1, sel_y2) && mouseY >= Math.min(sel_y1, sel_y2)) world.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); else world.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } public void mousePressed(int mouseX, int mouseY, int x, int y){ if(sel_x1 != Integer.MIN_VALUE && mouseX <= Math.max(sel_x1, sel_x2) && mouseX >= Math.min(sel_x1, sel_x2) && mouseY <= Math.max(sel_y1, sel_y2) && mouseY >= Math.min(sel_y1, sel_y2)){ int level = world.getEditLevel(); entry = new History.Entry(level); addedEntry = false; if(bg_tiles == null){ bg_tiles = new Tile[(Math.abs(sel_x2-sel_x1)+1)*(Math.abs(sel_y2-sel_y1)+1)]; for(int i=0; i<bg_tiles.length; i++) bg_tiles[i] = Tile.empty; } } else {repaint(sel_x1, sel_y1, sel_x2, sel_y2); activate();} } public void mouseReleased(int stX, int stY, int mouseX, int mouseY){ mouseMoved(0, 0, mouseX, mouseY); if(sel_x1 != Integer.MIN_VALUE && listener != null) listener.select(); } public void activate(){ world.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); sel_x1 = Integer.MIN_VALUE; bg_tiles = null; entry = null; addedEntry = false; if(listener != null) listener.deselect(); } public void selectAll(){ sel_x1 = 0; sel_x2 = world.getWorld().getWidth()-1; sel_y1 = 0; sel_y2 = world.getWorld().getHeight()-1; if(listener != null) listener.select(); world.repaint(); } public boolean hasSelection(){return sel_x1 != Integer.MIN_VALUE;} public void deselectAll(){activate(); world.repaint();} public void deleteSelection(){ int level = world.getEditLevel(); History.Entry entry = new History.Entry(level); World w = world.getWorld(); int _sy = Math.min(sel_y1, sel_y2), _sx = Math.min(sel_x1, sel_x2), width = Math.abs(sel_x1-sel_x2)+1; int sy = clamp(Math.min(sel_y1, sel_y2), 0, w.getHeight()-1), ey = clamp(Math.max(sel_y1, sel_y2), 0, w.getHeight()-1), sx = clamp(Math.min(sel_x1, sel_x2), 0, w.getWidth()-1), ex = clamp(Math.max(sel_x1, sel_x2), 0, w.getWidth()-1); for(int y=sy; y<=ey; y++) for(int x=sx; x<=ex; x++){ Cell c = w.getCell(x, y); if(c == null) continue; Tile t = (bg_tiles == null)?Tile.empty:bg_tiles[(y-_sy)*width+(x-_sx)]; entry.changeTile(x, y, c.getTile(level), t); c.setTile(t, level); } history.addEntry(entry); deselectAll(); } public void copy(Clipboard c){ World w = world.getWorld(); int level = world.getEditLevel(); int sy = clamp(Math.min(sel_y1, sel_y2), 0, w.getHeight()-1), ey = clamp(Math.max(sel_y1, sel_y2), 0, w.getHeight()-1), sx = clamp(Math.min(sel_x1, sel_x2), 0, w.getWidth()-1), ex = clamp(Math.max(sel_x1, sel_x2), 0, w.getWidth()-1); c.set(w, sx, sy, ex-sx+1, ey-sy+1, level); } public void paste(Clipboard clip){ if(!clip.hasData()) return; int level = world.getEditLevel(); History.Entry entry = new History.Entry(level); activate(); double s = world.getScale(); Rectangle r = world.getVisibleRect(); World w = world.getWorld(); int width = Math.min(w.getWidth(), clip.getWidth()), height = Math.min(w.getHeight(), clip.getHeight()); sel_x1 = (int)Math.floor((r.x+r.width*0.5)/(world.tile_size*s)); sel_y1 = (int)Math.floor((r.y+r.height*0.5)/(world.tile_size*s)); sel_x1 = Math.max(sel_x1-width/2, 0); sel_y1 = Math.max(sel_y1-height/2, 0); sel_x2 = sel_x1+width-1; sel_y2 = sel_y1+height-1; if(sel_x2 >= w.getWidth()){int dx = w.getWidth()-sel_x2+1; sel_x1 -= dx; sel_x2 -= dx;} if(sel_y2 >= w.getHeight()){int dy = w.getHeight()-sel_x2+1; sel_y1 -= dy; sel_y2 -= dy;} entry = new History.Entry(level); addedEntry = false; bg_tiles = new Tile[width*height]; for(int y=0; y<height; y++) for(int x=0; x<width; x++){ Cell c = w.getCell(sel_x1+x, sel_y1+y); if(c == null) c = w.addCell(sel_x1+x, sel_y1+y); bg_tiles[y*width+x] = c.getTile(level); Tile t = clip.getTile(x, y); entry.changeTile(sel_x1+x, sel_y1+y, c.getTile(level), t); c.setTile(t, level); } if(listener != null) listener.select(); history.addEntry(entry); world.repaint(); } public String getName(){return "Select tiles";} public String getIcon(){return "select";} public static interface Listener { public void select(); public void deselect(); } }