/*
* DragContext.java
* (FScape)
*
* Copyright (c) 2001-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.fscape.gui;
import de.sciss.fscape.util.Slots;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
/**
* Provides useful information during a
* drag-n-drop gesture.
*/
public class DragContext
implements KeyListener {
// -------- public variables --------
public static final int MOVE = 0; // drag-type
public static final int LINK = 1;
// -------- private variables --------
private Component source;
private Component target = null;
private String srcName;
private Container container;
private int type;
private Rectangle srcBounds;
private Point initialLoc;
// private Point lastLoc;
private Point currentLoc;
private Cursor dragCursor;
private Cursor oldCursor;
private int threshold;
private boolean dragStarted = false;
private boolean dragSuccessful = false;
private int targetLastState; // previous to error state
private Point srcPoint, targetPoint; // fuer Link-Pfeil
// -------- public methods --------
public DragContext( MouseEvent e, int type )
{
this.source = e.getComponent();
srcName = source.toString();
this.type = type;
srcBounds = source.getBounds();
initialLoc = new Point( srcBounds.x + e.getX(), srcBounds.y + e.getY() );
// lastLoc = initialLoc;
currentLoc = initialLoc;
srcPoint = new Point( 0, 0 );
targetPoint = new Point( 0, 0 );
dragStarted = false;
if( srcName.equals ( OpPanel.OBJ_NAME ) ) {
container = (Container) source;
} else {
container = source.getParent();
}
dragCursor = new Cursor( (( srcName.equals ( OpIcon.OBJ_NAME ) ) && (type == MOVE)) ?
Cursor.MOVE_CURSOR : Cursor.CROSSHAIR_CURSOR );
threshold = 5;
}
public Component getSource()
{
return source;
}
public int getType()
{
return type;
}
public Component getTarget()
{
return target;
}
/**
* Schwellwert in Pixels setzen, den die Maus
* mindestens ueberschreiten muss, damit der Drag beginnt
*/
public void setThreshold( int dist )
{
threshold = dist;
}
/**
* @return true, wenn der Schwellwert ueberschritten wurde
*/
public boolean hasDragStarted()
{
return dragStarted;
}
/**
* @return true, wenn der Drag gueltig war
*/
public boolean wasDragSuccessful()
{
return( dragSuccessful );
}
/**
* Always call when you get a new Message;
* this will update the DragContext's internal state
*/
public void mouseDragged( MouseEvent e )
{
if( e.getComponent() != source ) return;
Component newTarget;
if( dragStarted ) {
paintScheme( false );
}
// lastLoc = currentLoc;
currentLoc = new Point( srcBounds.x + e.getX(), srcBounds.y + e.getY() );
if( !dragStarted ) {
if( (currentLoc.x - initialLoc.x) * (currentLoc.x - initialLoc.x) +
(currentLoc.y - initialLoc.y) * (currentLoc.y - initialLoc.y) >=
threshold * threshold ) {
oldCursor = container.getCursor();
container.setCursor( dragCursor );
source.requestFocus();
source.addKeyListener( this );
dragStarted = true;
target = null;
}
}
if( dragStarted ) {
if( srcName.equals ( OpIcon.OBJ_NAME ) ) {
switch( type ) {
case MOVE:
newTarget = ((OpPanel) container).getOpIconAround(
currentLoc.x, currentLoc.y, (OpIcon) source, 0, 0 );
if( newTarget != target ) { // sth changed
if( target != null ) {
((OpIcon) target).setSelected( targetLastState );
}
target = newTarget;
if( target != null ) {
targetLastState = ((OpIcon) target).isSelected();
((OpIcon) target).setSelected( OpIcon.STATE_ERROR );
}
}
dragSuccessful = (target == null);
break;
case LINK:
newTarget = ((OpPanel) container).getOpIconAt(
currentLoc.x, currentLoc.y );
if( newTarget == source ) {
newTarget = null;
}
if( newTarget != target ) { // sth changed
if( target != null ) {
((OpIcon) target).setSelected( targetLastState );
}
dragSuccessful = false;
target = newTarget;
if( target != null ) { // pruefen ob Link moeglich ist
targetLastState = ((OpIcon) target).isSelected();
OpConnector.calcArrow( source, target, srcPoint, targetPoint,2,2);
if( !((OpIcon) target).getOperator().getSlots(
Slots.SLOTS_READER | Slots.SLOTS_FREE ).isEmpty() ) {
((OpIcon) target).setSelected( OpIcon.STATE_FRIENDLY ); // we could link to this
dragSuccessful = true;
} else {
((OpIcon) target).setSelected( OpIcon.STATE_ERROR ); // we cannot
}
}
}
break;
default:
break;
}
} else if( srcName.equals ( OpConnector.OBJ_NAME ) ) {
// XXX
dragSuccessful = true;
}
paintScheme( true );
}
}
/**
* Always call when you get dis Message;
* this will terminate the drag
*/
public void mouseReleased( MouseEvent e )
{
if( dragStarted ) {
if( (target != null) && ( target.toString ().equals ( OpIcon.OBJ_NAME ) ) ) {
((OpIcon) target).setSelected( targetLastState );
}
paintScheme( false );
container.setCursor( oldCursor );
source.removeKeyListener( this );
dragStarted = false;
}
}
protected void paintScheme( boolean mode )
{
Graphics2D g = (Graphics2D) container.getGraphics();
Graphics2D g2;
Point loc;
if( g == null ) return;
// g.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g.setXORMode(container.getBackground());
g.setColor(container.getForeground());
switch( type ) {
case MOVE:
((Dragable) source).paintScheme( g, currentLoc.x, currentLoc.y, mode );
break;
case LINK:
if( target == null ) {
OpConnector.drawArrow( g, srcBounds.x + (srcBounds.width >> 1),
srcBounds.y + (srcBounds.height >> 1),
currentLoc.x, currentLoc.y, true );
} else {
OpConnector.drawArrow( g, srcPoint.x, srcPoint.y,
targetPoint.x, targetPoint.y, true );
g2 = (Graphics2D) target.getGraphics(); // nochmal "innerhalb" des OpIcons zeichnen
if( g2 != null ) {
g2.setXORMode( container.getBackground() );
// g2.setColor( Color.black );
g2.setColor( container.getForeground () );
loc = target.getLocation();
OpConnector.drawArrow( g2, srcPoint.x - loc.x, srcPoint.y - loc.y,
targetPoint.x - loc.x, targetPoint.y - loc.y,
true );
g2.dispose();
}
}
break;
default:
break;
}
g.dispose();
}
// -------- (static) Utility methods --------
// -------- Key Listener methods --------
public void keyPressed(KeyEvent e) {
MouseEvent virtual;
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
virtual = new MouseEvent(source, MouseEvent.MOUSE_RELEASED,
System.currentTimeMillis(), 0,
currentLoc.x, currentLoc.y, 0, false);
dragSuccessful = false;
mouseReleased(virtual); // sicherheitshalber jetzt schon
source.dispatchEvent(virtual);
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}