/*
* (C) 2004 - Geotechnical Software Services
*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This code 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
package no.geosoft.cc.graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.Timer;
/**
* A default zoom interaction. The following actions are implemented:
*
* <ol>
* <li>Button 1 click at a point in the scene: The scene is zoomed in
* a certain factor with that point fixed.
* <li>Button 1 press and keep pressed: The scene is zoomed in
* continously until the button is released.
* <li>Button 3 click at a point in the scene: The scene is zoomed out
* a certain factor with that point fixed.
* <li>Button 3 press and keep pressed: The scene is zoomed out
* continously until the button is released.
* <li>Button 2 click: Unzoom.
* <li>Button 1 press, drag and release: User creates a rubber band
* and the scene is zoomed to the specified area.
* </ol>
*
* The <code>ZoomInteraction</code> class lacks the <em>G</em>
* prefix as it is an optional extension to G and not part of the core
* classes.
*
* @author <a href="mailto:info@geosoft.no">GeoSoft</a>
*/
public class ZoomInteraction
implements GInteraction, ActionListener
{
private static final double ZOOM_FACTOR = 0.9;
private final GScene scene_;
private final GObject interaction_;
private final GSegment rubberBand_;
private int x_[], y_[];
private int x0_, y0_;
private Timer timer_;
private double zoomFactor_;
/**
* Create a new zoom interaction on the specifed scene.
* The interaction is activated by GWindow.setInteraction().
* @see GWindow#startInteraction(GInteraction)
* @see GWindow#stopInteraction()
*
* @param scene Scene of this zoom interaction.
* @param style Style for the interaction rubber band
*/
public ZoomInteraction (GScene scene, GStyle style)
{
scene_ = scene;
// Create a graphic node for holding the interaction graphics
interaction_ = new GObject ("Interaction");
// Default rubberband style if none provided
if (style == null) {
style = new GStyle();
style.setLineWidth (1);
style.setForegroundColor (new Color (0, 0, 0));
style.setBackgroundColor (null);
}
interaction_.setStyle (style);
// Create and attach rubberband segment
rubberBand_ = new GSegment();
interaction_.addSegment (rubberBand_);
// For the rubberband geometry
x_ = new int[5];
y_ = new int[5];
}
/**
* Create a new zoom interaction on the specifed scene.
* @see GWindow#startInteraction(GInteraction)
* @see GWindow#stopInteraction()
*
* @param scene Scene of this zoom interaction.
*/
public ZoomInteraction (GScene scene)
{
this (scene, null);
}
/**
* Timer trigged event when the user keeps pressing a mouse button.
*
* @param event Not used.
*/
public void actionPerformed (ActionEvent event)
{
scene_.zoom (x0_, y0_, zoomFactor_);
}
/**
* Handle mouse events in the canvas.
*
* @param eventType Event trigging this method.
* @param x,y Pointer location.
*/
public void event (GScene scene, int eventType, int x, int y)
{
switch (eventType) {
case GWindow.BUTTON1_DOWN :
x0_ = x;
y0_ = y;
zoomFactor_ = ZOOM_FACTOR;
scene_.add (interaction_); // Front
// Cause actionPerformed() to be called every 90ms as long
// as button is pressed.
timer_ = new Timer (90, this);
timer_.setInitialDelay (500);
timer_.start();
break;
case GWindow.BUTTON1_UP :
interaction_.remove();
rubberBand_.setGeometry ((int []) null);
timer_.stop();
timer_.removeActionListener (this);
int dx = Math.abs (x - x0_);
int dy = Math.abs (x - x0_);
// If the rubber band is very small, interpret it as a click
if (dx < 3 || dy < 3)
scene_.zoom (x, y, zoomFactor_);
// Else we zoom into the area defined by the rubberband
else
scene_.zoom (x0_, y0_, x, y);
break;
case GWindow.BUTTON2_UP :
scene_.unzoom();
break;
case GWindow.BUTTON1_DRAG :
timer_.stop();
timer_.removeActionListener (this);
x_[0] = x0_;
x_[1] = x;
x_[2] = x;
x_[3] = x0_;
x_[4] = x0_;
y_[0] = y0_;
y_[1] = y0_;
y_[2] = y;
y_[3] = y;
y_[4] = y0_;
rubberBand_.setGeometry (x_, y_);
scene_.refresh();
break;
case GWindow.BUTTON3_DOWN :
x0_ = x;
y0_ = y;
zoomFactor_ = 1.0 / ZOOM_FACTOR;
// Cause actionPerformed() to be called every 90ms as long
// as button is pressed.
timer_ = new Timer (90, this);
timer_.setInitialDelay (500);
timer_.start();
break;
case GWindow.BUTTON3_UP :
timer_.stop();
timer_.removeActionListener (this);
scene_.zoom (x, y, zoomFactor_);
break;
}
}
}