/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: MeasureListener.java
*
* Copyright (c) 2004 Sun Microsystems and Static Free Software
*
* 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.database.geometry.Dimension2D;
import com.sun.electric.database.text.TextUtils;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.technology.Technology;
import com.sun.electric.tool.Client;
import com.sun.electric.tool.user.Highlight;
import com.sun.electric.tool.user.Highlighter;
import com.sun.electric.tool.user.waveform.Panel;
import com.sun.electric.tool.user.waveform.WaveformWindow;
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.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Class to make measurements in a window.
*/
public class MeasureListener implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener
{
public static MeasureListener theOne = new MeasureListener();
private static double lastMeasuredDistanceX = 0, lastMeasuredDistanceY = 0;
private static double lastValidMeasuredDistanceX = 0, lastValidMeasuredDistanceY = 0;
private static boolean measuring = false; // true if drawing measure line
private static List<Highlight> lastHighlights = new ArrayList<Highlight>();
private Point2D dbStart; // start of measure in database units
private MeasureListener() {}
public static Dimension2D getLastMeasuredDistance()
{
Dimension2D dim = new Dimension2D.Double(lastValidMeasuredDistanceX,
lastValidMeasuredDistanceY);
return dim;
}
private void startMeasure(Point2D dbStart)
{
lastValidMeasuredDistanceX = lastMeasuredDistanceX;
lastValidMeasuredDistanceY = lastMeasuredDistanceY;
this.dbStart = dbStart;
measuring = true;
lastHighlights.clear();
}
private void dragOutMeasure(EditWindow wnd, Point2D dbPoint)
{
if (measuring && dbStart != null)
{
// Highlight.clear();
Point2D start = dbStart;
Point2D end = dbPoint;
Highlighter highlighter = wnd.getRulerHighlighter();
for (Highlight h : lastHighlights)
{
highlighter.remove(h);
}
lastHighlights.clear();
// show coords at start and end point
Cell cell = wnd.getCell();
if (cell == null)
{
// System.out.println("No cell available for measure");
return; // nothing available
}
Technology tech = cell.getTechnology();
lastHighlights.add(highlighter.addMessage(cell, "("
+ TextUtils.formatDistance(start.getX(), tech) + "," + TextUtils.formatDistance(start.getY(), tech)
+ ")", start));
lastHighlights.add(highlighter.addMessage(cell, "("
+ TextUtils.formatDistance(end.getX(), tech) + "," + TextUtils.formatDistance(end.getY(), tech)
+ ")", end));
// add in line
lastHighlights.add(highlighter.addLine(start, end, cell));
lastMeasuredDistanceX = Math.abs(start.getX() - end.getX());
lastMeasuredDistanceY = Math.abs(start.getY() - end.getY());
Point2D center = new Point2D.Double((start.getX() + end.getX()) / 2,
(start.getY() + end.getY()) / 2);
double dist = start.distance(end);
String show = TextUtils.formatDistance(dist, tech) + " (dX="
+ TextUtils.formatDistance(lastMeasuredDistanceX, tech) + " dY="
+ TextUtils.formatDistance(lastMeasuredDistanceY, tech) + ")";
lastHighlights.add(highlighter.addMessage(cell, show, center, 1));
highlighter.finished();
wnd.clearDoingAreaDrag();
wnd.repaint();
}
}
public void reset()
{
if (measuring) measuring = false;
// clear measurements in the current window
WindowFrame wf = WindowFrame.getCurrentWindowFrame();
if (wf.getContent() instanceof EditWindow)
{
EditWindow wnd = (EditWindow)wf.getContent();
Highlighter highlighter = wnd.getRulerHighlighter();
highlighter.clear();
highlighter.finished();
wnd.repaint();
} else if (wf.getContent() instanceof WaveformWindow)
{
WaveformWindow ww = (WaveformWindow)wf.getContent();
for(Iterator<Panel> it = ww.getPanels(); it.hasNext(); )
{
Panel p = it.next();
p.clearMeasurements();
}
}
}
private void finishMeasure(EditWindow wnd)
{
Highlighter highlighter = wnd.getRulerHighlighter();
if (measuring)
{
for (Highlight h : lastHighlights)
{
highlighter.remove(h);
}
lastHighlights.clear();
measuring = false;
} else
{
// clear measures from the screen if user cancels twice in a row
highlighter.clear();
}
highlighter.finished();
wnd.repaint();
}
// ------------------------ Mouse Listener Stuff -------------------------
public void mousePressed(MouseEvent evt)
{
boolean ctrl = (evt.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
if (evt.getSource() instanceof EditWindow)
{
int newX = evt.getX();
int newY = evt.getY();
EditWindow wnd = (EditWindow)evt.getSource();
Point2D dbMouse = wnd.screenToDatabase(newX, newY);
EditWindow.gridAlign(dbMouse);
if (isLeftMouse(evt))
{
if (measuring && ctrl && dbStart != null)
{
// orthogonal only
dbMouse = convertToOrthogonal(dbStart, dbMouse);
}
startMeasure(dbMouse);
}
if (ClickZoomWireListener.isRightMouse(evt))
{
finishMeasure(wnd);
}
}
}
public void mouseDragged(MouseEvent evt)
{
boolean ctrl = (evt.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0;
if (evt.getSource() instanceof EditWindow)
{
int newX = evt.getX();
int newY = evt.getY();
EditWindow wnd = (EditWindow)evt.getSource();
Point2D dbMouse = wnd.screenToDatabase(newX, newY);
if (ctrl && dbStart != null)
{
dbMouse = convertToOrthogonal(dbStart, dbMouse);
}
EditWindow.gridAlign(dbMouse);
dragOutMeasure(wnd, dbMouse);
}
}
public void mouseMoved(MouseEvent evt)
{
mouseDragged(evt);
}
public void mouseClicked(MouseEvent evt) {}
public void mouseEntered(MouseEvent evt) {}
public void mouseExited(MouseEvent evt) {}
public void mouseReleased(MouseEvent evt) {}
public void mouseWheelMoved(MouseWheelEvent evt) {}
public void keyReleased(KeyEvent evt) {}
public void keyTyped(KeyEvent evt) {}
public void keyPressed(KeyEvent evt)
{
int chr = evt.getKeyCode();
if (evt.getSource() instanceof EditWindow)
{
EditWindow wnd = (EditWindow)evt.getSource();
if (chr == KeyEvent.VK_ESCAPE)
{
finishMeasure(wnd);
}
}
}
// mac stuff
private static final boolean isMac = Client.isOSMac();
/**
* See if event is a left mouse click. Platform independent.
*/
private boolean isLeftMouse(MouseEvent evt)
{
if (isMac)
{
if (!evt.isMetaDown())
{
if ((evt.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) return true;
}
} else
{
if ((evt.getModifiers() & MouseEvent.BUTTON1_MASK) == MouseEvent.BUTTON1_MASK) return true;
}
return false;
}
/**
* Convert the mousePoint to be orthogonal to the startPoint. Chooses
* direction which is orthogonally farther from startPoint
* @param startPoint the reference point
* @param mousePoint the mouse point
* @return a new point orthogonal to startPoint
*/
public static Point2D convertToOrthogonal(Point2D startPoint, Point2D mousePoint)
{
// move in direction that is farther
double xdist, ydist;
xdist = Math.abs(mousePoint.getX() - startPoint.getX());
ydist = Math.abs(mousePoint.getY() - startPoint.getY());
if (ydist > xdist)
return new Point2D.Double(startPoint.getX(), mousePoint.getY());
return new Point2D.Double(mousePoint.getX(), startPoint.getY());
}
}