package net.sourceforge.fidocadj.circuit;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import net.sourceforge.fidocadj.dialogs.*;
import net.sourceforge.fidocadj.globals.*;
import net.sourceforge.fidocadj.primitives.*;
import net.sourceforge.fidocadj.circuit.controllers.*;
import net.sourceforge.fidocadj.clipboard.*;
import net.sourceforge.fidocadj.timer.*;
import net.sourceforge.fidocadj.geom.*;
/** Handle the mouse click operations, as well as some dragging actions.
<pre>
cp file is part of FidoCadJ.
FidoCadJ 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.
FidoCadJ 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 FidoCadJ. If not,
@see <a href=http://www.gnu.org/licenses/>http://www.gnu.org/licenses/</a>.
Copyright 2007-2015 by Davide Bucci
</pre>
@author Davide Bucci
*/
public class MouseMoveClickHandler implements MouseMotionListener,
MouseListener
{
private final CircuitPanel cp;
private final EditorActions edt;
private final ContinuosMoveActions eea;
private final HandleActions haa;
// Record time for mouse down handle event in selection.
private double record_c;
// Record time for click up event in selection.
private double record_d;
/** Constructor. Create a MouseMoveClickHandler and associates it to the
provided handler.
@param p the CircuitPanel.
*/
public MouseMoveClickHandler(CircuitPanel p)
{
cp=p;
edt=cp.getEditorActions();
eea=cp.getContinuosMoveActions();
haa=new HandleActions(cp.getDrawingModel(), edt,
cp.getSelectionActions(), cp.getUndoActions());
record_c=record_d=1e100;
}
/** Called when the mouse is clicked inside the control
0.23.2: the Java click event is a bit too much restrictive. The mouse
need to be hold still during the click. This is apparently a problem for
a number of user. I have thus decided to use the mouse release event
instead of the complete click.
@param evt the MouseEvent to handle.
*/
public void mouseClicked(MouseEvent evt)
{
cp.requestFocusInWindow();
}
/** Handle the mouse movements when editing a graphic primitive.
This procedure is important since it is used to show interactively
to the user which element is being modified.
@param evt the MouseEvent to handle.
*/
public void mouseMoved(MouseEvent evt)
{
int xa=evt.getX();
int ya=evt.getY();
boolean toggle = getToggle(evt);
if (eea.continuosMove(cp.getMapCoordinates(), xa, ya, toggle))
cp.repaint();
}
/** Check if the "toggle" keyboard button is pressed during the mouse
operation. Toggle may be Control or Meta, depending on the operating
system.
@param evt the MouseEvent.
@return true if the toggle should be active.
*/
private boolean getToggle(MouseEvent evt)
{
if(Globals.useMetaForMultipleSelection) {
return evt.isMetaDown();
} else {
return evt.isControlDown();
}
}
/** Mouse interface: start of the dragging operations.
@param evt the MouseEvent to handle
*/
public void mousePressed(MouseEvent evt)
{
MyTimer mt = new MyTimer();
int px=evt.getX();
int py=evt.getY();
cp.getRuler().setActive(false);
cp.getRuler().setRulerStart(px, py);
cp.getRuler().setRulerEnd(px, py);
boolean toggle = getToggle(evt);
if(eea.actionSelected == ElementsEdtActions.SELECTION &&
(evt.getModifiers() & InputEvent.BUTTON3_MASK)==0 &&
!evt.isShiftDown())
{
haa.dragHandleStart(px, py, edt.getSelectionTolerance(),
toggle, cp.getMapCoordinates());
} else if(eea.actionSelected == ElementsEdtActions.SELECTION){
// Right click during selection
cp.getRuler().setActive(true);
}
if(cp.isProfiling()) {
double elapsed=mt.getElapsed();
if(elapsed<record_c) {
record_c=elapsed;
}
System.out.println("MP: Time elapsed: "+elapsed+
"; record: "+record_c+" ms");
}
}
/** Dragging event with the mouse.
@param evt the MouseEvent to handle
*/
public void mouseDragged(MouseEvent evt)
{
MyTimer mt = new MyTimer();
int px=evt.getX();
int py=evt.getY();
// Handle the ruler. Basically, we just save the coordinates and
// we launch a repaint which will be done as soon as possible.
// No graphical elements are drawn outside a repaint.
if((evt.getModifiers() & InputEvent.BUTTON3_MASK)!=0 ||
evt.isShiftDown())
{
cp.getRuler().setRulerEnd(px, py);
cp.repaint();
return;
}
haa.dragHandleDrag(cp, px, py, cp.getMapCoordinates(),
(evt.getModifiers() & ActionEvent.CTRL_MASK)==
ActionEvent.CTRL_MASK);
// A little profiling if necessary. I noticed that time needed for
// handling clicks is not negligible in large drawings, hence the
// need of controlling it.
if(cp.isProfiling()) {
double elapsed=mt.getElapsed();
if(elapsed<record_d) {
record_d=elapsed;
}
System.out.println("MD: Time elapsed: "+elapsed+
"; record: "+record_d+" ms");
}
}
/** Mouse release event.
@param evt the MouseEvent to handle
*/
public void mouseReleased(MouseEvent evt)
{
MyTimer mt = new MyTimer();
int px=evt.getX();
int py=evt.getY();
MapCoordinates cs=cp.getMapCoordinates();
boolean button3 = false;
boolean toggle = getToggle(evt);
// Key bindings are a little different with MacOSX.
if(Globals.weAreOnAMac) {
if(evt.getButton()==MouseEvent.BUTTON3)
button3=true;
else if(evt.getButton()==MouseEvent.BUTTON1 && evt.isControlDown())
button3=true;
} else {
button3 = (evt.getModifiers() & InputEvent.BUTTON3_MASK)==
InputEvent.BUTTON3_MASK;
}
// If we are in the selection state, either we are ending the editing
// of an element (and thus the dragging of a handle) or we are
// making a click.
if(eea.actionSelected==ElementsEdtActions.SELECTION) {
if(cp.getRuler().getRulerStartX()!=px ||
cp.getRuler().getRulerStartY()!=py) // NOPMD
{
haa.dragHandleEnd(cp, px, py, toggle, cs);
} else {
cp.getRuler().setActive(false);
cp.requestFocusInWindow();
eea.handleClick(cs,evt.getX(), evt.getY(),
button3, toggle, evt.getClickCount() >= 2);
}
cp.repaint();
} else {
cp.requestFocusInWindow();
if(eea.handleClick(cs,evt.getX(), evt.getY(),
button3, toggle, evt.getClickCount() >= 2))
{
cp.repaint();
}
}
// Having an idea of the release time is useful for the optimization
// of the click event handling. The most time-consuming operation
// which is done in this phase is finding the closest component to
// the mouse pointer and eventually selecting it.
if(cp.isProfiling()) {
double elapsed=mt.getElapsed();
if(elapsed<record_d) {
record_d=elapsed;
}
System.out.println("MR: Time elapsed: "+elapsed+
"; record: "+record_d+" ms");
}
}
/** The mouse pointer enters into the control. This method changes the
cursor associated to it.
@param evt the MouseEvent to handle
*/
public void mouseEntered(MouseEvent evt)
{
selectCursor();
}
/**
Define the icon used for the mouse cursor, depending on the current
editing action.
*/
public void selectCursor()
{
switch(eea.actionSelected) {
case ElementsEdtActions.NONE:
case ElementsEdtActions.ZOOM:
case ElementsEdtActions.HAND:
cp.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
break;
case ElementsEdtActions.LINE:
case ElementsEdtActions.TEXT:
case ElementsEdtActions.BEZIER:
case ElementsEdtActions.POLYGON:
case ElementsEdtActions.COMPLEXCURVE:
case ElementsEdtActions.ELLIPSE:
case ElementsEdtActions.RECTANGLE:
case ElementsEdtActions.CONNECTION:
case ElementsEdtActions.PCB_LINE:
case ElementsEdtActions.PCB_PAD:
cp.setCursor(Cursor.getPredefinedCursor(
Cursor.CROSSHAIR_CURSOR));
break;
case ElementsEdtActions.SELECTION:
default:
cp.setCursor(Cursor.getPredefinedCursor(
Cursor.DEFAULT_CURSOR));
break;
}
}
/** The mouse pointer has exited the control. This method changes the
cursor associated and restores the default one.
@param evt the MouseEvent to handle
*/
public void mouseExited(MouseEvent evt)
{
cp.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if(eea.successiveMove) {
eea.successiveMove = false;
cp.repaint();
}
}
}