/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ZoomAndPanListener.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.user.ui;
import com.sun.electric.Main;
import com.sun.electric.tool.user.Highlighter;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* Class to Zoom and Pan an EditWindow.
*/
public class ZoomAndPanListener
implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener
{
public static ZoomAndPanListener theOne = new ZoomAndPanListener();
private int startX, startY, lastX, lastY;
private ToolBar.CursorMode mode;
private ZoomAndPanListener() {}
public void mousePressed(MouseEvent evt)
{
lastX = startX = evt.getX();
lastY = startY = evt.getY();
mode = ToolBar.getCursorMode();
if (mode == ToolBar.CursorMode.ZOOM)
{
if ((evt.getModifiers()&MouseEvent.CTRL_MASK) != 0) mode = ToolBar.CursorMode.PAN;
} else if (mode == ToolBar.CursorMode.PAN)
{
if ((evt.getModifiers()&MouseEvent.CTRL_MASK) != 0) mode = ToolBar.CursorMode.ZOOM;
}
if (mode == ToolBar.CursorMode.ZOOM && (evt.getSource() instanceof EditWindow)) {
EditWindow wnd = (EditWindow)evt.getSource();
if (!ClickZoomWireListener.isRightMouse(evt))
{
wnd.setStartDrag(startX, startY);
wnd.setEndDrag(startX, startY);
wnd.setDoingAreaDrag();
}
}
setProperCursor(evt);
}
public void mouseClicked(MouseEvent evt) {}
public void mouseEntered(MouseEvent evt) {}
public void mouseExited(MouseEvent evt) {}
public void mouseMoved(MouseEvent evt)
{
setProperCursor(evt);
}
public static void setProperCursor(MouseEvent evt)
{
if (ToolBar.getCursorMode() == ToolBar.CursorMode.ZOOM)
{
if ((evt.getModifiers()&MouseEvent.SHIFT_MASK) != 0)
{
Main.setCurrentCursor(ToolBar.zoomOutCursor);
} else
{
Main.setCurrentCursor(ToolBar.zoomCursor);
}
}
}
public void mouseDragged(MouseEvent evt)
{
setProperCursor(evt);
int newX = evt.getX();
int newY = evt.getY();
if (evt.getSource() instanceof EditWindow)
{
EditWindow wnd = (EditWindow)evt.getSource();
if (wnd == null) return;
double scale = wnd.getScale();
if (mode == ToolBar.CursorMode.ZOOM)
{
wnd.setEndDrag(newX, newY);
wnd.repaint();
// if dragging the right mouse, zoom smoothly
if (ClickZoomWireListener.isRightMouse(evt))
{
// use hand motion to zoom; cap to maximum of 20 pixels per tick
int deltaY = newY - lastY;
double dY = deltaY / 20.0;
if (dY < 0) scale = scale - scale * dY;
else scale = scale * Math.exp(-dY)/*scale - scale * dY*/;
wnd.setScale(scale);
wnd.getSavedFocusBrowser().updateCurrentFocus();
wnd.fullRepaint();
}
} else if (mode == ToolBar.CursorMode.PAN)
{
// panning the window location
Point2D pt = wnd.getScheduledOffset();
wnd.setOffset(new Point2D.Double(pt.getX() - (newX - lastX) / scale,
pt.getY() + (newY - lastY) / scale));
wnd.getSavedFocusBrowser().updateCurrentFocus();
wnd.fullRepaint();
}
lastX = newX;
lastY = newY;
}
}
public void mouseReleased(MouseEvent evt)
{
setProperCursor(evt);
if (mode != ToolBar.CursorMode.ZOOM) return;
if (ClickZoomWireListener.isRightMouse(evt)) return;
if (evt.getSource() instanceof EditWindow)
{
EditWindow wnd = (EditWindow)evt.getSource();
if (wnd == null) return;
Point2D start = wnd.screenToDatabase((int)wnd.getStartDrag().getX(), (int)wnd.getStartDrag().getY());
Point2D end = wnd.screenToDatabase((int)wnd.getEndDrag().getX(), (int)wnd.getEndDrag().getY());
double minSelX = Math.min(start.getX(), end.getX());
double maxSelX = Math.max(start.getX(), end.getX());
double minSelY = Math.min(start.getY(), end.getY());
double maxSelY = Math.max(start.getY(), end.getY());
if ((evt.getModifiers()&MouseEvent.SHIFT_MASK) != 0)
{
wnd.setScale(wnd.getScale() * 0.5);
Point2D offset = new Point2D.Double((minSelX+maxSelX)/2, (minSelY+maxSelY)/2);
if (wnd.isInPlaceEdit())
wnd.getInPlaceTransformOut().transform(offset, offset);
wnd.setOffset(offset);
wnd.getSavedFocusBrowser().updateCurrentFocus();
wnd.fullRepaint();
Main.setCurrentCursor(ToolBar.zoomCursor);
} else
{
// determine if the user clicked on a single point to prevent unintended zoom-in
// a single point is 4 lambda or less AND 10 screen pixels or less
boolean onePoint = true;
Rectangle2D bounds = new Rectangle2D.Double(minSelX, minSelY, maxSelX-minSelX, maxSelY-minSelY);
if (bounds.getHeight() > 4 && bounds.getWidth() > 4) onePoint = false;
if (Math.abs(wnd.getStartDrag().getX()-wnd.getEndDrag().getX()) > 10 ||
Math.abs(wnd.getStartDrag().getY()-wnd.getEndDrag().getY()) > 10) onePoint = false;
if (!onePoint)
{
wnd.focusScreen(bounds);
} else
{
System.out.println("To zoom-in, drag an area");
}
}
wnd.clearDoingAreaDrag();
wnd.repaint();
}
}
public void mouseWheelMoved(MouseWheelEvent evt)
{
int clicks = evt.getWheelRotation();
System.out.println("Mouse wheel rolled by " + clicks);
}
public void keyPressed(KeyEvent evt)
{
int chr = evt.getKeyCode();
if (chr == KeyEvent.VK_ESCAPE)
{
if (evt.getSource() instanceof EditWindow)
{
EditWindow wnd = (EditWindow)evt.getSource();
wnd.clearDoingAreaDrag();
wnd.repaint();
mode = null;
}
}
}
public void keyReleased(KeyEvent evt) {}
public void keyTyped(KeyEvent evt) {}
// ----------------------------------- redisplay commands -----------------------------------
public static void redrawDisplay()
{
// get the current window
EditWindow wnd = EditWindow.getCurrent();
if (wnd == null) return;
wnd.fullRepaint();
}
// --------------------------- Pan Commands -------------------------------
private static double [] panningAmounts = {0.15, 0.3, 0.6};
/**
* Pan in X or Y direction.
* @param direction 0 if X or 1 if Y
* @param wf the WindowFrame
* @param ticks the amount and direction of pan.
*/
public static void panXOrY(int direction, WindowFrame wf, int ticks)
{
wf.getContent().panXOrY(direction, panningAmounts, ticks);
}
/**
* This method implements the command to center the selected objects.
*/
public static void centerSelection()
{
EditWindow wnd = EditWindow.needCurrent();
if (wnd == null) return;
Highlighter highlighter = wnd.getHighlighter();
Rectangle2D bounds = highlighter.getHighlightedArea(wnd);
if (bounds == null) return;
wnd.setOffset(new Point2D.Double(bounds.getCenterX(), bounds.getCenterY()));
wnd.getSavedFocusBrowser().updateCurrentFocus();
wnd.fullRepaint();
}
/**
* This method implements the command to center the cursor.
* @param wf the WindowFrame
*/
public static void centerCursor(WindowFrame wf)
{
wf.getContent().centerCursor();
}
}