/*
* org.openmicroscopy.shoola.util.ui.lens.LensUI.java
*
*------------------------------------------------------------------------------
* Copyright (C) 2006 University of Dundee. All rights reserved.
*
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.util.ui.lens;
//Java imports
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
//Third-party libraries
//Application-internal dependencies
/**
* Magnifying lens, will show a lens on the image and link into a second window
* which will display the magnified image.
*
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author Donald MacDonald
* <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
* @version 3.0
* <small>
* (<b>Internal version:</b> $Revision: $Date: $)
* </small>
* @since OME2.2
*/
class LensUI
extends JPanel
{
/** Pick size of the border, this is a border running <code>BORDER_PICK_SIZE
* </code> units around the edge of the lens.
*/
private int borderPickSize = 8;
/** Constants defining the border being picked. Where
* +-----+=====+-----+
* | ^^^ ^^^ ^^^ |
* | <NW N NE |
* | |
* | |
* | |
* + +
* $ $
* $ $
* $<W E>$
* $ $
* $ $
* + +
* | |
* | |
* | |
* | |
* | |
* +-----+=====+-----+
* ^^^ ^^^ ^^^
* SW S SE
* are passed back by {@link #getPickDir(int, int)} return the border area
* picked by the user.
*
* Constant for North border Pick.
*/
final static int NORTH = 0;
/** Constant for North west border Pick. */
final static int NORTH_WEST = 1;
/** Constant for North east border Pick. */
final static int NORTH_EAST = 2;
/** Constant for South border Pick. */
final static int SOUTH = 3;
/** Constant for South west border Pick. */
final static int SOUTH_WEST = 4;
/** Constant for South east border Pick. */
final static int SOUTH_EAST = 5;
/** Constant for East border Pick. */
final static int EAST = 6;
/** Constant for West border Pick. */
final static int WEST = 7;
/** Minimum height of the lens. This will constrain the size of the lens
* when the user resizes it using the border picking. */
final static int MINIMUM_HEIGHT = 20;
/** Maximum height of the lens. This will constrain the size of the lens
* when the user resizes it using the border picking. */
final static int MAXIMUM_HEIGHT = 150;
/** Minimum width of the lens. This will constrain the size of the lens
* when the user resizes it using the border picking. */
final static int MINIMUM_WIDTH = 20;
/** Maximum width of the lens. This will constrain the size of the lens
* when the user resizes it using the border picking. */
final static int MAXIMUM_WIDTH = 150;
/** When the width or height of the lens is this size, snap the cross hair
* to SNAPPED_CROSSHAIR length;
*/
final static int CROSSHAIR_SNAP = 30;
/** size of the crosshair when snapped. */
final static int SNAPPED_CROSSHAIR = 6;
/** size of the crosshair when nto snapped. */
final static int UNSNAPPED_CROSSHAIR = 8;
/** Default colour of the lens. */
final static Color DEFAULT_LENS_COLOR =
new Color(128, 128, 128, 240);
/** size of the crosshair, running from centre of lens. */
private int crosshairLength = UNSNAPPED_CROSSHAIR;
/** size of the visible crosshair. */
private int crosshairTick = crosshairLength/2-1;
/** Colour of the frame of the lens */
private Color lensBorderColour = DEFAULT_LENS_COLOR;
/** Colour of the lens cross hair. */
private Color lensCrossHairColour =
new Color(194, 194, 194, 220);
/** LensUI Controller. */
private LensController lensController;
/** Show the cross hair on the lens */
private boolean showCrossHair;
/** Mouselistener for the lens. */
private LensMouseListener mouseListener;
/** Parent component of the lens and zoomWindowUI. */
private LensComponent lensComponent;
/** lens popupMenu. */
private JPopupMenu menu;
/**
* Sets the pick border area when the lens resizes and also change the size
* of the crosshairs.
*
* @param w Width of lens.
* @param h Height of lens.
*/
private void setPickParam(int w, int h)
{
if (Math.min(w, h) < CROSSHAIR_SNAP)
{
crosshairLength = 6;
borderPickSize = 4;
}
else
{
crosshairLength = 8;
borderPickSize = 8;
}
crosshairTick = crosshairLength/2-1;
}
/**
* Constructor for the lens control. Will set initial width and height of
* the LensUI.
*
* @param lensComponent Parent component of the lens.
* @param w Width of the LensUI.
* @param h Height of the lens.
*/
LensUI(LensComponent lensComponent, int w, int h)
{
this.lensComponent = lensComponent;
setSize(new Dimension(w,h));
setOpaque(false);
setShowCrossHair(true);
mouseListener = new LensMouseListener(this);
addMouseListener(mouseListener);
addMouseMotionListener(mouseListener);
addMouseWheelListener(mouseListener);
}
/**
* Sets the popup menu of the lens to menu.
*
* @param menu popupmenu.
*/
void setPopupMenu(JPopupMenu menu)
{
this.menu = menu;
}
/**
* Sets the prefered size of the lens to (w, h) and if needed shrink the
* lens crosshairs.
*
* @param w see above.
* @param h see above/
*/
void setPreferredSize(int w, int h)
{
super.setPreferredSize(new Dimension(w, h));
setPickParam(w, h);
}
/**
* Returns <code>true</code> if the lens has been picked, this is the area
* inside the border.
*
* +--------+
* | Border |
* | +----+ |
* | |Lens| |
* | +----+ |
* | |
* +--------+
*
* @param x mouse X position inside the lens.
* @param y mouse Y position inside the lens.
*
* @return see above.
*/
boolean lensPicked(int x, int y)
{
Rectangle rect = new Rectangle(borderPickSize, borderPickSize,
this.getWidth()-borderPickSize*2,
this.getHeight()-borderPickSize*2);
return rect.contains(x, y);
}
/**
* Sets the image zoom factor. The image in the viewer has been zoomed by
* this number.
*/
void setImageZoomFactor()
{
setSize(lensComponent.getLensScaledSize());
setLocation(lensComponent.getLensScaledLocation().x,
lensComponent.getLensScaledLocation().y);
}
/**
* Returns <code>true</code> if the mouse event at the passed lcoation
* (x,y) is inside the border, <code>false</code> otherwise.
* +--------+
* | Border |
* | +----+ |
* | |Lens| |
* | +----+ |
* | |
* +--------+
*
* @param x mouse X position inside the lens.
* @param y mouse Y position inside the lens.
*
* @return see above.
*/
boolean lensBorderPicked(int x, int y)
{
Rectangle rect = new Rectangle(borderPickSize, borderPickSize,
this.getWidth()-borderPickSize*2,
this.getHeight()-borderPickSize*2);
Rectangle rectBorder = new Rectangle(0, 0,
this.getWidth(), this.getHeight());
return (!rect.contains(x, y) && rectBorder.contains(x, y));
}
/**
* Shows or hides the cross hairs in the lens.
*
* @param show see above.
*/
void setShowCrossHair(boolean show)
{
showCrossHair = show;
}
/**
* Mouse down event triggered from lens mouse listener.
*
* @param x x mouse position.
* @param y y mouse position.
*/
void mouseMoved(int x, int y)
{
lensController.lensMouseMoved(x, y);
lensComponent.updateLensLocation();
}
/**
* Mouse down event triggered from lens mouse listener.
*
* @param x x mouse position.
* @param y y mouse position.
*/
void mouseDown(int x, int y)
{
lensController.lensMouseDown(x, y);
}
/**
* Mouse drag event triggered from lens, if the shift key is pressed
* dX and dY will be the same; equal to which ever one is greater, this
* is used to keep the lens square when shift pressed.
*
* @param x x mouse position.
* @param y y mouse position.
* @param shift Pass <code>true</true> if the shift key is pressed,
* <code>false</true> otherwise.
*/
void mouseDrag(int x, int y, boolean shift)
{
lensController.lensMouseDrag(x, y, shift);
lensComponent.updateLensLocation();
}
/**
* Mouse down event triggered from lens mouse listener.
*
* @param x x mouse position.
* @param y y mouse position.
*/
void mouseUp(int x, int y)
{
lensController.lensMouseUp(x, y);
lensComponent.updateLensSize();
}
/**
* MouseWheel moved by tick units.
*
* @param tick The tick unit
*/
void mouseWheelMoved(int tick)
{
lensComponent.lensMouseWheelMoved(tick);
}
/**
* Shows the popup menu at (x,y).
*
* @param x see above.
* @param y see above.
* */
void showMenu(int x, int y) { menu.show(this, x, y); }
/**
* Attaches lens to controller.
*
* @param lensController
*/
void addController(LensController lensController)
{
this.lensController = lensController;
}
/**
* Returns the constant defining where in the border the user cliked.
* +-----+=====+-----+
* | ^^^ ^^^ ^^^ |
* | <NW N NE |
* | |
* | |
* | |
* + +
* $ $
* $ $
* $<W E>$
* $ $
* $ $
* + +
* | |
* | |
* | |
* | |
* | |
* +-----+=====+-----+
* ^^^ ^^^ ^^^
* SW S SE
*
* @param x mouse x position in the border.
* @param y mouse y position in the border.
*
* @return see above.
*/
int getPickDir(int x, int y)
{
int resizeDir=-1;
int resizeCornerSize = 0;
if (x <= borderPickSize) {
if (y < resizeCornerSize + borderPickSize)
resizeDir = NORTH_WEST;
else if (y > this.getHeight()-resizeCornerSize-borderPickSize)
resizeDir = SOUTH_WEST;
else resizeDir = WEST;
} else if (x >= this.getWidth()-borderPickSize) {
if (y < resizeCornerSize+borderPickSize) resizeDir = NORTH_EAST;
else if (y > this.getHeight()-resizeCornerSize-borderPickSize)
resizeDir = SOUTH_EAST;
else resizeDir = EAST;
} else if (y <= borderPickSize) {
if (x < resizeCornerSize+borderPickSize) resizeDir = NORTH_WEST;
else if (x > this.getWidth()-resizeCornerSize-borderPickSize)
resizeDir = NORTH_EAST;
else resizeDir = NORTH;
} else if (y >= this.getHeight()-borderPickSize) {
if (x < resizeCornerSize+borderPickSize) resizeDir = SOUTH_WEST;
else if (x > this.getWidth()-resizeCornerSize-borderPickSize)
resizeDir = SOUTH_EAST;
else resizeDir = SOUTH;
}
return resizeDir;
}
/**
* Sets the colour of the lens border.
*
* @param c Colour of the lens border.
*/
void setLensColour(Color c)
{
if (c == null) return;
this.lensBorderColour = c;
this.lensCrossHairColour = c;
invalidate();
repaint();
}
/**
* Overridden to show the lens frame and depending on settings the
* crosshairs.
* @see javax.swing.JComponent#paintComponent(Graphics)
*/
public void paintComponent(Graphics og)
{
super.paintComponent(og);
Graphics2D g = (Graphics2D) og;
g.setStroke(new BasicStroke(2.0f));
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(lensBorderColour);
g.drawRect(1, 1, getWidth()-3, getHeight()-3);
if (showCrossHair)
{
g.setStroke(new BasicStroke(1.0f));
g.setColor(lensCrossHairColour);
g.drawLine((getWidth()-crosshairTick+1)/2,
(getHeight()-crosshairTick+1)/2-crosshairLength,
(getWidth()-crosshairTick+1)/2,
(getHeight()-crosshairTick+1)/2-crosshairTick);
g.drawLine((getWidth()-crosshairTick+1)/2,
(getHeight()-crosshairTick+1)/2+crosshairTick,
(getWidth()-crosshairTick+1)/2,
(getHeight()-crosshairTick+1)/2+crosshairLength);
g.drawLine((getWidth()-crosshairTick+1)/2-crosshairLength,
(getHeight()-crosshairTick+1)/2,
(getWidth()-crosshairTick+1)/2-crosshairTick,
(getHeight()-crosshairTick+1)/2);
g.drawLine((getWidth()-crosshairTick+1)/2+crosshairTick,
(getHeight()-crosshairTick+1)/2,
(getWidth()-crosshairTick+1)/2+crosshairLength,
(getHeight()-crosshairTick+1)/2);
}
}
/**
* Overridden to set the location of the lens to the coordinates (x,y)
* @see java.awt.Component#setLocation(int, int)
*/
public void setLocation(int x, int y)
{
this.setBounds(x, y, getWidth(), getHeight());
}
/**
* Overridden to allow the panel to change size and the lens to resize with
* it.
* @see java.awt.Component#setSize(Dimension)
*/
public void setSize(Dimension d)
{
super.setSize(d);
setPickParam(d.width, d.height);
}
/**
* Overridden to allows the panel to change size and the lens to resize with
* it.
* @see java.awt.Component#setSize(int, int)
*/
public void setSize(int w, int h)
{
super.setSize(w, h);
setPickParam(w, h);
}
/**
* Overridden to set the bounds of the lens; x,y position and width and
* height. If the lens is too small shrink crosshairs.
* @see java.awt.Component#setBounds(int, int, int, int)
*/
public void setBounds(int x, int y, int w, int h)
{
super.setBounds(x, y, w, h);
setPickParam(w, h);
}
/**
* Overridden to set the bounds of the lens; x,y position and width and
* height. If the lens is too small shrink crosshairs.
* @see java.awt.Component#setBounds(Rectangle)
*/
public void setBounds(Rectangle r)
{
setBounds(r.x, r.y, r.width, r.height);
}
}