@Override
		public void mouseReleased(MouseEvent eve) {
			int mapX = dataHolder.getMapX();
			int mapY = dataHolder.getMapY();
			Point mousePoint = eve.getPoint();
			int viewScale = (int) (EditorApp.DEFAULT_TILE_SIZE * EditorApp.mapScale);
			int cursorX, cursorY;
			
			//do nothing if we are editing the line layer
			if (parent.getActiveLayer() == 4)
				return;
			if (eve.isPopupTrigger()) {
				//this needs to be copied to isRelease
				cursorX = mousePoint.x / viewScale;
				cursorY = mousePoint.y / viewScale;
				popup_tilescript.setAction(
						new TilescriptAction(mapX, mapY, tilePen.getI(0, 0), 
								parent.getActiveLayer()));
				popup_tilescript.setText("generate CMP for (" + cursorX + "," + cursorY + ")");
				popup_tra.setAction(new TraScriptAction(cursorX, cursorY, dataHolder.getMapNumber()));
				popup_tra.setText("make <TRA to this spot");
				popup.show(eve.getComponent(), eve.getX(), eve.getY());
				return;
			}			
			if ((eve.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0)
				return; //do nothing if right mouse button
			if (dragging) {
				//setCursor(null);
				return;
			}
			byte[][] oldDat;
			byte[][] newDat;
			Rectangle newCursorRect;
			int w, h;
			//Graphics2D g2d = (Graphics2D)((MapPane)eve.getSource()).getGraphics();
			switch (parent.getDrawMode()) {
			case EditorApp.DRAWMODE_RECT:
				if (selW < 0)
					cursorX = baseX + selW + 1;
				else
					cursorX = baseX;
				//absolutize to make calculations easy
				//(it no longer needs to be updated until next click)
				selW = Math.abs(selW);
				if (selH < 0)
					cursorY = baseY + selH + 1;
				else
					cursorY = baseY;
				//see above
				selH = Math.abs(selH);
				int tmpx = tilePen.dx;
				int tmpY = tilePen.dy;
				tilePen.dx = 0;
				tilePen.dy = 0;
				//capture the previous state
				oldDat = new byte[selW][selH];
				for (int dx = 0; dx < selW; dx++) {
					for (int dy = 0; dy < selH; dy++) {
						oldDat[dx][dy] = dataHolder.getTileB(cursorX + dx, cursorY + dy, parent.getActiveLayer());
					}
				}
				//draw over it
				for (int dx = 0; dx < selW; dx += tilePen.getW()) {
					for (int dy = 0; dy < selH; dy += tilePen.getH()) {
						drawPen(cursorX + dx, cursorY + dy, cursorX + selW, cursorY + selH);
					}
				}
				//capture the new state
				newDat = new byte[selW][selH];
				for (int dx = 0; dx < selW; dx++) {
					for (int dy = 0; dy < selH; dy++) {
						newDat[dx][dy] = dataHolder.getTileB(cursorX + dx, cursorY + dy, parent.getActiveLayer());
					}
				}
				redrawTiles(cursorX, cursorY, selW, selH);
				tilePen.dx = tmpx;
				tilePen.dy = tmpY;
				selW = 1;
				selH = 1;
				dataHolder.addEdit(dataHolder.new MapEdit(cursorX, cursorY, oldDat, newDat, parent.getActiveLayer()));
				break;
			case EditorApp.DRAWMODE_COPY:
				if (selW < 0)
					cursorX = baseX + selW + 1;
				else
					cursorX = baseX;
				//absolutize to make calculations easy
				//(it no longer needs to be updated until next click)
				selW = Math.abs(selW);
				if (selH < 0)
					cursorY = baseY + selH + 1;
				else
					cursorY = baseY;
				//see above
				selH = Math.abs(selH);
				
				//create a pen
				tilePen = new TileBuffer();
				tilePen.dx = baseX - cursorX;
				tilePen.dy = baseY - cursorY;
				tilePen.data = new byte[selW][selH];
				for (int x = 0; x < selW; x++) {
					for (int y = 0; y < selH; y++) {
						tilePen.data[x][y] = dataHolder.getTileB(cursorX + x, cursorY + y, parent.getActiveLayer());
					}
				}
				redrawTiles(cursorX, cursorY, selW, selH);
				preview.repaint();
				selW = 1;
				selH = 1;
				break;
			case EditorApp.DRAWMODE_FILL:
				int currentX = mousePoint.x / viewScale;
				int currentY = mousePoint.y / viewScale;
				if (currentX >= mapX)
					currentX = mapX-1;
				if (currentX < 0)
					currentX = 0;
				if (currentY >= mapY)
					currentY = mapY-1;
				if (currentY < 0)
					currentY = 0;
				Rectangle tracker = new Rectangle(currentX, currentY, 0, 0);
				fillPen(currentX, 
						currentY, 
						0, 
						0, 
						dataHolder.getTileB(currentX, currentY, parent.getActiveLayer()), 
						tracker);
				//System.out.println(tracker);
				tracker.width += 1;
				tracker.height += 1;
				redrawTiles(tracker.x, tracker.y,
						tracker.x + tracker.width,
						tracker.height + tracker.y);
				//oldCursorRect = new Rectangle(lastX - tilePen.dx, lastY - tilePen.dy, tilePen.getW(), tilePen.getH());
				newCursorRect = new Rectangle(currentX - tilePen.dx, currentY - tilePen.dy, tilePen.getW(), tilePen.getH());
				//put the cursor back
				moveCursor(newCursorRect);
				oldDat = new byte[tracker.width][tracker.height];
				for (int dx = 0; dx < tracker.width; dx++) {
					for (int dy = 0; dy < tracker.height; dy++) {
						oldDat[dx][dy] = prevLayerState[tracker.x + dx][tracker.y + dy];
					}
				}
				//capture the new state
				newDat = new byte[tracker.width][tracker.height];
				for (int dx = 0; dx < tracker.width; dx++) {
					for (int dy = 0; dy < tracker.height; dy++) {
						newDat[dx][dy] = dataHolder.getTileB(tracker.x + dx, tracker.y + dy, parent.getActiveLayer());
					}
				}
				//create the edit
				dataHolder.addEdit(dataHolder.new MapEdit(tracker.x, tracker.y, 
						oldDat, newDat, parent.getActiveLayer()));
				break;
			case EditorApp.DRAWMODE_REPLACE:
				currentX = eve.getX() / viewScale;
				currentY = eve.getY() / viewScale;
				if (currentX >= mapX)
					currentX = mapX-1;
				if (currentX < 0)
					currentX = 0;
				if (currentY >= mapY)
					currentY = mapY-1;
				if (currentY < 0)
					currentY = 0;
				Rectangle r = replacePen(currentX, currentY);
				r.width += 1;
				r.height += 1;
				redrawTiles(r.x, r.y, r.width, r.height);
				//put the cursor back
				//oldCursorRect = new Rectangle(lastX - tilePen.dx, lastY - tilePen.dy, tilePen.getW(), tilePen.getH());
				newCursorRect = new Rectangle(currentX - tilePen.dx, currentY - tilePen.dy, tilePen.getW(), tilePen.getH());
				moveCursor(newCursorRect);
				w = r.width - r.x;
				h = r.height - r.y;
				oldDat = new byte[w][h];
				for (int dx = 0; dx < w; dx++) {
					for (int dy = 0; dy < h; dy++) {
						oldDat[dx][dy] = prevLayerState[r.x + dx][r.y + dy];
					}
				}
				//capture the new state
				newDat = new byte[w][h];
				for (int dx = 0; dx < w; dx++) {
					for (int dy = 0; dy < h; dy++) {
						newDat[dx][dy] = dataHolder.getTileB(r.x + dx, r.y + dy, parent.getActiveLayer());
					}
				}
				//create the edit
				dataHolder.addEdit(dataHolder.new MapEdit(r.x, r.y, oldDat, 
						newDat, parent.getActiveLayer()));
				break;
			case EditorApp.DRAWMODE_DRAW:
				//capture the previous state
				if (selW > mapX)
					selW = mapX;
				if (selH > mapY)
					selH = mapY;
				w = selW - baseX;
				h = selH - baseY;
				oldDat = new byte[w][h];
				for (int dx = 0; dx < w; dx++) {
					for (int dy = 0; dy < h; dy++) {
						oldDat[dx][dy] = prevLayerState
								[baseX + dx - tilePen.dx][baseY + dy - tilePen.dy];
					}
				}
				//capture the new state
				newDat = new byte[w][h];
				for (int dx = 0; dx < w; dx++) {
					for (int dy = 0; dy < h; dy++) {
						newDat[dx][dy] = dataHolder.getTileB(
								baseX + dx - tilePen.dx, 
								baseY + dy - tilePen.dy, 
								parent.getActiveLayer());
					}
				}
				//create the edit
				dataHolder.addEdit(dataHolder.new MapEdit(baseX - tilePen.dx, baseY - tilePen.dy, oldDat, 
						newDat, parent.getActiveLayer()));
				break;
			default:
				break;
			}
		}