/* * Copyright 2004-2010 Information & Software Engineering Group (188/1) * Institute of Software Technology and Interactive Systems * Vienna University of Technology, Austria * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.tuwien.ifs.somtoolbox.util.mnemonic; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Toolkit; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JPanel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import javax.swing.event.MouseInputAdapter; /** * @author Rudolf Mayer * @version $Id: MapPanel.java 3587 2010-05-21 10:35:33Z mayer $ */ public class MapPanel extends JPanel { private static final long serialVersionUID = 1L; public static int BORDER = 10; public static int initialWidth = 800; public static int initialHeight = 600; protected EventListenerList listenerList = new EventListenerList(); private DragListener dragListener = new DragListener(); private BufferedImage backgroundImageMap; private boolean[][] toDraw; private double aspectRatio = 1.9455252918287937; private double nodeDiameter = 1; private double nodeSpacingX; private double nodeSpacingY; private double zoomAspect; private int zoomedHeight; private int zoomedWidth; public MapPanel(boolean[][] toDraw, String image) { this.toDraw = toDraw; jbInit(); setSize(initialWidth, initialHeight); setRequestFocusEnabled(false); if (image != null) { try { backgroundImageMap = ImageIO.read(new File(image)); aspectRatio = (double) backgroundImageMap.getWidth() / (double) backgroundImageMap.getHeight(); double maxWidth = Toolkit.getDefaultToolkit().getScreenSize().getWidth() - 40; double maxHeight = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight() - 200; double aspectX = maxWidth / backgroundImageMap.getWidth(); double aspectY = maxHeight / backgroundImageMap.getHeight(); zoomAspect = Math.min(aspectX, aspectY); zoomedHeight = (int) (backgroundImageMap.getHeight() * zoomAspect); zoomedWidth = (int) (backgroundImageMap.getWidth() * zoomAspect); setSize(getPreferredSize()); System.out.println("set background map: " + zoomedWidth + "/" + zoomedHeight + ", max zoom: " + zoomAspect); } catch (IOException e) { System.out.println("could not read image '" + image + "': " + e.getMessage()); e.printStackTrace(); } } else { aspectRatio = toDraw.length / toDraw[0].length; } if (toDraw != null) { setNodes(); } } public MapPanel(boolean[][] toDraw) { this.toDraw = toDraw; jbInit(); setSize(initialWidth, initialHeight); setRequestFocusEnabled(false); aspectRatio = toDraw.length / toDraw[0].length; setNodes(); } public MapPanel(int totalNodes, String image) { this(null, image); createNodes(totalNodes); } public void createNodes(int totalNodes) { int x = (int) Math.round(Math.sqrt(totalNodes * aspectRatio)); int y = (int) Math.round(x / aspectRatio); toDraw = new boolean[x][y]; System.out.println("toDraw: " + toDraw.length + " * " + toDraw[0].length); setNodes(); } /** * */ private void setNodes() { double availableWidth = getSize().getWidth() - 2 * BORDER; double availableHeight = getSize().getHeight() - 2 * BORDER; double nodeWidth = availableWidth / (2 * toDraw.length - 1); double nodeHeight = availableHeight / (2 * toDraw[0].length - 1); nodeDiameter = (int) Math.min(nodeWidth, nodeHeight); nodeSpacingX = (availableWidth - nodeDiameter * toDraw.length) / toDraw.length; nodeSpacingY = (availableHeight - nodeDiameter * toDraw[0].length) / toDraw[0].length; System.out.println("nodeDiameter: " + nodeDiameter + " spacing x: " + nodeSpacingX + " y: " + nodeSpacingY); for (int col = 0; col < toDraw.length; col++) { for (int row = 0; row < toDraw[0].length; row++) { int xPos = getXPos(col); int yPos = getYPos(row); // System.out.println("RGB at " + col + "/" + row + ":" + backgroundImageMap.getRGB(xPos, yPos)); if (backgroundImageMap == null || backgroundImageMap.getRGB((int) (xPos / zoomAspect), (int) (yPos / zoomAspect)) < -1) { toDraw[col][row] = true; } // if (backgroundImageMap.getRGB(xPos, yPos) != -1) { // System.out.println("blue value:" + // backgroundImageMap.getColorModel().getBlue(backgroundImageMap.getRGB(xPos, yPos))); // System.out.println("red value:" + // backgroundImageMap.getColorModel().getRed(backgroundImageMap.getRGB(xPos, yPos))); // System.out.println("green value:" + // backgroundImageMap.getColorModel().getGreen(backgroundImageMap.getRGB(xPos, yPos))); // } } } } /** * @param row the row * @return the vertical position on the screen */ private int getYPos(int row) { return (int) (BORDER + row * (nodeDiameter + nodeSpacingY)); } /** * @param col the column * @return the horizontal position on the screen */ private int getXPos(int col) { return (int) (BORDER + col * (nodeDiameter + nodeSpacingX)); } @Override public void paint(Graphics g) { super.paint(g); setBackground(Color.WHITE); setForeground(Color.GRAY); if (backgroundImageMap != null) { g.drawImage(backgroundImageMap, BORDER, BORDER, zoomedWidth, zoomedHeight, this); } // System.out.println("Painting..." + toDraw.length + " / " + toDraw[0].length + " diameter: " + nodeDiameter); for (int col = 0; col < toDraw.length; col++) { for (int row = 0; row < toDraw[0].length; row++) { int xPos = getXPos(col); int yPos = getYPos(row); if (toDraw[col][row]) { setForeground(Color.GRAY); g.fillRoundRect(xPos, yPos, (int) nodeDiameter - 1, (int) nodeDiameter - 1, 2 * BORDER, 2 * BORDER); } else { g.drawRoundRect(xPos, yPos, (int) nodeDiameter - 1, (int) nodeDiameter - 1, 2 * BORDER, 2 * BORDER); } } } g.drawRect((int) dragListener.startX, (int) dragListener.startY, (int) (dragListener.endX - dragListener.startX), (int) (dragListener.endY - dragListener.startY)); } private void jbInit() { registerListeners(); } private void registerListeners() { this.addMouseListener(new java.awt.event.MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { processMouseClick(e.getX(), e.getY()); } }); this.addMouseListener(dragListener); this.addMouseMotionListener(dragListener); } public void processMouseClick(double x, double y) { // System.out.println("in processMouseClick " + x + "/" + y); double translatedX = x - BORDER; double translatedY = y - BORDER; double actualX = translatedX % (nodeDiameter + nodeSpacingX); double actualY = translatedY % (nodeDiameter + nodeSpacingY); // System.out.println("original: " + x + "/" + y + " ==> " + actualX + "/" + actualY); if (actualX < nodeDiameter && actualY < nodeDiameter) { System.out.println("IN!"); int nodeX = (int) (translatedX / (nodeDiameter + nodeSpacingX)); int nodeY = (int) (translatedY / (nodeDiameter + nodeSpacingY)); invertNode(nodeX, nodeY); fireChangeEvent(); } else { System.out.println("OUT!"); } } /** * @param nodeX x-pos of the node to invert * @param nodeY y-pos of the node to invert */ private void invertNode(final int nodeX, final int nodeY) { System.out.print("inverting node " + nodeX + "/" + nodeY); toDraw[nodeX][nodeY] = !toDraw[nodeX][nodeY]; System.out.println(" --> " + toDraw[nodeX][nodeY]); repaint(); } // Notify all listeners that have registered interest for notification on this event type. The event instance is // lazily created using the // parameters passed into the fire method. protected void fireChangeEvent() { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: ((ChangeListener) listeners[i + 1]).stateChanged(new ChangeEvent(this)); } } } public void processAreaSelection(double startX, double startY, double endX, double endY) { int startCol = (int) Math.ceil((startX - BORDER) / (2 * nodeDiameter)); int endCol = (int) Math.floor((endX - BORDER) / (2 * nodeDiameter)); int startRow = (int) Math.ceil((startY - BORDER) / (2 * nodeDiameter)); int endRow = (int) Math.floor((endY - BORDER) / (2 * nodeDiameter)); System.out.println("processAreaSelection: " + startCol + "/" + startRow + " - " + endCol + "/" + endRow); for (int col = startCol; col <= endCol; col++) { for (int row = startRow; row <= endRow; row++) { invertNode(col, row); } } fireChangeEvent(); } public File saveScreenToImage(File file) { try { BufferedImage bi = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); Graphics g = bi.createGraphics(); paint(g); System.out.println("filename: " + file.getName()); if (file.getName().indexOf('.') == -1) { // no extension provided file = new File(file.getAbsoluteFile() + ".jpg"); System.out.println("new file ==> " + file.getAbsoluteFile()); } String imageType = file.getName().substring(file.getName().lastIndexOf('.') + 1); ImageIO.write(bi, imageType, file); return file; } catch (java.io.IOException ioEx) { System.out.println("Error saving sreen to file " + ioEx); ioEx.printStackTrace(System.err); } return null; } public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } public void removeChangeListener(ChangeListener l) { listenerList.remove(ChangeListener.class, l); } class DragListener extends MouseInputAdapter { double endX; double endY; double startX; double startY; @Override public void mousePressed(MouseEvent e) { startX = e.getX(); startY = e.getY(); } @Override public void mouseDragged(MouseEvent e) { endX = e.getX(); endY = e.getY(); repaint(); } @Override public void mouseReleased(MouseEvent e) { endX = e.getX(); endY = e.getY(); processAreaSelection(Math.min(startX, endX), Math.min(startY, endY), Math.max(startX, endX), Math.max( startY, endY)); startX = startY = endX = endY = 0; } } @Override public Dimension getPreferredSize() { if (backgroundImageMap != null) { System.out.println("preferred size: " + new Dimension(zoomedWidth + 2 * BORDER, zoomedHeight + 2 * BORDER)); return new Dimension(zoomedWidth + 2 * BORDER, zoomedHeight + 2 * BORDER); } else { return new Dimension(100, 100); } } @Override public Dimension getMinimumSize() { return getPreferredSize(); } public boolean[][] getToDraw() { return toDraw; } public int getNodeCount() { return getToDraw().length * getToDraw()[0].length; } }