package games.strategy.ui; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.awt.geom.Rectangle2D; import javax.swing.JComponent; import javax.swing.border.EtchedBorder; /** * A small image that tracks a selection area within a small image. Generally * used in conjunction with a ImageScrollerLarrgeView. */ public class ImageScrollerSmallView extends JComponent { private static final long serialVersionUID = 7010099211049677928L; private final ImageScrollModel m_model; private Image m_image; public ImageScrollerSmallView(final Image image, final ImageScrollModel model) { m_model = model; Util.ensureImageLoaded(image); setDoubleBuffered(false); m_image = image; this.setBorder(new EtchedBorder()); final int prefWidth = getInsetsWidth() + m_image.getWidth(this); final int prefHeight = getInsetsHeight() + m_image.getHeight(this); final Dimension prefSize = new Dimension(prefWidth, prefHeight); setPreferredSize(prefSize); setMinimumSize(prefSize); setMaximumSize(prefSize); final MouseAdapter MOUSE_LISTENER = new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { // try to center around the click final int x = (int) (e.getX() / getRatioX()) - (m_model.getBoxWidth() / 2); final int y = (int) (e.getY() / getRatioY()) - (m_model.getBoxHeight() / 2); m_model.set(x, y); } }; this.addMouseListener(MOUSE_LISTENER); final MouseMotionListener MOUSE_MOTION_LISTENER = new MouseMotionAdapter() { @Override public void mouseDragged(final MouseEvent e) { final long now = System.currentTimeMillis(); final long MIN_UPDATE_DELAY = 30; if (now < mLastUpdate + MIN_UPDATE_DELAY) { return; } mLastUpdate = now; final Rectangle bounds = (Rectangle) getBounds().clone(); // if the mouse is a little off the screen, allow it to still scroll // the screen bounds.grow(30, 0); if (!bounds.contains(e.getPoint())) { return; } // try to center around the click final int x = (int) (e.getX() / getRatioX()) - (m_model.getBoxWidth() / 2); final int y = (int) (e.getY() / getRatioY()) - (m_model.getBoxHeight() / 2); setSelection(x, y); } }; this.addMouseMotionListener(MOUSE_MOTION_LISTENER); model.addObserver((o, arg) -> repaint()); } public void changeImage(final Image image) { Util.ensureImageLoaded(image); setDoubleBuffered(false); m_image.flush(); m_image = image; final int prefWidth = getInsetsWidth() + m_image.getWidth(this); final int prefHeight = getInsetsHeight() + m_image.getHeight(this); final Dimension prefSize = new Dimension(prefWidth, prefHeight); setPreferredSize(prefSize); setMinimumSize(prefSize); setMaximumSize(prefSize); this.validate(); this.repaint(); } private int getInsetsWidth() { return getInsets().left + getInsets().right; } private int getInsetsHeight() { return getInsets().top + getInsets().bottom; } void setCoords(final int x, final int y) { m_model.set(x, y); } public Dimension getImageDimensions() { return Util.getDimension(m_image, this); } @Override public void paintComponent(final Graphics g) { g.drawImage(m_image, 0, 0, this); g.setColor(Color.lightGray); drawViewBox((Graphics2D) g); } private void drawViewBox(final Graphics2D g) { if (m_model.getBoxWidth() > m_model.getMaxWidth() && m_model.getBoxHeight() > m_model.getMaxHeight()) { return; } final double ratioX = getRatioX(); final double ratioY = getRatioY(); final double x = m_model.getX() * ratioX; final double y = m_model.getY() * ratioY; final double width = m_model.getBoxWidth() * ratioX; final double height = m_model.getBoxHeight() * ratioY; final Rectangle2D.Double rect = new Rectangle2D.Double(x, y, width, height); g.draw(rect); if (m_model.getScrollX()) { final double mapWidth = m_model.getMaxWidth() * ratioX; rect.x += mapWidth; g.draw(rect); rect.x -= 2 * mapWidth; g.draw(rect); } } public Image getOffScreenImage() { return m_image; } private void setSelection(final int x, final int y) { m_model.set(x, y); } private long mLastUpdate = 0; public double getRatioY() { return m_image.getHeight(null) / (double) m_model.getMaxHeight(); } public double getRatioX() { return m_image.getWidth(null) / (double) m_model.getMaxWidth(); } }