package com.elsealabs.xshot.views;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import com.elsealabs.xshot.capture.Capture;
import com.elsealabs.xshot.capture.Capture.AREA;
import com.elsealabs.xshot.math.Scale;
public class PanelCapture extends JPanel
{
// Referenced outside objects
private JComponent parent;
private JFrame frame;
private Capture capture;
private JScrollPane scrollPane;
// State-related attributes
private boolean debug = false;
private boolean saved = false;
// Size-related attributes
private int width;
private int height;
private Dimension frameSize;
private Point viewportPoint;
private Scale scale = Scale.getInstance();
// Information regarding collision
private int padWidth;
private int colWidth;
private int colHeight;
private Rectangle imageWhole;
private Rectangle imageNorth;
private Rectangle imageSouth;
private Rectangle imageEast;
private Rectangle imageWest;
private AREA currentArea;
private Point initial;
private boolean pressListening;
// Image hover hints
private AREA hoverArea;
/**
* Creates a new PanelCapture
*
* @param parent The component the capture is inside of
* @param frame The frame the parent and the panel are inside of
* @param capture The capture to display in the panel
*/
public PanelCapture(JComponent parent, JFrame frame, Capture capture)
{
this.parent = parent;
this.frame = frame;
this.capture = capture;
if (parent instanceof JScrollPane) scrollPane = ((JScrollPane) parent);
width = capture.getTotalBounds().width;
height = capture.getTotalBounds().height;
imageWhole = new Rectangle();
imageNorth = new Rectangle();
imageSouth = new Rectangle();
imageEast = new Rectangle();
imageWest = new Rectangle();
padWidth = 10;
colWidth = 20;
colHeight = 20;
frameSize = new Dimension(0, 0);
_addListeners();
}
/**
* Adds relevant listeners required f or the panel capture to
* function correctly.
*/
private void _addListeners()
{
/**
* Mouse Listener to track initial point that starts the drag
*/
addMouseListener(new MouseAdapter()
{
@Override
public void mouseReleased(MouseEvent e)
{
pressListening = false;
super.mouseReleased(e);
}
@Override
public void mousePressed(MouseEvent e)
{
if ((currentArea = locateArea(e.getPoint())) != null)
{
pressListening = true;
// Scale mouse clicks
Point original = e.getPoint();
Point scaled = new Point(scale.scale(original.x) , scale.scale(original.y));
initial = scaled;
}
super.mousePressed(e);
}
});
/**
* Mouse Motion Listener to track dragging
*/
addMouseMotionListener(new MouseMotionAdapter()
{
/**
* Fires the events to cause dragging the image to be recognized.
*/
@Override
public void mouseDragged(MouseEvent e)
{
Point scaled = scale.scalePoint(e.getPoint());
if (currentArea != null && pressListening)
{
// Update currentAreas based on whether or not they are being updated
// on the y-axis or the x-axis;
switch (currentArea)
{
case NORTH:
case SOUTH:
capture.addTo(currentArea, initial.y - scaled.y);
break;
case EAST:
case WEST:
capture.addTo(currentArea, initial.x - scaled.x);
break;
case NORTHWEST:
capture.addTo(Capture.AREA.NORTH, initial.y - scaled.y);
capture.addTo(Capture.AREA.WEST , initial.x - scaled.x);
break;
case NORTHEAST:
capture.addTo(Capture.AREA.NORTH, initial.y - scaled.y);
capture.addTo(Capture.AREA.EAST , initial.x - scaled.x);
break;
case SOUTHWEST:
capture.addTo(Capture.AREA.SOUTH, initial.y - scaled.y);
capture.addTo(Capture.AREA.WEST , initial.x - scaled.x);
break;
case SOUTHEAST:
capture.addTo(Capture.AREA.SOUTH, initial.y - scaled.y);
capture.addTo(Capture.AREA.EAST , initial.x - scaled.x);
break;
default:
break;
}
initial = scaled;
updateCollisionBounds();
repaint();
}
super.mouseDragged(e);
}
/**
* Updates the image visuals based on the position of the mouse.
*/
@Override
public void mouseMoved(MouseEvent e)
{
Point scaled = scale.scalePoint(e.getPoint());
if (imageWhole.contains(scaled)) hoverArea = locateArea(scaled);
else hoverArea = null;
repaint();
super.mouseMoved(e);
}
});
}
/**
* Paints the components and handles when information regarding
* positioning should be updated
*/
public void paint(Graphics gd)
{
Graphics2D g = (Graphics2D) gd;
g.clearRect(0, 0, width, height);
/**
* Scale all used bounds
*/
Rectangle boundsUpdatedScaled = scale.scaleRectangle(capture.getUpdatedBounds());
//System.out.println("SCALED BOUNDS: " + boundsUpdatedScaled);
/**
* This ensures that the viewport will only be repositioned when the user
* is re-sizing the frame.
*/
if (
frameSize.getWidth() != frame.getSize().getWidth() ||
frameSize.getHeight() != frame.getSize().getHeight()
)
{
repositionViewport();
updateCollisionBounds();
frameSize = frame.getSize();
}
// Draw the capture's image with it's most recently updated bounds
BufferedImage scaled = new BufferedImage(
boundsUpdatedScaled.width,
boundsUpdatedScaled.height,
BufferedImage.TYPE_INT_ARGB
);
Graphics gscaled = scaled.createGraphics();
g.drawImage(
capture.getUpdatedImage(),
boundsUpdatedScaled.x,
boundsUpdatedScaled.y,
boundsUpdatedScaled.width,
boundsUpdatedScaled.height,
null
);
// Draw the image's visual hints
if (hoverArea == null)
{
g.setColor(Color.LIGHT_GRAY);
g.draw(boundsUpdatedScaled);
}
else
{
g.setColor(Color.black);
g.draw(boundsUpdatedScaled);;
}
if (debug)
{
g.setColor(Color.RED);
g.draw(boundsUpdatedScaled);
g.setColor(Color.BLUE);
g.draw(imageEast);
g.draw(imageWest);
g.setColor(Color.GREEN);
g.draw(imageNorth);
g.draw(imageSouth);
}
}
/**
* This takes the width of the viewport and the width of the image
* current being displayed and centers the image in the viewport.
*/
public void repositionViewport()
{
if (parent instanceof JScrollPane)
{
Rectangle boundsUpdatedScaled = scale.scaleRectangle(capture.getUpdatedBounds());
JViewport viewport = scrollPane.getViewport();
int proper_width = (viewport.getWidth() / 2) - (boundsUpdatedScaled.width / 2);
int proper_height = (viewport.getHeight() / 2) - (boundsUpdatedScaled.height / 2);
viewportPoint = new Point(
(500 / 2) + boundsUpdatedScaled.x - proper_width,
(500 / 2) + boundsUpdatedScaled.y - proper_height
);
viewport.setViewPosition(viewportPoint);
}
}
/**
* Updates relevant boundaries generated from dimension information that
* will be used to calculate collision and image re-sizing.
*/
public void updateCollisionBounds()
{
Rectangle boundsUpdatedScaled = scale.scaleRectangle(capture.getUpdatedBounds());
// Bounds of entire image, plus padding
imageWhole.setBounds(
boundsUpdatedScaled.x - scale.scale(padWidth),
boundsUpdatedScaled.y - scale.scale(padWidth),
boundsUpdatedScaled.width + (scale.scale(padWidth) * 2),
boundsUpdatedScaled.height + (scale.scale(padWidth) * 2)
);
// Image's Northern Collision Bounds
imageNorth.setBounds(
boundsUpdatedScaled.x - (scale.scale(colWidth) / 2),
boundsUpdatedScaled.y - (scale.scale(colHeight) / 2),
boundsUpdatedScaled.width + scale.scale(colWidth),
scale.scale(colHeight)
);
// Image's Southern Collision Bounds
imageSouth.setBounds(
boundsUpdatedScaled.x - (scale.scale(colWidth) / 2),
boundsUpdatedScaled.y + boundsUpdatedScaled.height - (scale.scale(colHeight) / 2),
boundsUpdatedScaled.width + scale.scale(colWidth),
scale.scale(colHeight)
);
// Image's Eastern Collision Bounds
imageEast.setBounds(
boundsUpdatedScaled.x + boundsUpdatedScaled.width - (scale.scale(colWidth) / 2),
boundsUpdatedScaled.y - (scale.scale(colHeight) / 2),
scale.scale(colWidth),
boundsUpdatedScaled.height + scale.scale(colHeight)
);
// Image's Western Collision Bounds
imageWest.setBounds(
boundsUpdatedScaled.x - (scale.scale(colWidth) / 2),
boundsUpdatedScaled.y - (scale.scale(colHeight) / 2),
scale.scale(colWidth),
boundsUpdatedScaled.height + scale.scale(colHeight)
);
}
/**
* Quickly locate the area in which the point is contained by.
*
* @param p The point whose area is to be located.
* @return The area in which the point is located.
*/
public Capture.AREA locateArea(Point p)
{
if (imageNorth.contains(p) && imageEast .contains(p)) return Capture.AREA.NORTHEAST;
else if (imageEast .contains(p) && imageSouth.contains(p)) return Capture.AREA.SOUTHEAST;
else if (imageSouth.contains(p) && imageWest .contains(p)) return Capture.AREA.SOUTHWEST;
else if (imageWest .contains(p) && imageNorth.contains(p)) return Capture.AREA.NORTHWEST;
else if (imageNorth.contains(p)) return Capture.AREA.NORTH;
else if (imageEast .contains(p)) return Capture.AREA.EAST;
else if (imageSouth.contains(p)) return Capture.AREA.SOUTH;
else if (imageWest .contains(p)) return Capture.AREA.WEST;
else if (imageWhole.contains(p)) return Capture.AREA.WHOLE;
else return null;
}
public void setSaved(boolean saved)
{
this.saved = saved;
}
public boolean isSaved()
{
return saved;
}
}