/* * org.openmicroscopy.shoola.util.ui.lens.LensController.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.Cursor; //Third-party libraries //Application-internal dependencies /** * The LensController is the main controlling class which manipulates the lens, * Zoomwindow and allows the user to change the size and magnification of the * lens. * * @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 LensController { /** The default zoom value.*/ static final float DEFAULT_ZOOM = 2.0f; /** Reference to the Lens Model. */ private LensModel lensModel; /** Reference to the lens object which will be displayed on the Browser. */ private LensUI lens; /** X-coordinate of offset used to determine the pick spot on the lens. */ private int offsetX; /** Y-coordinate of offset used to determine the pick spot on the lens. */ private int offsetY; /** X-coordinate of the starting position of the lens. */ private int startX; /** Y-coordinate of the starting position of the lens. */ private int startY; /** Zoom Window which displays the area under the lens zoomed. */ private ZoomWindow zoomWindow; /** The direction in which the lens will be resized. */ private int resizeDir; /** This will be set to <code>true</code> if the lens is being dragged. */ private boolean lensDrag; /** This will be set to <code>true</code> if the border is being dragged. */ private boolean borderDrag; /** * Checks to see if the bounds of the lens are within the constraints; * {@link LensUI#MINIMUM_WIDTH}, {@link LensUI#MINIMUM_HEIGHT}, * {@link LensUI#MAXIMUM_WIDTH} or {@link LensUI#MAXIMUM_HEIGHT}. * * @param dx change in x-coordinate. * @param dy change in y-coordinate. * @param dw change in width. * @param dh change in height. * * @return true if in bounds. */ private boolean checkBounds(int dx, int dy, int dw , int dh) { int newX = lens.getX()+dx; int newY = lens.getY()+dy; int newWidth = (int) ((lens.getWidth()+dw)/ lensModel.getImageZoomFactor()); int newHeight = (int) ((lens.getHeight()+dh)/ lensModel.getImageZoomFactor()); return (newX > 0 && newY > 0 && newWidth >= LensUI.MINIMUM_WIDTH && newWidth <= LensUI.MAXIMUM_WIDTH && newHeight >= LensUI.MINIMUM_HEIGHT && newHeight <= LensUI.MAXIMUM_HEIGHT && newHeight+newY <= lensModel.getImageScaledHeight() && newWidth+newX <= lensModel.getImageScaledWidth()); } /** * Sets the size and position of the lens based on the parameters provided. * Updates, model and zoomwindowUI at the same time. * * @param dx change in x-coordinate. * @param dy change in y-coordinate. * @param dw change in width. * @param dh change in height. * @param keepSquare adjust the deltas so the lens is square when moving. */ private void setLensBounds(int dx, int dy, int dw, int dh, boolean keepSquare) { int newX = lens.getX()+dx; int newY = lens.getY()+dy; int newWidth, newHeight; if (keepSquare) { int mx = Math.max(dw, dh); int mn = Math.min(dw, dh); if (Math.abs(mx) > Math.abs(mn)) { dw = mx; dh = mx; } else { dw = mn; dh = mn; } } if (checkBounds(dx, dy, dw, dh)) { newWidth = lens.getWidth()+dw; newHeight = lens.getHeight()+dh; lens.setBounds(newX, newY, newWidth, newHeight); double f = lensModel.getImageZoomFactor(); lensModel.setLensLocation((int) (newX/f), (int)(newY/f)); lensModel.setWidth((int) (newWidth/f)); lensModel.setHeight((int) (newHeight/f)); zoomWindow.setLensXY(lensModel.getX(), lensModel.getY()); zoomWindow.setLensWidthHeight(lensModel.getWidth(), lensModel.getHeight()); setZoomUISize(); } } /** * Sets the new UI size of the zoom window based on the zoomfactor and * lens size. */ private void setZoomUISize() { float zoomFactor = lensModel.getZoomFactor(); int width = lensModel.getWidth(); int height = lensModel.getHeight(); zoomWindow.setZoomUISize(width*zoomFactor, height*zoomFactor); zoomWindow.setLensZoomFactor(zoomFactor); //zoomWindow.setZoomImage(lensModel.getZoomedImage()); } /** * Returns the correct cursor type for the border edge selected. * * @param resizeDir Direction of the border picked. * @return See above. */ private Cursor getCursorForDir(int resizeDir) { Cursor s = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); switch (resizeDir) { case LensUI.SOUTH: s = new Cursor(Cursor.S_RESIZE_CURSOR); break; case LensUI.NORTH: s = Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR); break; case LensUI.WEST: s = Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR); break; case LensUI.EAST: s = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR); break; case LensUI.SOUTH_EAST: s = Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR); break; case LensUI.SOUTH_WEST: s = Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR); break; case LensUI.NORTH_WEST: s = Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR); break; case LensUI.NORTH_EAST: s = Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR); break; } return s; } /** * Creates a new instance. * * @param model Model of the data. Mustn't be <code>null</code>. * @param lens Viewport on image canvas. * Mustn't be <code>null</code>. * @param zoomWindow Zoomed version of the viewport on image canvas. * Mustn't be <code>null</code>. */ LensController(LensModel model, LensUI lens, ZoomWindow zoomWindow) { if (model == null) throw new IllegalArgumentException("No model."); if (lens == null) throw new IllegalArgumentException("No view."); if (zoomWindow == null) throw new IllegalArgumentException("No window."); lensModel = model; this.lens = lens; this.zoomWindow = zoomWindow; lensDrag = false; borderDrag = false; } /** * Sets the position of the lens to x,y on the image. * * @param x See above. * @param y See above. */ void setLensLocation(int x, int y) { lensModel.setLensLocation(x,y); lens.setLocation(lensModel.getScaledX(),lensModel.getScaledY()); //zoomWindow.setZoomImage(lensModel.getZoomedImage()); zoomWindow.setLensXY(lensModel.getX(), lensModel.getY()); zoomWindow.setLensWidthHeight(lensModel.getWidth(), lensModel.getHeight()); } /** * Sets the size of the lens to width, height on the image. * * @param w See above. * @param h See above. */ void setLensSize(int w, int h) { int scaledW, scaledH; scaledW = (int) (w*lensModel.getImageZoomFactor()); scaledH = (int) (h*lensModel.getImageZoomFactor()); if (lens.getX()+scaledW > lensModel.getImageScaledWidth()) { scaledW = lensModel.getImageScaledWidth()-lens.getX(); w = (int) (scaledW/lensModel.getImageZoomFactor()); } if (lens.getY()+scaledH > lensModel.getImageScaledHeight()) { scaledH = lensModel.getImageScaledHeight()-lens.getY(); h = (int) (scaledH/lensModel.getImageZoomFactor()); } lensModel.setWidth(w); lensModel.setHeight(h); lens.setSize(scaledW, scaledH); //zoomWindow.setZoomImage(lensModel.getZoomedImage()); zoomWindow.setLensWidthHeight(lensModel.getWidth(), lensModel.getHeight()); setZoomUISize(); } /** * Sets the zoomfactor for the lens. * * @param zoomFactor The value to set. */ void setZoomFactor(float zoomFactor) { lensModel.setZoomFactor(zoomFactor); setZoomUISize(); //zoomWindow.repaint(); //zoomWindow.setZoomImage(lensModel.getZoomedImage()); } /** * Shows or hides the crosshairs on the lens. * * @param isVisible Pass <code>true</code> to show, <code>false</code> * to hide. */ void setShowCrossHairs(boolean isVisible) { lens.setShowCrossHair(isVisible); } /** * Mouse up event triggered from lens. * * @param x x mouse position. * @param y y mouse position. */ void lensMouseUp(int x, int y) { lensDrag = false; borderDrag = false; offsetX = 0; offsetY = 0; lens.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } /** * Mouse moved event triggered from lens. * * @param x x mouse position. * @param y y mouse position. */ void lensMouseMoved(int x, int y) { if (lens.lensPicked(x, y)) { Cursor s = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); lens.setCursor(s); } else if (lens.lensBorderPicked(x, y)) { resizeDir = lens.getPickDir(x, y); Cursor s = getCursorForDir(resizeDir); lens.setCursor(s); } } /** * Mouse down event triggered from lens. * * @param x x mouse position. * @param y y mouse position. */ void lensMouseDown(int x, int y) { if (lens.lensBorderPicked(x, y)) { borderDrag = true; resizeDir = lens.getPickDir(x, y); Cursor s = getCursorForDir(resizeDir); lens.setCursor(s); startX = lens.getX(); startY = lens.getY(); offsetX = x; offsetY = y; } else if (lens.lensPicked(x, y)) { offsetX = x; offsetY = y; startX = lens.getX(); startY = lens.getY(); lensDrag = true; } } /** * 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 isShiftDown Pass <code>true</true> if the shift key is pressed, * <code>false</true> otherwise. */ void lensMouseDrag(int x, int y, boolean isShiftDown) { if (borderDrag) { int deltaX = 0; int deltaY = 0; int deltaW = 0; int deltaH = 0; switch(resizeDir) { case LensUI.NORTH: if (y-offsetY < 0) { deltaY = (y-offsetY); deltaH = Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startY = startY+(y-offsetY); } else { deltaY = (y-offsetY); deltaH = -Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startY = startY+(y-offsetY); } break; case LensUI.SOUTH: if (y-offsetY > 0) { deltaH = Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetY = y; } else { deltaH = -Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetY = y; } break; case LensUI.EAST: if (x-offsetX > 0) { deltaW = Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetX = x; } else { deltaW = -Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetX = x; } break; case LensUI.WEST: if (x-offsetX > 0) { deltaX = (x-offsetX); deltaW = -Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startX = startX+(x-offsetX); } else { deltaX = -Math.abs(x-offsetX); deltaW = Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startX = startX+(x-offsetX); } break; case LensUI.NORTH_EAST: if (y-offsetY < 0) { deltaY = (y-offsetY); deltaH = Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startY = startY+(y-offsetY); } else { deltaY = (y-offsetY); deltaH = -Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startY = startY+(y-offsetY); } if (x-offsetX > 0) { deltaW = Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetX = x; } else { deltaW = -Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetX = x; } break; case LensUI.NORTH_WEST: if (y-offsetY < 0) { deltaY = (y-offsetY); deltaH = Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startY = startY+(y-offsetY); } else { deltaY = (y-offsetY); deltaH = -Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startY = startY+(y-offsetY); } if (x-offsetX > 0) { deltaX = (x-offsetX); deltaW = -Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startX = startX+(x-offsetX); } else { deltaX = -Math.abs(x-offsetX); deltaW = Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startX = startX+(x-offsetX); } break; case LensUI.SOUTH_EAST: if (y-offsetY > 0) { deltaH = Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetY = y; } else { deltaH = -Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetY = y; } if (x-offsetX > 0) { deltaW = Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetX = x; } else { deltaW = -Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetX = x; } break; case LensUI.SOUTH_WEST: if (y-offsetY > 0) { deltaH = Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetY = y; } else { deltaH = -Math.abs(y-offsetY); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) offsetY = y; } if (x-offsetX > 0) { deltaX = (x-offsetX); deltaW = -Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startX = startX+(x-offsetX); } else { deltaX = -Math.abs(x-offsetX); deltaW = Math.abs(x-offsetX); if (checkBounds(deltaX, deltaY, deltaW, deltaH)) startX = startX+(x-offsetX); } break; } setLensBounds(deltaX, deltaY, deltaW, deltaH, isShiftDown); } if (lensDrag) { boolean moveX = true; boolean moveY = true; if(startX+(x-offsetX) < 0) { moveX = false; startX = 0; } double v = (startX+(x-offsetX))/lensModel.getImageZoomFactor()+ lensModel.getWidth(); if (v > lensModel.getImageWidth()) { moveX = false; startX = lensModel.getImageScaledWidth()- lensModel.getScaledWidth(); } if (startY+(y-offsetY) < 0) { moveY = false; startY = 0; } if (startY+(y-offsetY)+lens.getHeight() > lensModel.getImageScaledHeight()) { moveY = false; startY = lensModel.getImageScaledHeight()- lensModel.getScaledHeight(); } if (moveX) startX = startX+(x-offsetX); if (moveY) startY = startY+(y-offsetY); setLensLocation((int) (startX/lensModel.getImageZoomFactor()), (int) (startY/lensModel.getImageZoomFactor())); } } }